bhnd_pci_hostb.c revision 298479
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: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c 298479 2016-04-22 16:26:53Z adrian $"); 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 "bhnd_pcireg.h" 60#include "bhnd_pci_hostbvar.h" 61 62#define BHND_PCI_ASSERT_QUIRK(_sc, _name) \ 63 KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set")) 64 65#define BHND_PCI_DEV(_core, _quirks) \ 66 BHND_DEVICE(_core, "", _quirks, BHND_DF_HOSTB) 67 68static const struct bhnd_device_quirk bhnd_pci_quirks[]; 69static const struct bhnd_device_quirk bhnd_pcie_quirks[]; 70 71static int bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc); 72static int bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc); 73static int bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc); 74 75/* 76 * device/quirk tables 77 */ 78static const struct bhnd_device bhnd_pci_devs[] = { 79 BHND_PCI_DEV(PCI, bhnd_pci_quirks), 80 BHND_PCI_DEV(PCIE, bhnd_pcie_quirks), 81 BHND_DEVICE_END 82}; 83 84static const struct bhnd_device_quirk bhnd_pci_quirks[] = { 85 { BHND_HWREV_ANY, BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST }, 86 { BHND_HWREV_GTE(11), BHND_PCI_QUIRK_SBTOPCI2_READMULTI | 87 BHND_PCI_QUIRK_CLKRUN_DSBL }, 88 BHND_DEVICE_QUIRK_END 89}; 90 91static const struct bhnd_device_quirk bhnd_pcie_quirks[] = { 92 { BHND_HWREV_EQ (0), BHND_PCIE_QUIRK_SDR9_L0s_HANG }, 93 { BHND_HWREV_RANGE (0, 1), BHND_PCIE_QUIRK_UR_STATUS_FIX }, 94 { BHND_HWREV_EQ (1), BHND_PCIE_QUIRK_PCIPM_REQEN }, 95 96 { BHND_HWREV_RANGE (3, 5), BHND_PCIE_QUIRK_ASPM_OVR | 97 BHND_PCIE_QUIRK_SDR9_POLARITY | 98 BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY }, 99 100 { BHND_HWREV_LTE (6), BHND_PCIE_QUIRK_L1_IDLE_THRESH }, 101 { BHND_HWREV_GTE (6), BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET }, 102 { BHND_HWREV_EQ (7), BHND_PCIE_QUIRK_SERDES_NOPLLDOWN }, 103 { BHND_HWREV_GTE (8), BHND_PCIE_QUIRK_L1_TIMER_PERF }, 104 { BHND_HWREV_GTE (10), BHND_PCIE_QUIRK_SD_C22_EXTADDR }, 105 BHND_DEVICE_QUIRK_END 106}; 107 108// Quirk handling TODO 109// WARs for the following are not yet implemented: 110// - BHND_PCIE_QUIRK_ASPM_OVR 111// - BHND_PCIE_QUIRK_SERDES_NOPLLDOWN 112// Quirks (and WARs) for the following are not yet defined: 113// - Power savings via MDIO BLK1/PWR_MGMT3 on PCIe hwrev 15-20, 21-22 114// - WOWL PME enable/disable 115// - 4360 PCIe SerDes Tx amplitude/deemphasis (vendor Apple, boards 116// BCM94360X51P2, BCM94360X51A). 117// - PCI latency timer (boards CB2_4321_BOARD, CB2_4321_AG_BOARD) 118// - Max SerDes TX drive strength (vendor Apple, pcie >= rev10, 119// board BCM94322X9) 120// - 700mV SerDes TX drive strength (chipid BCM4331, boards BCM94331X19, 121// BCM94331X28, BCM94331X29B, BCM94331X19C) 122 123#define BHND_PCI_SOFTC(_sc) (&((_sc)->common)) 124 125#define BHND_PCI_READ_2(_sc, _reg) \ 126 bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg)) 127 128#define BHND_PCI_READ_4(_sc, _reg) \ 129 bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg)) 130 131#define BHND_PCI_WRITE_2(_sc, _reg, _val) \ 132 bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val)) 133 134#define BHND_PCI_WRITE_4(_sc, _reg, _val) \ 135 bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val)) 136 137#define BHND_PCI_PROTO_READ_4(_sc, _reg) \ 138 bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg)) 139 140#define BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val) \ 141 bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val)) 142 143#define BHND_PCI_MDIO_READ(_sc, _phy, _reg) \ 144 bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg)) 145 146#define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val) \ 147 bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val)) 148 149#define BPCI_REG_SET(_regv, _attr, _val) \ 150 BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val)) 151 152#define BPCI_REG_GET(_regv, _attr) \ 153 BHND_PCI_REG_GET((_regv), BHND_ ## _attr) 154 155#define BPCI_CMN_REG_SET(_regv, _attr, _val) \ 156 BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv), \ 157 BHND_ ## _attr, (_val)) 158 159#define BPCI_CMN_REG_GET(_regv, _attr) \ 160 BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv), \ 161 BHND_ ## _attr) 162 163static int 164bhnd_pci_hostb_attach(device_t dev) 165{ 166 struct bhnd_pcihb_softc *sc; 167 int error; 168 169 sc = device_get_softc(dev); 170 sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs, 171 sizeof(bhnd_pci_devs[0])); 172 173 if ((error = bhnd_pci_generic_attach(dev))) 174 return (error); 175 176 /* Apply early single-shot work-arounds */ 177 if ((error = bhnd_pci_wars_early_once(sc))) { 178 bhnd_pci_generic_detach(dev); 179 return (error); 180 } 181 182 /* Apply attach/resume work-arounds */ 183 if ((error = bhnd_pci_wars_hwup(sc))) { 184 bhnd_pci_generic_detach(dev); 185 return (error); 186 } 187 188 189 return (0); 190} 191 192static int 193bhnd_pci_hostb_detach(device_t dev) 194{ 195 struct bhnd_pcihb_softc *sc; 196 int error; 197 198 sc = device_get_softc(dev); 199 200 /* Apply suspend/detach work-arounds */ 201 if ((error = bhnd_pci_wars_hwdown(sc))) 202 return (error); 203 204 return (bhnd_pci_generic_detach(dev)); 205} 206 207static int 208bhnd_pci_hostb_suspend(device_t dev) 209{ 210 struct bhnd_pcihb_softc *sc; 211 int error; 212 213 sc = device_get_softc(dev); 214 215 /* Apply suspend/detach work-arounds */ 216 if ((error = bhnd_pci_wars_hwdown(sc))) 217 return (error); 218 219 return (bhnd_pci_generic_suspend(dev)); 220} 221 222static int 223bhnd_pci_hostb_resume(device_t dev) 224{ 225 struct bhnd_pcihb_softc *sc; 226 int error; 227 228 sc = device_get_softc(dev); 229 230 if ((error = bhnd_pci_generic_resume(dev))) 231 return (error); 232 233 /* Apply attach/resume work-arounds */ 234 if ((error = bhnd_pci_wars_hwup(sc))) { 235 bhnd_pci_generic_detach(dev); 236 return (error); 237 } 238 239 return (0); 240} 241 242/** 243 * Apply any hardware work-arounds that must be executed exactly once, early in 244 * the attach process. 245 * 246 * This must be called after core enumeration and discovery of all applicable 247 * quirks, but prior to probe/attach of any cores, parsing of 248 * SPROM, etc. 249 */ 250static int 251bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc) 252{ 253 /* Determine correct polarity by observing the attach-time PCIe PHY 254 * link status. This is used later to reset/force the SerDes 255 * polarity */ 256 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) { 257 uint32_t st; 258 bool inv; 259 260 261 st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG); 262 inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0); 263 sc->sdr9_quirk_polarity.inv = inv; 264 } 265 266 return (0); 267} 268 269/** 270 * Apply any hardware workarounds that are required upon attach or resume 271 * of the bridge device. 272 */ 273static int 274bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc) 275{ 276 /* Note that the order here matters; these work-arounds 277 * should not be re-ordered without careful review of their 278 * interdependencies */ 279 280 /* Enable PCI prefetch/burst/readmulti flags */ 281 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST || 282 sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI) 283 { 284 uint32_t sbp2; 285 sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2); 286 287 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST) 288 sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST); 289 290 if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI) 291 sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI; 292 293 BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2); 294 } 295 296 /* Disable PCI CLKRUN# */ 297 if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) { 298 uint32_t ctl; 299 300 ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL); 301 ctl |= BHND_PCI_CLKRUN_DSBL; 302 BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl); 303 } 304 305 /* Enable TLP unmatched address handling work-around */ 306 if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) { 307 uint32_t wrs; 308 wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG); 309 wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT; 310 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs); 311 } 312 313 /* Adjust SerDes CDR tuning to ensure that CDR is stable before sending 314 * data during L0s to L0 exit transitions. */ 315 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) { 316 uint16_t sdv; 317 318 /* Set RX track/acquire timers to 2.064us/40.96us */ 319 sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16)); 320 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ, 321 (40960/1024)); 322 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, 323 BHND_PCIE_SDR9_RX_TIMER1, sdv); 324 325 /* Apply CDR frequency workaround */ 326 sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN; 327 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0); 328 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, 329 BHND_PCIE_SDR9_RX_CDR, sdv); 330 331 /* Apply CDR BW tunings */ 332 sdv = 0; 333 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2); 334 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4); 335 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6); 336 sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6); 337 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, 338 BHND_PCIE_SDR9_RX_CDRBW, sdv); 339 } 340 341 /* Force correct SerDes polarity */ 342 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) { 343 uint16_t rxctl; 344 345 rxctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_TXRX, 346 BHND_PCIE_SDR9_RX_CTRL); 347 348 rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE; 349 if (sc->sdr9_quirk_polarity.inv) 350 rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV; 351 else 352 rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV; 353 354 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, 355 BHND_PCIE_SDR9_RX_CTRL, rxctl); 356 } 357 358 /* Disable startup retry on PLL frequency detection failure */ 359 if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) { 360 uint16_t pctl; 361 362 pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL, 363 BHND_PCIE_SDR9_PLL_CTRL); 364 365 pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN; 366 BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL, 367 BHND_PCIE_SDR9_PLL_CTRL, pctl); 368 } 369 370 /* Explicitly enable PCI-PM */ 371 if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) { 372 uint32_t lcreg; 373 lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG); 374 lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN; 375 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg); 376 } 377 378 /* Adjust L1 timer to fix slow L1->L0 transitions */ 379 if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) { 380 uint32_t pmt; 381 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG); 382 pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME, 383 BHND_PCIE_L1THRESHOLD_WARVAL); 384 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); 385 } 386 387 /* Extend L1 timer for better performance. 388 * TODO: We could enable/disable this on demand for better power 389 * savings if we tie this to HT clock request handling */ 390 if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) { 391 uint32_t pmt; 392 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG); 393 pmt |= BHND_PCIE_ASPMTIMER_EXTEND; 394 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); 395 } 396 397 /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */ 398 if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) { 399 bus_size_t reg; 400 uint16_t cfg; 401 402 /* Fetch the misc cfg flags from SPROM */ 403 reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG; 404 cfg = BHND_PCI_READ_2(sc, reg); 405 406 /* Write EXIT_NOPRST flag if not already set in SPROM */ 407 if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) { 408 cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST; 409 BHND_PCI_WRITE_2(sc, reg, cfg); 410 } 411 } 412 413 return (0); 414} 415 416/** 417 * Apply any hardware workarounds that are required upon detach or suspend 418 * of the bridge device. 419 */ 420static int 421bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc) 422{ 423 /* Reduce L1 timer for better power savings. 424 * TODO: We could enable/disable this on demand for better power 425 * savings if we tie this to HT clock request handling */ 426 if (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) { 427 uint32_t pmt; 428 pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG); 429 pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND; 430 BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); 431 } 432 433 return (0); 434} 435 436static device_method_t bhnd_pci_hostb_methods[] = { 437 /* Device interface */ 438 DEVMETHOD(device_attach, bhnd_pci_hostb_attach), 439 DEVMETHOD(device_detach, bhnd_pci_hostb_detach), 440 DEVMETHOD(device_suspend, bhnd_pci_hostb_suspend), 441 DEVMETHOD(device_resume, bhnd_pci_hostb_resume), 442 443 DEVMETHOD_END 444}; 445 446DEFINE_CLASS_1(bhnd_pci_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, 447 sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver); 448 449DRIVER_MODULE(bhnd_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0); 450 451MODULE_VERSION(bhnd_pci_hostb, 1); 452MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1); 453