]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
MFV r330102: ntp 4.2.8p11
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / cores / pci / bhnd_pci_hostb.c
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
177 #define BHND_PCI_SOFTC(_sc)     (&((_sc)->common))
178
179 #define BHND_PCI_READ_2(_sc, _reg)              \
180         bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
181
182 #define BHND_PCI_READ_4(_sc, _reg)              \
183         bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg))
184
185 #define BHND_PCI_WRITE_2(_sc, _reg, _val)       \
186         bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
187         
188 #define BHND_PCI_WRITE_4(_sc, _reg, _val)       \
189         bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val))
190
191 #define BHND_PCI_PROTO_READ_4(_sc, _reg)        \
192         bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg))
193
194 #define BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val) \
195         bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val))
196         
197 #define BHND_PCI_MDIO_READ(_sc, _phy, _reg)     \
198         bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg))
199
200 #define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)              \
201         bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
202
203 #define BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)               \
204         bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
205
206 #define BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)        \
207         bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),           \
208             (_devaddr), (_reg), (_val))
209
210 #define BPCI_REG_SET(_regv, _attr, _val)        \
211         BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
212
213 #define BPCI_REG_GET(_regv, _attr)      \
214         BHND_PCI_REG_GET((_regv), BHND_ ## _attr)
215
216 #define BPCI_CMN_REG_SET(_regv, _attr, _val)                    \
217         BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),      \
218             BHND_ ## _attr, (_val))
219
220 #define BPCI_CMN_REG_GET(_regv, _attr)                          \
221         BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv),      \
222             BHND_ ## _attr)
223
224 static int
225 bhnd_pci_hostb_attach(device_t dev)
226 {
227         struct bhnd_pcihb_softc *sc;
228         int                      error;
229
230         sc = device_get_softc(dev);
231         sc->dev = dev;
232         sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
233             sizeof(bhnd_pci_devs[0]));
234
235         /* Find the host PCI bridge device */
236         sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
237         if (sc->pci_dev == NULL) {
238                 device_printf(dev, "parent pci bridge device not found\n");
239                 return (ENXIO);
240         }
241
242         /* Common setup */
243         if ((error = bhnd_pci_generic_attach(dev)))
244                 return (error);
245
246         /* Apply early single-shot work-arounds */
247         if ((error = bhnd_pci_wars_early_once(sc)))
248                 goto failed;
249
250         /* Apply attach/resume work-arounds */
251         if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
252                 goto failed;
253
254         return (0);
255         
256 failed:
257         bhnd_pci_generic_detach(dev);
258         return (error);
259 }
260
261 static int
262 bhnd_pci_hostb_detach(device_t dev)
263 {
264         struct bhnd_pcihb_softc *sc;
265         int                      error;
266
267         sc = device_get_softc(dev);
268
269         /* Apply suspend/detach work-arounds */
270         if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
271                 return (error);
272
273         return (bhnd_pci_generic_detach(dev));
274 }
275
276 static int
277 bhnd_pci_hostb_suspend(device_t dev)
278 {
279         struct bhnd_pcihb_softc *sc;
280         int                      error;
281
282         sc = device_get_softc(dev);
283
284         /* Apply suspend/detach work-arounds */
285         if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
286                 return (error);
287
288         return (bhnd_pci_generic_suspend(dev));
289 }
290
291 static int
292 bhnd_pci_hostb_resume(device_t dev)
293 {
294         struct bhnd_pcihb_softc *sc;
295         int                      error;
296
297         sc = device_get_softc(dev);
298
299         if ((error = bhnd_pci_generic_resume(dev)))
300                 return (error);
301
302         /* Apply attach/resume work-arounds */
303         if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
304                 bhnd_pci_generic_detach(dev);
305                 return (error);
306         }
307
308         return (0);
309 }
310
311 /**
312  * Apply any hardware work-arounds that must be executed exactly once, early in
313  * the attach process.
314  * 
315  * This must be called after core enumeration and discovery of all applicable
316  * quirks, but prior to probe/attach of any cores, parsing of
317  * SPROM, etc.
318  */
319 static int
320 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
321 {
322         int error;
323
324         /* Set PCI latency timer */
325         if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
326                 pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
327                     1); 
328         }
329
330         /* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
331         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
332                 struct bhnd_board_info  board;
333                 bool                    aspm_en;
334
335                 /* Fetch board info */
336                 if ((error = bhnd_read_board_info(sc->dev, &board)))
337                         return (error);
338                 
339                 /* Check board flags */
340                 aspm_en = true;
341                 if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
342                         aspm_en = false;
343
344                 /* Early Apple devices did not (but should have) set
345                  * BHND_BFL2_PCIEWAR_OVR in SPROM. */
346                 if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
347                         aspm_en = false;
348
349                 sc->aspm_quirk_override.aspm_en = aspm_en;
350         }
351
352         /* Determine correct polarity by observing the attach-time PCIe PHY
353          * link status. This is used later to reset/force the SerDes
354          * polarity */
355         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
356                 uint32_t st;
357                 bool inv;
358
359                 st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
360                 inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
361                 sc->sdr9_quirk_polarity.inv = inv;
362         }
363
364         /* Override maximum read request size */
365         if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
366                 int     msize;
367
368                 msize = 128; /* compatible with all PCIe-G1 core revisions */
369                 if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
370                         msize = 512;
371
372                 if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
373                         panic("set mrrs on non-PCIe device");
374         }
375
376         return (0);
377 }
378
379 /**
380  * Apply any hardware workarounds that are required upon attach or resume
381  * of the bridge device.
382  */
383 static int
384 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
385 {
386         /* Note that the order here matters; these work-arounds
387          * should not be re-ordered without careful review of their
388          * interdependencies */
389
390         /* Enable PCI prefetch/burst/readmulti flags */
391         if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST ||
392             sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
393         {
394                 uint32_t sbp2;
395                 sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2);
396
397                 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST)
398                         sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST);
399
400                 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI)
401                         sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI;
402
403                 BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2);
404         }
405
406         /* Disable PCI CLKRUN# */
407         if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) {
408                 uint32_t ctl;
409         
410                 ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL);
411                 ctl |= BHND_PCI_CLKRUN_DSBL;
412                 BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl);
413         }
414         
415         /* Enable TLP unmatched address handling work-around */
416         if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) {
417                 uint32_t wrs;
418                 wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG);
419                 wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT;
420                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs);
421         }
422
423         /* Adjust SerDes CDR tuning to ensure that CDR is stable before sending
424          * data during L0s to L0 exit transitions. */
425         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) {
426                 uint16_t sdv;
427
428                 /* Set RX track/acquire timers to 2.064us/40.96us */
429                 sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16));
430                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ,
431                     (40960/1024));
432                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
433                     BHND_PCIE_SDR9_RX_TIMER1, sdv);
434
435                 /* Apply CDR frequency workaround */
436                 sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN;
437                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0);
438                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
439                     BHND_PCIE_SDR9_RX_CDR, sdv);
440
441                 /* Apply CDR BW tunings */
442                 sdv = 0;
443                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2);
444                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4);
445                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6);
446                 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6);
447                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
448                     BHND_PCIE_SDR9_RX_CDRBW, sdv);
449         }
450
451         /* Force correct SerDes polarity */
452         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) {
453                 uint16_t        rxctl;
454
455                 rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX,
456                     BHND_PCIE_SDR9_RX_CTRL);
457
458                 rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE;
459                 if (sc->sdr9_quirk_polarity.inv)
460                         rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
461                 else
462                         rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV;
463
464                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX,
465                     BHND_PCIE_SDR9_RX_CTRL, rxctl);
466         }
467
468         /* Disable startup retry on PLL frequency detection failure */
469         if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) {
470                 uint16_t        pctl;
471
472                 pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL,
473                     BHND_PCIE_SDR9_PLL_CTRL);
474
475                 pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN;
476                 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL,
477                     BHND_PCIE_SDR9_PLL_CTRL, pctl);
478         }
479         
480         /* Explicitly enable PCI-PM */
481         if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) {
482                 uint32_t lcreg;
483                 lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG);
484                 lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN;
485                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg);
486         }
487
488         /* Adjust L1 timer to fix slow L1->L0 transitions */
489         if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) {
490                 uint32_t pmt;
491                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
492                 pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME,
493                     BHND_PCIE_L1THRESHOLD_WARVAL);
494                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
495         }
496
497         /* Extend L1 timer for better performance.
498          * TODO: We could enable/disable this on demand for better power
499          * savings if we tie this to HT clock request handling */
500         if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
501                 uint32_t pmt;
502                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
503                 pmt |= BHND_PCIE_ASPMTIMER_EXTEND;
504                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
505         }
506
507         /* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
508         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
509                 bus_size_t      reg;
510                 uint16_t        cfg;
511
512                 /* Set ASPM L1/L0s flags in SPROM shadow */
513                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
514                 cfg = BHND_PCI_READ_2(sc, reg);
515
516                 if (sc->aspm_quirk_override.aspm_en)
517                         cfg |= BHND_PCIE_SRSH_ASPM_ENB;
518                 else
519                         cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
520                 
521                 BHND_PCI_WRITE_2(sc, reg, cfg);
522
523
524                 /* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
525                 cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
526
527                 if (sc->aspm_quirk_override.aspm_en)
528                         cfg |= PCIEM_LINK_CTL_ASPMC;
529                 else
530                         cfg &= ~PCIEM_LINK_CTL_ASPMC;
531
532                 cfg &= ~PCIEM_LINK_CTL_ECPM;            /* CLKREQ# */
533
534                 pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2); 
535
536                 /* Set CLKREQ (ECPM) flags in SPROM shadow */
537                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
538                 cfg = BHND_PCI_READ_2(sc, reg);
539                 
540                 if (sc->aspm_quirk_override.aspm_en)
541                         cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
542                 else
543                         cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
544
545                 BHND_PCI_WRITE_2(sc, reg, cfg);
546         }
547
548         /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
549         if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
550                 bus_size_t      reg;
551                 uint16_t        cfg;
552
553                 /* Fetch the misc cfg flags from SPROM */
554                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG;
555                 cfg = BHND_PCI_READ_2(sc, reg);
556
557                 /* Write EXIT_NOPRST flag if not already set in SPROM */
558                 if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) {
559                         cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST;
560                         BHND_PCI_WRITE_2(sc, reg, cfg);
561                 }
562         }
563
564         /* Disable SerDes PLL down */
565         if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
566                 device_t        bhnd, chipc;
567                 bus_size_t      reg;
568                 
569                 bhnd = device_get_parent(sc->dev);
570                 chipc = bhnd_bus_find_child(bhnd, BHND_DEVCLASS_CC, 0);
571                 KASSERT(chipc != NULL, ("missing chipcommon device"));
572
573                 /* Write SerDes PLL disable flag to the ChipCommon core */
574                 BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
575                     CHIPCTRL_4321_PLL_DOWN);
576
577                 /* Clear SPROM shadow backdoor register */
578                 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
579                 BHND_PCI_WRITE_2(sc, reg, 0);
580         }
581
582         /* Adjust TX drive strength and pre-emphasis coefficient */
583         if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
584                 uint16_t txdrv;
585
586                 /* Fetch current TX driver parameters */
587                 txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
588                     BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
589
590                 /* Set 700mV drive strength */
591                 if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
592                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
593                             BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
594
595                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
596                             BHND_PCIE_APPLE_TX_IDRIVER_700MV);
597                 }
598
599                 /* ... or, set max drive strength */
600                 if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
601                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
602                             BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
603                         
604                         txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
605                             BHND_PCIE_APPLE_TX_IDRIVER_MAX);
606                 }
607
608                 BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
609                     BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
610         }
611
612         return (0);
613 }
614
615 /**
616  * Apply any hardware workarounds that are required upon detach or suspend
617  * of the bridge device.
618  */
619 static int
620 bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
621 {
622         /* Reduce L1 timer for better power savings.
623          * TODO: We could enable/disable this on demand for better power
624          * savings if we tie this to HT clock request handling */
625         if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) {
626                 uint32_t pmt;
627                 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG);
628                 pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND;
629                 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
630         }
631
632         /* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
633         if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
634                 uint16_t        lcreg;
635
636                 lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
637
638                 lcreg |= PCIEM_LINK_CTL_ECPM;   /* CLKREQ# */
639                 if (state == BHND_PCI_WAR_SUSPEND)
640                         lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
641
642                 pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
643         }
644
645         return (0);
646 }
647
648 static device_method_t bhnd_pci_hostb_methods[] = {
649         /* Device interface */
650         DEVMETHOD(device_attach,                bhnd_pci_hostb_attach),
651         DEVMETHOD(device_detach,                bhnd_pci_hostb_detach),
652         DEVMETHOD(device_suspend,               bhnd_pci_hostb_suspend),
653         DEVMETHOD(device_resume,                bhnd_pci_hostb_resume), 
654
655         DEVMETHOD_END
656 };
657
658 DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, 
659     sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
660 DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
661
662 MODULE_VERSION(bhnd_pci_hostb, 1);
663 MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);
664 MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);