14ad7e9b0SAdrian Chadd /*- 2bb64eeccSAdrian Chadd * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 34ad7e9b0SAdrian Chadd * All rights reserved. 44ad7e9b0SAdrian Chadd * 54ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without 64ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions 74ad7e9b0SAdrian Chadd * are met: 84ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 94ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer, 104ad7e9b0SAdrian Chadd * without modification. 114ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 124ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 134ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially 144ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 154ad7e9b0SAdrian Chadd * 164ad7e9b0SAdrian Chadd * NO WARRANTY 174ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 184ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 194ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 204ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 214ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 224ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 234ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 244ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 254ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 264ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 274ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 284ad7e9b0SAdrian Chadd */ 294ad7e9b0SAdrian Chadd 304ad7e9b0SAdrian Chadd #include <sys/cdefs.h> 314ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$"); 324ad7e9b0SAdrian Chadd 334ad7e9b0SAdrian Chadd /* 344ad7e9b0SAdrian Chadd * PCI-specific implementation for the BHNDB bridge driver. 354ad7e9b0SAdrian Chadd * 364ad7e9b0SAdrian Chadd * Provides support for bridging from a PCI parent bus to a BHND-compatible 374ad7e9b0SAdrian Chadd * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point 384ad7e9b0SAdrian Chadd * mode. 394ad7e9b0SAdrian Chadd * 408ef24a0dSAdrian Chadd * This driver handles all initial generic host-level PCI interactions with a 418ef24a0dSAdrian Chadd * PCI/PCIe bridge core operating in endpoint mode. Once the bridged bhnd(4) 428ef24a0dSAdrian Chadd * bus has been enumerated, this driver works in tandem with a core-specific 438ef24a0dSAdrian Chadd * bhnd_pci_hostb driver to manage the PCI core. 444ad7e9b0SAdrian Chadd */ 454ad7e9b0SAdrian Chadd 464ad7e9b0SAdrian Chadd #include <sys/param.h> 474ad7e9b0SAdrian Chadd #include <sys/kernel.h> 484ad7e9b0SAdrian Chadd #include <sys/bus.h> 494ad7e9b0SAdrian Chadd #include <sys/limits.h> 504ad7e9b0SAdrian Chadd #include <sys/malloc.h> 514ad7e9b0SAdrian Chadd #include <sys/module.h> 524ad7e9b0SAdrian Chadd #include <sys/systm.h> 534ad7e9b0SAdrian Chadd 544ad7e9b0SAdrian Chadd #include <dev/pci/pcireg.h> 554ad7e9b0SAdrian Chadd #include <dev/pci/pcivar.h> 564ad7e9b0SAdrian Chadd 574ad7e9b0SAdrian Chadd #include <dev/bhnd/bhnd.h> 584ad7e9b0SAdrian Chadd 594ad7e9b0SAdrian Chadd #include <dev/bhnd/cores/pci/bhnd_pcireg.h> 604ad7e9b0SAdrian Chadd 614ad7e9b0SAdrian Chadd #include "bhndb_pcireg.h" 624ad7e9b0SAdrian Chadd #include "bhndb_pcivar.h" 634ad7e9b0SAdrian Chadd #include "bhndb_private.h" 644ad7e9b0SAdrian Chadd 654ad7e9b0SAdrian Chadd static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc); 664ad7e9b0SAdrian Chadd static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc); 674ad7e9b0SAdrian Chadd 684ad7e9b0SAdrian Chadd static int bhndb_pci_compat_setregwin(struct bhndb_pci_softc *, 694ad7e9b0SAdrian Chadd const struct bhndb_regwin *, bhnd_addr_t); 704ad7e9b0SAdrian Chadd static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, 714ad7e9b0SAdrian Chadd const struct bhndb_regwin *, bhnd_addr_t); 724ad7e9b0SAdrian Chadd 73e83ce340SAdrian Chadd static void bhndb_init_sromless_pci_config( 74e83ce340SAdrian Chadd struct bhndb_pci_softc *sc); 75e83ce340SAdrian Chadd 76e83ce340SAdrian Chadd static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc); 77f9cf87a0SAdrian Chadd static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc); 784ad7e9b0SAdrian Chadd 794ad7e9b0SAdrian Chadd /** 804ad7e9b0SAdrian Chadd * Default bhndb_pci implementation of device_probe(). 814ad7e9b0SAdrian Chadd * 824ad7e9b0SAdrian Chadd * Verifies that the parent is a PCI/PCIe device. 834ad7e9b0SAdrian Chadd */ 844ad7e9b0SAdrian Chadd static int 854ad7e9b0SAdrian Chadd bhndb_pci_probe(device_t dev) 864ad7e9b0SAdrian Chadd { 874ad7e9b0SAdrian Chadd device_t parent; 884ad7e9b0SAdrian Chadd devclass_t parent_bus; 894ad7e9b0SAdrian Chadd devclass_t pci; 904ad7e9b0SAdrian Chadd 914ad7e9b0SAdrian Chadd /* Our parent must be a PCI/PCIe device. */ 924ad7e9b0SAdrian Chadd pci = devclass_find("pci"); 934ad7e9b0SAdrian Chadd parent = device_get_parent(dev); 944ad7e9b0SAdrian Chadd parent_bus = device_get_devclass(device_get_parent(parent)); 954ad7e9b0SAdrian Chadd 964ad7e9b0SAdrian Chadd if (parent_bus != pci) 974ad7e9b0SAdrian Chadd return (ENXIO); 984ad7e9b0SAdrian Chadd 994ad7e9b0SAdrian Chadd device_set_desc(dev, "PCI-BHND bridge"); 1004ad7e9b0SAdrian Chadd 1014ad7e9b0SAdrian Chadd return (BUS_PROBE_DEFAULT); 1024ad7e9b0SAdrian Chadd } 1034ad7e9b0SAdrian Chadd 1044ad7e9b0SAdrian Chadd static int 1054ad7e9b0SAdrian Chadd bhndb_pci_attach(device_t dev) 1064ad7e9b0SAdrian Chadd { 1074ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc; 1084ad7e9b0SAdrian Chadd int error, reg; 1094ad7e9b0SAdrian Chadd 1104ad7e9b0SAdrian Chadd sc = device_get_softc(dev); 1114ad7e9b0SAdrian Chadd sc->dev = dev; 112e83ce340SAdrian Chadd sc->parent = device_get_parent(dev); 1134ad7e9b0SAdrian Chadd 1144ad7e9b0SAdrian Chadd /* Enable PCI bus mastering */ 115e83ce340SAdrian Chadd pci_enable_busmaster(sc->parent); 1164ad7e9b0SAdrian Chadd 1174ad7e9b0SAdrian Chadd /* Determine our bridge device class */ 1184ad7e9b0SAdrian Chadd sc->pci_devclass = BHND_DEVCLASS_PCI; 119e83ce340SAdrian Chadd if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0) 1204ad7e9b0SAdrian Chadd sc->pci_devclass = BHND_DEVCLASS_PCIE; 1214ad7e9b0SAdrian Chadd 122bb64eeccSAdrian Chadd /* Enable clocks (if supported by this hardware) */ 123bb64eeccSAdrian Chadd if ((error = bhndb_enable_pci_clocks(sc))) 1244ad7e9b0SAdrian Chadd return (error); 1254ad7e9b0SAdrian Chadd 1264ad7e9b0SAdrian Chadd /* Use siba(4)-compatible regwin handling until we know 1274ad7e9b0SAdrian Chadd * what kind of bus is attached */ 1284ad7e9b0SAdrian Chadd sc->set_regwin = bhndb_pci_compat_setregwin; 1294ad7e9b0SAdrian Chadd 1304ad7e9b0SAdrian Chadd /* Perform full bridge attach. This should call back into our 1314ad7e9b0SAdrian Chadd * bhndb_pci_init_full_config() implementation once the bridged 1324ad7e9b0SAdrian Chadd * bhnd(4) bus has been enumerated, but before any devices have been 1334ad7e9b0SAdrian Chadd * probed or attached. */ 1344ad7e9b0SAdrian Chadd if ((error = bhndb_attach(dev, sc->pci_devclass))) 1354ad7e9b0SAdrian Chadd return (error); 1364ad7e9b0SAdrian Chadd 1374ad7e9b0SAdrian Chadd /* If supported, switch to the faster regwin handling */ 1384ad7e9b0SAdrian Chadd if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) { 1394ad7e9b0SAdrian Chadd atomic_store_rel_ptr((volatile void *) &sc->set_regwin, 1404ad7e9b0SAdrian Chadd (uintptr_t) &bhndb_pci_fast_setregwin); 1414ad7e9b0SAdrian Chadd } 1424ad7e9b0SAdrian Chadd 1434ad7e9b0SAdrian Chadd return (0); 1444ad7e9b0SAdrian Chadd } 1454ad7e9b0SAdrian Chadd 1464ad7e9b0SAdrian Chadd static int 1474ad7e9b0SAdrian Chadd bhndb_pci_init_full_config(device_t dev, device_t child, 148bb64eeccSAdrian Chadd const struct bhndb_hw_priority *hw_prio_table) 1494ad7e9b0SAdrian Chadd { 1504ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc; 151e83ce340SAdrian Chadd device_t nv_dev; 152e83ce340SAdrian Chadd bus_size_t nv_sz; 1534ad7e9b0SAdrian Chadd int error; 1544ad7e9b0SAdrian Chadd 1554ad7e9b0SAdrian Chadd sc = device_get_softc(dev); 1564ad7e9b0SAdrian Chadd 157bb64eeccSAdrian Chadd /* Let our parent perform standard initialization first */ 158bb64eeccSAdrian Chadd if ((error = bhndb_generic_init_full_config(dev, child, hw_prio_table))) 1594ad7e9b0SAdrian Chadd return (error); 1604ad7e9b0SAdrian Chadd 161bb64eeccSAdrian Chadd /* Fix-up power on defaults for SROM-less devices. */ 1624ad7e9b0SAdrian Chadd bhndb_init_sromless_pci_config(sc); 1634ad7e9b0SAdrian Chadd 164e83ce340SAdrian Chadd /* If SPROM is mapped directly into BAR0, add NVRAM device. */ 165e83ce340SAdrian Chadd nv_sz = bhndb_pci_sprom_size(sc); 166e83ce340SAdrian Chadd if (nv_sz > 0) { 167e83ce340SAdrian Chadd struct bhndb_devinfo *dinfo; 168e83ce340SAdrian Chadd const char *dname; 169e83ce340SAdrian Chadd 170e83ce340SAdrian Chadd if (bootverbose) { 171f9cf87a0SAdrian Chadd device_printf(dev, "found SPROM (%u bytes)\n", 172f9cf87a0SAdrian Chadd (unsigned int) nv_sz); 173e83ce340SAdrian Chadd } 174e83ce340SAdrian Chadd 175e83ce340SAdrian Chadd /* Add sprom device */ 176e83ce340SAdrian Chadd dname = "bhnd_nvram"; 177e83ce340SAdrian Chadd if ((nv_dev = BUS_ADD_CHILD(dev, 0, dname, -1)) == NULL) { 178e83ce340SAdrian Chadd device_printf(dev, "failed to add sprom device\n"); 179e83ce340SAdrian Chadd return (ENXIO); 180e83ce340SAdrian Chadd } 181e83ce340SAdrian Chadd 182e83ce340SAdrian Chadd /* Initialize device address space and resource covering the 183e83ce340SAdrian Chadd * BAR0 SPROM shadow. */ 184e83ce340SAdrian Chadd dinfo = device_get_ivars(nv_dev); 185e83ce340SAdrian Chadd dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; 186e83ce340SAdrian Chadd error = bus_set_resource(nv_dev, SYS_RES_MEMORY, 0, 187e83ce340SAdrian Chadd bhndb_pci_sprom_addr(sc), nv_sz); 188e83ce340SAdrian Chadd 189e83ce340SAdrian Chadd if (error) { 190e83ce340SAdrian Chadd device_printf(dev, 191e83ce340SAdrian Chadd "failed to register sprom resources\n"); 192e83ce340SAdrian Chadd return (error); 193e83ce340SAdrian Chadd } 194e83ce340SAdrian Chadd 195e83ce340SAdrian Chadd /* Attach the device */ 196e83ce340SAdrian Chadd if ((error = device_probe_and_attach(nv_dev))) { 197e83ce340SAdrian Chadd device_printf(dev, "sprom attach failed\n"); 198e83ce340SAdrian Chadd return (error); 199e83ce340SAdrian Chadd } 200e83ce340SAdrian Chadd } 201e83ce340SAdrian Chadd 2024ad7e9b0SAdrian Chadd return (0); 2034ad7e9b0SAdrian Chadd } 2044ad7e9b0SAdrian Chadd 205e83ce340SAdrian Chadd static const struct bhndb_regwin * 206e83ce340SAdrian Chadd bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc) 207e83ce340SAdrian Chadd { 208e83ce340SAdrian Chadd struct bhndb_resources *bres; 209e83ce340SAdrian Chadd const struct bhndb_hwcfg *cfg; 210e83ce340SAdrian Chadd const struct bhndb_regwin *sprom_win; 211e83ce340SAdrian Chadd 212e83ce340SAdrian Chadd bres = sc->bhndb.bus_res; 213e83ce340SAdrian Chadd cfg = bres->cfg; 214e83ce340SAdrian Chadd 215e83ce340SAdrian Chadd sprom_win = bhndb_regwin_find_type(cfg->register_windows, 216e83ce340SAdrian Chadd BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE); 217e83ce340SAdrian Chadd 218e83ce340SAdrian Chadd return (sprom_win); 219e83ce340SAdrian Chadd } 220e83ce340SAdrian Chadd 221e83ce340SAdrian Chadd static bus_addr_t 222e83ce340SAdrian Chadd bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc) 223e83ce340SAdrian Chadd { 224e83ce340SAdrian Chadd const struct bhndb_regwin *sprom_win; 225e83ce340SAdrian Chadd struct resource *r; 226e83ce340SAdrian Chadd 227e83ce340SAdrian Chadd /* Fetch the SPROM register window */ 228e83ce340SAdrian Chadd sprom_win = bhndb_pci_sprom_regwin(sc); 229e83ce340SAdrian Chadd KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+")); 230e83ce340SAdrian Chadd 231e83ce340SAdrian Chadd /* Fetch the associated resource */ 232e83ce340SAdrian Chadd r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win); 233e83ce340SAdrian Chadd KASSERT(r != NULL, ("missing resource for sprom window\n")); 234e83ce340SAdrian Chadd 235e83ce340SAdrian Chadd return (rman_get_start(r) + sprom_win->win_offset); 236e83ce340SAdrian Chadd } 237e83ce340SAdrian Chadd 238e83ce340SAdrian Chadd static bus_size_t 239e83ce340SAdrian Chadd bhndb_pci_sprom_size(struct bhndb_pci_softc *sc) 240e83ce340SAdrian Chadd { 241e83ce340SAdrian Chadd const struct bhndb_regwin *sprom_win; 242e83ce340SAdrian Chadd uint32_t sctl; 243e83ce340SAdrian Chadd bus_size_t sprom_sz; 244e83ce340SAdrian Chadd 245e83ce340SAdrian Chadd sprom_win = bhndb_pci_sprom_regwin(sc); 246e83ce340SAdrian Chadd 247e83ce340SAdrian Chadd /* PCI_V2 and later devices map SPROM/OTP via ChipCommon */ 248e83ce340SAdrian Chadd if (sprom_win == NULL) 249e83ce340SAdrian Chadd return (0); 250e83ce340SAdrian Chadd 251e83ce340SAdrian Chadd /* Determine SPROM size */ 252e83ce340SAdrian Chadd sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4); 253e83ce340SAdrian Chadd if (sctl & BHNDB_PCI_SPROM_BLANK) 254e83ce340SAdrian Chadd return (0); 255e83ce340SAdrian Chadd 256e83ce340SAdrian Chadd switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) { 257e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_1KB: 258e83ce340SAdrian Chadd sprom_sz = (1 * 1024); 259e83ce340SAdrian Chadd break; 260e83ce340SAdrian Chadd 261e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_4KB: 262e83ce340SAdrian Chadd sprom_sz = (4 * 1024); 263e83ce340SAdrian Chadd break; 264e83ce340SAdrian Chadd 265e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_16KB: 266e83ce340SAdrian Chadd sprom_sz = (16 * 1024); 267e83ce340SAdrian Chadd break; 268e83ce340SAdrian Chadd 269e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_RESERVED: 270e83ce340SAdrian Chadd default: 271e83ce340SAdrian Chadd device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl); 272e83ce340SAdrian Chadd return (0); 273e83ce340SAdrian Chadd } 274e83ce340SAdrian Chadd 275e83ce340SAdrian Chadd if (sprom_sz > sprom_win->win_size) { 276e83ce340SAdrian Chadd device_printf(sc->dev, 277e83ce340SAdrian Chadd "PCI sprom size (0x%x) overruns defined register window\n", 278e83ce340SAdrian Chadd sctl); 279e83ce340SAdrian Chadd return (0); 280e83ce340SAdrian Chadd } 281e83ce340SAdrian Chadd 282e83ce340SAdrian Chadd return (sprom_sz); 283e83ce340SAdrian Chadd } 284e83ce340SAdrian Chadd 2854ad7e9b0SAdrian Chadd /* 2864ad7e9b0SAdrian Chadd * On devices without a SROM, the PCI(e) cores will be initialized with 287bb64eeccSAdrian Chadd * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows 288bb64eeccSAdrian Chadd * mapped to the wrong core. 2894ad7e9b0SAdrian Chadd * 290bb64eeccSAdrian Chadd * This function updates the SROM shadow to point the BAR0 windows at the 2914ad7e9b0SAdrian Chadd * current PCI core. 2924ad7e9b0SAdrian Chadd * 293bb64eeccSAdrian Chadd * Applies to all PCI/PCIe revisions. 2944ad7e9b0SAdrian Chadd */ 2954ad7e9b0SAdrian Chadd static void 2964ad7e9b0SAdrian Chadd bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) 2974ad7e9b0SAdrian Chadd { 298bb64eeccSAdrian Chadd struct bhndb_resources *bres; 299bb64eeccSAdrian Chadd const struct bhndb_hwcfg *cfg; 300bb64eeccSAdrian Chadd const struct bhndb_regwin *win; 301bb64eeccSAdrian Chadd struct resource *core_regs; 302bb64eeccSAdrian Chadd bus_size_t srom_offset; 303bb64eeccSAdrian Chadd u_int pci_cidx, sprom_cidx; 3044ad7e9b0SAdrian Chadd uint16_t val; 3054ad7e9b0SAdrian Chadd 306bb64eeccSAdrian Chadd bres = sc->bhndb.bus_res; 307bb64eeccSAdrian Chadd cfg = bres->cfg; 308bb64eeccSAdrian Chadd 309bb64eeccSAdrian Chadd if (bhnd_get_vendor(sc->bhndb.hostb_dev) != BHND_MFGID_BCM) 310bb64eeccSAdrian Chadd return; 311bb64eeccSAdrian Chadd 312bb64eeccSAdrian Chadd switch (bhnd_get_device(sc->bhndb.hostb_dev)) { 313bb64eeccSAdrian Chadd case BHND_COREID_PCI: 314bb64eeccSAdrian Chadd srom_offset = BHND_PCI_SRSH_PI_OFFSET; 315bb64eeccSAdrian Chadd break; 316bb64eeccSAdrian Chadd case BHND_COREID_PCIE: 317bb64eeccSAdrian Chadd srom_offset = BHND_PCIE_SRSH_PI_OFFSET; 318bb64eeccSAdrian Chadd break; 319bb64eeccSAdrian Chadd default: 320bb64eeccSAdrian Chadd device_printf(sc->dev, "unsupported PCI host bridge device\n"); 321bb64eeccSAdrian Chadd return; 322bb64eeccSAdrian Chadd } 323bb64eeccSAdrian Chadd 324bb64eeccSAdrian Chadd /* Locate the static register window mapping the PCI core */ 325bb64eeccSAdrian Chadd win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass, 326bb64eeccSAdrian Chadd 0, BHND_PORT_DEVICE, 0, 0); 327bb64eeccSAdrian Chadd if (win == NULL) { 328bb64eeccSAdrian Chadd device_printf(sc->dev, "missing PCI core register window\n"); 329bb64eeccSAdrian Chadd return; 330bb64eeccSAdrian Chadd } 331bb64eeccSAdrian Chadd 332bb64eeccSAdrian Chadd /* Fetch the resource containing the register window */ 333bb64eeccSAdrian Chadd core_regs = bhndb_find_regwin_resource(bres, win); 334bb64eeccSAdrian Chadd if (core_regs == NULL) { 335bb64eeccSAdrian Chadd device_printf(sc->dev, "missing PCI core register resource\n"); 336bb64eeccSAdrian Chadd return; 337bb64eeccSAdrian Chadd } 338bb64eeccSAdrian Chadd 3394ad7e9b0SAdrian Chadd /* Fetch the SPROM's configured core index */ 340bb64eeccSAdrian Chadd val = bus_read_2(core_regs, win->win_offset + srom_offset); 341bb64eeccSAdrian Chadd sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT; 3424ad7e9b0SAdrian Chadd 3434ad7e9b0SAdrian Chadd /* If it doesn't match host bridge's core index, update the index 3444ad7e9b0SAdrian Chadd * value */ 345bb64eeccSAdrian Chadd pci_cidx = bhnd_get_core_index(sc->bhndb.hostb_dev); 346bb64eeccSAdrian Chadd if (sprom_cidx != pci_cidx) { 347bb64eeccSAdrian Chadd val &= ~BHND_PCI_SRSH_PI_MASK; 348bb64eeccSAdrian Chadd val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT); 349bb64eeccSAdrian Chadd bus_write_2(core_regs, 350bb64eeccSAdrian Chadd win->win_offset + srom_offset, val); 3514ad7e9b0SAdrian Chadd } 3524ad7e9b0SAdrian Chadd } 3534ad7e9b0SAdrian Chadd 3544ad7e9b0SAdrian Chadd static int 3554ad7e9b0SAdrian Chadd bhndb_pci_resume(device_t dev) 3564ad7e9b0SAdrian Chadd { 3574ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc; 3584ad7e9b0SAdrian Chadd int error; 3594ad7e9b0SAdrian Chadd 3604ad7e9b0SAdrian Chadd sc = device_get_softc(dev); 3614ad7e9b0SAdrian Chadd 362bb64eeccSAdrian Chadd /* Enable clocks (if supported by this hardware) */ 363bb64eeccSAdrian Chadd if ((error = bhndb_enable_pci_clocks(sc))) 3644ad7e9b0SAdrian Chadd return (error); 3654ad7e9b0SAdrian Chadd 366bb64eeccSAdrian Chadd /* Perform resume */ 367bb64eeccSAdrian Chadd return (bhndb_generic_resume(dev)); 368bb64eeccSAdrian Chadd } 369bb64eeccSAdrian Chadd 370bb64eeccSAdrian Chadd static int 371bb64eeccSAdrian Chadd bhndb_pci_suspend(device_t dev) 372bb64eeccSAdrian Chadd { 373bb64eeccSAdrian Chadd struct bhndb_pci_softc *sc; 374bb64eeccSAdrian Chadd int error; 375bb64eeccSAdrian Chadd 376bb64eeccSAdrian Chadd sc = device_get_softc(dev); 377bb64eeccSAdrian Chadd 378bb64eeccSAdrian Chadd /* Disable clocks (if supported by this hardware) */ 379bb64eeccSAdrian Chadd if ((error = bhndb_disable_pci_clocks(sc))) 3804ad7e9b0SAdrian Chadd return (error); 3814ad7e9b0SAdrian Chadd 382bb64eeccSAdrian Chadd /* Perform suspend */ 383bb64eeccSAdrian Chadd return (bhndb_generic_suspend(dev)); 384bb64eeccSAdrian Chadd } 385bb64eeccSAdrian Chadd 386bb64eeccSAdrian Chadd static int 387bb64eeccSAdrian Chadd bhndb_pci_detach(device_t dev) 388bb64eeccSAdrian Chadd { 389bb64eeccSAdrian Chadd struct bhndb_pci_softc *sc; 390bb64eeccSAdrian Chadd int error; 391bb64eeccSAdrian Chadd 392bb64eeccSAdrian Chadd sc = device_get_softc(dev); 393bb64eeccSAdrian Chadd 394bb64eeccSAdrian Chadd /* Disable clocks (if supported by this hardware) */ 395bb64eeccSAdrian Chadd if ((error = bhndb_disable_pci_clocks(sc))) 396bb64eeccSAdrian Chadd return (error); 397bb64eeccSAdrian Chadd 398bb64eeccSAdrian Chadd /* Perform detach */ 399bb64eeccSAdrian Chadd if ((error = bhndb_generic_detach(dev))) 400bb64eeccSAdrian Chadd return (error); 401bb64eeccSAdrian Chadd 402bb64eeccSAdrian Chadd /* Disable PCI bus mastering */ 403e83ce340SAdrian Chadd pci_disable_busmaster(sc->parent); 404bb64eeccSAdrian Chadd 4054ad7e9b0SAdrian Chadd return (0); 4064ad7e9b0SAdrian Chadd } 4074ad7e9b0SAdrian Chadd 4084ad7e9b0SAdrian Chadd static int 4094ad7e9b0SAdrian Chadd bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw, 4104ad7e9b0SAdrian Chadd bhnd_addr_t addr) 4114ad7e9b0SAdrian Chadd { 4124ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc = device_get_softc(dev); 4134ad7e9b0SAdrian Chadd return (sc->set_regwin(sc, rw, addr)); 4144ad7e9b0SAdrian Chadd } 4154ad7e9b0SAdrian Chadd 4164ad7e9b0SAdrian Chadd /** 4174ad7e9b0SAdrian Chadd * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation. 4184ad7e9b0SAdrian Chadd * 4194ad7e9b0SAdrian Chadd * On siba(4) devices, it's possible that writing a PCI window register may 4204ad7e9b0SAdrian Chadd * not succeed; it's necessary to immediately read the configuration register 4214ad7e9b0SAdrian Chadd * and retry if not set to the desired value. 4224ad7e9b0SAdrian Chadd * 4234ad7e9b0SAdrian Chadd * This is not necessary on bcma(4) devices, but other than the overhead of 4244ad7e9b0SAdrian Chadd * validating the register, there's no harm in performing the verification. 4254ad7e9b0SAdrian Chadd */ 4264ad7e9b0SAdrian Chadd static int 4274ad7e9b0SAdrian Chadd bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc, 4284ad7e9b0SAdrian Chadd const struct bhndb_regwin *rw, bhnd_addr_t addr) 4294ad7e9b0SAdrian Chadd { 4304ad7e9b0SAdrian Chadd int error; 431e83ce340SAdrian Chadd int reg; 4324ad7e9b0SAdrian Chadd 4334ad7e9b0SAdrian Chadd if (rw->win_type != BHNDB_REGWIN_T_DYN) 4344ad7e9b0SAdrian Chadd return (ENODEV); 4354ad7e9b0SAdrian Chadd 436e83ce340SAdrian Chadd reg = rw->d.dyn.cfg_offset; 4374ad7e9b0SAdrian Chadd for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) { 4384ad7e9b0SAdrian Chadd if ((error = bhndb_pci_fast_setregwin(sc, rw, addr))) 4394ad7e9b0SAdrian Chadd return (error); 4404ad7e9b0SAdrian Chadd 441e83ce340SAdrian Chadd if (pci_read_config(sc->parent, reg, 4) == addr) 4424ad7e9b0SAdrian Chadd return (0); 4434ad7e9b0SAdrian Chadd 4444ad7e9b0SAdrian Chadd DELAY(10); 4454ad7e9b0SAdrian Chadd } 4464ad7e9b0SAdrian Chadd 4474ad7e9b0SAdrian Chadd /* Unable to set window */ 4484ad7e9b0SAdrian Chadd return (ENODEV); 4494ad7e9b0SAdrian Chadd } 4504ad7e9b0SAdrian Chadd 4514ad7e9b0SAdrian Chadd /** 4524ad7e9b0SAdrian Chadd * A bcma(4)-only bhndb_set_window_addr implementation. 4534ad7e9b0SAdrian Chadd */ 4544ad7e9b0SAdrian Chadd static int 4554ad7e9b0SAdrian Chadd bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc, 4564ad7e9b0SAdrian Chadd const struct bhndb_regwin *rw, bhnd_addr_t addr) 4574ad7e9b0SAdrian Chadd { 4584ad7e9b0SAdrian Chadd /* The PCI bridge core only supports 32-bit addressing, regardless 4594ad7e9b0SAdrian Chadd * of the bus' support for 64-bit addressing */ 4604ad7e9b0SAdrian Chadd if (addr > UINT32_MAX) 4614ad7e9b0SAdrian Chadd return (ERANGE); 4624ad7e9b0SAdrian Chadd 4634ad7e9b0SAdrian Chadd switch (rw->win_type) { 4644ad7e9b0SAdrian Chadd case BHNDB_REGWIN_T_DYN: 4654ad7e9b0SAdrian Chadd /* Addresses must be page aligned */ 4664ad7e9b0SAdrian Chadd if (addr % rw->win_size != 0) 4674ad7e9b0SAdrian Chadd return (EINVAL); 4684ad7e9b0SAdrian Chadd 469e83ce340SAdrian Chadd pci_write_config(sc->parent, rw->d.dyn.cfg_offset, addr, 4); 4704ad7e9b0SAdrian Chadd break; 4714ad7e9b0SAdrian Chadd default: 4724ad7e9b0SAdrian Chadd return (ENODEV); 4734ad7e9b0SAdrian Chadd } 4744ad7e9b0SAdrian Chadd 4754ad7e9b0SAdrian Chadd return (0); 4764ad7e9b0SAdrian Chadd } 4774ad7e9b0SAdrian Chadd 478d567592bSAdrian Chadd static int 479d567592bSAdrian Chadd bhndb_pci_populate_board_info(device_t dev, device_t child, 480d567592bSAdrian Chadd struct bhnd_board_info *info) 481d567592bSAdrian Chadd { 482d567592bSAdrian Chadd struct bhndb_pci_softc *sc; 483d567592bSAdrian Chadd 484d567592bSAdrian Chadd sc = device_get_softc(dev); 485d567592bSAdrian Chadd 4868ef24a0dSAdrian Chadd /* 4878ef24a0dSAdrian Chadd * On a subset of Apple BCM4360 modules, always prefer the 4888ef24a0dSAdrian Chadd * PCI subdevice to the SPROM-supplied boardtype. 4898ef24a0dSAdrian Chadd * 4908ef24a0dSAdrian Chadd * TODO: 4918ef24a0dSAdrian Chadd * 4928ef24a0dSAdrian Chadd * Broadcom's own drivers implement this override, and then later use 4938ef24a0dSAdrian Chadd * the remapped BCM4360 board type to determine the required 4948ef24a0dSAdrian Chadd * board-specific workarounds. 4958ef24a0dSAdrian Chadd * 4968ef24a0dSAdrian Chadd * Without access to this hardware, it's unclear why this mapping 4978ef24a0dSAdrian Chadd * is done, and we must do the same. If we can survey the hardware 4988ef24a0dSAdrian Chadd * in question, it may be possible to replace this behavior with 4998ef24a0dSAdrian Chadd * explicit references to the SPROM-supplied boardtype(s) in our 5008ef24a0dSAdrian Chadd * quirk definitions. 5018ef24a0dSAdrian Chadd */ 5028ef24a0dSAdrian Chadd if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) { 5038ef24a0dSAdrian Chadd switch (info->board_type) { 5048ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X29C: 5058ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X29CP2: 5068ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X51: 5078ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X51P2: 5088ef24a0dSAdrian Chadd info->board_type = 0; /* allow override below */ 5098ef24a0dSAdrian Chadd break; 5108ef24a0dSAdrian Chadd default: 5118ef24a0dSAdrian Chadd break; 5128ef24a0dSAdrian Chadd } 5138ef24a0dSAdrian Chadd } 5148ef24a0dSAdrian Chadd 515d567592bSAdrian Chadd /* If NVRAM did not supply vendor/type info, provide the PCI 516d567592bSAdrian Chadd * subvendor/subdevice values. */ 517d567592bSAdrian Chadd if (info->board_vendor == 0) 518d567592bSAdrian Chadd info->board_vendor = pci_get_subvendor(sc->parent); 519d567592bSAdrian Chadd 520d567592bSAdrian Chadd if (info->board_type == 0) 521d567592bSAdrian Chadd info->board_type = pci_get_subdevice(sc->parent); 522d567592bSAdrian Chadd 523d567592bSAdrian Chadd return (0); 524d567592bSAdrian Chadd } 525d567592bSAdrian Chadd 5264ad7e9b0SAdrian Chadd /** 527bb64eeccSAdrian Chadd * Enable externally managed clocks, if required. 5284ad7e9b0SAdrian Chadd * 529bb64eeccSAdrian Chadd * Some PCI chipsets (BCM4306, possibly others) chips do not support 530bb64eeccSAdrian Chadd * the idle low-power clock. Clocking must be bootstrapped at 531bb64eeccSAdrian Chadd * attach/resume by directly adjusting GPIO registers exposed in the 532bb64eeccSAdrian Chadd * PCI config space, and correspondingly, explicitly shutdown at 533bb64eeccSAdrian Chadd * detach/suspend. 5344ad7e9b0SAdrian Chadd * 5354ad7e9b0SAdrian Chadd * @param sc Bridge driver state. 5364ad7e9b0SAdrian Chadd */ 5374ad7e9b0SAdrian Chadd static int 5384ad7e9b0SAdrian Chadd bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) 5394ad7e9b0SAdrian Chadd { 5404ad7e9b0SAdrian Chadd uint32_t gpio_in, gpio_out, gpio_en; 5414ad7e9b0SAdrian Chadd uint32_t gpio_flags; 5424ad7e9b0SAdrian Chadd uint16_t pci_status; 5434ad7e9b0SAdrian Chadd 544bb64eeccSAdrian Chadd /* Only supported and required on PCI devices */ 545bb64eeccSAdrian Chadd if (sc->pci_devclass != BHND_DEVCLASS_PCI) 546bb64eeccSAdrian Chadd return (0); 5474ad7e9b0SAdrian Chadd 5484ad7e9b0SAdrian Chadd /* Read state of XTAL pin */ 549e83ce340SAdrian Chadd gpio_in = pci_read_config(sc->parent, BHNDB_PCI_GPIO_IN, 4); 5504ad7e9b0SAdrian Chadd if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON) 5514ad7e9b0SAdrian Chadd return (0); /* already enabled */ 5524ad7e9b0SAdrian Chadd 5534ad7e9b0SAdrian Chadd /* Fetch current config */ 554e83ce340SAdrian Chadd gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 555e83ce340SAdrian Chadd gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 5564ad7e9b0SAdrian Chadd 5574ad7e9b0SAdrian Chadd /* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */ 5584ad7e9b0SAdrian Chadd gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 5594ad7e9b0SAdrian Chadd gpio_out |= gpio_flags; 5604ad7e9b0SAdrian Chadd gpio_en |= gpio_flags; 5614ad7e9b0SAdrian Chadd 562e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 563e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 5644ad7e9b0SAdrian Chadd DELAY(1000); 5654ad7e9b0SAdrian Chadd 5664ad7e9b0SAdrian Chadd /* Reset PLL_OFF */ 5674ad7e9b0SAdrian Chadd gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; 568e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 5694ad7e9b0SAdrian Chadd DELAY(5000); 5704ad7e9b0SAdrian Chadd 5714ad7e9b0SAdrian Chadd /* Clear any PCI 'sent target-abort' flag. */ 572e83ce340SAdrian Chadd pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2); 5734ad7e9b0SAdrian Chadd pci_status &= ~PCIM_STATUS_STABORT; 574e83ce340SAdrian Chadd pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2); 5754ad7e9b0SAdrian Chadd 5764ad7e9b0SAdrian Chadd return (0); 5774ad7e9b0SAdrian Chadd } 5784ad7e9b0SAdrian Chadd 5794ad7e9b0SAdrian Chadd /** 580bb64eeccSAdrian Chadd * Disable externally managed clocks, if required. 5814ad7e9b0SAdrian Chadd * 5824ad7e9b0SAdrian Chadd * @param sc Bridge driver state. 5834ad7e9b0SAdrian Chadd */ 5844ad7e9b0SAdrian Chadd static int 5854ad7e9b0SAdrian Chadd bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) 5864ad7e9b0SAdrian Chadd { 5874ad7e9b0SAdrian Chadd uint32_t gpio_out, gpio_en; 5884ad7e9b0SAdrian Chadd 589bb64eeccSAdrian Chadd /* Only supported and required on PCI devices */ 590bb64eeccSAdrian Chadd if (sc->pci_devclass != BHND_DEVCLASS_PCI) 591bb64eeccSAdrian Chadd return (0); 5924ad7e9b0SAdrian Chadd 5934ad7e9b0SAdrian Chadd /* Fetch current config */ 594e83ce340SAdrian Chadd gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 595e83ce340SAdrian Chadd gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 5964ad7e9b0SAdrian Chadd 5974ad7e9b0SAdrian Chadd /* Set PLL_OFF to HIGH, XTAL_ON to LOW. */ 5984ad7e9b0SAdrian Chadd gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON; 5994ad7e9b0SAdrian Chadd gpio_out |= BHNDB_PCI_GPIO_PLL_OFF; 600e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 6014ad7e9b0SAdrian Chadd 6024ad7e9b0SAdrian Chadd /* Enable both output pins */ 6034ad7e9b0SAdrian Chadd gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 604e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 6054ad7e9b0SAdrian Chadd 6064ad7e9b0SAdrian Chadd return (0); 6074ad7e9b0SAdrian Chadd } 6084ad7e9b0SAdrian Chadd 609*f90f4b65SLandon J. Fuller static bhnd_clksrc 610*f90f4b65SLandon J. Fuller bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child, 611*f90f4b65SLandon J. Fuller bhnd_clock clock) 612*f90f4b65SLandon J. Fuller { 613*f90f4b65SLandon J. Fuller struct bhndb_pci_softc *sc; 614*f90f4b65SLandon J. Fuller uint32_t gpio_out; 615*f90f4b65SLandon J. Fuller 616*f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 617*f90f4b65SLandon J. Fuller 618*f90f4b65SLandon J. Fuller /* Only supported on PCI devices */ 619*f90f4b65SLandon J. Fuller if (sc->pci_devclass != BHND_DEVCLASS_PCI) 620*f90f4b65SLandon J. Fuller return (ENODEV); 621*f90f4b65SLandon J. Fuller 622*f90f4b65SLandon J. Fuller /* Only ILP is supported */ 623*f90f4b65SLandon J. Fuller if (clock != BHND_CLOCK_ILP) 624*f90f4b65SLandon J. Fuller return (ENXIO); 625*f90f4b65SLandon J. Fuller 626*f90f4b65SLandon J. Fuller gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 627*f90f4b65SLandon J. Fuller if (gpio_out & BHNDB_PCI_GPIO_SCS) 628*f90f4b65SLandon J. Fuller return (BHND_CLKSRC_PCI); 629*f90f4b65SLandon J. Fuller else 630*f90f4b65SLandon J. Fuller return (BHND_CLKSRC_XTAL); 631*f90f4b65SLandon J. Fuller } 632*f90f4b65SLandon J. Fuller 633*f90f4b65SLandon J. Fuller static int 634*f90f4b65SLandon J. Fuller bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child, 635*f90f4b65SLandon J. Fuller bhnd_clock clock) 636*f90f4b65SLandon J. Fuller { 637*f90f4b65SLandon J. Fuller struct bhndb_pci_softc *sc = device_get_softc(dev); 638*f90f4b65SLandon J. Fuller 639*f90f4b65SLandon J. Fuller /* Only supported on PCI devices */ 640*f90f4b65SLandon J. Fuller if (sc->pci_devclass != BHND_DEVCLASS_PCI) 641*f90f4b65SLandon J. Fuller return (ENODEV); 642*f90f4b65SLandon J. Fuller 643*f90f4b65SLandon J. Fuller /* Only HT is supported */ 644*f90f4b65SLandon J. Fuller if (clock != BHND_CLOCK_HT) 645*f90f4b65SLandon J. Fuller return (ENXIO); 646*f90f4b65SLandon J. Fuller 647*f90f4b65SLandon J. Fuller return (bhndb_disable_pci_clocks(sc)); 648*f90f4b65SLandon J. Fuller } 649*f90f4b65SLandon J. Fuller 650*f90f4b65SLandon J. Fuller static int 651*f90f4b65SLandon J. Fuller bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child, 652*f90f4b65SLandon J. Fuller bhnd_clock clock) 653*f90f4b65SLandon J. Fuller { 654*f90f4b65SLandon J. Fuller struct bhndb_pci_softc *sc = device_get_softc(dev); 655*f90f4b65SLandon J. Fuller 656*f90f4b65SLandon J. Fuller /* Only supported on PCI devices */ 657*f90f4b65SLandon J. Fuller if (sc->pci_devclass != BHND_DEVCLASS_PCI) 658*f90f4b65SLandon J. Fuller return (ENODEV); 659*f90f4b65SLandon J. Fuller 660*f90f4b65SLandon J. Fuller /* Only HT is supported */ 661*f90f4b65SLandon J. Fuller if (clock != BHND_CLOCK_HT) 662*f90f4b65SLandon J. Fuller return (ENXIO); 663*f90f4b65SLandon J. Fuller 664*f90f4b65SLandon J. Fuller return (bhndb_enable_pci_clocks(sc)); 665*f90f4b65SLandon J. Fuller } 666*f90f4b65SLandon J. Fuller 6674ad7e9b0SAdrian Chadd static device_method_t bhndb_pci_methods[] = { 6684ad7e9b0SAdrian Chadd /* Device interface */ 6694ad7e9b0SAdrian Chadd DEVMETHOD(device_probe, bhndb_pci_probe), 6704ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bhndb_pci_attach), 6714ad7e9b0SAdrian Chadd DEVMETHOD(device_resume, bhndb_pci_resume), 672bb64eeccSAdrian Chadd DEVMETHOD(device_suspend, bhndb_pci_suspend), 673bb64eeccSAdrian Chadd DEVMETHOD(device_detach, bhndb_pci_detach), 6744ad7e9b0SAdrian Chadd 675*f90f4b65SLandon J. Fuller /* BHND interface */ 676*f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhndb_pci_pwrctl_get_clksrc), 677*f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhndb_pci_pwrctl_gate_clock), 678*f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock), 679*f90f4b65SLandon J. Fuller 6804ad7e9b0SAdrian Chadd /* BHNDB interface */ 6814ad7e9b0SAdrian Chadd DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config), 6824ad7e9b0SAdrian Chadd DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr), 683d567592bSAdrian Chadd DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info), 6844ad7e9b0SAdrian Chadd 6854ad7e9b0SAdrian Chadd DEVMETHOD_END 6864ad7e9b0SAdrian Chadd }; 6874ad7e9b0SAdrian Chadd 6884ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, 6894ad7e9b0SAdrian Chadd sizeof(struct bhndb_pci_softc), bhndb_driver); 6904ad7e9b0SAdrian Chadd 6914ad7e9b0SAdrian Chadd MODULE_VERSION(bhndb_pci, 1); 692148ed571SAdrian Chadd MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1); 6934ad7e9b0SAdrian Chadd MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); 6944ad7e9b0SAdrian Chadd MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1); 695148ed571SAdrian Chadd MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1); 696