xref: /freebsd/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 /*
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 #define	BHND_PCI_SOFTC(_sc)	(&((_sc)->common))
175 
176 #define	BHND_PCI_READ_2(_sc, _reg)		\
177 	bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
178 
179 #define	BHND_PCI_READ_4(_sc, _reg)		\
180 	bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
181 
182 #define	BHND_PCI_WRITE_2(_sc, _reg, _val)	\
183 	bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
184 
185 #define	BHND_PCI_WRITE_4(_sc, _reg, _val)	\
186 	bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
187 
188 #define	BHND_PCI_PROTO_READ_4(_sc, _reg)	\
189 	bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
190 
191 #define	BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val)	\
192 	bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
193 
194 #define	BHND_PCI_MDIO_READ(_sc, _phy, _reg)	\
195 	bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
196 
197 #define	BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)		\
198 	bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
199 
200 #define	BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)		\
201 	bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
202 
203 #define	BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)	\
204 	bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),		\
205 	    (_devaddr), (_reg), (_val))
206 
207 #define	BPCI_REG_SET(_regv, _attr, _val)	\
208 	BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
209 
210 #define	BPCI_REG_GET(_regv, _attr)	\
211 	BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
212 
213 #define	BPCI_CMN_REG_SET(_regv, _attr, _val)			\
214 	BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
215 	    BHND_ ## _attr, (_val))
216 
217 #define	BPCI_CMN_REG_GET(_regv, _attr)				\
218 	BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),	\
219 	    BHND_ ## _attr)
220 
221 static int
bhnd_pci_hostb_attach(device_t dev)222 bhnd_pci_hostb_attach(device_t dev)
223 {
224 	struct bhnd_pcihb_softc	*sc;
225 	int			 error;
226 
227 	sc = device_get_softc(dev);
228 	sc->dev = dev;
229 	sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
230 	    sizeof(bhnd_pci_devs[0]));
231 
232 	/* Find the host PCI bridge device */
233 	sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
234 	if (sc->pci_dev == NULL) {
235 		device_printf(dev, "parent pci bridge device not found\n");
236 		return (ENXIO);
237 	}
238 
239 	/* Common setup */
240 	if ((error = bhnd_pci_generic_attach(dev)))
241 		return (error);
242 
243 	/* Apply early single-shot work-arounds */
244 	if ((error = bhnd_pci_wars_early_once(sc)))
245 		goto failed;
246 
247 	/* Apply attach/resume work-arounds */
248 	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
249 		goto failed;
250 
251 	return (0);
252 
253 failed:
254 	bhnd_pci_generic_detach(dev);
255 	return (error);
256 }
257 
258 static int
bhnd_pci_hostb_detach(device_t dev)259 bhnd_pci_hostb_detach(device_t dev)
260 {
261 	struct bhnd_pcihb_softc *sc;
262 	int			 error;
263 
264 	sc = device_get_softc(dev);
265 
266 	/* Apply suspend/detach work-arounds */
267 	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
268 		return (error);
269 
270 	return (bhnd_pci_generic_detach(dev));
271 }
272 
273 static int
bhnd_pci_hostb_suspend(device_t dev)274 bhnd_pci_hostb_suspend(device_t dev)
275 {
276 	struct bhnd_pcihb_softc *sc;
277 	int			 error;
278 
279 	sc = device_get_softc(dev);
280 
281 	/* Apply suspend/detach work-arounds */
282 	if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
283 		return (error);
284 
285 	return (bhnd_pci_generic_suspend(dev));
286 }
287 
288 static int
bhnd_pci_hostb_resume(device_t dev)289 bhnd_pci_hostb_resume(device_t dev)
290 {
291 	struct bhnd_pcihb_softc	*sc;
292 	int			 error;
293 
294 	sc = device_get_softc(dev);
295 
296 	if ((error = bhnd_pci_generic_resume(dev)))
297 		return (error);
298 
299 	/* Apply attach/resume work-arounds */
300 	if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
301 		bhnd_pci_generic_detach(dev);
302 		return (error);
303 	}
304 
305 	return (0);
306 }
307 
308 /**
309  * Apply any hardware work-arounds that must be executed exactly once, early in
310  * the attach process.
311  *
312  * This must be called after core enumeration and discovery of all applicable
313  * quirks, but prior to probe/attach of any cores, parsing of
314  * SPROM, etc.
315  */
316 static int
bhnd_pci_wars_early_once(struct bhnd_pcihb_softc * sc)317 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
318 {
319 	int error;
320 
321 	/* Set PCI latency timer */
322 	if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
323 		pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
324 		    1);
325 	}
326 
327 	/* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
328 	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
329 		struct bhnd_board_info	board;
330 		bool			aspm_en;
331 
332 		/* Fetch board info */
333 		if ((error = bhnd_read_board_info(sc->dev, &board)))
334 			return (error);
335 
336 		/* Check board flags */
337 		aspm_en = true;
338 		if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
339 			aspm_en = false;
340 
341 		/* Early Apple devices did not (but should have) set
342 		 * BHND_BFL2_PCIEWAR_OVR in SPROM. */
343 		if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
344 			aspm_en = false;
345 
346 		sc->aspm_quirk_override.aspm_en = aspm_en;
347 	}
348 
349 	/* Determine correct polarity by observing the attach-time PCIe PHY
350 	 * link status. This is used later to reset/force the SerDes
351 	 * polarity */
352 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
353 		uint32_t st;
354 		bool inv;
355 
356 		st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
357 		inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
358 		sc->sdr9_quirk_polarity.inv = inv;
359 	}
360 
361 	/* Override maximum read request size */
362 	if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
363 		int	msize;
364 
365 		msize = 128; /* compatible with all PCIe-G1 core revisions */
366 		if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
367 			msize = 512;
368 
369 		if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
370 			panic("set mrrs on non-PCIe device");
371 	}
372 
373 	return (0);
374 }
375 
376 /**
377  * Apply any hardware workarounds that are required upon attach or resume
378  * of the bridge device.
379  */
380 static int
bhnd_pci_wars_hwup(struct bhnd_pcihb_softc * sc,bhnd_pci_war_state state)381 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
382 {
383 	/* Note that the order here matters; these work-arounds
384 	 * should not be re-ordered without careful review of their
385 	 * interdependencies */
386 
387 	/* Enable PCI prefetch/burst/readmulti flags */
388 	if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
389 	    sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
390 	{
391 		uint32_t sbp2;
392 		sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
393 
394 		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
395 			sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
396 
397 		if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
398 			sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
399 
400 		BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
401 	}
402 
403 	/* Disable PCI CLKRUN# */
404 	if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
405 		uint32_t ctl;
406 
407 		ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
408 		ctl |= BHND_PCI_CLKRUN_DSBL;
409 		BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
410 	}
411 
412 	/* Enable TLP unmatched address handling work-around */
413 	if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
414 		uint32_t wrs;
415 		wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
416 		wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
417 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
418 	}
419 
420 	/* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
421 	 * data during L0s to L0 exit transitions. */
422 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
423 		uint16_t sdv;
424 
425 		/* Set RX track/acquire timers to 2.064us/40.96us */
426 		sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
427 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
428 		    (40960/1024));
429 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
430 		    BHND_PCIE_SDR9_RX_TIMER1, sdv);
431 
432 		/* Apply CDR frequency workaround */
433 		sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
434 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
435 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
436 		    BHND_PCIE_SDR9_RX_CDR, sdv);
437 
438 		/* Apply CDR BW tunings */
439 		sdv = 0;
440 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
441 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
442 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
443 		sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
444 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
445 		    BHND_PCIE_SDR9_RX_CDRBW, sdv);
446 	}
447 
448 	/* Force correct SerDes polarity */
449 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
450 		uint16_t	rxctl;
451 
452 		rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
453 		    BHND_PCIE_SDR9_RX_CTRL);
454 
455 		rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
456 		if (sc->sdr9_quirk_polarity.inv)
457 			rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
458 		else
459 			rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
460 
461 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
462 		    BHND_PCIE_SDR9_RX_CTRL, rxctl);
463 	}
464 
465 	/* Disable startup retry on PLL frequency detection failure */
466 	if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
467 		uint16_t	pctl;
468 
469 		pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
470 		    BHND_PCIE_SDR9_PLL_CTRL);
471 
472 		pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
473 		BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
474 		    BHND_PCIE_SDR9_PLL_CTRL, pctl);
475 	}
476 
477 	/* Explicitly enable PCI-PM */
478 	if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
479 		uint32_t lcreg;
480 		lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
481 		lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
482 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
483 	}
484 
485 	/* Adjust L1 timer to fix slow L1->L0 transitions */
486 	if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
487 		uint32_t pmt;
488 		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
489 		pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
490 		    BHND_PCIE_L1THRESHOLD_WARVAL);
491 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
492 	}
493 
494 	/* Extend L1 timer for better performance.
495 	 * TODO: We could enable/disable this on demand for better power
496 	 * savings if we tie this to HT clock request handling */
497 	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
498 		uint32_t pmt;
499 		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
500 		pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
501 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
502 	}
503 
504 	/* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
505 	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
506 		bus_size_t	reg;
507 		uint16_t	cfg;
508 
509 		/* Set ASPM L1/L0s flags in SPROM shadow */
510 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
511 		cfg = BHND_PCI_READ_2(sc, reg);
512 
513 		if (sc->aspm_quirk_override.aspm_en)
514 			cfg |= BHND_PCIE_SRSH_ASPM_ENB;
515 		else
516 			cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
517 
518 		BHND_PCI_WRITE_2(sc, reg, cfg);
519 
520 		/* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
521 		cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
522 
523 		if (sc->aspm_quirk_override.aspm_en)
524 			cfg |= PCIEM_LINK_CTL_ASPMC;
525 		else
526 			cfg &= ~PCIEM_LINK_CTL_ASPMC;
527 
528 		cfg &= ~PCIEM_LINK_CTL_ECPM;		/* CLKREQ# */
529 
530 		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2);
531 
532 		/* Set CLKREQ (ECPM) flags in SPROM shadow */
533 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
534 		cfg = BHND_PCI_READ_2(sc, reg);
535 
536 		if (sc->aspm_quirk_override.aspm_en)
537 			cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
538 		else
539 			cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
540 
541 		BHND_PCI_WRITE_2(sc, reg, cfg);
542 	}
543 
544 	/* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
545 	if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
546 		bus_size_t	reg;
547 		uint16_t	cfg;
548 
549 		/* Fetch the misc cfg flags from SPROM */
550 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG;
551 		cfg = BHND_PCI_READ_2(sc, reg);
552 
553 		/* Write EXIT_NOPRST flag if not already set in SPROM */
554 		if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) {
555 			cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST;
556 			BHND_PCI_WRITE_2(sc, reg, cfg);
557 		}
558 	}
559 
560 	/* Disable SerDes PLL down */
561 	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
562 		device_t	bhnd, chipc;
563 		bus_size_t	reg;
564 
565 		bhnd = device_get_parent(sc->dev);
566 		chipc = bhnd_bus_find_child(bhnd, BHND_DEVCLASS_CC, 0);
567 		KASSERT(chipc != NULL, ("missing chipcommon device"));
568 
569 		/* Write SerDes PLL disable flag to the ChipCommon core */
570 		BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
571 		    CHIPCTRL_4321_PLL_DOWN);
572 
573 		/* Clear SPROM shadow backdoor register */
574 		reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
575 		BHND_PCI_WRITE_2(sc, reg, 0);
576 	}
577 
578 	/* Adjust TX drive strength and pre-emphasis coefficient */
579 	if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
580 		uint16_t txdrv;
581 
582 		/* Fetch current TX driver parameters */
583 		txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
584 		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
585 
586 		/* Set 700mV drive strength */
587 		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
588 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
589 			    BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
590 
591 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
592 			    BHND_PCIE_APPLE_TX_IDRIVER_700MV);
593 		}
594 
595 		/* ... or, set max drive strength */
596 		if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
597 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
598 			    BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
599 
600 			txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
601 			    BHND_PCIE_APPLE_TX_IDRIVER_MAX);
602 		}
603 
604 		BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
605 		    BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
606 	}
607 
608 	return (0);
609 }
610 
611 /**
612  * Apply any hardware workarounds that are required upon detach or suspend
613  * of the bridge device.
614  */
615 static int
bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc * sc,bhnd_pci_war_state state)616 bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
617 {
618 	/* Reduce L1 timer for better power savings.
619 	 * TODO: We could enable/disable this on demand for better power
620 	 * savings if we tie this to HT clock request handling */
621 	if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
622 		uint32_t pmt;
623 		pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
624 		pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND;
625 		BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
626 	}
627 
628 	/* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
629 	if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
630 		uint16_t	lcreg;
631 
632 		lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
633 
634 		lcreg |= PCIEM_LINK_CTL_ECPM;	/* CLKREQ# */
635 		if (state == BHND_PCI_WAR_SUSPEND)
636 			lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
637 
638 		pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
639 	}
640 
641 	return (0);
642 }
643 
644 static device_method_t bhnd_pci_hostb_methods[] = {
645 	/* Device interface */
646 	DEVMETHOD(device_attach,		bhnd_pci_hostb_attach),
647 	DEVMETHOD(device_detach,		bhnd_pci_hostb_detach),
648 	DEVMETHOD(device_suspend,		bhnd_pci_hostb_suspend),
649 	DEVMETHOD(device_resume,		bhnd_pci_hostb_resume),
650 
651 	DEVMETHOD_END
652 };
653 
654 DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
655     sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
656 DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, 0, 0);
657 
658 MODULE_VERSION(bhnd_pci_hostb, 1);
659 MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);
660 MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);
661