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