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 68static const struct bhnd_device_quirk bhnd_pci_quirks[]; 69static const struct bhnd_device_quirk bhnd_pcie_quirks[]; 70 71/* Device driver work-around variations */ 72typedef 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 79static int bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc); 80static int bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, 81 bhnd_pci_war_state state); 82static 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 92static 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 98static 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 111static 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 218static int 219bhnd_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 250failed: 251 bhnd_pci_generic_detach(dev); 252 return (error); 253} 254 255static int 256bhnd_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 270static int 271bhnd_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 285static int 286bhnd_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 */ 313static int 314bhnd_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 */ 377static int 378bhnd_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 */ 613static int 614bhnd_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 642static 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 652DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, 653 sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver); 654DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0); 655 656MODULE_VERSION(bhnd_pci_hostb, 1); 657MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1); 658MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1); 659