14ad7e9b0SAdrian Chadd /*- 24ad7e9b0SAdrian Chadd * Copyright (c) 2015 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 #include <sys/param.h> 344ad7e9b0SAdrian Chadd #include <sys/bus.h> 354ad7e9b0SAdrian Chadd #include <sys/kernel.h> 364ad7e9b0SAdrian Chadd #include <sys/malloc.h> 374ad7e9b0SAdrian Chadd #include <sys/module.h> 384ad7e9b0SAdrian Chadd #include <sys/systm.h> 394ad7e9b0SAdrian Chadd 404ad7e9b0SAdrian Chadd #include <machine/bus.h> 414ad7e9b0SAdrian Chadd 424ad7e9b0SAdrian Chadd #include "bcmavar.h" 434ad7e9b0SAdrian Chadd 444ad7e9b0SAdrian Chadd #include "bcma_eromreg.h" 454ad7e9b0SAdrian Chadd #include "bcma_eromvar.h" 464ad7e9b0SAdrian Chadd 474ad7e9b0SAdrian Chadd int 484ad7e9b0SAdrian Chadd bcma_probe(device_t dev) 494ad7e9b0SAdrian Chadd { 504ad7e9b0SAdrian Chadd device_set_desc(dev, "BCMA BHND bus"); 514ad7e9b0SAdrian Chadd return (BUS_PROBE_DEFAULT); 524ad7e9b0SAdrian Chadd } 534ad7e9b0SAdrian Chadd 544ad7e9b0SAdrian Chadd int 554ad7e9b0SAdrian Chadd bcma_attach(device_t dev) 564ad7e9b0SAdrian Chadd { 574ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 584ad7e9b0SAdrian Chadd device_t *devs, child; 594ad7e9b0SAdrian Chadd int ndevs; 604ad7e9b0SAdrian Chadd int error; 614ad7e9b0SAdrian Chadd 624ad7e9b0SAdrian Chadd 634ad7e9b0SAdrian Chadd if ((error = device_get_children(dev, &devs, &ndevs))) 644ad7e9b0SAdrian Chadd return (error); 654ad7e9b0SAdrian Chadd 664ad7e9b0SAdrian Chadd /* 674ad7e9b0SAdrian Chadd * Map our children's agent register block. 684ad7e9b0SAdrian Chadd */ 694ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 704ad7e9b0SAdrian Chadd bhnd_addr_t addr; 714ad7e9b0SAdrian Chadd bhnd_size_t size; 724ad7e9b0SAdrian Chadd rman_res_t r_start, r_count, r_end; 734ad7e9b0SAdrian Chadd 744ad7e9b0SAdrian Chadd child = devs[i]; 754ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 764ad7e9b0SAdrian Chadd 774ad7e9b0SAdrian Chadd KASSERT(!device_is_suspended(child), 784ad7e9b0SAdrian Chadd ("bcma(4) stateful suspend handling requires that devices " 794ad7e9b0SAdrian Chadd "not be suspended before bcma_attach()")); 804ad7e9b0SAdrian Chadd 814ad7e9b0SAdrian Chadd /* Verify that the agent register block exists and is 824ad7e9b0SAdrian Chadd * mappable */ 834ad7e9b0SAdrian Chadd if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1) 844ad7e9b0SAdrian Chadd continue; 854ad7e9b0SAdrian Chadd 864ad7e9b0SAdrian Chadd /* Fetch the address of the agent register block */ 874ad7e9b0SAdrian Chadd error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0, 884ad7e9b0SAdrian Chadd &addr, &size); 894ad7e9b0SAdrian Chadd if (error) { 904ad7e9b0SAdrian Chadd device_printf(dev, "failed fetching agent register " 914ad7e9b0SAdrian Chadd "block address for core %d\n", i); 924ad7e9b0SAdrian Chadd goto cleanup; 934ad7e9b0SAdrian Chadd } 944ad7e9b0SAdrian Chadd 954ad7e9b0SAdrian Chadd /* Allocate the resource */ 964ad7e9b0SAdrian Chadd r_start = addr; 974ad7e9b0SAdrian Chadd r_count = size; 984ad7e9b0SAdrian Chadd r_end = r_start + r_count - 1; 994ad7e9b0SAdrian Chadd 1004ad7e9b0SAdrian Chadd dinfo->rid_agent = 0; 1014ad7e9b0SAdrian Chadd dinfo->res_agent = bhnd_alloc_resource(dev, SYS_RES_MEMORY, 1024ad7e9b0SAdrian Chadd &dinfo->rid_agent, r_start, r_end, r_count, RF_ACTIVE); 1034ad7e9b0SAdrian Chadd if (dinfo->res_agent == NULL) { 1044ad7e9b0SAdrian Chadd device_printf(dev, "failed allocating agent register " 1054ad7e9b0SAdrian Chadd "block for core %d\n", i); 1064ad7e9b0SAdrian Chadd error = ENXIO; 1074ad7e9b0SAdrian Chadd goto cleanup; 1084ad7e9b0SAdrian Chadd } 1094ad7e9b0SAdrian Chadd } 1104ad7e9b0SAdrian Chadd 1114ad7e9b0SAdrian Chadd cleanup: 1124ad7e9b0SAdrian Chadd free(devs, M_BHND); 1134ad7e9b0SAdrian Chadd if (error) 1144ad7e9b0SAdrian Chadd return (error); 1154ad7e9b0SAdrian Chadd 1164ad7e9b0SAdrian Chadd return (bhnd_generic_attach(dev)); 1174ad7e9b0SAdrian Chadd } 1184ad7e9b0SAdrian Chadd 1194ad7e9b0SAdrian Chadd int 1204ad7e9b0SAdrian Chadd bcma_detach(device_t dev) 1214ad7e9b0SAdrian Chadd { 1224ad7e9b0SAdrian Chadd return (bhnd_generic_detach(dev)); 1234ad7e9b0SAdrian Chadd } 1244ad7e9b0SAdrian Chadd 1254ad7e9b0SAdrian Chadd static int 1264ad7e9b0SAdrian Chadd bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 1274ad7e9b0SAdrian Chadd { 1284ad7e9b0SAdrian Chadd const struct bcma_devinfo *dinfo; 1294ad7e9b0SAdrian Chadd const struct bhnd_core_info *ci; 1304ad7e9b0SAdrian Chadd 1314ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 1324ad7e9b0SAdrian Chadd ci = &dinfo->corecfg->core_info; 1334ad7e9b0SAdrian Chadd 1344ad7e9b0SAdrian Chadd switch (index) { 1354ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR: 1364ad7e9b0SAdrian Chadd *result = ci->vendor; 1374ad7e9b0SAdrian Chadd return (0); 1384ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE: 1394ad7e9b0SAdrian Chadd *result = ci->device; 1404ad7e9b0SAdrian Chadd return (0); 1414ad7e9b0SAdrian Chadd case BHND_IVAR_HWREV: 1424ad7e9b0SAdrian Chadd *result = ci->hwrev; 1434ad7e9b0SAdrian Chadd return (0); 1444ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_CLASS: 1454ad7e9b0SAdrian Chadd *result = bhnd_core_class(ci); 1464ad7e9b0SAdrian Chadd return (0); 1474ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR_NAME: 1484ad7e9b0SAdrian Chadd *result = (uintptr_t) bhnd_vendor_name(ci->vendor); 1494ad7e9b0SAdrian Chadd return (0); 1504ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_NAME: 1514ad7e9b0SAdrian Chadd *result = (uintptr_t) bhnd_core_name(ci); 1524ad7e9b0SAdrian Chadd return (0); 1534ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_INDEX: 1544ad7e9b0SAdrian Chadd *result = ci->core_idx; 1554ad7e9b0SAdrian Chadd return (0); 1564ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_UNIT: 1574ad7e9b0SAdrian Chadd *result = ci->unit; 1584ad7e9b0SAdrian Chadd return (0); 1594ad7e9b0SAdrian Chadd default: 1604ad7e9b0SAdrian Chadd return (ENOENT); 1614ad7e9b0SAdrian Chadd } 1624ad7e9b0SAdrian Chadd } 1634ad7e9b0SAdrian Chadd 1644ad7e9b0SAdrian Chadd static int 1654ad7e9b0SAdrian Chadd bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 1664ad7e9b0SAdrian Chadd { 1674ad7e9b0SAdrian Chadd switch (index) { 1684ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR: 1694ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE: 1704ad7e9b0SAdrian Chadd case BHND_IVAR_HWREV: 1714ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_CLASS: 1724ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR_NAME: 1734ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_NAME: 1744ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_INDEX: 1754ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_UNIT: 1764ad7e9b0SAdrian Chadd return (EINVAL); 1774ad7e9b0SAdrian Chadd default: 1784ad7e9b0SAdrian Chadd return (ENOENT); 1794ad7e9b0SAdrian Chadd } 1804ad7e9b0SAdrian Chadd } 1814ad7e9b0SAdrian Chadd 1824ad7e9b0SAdrian Chadd static void 1834ad7e9b0SAdrian Chadd bcma_child_deleted(device_t dev, device_t child) 1844ad7e9b0SAdrian Chadd { 1854ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo = device_get_ivars(child); 1864ad7e9b0SAdrian Chadd if (dinfo != NULL) 1874ad7e9b0SAdrian Chadd bcma_free_dinfo(dev, dinfo); 1884ad7e9b0SAdrian Chadd } 1894ad7e9b0SAdrian Chadd 1904ad7e9b0SAdrian Chadd static struct resource_list * 1914ad7e9b0SAdrian Chadd bcma_get_resource_list(device_t dev, device_t child) 1924ad7e9b0SAdrian Chadd { 1934ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo = device_get_ivars(child); 1944ad7e9b0SAdrian Chadd return (&dinfo->resources); 1954ad7e9b0SAdrian Chadd } 1964ad7e9b0SAdrian Chadd 1974ad7e9b0SAdrian Chadd 1984ad7e9b0SAdrian Chadd static int 1994ad7e9b0SAdrian Chadd bcma_reset_core(device_t dev, device_t child, uint16_t flags) 2004ad7e9b0SAdrian Chadd { 2014ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2024ad7e9b0SAdrian Chadd 2034ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 2044ad7e9b0SAdrian Chadd BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags); 2054ad7e9b0SAdrian Chadd 2064ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 2074ad7e9b0SAdrian Chadd 2084ad7e9b0SAdrian Chadd /* Can't reset the core without access to the agent registers */ 2094ad7e9b0SAdrian Chadd if (dinfo->res_agent == NULL) 2104ad7e9b0SAdrian Chadd return (ENODEV); 2114ad7e9b0SAdrian Chadd 2124ad7e9b0SAdrian Chadd // TODO - perform reset 2134ad7e9b0SAdrian Chadd 2144ad7e9b0SAdrian Chadd return (ENXIO); 2154ad7e9b0SAdrian Chadd } 2164ad7e9b0SAdrian Chadd 2174ad7e9b0SAdrian Chadd static int 2184ad7e9b0SAdrian Chadd bcma_suspend_core(device_t dev, device_t child) 2194ad7e9b0SAdrian Chadd { 2204ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2214ad7e9b0SAdrian Chadd 2224ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 2234ad7e9b0SAdrian Chadd BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child); 2244ad7e9b0SAdrian Chadd 2254ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 2264ad7e9b0SAdrian Chadd 2274ad7e9b0SAdrian Chadd /* Can't suspend the core without access to the agent registers */ 2284ad7e9b0SAdrian Chadd if (dinfo->res_agent == NULL) 2294ad7e9b0SAdrian Chadd return (ENODEV); 2304ad7e9b0SAdrian Chadd 2314ad7e9b0SAdrian Chadd // TODO - perform suspend 2324ad7e9b0SAdrian Chadd 2334ad7e9b0SAdrian Chadd return (ENXIO); 2344ad7e9b0SAdrian Chadd } 2354ad7e9b0SAdrian Chadd 2364ad7e9b0SAdrian Chadd static u_int 2374ad7e9b0SAdrian Chadd bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type) 2384ad7e9b0SAdrian Chadd { 2394ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2404ad7e9b0SAdrian Chadd 2414ad7e9b0SAdrian Chadd /* delegate non-bus-attached devices to our parent */ 2424ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 2434ad7e9b0SAdrian Chadd return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, 2444ad7e9b0SAdrian Chadd type)); 2454ad7e9b0SAdrian Chadd 2464ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 2474ad7e9b0SAdrian Chadd switch (type) { 2484ad7e9b0SAdrian Chadd case BHND_PORT_DEVICE: 2494ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_dev_ports); 2504ad7e9b0SAdrian Chadd case BHND_PORT_BRIDGE: 2514ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_bridge_ports); 2524ad7e9b0SAdrian Chadd case BHND_PORT_AGENT: 2534ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_wrapper_ports); 2544ad7e9b0SAdrian Chadd } 2554ad7e9b0SAdrian Chadd } 2564ad7e9b0SAdrian Chadd 2574ad7e9b0SAdrian Chadd static u_int 2584ad7e9b0SAdrian Chadd bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type, 2594ad7e9b0SAdrian Chadd u_int port_num) 2604ad7e9b0SAdrian Chadd { 2614ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2624ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 2634ad7e9b0SAdrian Chadd struct bcma_sport *port; 2644ad7e9b0SAdrian Chadd 2654ad7e9b0SAdrian Chadd /* delegate non-bus-attached devices to our parent */ 2664ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 2674ad7e9b0SAdrian Chadd return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, 2684ad7e9b0SAdrian Chadd type, port_num)); 2694ad7e9b0SAdrian Chadd 2704ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 2714ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, type); 2724ad7e9b0SAdrian Chadd 2734ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 2744ad7e9b0SAdrian Chadd if (port->sp_num == port_num) 2754ad7e9b0SAdrian Chadd return (port->sp_num_maps); 2764ad7e9b0SAdrian Chadd } 2774ad7e9b0SAdrian Chadd 2784ad7e9b0SAdrian Chadd /* not found */ 2794ad7e9b0SAdrian Chadd return (0); 2804ad7e9b0SAdrian Chadd } 2814ad7e9b0SAdrian Chadd 2824ad7e9b0SAdrian Chadd static int 2834ad7e9b0SAdrian Chadd bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, 2844ad7e9b0SAdrian Chadd u_int port_num, u_int region_num) 2854ad7e9b0SAdrian Chadd { 2864ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 2874ad7e9b0SAdrian Chadd struct bcma_map *map; 2884ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 2894ad7e9b0SAdrian Chadd struct bcma_sport *port; 2904ad7e9b0SAdrian Chadd 2914ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 2924ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 2934ad7e9b0SAdrian Chadd 2944ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 2954ad7e9b0SAdrian Chadd if (port->sp_num != port_num) 2964ad7e9b0SAdrian Chadd continue; 2974ad7e9b0SAdrian Chadd 2984ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) 2994ad7e9b0SAdrian Chadd if (map->m_region_num == region_num) 3004ad7e9b0SAdrian Chadd return map->m_rid; 3014ad7e9b0SAdrian Chadd } 3024ad7e9b0SAdrian Chadd 3034ad7e9b0SAdrian Chadd return -1; 3044ad7e9b0SAdrian Chadd } 3054ad7e9b0SAdrian Chadd 3064ad7e9b0SAdrian Chadd static int 3074ad7e9b0SAdrian Chadd bcma_decode_port_rid(device_t dev, device_t child, int type, int rid, 3084ad7e9b0SAdrian Chadd bhnd_port_type *port_type, u_int *port_num, u_int *region_num) 3094ad7e9b0SAdrian Chadd { 3104ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 3114ad7e9b0SAdrian Chadd struct bcma_map *map; 3124ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 3134ad7e9b0SAdrian Chadd struct bcma_sport *port; 3144ad7e9b0SAdrian Chadd 3154ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 3164ad7e9b0SAdrian Chadd 3174ad7e9b0SAdrian Chadd /* Ports are always memory mapped */ 3184ad7e9b0SAdrian Chadd if (type != SYS_RES_MEMORY) 3194ad7e9b0SAdrian Chadd return (EINVAL); 3204ad7e9b0SAdrian Chadd 3214ad7e9b0SAdrian Chadd /* Starting with the most likely device list, search all three port 3224ad7e9b0SAdrian Chadd * lists */ 3234ad7e9b0SAdrian Chadd bhnd_port_type types[] = { 3244ad7e9b0SAdrian Chadd BHND_PORT_DEVICE, 3254ad7e9b0SAdrian Chadd BHND_PORT_AGENT, 3264ad7e9b0SAdrian Chadd BHND_PORT_BRIDGE 3274ad7e9b0SAdrian Chadd }; 3284ad7e9b0SAdrian Chadd 3294ad7e9b0SAdrian Chadd for (int i = 0; i < nitems(types); i++) { 3304ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]); 3314ad7e9b0SAdrian Chadd 3324ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 3334ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) { 3344ad7e9b0SAdrian Chadd if (map->m_rid != rid) 3354ad7e9b0SAdrian Chadd continue; 3364ad7e9b0SAdrian Chadd 3374ad7e9b0SAdrian Chadd *port_type = port->sp_type; 3384ad7e9b0SAdrian Chadd *port_num = port->sp_num; 3394ad7e9b0SAdrian Chadd *region_num = map->m_region_num; 3404ad7e9b0SAdrian Chadd return (0); 3414ad7e9b0SAdrian Chadd } 3424ad7e9b0SAdrian Chadd } 3434ad7e9b0SAdrian Chadd } 3444ad7e9b0SAdrian Chadd 3454ad7e9b0SAdrian Chadd return (ENOENT); 3464ad7e9b0SAdrian Chadd } 3474ad7e9b0SAdrian Chadd 3484ad7e9b0SAdrian Chadd static int 3494ad7e9b0SAdrian Chadd bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, 3504ad7e9b0SAdrian Chadd u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) 3514ad7e9b0SAdrian Chadd { 3524ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 3534ad7e9b0SAdrian Chadd struct bcma_map *map; 3544ad7e9b0SAdrian Chadd struct bcma_sport_list *ports; 3554ad7e9b0SAdrian Chadd struct bcma_sport *port; 3564ad7e9b0SAdrian Chadd 3574ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child); 3584ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 3594ad7e9b0SAdrian Chadd 3604ad7e9b0SAdrian Chadd /* Search the port list */ 3614ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) { 3624ad7e9b0SAdrian Chadd if (port->sp_num != port_num) 3634ad7e9b0SAdrian Chadd continue; 3644ad7e9b0SAdrian Chadd 3654ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) { 3664ad7e9b0SAdrian Chadd if (map->m_region_num != region_num) 3674ad7e9b0SAdrian Chadd continue; 3684ad7e9b0SAdrian Chadd 3694ad7e9b0SAdrian Chadd /* Found! */ 3704ad7e9b0SAdrian Chadd *addr = map->m_base; 3714ad7e9b0SAdrian Chadd *size = map->m_size; 3724ad7e9b0SAdrian Chadd return (0); 3734ad7e9b0SAdrian Chadd } 3744ad7e9b0SAdrian Chadd } 3754ad7e9b0SAdrian Chadd 3764ad7e9b0SAdrian Chadd return (ENOENT); 3774ad7e9b0SAdrian Chadd } 3784ad7e9b0SAdrian Chadd 3794ad7e9b0SAdrian Chadd /** 3804ad7e9b0SAdrian Chadd * Scan a device enumeration ROM table, adding all valid discovered cores to 3814ad7e9b0SAdrian Chadd * the bus. 3824ad7e9b0SAdrian Chadd * 3834ad7e9b0SAdrian Chadd * @param bus The bcma bus. 3844ad7e9b0SAdrian Chadd * @param erom_res An active resource mapping the EROM core. 3854ad7e9b0SAdrian Chadd * @param erom_offset Base offset of the EROM core's register mapping. 3864ad7e9b0SAdrian Chadd */ 3874ad7e9b0SAdrian Chadd int 3884ad7e9b0SAdrian Chadd bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offset) 3894ad7e9b0SAdrian Chadd { 3904ad7e9b0SAdrian Chadd struct bcma_erom erom; 3914ad7e9b0SAdrian Chadd struct bcma_corecfg *corecfg; 3924ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo; 3934ad7e9b0SAdrian Chadd device_t child; 3944ad7e9b0SAdrian Chadd int error; 3954ad7e9b0SAdrian Chadd 3964ad7e9b0SAdrian Chadd dinfo = NULL; 3974ad7e9b0SAdrian Chadd corecfg = NULL; 3984ad7e9b0SAdrian Chadd 3994ad7e9b0SAdrian Chadd /* Initialize our reader */ 4004ad7e9b0SAdrian Chadd error = bcma_erom_open(&erom, erom_res, erom_offset); 4014ad7e9b0SAdrian Chadd if (error) 4024ad7e9b0SAdrian Chadd return (error); 4034ad7e9b0SAdrian Chadd 4044ad7e9b0SAdrian Chadd /* Add all cores. */ 4054ad7e9b0SAdrian Chadd while (!error) { 4064ad7e9b0SAdrian Chadd /* Parse next core */ 4074ad7e9b0SAdrian Chadd error = bcma_erom_parse_corecfg(&erom, &corecfg); 4084ad7e9b0SAdrian Chadd if (error && error == ENOENT) { 4094ad7e9b0SAdrian Chadd return (0); 4104ad7e9b0SAdrian Chadd } else if (error) { 4114ad7e9b0SAdrian Chadd goto failed; 4124ad7e9b0SAdrian Chadd } 4134ad7e9b0SAdrian Chadd 4144ad7e9b0SAdrian Chadd /* Allocate per-device bus info */ 4154ad7e9b0SAdrian Chadd dinfo = bcma_alloc_dinfo(bus, corecfg); 4164ad7e9b0SAdrian Chadd if (dinfo == NULL) { 4174ad7e9b0SAdrian Chadd error = ENXIO; 4184ad7e9b0SAdrian Chadd goto failed; 4194ad7e9b0SAdrian Chadd } 4204ad7e9b0SAdrian Chadd 4214ad7e9b0SAdrian Chadd /* The dinfo instance now owns the corecfg value */ 4224ad7e9b0SAdrian Chadd corecfg = NULL; 4234ad7e9b0SAdrian Chadd 4244ad7e9b0SAdrian Chadd /* Add the child device */ 4254ad7e9b0SAdrian Chadd child = device_add_child(bus, NULL, -1); 4264ad7e9b0SAdrian Chadd if (child == NULL) { 4274ad7e9b0SAdrian Chadd error = ENXIO; 4284ad7e9b0SAdrian Chadd goto failed; 4294ad7e9b0SAdrian Chadd } 4304ad7e9b0SAdrian Chadd 4314ad7e9b0SAdrian Chadd /* The child device now owns the dinfo pointer */ 4324ad7e9b0SAdrian Chadd device_set_ivars(child, dinfo); 4334ad7e9b0SAdrian Chadd dinfo = NULL; 4344ad7e9b0SAdrian Chadd 4354ad7e9b0SAdrian Chadd /* If pins are floating or the hardware is otherwise 4364ad7e9b0SAdrian Chadd * unpopulated, the device shouldn't be used. */ 4374ad7e9b0SAdrian Chadd if (bhnd_is_hw_disabled(child)) 4384ad7e9b0SAdrian Chadd device_disable(child); 4394ad7e9b0SAdrian Chadd } 4404ad7e9b0SAdrian Chadd 4414ad7e9b0SAdrian Chadd /* Hit EOF parsing cores? */ 4424ad7e9b0SAdrian Chadd if (error == ENOENT) 4434ad7e9b0SAdrian Chadd return (0); 4444ad7e9b0SAdrian Chadd 4454ad7e9b0SAdrian Chadd failed: 4464ad7e9b0SAdrian Chadd if (dinfo != NULL) 4474ad7e9b0SAdrian Chadd bcma_free_dinfo(bus, dinfo); 4484ad7e9b0SAdrian Chadd 4494ad7e9b0SAdrian Chadd if (corecfg != NULL) 4504ad7e9b0SAdrian Chadd bcma_free_corecfg(corecfg); 4514ad7e9b0SAdrian Chadd 4524ad7e9b0SAdrian Chadd return (error); 4534ad7e9b0SAdrian Chadd } 4544ad7e9b0SAdrian Chadd 4554ad7e9b0SAdrian Chadd 4564ad7e9b0SAdrian Chadd static device_method_t bcma_methods[] = { 4574ad7e9b0SAdrian Chadd /* Device interface */ 4584ad7e9b0SAdrian Chadd DEVMETHOD(device_probe, bcma_probe), 4594ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bcma_attach), 4604ad7e9b0SAdrian Chadd DEVMETHOD(device_detach, bcma_detach), 4614ad7e9b0SAdrian Chadd 4624ad7e9b0SAdrian Chadd /* Bus interface */ 4634ad7e9b0SAdrian Chadd DEVMETHOD(bus_child_deleted, bcma_child_deleted), 4644ad7e9b0SAdrian Chadd DEVMETHOD(bus_read_ivar, bcma_read_ivar), 4654ad7e9b0SAdrian Chadd DEVMETHOD(bus_write_ivar, bcma_write_ivar), 4664ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_resource_list, bcma_get_resource_list), 4674ad7e9b0SAdrian Chadd 4684ad7e9b0SAdrian Chadd /* BHND interface */ 4694ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core), 4704ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core), 4714ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), 4724ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count), 4734ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid), 4744ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid), 4754ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr), 4764ad7e9b0SAdrian Chadd 4774ad7e9b0SAdrian Chadd DEVMETHOD_END 4784ad7e9b0SAdrian Chadd }; 4794ad7e9b0SAdrian Chadd 4804ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver); 4814ad7e9b0SAdrian Chadd MODULE_VERSION(bcma, 1); 4824ad7e9b0SAdrian Chadd MODULE_DEPEND(bcma, bhnd, 1, 1, 1); 483