1 /*- 2 * Copyright (c) 2015-2016 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 * PCI-specific implementation for the BHNDB bridge driver. 35 * 36 * Provides support for bridging from a PCI parent bus to a BHND-compatible 37 * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point 38 * mode. 39 * 40 * This driver handles all initial generic host-level PCI interactions with a 41 * PCI/PCIe bridge core operating in endpoint mode. Once the bridged bhnd(4) 42 * bus has been enumerated, this driver works in tandem with a core-specific 43 * bhnd_pci_hostb driver to manage the PCI core. 44 */ 45 46 #include <sys/param.h> 47 #include <sys/kernel.h> 48 #include <sys/bus.h> 49 #include <sys/limits.h> 50 #include <sys/malloc.h> 51 #include <sys/module.h> 52 #include <sys/systm.h> 53 54 #include <dev/pci/pcireg.h> 55 #include <dev/pci/pcivar.h> 56 57 #include <dev/bhnd/bhnd.h> 58 59 #include <dev/bhnd/cores/pci/bhnd_pcireg.h> 60 61 #include "bhndb_pcireg.h" 62 #include "bhndb_pcivar.h" 63 #include "bhndb_private.h" 64 65 static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc); 66 static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc); 67 68 static int bhndb_pci_compat_setregwin(struct bhndb_pci_softc *, 69 const struct bhndb_regwin *, bhnd_addr_t); 70 static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, 71 const struct bhndb_regwin *, bhnd_addr_t); 72 73 static void bhndb_init_sromless_pci_config( 74 struct bhndb_pci_softc *sc); 75 76 static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc); 77 static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc); 78 79 /** 80 * Default bhndb_pci implementation of device_probe(). 81 * 82 * Verifies that the parent is a PCI/PCIe device. 83 */ 84 static int 85 bhndb_pci_probe(device_t dev) 86 { 87 device_t parent; 88 devclass_t parent_bus; 89 devclass_t pci; 90 91 /* Our parent must be a PCI/PCIe device. */ 92 pci = devclass_find("pci"); 93 parent = device_get_parent(dev); 94 parent_bus = device_get_devclass(device_get_parent(parent)); 95 96 if (parent_bus != pci) 97 return (ENXIO); 98 99 device_set_desc(dev, "PCI-BHND bridge"); 100 101 return (BUS_PROBE_DEFAULT); 102 } 103 104 static int 105 bhndb_pci_attach(device_t dev) 106 { 107 struct bhndb_pci_softc *sc; 108 int error, reg; 109 110 sc = device_get_softc(dev); 111 sc->dev = dev; 112 sc->parent = device_get_parent(dev); 113 114 /* Enable PCI bus mastering */ 115 pci_enable_busmaster(sc->parent); 116 117 /* Determine our bridge device class */ 118 sc->pci_devclass = BHND_DEVCLASS_PCI; 119 if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0) 120 sc->pci_devclass = BHND_DEVCLASS_PCIE; 121 122 /* Enable clocks (if supported by this hardware) */ 123 if ((error = bhndb_enable_pci_clocks(sc))) 124 return (error); 125 126 /* Use siba(4)-compatible regwin handling until we know 127 * what kind of bus is attached */ 128 sc->set_regwin = bhndb_pci_compat_setregwin; 129 130 /* Perform full bridge attach. This should call back into our 131 * bhndb_pci_init_full_config() implementation once the bridged 132 * bhnd(4) bus has been enumerated, but before any devices have been 133 * probed or attached. */ 134 if ((error = bhndb_attach(dev, sc->pci_devclass))) 135 return (error); 136 137 /* If supported, switch to the faster regwin handling */ 138 if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) { 139 atomic_store_rel_ptr((volatile void *) &sc->set_regwin, 140 (uintptr_t) &bhndb_pci_fast_setregwin); 141 } 142 143 return (0); 144 } 145 146 static int 147 bhndb_pci_init_full_config(device_t dev, device_t child, 148 const struct bhndb_hw_priority *hw_prio_table) 149 { 150 struct bhndb_pci_softc *sc; 151 device_t nv_dev; 152 bus_size_t nv_sz; 153 int error; 154 155 sc = device_get_softc(dev); 156 157 /* Let our parent perform standard initialization first */ 158 if ((error = bhndb_generic_init_full_config(dev, child, hw_prio_table))) 159 return (error); 160 161 /* Fix-up power on defaults for SROM-less devices. */ 162 bhndb_init_sromless_pci_config(sc); 163 164 /* If SPROM is mapped directly into BAR0, add NVRAM device. */ 165 nv_sz = bhndb_pci_sprom_size(sc); 166 if (nv_sz > 0) { 167 struct bhndb_devinfo *dinfo; 168 const char *dname; 169 170 if (bootverbose) { 171 device_printf(dev, "found SPROM (%u bytes)\n", 172 (unsigned int) nv_sz); 173 } 174 175 /* Add sprom device */ 176 dname = "bhnd_nvram"; 177 if ((nv_dev = BUS_ADD_CHILD(dev, 0, dname, -1)) == NULL) { 178 device_printf(dev, "failed to add sprom device\n"); 179 return (ENXIO); 180 } 181 182 /* Initialize device address space and resource covering the 183 * BAR0 SPROM shadow. */ 184 dinfo = device_get_ivars(nv_dev); 185 dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; 186 error = bus_set_resource(nv_dev, SYS_RES_MEMORY, 0, 187 bhndb_pci_sprom_addr(sc), nv_sz); 188 189 if (error) { 190 device_printf(dev, 191 "failed to register sprom resources\n"); 192 return (error); 193 } 194 195 /* Attach the device */ 196 if ((error = device_probe_and_attach(nv_dev))) { 197 device_printf(dev, "sprom attach failed\n"); 198 return (error); 199 } 200 } 201 202 return (0); 203 } 204 205 static const struct bhndb_regwin * 206 bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc) 207 { 208 struct bhndb_resources *bres; 209 const struct bhndb_hwcfg *cfg; 210 const struct bhndb_regwin *sprom_win; 211 212 bres = sc->bhndb.bus_res; 213 cfg = bres->cfg; 214 215 sprom_win = bhndb_regwin_find_type(cfg->register_windows, 216 BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE); 217 218 return (sprom_win); 219 } 220 221 static bus_addr_t 222 bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc) 223 { 224 const struct bhndb_regwin *sprom_win; 225 struct resource *r; 226 227 /* Fetch the SPROM register window */ 228 sprom_win = bhndb_pci_sprom_regwin(sc); 229 KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+")); 230 231 /* Fetch the associated resource */ 232 r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win); 233 KASSERT(r != NULL, ("missing resource for sprom window\n")); 234 235 return (rman_get_start(r) + sprom_win->win_offset); 236 } 237 238 static bus_size_t 239 bhndb_pci_sprom_size(struct bhndb_pci_softc *sc) 240 { 241 const struct bhndb_regwin *sprom_win; 242 uint32_t sctl; 243 bus_size_t sprom_sz; 244 245 sprom_win = bhndb_pci_sprom_regwin(sc); 246 247 /* PCI_V2 and later devices map SPROM/OTP via ChipCommon */ 248 if (sprom_win == NULL) 249 return (0); 250 251 /* Determine SPROM size */ 252 sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4); 253 if (sctl & BHNDB_PCI_SPROM_BLANK) 254 return (0); 255 256 switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) { 257 case BHNDB_PCI_SPROM_SZ_1KB: 258 sprom_sz = (1 * 1024); 259 break; 260 261 case BHNDB_PCI_SPROM_SZ_4KB: 262 sprom_sz = (4 * 1024); 263 break; 264 265 case BHNDB_PCI_SPROM_SZ_16KB: 266 sprom_sz = (16 * 1024); 267 break; 268 269 case BHNDB_PCI_SPROM_SZ_RESERVED: 270 default: 271 device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl); 272 return (0); 273 } 274 275 if (sprom_sz > sprom_win->win_size) { 276 device_printf(sc->dev, 277 "PCI sprom size (0x%x) overruns defined register window\n", 278 sctl); 279 return (0); 280 } 281 282 return (sprom_sz); 283 } 284 285 /* 286 * On devices without a SROM, the PCI(e) cores will be initialized with 287 * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows 288 * mapped to the wrong core. 289 * 290 * This function updates the SROM shadow to point the BAR0 windows at the 291 * current PCI core. 292 * 293 * Applies to all PCI/PCIe revisions. 294 */ 295 static void 296 bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) 297 { 298 struct bhndb_resources *bres; 299 const struct bhndb_hwcfg *cfg; 300 const struct bhndb_regwin *win; 301 struct resource *core_regs; 302 bus_size_t srom_offset; 303 u_int pci_cidx, sprom_cidx; 304 uint16_t val; 305 306 bres = sc->bhndb.bus_res; 307 cfg = bres->cfg; 308 309 if (bhnd_get_vendor(sc->bhndb.hostb_dev) != BHND_MFGID_BCM) 310 return; 311 312 switch (bhnd_get_device(sc->bhndb.hostb_dev)) { 313 case BHND_COREID_PCI: 314 srom_offset = BHND_PCI_SRSH_PI_OFFSET; 315 break; 316 case BHND_COREID_PCIE: 317 srom_offset = BHND_PCIE_SRSH_PI_OFFSET; 318 break; 319 default: 320 device_printf(sc->dev, "unsupported PCI host bridge device\n"); 321 return; 322 } 323 324 /* Locate the static register window mapping the PCI core */ 325 win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass, 326 0, BHND_PORT_DEVICE, 0, 0); 327 if (win == NULL) { 328 device_printf(sc->dev, "missing PCI core register window\n"); 329 return; 330 } 331 332 /* Fetch the resource containing the register window */ 333 core_regs = bhndb_find_regwin_resource(bres, win); 334 if (core_regs == NULL) { 335 device_printf(sc->dev, "missing PCI core register resource\n"); 336 return; 337 } 338 339 /* Fetch the SPROM's configured core index */ 340 val = bus_read_2(core_regs, win->win_offset + srom_offset); 341 sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT; 342 343 /* If it doesn't match host bridge's core index, update the index 344 * value */ 345 pci_cidx = bhnd_get_core_index(sc->bhndb.hostb_dev); 346 if (sprom_cidx != pci_cidx) { 347 val &= ~BHND_PCI_SRSH_PI_MASK; 348 val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT); 349 bus_write_2(core_regs, 350 win->win_offset + srom_offset, val); 351 } 352 } 353 354 static int 355 bhndb_pci_resume(device_t dev) 356 { 357 struct bhndb_pci_softc *sc; 358 int error; 359 360 sc = device_get_softc(dev); 361 362 /* Enable clocks (if supported by this hardware) */ 363 if ((error = bhndb_enable_pci_clocks(sc))) 364 return (error); 365 366 /* Perform resume */ 367 return (bhndb_generic_resume(dev)); 368 } 369 370 static int 371 bhndb_pci_suspend(device_t dev) 372 { 373 struct bhndb_pci_softc *sc; 374 int error; 375 376 sc = device_get_softc(dev); 377 378 /* Disable clocks (if supported by this hardware) */ 379 if ((error = bhndb_disable_pci_clocks(sc))) 380 return (error); 381 382 /* Perform suspend */ 383 return (bhndb_generic_suspend(dev)); 384 } 385 386 static int 387 bhndb_pci_detach(device_t dev) 388 { 389 struct bhndb_pci_softc *sc; 390 int error; 391 392 sc = device_get_softc(dev); 393 394 /* Disable clocks (if supported by this hardware) */ 395 if ((error = bhndb_disable_pci_clocks(sc))) 396 return (error); 397 398 /* Perform detach */ 399 if ((error = bhndb_generic_detach(dev))) 400 return (error); 401 402 /* Disable PCI bus mastering */ 403 pci_disable_busmaster(sc->parent); 404 405 return (0); 406 } 407 408 static int 409 bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw, 410 bhnd_addr_t addr) 411 { 412 struct bhndb_pci_softc *sc = device_get_softc(dev); 413 return (sc->set_regwin(sc, rw, addr)); 414 } 415 416 /** 417 * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation. 418 * 419 * On siba(4) devices, it's possible that writing a PCI window register may 420 * not succeed; it's necessary to immediately read the configuration register 421 * and retry if not set to the desired value. 422 * 423 * This is not necessary on bcma(4) devices, but other than the overhead of 424 * validating the register, there's no harm in performing the verification. 425 */ 426 static int 427 bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc, 428 const struct bhndb_regwin *rw, bhnd_addr_t addr) 429 { 430 int error; 431 int reg; 432 433 if (rw->win_type != BHNDB_REGWIN_T_DYN) 434 return (ENODEV); 435 436 reg = rw->d.dyn.cfg_offset; 437 for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) { 438 if ((error = bhndb_pci_fast_setregwin(sc, rw, addr))) 439 return (error); 440 441 if (pci_read_config(sc->parent, reg, 4) == addr) 442 return (0); 443 444 DELAY(10); 445 } 446 447 /* Unable to set window */ 448 return (ENODEV); 449 } 450 451 /** 452 * A bcma(4)-only bhndb_set_window_addr implementation. 453 */ 454 static int 455 bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc, 456 const struct bhndb_regwin *rw, bhnd_addr_t addr) 457 { 458 /* The PCI bridge core only supports 32-bit addressing, regardless 459 * of the bus' support for 64-bit addressing */ 460 if (addr > UINT32_MAX) 461 return (ERANGE); 462 463 switch (rw->win_type) { 464 case BHNDB_REGWIN_T_DYN: 465 /* Addresses must be page aligned */ 466 if (addr % rw->win_size != 0) 467 return (EINVAL); 468 469 pci_write_config(sc->parent, rw->d.dyn.cfg_offset, addr, 4); 470 break; 471 default: 472 return (ENODEV); 473 } 474 475 return (0); 476 } 477 478 static int 479 bhndb_pci_populate_board_info(device_t dev, device_t child, 480 struct bhnd_board_info *info) 481 { 482 struct bhndb_pci_softc *sc; 483 484 sc = device_get_softc(dev); 485 486 /* 487 * On a subset of Apple BCM4360 modules, always prefer the 488 * PCI subdevice to the SPROM-supplied boardtype. 489 * 490 * TODO: 491 * 492 * Broadcom's own drivers implement this override, and then later use 493 * the remapped BCM4360 board type to determine the required 494 * board-specific workarounds. 495 * 496 * Without access to this hardware, it's unclear why this mapping 497 * is done, and we must do the same. If we can survey the hardware 498 * in question, it may be possible to replace this behavior with 499 * explicit references to the SPROM-supplied boardtype(s) in our 500 * quirk definitions. 501 */ 502 if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) { 503 switch (info->board_type) { 504 case BHND_BOARD_BCM94360X29C: 505 case BHND_BOARD_BCM94360X29CP2: 506 case BHND_BOARD_BCM94360X51: 507 case BHND_BOARD_BCM94360X51P2: 508 info->board_type = 0; /* allow override below */ 509 break; 510 default: 511 break; 512 } 513 } 514 515 /* If NVRAM did not supply vendor/type info, provide the PCI 516 * subvendor/subdevice values. */ 517 if (info->board_vendor == 0) 518 info->board_vendor = pci_get_subvendor(sc->parent); 519 520 if (info->board_type == 0) 521 info->board_type = pci_get_subdevice(sc->parent); 522 523 return (0); 524 } 525 526 /** 527 * Enable externally managed clocks, if required. 528 * 529 * Some PCI chipsets (BCM4306, possibly others) chips do not support 530 * the idle low-power clock. Clocking must be bootstrapped at 531 * attach/resume by directly adjusting GPIO registers exposed in the 532 * PCI config space, and correspondingly, explicitly shutdown at 533 * detach/suspend. 534 * 535 * @param sc Bridge driver state. 536 */ 537 static int 538 bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) 539 { 540 uint32_t gpio_in, gpio_out, gpio_en; 541 uint32_t gpio_flags; 542 uint16_t pci_status; 543 544 /* Only supported and required on PCI devices */ 545 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 546 return (0); 547 548 /* Read state of XTAL pin */ 549 gpio_in = pci_read_config(sc->parent, BHNDB_PCI_GPIO_IN, 4); 550 if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON) 551 return (0); /* already enabled */ 552 553 /* Fetch current config */ 554 gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 555 gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 556 557 /* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */ 558 gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 559 gpio_out |= gpio_flags; 560 gpio_en |= gpio_flags; 561 562 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 563 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 564 DELAY(1000); 565 566 /* Reset PLL_OFF */ 567 gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; 568 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 569 DELAY(5000); 570 571 /* Clear any PCI 'sent target-abort' flag. */ 572 pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2); 573 pci_status &= ~PCIM_STATUS_STABORT; 574 pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2); 575 576 return (0); 577 } 578 579 /** 580 * Disable externally managed clocks, if required. 581 * 582 * @param sc Bridge driver state. 583 */ 584 static int 585 bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) 586 { 587 uint32_t gpio_out, gpio_en; 588 589 /* Only supported and required on PCI devices */ 590 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 591 return (0); 592 593 /* Fetch current config */ 594 gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 595 gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 596 597 /* Set PLL_OFF to HIGH, XTAL_ON to LOW. */ 598 gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON; 599 gpio_out |= BHNDB_PCI_GPIO_PLL_OFF; 600 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 601 602 /* Enable both output pins */ 603 gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 604 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 605 606 return (0); 607 } 608 609 static device_method_t bhndb_pci_methods[] = { 610 /* Device interface */ 611 DEVMETHOD(device_probe, bhndb_pci_probe), 612 DEVMETHOD(device_attach, bhndb_pci_attach), 613 DEVMETHOD(device_resume, bhndb_pci_resume), 614 DEVMETHOD(device_suspend, bhndb_pci_suspend), 615 DEVMETHOD(device_detach, bhndb_pci_detach), 616 617 /* BHNDB interface */ 618 DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config), 619 DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr), 620 DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info), 621 622 DEVMETHOD_END 623 }; 624 625 DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, 626 sizeof(struct bhndb_pci_softc), bhndb_driver); 627 628 MODULE_VERSION(bhndb_pci, 1); 629 MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1); 630 MODULE_DEPEND(bhndb_pci, bhnd_pcie2_hostb, 1, 1, 1); 631 MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); 632 MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1); 633 MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1); 634