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