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_pci_init_msi(struct bhndb_pci_softc *sc); 66 static int bhndb_pci_add_children(struct bhndb_pci_softc *sc); 67 68 static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc); 69 static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc); 70 71 static int bhndb_pci_compat_setregwin(struct bhndb_pci_softc *, 72 const struct bhndb_regwin *, bhnd_addr_t); 73 static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, 74 const struct bhndb_regwin *, bhnd_addr_t); 75 76 static void bhndb_init_sromless_pci_config( 77 struct bhndb_pci_softc *sc); 78 79 static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc); 80 static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc); 81 82 #define BHNDB_PCI_MSI_COUNT 1 83 84 /** 85 * Default bhndb_pci implementation of device_probe(). 86 * 87 * Verifies that the parent is a PCI/PCIe device. 88 */ 89 static int 90 bhndb_pci_probe(device_t dev) 91 { 92 device_t parent; 93 devclass_t parent_bus; 94 devclass_t pci; 95 96 /* Our parent must be a PCI/PCIe device. */ 97 pci = devclass_find("pci"); 98 parent = device_get_parent(dev); 99 parent_bus = device_get_devclass(device_get_parent(parent)); 100 101 if (parent_bus != pci) 102 return (ENXIO); 103 104 device_set_desc(dev, "PCI-BHND bridge"); 105 106 return (BUS_PROBE_DEFAULT); 107 } 108 109 /* Configure MSI interrupts */ 110 static int 111 bhndb_pci_init_msi(struct bhndb_pci_softc *sc) 112 { 113 int error; 114 115 /* Is MSI available? */ 116 if (pci_msi_count(sc->parent) < BHNDB_PCI_MSI_COUNT) 117 return (ENXIO); 118 119 /* Allocate expected message count */ 120 sc->intr.msi_count = BHNDB_PCI_MSI_COUNT; 121 if ((error = pci_alloc_msi(sc->parent, &sc->intr.msi_count))) { 122 device_printf(sc->dev, "failed to allocate MSI interrupts: " 123 "%d\n", error); 124 return (error); 125 } 126 127 if (sc->intr.msi_count < BHNDB_PCI_MSI_COUNT) 128 return (ENXIO); 129 130 /* MSI uses resource IDs starting at 1 */ 131 sc->intr.intr_rid = 1; 132 133 return (0); 134 } 135 136 static int 137 bhndb_pci_attach(device_t dev) 138 { 139 struct bhndb_pci_softc *sc; 140 int error, reg; 141 142 sc = device_get_softc(dev); 143 sc->dev = dev; 144 sc->parent = device_get_parent(dev); 145 sc->set_regwin = bhndb_pci_compat_setregwin; 146 147 /* Enable PCI bus mastering */ 148 pci_enable_busmaster(sc->parent); 149 150 /* Set up interrupt handling */ 151 if (bhndb_pci_init_msi(sc) == 0) { 152 device_printf(dev, "Using MSI interrupts on %s\n", 153 device_get_nameunit(sc->parent)); 154 } else { 155 device_printf(dev, "Using INTx interrupts on %s\n", 156 device_get_nameunit(sc->parent)); 157 sc->intr.intr_rid = 0; 158 } 159 160 /* Determine our bridge device class */ 161 sc->pci_devclass = BHND_DEVCLASS_PCI; 162 if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0) 163 sc->pci_devclass = BHND_DEVCLASS_PCIE; 164 else 165 sc->pci_devclass = BHND_DEVCLASS_PCI; 166 167 /* Enable clocks (if required by this hardware) */ 168 if ((error = bhndb_enable_pci_clocks(sc))) 169 goto cleanup; 170 171 /* Perform bridge attach, fully initializing the bridge 172 * configuration. */ 173 if ((error = bhndb_attach(dev, sc->pci_devclass))) 174 goto cleanup; 175 176 /* If supported, switch to faster regwin handling */ 177 if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) { 178 atomic_store_rel_ptr((volatile void *) &sc->set_regwin, 179 (uintptr_t) &bhndb_pci_fast_setregwin); 180 } 181 182 /* Enable PCI bus mastering */ 183 pci_enable_busmaster(sc->parent); 184 185 /* Fix-up power on defaults for SROM-less devices. */ 186 bhndb_init_sromless_pci_config(sc); 187 188 /* Add any additional child devices */ 189 if ((error = bhndb_pci_add_children(sc))) 190 goto cleanup; 191 192 /* Probe and attach our children */ 193 if ((error = bus_generic_attach(dev))) 194 goto cleanup; 195 196 return (0); 197 198 cleanup: 199 device_delete_children(dev); 200 bhndb_disable_pci_clocks(sc); 201 if (sc->intr.msi_count > 0) 202 pci_release_msi(dev); 203 204 pci_disable_busmaster(sc->parent); 205 206 return (error); 207 } 208 209 static int 210 bhndb_pci_detach(device_t dev) 211 { 212 struct bhndb_pci_softc *sc; 213 int error; 214 215 sc = device_get_softc(dev); 216 217 /* Attempt to detach our children */ 218 if ((error = bus_generic_detach(dev))) 219 return (error); 220 221 /* Perform generic bridge detach */ 222 if ((error = bhndb_generic_detach(dev))) 223 return (error); 224 225 /* Disable clocks (if required by this hardware) */ 226 if ((error = bhndb_disable_pci_clocks(sc))) 227 return (error); 228 229 /* Release MSI interrupts */ 230 if (sc->intr.msi_count > 0) 231 pci_release_msi(dev); 232 233 /* Disable PCI bus mastering */ 234 pci_disable_busmaster(sc->parent); 235 236 return (0); 237 } 238 239 static int 240 bhndb_pci_add_children(struct bhndb_pci_softc *sc) 241 { 242 bus_size_t nv_sz; 243 int error; 244 245 /** 246 * If SPROM is mapped directly into BAR0, add child NVRAM 247 * device. 248 */ 249 nv_sz = bhndb_pci_sprom_size(sc); 250 if (nv_sz > 0) { 251 struct bhndb_devinfo *dinfo; 252 device_t child; 253 254 if (bootverbose) { 255 device_printf(sc->dev, "found SPROM (%ju bytes)\n", 256 (uintmax_t)nv_sz); 257 } 258 259 /* Add sprom device, ordered early enough to be available 260 * before the bridged bhnd(4) bus is attached. */ 261 child = BUS_ADD_CHILD(sc->dev, 262 BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY, "bhnd_nvram", -1); 263 if (child == NULL) { 264 device_printf(sc->dev, "failed to add sprom device\n"); 265 return (ENXIO); 266 } 267 268 /* Initialize device address space and resource covering the 269 * BAR0 SPROM shadow. */ 270 dinfo = device_get_ivars(child); 271 dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; 272 273 error = bus_set_resource(child, SYS_RES_MEMORY, 0, 274 bhndb_pci_sprom_addr(sc), nv_sz); 275 if (error) { 276 device_printf(sc->dev, 277 "failed to register sprom resources\n"); 278 return (error); 279 } 280 } 281 282 return (0); 283 } 284 285 static const struct bhndb_regwin * 286 bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc) 287 { 288 struct bhndb_resources *bres; 289 const struct bhndb_hwcfg *cfg; 290 const struct bhndb_regwin *sprom_win; 291 292 bres = sc->bhndb.bus_res; 293 cfg = bres->cfg; 294 295 sprom_win = bhndb_regwin_find_type(cfg->register_windows, 296 BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE); 297 298 return (sprom_win); 299 } 300 301 static bus_addr_t 302 bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc) 303 { 304 const struct bhndb_regwin *sprom_win; 305 struct resource *r; 306 307 /* Fetch the SPROM register window */ 308 sprom_win = bhndb_pci_sprom_regwin(sc); 309 KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+")); 310 311 /* Fetch the associated resource */ 312 r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win); 313 KASSERT(r != NULL, ("missing resource for sprom window\n")); 314 315 return (rman_get_start(r) + sprom_win->win_offset); 316 } 317 318 static bus_size_t 319 bhndb_pci_sprom_size(struct bhndb_pci_softc *sc) 320 { 321 const struct bhndb_regwin *sprom_win; 322 uint32_t sctl; 323 bus_size_t sprom_sz; 324 325 sprom_win = bhndb_pci_sprom_regwin(sc); 326 327 /* PCI_V2 and later devices map SPROM/OTP via ChipCommon */ 328 if (sprom_win == NULL) 329 return (0); 330 331 /* Determine SPROM size */ 332 sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4); 333 if (sctl & BHNDB_PCI_SPROM_BLANK) 334 return (0); 335 336 switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) { 337 case BHNDB_PCI_SPROM_SZ_1KB: 338 sprom_sz = (1 * 1024); 339 break; 340 341 case BHNDB_PCI_SPROM_SZ_4KB: 342 sprom_sz = (4 * 1024); 343 break; 344 345 case BHNDB_PCI_SPROM_SZ_16KB: 346 sprom_sz = (16 * 1024); 347 break; 348 349 case BHNDB_PCI_SPROM_SZ_RESERVED: 350 default: 351 device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl); 352 return (0); 353 } 354 355 if (sprom_sz > sprom_win->win_size) { 356 device_printf(sc->dev, 357 "PCI sprom size (0x%x) overruns defined register window\n", 358 sctl); 359 return (0); 360 } 361 362 return (sprom_sz); 363 } 364 365 /* 366 * On devices without a SROM, the PCI(e) cores will be initialized with 367 * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows 368 * mapped to the wrong core. 369 * 370 * This function updates the SROM shadow to point the BAR0 windows at the 371 * current PCI core. 372 * 373 * Applies to all PCI/PCIe revisions. 374 */ 375 static void 376 bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) 377 { 378 struct bhndb_resources *bres; 379 const struct bhndb_hwcfg *cfg; 380 const struct bhndb_regwin *win; 381 struct bhnd_core_info hostb_core; 382 struct resource *core_regs; 383 bus_size_t srom_offset; 384 u_int pci_cidx, sprom_cidx; 385 uint16_t val; 386 int error; 387 388 bres = sc->bhndb.bus_res; 389 cfg = bres->cfg; 390 391 /* Find our hostb core */ 392 error = BHNDB_GET_HOSTB_CORE(sc->dev, sc->bhndb.bus_dev, &hostb_core); 393 if (error) { 394 device_printf(sc->dev, "no host bridge device found\n"); 395 return; 396 } 397 398 if (hostb_core.vendor != BHND_MFGID_BCM) 399 return; 400 401 switch (hostb_core.device) { 402 case BHND_COREID_PCI: 403 srom_offset = BHND_PCI_SRSH_PI_OFFSET; 404 break; 405 case BHND_COREID_PCIE: 406 srom_offset = BHND_PCIE_SRSH_PI_OFFSET; 407 break; 408 default: 409 device_printf(sc->dev, "unsupported PCI host bridge device\n"); 410 return; 411 } 412 413 /* Locate the static register window mapping the PCI core */ 414 win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass, 415 0, BHND_PORT_DEVICE, 0, 0); 416 if (win == NULL) { 417 device_printf(sc->dev, "missing PCI core register window\n"); 418 return; 419 } 420 421 /* Fetch the resource containing the register window */ 422 core_regs = bhndb_find_regwin_resource(bres, win); 423 if (core_regs == NULL) { 424 device_printf(sc->dev, "missing PCI core register resource\n"); 425 return; 426 } 427 428 /* Fetch the SPROM's configured core index */ 429 val = bus_read_2(core_regs, win->win_offset + srom_offset); 430 sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT; 431 432 /* If it doesn't match host bridge's core index, update the index 433 * value */ 434 pci_cidx = hostb_core.core_idx; 435 if (sprom_cidx != pci_cidx) { 436 val &= ~BHND_PCI_SRSH_PI_MASK; 437 val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT); 438 bus_write_2(core_regs, 439 win->win_offset + srom_offset, val); 440 } 441 } 442 443 static int 444 bhndb_pci_resume(device_t dev) 445 { 446 struct bhndb_pci_softc *sc; 447 int error; 448 449 sc = device_get_softc(dev); 450 451 /* Enable clocks (if supported by this hardware) */ 452 if ((error = bhndb_enable_pci_clocks(sc))) 453 return (error); 454 455 /* Perform resume */ 456 return (bhndb_generic_resume(dev)); 457 } 458 459 static int 460 bhndb_pci_suspend(device_t dev) 461 { 462 struct bhndb_pci_softc *sc; 463 int error; 464 465 sc = device_get_softc(dev); 466 467 /* Disable clocks (if supported by this hardware) */ 468 if ((error = bhndb_disable_pci_clocks(sc))) 469 return (error); 470 471 /* Perform suspend */ 472 return (bhndb_generic_suspend(dev)); 473 } 474 475 static int 476 bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw, 477 bhnd_addr_t addr) 478 { 479 struct bhndb_pci_softc *sc = device_get_softc(dev); 480 return (sc->set_regwin(sc, rw, addr)); 481 } 482 483 /** 484 * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation. 485 * 486 * On siba(4) devices, it's possible that writing a PCI window register may 487 * not succeed; it's necessary to immediately read the configuration register 488 * and retry if not set to the desired value. 489 * 490 * This is not necessary on bcma(4) devices, but other than the overhead of 491 * validating the register, there's no harm in performing the verification. 492 */ 493 static int 494 bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc, 495 const struct bhndb_regwin *rw, bhnd_addr_t addr) 496 { 497 int error; 498 int reg; 499 500 if (rw->win_type != BHNDB_REGWIN_T_DYN) 501 return (ENODEV); 502 503 reg = rw->d.dyn.cfg_offset; 504 for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) { 505 if ((error = bhndb_pci_fast_setregwin(sc, rw, addr))) 506 return (error); 507 508 if (pci_read_config(sc->parent, reg, 4) == addr) 509 return (0); 510 511 DELAY(10); 512 } 513 514 /* Unable to set window */ 515 return (ENODEV); 516 } 517 518 /** 519 * A bcma(4)-only bhndb_set_window_addr implementation. 520 */ 521 static int 522 bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc, 523 const struct bhndb_regwin *rw, bhnd_addr_t addr) 524 { 525 /* The PCI bridge core only supports 32-bit addressing, regardless 526 * of the bus' support for 64-bit addressing */ 527 if (addr > UINT32_MAX) 528 return (ERANGE); 529 530 switch (rw->win_type) { 531 case BHNDB_REGWIN_T_DYN: 532 /* Addresses must be page aligned */ 533 if (addr % rw->win_size != 0) 534 return (EINVAL); 535 536 pci_write_config(sc->parent, rw->d.dyn.cfg_offset, addr, 4); 537 break; 538 default: 539 return (ENODEV); 540 } 541 542 return (0); 543 } 544 545 static int 546 bhndb_pci_populate_board_info(device_t dev, device_t child, 547 struct bhnd_board_info *info) 548 { 549 struct bhndb_pci_softc *sc; 550 551 sc = device_get_softc(dev); 552 553 /* 554 * On a subset of Apple BCM4360 modules, always prefer the 555 * PCI subdevice to the SPROM-supplied boardtype. 556 * 557 * TODO: 558 * 559 * Broadcom's own drivers implement this override, and then later use 560 * the remapped BCM4360 board type to determine the required 561 * board-specific workarounds. 562 * 563 * Without access to this hardware, it's unclear why this mapping 564 * is done, and we must do the same. If we can survey the hardware 565 * in question, it may be possible to replace this behavior with 566 * explicit references to the SPROM-supplied boardtype(s) in our 567 * quirk definitions. 568 */ 569 if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) { 570 switch (info->board_type) { 571 case BHND_BOARD_BCM94360X29C: 572 case BHND_BOARD_BCM94360X29CP2: 573 case BHND_BOARD_BCM94360X51: 574 case BHND_BOARD_BCM94360X51P2: 575 info->board_type = 0; /* allow override below */ 576 break; 577 default: 578 break; 579 } 580 } 581 582 /* If NVRAM did not supply vendor/type info, provide the PCI 583 * subvendor/subdevice values. */ 584 if (info->board_vendor == 0) 585 info->board_vendor = pci_get_subvendor(sc->parent); 586 587 if (info->board_type == 0) 588 info->board_type = pci_get_subdevice(sc->parent); 589 590 return (0); 591 } 592 593 /** 594 * Enable externally managed clocks, if required. 595 * 596 * Some PCI chipsets (BCM4306, possibly others) chips do not support 597 * the idle low-power clock. Clocking must be bootstrapped at 598 * attach/resume by directly adjusting GPIO registers exposed in the 599 * PCI config space, and correspondingly, explicitly shutdown at 600 * detach/suspend. 601 * 602 * @param sc Bridge driver state. 603 */ 604 static int 605 bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) 606 { 607 uint32_t gpio_in, gpio_out, gpio_en; 608 uint32_t gpio_flags; 609 uint16_t pci_status; 610 611 /* Only supported and required on PCI devices */ 612 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 613 return (0); 614 615 /* Read state of XTAL pin */ 616 gpio_in = pci_read_config(sc->parent, BHNDB_PCI_GPIO_IN, 4); 617 if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON) 618 return (0); /* already enabled */ 619 620 /* Fetch current config */ 621 gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 622 gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 623 624 /* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */ 625 gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 626 gpio_out |= gpio_flags; 627 gpio_en |= gpio_flags; 628 629 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 630 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 631 DELAY(1000); 632 633 /* Reset PLL_OFF */ 634 gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; 635 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 636 DELAY(5000); 637 638 /* Clear any PCI 'sent target-abort' flag. */ 639 pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2); 640 pci_status &= ~PCIM_STATUS_STABORT; 641 pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2); 642 643 return (0); 644 } 645 646 /** 647 * Disable externally managed clocks, if required. 648 * 649 * @param sc Bridge driver state. 650 */ 651 static int 652 bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) 653 { 654 uint32_t gpio_out, gpio_en; 655 656 /* Only supported and required on PCI devices */ 657 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 658 return (0); 659 660 /* Fetch current config */ 661 gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 662 gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 663 664 /* Set PLL_OFF to HIGH, XTAL_ON to LOW. */ 665 gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON; 666 gpio_out |= BHNDB_PCI_GPIO_PLL_OFF; 667 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 668 669 /* Enable both output pins */ 670 gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 671 pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 672 673 return (0); 674 } 675 676 static bhnd_clksrc 677 bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child, 678 bhnd_clock clock) 679 { 680 struct bhndb_pci_softc *sc; 681 uint32_t gpio_out; 682 683 sc = device_get_softc(dev); 684 685 /* Only supported on PCI devices */ 686 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 687 return (ENODEV); 688 689 /* Only ILP is supported */ 690 if (clock != BHND_CLOCK_ILP) 691 return (ENXIO); 692 693 gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 694 if (gpio_out & BHNDB_PCI_GPIO_SCS) 695 return (BHND_CLKSRC_PCI); 696 else 697 return (BHND_CLKSRC_XTAL); 698 } 699 700 static int 701 bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child, 702 bhnd_clock clock) 703 { 704 struct bhndb_pci_softc *sc = device_get_softc(dev); 705 706 /* Only supported on PCI devices */ 707 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 708 return (ENODEV); 709 710 /* Only HT is supported */ 711 if (clock != BHND_CLOCK_HT) 712 return (ENXIO); 713 714 return (bhndb_disable_pci_clocks(sc)); 715 } 716 717 static int 718 bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child, 719 bhnd_clock clock) 720 { 721 struct bhndb_pci_softc *sc = device_get_softc(dev); 722 723 /* Only supported on PCI devices */ 724 if (sc->pci_devclass != BHND_DEVCLASS_PCI) 725 return (ENODEV); 726 727 /* Only HT is supported */ 728 if (clock != BHND_CLOCK_HT) 729 return (ENXIO); 730 731 return (bhndb_enable_pci_clocks(sc)); 732 } 733 734 static int 735 bhndb_pci_assign_intr(device_t dev, device_t child, int rid) 736 { 737 struct bhndb_pci_softc *sc; 738 rman_res_t start, count; 739 int error; 740 741 sc = device_get_softc(dev); 742 743 /* Is the rid valid? */ 744 if (rid >= bhnd_get_intr_count(child)) 745 return (EINVAL); 746 747 /* Fetch our common PCI interrupt's start/count. */ 748 error = bus_get_resource(sc->parent, SYS_RES_IRQ, sc->intr.intr_rid, 749 &start, &count); 750 if (error) 751 return (error); 752 753 /* Add to child's resource list */ 754 return (bus_set_resource(child, SYS_RES_IRQ, rid, start, count)); 755 } 756 757 static device_method_t bhndb_pci_methods[] = { 758 /* Device interface */ 759 DEVMETHOD(device_probe, bhndb_pci_probe), 760 DEVMETHOD(device_attach, bhndb_pci_attach), 761 DEVMETHOD(device_resume, bhndb_pci_resume), 762 DEVMETHOD(device_suspend, bhndb_pci_suspend), 763 DEVMETHOD(device_detach, bhndb_pci_detach), 764 765 /* BHND interface */ 766 DEVMETHOD(bhnd_bus_assign_intr, bhndb_pci_assign_intr), 767 768 DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhndb_pci_pwrctl_get_clksrc), 769 DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhndb_pci_pwrctl_gate_clock), 770 DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock), 771 772 /* BHNDB interface */ 773 DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr), 774 DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info), 775 776 DEVMETHOD_END 777 }; 778 779 DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, 780 sizeof(struct bhndb_pci_softc), bhndb_driver); 781 782 MODULE_VERSION(bhndb_pci, 1); 783 MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1); 784 MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); 785 MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1); 786 MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1); 787