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