2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
34 * Broadcom BHND PCI/PCIe-Gen1 PCI-Host Bridge.
36 * This driver handles all interactions with PCI bridge cores operating in
39 * Host-level PCI operations are handled at the bhndb bridge level by the
43 #include <sys/param.h>
44 #include <sys/kernel.h>
46 #include <sys/malloc.h>
49 #include <sys/module.h>
51 #include <sys/systm.h>
53 #include <machine/bus.h>
55 #include <machine/resource.h>
57 #include <dev/bhnd/bhnd.h>
59 #include <dev/pci/pcireg.h>
60 #include <dev/pci/pcivar.h>
62 #include <dev/bhnd/cores/chipc/chipc.h>
63 #include <dev/bhnd/cores/chipc/chipcreg.h>
65 #include "bhnd_pcireg.h"
66 #include "bhnd_pci_hostbvar.h"
68 static const struct bhnd_device_quirk bhnd_pci_quirks[];
69 static const struct bhnd_device_quirk bhnd_pcie_quirks[];
71 /* Device driver work-around variations */
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 */
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);
89 #define BHND_PCI_DEV(_core, _quirks) \
90 BHND_DEVICE(BCM, _core, NULL, _quirks, BHND_DF_HOSTB)
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),
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),
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),
108 BHND_DEVICE_QUIRK_END
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),
117 BHND_CORE_QUIRK (HWREV_EQ (1), BHND_PCIE_QUIRK_PCIPM_REQEN),
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),
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),
128 BHND_CORE_QUIRK (HWREV_LTE(17), BHND_PCIE_QUIRK_MAX_MRRS_128),
130 /* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
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 },
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 },
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__ }
147 BHND_A4331_QUIRK(BCM94331X19, BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
148 BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
150 BHND_A4331_QUIRK(BCM94331X28, BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
151 BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
153 BHND_A4331_QUIRK(BCM94331X28B, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
155 BHND_A4331_QUIRK(BCM94331X29B, BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
156 BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
158 BHND_A4331_QUIRK(BCM94331X19C, BHND_PCIE_QUIRK_SERDES_TXDRV_MAX |
159 BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
161 BHND_A4331_QUIRK(BCM94331X29D, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
163 BHND_A4331_QUIRK(BCM94331X33, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
165 #undef BHND_A4331_QUIRK
167 BHND_DEVICE_QUIRK_END
171 #define BHND_PCI_SOFTC(_sc) (&((_sc)->common))
173 #define BHND_PCI_READ_2(_sc, _reg) \
174 bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
176 #define BHND_PCI_READ_4(_sc, _reg) \
177 bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
179 #define BHND_PCI_WRITE_2(_sc, _reg, _val) \
180 bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
182 #define BHND_PCI_WRITE_4(_sc, _reg, _val) \
183 bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
185 #define BHND_PCI_PROTO_READ_4(_sc, _reg) \
186 bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
188 #define BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val) \
189 bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
191 #define BHND_PCI_MDIO_READ(_sc, _phy, _reg) \
192 bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
194 #define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val) \
195 bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
197 #define BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg) \
198 bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
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))
204 #define BPCI_REG_SET(_regv, _attr, _val) \
205 BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
207 #define BPCI_REG_GET(_regv, _attr) \
208 BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
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))
214 #define BPCI_CMN_REG_GET(_regv, _attr) \
215 BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv), \
219 bhnd_pci_hostb_attach(device_t dev)
221 struct bhnd_pcihb_softc *sc;
224 sc = device_get_softc(dev);
226 sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
227 sizeof(bhnd_pci_devs[0]));
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");
237 if ((error = bhnd_pci_generic_attach(dev)))
240 /* Apply early single-shot work-arounds */
241 if ((error = bhnd_pci_wars_early_once(sc)))
244 /* Apply attach/resume work-arounds */
245 if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
251 bhnd_pci_generic_detach(dev);
256 bhnd_pci_hostb_detach(device_t dev)
258 struct bhnd_pcihb_softc *sc;
261 sc = device_get_softc(dev);
263 /* Apply suspend/detach work-arounds */
264 if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
267 return (bhnd_pci_generic_detach(dev));
271 bhnd_pci_hostb_suspend(device_t dev)
273 struct bhnd_pcihb_softc *sc;
276 sc = device_get_softc(dev);
278 /* Apply suspend/detach work-arounds */
279 if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
282 return (bhnd_pci_generic_suspend(dev));
286 bhnd_pci_hostb_resume(device_t dev)
288 struct bhnd_pcihb_softc *sc;
291 sc = device_get_softc(dev);
293 if ((error = bhnd_pci_generic_resume(dev)))
296 /* Apply attach/resume work-arounds */
297 if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
298 bhnd_pci_generic_detach(dev);
306 * Apply any hardware work-arounds that must be executed exactly once, early in
307 * the attach process.
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
314 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
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 */,
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;
329 /* Fetch board info */
330 if ((error = bhnd_read_board_info(sc->dev, &board)))
333 /* Check board flags */
335 if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
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)
343 sc->aspm_quirk_override.aspm_en = aspm_en;
346 /* Determine correct polarity by observing the attach-time PCIe PHY
347 * link status. This is used later to reset/force the SerDes
349 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
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;
358 /* Override maximum read request size */
359 if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
362 msize = 128; /* compatible with all PCIe-G1 core revisions */
363 if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
366 if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
367 panic("set mrrs on non-PCIe device");
374 * Apply any hardware workarounds that are required upon attach or resume
375 * of the bridge device.
378 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
380 /* Note that the order here matters; these work-arounds
381 * should not be re-ordered without careful review of their
382 * interdependencies */
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)
389 sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
391 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
392 sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
394 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
395 sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
397 BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
400 /* Disable PCI CLKRUN# */
401 if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
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);
409 /* Enable TLP unmatched address handling work-around */
410 if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
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);
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) {
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,
426 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
427 BHND_PCIE_SDR9_RX_TIMER1, sdv);
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);
435 /* Apply CDR BW tunings */
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);
445 /* Force correct SerDes polarity */
446 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
449 rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
450 BHND_PCIE_SDR9_RX_CTRL);
452 rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
453 if (sc->sdr9_quirk_polarity.inv)
454 rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
456 rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
458 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
459 BHND_PCIE_SDR9_RX_CTRL, rxctl);
462 /* Disable startup retry on PLL frequency detection failure */
463 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
466 pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
467 BHND_PCIE_SDR9_PLL_CTRL);
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);
474 /* Explicitly enable PCI-PM */
475 if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
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);
482 /* Adjust L1 timer to fix slow L1->L0 transitions */
483 if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
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);
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) {
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);
501 /* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
502 if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
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);
510 if (sc->aspm_quirk_override.aspm_en)
511 cfg |= BHND_PCIE_SRSH_ASPM_ENB;
513 cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
515 BHND_PCI_WRITE_2(sc, reg, cfg);
518 /* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
519 cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
521 if (sc->aspm_quirk_override.aspm_en)
522 cfg |= PCIEM_LINK_CTL_ASPMC;
524 cfg &= ~PCIEM_LINK_CTL_ASPMC;
526 cfg &= ~PCIEM_LINK_CTL_ECPM; /* CLKREQ# */
528 pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2);
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);
534 if (sc->aspm_quirk_override.aspm_en)
535 cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
537 cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
539 BHND_PCI_WRITE_2(sc, reg, cfg);
542 /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
543 if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
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);
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);
558 /* Disable SerDes PLL down */
559 if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
560 device_t bhnd, chipc;
563 bhnd = device_get_parent(sc->dev);
564 chipc = bhnd_find_child(bhnd, BHND_DEVCLASS_CC, 0);
565 KASSERT(chipc != NULL, ("missing chipcommon device"));
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);
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);
576 /* Adjust TX drive strength and pre-emphasis coefficient */
577 if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
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);
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);
589 txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
590 BHND_PCIE_APPLE_TX_IDRIVER_700MV);
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);
598 txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
599 BHND_PCIE_APPLE_TX_IDRIVER_MAX);
602 BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
603 BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
610 * Apply any hardware workarounds that are required upon detach or suspend
611 * of the bridge device.
614 bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
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) {
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);
626 /* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
627 if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
630 lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
632 lcreg |= PCIEM_LINK_CTL_ECPM; /* CLKREQ# */
633 if (state == BHND_PCI_WAR_SUSPEND)
634 lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
636 pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
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),
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);
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);