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 65*111d7cb2SLandon J. Fuller static int bhndb_pci_add_children(struct bhndb_pci_softc *sc); 66*111d7cb2SLandon J. Fuller 674ad7e9b0SAdrian Chadd static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc); 684ad7e9b0SAdrian Chadd static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc); 694ad7e9b0SAdrian Chadd 704ad7e9b0SAdrian Chadd static int bhndb_pci_compat_setregwin(struct bhndb_pci_softc *, 714ad7e9b0SAdrian Chadd const struct bhndb_regwin *, bhnd_addr_t); 724ad7e9b0SAdrian Chadd static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, 734ad7e9b0SAdrian Chadd const struct bhndb_regwin *, bhnd_addr_t); 744ad7e9b0SAdrian Chadd 75e83ce340SAdrian Chadd static void bhndb_init_sromless_pci_config( 76e83ce340SAdrian Chadd struct bhndb_pci_softc *sc); 77e83ce340SAdrian Chadd 78e83ce340SAdrian Chadd static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc); 79f9cf87a0SAdrian Chadd static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc); 804ad7e9b0SAdrian Chadd 814ad7e9b0SAdrian Chadd /** 824ad7e9b0SAdrian Chadd * Default bhndb_pci implementation of device_probe(). 834ad7e9b0SAdrian Chadd * 844ad7e9b0SAdrian Chadd * Verifies that the parent is a PCI/PCIe device. 854ad7e9b0SAdrian Chadd */ 864ad7e9b0SAdrian Chadd static int 874ad7e9b0SAdrian Chadd bhndb_pci_probe(device_t dev) 884ad7e9b0SAdrian Chadd { 894ad7e9b0SAdrian Chadd device_t parent; 904ad7e9b0SAdrian Chadd devclass_t parent_bus; 914ad7e9b0SAdrian Chadd devclass_t pci; 924ad7e9b0SAdrian Chadd 934ad7e9b0SAdrian Chadd /* Our parent must be a PCI/PCIe device. */ 944ad7e9b0SAdrian Chadd pci = devclass_find("pci"); 954ad7e9b0SAdrian Chadd parent = device_get_parent(dev); 964ad7e9b0SAdrian Chadd parent_bus = device_get_devclass(device_get_parent(parent)); 974ad7e9b0SAdrian Chadd 984ad7e9b0SAdrian Chadd if (parent_bus != pci) 994ad7e9b0SAdrian Chadd return (ENXIO); 1004ad7e9b0SAdrian Chadd 1014ad7e9b0SAdrian Chadd device_set_desc(dev, "PCI-BHND bridge"); 1024ad7e9b0SAdrian Chadd 1034ad7e9b0SAdrian Chadd return (BUS_PROBE_DEFAULT); 1044ad7e9b0SAdrian Chadd } 1054ad7e9b0SAdrian Chadd 1064ad7e9b0SAdrian Chadd static int 1074ad7e9b0SAdrian Chadd bhndb_pci_attach(device_t dev) 1084ad7e9b0SAdrian Chadd { 1094ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc; 1104ad7e9b0SAdrian Chadd int error, reg; 1114ad7e9b0SAdrian Chadd 1124ad7e9b0SAdrian Chadd sc = device_get_softc(dev); 1134ad7e9b0SAdrian Chadd sc->dev = dev; 114e83ce340SAdrian Chadd sc->parent = device_get_parent(dev); 1154ad7e9b0SAdrian Chadd sc->set_regwin = bhndb_pci_compat_setregwin; 1164ad7e9b0SAdrian Chadd 117*111d7cb2SLandon J. Fuller if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0) 118*111d7cb2SLandon J. Fuller sc->pci_devclass = BHND_DEVCLASS_PCIE; 119*111d7cb2SLandon J. Fuller else 120*111d7cb2SLandon J. Fuller sc->pci_devclass = BHND_DEVCLASS_PCI; 1214ad7e9b0SAdrian Chadd 122*111d7cb2SLandon J. Fuller /* Enable clocks (if required by this hardware) */ 123*111d7cb2SLandon J. Fuller if ((error = bhndb_enable_pci_clocks(sc))) 124*111d7cb2SLandon J. Fuller goto cleanup; 125*111d7cb2SLandon J. Fuller 126*111d7cb2SLandon J. Fuller /* Perform bridge attach, fully initializing the bridge 127*111d7cb2SLandon J. Fuller * configuration. */ 128*111d7cb2SLandon J. Fuller if ((error = bhndb_attach(dev, sc->pci_devclass))) 129*111d7cb2SLandon J. Fuller goto cleanup; 130*111d7cb2SLandon J. Fuller 131*111d7cb2SLandon J. Fuller /* If supported, switch to faster regwin handling */ 1324ad7e9b0SAdrian Chadd if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) { 1334ad7e9b0SAdrian Chadd atomic_store_rel_ptr((volatile void *) &sc->set_regwin, 1344ad7e9b0SAdrian Chadd (uintptr_t) &bhndb_pci_fast_setregwin); 1354ad7e9b0SAdrian Chadd } 1364ad7e9b0SAdrian Chadd 137*111d7cb2SLandon J. Fuller /* Enable PCI bus mastering */ 138*111d7cb2SLandon J. Fuller pci_enable_busmaster(sc->parent); 1394ad7e9b0SAdrian Chadd 140bb64eeccSAdrian Chadd /* Fix-up power on defaults for SROM-less devices. */ 1414ad7e9b0SAdrian Chadd bhndb_init_sromless_pci_config(sc); 1424ad7e9b0SAdrian Chadd 143*111d7cb2SLandon J. Fuller /* Add any additional child devices */ 144*111d7cb2SLandon J. Fuller if ((error = bhndb_pci_add_children(sc))) 145*111d7cb2SLandon J. Fuller goto cleanup; 146*111d7cb2SLandon J. Fuller 147*111d7cb2SLandon J. Fuller /* Probe and attach our children */ 148*111d7cb2SLandon J. Fuller if ((error = bus_generic_attach(dev))) 149*111d7cb2SLandon J. Fuller goto cleanup; 150*111d7cb2SLandon J. Fuller 151*111d7cb2SLandon J. Fuller return (0); 152*111d7cb2SLandon J. Fuller 153*111d7cb2SLandon J. Fuller cleanup: 154*111d7cb2SLandon J. Fuller device_delete_children(dev); 155*111d7cb2SLandon J. Fuller bhndb_disable_pci_clocks(sc); 156*111d7cb2SLandon J. Fuller pci_disable_busmaster(sc->parent); 157*111d7cb2SLandon J. Fuller 158*111d7cb2SLandon J. Fuller return (error); 159*111d7cb2SLandon J. Fuller } 160*111d7cb2SLandon J. Fuller 161*111d7cb2SLandon J. Fuller static int 162*111d7cb2SLandon J. Fuller bhndb_pci_detach(device_t dev) 163*111d7cb2SLandon J. Fuller { 164*111d7cb2SLandon J. Fuller struct bhndb_pci_softc *sc; 165*111d7cb2SLandon J. Fuller int error; 166*111d7cb2SLandon J. Fuller 167*111d7cb2SLandon J. Fuller sc = device_get_softc(dev); 168*111d7cb2SLandon J. Fuller 169*111d7cb2SLandon J. Fuller /* Attempt to detach our children */ 170*111d7cb2SLandon J. Fuller if ((error = bus_generic_detach(dev))) 171*111d7cb2SLandon J. Fuller return (error); 172*111d7cb2SLandon J. Fuller 173*111d7cb2SLandon J. Fuller /* Perform generic bridge detach */ 174*111d7cb2SLandon J. Fuller if ((error = bhndb_generic_detach(dev))) 175*111d7cb2SLandon J. Fuller return (error); 176*111d7cb2SLandon J. Fuller 177*111d7cb2SLandon J. Fuller /* Disable clocks (if required by this hardware) */ 178*111d7cb2SLandon J. Fuller if ((error = bhndb_disable_pci_clocks(sc))) 179*111d7cb2SLandon J. Fuller return (error); 180*111d7cb2SLandon J. Fuller 181*111d7cb2SLandon J. Fuller /* Disable PCI bus mastering */ 182*111d7cb2SLandon J. Fuller pci_disable_busmaster(sc->parent); 183*111d7cb2SLandon J. Fuller 184*111d7cb2SLandon J. Fuller return (0); 185*111d7cb2SLandon J. Fuller } 186*111d7cb2SLandon J. Fuller 187*111d7cb2SLandon J. Fuller static int 188*111d7cb2SLandon J. Fuller bhndb_pci_add_children(struct bhndb_pci_softc *sc) 189*111d7cb2SLandon J. Fuller { 190*111d7cb2SLandon J. Fuller bus_size_t nv_sz; 191*111d7cb2SLandon J. Fuller int error; 192*111d7cb2SLandon J. Fuller 193*111d7cb2SLandon J. Fuller /** 194*111d7cb2SLandon J. Fuller * If SPROM is mapped directly into BAR0, add child NVRAM 195*111d7cb2SLandon J. Fuller * device. 196*111d7cb2SLandon J. Fuller */ 197e83ce340SAdrian Chadd nv_sz = bhndb_pci_sprom_size(sc); 198e83ce340SAdrian Chadd if (nv_sz > 0) { 199e83ce340SAdrian Chadd struct bhndb_devinfo *dinfo; 200*111d7cb2SLandon J. Fuller device_t child; 201e83ce340SAdrian Chadd 202e83ce340SAdrian Chadd if (bootverbose) { 203*111d7cb2SLandon J. Fuller device_printf(sc->dev, "found SPROM (%ju bytes)\n", 204*111d7cb2SLandon J. Fuller (uintmax_t)nv_sz); 205e83ce340SAdrian Chadd } 206e83ce340SAdrian Chadd 207*111d7cb2SLandon J. Fuller /* Add sprom device, ordered early enough to be available 208*111d7cb2SLandon J. Fuller * before the bridged bhnd(4) bus is attached. */ 209*111d7cb2SLandon J. Fuller child = BUS_ADD_CHILD(sc->dev, 210*111d7cb2SLandon J. Fuller BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY, "bhnd_nvram", -1); 211*111d7cb2SLandon J. Fuller if (child == NULL) { 212*111d7cb2SLandon J. Fuller device_printf(sc->dev, "failed to add sprom device\n"); 213e83ce340SAdrian Chadd return (ENXIO); 214e83ce340SAdrian Chadd } 215e83ce340SAdrian Chadd 216e83ce340SAdrian Chadd /* Initialize device address space and resource covering the 217e83ce340SAdrian Chadd * BAR0 SPROM shadow. */ 218*111d7cb2SLandon J. Fuller dinfo = device_get_ivars(child); 219e83ce340SAdrian Chadd dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; 220*111d7cb2SLandon J. Fuller 221*111d7cb2SLandon J. Fuller error = bus_set_resource(child, SYS_RES_MEMORY, 0, 222e83ce340SAdrian Chadd bhndb_pci_sprom_addr(sc), nv_sz); 223e83ce340SAdrian Chadd if (error) { 224*111d7cb2SLandon J. Fuller device_printf(sc->dev, 225e83ce340SAdrian Chadd "failed to register sprom resources\n"); 226e83ce340SAdrian Chadd return (error); 227e83ce340SAdrian Chadd } 228e83ce340SAdrian Chadd } 229e83ce340SAdrian Chadd 2304ad7e9b0SAdrian Chadd return (0); 2314ad7e9b0SAdrian Chadd } 2324ad7e9b0SAdrian Chadd 233e83ce340SAdrian Chadd static const struct bhndb_regwin * 234e83ce340SAdrian Chadd bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc) 235e83ce340SAdrian Chadd { 236e83ce340SAdrian Chadd struct bhndb_resources *bres; 237e83ce340SAdrian Chadd const struct bhndb_hwcfg *cfg; 238e83ce340SAdrian Chadd const struct bhndb_regwin *sprom_win; 239e83ce340SAdrian Chadd 240e83ce340SAdrian Chadd bres = sc->bhndb.bus_res; 241e83ce340SAdrian Chadd cfg = bres->cfg; 242e83ce340SAdrian Chadd 243e83ce340SAdrian Chadd sprom_win = bhndb_regwin_find_type(cfg->register_windows, 244e83ce340SAdrian Chadd BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE); 245e83ce340SAdrian Chadd 246e83ce340SAdrian Chadd return (sprom_win); 247e83ce340SAdrian Chadd } 248e83ce340SAdrian Chadd 249e83ce340SAdrian Chadd static bus_addr_t 250e83ce340SAdrian Chadd bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc) 251e83ce340SAdrian Chadd { 252e83ce340SAdrian Chadd const struct bhndb_regwin *sprom_win; 253e83ce340SAdrian Chadd struct resource *r; 254e83ce340SAdrian Chadd 255e83ce340SAdrian Chadd /* Fetch the SPROM register window */ 256e83ce340SAdrian Chadd sprom_win = bhndb_pci_sprom_regwin(sc); 257e83ce340SAdrian Chadd KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+")); 258e83ce340SAdrian Chadd 259e83ce340SAdrian Chadd /* Fetch the associated resource */ 260e83ce340SAdrian Chadd r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win); 261e83ce340SAdrian Chadd KASSERT(r != NULL, ("missing resource for sprom window\n")); 262e83ce340SAdrian Chadd 263e83ce340SAdrian Chadd return (rman_get_start(r) + sprom_win->win_offset); 264e83ce340SAdrian Chadd } 265e83ce340SAdrian Chadd 266e83ce340SAdrian Chadd static bus_size_t 267e83ce340SAdrian Chadd bhndb_pci_sprom_size(struct bhndb_pci_softc *sc) 268e83ce340SAdrian Chadd { 269e83ce340SAdrian Chadd const struct bhndb_regwin *sprom_win; 270e83ce340SAdrian Chadd uint32_t sctl; 271e83ce340SAdrian Chadd bus_size_t sprom_sz; 272e83ce340SAdrian Chadd 273e83ce340SAdrian Chadd sprom_win = bhndb_pci_sprom_regwin(sc); 274e83ce340SAdrian Chadd 275e83ce340SAdrian Chadd /* PCI_V2 and later devices map SPROM/OTP via ChipCommon */ 276e83ce340SAdrian Chadd if (sprom_win == NULL) 277e83ce340SAdrian Chadd return (0); 278e83ce340SAdrian Chadd 279e83ce340SAdrian Chadd /* Determine SPROM size */ 280e83ce340SAdrian Chadd sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4); 281e83ce340SAdrian Chadd if (sctl & BHNDB_PCI_SPROM_BLANK) 282e83ce340SAdrian Chadd return (0); 283e83ce340SAdrian Chadd 284e83ce340SAdrian Chadd switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) { 285e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_1KB: 286e83ce340SAdrian Chadd sprom_sz = (1 * 1024); 287e83ce340SAdrian Chadd break; 288e83ce340SAdrian Chadd 289e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_4KB: 290e83ce340SAdrian Chadd sprom_sz = (4 * 1024); 291e83ce340SAdrian Chadd break; 292e83ce340SAdrian Chadd 293e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_16KB: 294e83ce340SAdrian Chadd sprom_sz = (16 * 1024); 295e83ce340SAdrian Chadd break; 296e83ce340SAdrian Chadd 297e83ce340SAdrian Chadd case BHNDB_PCI_SPROM_SZ_RESERVED: 298e83ce340SAdrian Chadd default: 299e83ce340SAdrian Chadd device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl); 300e83ce340SAdrian Chadd return (0); 301e83ce340SAdrian Chadd } 302e83ce340SAdrian Chadd 303e83ce340SAdrian Chadd if (sprom_sz > sprom_win->win_size) { 304e83ce340SAdrian Chadd device_printf(sc->dev, 305e83ce340SAdrian Chadd "PCI sprom size (0x%x) overruns defined register window\n", 306e83ce340SAdrian Chadd sctl); 307e83ce340SAdrian Chadd return (0); 308e83ce340SAdrian Chadd } 309e83ce340SAdrian Chadd 310e83ce340SAdrian Chadd return (sprom_sz); 311e83ce340SAdrian Chadd } 312e83ce340SAdrian Chadd 3134ad7e9b0SAdrian Chadd /* 3144ad7e9b0SAdrian Chadd * On devices without a SROM, the PCI(e) cores will be initialized with 315bb64eeccSAdrian Chadd * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows 316bb64eeccSAdrian Chadd * mapped to the wrong core. 3174ad7e9b0SAdrian Chadd * 318bb64eeccSAdrian Chadd * This function updates the SROM shadow to point the BAR0 windows at the 3194ad7e9b0SAdrian Chadd * current PCI core. 3204ad7e9b0SAdrian Chadd * 321bb64eeccSAdrian Chadd * Applies to all PCI/PCIe revisions. 3224ad7e9b0SAdrian Chadd */ 3234ad7e9b0SAdrian Chadd static void 3244ad7e9b0SAdrian Chadd bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) 3254ad7e9b0SAdrian Chadd { 326bb64eeccSAdrian Chadd struct bhndb_resources *bres; 327bb64eeccSAdrian Chadd const struct bhndb_hwcfg *cfg; 328bb64eeccSAdrian Chadd const struct bhndb_regwin *win; 329*111d7cb2SLandon J. Fuller struct bhnd_core_info hostb_core; 330bb64eeccSAdrian Chadd struct resource *core_regs; 331bb64eeccSAdrian Chadd bus_size_t srom_offset; 332bb64eeccSAdrian Chadd u_int pci_cidx, sprom_cidx; 3334ad7e9b0SAdrian Chadd uint16_t val; 334*111d7cb2SLandon J. Fuller int error; 3354ad7e9b0SAdrian Chadd 336bb64eeccSAdrian Chadd bres = sc->bhndb.bus_res; 337bb64eeccSAdrian Chadd cfg = bres->cfg; 338bb64eeccSAdrian Chadd 339*111d7cb2SLandon J. Fuller /* Find our hostb core */ 340*111d7cb2SLandon J. Fuller error = BHNDB_GET_HOSTB_CORE(sc->dev, sc->bhndb.bus_dev, &hostb_core); 341*111d7cb2SLandon J. Fuller if (error) { 342*111d7cb2SLandon J. Fuller device_printf(sc->dev, "no host bridge device found\n"); 343*111d7cb2SLandon J. Fuller return; 344*111d7cb2SLandon J. Fuller } 345*111d7cb2SLandon J. Fuller 346*111d7cb2SLandon J. Fuller if (hostb_core.vendor != BHND_MFGID_BCM) 347bb64eeccSAdrian Chadd return; 348bb64eeccSAdrian Chadd 349*111d7cb2SLandon J. Fuller switch (hostb_core.device) { 350bb64eeccSAdrian Chadd case BHND_COREID_PCI: 351bb64eeccSAdrian Chadd srom_offset = BHND_PCI_SRSH_PI_OFFSET; 352bb64eeccSAdrian Chadd break; 353bb64eeccSAdrian Chadd case BHND_COREID_PCIE: 354bb64eeccSAdrian Chadd srom_offset = BHND_PCIE_SRSH_PI_OFFSET; 355bb64eeccSAdrian Chadd break; 356bb64eeccSAdrian Chadd default: 357bb64eeccSAdrian Chadd device_printf(sc->dev, "unsupported PCI host bridge device\n"); 358bb64eeccSAdrian Chadd return; 359bb64eeccSAdrian Chadd } 360bb64eeccSAdrian Chadd 361bb64eeccSAdrian Chadd /* Locate the static register window mapping the PCI core */ 362bb64eeccSAdrian Chadd win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass, 363bb64eeccSAdrian Chadd 0, BHND_PORT_DEVICE, 0, 0); 364bb64eeccSAdrian Chadd if (win == NULL) { 365bb64eeccSAdrian Chadd device_printf(sc->dev, "missing PCI core register window\n"); 366bb64eeccSAdrian Chadd return; 367bb64eeccSAdrian Chadd } 368bb64eeccSAdrian Chadd 369bb64eeccSAdrian Chadd /* Fetch the resource containing the register window */ 370bb64eeccSAdrian Chadd core_regs = bhndb_find_regwin_resource(bres, win); 371bb64eeccSAdrian Chadd if (core_regs == NULL) { 372bb64eeccSAdrian Chadd device_printf(sc->dev, "missing PCI core register resource\n"); 373bb64eeccSAdrian Chadd return; 374bb64eeccSAdrian Chadd } 375bb64eeccSAdrian Chadd 3764ad7e9b0SAdrian Chadd /* Fetch the SPROM's configured core index */ 377bb64eeccSAdrian Chadd val = bus_read_2(core_regs, win->win_offset + srom_offset); 378bb64eeccSAdrian Chadd sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT; 3794ad7e9b0SAdrian Chadd 3804ad7e9b0SAdrian Chadd /* If it doesn't match host bridge's core index, update the index 3814ad7e9b0SAdrian Chadd * value */ 382*111d7cb2SLandon J. Fuller pci_cidx = hostb_core.core_idx; 383bb64eeccSAdrian Chadd if (sprom_cidx != pci_cidx) { 384bb64eeccSAdrian Chadd val &= ~BHND_PCI_SRSH_PI_MASK; 385bb64eeccSAdrian Chadd val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT); 386bb64eeccSAdrian Chadd bus_write_2(core_regs, 387bb64eeccSAdrian Chadd win->win_offset + srom_offset, val); 3884ad7e9b0SAdrian Chadd } 3894ad7e9b0SAdrian Chadd } 3904ad7e9b0SAdrian Chadd 3914ad7e9b0SAdrian Chadd static int 3924ad7e9b0SAdrian Chadd bhndb_pci_resume(device_t dev) 3934ad7e9b0SAdrian Chadd { 3944ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc; 3954ad7e9b0SAdrian Chadd int error; 3964ad7e9b0SAdrian Chadd 3974ad7e9b0SAdrian Chadd sc = device_get_softc(dev); 3984ad7e9b0SAdrian Chadd 399bb64eeccSAdrian Chadd /* Enable clocks (if supported by this hardware) */ 400bb64eeccSAdrian Chadd if ((error = bhndb_enable_pci_clocks(sc))) 4014ad7e9b0SAdrian Chadd return (error); 4024ad7e9b0SAdrian Chadd 403bb64eeccSAdrian Chadd /* Perform resume */ 404bb64eeccSAdrian Chadd return (bhndb_generic_resume(dev)); 405bb64eeccSAdrian Chadd } 406bb64eeccSAdrian Chadd 407bb64eeccSAdrian Chadd static int 408bb64eeccSAdrian Chadd bhndb_pci_suspend(device_t dev) 409bb64eeccSAdrian Chadd { 410bb64eeccSAdrian Chadd struct bhndb_pci_softc *sc; 411bb64eeccSAdrian Chadd int error; 412bb64eeccSAdrian Chadd 413bb64eeccSAdrian Chadd sc = device_get_softc(dev); 414bb64eeccSAdrian Chadd 415bb64eeccSAdrian Chadd /* Disable clocks (if supported by this hardware) */ 416bb64eeccSAdrian Chadd if ((error = bhndb_disable_pci_clocks(sc))) 4174ad7e9b0SAdrian Chadd return (error); 4184ad7e9b0SAdrian Chadd 419bb64eeccSAdrian Chadd /* Perform suspend */ 420bb64eeccSAdrian Chadd return (bhndb_generic_suspend(dev)); 421bb64eeccSAdrian Chadd } 422bb64eeccSAdrian Chadd 423bb64eeccSAdrian Chadd static int 4244ad7e9b0SAdrian Chadd bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw, 4254ad7e9b0SAdrian Chadd bhnd_addr_t addr) 4264ad7e9b0SAdrian Chadd { 4274ad7e9b0SAdrian Chadd struct bhndb_pci_softc *sc = device_get_softc(dev); 4284ad7e9b0SAdrian Chadd return (sc->set_regwin(sc, rw, addr)); 4294ad7e9b0SAdrian Chadd } 4304ad7e9b0SAdrian Chadd 4314ad7e9b0SAdrian Chadd /** 4324ad7e9b0SAdrian Chadd * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation. 4334ad7e9b0SAdrian Chadd * 4344ad7e9b0SAdrian Chadd * On siba(4) devices, it's possible that writing a PCI window register may 4354ad7e9b0SAdrian Chadd * not succeed; it's necessary to immediately read the configuration register 4364ad7e9b0SAdrian Chadd * and retry if not set to the desired value. 4374ad7e9b0SAdrian Chadd * 4384ad7e9b0SAdrian Chadd * This is not necessary on bcma(4) devices, but other than the overhead of 4394ad7e9b0SAdrian Chadd * validating the register, there's no harm in performing the verification. 4404ad7e9b0SAdrian Chadd */ 4414ad7e9b0SAdrian Chadd static int 4424ad7e9b0SAdrian Chadd bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc, 4434ad7e9b0SAdrian Chadd const struct bhndb_regwin *rw, bhnd_addr_t addr) 4444ad7e9b0SAdrian Chadd { 4454ad7e9b0SAdrian Chadd int error; 446e83ce340SAdrian Chadd int reg; 4474ad7e9b0SAdrian Chadd 4484ad7e9b0SAdrian Chadd if (rw->win_type != BHNDB_REGWIN_T_DYN) 4494ad7e9b0SAdrian Chadd return (ENODEV); 4504ad7e9b0SAdrian Chadd 451e83ce340SAdrian Chadd reg = rw->d.dyn.cfg_offset; 4524ad7e9b0SAdrian Chadd for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) { 4534ad7e9b0SAdrian Chadd if ((error = bhndb_pci_fast_setregwin(sc, rw, addr))) 4544ad7e9b0SAdrian Chadd return (error); 4554ad7e9b0SAdrian Chadd 456e83ce340SAdrian Chadd if (pci_read_config(sc->parent, reg, 4) == addr) 4574ad7e9b0SAdrian Chadd return (0); 4584ad7e9b0SAdrian Chadd 4594ad7e9b0SAdrian Chadd DELAY(10); 4604ad7e9b0SAdrian Chadd } 4614ad7e9b0SAdrian Chadd 4624ad7e9b0SAdrian Chadd /* Unable to set window */ 4634ad7e9b0SAdrian Chadd return (ENODEV); 4644ad7e9b0SAdrian Chadd } 4654ad7e9b0SAdrian Chadd 4664ad7e9b0SAdrian Chadd /** 4674ad7e9b0SAdrian Chadd * A bcma(4)-only bhndb_set_window_addr implementation. 4684ad7e9b0SAdrian Chadd */ 4694ad7e9b0SAdrian Chadd static int 4704ad7e9b0SAdrian Chadd bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc, 4714ad7e9b0SAdrian Chadd const struct bhndb_regwin *rw, bhnd_addr_t addr) 4724ad7e9b0SAdrian Chadd { 4734ad7e9b0SAdrian Chadd /* The PCI bridge core only supports 32-bit addressing, regardless 4744ad7e9b0SAdrian Chadd * of the bus' support for 64-bit addressing */ 4754ad7e9b0SAdrian Chadd if (addr > UINT32_MAX) 4764ad7e9b0SAdrian Chadd return (ERANGE); 4774ad7e9b0SAdrian Chadd 4784ad7e9b0SAdrian Chadd switch (rw->win_type) { 4794ad7e9b0SAdrian Chadd case BHNDB_REGWIN_T_DYN: 4804ad7e9b0SAdrian Chadd /* Addresses must be page aligned */ 4814ad7e9b0SAdrian Chadd if (addr % rw->win_size != 0) 4824ad7e9b0SAdrian Chadd return (EINVAL); 4834ad7e9b0SAdrian Chadd 484e83ce340SAdrian Chadd pci_write_config(sc->parent, rw->d.dyn.cfg_offset, addr, 4); 4854ad7e9b0SAdrian Chadd break; 4864ad7e9b0SAdrian Chadd default: 4874ad7e9b0SAdrian Chadd return (ENODEV); 4884ad7e9b0SAdrian Chadd } 4894ad7e9b0SAdrian Chadd 4904ad7e9b0SAdrian Chadd return (0); 4914ad7e9b0SAdrian Chadd } 4924ad7e9b0SAdrian Chadd 493d567592bSAdrian Chadd static int 494d567592bSAdrian Chadd bhndb_pci_populate_board_info(device_t dev, device_t child, 495d567592bSAdrian Chadd struct bhnd_board_info *info) 496d567592bSAdrian Chadd { 497d567592bSAdrian Chadd struct bhndb_pci_softc *sc; 498d567592bSAdrian Chadd 499d567592bSAdrian Chadd sc = device_get_softc(dev); 500d567592bSAdrian Chadd 5018ef24a0dSAdrian Chadd /* 5028ef24a0dSAdrian Chadd * On a subset of Apple BCM4360 modules, always prefer the 5038ef24a0dSAdrian Chadd * PCI subdevice to the SPROM-supplied boardtype. 5048ef24a0dSAdrian Chadd * 5058ef24a0dSAdrian Chadd * TODO: 5068ef24a0dSAdrian Chadd * 5078ef24a0dSAdrian Chadd * Broadcom's own drivers implement this override, and then later use 5088ef24a0dSAdrian Chadd * the remapped BCM4360 board type to determine the required 5098ef24a0dSAdrian Chadd * board-specific workarounds. 5108ef24a0dSAdrian Chadd * 5118ef24a0dSAdrian Chadd * Without access to this hardware, it's unclear why this mapping 5128ef24a0dSAdrian Chadd * is done, and we must do the same. If we can survey the hardware 5138ef24a0dSAdrian Chadd * in question, it may be possible to replace this behavior with 5148ef24a0dSAdrian Chadd * explicit references to the SPROM-supplied boardtype(s) in our 5158ef24a0dSAdrian Chadd * quirk definitions. 5168ef24a0dSAdrian Chadd */ 5178ef24a0dSAdrian Chadd if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) { 5188ef24a0dSAdrian Chadd switch (info->board_type) { 5198ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X29C: 5208ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X29CP2: 5218ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X51: 5228ef24a0dSAdrian Chadd case BHND_BOARD_BCM94360X51P2: 5238ef24a0dSAdrian Chadd info->board_type = 0; /* allow override below */ 5248ef24a0dSAdrian Chadd break; 5258ef24a0dSAdrian Chadd default: 5268ef24a0dSAdrian Chadd break; 5278ef24a0dSAdrian Chadd } 5288ef24a0dSAdrian Chadd } 5298ef24a0dSAdrian Chadd 530d567592bSAdrian Chadd /* If NVRAM did not supply vendor/type info, provide the PCI 531d567592bSAdrian Chadd * subvendor/subdevice values. */ 532d567592bSAdrian Chadd if (info->board_vendor == 0) 533d567592bSAdrian Chadd info->board_vendor = pci_get_subvendor(sc->parent); 534d567592bSAdrian Chadd 535d567592bSAdrian Chadd if (info->board_type == 0) 536d567592bSAdrian Chadd info->board_type = pci_get_subdevice(sc->parent); 537d567592bSAdrian Chadd 538d567592bSAdrian Chadd return (0); 539d567592bSAdrian Chadd } 540d567592bSAdrian Chadd 5414ad7e9b0SAdrian Chadd /** 542bb64eeccSAdrian Chadd * Enable externally managed clocks, if required. 5434ad7e9b0SAdrian Chadd * 544bb64eeccSAdrian Chadd * Some PCI chipsets (BCM4306, possibly others) chips do not support 545bb64eeccSAdrian Chadd * the idle low-power clock. Clocking must be bootstrapped at 546bb64eeccSAdrian Chadd * attach/resume by directly adjusting GPIO registers exposed in the 547bb64eeccSAdrian Chadd * PCI config space, and correspondingly, explicitly shutdown at 548bb64eeccSAdrian Chadd * detach/suspend. 5494ad7e9b0SAdrian Chadd * 5504ad7e9b0SAdrian Chadd * @param sc Bridge driver state. 5514ad7e9b0SAdrian Chadd */ 5524ad7e9b0SAdrian Chadd static int 5534ad7e9b0SAdrian Chadd bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) 5544ad7e9b0SAdrian Chadd { 5554ad7e9b0SAdrian Chadd uint32_t gpio_in, gpio_out, gpio_en; 5564ad7e9b0SAdrian Chadd uint32_t gpio_flags; 5574ad7e9b0SAdrian Chadd uint16_t pci_status; 5584ad7e9b0SAdrian Chadd 559bb64eeccSAdrian Chadd /* Only supported and required on PCI devices */ 560bb64eeccSAdrian Chadd if (sc->pci_devclass != BHND_DEVCLASS_PCI) 561bb64eeccSAdrian Chadd return (0); 5624ad7e9b0SAdrian Chadd 5634ad7e9b0SAdrian Chadd /* Read state of XTAL pin */ 564e83ce340SAdrian Chadd gpio_in = pci_read_config(sc->parent, BHNDB_PCI_GPIO_IN, 4); 5654ad7e9b0SAdrian Chadd if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON) 5664ad7e9b0SAdrian Chadd return (0); /* already enabled */ 5674ad7e9b0SAdrian Chadd 5684ad7e9b0SAdrian Chadd /* Fetch current config */ 569e83ce340SAdrian Chadd gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 570e83ce340SAdrian Chadd gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 5714ad7e9b0SAdrian Chadd 5724ad7e9b0SAdrian Chadd /* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */ 5734ad7e9b0SAdrian Chadd gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 5744ad7e9b0SAdrian Chadd gpio_out |= gpio_flags; 5754ad7e9b0SAdrian Chadd gpio_en |= gpio_flags; 5764ad7e9b0SAdrian Chadd 577e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 578e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 5794ad7e9b0SAdrian Chadd DELAY(1000); 5804ad7e9b0SAdrian Chadd 5814ad7e9b0SAdrian Chadd /* Reset PLL_OFF */ 5824ad7e9b0SAdrian Chadd gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; 583e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 5844ad7e9b0SAdrian Chadd DELAY(5000); 5854ad7e9b0SAdrian Chadd 5864ad7e9b0SAdrian Chadd /* Clear any PCI 'sent target-abort' flag. */ 587e83ce340SAdrian Chadd pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2); 5884ad7e9b0SAdrian Chadd pci_status &= ~PCIM_STATUS_STABORT; 589e83ce340SAdrian Chadd pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2); 5904ad7e9b0SAdrian Chadd 5914ad7e9b0SAdrian Chadd return (0); 5924ad7e9b0SAdrian Chadd } 5934ad7e9b0SAdrian Chadd 5944ad7e9b0SAdrian Chadd /** 595bb64eeccSAdrian Chadd * Disable externally managed clocks, if required. 5964ad7e9b0SAdrian Chadd * 5974ad7e9b0SAdrian Chadd * @param sc Bridge driver state. 5984ad7e9b0SAdrian Chadd */ 5994ad7e9b0SAdrian Chadd static int 6004ad7e9b0SAdrian Chadd bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) 6014ad7e9b0SAdrian Chadd { 6024ad7e9b0SAdrian Chadd uint32_t gpio_out, gpio_en; 6034ad7e9b0SAdrian Chadd 604bb64eeccSAdrian Chadd /* Only supported and required on PCI devices */ 605bb64eeccSAdrian Chadd if (sc->pci_devclass != BHND_DEVCLASS_PCI) 606bb64eeccSAdrian Chadd return (0); 6074ad7e9b0SAdrian Chadd 6084ad7e9b0SAdrian Chadd /* Fetch current config */ 609e83ce340SAdrian Chadd gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 610e83ce340SAdrian Chadd gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); 6114ad7e9b0SAdrian Chadd 6124ad7e9b0SAdrian Chadd /* Set PLL_OFF to HIGH, XTAL_ON to LOW. */ 6134ad7e9b0SAdrian Chadd gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON; 6144ad7e9b0SAdrian Chadd gpio_out |= BHNDB_PCI_GPIO_PLL_OFF; 615e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); 6164ad7e9b0SAdrian Chadd 6174ad7e9b0SAdrian Chadd /* Enable both output pins */ 6184ad7e9b0SAdrian Chadd gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); 619e83ce340SAdrian Chadd pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); 6204ad7e9b0SAdrian Chadd 6214ad7e9b0SAdrian Chadd return (0); 6224ad7e9b0SAdrian Chadd } 6234ad7e9b0SAdrian Chadd 624f90f4b65SLandon J. Fuller static bhnd_clksrc 625f90f4b65SLandon J. Fuller bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child, 626f90f4b65SLandon J. Fuller bhnd_clock clock) 627f90f4b65SLandon J. Fuller { 628f90f4b65SLandon J. Fuller struct bhndb_pci_softc *sc; 629f90f4b65SLandon J. Fuller uint32_t gpio_out; 630f90f4b65SLandon J. Fuller 631f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 632f90f4b65SLandon J. Fuller 633f90f4b65SLandon J. Fuller /* Only supported on PCI devices */ 634f90f4b65SLandon J. Fuller if (sc->pci_devclass != BHND_DEVCLASS_PCI) 635f90f4b65SLandon J. Fuller return (ENODEV); 636f90f4b65SLandon J. Fuller 637f90f4b65SLandon J. Fuller /* Only ILP is supported */ 638f90f4b65SLandon J. Fuller if (clock != BHND_CLOCK_ILP) 639f90f4b65SLandon J. Fuller return (ENXIO); 640f90f4b65SLandon J. Fuller 641f90f4b65SLandon J. Fuller gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); 642f90f4b65SLandon J. Fuller if (gpio_out & BHNDB_PCI_GPIO_SCS) 643f90f4b65SLandon J. Fuller return (BHND_CLKSRC_PCI); 644f90f4b65SLandon J. Fuller else 645f90f4b65SLandon J. Fuller return (BHND_CLKSRC_XTAL); 646f90f4b65SLandon J. Fuller } 647f90f4b65SLandon J. Fuller 648f90f4b65SLandon J. Fuller static int 649f90f4b65SLandon J. Fuller bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child, 650f90f4b65SLandon J. Fuller bhnd_clock clock) 651f90f4b65SLandon J. Fuller { 652f90f4b65SLandon J. Fuller struct bhndb_pci_softc *sc = device_get_softc(dev); 653f90f4b65SLandon J. Fuller 654f90f4b65SLandon J. Fuller /* Only supported on PCI devices */ 655f90f4b65SLandon J. Fuller if (sc->pci_devclass != BHND_DEVCLASS_PCI) 656f90f4b65SLandon J. Fuller return (ENODEV); 657f90f4b65SLandon J. Fuller 658f90f4b65SLandon J. Fuller /* Only HT is supported */ 659f90f4b65SLandon J. Fuller if (clock != BHND_CLOCK_HT) 660f90f4b65SLandon J. Fuller return (ENXIO); 661f90f4b65SLandon J. Fuller 662f90f4b65SLandon J. Fuller return (bhndb_disable_pci_clocks(sc)); 663f90f4b65SLandon J. Fuller } 664f90f4b65SLandon J. Fuller 665f90f4b65SLandon J. Fuller static int 666f90f4b65SLandon J. Fuller bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child, 667f90f4b65SLandon J. Fuller bhnd_clock clock) 668f90f4b65SLandon J. Fuller { 669f90f4b65SLandon J. Fuller struct bhndb_pci_softc *sc = device_get_softc(dev); 670f90f4b65SLandon J. Fuller 671f90f4b65SLandon J. Fuller /* Only supported on PCI devices */ 672f90f4b65SLandon J. Fuller if (sc->pci_devclass != BHND_DEVCLASS_PCI) 673f90f4b65SLandon J. Fuller return (ENODEV); 674f90f4b65SLandon J. Fuller 675f90f4b65SLandon J. Fuller /* Only HT is supported */ 676f90f4b65SLandon J. Fuller if (clock != BHND_CLOCK_HT) 677f90f4b65SLandon J. Fuller return (ENXIO); 678f90f4b65SLandon J. Fuller 679f90f4b65SLandon J. Fuller return (bhndb_enable_pci_clocks(sc)); 680f90f4b65SLandon J. Fuller } 681f90f4b65SLandon J. Fuller 6824ad7e9b0SAdrian Chadd static device_method_t bhndb_pci_methods[] = { 6834ad7e9b0SAdrian Chadd /* Device interface */ 6844ad7e9b0SAdrian Chadd DEVMETHOD(device_probe, bhndb_pci_probe), 6854ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bhndb_pci_attach), 6864ad7e9b0SAdrian Chadd DEVMETHOD(device_resume, bhndb_pci_resume), 687bb64eeccSAdrian Chadd DEVMETHOD(device_suspend, bhndb_pci_suspend), 688bb64eeccSAdrian Chadd DEVMETHOD(device_detach, bhndb_pci_detach), 6894ad7e9b0SAdrian Chadd 690f90f4b65SLandon J. Fuller /* BHND interface */ 691f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhndb_pci_pwrctl_get_clksrc), 692f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhndb_pci_pwrctl_gate_clock), 693f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock), 694f90f4b65SLandon J. Fuller 6954ad7e9b0SAdrian Chadd /* BHNDB interface */ 6964ad7e9b0SAdrian Chadd DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr), 697d567592bSAdrian Chadd DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info), 6984ad7e9b0SAdrian Chadd 6994ad7e9b0SAdrian Chadd DEVMETHOD_END 7004ad7e9b0SAdrian Chadd }; 7014ad7e9b0SAdrian Chadd 7024ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, 7034ad7e9b0SAdrian Chadd sizeof(struct bhndb_pci_softc), bhndb_driver); 7044ad7e9b0SAdrian Chadd 7054ad7e9b0SAdrian Chadd MODULE_VERSION(bhndb_pci, 1); 706148ed571SAdrian Chadd MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1); 7074ad7e9b0SAdrian Chadd MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); 7084ad7e9b0SAdrian Chadd MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1); 709148ed571SAdrian Chadd MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1); 710