14ad7e9b0SAdrian Chadd /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
36e778a7eSPedro F. Giffuni *
4caeff9a3SLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
5caeff9a3SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation
64ad7e9b0SAdrian Chadd * All rights reserved.
74ad7e9b0SAdrian Chadd *
8caeff9a3SLandon J. Fuller * Portions of this software were developed by Landon Fuller
9caeff9a3SLandon J. Fuller * under sponsorship from the FreeBSD Foundation.
10caeff9a3SLandon J. Fuller *
114ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without
124ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions
134ad7e9b0SAdrian Chadd * are met:
144ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
154ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer,
164ad7e9b0SAdrian Chadd * without modification.
174ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer
184ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
194ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially
204ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution.
214ad7e9b0SAdrian Chadd *
224ad7e9b0SAdrian Chadd * NO WARRANTY
234ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
244ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
254ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
264ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
274ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
284ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
294ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
304ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
314ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
324ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
334ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES.
344ad7e9b0SAdrian Chadd */
354ad7e9b0SAdrian Chadd
364ad7e9b0SAdrian Chadd #include <sys/param.h>
374ad7e9b0SAdrian Chadd #include <sys/bus.h>
384ad7e9b0SAdrian Chadd #include <sys/kernel.h>
394ad7e9b0SAdrian Chadd #include <sys/malloc.h>
404ad7e9b0SAdrian Chadd #include <sys/module.h>
414ad7e9b0SAdrian Chadd #include <sys/systm.h>
424ad7e9b0SAdrian Chadd
434ad7e9b0SAdrian Chadd #include <machine/bus.h>
444ad7e9b0SAdrian Chadd
458a03f98aSLandon J. Fuller #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
464ad7e9b0SAdrian Chadd
47824b48efSLandon J. Fuller #include "bcma_dmp.h"
48824b48efSLandon J. Fuller
494ad7e9b0SAdrian Chadd #include "bcma_eromreg.h"
504ad7e9b0SAdrian Chadd #include "bcma_eromvar.h"
51824b48efSLandon J. Fuller
528a03f98aSLandon J. Fuller #include "bcmavar.h"
534ad7e9b0SAdrian Chadd
54664a7497SLandon J. Fuller /* RID used when allocating EROM table */
55664a7497SLandon J. Fuller #define BCMA_EROM_RID 0
56664a7497SLandon J. Fuller
57111d7cb2SLandon J. Fuller static bhnd_erom_class_t *
bcma_get_erom_class(driver_t * driver)58111d7cb2SLandon J. Fuller bcma_get_erom_class(driver_t *driver)
59111d7cb2SLandon J. Fuller {
60111d7cb2SLandon J. Fuller return (&bcma_erom_parser);
61111d7cb2SLandon J. Fuller }
62111d7cb2SLandon J. Fuller
634ad7e9b0SAdrian Chadd int
bcma_probe(device_t dev)644ad7e9b0SAdrian Chadd bcma_probe(device_t dev)
654ad7e9b0SAdrian Chadd {
664ad7e9b0SAdrian Chadd device_set_desc(dev, "BCMA BHND bus");
674ad7e9b0SAdrian Chadd return (BUS_PROBE_DEFAULT);
684ad7e9b0SAdrian Chadd }
694ad7e9b0SAdrian Chadd
70111d7cb2SLandon J. Fuller /**
71111d7cb2SLandon J. Fuller * Default bcma(4) bus driver implementation of DEVICE_ATTACH().
72111d7cb2SLandon J. Fuller *
73111d7cb2SLandon J. Fuller * This implementation initializes internal bcma(4) state and performs
74111d7cb2SLandon J. Fuller * bus enumeration, and must be called by subclassing drivers in
75111d7cb2SLandon J. Fuller * DEVICE_ATTACH() before any other bus methods.
76111d7cb2SLandon J. Fuller */
774ad7e9b0SAdrian Chadd int
bcma_attach(device_t dev)784ad7e9b0SAdrian Chadd bcma_attach(device_t dev)
794ad7e9b0SAdrian Chadd {
804ad7e9b0SAdrian Chadd int error;
814ad7e9b0SAdrian Chadd
82111d7cb2SLandon J. Fuller /* Enumerate children */
83111d7cb2SLandon J. Fuller if ((error = bcma_add_children(dev))) {
84111d7cb2SLandon J. Fuller device_delete_children(dev);
854ad7e9b0SAdrian Chadd return (error);
864ad7e9b0SAdrian Chadd }
874ad7e9b0SAdrian Chadd
88111d7cb2SLandon J. Fuller return (0);
894ad7e9b0SAdrian Chadd }
904ad7e9b0SAdrian Chadd
914ad7e9b0SAdrian Chadd int
bcma_detach(device_t dev)924ad7e9b0SAdrian Chadd bcma_detach(device_t dev)
934ad7e9b0SAdrian Chadd {
944ad7e9b0SAdrian Chadd return (bhnd_generic_detach(dev));
954ad7e9b0SAdrian Chadd }
964ad7e9b0SAdrian Chadd
978a03f98aSLandon J. Fuller static device_t
bcma_add_child(device_t dev,u_int order,const char * name,int unit)988a03f98aSLandon J. Fuller bcma_add_child(device_t dev, u_int order, const char *name, int unit)
998a03f98aSLandon J. Fuller {
1008a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo;
1018a03f98aSLandon J. Fuller device_t child;
1028a03f98aSLandon J. Fuller
1038a03f98aSLandon J. Fuller child = device_add_child_ordered(dev, order, name, unit);
1048a03f98aSLandon J. Fuller if (child == NULL)
1058a03f98aSLandon J. Fuller return (NULL);
1068a03f98aSLandon J. Fuller
1078a03f98aSLandon J. Fuller if ((dinfo = bcma_alloc_dinfo(dev)) == NULL) {
1088a03f98aSLandon J. Fuller device_delete_child(dev, child);
1098a03f98aSLandon J. Fuller return (NULL);
1108a03f98aSLandon J. Fuller }
1118a03f98aSLandon J. Fuller
1128a03f98aSLandon J. Fuller device_set_ivars(child, dinfo);
1138a03f98aSLandon J. Fuller
1148a03f98aSLandon J. Fuller return (child);
1158a03f98aSLandon J. Fuller }
1168a03f98aSLandon J. Fuller
1178a03f98aSLandon J. Fuller static void
bcma_child_deleted(device_t dev,device_t child)1188a03f98aSLandon J. Fuller bcma_child_deleted(device_t dev, device_t child)
1198a03f98aSLandon J. Fuller {
1208a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo;
1218a03f98aSLandon J. Fuller
1228a03f98aSLandon J. Fuller /* Call required bhnd(4) implementation */
1238a03f98aSLandon J. Fuller bhnd_generic_child_deleted(dev, child);
1248a03f98aSLandon J. Fuller
1258a03f98aSLandon J. Fuller /* Free bcma device info */
1268a03f98aSLandon J. Fuller if ((dinfo = device_get_ivars(child)) != NULL)
127caeff9a3SLandon J. Fuller bcma_free_dinfo(dev, child, dinfo);
1288a03f98aSLandon J. Fuller
1298a03f98aSLandon J. Fuller device_set_ivars(child, NULL);
1308a03f98aSLandon J. Fuller }
1318a03f98aSLandon J. Fuller
1324ad7e9b0SAdrian Chadd static int
bcma_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)1334ad7e9b0SAdrian Chadd bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
1344ad7e9b0SAdrian Chadd {
1354ad7e9b0SAdrian Chadd const struct bcma_devinfo *dinfo;
1364ad7e9b0SAdrian Chadd const struct bhnd_core_info *ci;
1374ad7e9b0SAdrian Chadd
1384ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
1394ad7e9b0SAdrian Chadd ci = &dinfo->corecfg->core_info;
1404ad7e9b0SAdrian Chadd
1414ad7e9b0SAdrian Chadd switch (index) {
1424ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR:
1434ad7e9b0SAdrian Chadd *result = ci->vendor;
1444ad7e9b0SAdrian Chadd return (0);
1454ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE:
1464ad7e9b0SAdrian Chadd *result = ci->device;
1474ad7e9b0SAdrian Chadd return (0);
1484ad7e9b0SAdrian Chadd case BHND_IVAR_HWREV:
1494ad7e9b0SAdrian Chadd *result = ci->hwrev;
1504ad7e9b0SAdrian Chadd return (0);
1514ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_CLASS:
1524ad7e9b0SAdrian Chadd *result = bhnd_core_class(ci);
1534ad7e9b0SAdrian Chadd return (0);
1544ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR_NAME:
1554ad7e9b0SAdrian Chadd *result = (uintptr_t) bhnd_vendor_name(ci->vendor);
1564ad7e9b0SAdrian Chadd return (0);
1574ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_NAME:
1584ad7e9b0SAdrian Chadd *result = (uintptr_t) bhnd_core_name(ci);
1594ad7e9b0SAdrian Chadd return (0);
1604ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_INDEX:
1614ad7e9b0SAdrian Chadd *result = ci->core_idx;
1624ad7e9b0SAdrian Chadd return (0);
1634ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_UNIT:
1644ad7e9b0SAdrian Chadd *result = ci->unit;
1654ad7e9b0SAdrian Chadd return (0);
1668a03f98aSLandon J. Fuller case BHND_IVAR_PMU_INFO:
1678a03f98aSLandon J. Fuller *result = (uintptr_t) dinfo->pmu_info;
1688a03f98aSLandon J. Fuller return (0);
1694ad7e9b0SAdrian Chadd default:
1704ad7e9b0SAdrian Chadd return (ENOENT);
1714ad7e9b0SAdrian Chadd }
1724ad7e9b0SAdrian Chadd }
1734ad7e9b0SAdrian Chadd
1744ad7e9b0SAdrian Chadd static int
bcma_write_ivar(device_t dev,device_t child,int index,uintptr_t value)1754ad7e9b0SAdrian Chadd bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
1764ad7e9b0SAdrian Chadd {
1778a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo;
1788a03f98aSLandon J. Fuller
1798a03f98aSLandon J. Fuller dinfo = device_get_ivars(child);
1808a03f98aSLandon J. Fuller
1814ad7e9b0SAdrian Chadd switch (index) {
1824ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR:
1834ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE:
1844ad7e9b0SAdrian Chadd case BHND_IVAR_HWREV:
1854ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_CLASS:
1864ad7e9b0SAdrian Chadd case BHND_IVAR_VENDOR_NAME:
1874ad7e9b0SAdrian Chadd case BHND_IVAR_DEVICE_NAME:
1884ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_INDEX:
1894ad7e9b0SAdrian Chadd case BHND_IVAR_CORE_UNIT:
1904ad7e9b0SAdrian Chadd return (EINVAL);
1918a03f98aSLandon J. Fuller case BHND_IVAR_PMU_INFO:
1924e96bf3aSLandon J. Fuller dinfo->pmu_info = (void *)value;
1938a03f98aSLandon J. Fuller return (0);
1944ad7e9b0SAdrian Chadd default:
1954ad7e9b0SAdrian Chadd return (ENOENT);
1964ad7e9b0SAdrian Chadd }
1974ad7e9b0SAdrian Chadd }
1984ad7e9b0SAdrian Chadd
1994ad7e9b0SAdrian Chadd static struct resource_list *
bcma_get_resource_list(device_t dev,device_t child)2004ad7e9b0SAdrian Chadd bcma_get_resource_list(device_t dev, device_t child)
2014ad7e9b0SAdrian Chadd {
2024ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo = device_get_ivars(child);
2034ad7e9b0SAdrian Chadd return (&dinfo->resources);
2044ad7e9b0SAdrian Chadd }
2054ad7e9b0SAdrian Chadd
2064ad7e9b0SAdrian Chadd static int
bcma_read_iost(device_t dev,device_t child,uint16_t * iost)2078a03f98aSLandon J. Fuller bcma_read_iost(device_t dev, device_t child, uint16_t *iost)
2088a03f98aSLandon J. Fuller {
2098a03f98aSLandon J. Fuller uint32_t value;
2108a03f98aSLandon J. Fuller int error;
2118a03f98aSLandon J. Fuller
2128a03f98aSLandon J. Fuller if ((error = bhnd_read_config(child, BCMA_DMP_IOSTATUS, &value, 4)))
2138a03f98aSLandon J. Fuller return (error);
2148a03f98aSLandon J. Fuller
2158a03f98aSLandon J. Fuller /* Return only the bottom 16 bits */
2168a03f98aSLandon J. Fuller *iost = (value & BCMA_DMP_IOST_MASK);
2178a03f98aSLandon J. Fuller return (0);
2188a03f98aSLandon J. Fuller }
2198a03f98aSLandon J. Fuller
2208a03f98aSLandon J. Fuller static int
bcma_read_ioctl(device_t dev,device_t child,uint16_t * ioctl)2218a03f98aSLandon J. Fuller bcma_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
2228a03f98aSLandon J. Fuller {
2238a03f98aSLandon J. Fuller uint32_t value;
2248a03f98aSLandon J. Fuller int error;
2258a03f98aSLandon J. Fuller
2268a03f98aSLandon J. Fuller if ((error = bhnd_read_config(child, BCMA_DMP_IOCTRL, &value, 4)))
2278a03f98aSLandon J. Fuller return (error);
2288a03f98aSLandon J. Fuller
2298a03f98aSLandon J. Fuller /* Return only the bottom 16 bits */
2308a03f98aSLandon J. Fuller *ioctl = (value & BCMA_DMP_IOCTRL_MASK);
2318a03f98aSLandon J. Fuller return (0);
2328a03f98aSLandon J. Fuller }
2338a03f98aSLandon J. Fuller
2348a03f98aSLandon J. Fuller static int
bcma_write_ioctl(device_t dev,device_t child,uint16_t value,uint16_t mask)2358a03f98aSLandon J. Fuller bcma_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
2364ad7e9b0SAdrian Chadd {
2374ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
2388a03f98aSLandon J. Fuller struct bhnd_resource *r;
2398a03f98aSLandon J. Fuller uint32_t ioctl;
2404ad7e9b0SAdrian Chadd
2414ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev)
2428a03f98aSLandon J. Fuller return (EINVAL);
2434ad7e9b0SAdrian Chadd
2444ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
2458a03f98aSLandon J. Fuller if ((r = dinfo->res_agent) == NULL)
2464ad7e9b0SAdrian Chadd return (ENODEV);
2474ad7e9b0SAdrian Chadd
2488a03f98aSLandon J. Fuller /* Write new value */
2498a03f98aSLandon J. Fuller ioctl = bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
2508a03f98aSLandon J. Fuller ioctl &= ~(BCMA_DMP_IOCTRL_MASK & mask);
2518a03f98aSLandon J. Fuller ioctl |= (value & mask);
2524ad7e9b0SAdrian Chadd
2538a03f98aSLandon J. Fuller bhnd_bus_write_4(r, BCMA_DMP_IOCTRL, ioctl);
25431318f07SAdrian Chadd
2558a03f98aSLandon J. Fuller /* Perform read-back and wait for completion */
2568a03f98aSLandon J. Fuller bhnd_bus_read_4(r, BCMA_DMP_IOCTRL);
25731318f07SAdrian Chadd DELAY(10);
25831318f07SAdrian Chadd
25931318f07SAdrian Chadd return (0);
2604ad7e9b0SAdrian Chadd }
2614ad7e9b0SAdrian Chadd
2628a03f98aSLandon J. Fuller static bool
bcma_is_hw_suspended(device_t dev,device_t child)2638a03f98aSLandon J. Fuller bcma_is_hw_suspended(device_t dev, device_t child)
2648a03f98aSLandon J. Fuller {
2658a03f98aSLandon J. Fuller uint32_t rst;
2668a03f98aSLandon J. Fuller uint16_t ioctl;
2678a03f98aSLandon J. Fuller int error;
2688a03f98aSLandon J. Fuller
2698a03f98aSLandon J. Fuller /* Is core held in RESET? */
2708a03f98aSLandon J. Fuller error = bhnd_read_config(child, BCMA_DMP_RESETCTRL, &rst, 4);
2718a03f98aSLandon J. Fuller if (error) {
2728a03f98aSLandon J. Fuller device_printf(child, "error reading HW reset state: %d\n",
2738a03f98aSLandon J. Fuller error);
2748a03f98aSLandon J. Fuller return (true);
2758a03f98aSLandon J. Fuller }
2768a03f98aSLandon J. Fuller
277ba3eb10dSMichael Zhilin if (rst & BCMA_DMP_RC_RESET)
2788a03f98aSLandon J. Fuller return (true);
2798a03f98aSLandon J. Fuller
2808a03f98aSLandon J. Fuller /* Is core clocked? */
2818a03f98aSLandon J. Fuller error = bhnd_read_ioctl(child, &ioctl);
2828a03f98aSLandon J. Fuller if (error) {
2838a03f98aSLandon J. Fuller device_printf(child, "error reading HW ioctl register: %d\n",
2848a03f98aSLandon J. Fuller error);
2858a03f98aSLandon J. Fuller return (true);
2868a03f98aSLandon J. Fuller }
2878a03f98aSLandon J. Fuller
2888a03f98aSLandon J. Fuller if (!(ioctl & BHND_IOCTL_CLK_EN))
2898a03f98aSLandon J. Fuller return (true);
2908a03f98aSLandon J. Fuller
2918a03f98aSLandon J. Fuller return (false);
2928a03f98aSLandon J. Fuller }
2938a03f98aSLandon J. Fuller
2944ad7e9b0SAdrian Chadd static int
bcma_reset_hw(device_t dev,device_t child,uint16_t ioctl,uint16_t reset_ioctl)295ac59515bSLandon J. Fuller bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl,
296ac59515bSLandon J. Fuller uint16_t reset_ioctl)
2974ad7e9b0SAdrian Chadd {
2984ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
2998a03f98aSLandon J. Fuller struct bhnd_resource *r;
300ac59515bSLandon J. Fuller uint16_t clkflags;
3018a03f98aSLandon J. Fuller int error;
3024ad7e9b0SAdrian Chadd
3034ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev)
3048a03f98aSLandon J. Fuller return (EINVAL);
3054ad7e9b0SAdrian Chadd
3064ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
3078a03f98aSLandon J. Fuller
308ac59515bSLandon J. Fuller /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
309ac59515bSLandon J. Fuller clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
310ac59515bSLandon J. Fuller if (ioctl & clkflags)
3118a03f98aSLandon J. Fuller return (EINVAL);
3124ad7e9b0SAdrian Chadd
3134ad7e9b0SAdrian Chadd /* Can't suspend the core without access to the agent registers */
3148a03f98aSLandon J. Fuller if ((r = dinfo->res_agent) == NULL)
3154ad7e9b0SAdrian Chadd return (ENODEV);
3164ad7e9b0SAdrian Chadd
3178a03f98aSLandon J. Fuller /* Place core into known RESET state */
318ac59515bSLandon J. Fuller if ((error = bhnd_suspend_hw(child, reset_ioctl)))
3198a03f98aSLandon J. Fuller return (error);
3204ad7e9b0SAdrian Chadd
3218a03f98aSLandon J. Fuller /*
3228a03f98aSLandon J. Fuller * Leaving the core in reset:
3238a03f98aSLandon J. Fuller * - Set the caller's IOCTL flags
3248a03f98aSLandon J. Fuller * - Enable clocks
3258a03f98aSLandon J. Fuller * - Force clock distribution to ensure propagation throughout the
3268a03f98aSLandon J. Fuller * core.
3278a03f98aSLandon J. Fuller */
328ac59515bSLandon J. Fuller if ((error = bhnd_write_ioctl(child, ioctl | clkflags, UINT16_MAX)))
3298a03f98aSLandon J. Fuller return (error);
3308a03f98aSLandon J. Fuller
3318a03f98aSLandon J. Fuller /* Bring the core out of reset */
3328a03f98aSLandon J. Fuller if ((error = bcma_dmp_write_reset(child, dinfo, 0x0)))
3338a03f98aSLandon J. Fuller return (error);
3348a03f98aSLandon J. Fuller
3358a03f98aSLandon J. Fuller /* Disable forced clock gating (leaving clock enabled) */
3368a03f98aSLandon J. Fuller error = bhnd_write_ioctl(child, 0x0, BHND_IOCTL_CLK_FORCE);
3378a03f98aSLandon J. Fuller if (error)
3388a03f98aSLandon J. Fuller return (error);
3398a03f98aSLandon J. Fuller
3408a03f98aSLandon J. Fuller return (0);
3414ad7e9b0SAdrian Chadd }
3424ad7e9b0SAdrian Chadd
3438a03f98aSLandon J. Fuller static int
bcma_suspend_hw(device_t dev,device_t child,uint16_t ioctl)344ac59515bSLandon J. Fuller bcma_suspend_hw(device_t dev, device_t child, uint16_t ioctl)
345f90f4b65SLandon J. Fuller {
346f90f4b65SLandon J. Fuller struct bcma_devinfo *dinfo;
347f90f4b65SLandon J. Fuller struct bhnd_resource *r;
348ac59515bSLandon J. Fuller uint16_t clkflags;
3498a03f98aSLandon J. Fuller int error;
350f90f4b65SLandon J. Fuller
351f90f4b65SLandon J. Fuller if (device_get_parent(child) != dev)
3528a03f98aSLandon J. Fuller return (EINVAL);
353f90f4b65SLandon J. Fuller
354f90f4b65SLandon J. Fuller dinfo = device_get_ivars(child);
3558a03f98aSLandon J. Fuller
356ac59515bSLandon J. Fuller /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
357ac59515bSLandon J. Fuller clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
358ac59515bSLandon J. Fuller if (ioctl & clkflags)
359ac59515bSLandon J. Fuller return (EINVAL);
360ac59515bSLandon J. Fuller
3618a03f98aSLandon J. Fuller /* Can't suspend the core without access to the agent registers */
362f90f4b65SLandon J. Fuller if ((r = dinfo->res_agent) == NULL)
3638a03f98aSLandon J. Fuller return (ENODEV);
364f90f4b65SLandon J. Fuller
3658a03f98aSLandon J. Fuller /* Wait for any pending reset operations to clear */
3668a03f98aSLandon J. Fuller if ((error = bcma_dmp_wait_reset(child, dinfo)))
3678a03f98aSLandon J. Fuller return (error);
368f90f4b65SLandon J. Fuller
369ac59515bSLandon J. Fuller /* Put core into reset (if not already in reset) */
370ba3eb10dSMichael Zhilin if ((error = bcma_dmp_write_reset(child, dinfo, BCMA_DMP_RC_RESET)))
3718a03f98aSLandon J. Fuller return (error);
3728a03f98aSLandon J. Fuller
373ac59515bSLandon J. Fuller /* Write core flags (and clear CLK_EN/CLK_FORCE) */
374ac59515bSLandon J. Fuller if ((error = bhnd_write_ioctl(child, ioctl, ~clkflags)))
3758a03f98aSLandon J. Fuller return (error);
3768a03f98aSLandon J. Fuller
3778a03f98aSLandon J. Fuller return (0);
3788a03f98aSLandon J. Fuller }
3798a03f98aSLandon J. Fuller
3808a03f98aSLandon J. Fuller static int
bcma_read_config(device_t dev,device_t child,bus_size_t offset,void * value,u_int width)3818a03f98aSLandon J. Fuller bcma_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
382f90f4b65SLandon J. Fuller u_int width)
383f90f4b65SLandon J. Fuller {
384f90f4b65SLandon J. Fuller struct bcma_devinfo *dinfo;
385f90f4b65SLandon J. Fuller struct bhnd_resource *r;
386f90f4b65SLandon J. Fuller
387f90f4b65SLandon J. Fuller /* Must be a directly attached child core */
388f90f4b65SLandon J. Fuller if (device_get_parent(child) != dev)
3898a03f98aSLandon J. Fuller return (EINVAL);
390f90f4b65SLandon J. Fuller
391f90f4b65SLandon J. Fuller /* Fetch the agent registers */
392f90f4b65SLandon J. Fuller dinfo = device_get_ivars(child);
393f90f4b65SLandon J. Fuller if ((r = dinfo->res_agent) == NULL)
3948a03f98aSLandon J. Fuller return (ENODEV);
395f90f4b65SLandon J. Fuller
396f90f4b65SLandon J. Fuller /* Verify bounds */
397f90f4b65SLandon J. Fuller if (offset > rman_get_size(r->res))
3988a03f98aSLandon J. Fuller return (EFAULT);
399f90f4b65SLandon J. Fuller
400f90f4b65SLandon J. Fuller if (rman_get_size(r->res) - offset < width)
4018a03f98aSLandon J. Fuller return (EFAULT);
402f90f4b65SLandon J. Fuller
403f90f4b65SLandon J. Fuller switch (width) {
404f90f4b65SLandon J. Fuller case 1:
4058a03f98aSLandon J. Fuller *((uint8_t *)value) = bhnd_bus_read_1(r, offset);
4068a03f98aSLandon J. Fuller return (0);
407f90f4b65SLandon J. Fuller case 2:
4088a03f98aSLandon J. Fuller *((uint16_t *)value) = bhnd_bus_read_2(r, offset);
4098a03f98aSLandon J. Fuller return (0);
410f90f4b65SLandon J. Fuller case 4:
4118a03f98aSLandon J. Fuller *((uint32_t *)value) = bhnd_bus_read_4(r, offset);
4128a03f98aSLandon J. Fuller return (0);
413f90f4b65SLandon J. Fuller default:
4148a03f98aSLandon J. Fuller return (EINVAL);
4158a03f98aSLandon J. Fuller }
4168a03f98aSLandon J. Fuller }
4178a03f98aSLandon J. Fuller
4188a03f98aSLandon J. Fuller static int
bcma_write_config(device_t dev,device_t child,bus_size_t offset,const void * value,u_int width)4198a03f98aSLandon J. Fuller bcma_write_config(device_t dev, device_t child, bus_size_t offset,
4208a03f98aSLandon J. Fuller const void *value, u_int width)
4218a03f98aSLandon J. Fuller {
4228a03f98aSLandon J. Fuller struct bcma_devinfo *dinfo;
4238a03f98aSLandon J. Fuller struct bhnd_resource *r;
4248a03f98aSLandon J. Fuller
4258a03f98aSLandon J. Fuller /* Must be a directly attached child core */
4268a03f98aSLandon J. Fuller if (device_get_parent(child) != dev)
4278a03f98aSLandon J. Fuller return (EINVAL);
4288a03f98aSLandon J. Fuller
4298a03f98aSLandon J. Fuller /* Fetch the agent registers */
4308a03f98aSLandon J. Fuller dinfo = device_get_ivars(child);
4318a03f98aSLandon J. Fuller if ((r = dinfo->res_agent) == NULL)
4328a03f98aSLandon J. Fuller return (ENODEV);
4338a03f98aSLandon J. Fuller
4348a03f98aSLandon J. Fuller /* Verify bounds */
4358a03f98aSLandon J. Fuller if (offset > rman_get_size(r->res))
4368a03f98aSLandon J. Fuller return (EFAULT);
4378a03f98aSLandon J. Fuller
4388a03f98aSLandon J. Fuller if (rman_get_size(r->res) - offset < width)
4398a03f98aSLandon J. Fuller return (EFAULT);
4408a03f98aSLandon J. Fuller
4418a03f98aSLandon J. Fuller switch (width) {
4428a03f98aSLandon J. Fuller case 1:
4438a03f98aSLandon J. Fuller bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
4448a03f98aSLandon J. Fuller return (0);
4458a03f98aSLandon J. Fuller case 2:
4468a03f98aSLandon J. Fuller bhnd_bus_write_2(r, offset, *(const uint16_t *)value);
4478a03f98aSLandon J. Fuller return (0);
4488a03f98aSLandon J. Fuller case 4:
4498a03f98aSLandon J. Fuller bhnd_bus_write_4(r, offset, *(const uint32_t *)value);
4508a03f98aSLandon J. Fuller return (0);
4518a03f98aSLandon J. Fuller default:
4528a03f98aSLandon J. Fuller return (EINVAL);
453f90f4b65SLandon J. Fuller }
454f90f4b65SLandon J. Fuller }
455f90f4b65SLandon J. Fuller
4564ad7e9b0SAdrian Chadd static u_int
bcma_get_port_count(device_t dev,device_t child,bhnd_port_type type)4574ad7e9b0SAdrian Chadd bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
4584ad7e9b0SAdrian Chadd {
4594ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
4604ad7e9b0SAdrian Chadd
4614ad7e9b0SAdrian Chadd /* delegate non-bus-attached devices to our parent */
4624ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev)
4634ad7e9b0SAdrian Chadd return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
4644ad7e9b0SAdrian Chadd type));
4654ad7e9b0SAdrian Chadd
4664ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
4674ad7e9b0SAdrian Chadd switch (type) {
4684ad7e9b0SAdrian Chadd case BHND_PORT_DEVICE:
4694ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_dev_ports);
4704ad7e9b0SAdrian Chadd case BHND_PORT_BRIDGE:
4714ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_bridge_ports);
4724ad7e9b0SAdrian Chadd case BHND_PORT_AGENT:
4734ad7e9b0SAdrian Chadd return (dinfo->corecfg->num_wrapper_ports);
474988fa8d0SAdrian Chadd default:
475988fa8d0SAdrian Chadd device_printf(dev, "%s: unknown type (%d)\n",
476988fa8d0SAdrian Chadd __func__,
477988fa8d0SAdrian Chadd type);
478988fa8d0SAdrian Chadd return (0);
4794ad7e9b0SAdrian Chadd }
4804ad7e9b0SAdrian Chadd }
4814ad7e9b0SAdrian Chadd
4824ad7e9b0SAdrian Chadd static u_int
bcma_get_region_count(device_t dev,device_t child,bhnd_port_type type,u_int port_num)4834ad7e9b0SAdrian Chadd bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type,
4844ad7e9b0SAdrian Chadd u_int port_num)
4854ad7e9b0SAdrian Chadd {
4864ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
4874ad7e9b0SAdrian Chadd struct bcma_sport_list *ports;
4884ad7e9b0SAdrian Chadd struct bcma_sport *port;
4894ad7e9b0SAdrian Chadd
4904ad7e9b0SAdrian Chadd /* delegate non-bus-attached devices to our parent */
4914ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev)
4924ad7e9b0SAdrian Chadd return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
4934ad7e9b0SAdrian Chadd type, port_num));
4944ad7e9b0SAdrian Chadd
4954ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
4964ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, type);
4974ad7e9b0SAdrian Chadd
4984ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) {
4994ad7e9b0SAdrian Chadd if (port->sp_num == port_num)
5004ad7e9b0SAdrian Chadd return (port->sp_num_maps);
5014ad7e9b0SAdrian Chadd }
5024ad7e9b0SAdrian Chadd
5034ad7e9b0SAdrian Chadd /* not found */
5044ad7e9b0SAdrian Chadd return (0);
5054ad7e9b0SAdrian Chadd }
5064ad7e9b0SAdrian Chadd
5074ad7e9b0SAdrian Chadd static int
bcma_get_port_rid(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num)5084ad7e9b0SAdrian Chadd bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
5094ad7e9b0SAdrian Chadd u_int port_num, u_int region_num)
5104ad7e9b0SAdrian Chadd {
5114ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
5124ad7e9b0SAdrian Chadd struct bcma_map *map;
5134ad7e9b0SAdrian Chadd struct bcma_sport_list *ports;
5144ad7e9b0SAdrian Chadd struct bcma_sport *port;
5154ad7e9b0SAdrian Chadd
5164ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
5174ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
5184ad7e9b0SAdrian Chadd
5194ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) {
5204ad7e9b0SAdrian Chadd if (port->sp_num != port_num)
5214ad7e9b0SAdrian Chadd continue;
5224ad7e9b0SAdrian Chadd
5234ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link)
5244ad7e9b0SAdrian Chadd if (map->m_region_num == region_num)
5254ad7e9b0SAdrian Chadd return map->m_rid;
5264ad7e9b0SAdrian Chadd }
5274ad7e9b0SAdrian Chadd
5284ad7e9b0SAdrian Chadd return -1;
5294ad7e9b0SAdrian Chadd }
5304ad7e9b0SAdrian Chadd
5314ad7e9b0SAdrian Chadd static int
bcma_decode_port_rid(device_t dev,device_t child,int type,int rid,bhnd_port_type * port_type,u_int * port_num,u_int * region_num)5324ad7e9b0SAdrian Chadd bcma_decode_port_rid(device_t dev, device_t child, int type, int rid,
5334ad7e9b0SAdrian Chadd bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
5344ad7e9b0SAdrian Chadd {
5354ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
5364ad7e9b0SAdrian Chadd struct bcma_map *map;
5374ad7e9b0SAdrian Chadd struct bcma_sport_list *ports;
5384ad7e9b0SAdrian Chadd struct bcma_sport *port;
5394ad7e9b0SAdrian Chadd
5404ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
5414ad7e9b0SAdrian Chadd
5424ad7e9b0SAdrian Chadd /* Ports are always memory mapped */
5434ad7e9b0SAdrian Chadd if (type != SYS_RES_MEMORY)
5444ad7e9b0SAdrian Chadd return (EINVAL);
5454ad7e9b0SAdrian Chadd
5464ad7e9b0SAdrian Chadd /* Starting with the most likely device list, search all three port
5474ad7e9b0SAdrian Chadd * lists */
5484ad7e9b0SAdrian Chadd bhnd_port_type types[] = {
5494ad7e9b0SAdrian Chadd BHND_PORT_DEVICE,
5504ad7e9b0SAdrian Chadd BHND_PORT_AGENT,
5514ad7e9b0SAdrian Chadd BHND_PORT_BRIDGE
5524ad7e9b0SAdrian Chadd };
5534ad7e9b0SAdrian Chadd
5544ad7e9b0SAdrian Chadd for (int i = 0; i < nitems(types); i++) {
5554ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]);
5564ad7e9b0SAdrian Chadd
5574ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) {
5584ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) {
5594ad7e9b0SAdrian Chadd if (map->m_rid != rid)
5604ad7e9b0SAdrian Chadd continue;
5614ad7e9b0SAdrian Chadd
5624ad7e9b0SAdrian Chadd *port_type = port->sp_type;
5634ad7e9b0SAdrian Chadd *port_num = port->sp_num;
5644ad7e9b0SAdrian Chadd *region_num = map->m_region_num;
5654ad7e9b0SAdrian Chadd return (0);
5664ad7e9b0SAdrian Chadd }
5674ad7e9b0SAdrian Chadd }
5684ad7e9b0SAdrian Chadd }
5694ad7e9b0SAdrian Chadd
5704ad7e9b0SAdrian Chadd return (ENOENT);
5714ad7e9b0SAdrian Chadd }
5724ad7e9b0SAdrian Chadd
5734ad7e9b0SAdrian Chadd static int
bcma_get_region_addr(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num,bhnd_addr_t * addr,bhnd_size_t * size)5744ad7e9b0SAdrian Chadd bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
5754ad7e9b0SAdrian Chadd u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
5764ad7e9b0SAdrian Chadd {
5774ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
5784ad7e9b0SAdrian Chadd struct bcma_map *map;
5794ad7e9b0SAdrian Chadd struct bcma_sport_list *ports;
5804ad7e9b0SAdrian Chadd struct bcma_sport *port;
5814ad7e9b0SAdrian Chadd
5824ad7e9b0SAdrian Chadd dinfo = device_get_ivars(child);
5834ad7e9b0SAdrian Chadd ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
5844ad7e9b0SAdrian Chadd
5854ad7e9b0SAdrian Chadd /* Search the port list */
5864ad7e9b0SAdrian Chadd STAILQ_FOREACH(port, ports, sp_link) {
5874ad7e9b0SAdrian Chadd if (port->sp_num != port_num)
5884ad7e9b0SAdrian Chadd continue;
5894ad7e9b0SAdrian Chadd
5904ad7e9b0SAdrian Chadd STAILQ_FOREACH(map, &port->sp_maps, m_link) {
5914ad7e9b0SAdrian Chadd if (map->m_region_num != region_num)
5924ad7e9b0SAdrian Chadd continue;
5934ad7e9b0SAdrian Chadd
5944ad7e9b0SAdrian Chadd /* Found! */
5954ad7e9b0SAdrian Chadd *addr = map->m_base;
5964ad7e9b0SAdrian Chadd *size = map->m_size;
5974ad7e9b0SAdrian Chadd return (0);
5984ad7e9b0SAdrian Chadd }
5994ad7e9b0SAdrian Chadd }
6004ad7e9b0SAdrian Chadd
6014ad7e9b0SAdrian Chadd return (ENOENT);
6024ad7e9b0SAdrian Chadd }
6034ad7e9b0SAdrian Chadd
604824b48efSLandon J. Fuller /**
605824b48efSLandon J. Fuller * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
606824b48efSLandon J. Fuller */
607caeff9a3SLandon J. Fuller u_int
bcma_get_intr_count(device_t dev,device_t child)608824b48efSLandon J. Fuller bcma_get_intr_count(device_t dev, device_t child)
609824b48efSLandon J. Fuller {
610824b48efSLandon J. Fuller struct bcma_devinfo *dinfo;
611caeff9a3SLandon J. Fuller
612caeff9a3SLandon J. Fuller /* delegate non-bus-attached devices to our parent */
613caeff9a3SLandon J. Fuller if (device_get_parent(child) != dev)
614caeff9a3SLandon J. Fuller return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
615824b48efSLandon J. Fuller
616824b48efSLandon J. Fuller dinfo = device_get_ivars(child);
617caeff9a3SLandon J. Fuller return (dinfo->num_intrs);
618824b48efSLandon J. Fuller }
619824b48efSLandon J. Fuller
620824b48efSLandon J. Fuller /**
621caeff9a3SLandon J. Fuller * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC().
622824b48efSLandon J. Fuller */
623824b48efSLandon J. Fuller int
bcma_get_intr_ivec(device_t dev,device_t child,u_int intr,u_int * ivec)624caeff9a3SLandon J. Fuller bcma_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
625824b48efSLandon J. Fuller {
626824b48efSLandon J. Fuller struct bcma_devinfo *dinfo;
627caeff9a3SLandon J. Fuller struct bcma_intr *desc;
628caeff9a3SLandon J. Fuller
629caeff9a3SLandon J. Fuller /* delegate non-bus-attached devices to our parent */
630caeff9a3SLandon J. Fuller if (device_get_parent(child) != dev) {
631caeff9a3SLandon J. Fuller return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child,
632caeff9a3SLandon J. Fuller intr, ivec));
633caeff9a3SLandon J. Fuller }
634824b48efSLandon J. Fuller
635824b48efSLandon J. Fuller dinfo = device_get_ivars(child);
636824b48efSLandon J. Fuller
637caeff9a3SLandon J. Fuller STAILQ_FOREACH(desc, &dinfo->intrs, i_link) {
638caeff9a3SLandon J. Fuller if (desc->i_sel == intr) {
639caeff9a3SLandon J. Fuller *ivec = desc->i_busline;
640824b48efSLandon J. Fuller return (0);
641824b48efSLandon J. Fuller }
642caeff9a3SLandon J. Fuller }
643caeff9a3SLandon J. Fuller
644caeff9a3SLandon J. Fuller /* Not found */
645caeff9a3SLandon J. Fuller return (ENXIO);
646caeff9a3SLandon J. Fuller }
647824b48efSLandon J. Fuller
6484ad7e9b0SAdrian Chadd /**
649664a7497SLandon J. Fuller * Scan the device enumeration ROM table, adding all valid discovered cores to
6504ad7e9b0SAdrian Chadd * the bus.
6514ad7e9b0SAdrian Chadd *
6524ad7e9b0SAdrian Chadd * @param bus The bcma bus.
6534ad7e9b0SAdrian Chadd */
6544ad7e9b0SAdrian Chadd int
bcma_add_children(device_t bus)655664a7497SLandon J. Fuller bcma_add_children(device_t bus)
6564ad7e9b0SAdrian Chadd {
657664a7497SLandon J. Fuller bhnd_erom_t *erom;
658664a7497SLandon J. Fuller struct bcma_erom *bcma_erom;
65989294a78SLandon J. Fuller struct bhnd_erom_io *eio;
660664a7497SLandon J. Fuller const struct bhnd_chipid *cid;
6614ad7e9b0SAdrian Chadd struct bcma_corecfg *corecfg;
6624ad7e9b0SAdrian Chadd struct bcma_devinfo *dinfo;
6634ad7e9b0SAdrian Chadd device_t child;
6644ad7e9b0SAdrian Chadd int error;
6654ad7e9b0SAdrian Chadd
666664a7497SLandon J. Fuller cid = BHND_BUS_GET_CHIPID(bus, bus);
6674ad7e9b0SAdrian Chadd corecfg = NULL;
6684ad7e9b0SAdrian Chadd
669664a7497SLandon J. Fuller /* Allocate our EROM parser */
67089294a78SLandon J. Fuller eio = bhnd_erom_iores_new(bus, BCMA_EROM_RID);
67189294a78SLandon J. Fuller erom = bhnd_erom_alloc(&bcma_erom_parser, cid, eio);
67289294a78SLandon J. Fuller if (erom == NULL) {
67389294a78SLandon J. Fuller bhnd_erom_io_fini(eio);
674664a7497SLandon J. Fuller return (ENODEV);
67589294a78SLandon J. Fuller }
6764ad7e9b0SAdrian Chadd
6774ad7e9b0SAdrian Chadd /* Add all cores. */
678664a7497SLandon J. Fuller bcma_erom = (struct bcma_erom *)erom;
679664a7497SLandon J. Fuller while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
6804ad7e9b0SAdrian Chadd /* Add the child device */
681688fc8c0SLandon J. Fuller child = BUS_ADD_CHILD(bus, 0, NULL, -1);
6824ad7e9b0SAdrian Chadd if (child == NULL) {
6834ad7e9b0SAdrian Chadd error = ENXIO;
684111d7cb2SLandon J. Fuller goto cleanup;
6854ad7e9b0SAdrian Chadd }
6864ad7e9b0SAdrian Chadd
687688fc8c0SLandon J. Fuller /* Initialize device ivars */
688688fc8c0SLandon J. Fuller dinfo = device_get_ivars(child);
689caeff9a3SLandon J. Fuller if ((error = bcma_init_dinfo(bus, child, dinfo, corecfg)))
690111d7cb2SLandon J. Fuller goto cleanup;
691688fc8c0SLandon J. Fuller
692688fc8c0SLandon J. Fuller /* The dinfo instance now owns the corecfg value */
693688fc8c0SLandon J. Fuller corecfg = NULL;
6944ad7e9b0SAdrian Chadd
6954ad7e9b0SAdrian Chadd /* If pins are floating or the hardware is otherwise
6964ad7e9b0SAdrian Chadd * unpopulated, the device shouldn't be used. */
6974ad7e9b0SAdrian Chadd if (bhnd_is_hw_disabled(child))
6984ad7e9b0SAdrian Chadd device_disable(child);
699f90f4b65SLandon J. Fuller
700f90f4b65SLandon J. Fuller /* Issue bus callback for fully initialized child. */
701f90f4b65SLandon J. Fuller BHND_BUS_CHILD_ADDED(bus, child);
7024ad7e9b0SAdrian Chadd }
7034ad7e9b0SAdrian Chadd
704111d7cb2SLandon J. Fuller /* EOF while parsing cores is expected */
7054ad7e9b0SAdrian Chadd if (error == ENOENT)
706664a7497SLandon J. Fuller error = 0;
7074ad7e9b0SAdrian Chadd
708111d7cb2SLandon J. Fuller cleanup:
709664a7497SLandon J. Fuller bhnd_erom_free(erom);
710664a7497SLandon J. Fuller
7114ad7e9b0SAdrian Chadd if (corecfg != NULL)
7124ad7e9b0SAdrian Chadd bcma_free_corecfg(corecfg);
7134ad7e9b0SAdrian Chadd
714111d7cb2SLandon J. Fuller if (error)
715111d7cb2SLandon J. Fuller device_delete_children(bus);
716111d7cb2SLandon J. Fuller
7174ad7e9b0SAdrian Chadd return (error);
7184ad7e9b0SAdrian Chadd }
7194ad7e9b0SAdrian Chadd
7204ad7e9b0SAdrian Chadd static device_method_t bcma_methods[] = {
7214ad7e9b0SAdrian Chadd /* Device interface */
7224ad7e9b0SAdrian Chadd DEVMETHOD(device_probe, bcma_probe),
7234ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bcma_attach),
7244ad7e9b0SAdrian Chadd DEVMETHOD(device_detach, bcma_detach),
7254ad7e9b0SAdrian Chadd
7264ad7e9b0SAdrian Chadd /* Bus interface */
7278a03f98aSLandon J. Fuller DEVMETHOD(bus_add_child, bcma_add_child),
7288a03f98aSLandon J. Fuller DEVMETHOD(bus_child_deleted, bcma_child_deleted),
7294ad7e9b0SAdrian Chadd DEVMETHOD(bus_read_ivar, bcma_read_ivar),
7304ad7e9b0SAdrian Chadd DEVMETHOD(bus_write_ivar, bcma_write_ivar),
7314ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_resource_list, bcma_get_resource_list),
7324ad7e9b0SAdrian Chadd
7334ad7e9b0SAdrian Chadd /* BHND interface */
734111d7cb2SLandon J. Fuller DEVMETHOD(bhnd_bus_get_erom_class, bcma_get_erom_class),
7358a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_read_ioctl, bcma_read_ioctl),
7368a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_write_ioctl, bcma_write_ioctl),
7378a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_read_iost, bcma_read_iost),
7388a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_is_hw_suspended, bcma_is_hw_suspended),
7398a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_reset_hw, bcma_reset_hw),
7408a03f98aSLandon J. Fuller DEVMETHOD(bhnd_bus_suspend_hw, bcma_suspend_hw),
741f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_read_config, bcma_read_config),
742f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_write_config, bcma_write_config),
7434ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count),
7444ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count),
7454ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid),
7464ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid),
7474ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr),
748824b48efSLandon J. Fuller DEVMETHOD(bhnd_bus_get_intr_count, bcma_get_intr_count),
749caeff9a3SLandon J. Fuller DEVMETHOD(bhnd_bus_get_intr_ivec, bcma_get_intr_ivec),
7504ad7e9b0SAdrian Chadd
7514ad7e9b0SAdrian Chadd DEVMETHOD_END
7524ad7e9b0SAdrian Chadd };
7534ad7e9b0SAdrian Chadd
7544ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver);
7554ad7e9b0SAdrian Chadd MODULE_VERSION(bcma, 1);
7564ad7e9b0SAdrian Chadd MODULE_DEPEND(bcma, bhnd, 1, 1, 1);
757