xref: /freebsd/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c (revision 512bd18d)
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * Copyright (c) 2017 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Landon Fuller
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17  *    redistribution must be conditioned upon including a substantially
18  *    similar Disclaimer requirement for further binary redistribution.
19  *
20  * NO WARRANTY
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGES.
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 /*
38  * Broadcom BHND PCI/PCIe-Gen1 PCI-Host Bridge.
39  *
40  * This driver handles all interactions with PCI bridge cores operating in
41  * endpoint mode.
42  *
43  * Host-level PCI operations are handled at the bhndb bridge level by the
44  * bhndb_pci driver.
45  */
46 
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 
50 #include <sys/malloc.h>
51 
52 #include <sys/bus.h>
53 #include <sys/module.h>
54 
55 #include <sys/systm.h>
56 
57 #include <machine/bus.h>
58 #include <sys/rman.h>
59 #include <machine/resource.h>
60 
61 #include <dev/bhnd/bhnd.h>
62 
63 #include <dev/pci/pcireg.h>
64 #include <dev/pci/pcivar.h>
65 
66 #include <dev/bhnd/cores/chipc/chipc.h>
67 #include <dev/bhnd/cores/chipc/chipcreg.h>
68 
69 #include "bhnd_pcireg.h"
70 #include "bhnd_pci_hostbvar.h"
71 
72 static const struct bhnd_device_quirk bhnd_pci_quirks[];
73 static const struct bhnd_device_quirk bhnd_pcie_quirks[];
74 
75 /* Device driver work-around variations */
76 typedef enum {
77 	BHND_PCI_WAR_ATTACH,	/**< apply attach workarounds */
78 	BHND_PCI_WAR_RESUME,	/**< apply resume workarounds */
79 	BHND_PCI_WAR_SUSPEND,	/**< apply suspend workarounds */
80 	BHND_PCI_WAR_DETACH	/**< apply detach workarounds */
81 } bhnd_pci_war_state;
82 
83 static int	bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
84 static int	bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc,
85 		    bhnd_pci_war_state state);
86 static int	bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc,
87 		    bhnd_pci_war_state state);
88 
89 /*
90  * device/quirk tables
91  */
92 
93 #define	BHND_PCI_DEV(_core, _quirks)		\
94 	BHND_DEVICE(BCM, _core, NULL, _quirks, BHND_DF_HOSTB)
95 
96 static const struct bhnd_device bhnd_pci_devs[] = {
97 	BHND_PCI_DEV(PCI,	bhnd_pci_quirks),
98 	BHND_PCI_DEV(PCIE,	bhnd_pcie_quirks),
99 	BHND_DEVICE_END
100 };
101 
102 static const struct bhnd_device_quirk bhnd_pci_quirks[] = {
103 	/* core revision quirks */
104 	BHND_CORE_QUIRK	(HWREV_ANY,	BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST),
105 	BHND_CORE_QUIRK	(HWREV_GTE(11),	BHND_PCI_QUIRK_SBTOPCI2_READMULTI |
106 					BHND_PCI_QUIRK_CLKRUN_DSBL),
107 
108 	/* BCM4321CB2 boards that require 960ns latency timer override */
109 	BHND_BOARD_QUIRK(BCM4321CB2,	BHND_PCI_QUIRK_960NS_LATTIM_OVR),
110 	BHND_BOARD_QUIRK(BCM4321CB2_AG,	BHND_PCI_QUIRK_960NS_LATTIM_OVR),
111 
112 	BHND_DEVICE_QUIRK_END
113 };
114 
115 static const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
116 	/* core revision quirks */
117 	BHND_CORE_QUIRK	(HWREV_EQ (0),	BHND_PCIE_QUIRK_SDR9_L0s_HANG),
118 	BHND_CORE_QUIRK	(HWREV_RANGE(0,1),
119 	    BHND_PCIE_QUIRK_UR_STATUS_FIX),
120 
121 	BHND_CORE_QUIRK	(HWREV_EQ (1),	BHND_PCIE_QUIRK_PCIPM_REQEN),
122 
123 	BHND_CORE_QUIRK	(HWREV_RANGE(3,5),
124 	    BHND_PCIE_QUIRK_ASPM_OVR | BHND_PCIE_QUIRK_SDR9_POLARITY |
125 	    BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY),
126 
127 	BHND_CORE_QUIRK	(HWREV_LTE(6),	BHND_PCIE_QUIRK_L1_IDLE_THRESH),
128 	BHND_CORE_QUIRK	(HWREV_GTE(6),	BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET),
129 	BHND_CORE_QUIRK	(HWREV_EQ (7),	BHND_PCIE_QUIRK_SERDES_NOPLLDOWN),
130 	BHND_CORE_QUIRK	(HWREV_GTE(8),	BHND_PCIE_QUIRK_L1_TIMER_PERF),
131 
132 	BHND_CORE_QUIRK	(HWREV_LTE(17),	BHND_PCIE_QUIRK_MAX_MRRS_128),
133 
134 	/* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
135 	 * to be set. */
136 	{{ BHND_MATCH_BOARD_VENDOR	(PCI_VENDOR_APPLE),
137 	   BHND_MATCH_BOARD_REV		(HWREV_LTE(0x71)),
138 	   BHND_MATCH_SROMREV		(EQ(4)) },
139 		BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN },
140 
141 	/* Apple BCM4322 boards that require 700mV SerDes TX drive strength. */
142 	{{ BHND_MATCH_CHIP_ID(BCM4322),
143 	   BHND_MATCH_BOARD(PCI_VENDOR_APPLE, BCM94322X9), },
144 		BHND_PCIE_QUIRK_SERDES_TXDRV_700MV },
145 
146 	/* Apple BCM4331 board-specific quirks */
147 #define	BHND_A4331_QUIRK(_board, ...)	\
148 	{{ BHND_MATCH_CHIP_ID(BCM4331),		\
149 	    BHND_MATCH_BOARD(PCI_VENDOR_APPLE, _board) }, __VA_ARGS__ }
150 
151 	BHND_A4331_QUIRK(BCM94331X19,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
152 					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
153 
154 	BHND_A4331_QUIRK(BCM94331X28,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
155 					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
156 
157 	BHND_A4331_QUIRK(BCM94331X28B,	BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
158 
159 	BHND_A4331_QUIRK(BCM94331X29B,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
160 					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
161 
162 	BHND_A4331_QUIRK(BCM94331X19C,	BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
163 					BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
164 
165 	BHND_A4331_QUIRK(BCM94331X29D,	BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
166 
167 	BHND_A4331_QUIRK(BCM94331X33,	BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
168 
169 #undef BHND_A4331_QUIRK
170 
171 	BHND_DEVICE_QUIRK_END
172 };
173 
174 
175 #define	BHND_PCI_SOFTC(_sc)	(&((_sc)->common))
176 
177 #define	BHND_PCI_READ_2(_sc, _reg)		\
178 	bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
179 
180 #define	BHND_PCI_READ_4(_sc, _reg)		\
181 	bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
182 
183 #define	BHND_PCI_WRITE_2(_sc, _reg, _val)	\
184 	bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
185 
186 #define	BHND_PCI_WRITE_4(_sc, _reg, _val)	\
187 	bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
188 
189 #define	BHND_PCI_PROTO_READ_4(_sc, _reg)	\
190 	bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
191 
192 #define	BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val)	\
193 	bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
194 
195 #define	BHND_PCI_MDIO_READ(_sc, _phy, _reg)	\
196 	bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
197 
198 #define	BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)		\
199 	bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
200 
201 #define	BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)		\
202 	bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
203 
204 #define	BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)	\
205 	bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),		\
206 	    (_devaddr), (_reg), (_val))
207 
208 #define	BPCI_REG_SET(_regv, _attr, _val)	\
209 	BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
210 
211 #define	BPCI_REG_GET(_regv, _attr)	\
212 	BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
213 
214 #define	BPCI_CMN_REG_SET(_regv, _attr, _val)			\
215 	BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
216 	    BHND_ ## _attr, (_val))
217 
218 #define	BPCI_CMN_REG_GET(_regv, _attr)				\
219 	BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
220 	    BHND_ ## _attr)
221 
222 static int
223 bhnd_pci_hostb_attach(device_t dev)
224 {
225 	struct bhnd_pcihb_softc	*sc;
226 	int			 error;
227 
228 	sc = device_get_softc(dev);
229 	sc->dev = dev;
230 	sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
231 	    sizeof(bhnd_pci_devs[0]));
232 
233 	/* Find the host PCI bridge device */
234 	sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
235 	if (sc->pci_dev == NULL) {
236 		device_printf(dev, "parent pci bridge device not found\n");
237 		return (ENXIO);
238 	}
239 
240 	/* Common setup */
241 	if ((error = bhnd_pci_generic_attach(dev)))
242 		return (error);
243 
244 	/* Apply early single-shot work-arounds */
245 	if ((error = bhnd_pci_wars_early_once(sc)))
246 		goto failed;
247 
248 	/* Apply attach/resume work-arounds */
249 	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
250 		goto failed;
251 
252 	return (0);
253 
254 failed:
255 	bhnd_pci_generic_detach(dev);
256 	return (error);
257 }
258 
259 static int
260 bhnd_pci_hostb_detach(device_t dev)
261 {
262 	struct bhnd_pcihb_softc *sc;
263 	int			 error;
264 
265 	sc = device_get_softc(dev);
266 
267 	/* Apply suspend/detach work-arounds */
268 	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
269 		return (error);
270 
271 	return (bhnd_pci_generic_detach(dev));
272 }
273 
274 static int
275 bhnd_pci_hostb_suspend(device_t dev)
276 {
277 	struct bhnd_pcihb_softc *sc;
278 	int			 error;
279 
280 	sc = device_get_softc(dev);
281 
282 	/* Apply suspend/detach work-arounds */
283 	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
284 		return (error);
285 
286 	return (bhnd_pci_generic_suspend(dev));
287 }
288 
289 static int
290 bhnd_pci_hostb_resume(device_t dev)
291 {
292 	struct bhnd_pcihb_softc	*sc;
293 	int			 error;
294 
295 	sc = device_get_softc(dev);
296 
297 	if ((error = bhnd_pci_generic_resume(dev)))
298 		return (error);
299 
300 	/* Apply attach/resume work-arounds */
301 	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
302 		bhnd_pci_generic_detach(dev);
303 		return (error);
304 	}
305 
306 	return (0);
307 }
308 
309 /**
310  * Apply any hardware work-arounds that must be executed exactly once, early in
311  * the attach process.
312  *
313  * This must be called after core enumeration and discovery of all applicable
314  * quirks, but prior to probe/attach of any cores, parsing of
315  * SPROM, etc.
316  */
317 static int
318 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
319 {
320 	int error;
321 
322 	/* Set PCI latency timer */
323 	if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
324 		pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
325 		    1);
326 	}
327 
328 	/* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
329 	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
330 		struct bhnd_board_info	board;
331 		bool			aspm_en;
332 
333 		/* Fetch board info */
334 		if ((error = bhnd_read_board_info(sc->dev, &board)))
335 			return (error);
336 
337 		/* Check board flags */
338 		aspm_en = true;
339 		if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
340 			aspm_en = false;
341 
342 		/* Early Apple devices did not (but should have) set
343 		 * BHND_BFL2_PCIEWAR_OVR in SPROM. */
344 		if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
345 			aspm_en = false;
346 
347 		sc->aspm_quirk_override.aspm_en = aspm_en;
348 	}
349 
350 	/* Determine correct polarity by observing the attach-time PCIe PHY
351 	 * link status. This is used later to reset/force the SerDes
352 	 * polarity */
353 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
354 		uint32_t st;
355 		bool inv;
356 
357 		st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
358 		inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
359 		sc->sdr9_quirk_polarity.inv = inv;
360 	}
361 
362 	/* Override maximum read request size */
363 	if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
364 		int	msize;
365 
366 		msize = 128; /* compatible with all PCIe-G1 core revisions */
367 		if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
368 			msize = 512;
369 
370 		if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
371 			panic("set mrrs on non-PCIe device");
372 	}
373 
374 	return (0);
375 }
376 
377 /**
378  * Apply any hardware workarounds that are required upon attach or resume
379  * of the bridge device.
380  */
381 static int
382 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
383 {
384 	/* Note that the order here matters; these work-arounds
385 	 * should not be re-ordered without careful review of their
386 	 * interdependencies */
387 
388 	/* Enable PCI prefetch/burst/readmulti flags */
389 	if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
390 	    sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
391 	{
392 		uint32_t sbp2;
393 		sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
394 
395 		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
396 			sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
397 
398 		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
399 			sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
400 
401 		BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
402 	}
403 
404 	/* Disable PCI CLKRUN# */
405 	if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
406 		uint32_t ctl;
407 
408 		ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
409 		ctl |= BHND_PCI_CLKRUN_DSBL;
410 		BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
411 	}
412 
413 	/* Enable TLP unmatched address handling work-around */
414 	if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
415 		uint32_t wrs;
416 		wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
417 		wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
418 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
419 	}
420 
421 	/* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
422 	 * data during L0s to L0 exit transitions. */
423 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
424 		uint16_t sdv;
425 
426 		/* Set RX track/acquire timers to 2.064us/40.96us */
427 		sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
428 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
429 		    (40960/1024));
430 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
431 		    BHND_PCIE_SDR9_RX_TIMER1, sdv);
432 
433 		/* Apply CDR frequency workaround */
434 		sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
435 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
436 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
437 		    BHND_PCIE_SDR9_RX_CDR, sdv);
438 
439 		/* Apply CDR BW tunings */
440 		sdv = 0;
441 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
442 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
443 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
444 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
445 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
446 		    BHND_PCIE_SDR9_RX_CDRBW, sdv);
447 	}
448 
449 	/* Force correct SerDes polarity */
450 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
451 		uint16_t	rxctl;
452 
453 		rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
454 		    BHND_PCIE_SDR9_RX_CTRL);
455 
456 		rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
457 		if (sc->sdr9_quirk_polarity.inv)
458 			rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
459 		else
460 			rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
461 
462 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
463 		    BHND_PCIE_SDR9_RX_CTRL, rxctl);
464 	}
465 
466 	/* Disable startup retry on PLL frequency detection failure */
467 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
468 		uint16_t	pctl;
469 
470 		pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
471 		    BHND_PCIE_SDR9_PLL_CTRL);
472 
473 		pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
474 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
475 		    BHND_PCIE_SDR9_PLL_CTRL, pctl);
476 	}
477 
478 	/* Explicitly enable PCI-PM */
479 	if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
480 		uint32_t lcreg;
481 		lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
482 		lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
483 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
484 	}
485 
486 	/* Adjust L1 timer to fix slow L1->L0 transitions */
487 	if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
488 		uint32_t pmt;
489 		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
490 		pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
491 		    BHND_PCIE_L1THRESHOLD_WARVAL);
492 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
493 	}
494 
495 	/* Extend L1 timer for better performance.
496 	 * TODO: We could enable/disable this on demand for better power
497 	 * savings if we tie this to HT clock request handling */
498 	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
499 		uint32_t pmt;
500 		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
501 		pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
502 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
503 	}
504 
505 	/* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
506 	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
507 		bus_size_t	reg;
508 		uint16_t	cfg;
509 
510 		/* Set ASPM L1/L0s flags in SPROM shadow */
511 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
512 		cfg = BHND_PCI_READ_2(sc, reg);
513 
514 		if (sc->aspm_quirk_override.aspm_en)
515 			cfg |= BHND_PCIE_SRSH_ASPM_ENB;
516 		else
517 			cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
518 
519 		BHND_PCI_WRITE_2(sc, reg, cfg);
520 
521 
522 		/* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
523 		cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
524 
525 		if (sc->aspm_quirk_override.aspm_en)
526 			cfg |= PCIEM_LINK_CTL_ASPMC;
527 		else
528 			cfg &= ~PCIEM_LINK_CTL_ASPMC;
529 
530 		cfg &= ~PCIEM_LINK_CTL_ECPM;		/* CLKREQ# */
531 
532 		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2);
533 
534 		/* Set CLKREQ (ECPM) flags in SPROM shadow */
535 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
536 		cfg = BHND_PCI_READ_2(sc, reg);
537 
538 		if (sc->aspm_quirk_override.aspm_en)
539 			cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
540 		else
541 			cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
542 
543 		BHND_PCI_WRITE_2(sc, reg, cfg);
544 	}
545 
546 	/* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
547 	if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
548 		bus_size_t	reg;
549 		uint16_t	cfg;
550 
551 		/* Fetch the misc cfg flags from SPROM */
552 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG;
553 		cfg = BHND_PCI_READ_2(sc, reg);
554 
555 		/* Write EXIT_NOPRST flag if not already set in SPROM */
556 		if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) {
557 			cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST;
558 			BHND_PCI_WRITE_2(sc, reg, cfg);
559 		}
560 	}
561 
562 	/* Disable SerDes PLL down */
563 	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
564 		device_t	bhnd, chipc;
565 		bus_size_t	reg;
566 
567 		bhnd = device_get_parent(sc->dev);
568 		chipc = bhnd_bus_find_child(bhnd, BHND_DEVCLASS_CC, 0);
569 		KASSERT(chipc != NULL, ("missing chipcommon device"));
570 
571 		/* Write SerDes PLL disable flag to the ChipCommon core */
572 		BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
573 		    CHIPCTRL_4321_PLL_DOWN);
574 
575 		/* Clear SPROM shadow backdoor register */
576 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
577 		BHND_PCI_WRITE_2(sc, reg, 0);
578 	}
579 
580 	/* Adjust TX drive strength and pre-emphasis coefficient */
581 	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
582 		uint16_t txdrv;
583 
584 		/* Fetch current TX driver parameters */
585 		txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
586 		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
587 
588 		/* Set 700mV drive strength */
589 		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
590 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
591 			    BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
592 
593 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
594 			    BHND_PCIE_APPLE_TX_IDRIVER_700MV);
595 		}
596 
597 		/* ... or, set max drive strength */
598 		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
599 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
600 			    BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
601 
602 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
603 			    BHND_PCIE_APPLE_TX_IDRIVER_MAX);
604 		}
605 
606 		BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
607 		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
608 	}
609 
610 	return (0);
611 }
612 
613 /**
614  * Apply any hardware workarounds that are required upon detach or suspend
615  * of the bridge device.
616  */
617 static int
618 bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
619 {
620 	/* Reduce L1 timer for better power savings.
621 	 * TODO: We could enable/disable this on demand for better power
622 	 * savings if we tie this to HT clock request handling */
623 	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
624 		uint32_t pmt;
625 		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
626 		pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND;
627 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
628 	}
629 
630 	/* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
631 	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
632 		uint16_t	lcreg;
633 
634 		lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
635 
636 		lcreg |= PCIEM_LINK_CTL_ECPM;	/* CLKREQ# */
637 		if (state == BHND_PCI_WAR_SUSPEND)
638 			lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
639 
640 		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
641 	}
642 
643 	return (0);
644 }
645 
646 static device_method_t bhnd_pci_hostb_methods[] = {
647 	/* Device interface */
648 	DEVMETHOD(device_attach,		bhnd_pci_hostb_attach),
649 	DEVMETHOD(device_detach,		bhnd_pci_hostb_detach),
650 	DEVMETHOD(device_suspend,		bhnd_pci_hostb_suspend),
651 	DEVMETHOD(device_resume,		bhnd_pci_hostb_resume),
652 
653 	DEVMETHOD_END
654 };
655 
656 DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
657     sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
658 DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
659 
660 MODULE_VERSION(bhnd_pci_hostb, 1);
661 MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);
662 MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);
663