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