]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r305575, and update
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / cores / pci / bhnd_pci_hostb.c
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
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
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
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
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
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
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
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);