1*4ad7e9b0SAdrian Chadd /*- 2*4ad7e9b0SAdrian Chadd * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 3*4ad7e9b0SAdrian Chadd * All rights reserved. 4*4ad7e9b0SAdrian Chadd * 5*4ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without 6*4ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions 7*4ad7e9b0SAdrian Chadd * are met: 8*4ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 9*4ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer, 10*4ad7e9b0SAdrian Chadd * without modification. 11*4ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12*4ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13*4ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially 14*4ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 15*4ad7e9b0SAdrian Chadd * 16*4ad7e9b0SAdrian Chadd * NO WARRANTY 17*4ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*4ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*4ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20*4ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21*4ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22*4ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*4ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*4ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25*4ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*4ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27*4ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 28*4ad7e9b0SAdrian Chadd */ 29*4ad7e9b0SAdrian Chadd 30*4ad7e9b0SAdrian Chadd #include <sys/cdefs.h> 31*4ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$"); 32*4ad7e9b0SAdrian Chadd 33*4ad7e9b0SAdrian Chadd #include <sys/param.h> 34*4ad7e9b0SAdrian Chadd #include <sys/kernel.h> 35*4ad7e9b0SAdrian Chadd #include <sys/bus.h> 36*4ad7e9b0SAdrian Chadd #include <sys/module.h> 37*4ad7e9b0SAdrian Chadd 38*4ad7e9b0SAdrian Chadd #include <dev/bhnd/bhnd_ids.h> 39*4ad7e9b0SAdrian Chadd #include <dev/bhnd/bhndb/bhndbvar.h> 40*4ad7e9b0SAdrian Chadd #include <dev/bhnd/bhndb/bhndb_hwdata.h> 41*4ad7e9b0SAdrian Chadd 42*4ad7e9b0SAdrian Chadd #include "bcmavar.h" 43*4ad7e9b0SAdrian Chadd 44*4ad7e9b0SAdrian Chadd #include "bcma_eromreg.h" 45*4ad7e9b0SAdrian Chadd #include "bcma_eromvar.h" 46*4ad7e9b0SAdrian Chadd 47*4ad7e9b0SAdrian Chadd /* 48*4ad7e9b0SAdrian Chadd * Supports attachment of bcma(4) bus devices via a bhndb bridge. 49*4ad7e9b0SAdrian Chadd */ 50*4ad7e9b0SAdrian Chadd 51*4ad7e9b0SAdrian Chadd static int 52*4ad7e9b0SAdrian Chadd bcma_bhndb_probe(device_t dev) 53*4ad7e9b0SAdrian Chadd { 54*4ad7e9b0SAdrian Chadd const struct bhnd_chipid *cid; 55*4ad7e9b0SAdrian Chadd 56*4ad7e9b0SAdrian Chadd /* Check bus type */ 57*4ad7e9b0SAdrian Chadd cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); 58*4ad7e9b0SAdrian Chadd if (cid->chip_type != BHND_CHIPTYPE_BCMA) 59*4ad7e9b0SAdrian Chadd return (ENXIO); 60*4ad7e9b0SAdrian Chadd 61*4ad7e9b0SAdrian Chadd /* Delegate to default probe implementation */ 62*4ad7e9b0SAdrian Chadd return (bcma_probe(dev)); 63*4ad7e9b0SAdrian Chadd } 64*4ad7e9b0SAdrian Chadd 65*4ad7e9b0SAdrian Chadd static int 66*4ad7e9b0SAdrian Chadd bcma_bhndb_attach(device_t dev) 67*4ad7e9b0SAdrian Chadd { 68*4ad7e9b0SAdrian Chadd const struct bhnd_chipid *cid; 69*4ad7e9b0SAdrian Chadd struct resource *erom_res; 70*4ad7e9b0SAdrian Chadd int error; 71*4ad7e9b0SAdrian Chadd int rid; 72*4ad7e9b0SAdrian Chadd 73*4ad7e9b0SAdrian Chadd cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); 74*4ad7e9b0SAdrian Chadd 75*4ad7e9b0SAdrian Chadd /* Map the EROM resource and enumerate our children. */ 76*4ad7e9b0SAdrian Chadd rid = 0; 77*4ad7e9b0SAdrian Chadd erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr, 78*4ad7e9b0SAdrian Chadd cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE, 79*4ad7e9b0SAdrian Chadd RF_ACTIVE); 80*4ad7e9b0SAdrian Chadd if (erom_res == NULL) { 81*4ad7e9b0SAdrian Chadd device_printf(dev, "failed to allocate EROM resource\n"); 82*4ad7e9b0SAdrian Chadd return (ENXIO); 83*4ad7e9b0SAdrian Chadd } 84*4ad7e9b0SAdrian Chadd 85*4ad7e9b0SAdrian Chadd error = bcma_add_children(dev, erom_res, BCMA_EROM_TABLE_START); 86*4ad7e9b0SAdrian Chadd 87*4ad7e9b0SAdrian Chadd /* Clean up */ 88*4ad7e9b0SAdrian Chadd bus_release_resource(dev, SYS_RES_MEMORY, rid, erom_res); 89*4ad7e9b0SAdrian Chadd if (error) 90*4ad7e9b0SAdrian Chadd return (error); 91*4ad7e9b0SAdrian Chadd 92*4ad7e9b0SAdrian Chadd /* Initialize full bridge configuration */ 93*4ad7e9b0SAdrian Chadd error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev, 94*4ad7e9b0SAdrian Chadd bhndb_bcma_priority_table); 95*4ad7e9b0SAdrian Chadd if (error) 96*4ad7e9b0SAdrian Chadd return (error); 97*4ad7e9b0SAdrian Chadd 98*4ad7e9b0SAdrian Chadd /* Call our superclass' implementation */ 99*4ad7e9b0SAdrian Chadd return (bcma_attach(dev)); 100*4ad7e9b0SAdrian Chadd } 101*4ad7e9b0SAdrian Chadd 102*4ad7e9b0SAdrian Chadd static int 103*4ad7e9b0SAdrian Chadd bcma_bhndb_suspend_child(device_t dev, device_t child) 104*4ad7e9b0SAdrian Chadd { 105*4ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 106*4ad7e9b0SAdrian Chadd int error; 107*4ad7e9b0SAdrian Chadd 108*4ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 109*4ad7e9b0SAdrian Chadd BUS_SUSPEND_CHILD(device_get_parent(dev), child); 110*4ad7e9b0SAdrian Chadd 111*4ad7e9b0SAdrian Chadd if (device_is_suspended(child)) 112*4ad7e9b0SAdrian Chadd return (EBUSY); 113*4ad7e9b0SAdrian Chadd 114*4ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 115*4ad7e9b0SAdrian Chadd 116*4ad7e9b0SAdrian Chadd /* Suspend the child */ 117*4ad7e9b0SAdrian Chadd if ((error = bhnd_generic_br_suspend_child(dev, child))) 118*4ad7e9b0SAdrian Chadd return (error); 119*4ad7e9b0SAdrian Chadd 120*4ad7e9b0SAdrian Chadd /* Suspend child's agent resource */ 121*4ad7e9b0SAdrian Chadd if (dinfo->res_agent != NULL) 122*4ad7e9b0SAdrian Chadd BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, 123*4ad7e9b0SAdrian Chadd SYS_RES_MEMORY, dinfo->res_agent->res); 124*4ad7e9b0SAdrian Chadd 125*4ad7e9b0SAdrian Chadd return (0); 126*4ad7e9b0SAdrian Chadd } 127*4ad7e9b0SAdrian Chadd 128*4ad7e9b0SAdrian Chadd static int 129*4ad7e9b0SAdrian Chadd bcma_bhndb_resume_child(device_t dev, device_t child) 130*4ad7e9b0SAdrian Chadd { 131*4ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 132*4ad7e9b0SAdrian Chadd int error; 133*4ad7e9b0SAdrian Chadd 134*4ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 135*4ad7e9b0SAdrian Chadd BUS_SUSPEND_CHILD(device_get_parent(dev), child); 136*4ad7e9b0SAdrian Chadd 137*4ad7e9b0SAdrian Chadd if (!device_is_suspended(child)) 138*4ad7e9b0SAdrian Chadd return (EBUSY); 139*4ad7e9b0SAdrian Chadd 140*4ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 141*4ad7e9b0SAdrian Chadd 142*4ad7e9b0SAdrian Chadd /* Resume child's agent resource */ 143*4ad7e9b0SAdrian Chadd if (dinfo->res_agent != NULL) { 144*4ad7e9b0SAdrian Chadd error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev, 145*4ad7e9b0SAdrian Chadd SYS_RES_MEMORY, dinfo->res_agent->res); 146*4ad7e9b0SAdrian Chadd if (error) 147*4ad7e9b0SAdrian Chadd return (error); 148*4ad7e9b0SAdrian Chadd } 149*4ad7e9b0SAdrian Chadd 150*4ad7e9b0SAdrian Chadd /* Resume the child */ 151*4ad7e9b0SAdrian Chadd if ((error = bhnd_generic_br_resume_child(dev, child))) { 152*4ad7e9b0SAdrian Chadd /* On failure, re-suspend the agent resource */ 153*4ad7e9b0SAdrian Chadd if (dinfo->res_agent != NULL) { 154*4ad7e9b0SAdrian Chadd BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, 155*4ad7e9b0SAdrian Chadd SYS_RES_MEMORY, dinfo->res_agent->res); 156*4ad7e9b0SAdrian Chadd } 157*4ad7e9b0SAdrian Chadd 158*4ad7e9b0SAdrian Chadd return (error); 159*4ad7e9b0SAdrian Chadd } 160*4ad7e9b0SAdrian Chadd 161*4ad7e9b0SAdrian Chadd return (0); 162*4ad7e9b0SAdrian Chadd } 163*4ad7e9b0SAdrian Chadd 164*4ad7e9b0SAdrian Chadd static device_method_t bcma_bhndb_methods[] = { 165*4ad7e9b0SAdrian Chadd /* Device interface */ 166*4ad7e9b0SAdrian Chadd DEVMETHOD(device_probe, bcma_bhndb_probe), 167*4ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bcma_bhndb_attach), 168*4ad7e9b0SAdrian Chadd 169*4ad7e9b0SAdrian Chadd /* Bus interface */ 170*4ad7e9b0SAdrian Chadd DEVMETHOD(bus_suspend_child, bcma_bhndb_suspend_child), 171*4ad7e9b0SAdrian Chadd DEVMETHOD(bus_resume_child, bcma_bhndb_resume_child), 172*4ad7e9b0SAdrian Chadd 173*4ad7e9b0SAdrian Chadd DEVMETHOD_END 174*4ad7e9b0SAdrian Chadd }; 175*4ad7e9b0SAdrian Chadd 176*4ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhnd, bcma_bhndb_driver, bcma_bhndb_methods, 177*4ad7e9b0SAdrian Chadd sizeof(struct bcma_softc), bcma_driver); 178*4ad7e9b0SAdrian Chadd 179*4ad7e9b0SAdrian Chadd DRIVER_MODULE(bcma_bhndb, bhndb, bcma_bhndb_driver, bhnd_devclass, NULL, NULL); 180*4ad7e9b0SAdrian Chadd 181*4ad7e9b0SAdrian Chadd MODULE_VERSION(bcma_bhndb, 1); 182*4ad7e9b0SAdrian Chadd MODULE_DEPEND(bcma_bhndb, bcma, 1, 1, 1); 183*4ad7e9b0SAdrian Chadd MODULE_DEPEND(bcma_bhndb, bhndb, 1, 1, 1); 184