]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
MFV r323530,r323533,r323534: 7431 ZFS Channel Programs, and followups
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / cores / pci / bhnd_pci_hostb.c
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * Copyright (c) 2017 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Landon Fuller
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17  *    redistribution must be conditioned upon including a substantially
18  *    similar Disclaimer requirement for further binary redistribution.
19  *
20  * NO WARRANTY
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGES.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
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_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_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
175 #define BHND_PCI_SOFTC(_sc)     (&((_sc)->common))
176
177 #define BHND_PCI_READ_2(_sc, _reg)              \
178         bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
179
180 #define BHND_PCI_READ_4(_sc, _reg)              \
181         bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
182
183 #define BHND_PCI_WRITE_2(_sc, _reg, _val)       \
184         bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
185         
186 #define BHND_PCI_WRITE_4(_sc, _reg, _val)       \
187         bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
188
189 #define BHND_PCI_PROTO_READ_4(_sc, _reg)        \
190         bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
191
192 #define BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val) \
193         bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
194         
195 #define BHND_PCI_MDIO_READ(_sc, _phy, _reg)     \
196         bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
197
198 #define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)              \
199         bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
200
201 #define BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)               \
202         bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
203
204 #define BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)        \
205         bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),           \
206             (_devaddr), (_reg), (_val))
207
208 #define BPCI_REG_SET(_regv, _attr, _val)        \
209         BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
210
211 #define BPCI_REG_GET(_regv, _attr)      \
212         BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
213
214 #define BPCI_CMN_REG_SET(_regv, _attr, _val)                    \
215         BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),      \
216             BHND_ ## _attr, (_val))
217
218 #define BPCI_CMN_REG_GET(_regv, _attr)                          \
219         BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),      \
220             BHND_ ## _attr)
221
222 static int
223 bhnd_pci_hostb_attach(device_t dev)
224 {
225         struct bhnd_pcihb_softc *sc;
226         int                      error;
227
228         sc = device_get_softc(dev);
229         sc->dev = dev;
230         sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
231             sizeof(bhnd_pci_devs[0]));
232
233         /* Find the host PCI bridge device */
234         sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
235         if (sc->pci_dev == NULL) {
236                 device_printf(dev, "parent pci bridge device not found\n");
237                 return (ENXIO);
238         }
239
240         /* Common setup */
241         if ((error = bhnd_pci_generic_attach(dev)))
242                 return (error);
243
244         /* Apply early single-shot work-arounds */
245         if ((error = bhnd_pci_wars_early_once(sc)))
246                 goto failed;
247
248         /* Apply attach/resume work-arounds */
249         if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
250                 goto failed;
251
252         return (0);
253         
254 failed:
255         bhnd_pci_generic_detach(dev);
256         return (error);
257 }
258
259 static int
260 bhnd_pci_hostb_detach(device_t dev)
261 {
262         struct bhnd_pcihb_softc *sc;
263         int                      error;
264
265         sc = device_get_softc(dev);
266
267         /* Apply suspend/detach work-arounds */
268         if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
269                 return (error);
270
271         return (bhnd_pci_generic_detach(dev));
272 }
273
274 static int
275 bhnd_pci_hostb_suspend(device_t dev)
276 {
277         struct bhnd_pcihb_softc *sc;
278         int                      error;
279
280         sc = device_get_softc(dev);
281
282         /* Apply suspend/detach work-arounds */
283         if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
284                 return (error);
285
286         return (bhnd_pci_generic_suspend(dev));
287 }
288
289 static int
290 bhnd_pci_hostb_resume(device_t dev)
291 {
292         struct bhnd_pcihb_softc *sc;
293         int                      error;
294
295         sc = device_get_softc(dev);
296
297         if ((error = bhnd_pci_generic_resume(dev)))
298                 return (error);
299
300         /* Apply attach/resume work-arounds */
301         if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
302                 bhnd_pci_generic_detach(dev);
303                 return (error);
304         }
305
306         return (0);
307 }
308
309 /**
310  * Apply any hardware work-arounds that must be executed exactly once, early in
311  * the attach process.
312  * 
313  * This must be called after core enumeration and discovery of all applicable
314  * quirks, but prior to probe/attach of any cores, parsing of
315  * SPROM, etc.
316  */
317 static int
318 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
319 {
320         int error;
321
322         /* Set PCI latency timer */
323         if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
324                 pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
325                     1); 
326         }
327
328         /* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
329         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
330                 struct bhnd_board_info  board;
331                 bool                    aspm_en;
332
333                 /* Fetch board info */
334                 if ((error = bhnd_read_board_info(sc->dev, &board)))
335                         return (error);
336                 
337                 /* Check board flags */
338                 aspm_en = true;
339                 if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
340                         aspm_en = false;
341
342                 /* Early Apple devices did not (but should have) set
343                  * BHND_BFL2_PCIEWAR_OVR in SPROM. */
344                 if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
345                         aspm_en = false;
346
347                 sc->aspm_quirk_override.aspm_en = aspm_en;
348         }
349
350         /* Determine correct polarity by observing the attach-time PCIe PHY
351          * link status. This is used later to reset/force the SerDes
352          * polarity */
353         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
354                 uint32_t st;
355                 bool inv;
356
357                 st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
358                 inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
359                 sc->sdr9_quirk_polarity.inv = inv;
360         }
361
362         /* Override maximum read request size */
363         if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
364                 int     msize;
365
366                 msize = 128; /* compatible with all PCIe-G1 core revisions */
367                 if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
368                         msize = 512;
369
370                 if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
371                         panic("set mrrs on non-PCIe device");
372         }
373
374         return (0);
375 }
376
377 /**
378  * Apply any hardware workarounds that are required upon attach or resume
379  * of the bridge device.
380  */
381 static int
382 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
383 {
384         /* Note that the order here matters; these work-arounds
385          * should not be re-ordered without careful review of their
386          * interdependencies */
387
388         /* Enable PCI prefetch/burst/readmulti flags */
389         if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
390             sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
391         {
392                 uint32_t sbp2;
393                 sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
394
395                 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
396                         sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
397
398                 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
399                         sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
400
401                 BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
402         }
403
404         /* Disable PCI CLKRUN# */
405         if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
406                 uint32_t ctl;
407         
408                 ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
409                 ctl |= BHND_PCI_CLKRUN_DSBL;
410                 BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
411         }
412         
413         /* Enable TLP unmatched address handling work-around */
414         if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
415                 uint32_t wrs;
416                 wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
417                 wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
418                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
419         }
420
421         /* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
422          * data during L0s to L0 exit transitions. */
423         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
424                 uint16_t sdv;
425
426                 /* Set RX track/acquire timers to 2.064us/40.96us */
427                 sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
428                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
429                     (40960/1024));
430                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
431                     BHND_PCIE_SDR9_RX_TIMER1, sdv);
432
433                 /* Apply CDR frequency workaround */
434                 sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
435                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
436                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
437                     BHND_PCIE_SDR9_RX_CDR, sdv);
438
439                 /* Apply CDR BW tunings */
440                 sdv = 0;
441                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
442                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
443                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
444                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
445                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
446                     BHND_PCIE_SDR9_RX_CDRBW, sdv);
447         }
448
449         /* Force correct SerDes polarity */
450         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
451                 uint16_t        rxctl;
452
453                 rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
454                     BHND_PCIE_SDR9_RX_CTRL);
455
456                 rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
457                 if (sc->sdr9_quirk_polarity.inv)
458                         rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
459                 else
460                         rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
461
462                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
463                     BHND_PCIE_SDR9_RX_CTRL, rxctl);
464         }
465
466         /* Disable startup retry on PLL frequency detection failure */
467         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
468                 uint16_t        pctl;
469
470                 pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
471                     BHND_PCIE_SDR9_PLL_CTRL);
472
473                 pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
474                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
475                     BHND_PCIE_SDR9_PLL_CTRL, pctl);
476         }
477         
478         /* Explicitly enable PCI-PM */
479         if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
480                 uint32_t lcreg;
481                 lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
482                 lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
483                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
484         }
485
486         /* Adjust L1 timer to fix slow L1->L0 transitions */
487         if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
488                 uint32_t pmt;
489                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
490                 pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
491                     BHND_PCIE_L1THRESHOLD_WARVAL);
492                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
493         }
494
495         /* Extend L1 timer for better performance.
496          * TODO: We could enable/disable this on demand for better power
497          * savings if we tie this to HT clock request handling */
498         if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
499                 uint32_t pmt;
500                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
501                 pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
502                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
503         }
504
505         /* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
506         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
507                 bus_size_t      reg;
508                 uint16_t        cfg;
509
510                 /* Set ASPM L1/L0s flags in SPROM shadow */
511                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
512                 cfg = BHND_PCI_READ_2(sc, reg);
513
514                 if (sc->aspm_quirk_override.aspm_en)
515                         cfg |= BHND_PCIE_SRSH_ASPM_ENB;
516                 else
517                         cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
518                 
519                 BHND_PCI_WRITE_2(sc, reg, cfg);
520
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, bhnd_hostb_devclass, 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);