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);
Cache object: f45f64b0be35d1d8f2cc3ae1cb085225
|