14ad7e9b0SAdrian Chadd /*- 2f90f4b65SLandon J. Fuller * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> 38e35bf83SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation 44ad7e9b0SAdrian Chadd * All rights reserved. 54ad7e9b0SAdrian Chadd * 68e35bf83SLandon J. Fuller * Portions of this software were developed by Landon Fuller 78e35bf83SLandon J. Fuller * under sponsorship from the FreeBSD Foundation. 88e35bf83SLandon J. Fuller * 94ad7e9b0SAdrian Chadd * Redistribution and use in source and binary forms, with or without 104ad7e9b0SAdrian Chadd * modification, are permitted provided that the following conditions 114ad7e9b0SAdrian Chadd * are met: 124ad7e9b0SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 134ad7e9b0SAdrian Chadd * notice, this list of conditions and the following disclaimer, 144ad7e9b0SAdrian Chadd * without modification. 154ad7e9b0SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 164ad7e9b0SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 174ad7e9b0SAdrian Chadd * redistribution must be conditioned upon including a substantially 184ad7e9b0SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 194ad7e9b0SAdrian Chadd * 204ad7e9b0SAdrian Chadd * NO WARRANTY 214ad7e9b0SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 224ad7e9b0SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 234ad7e9b0SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 244ad7e9b0SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 254ad7e9b0SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 264ad7e9b0SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 274ad7e9b0SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 284ad7e9b0SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 294ad7e9b0SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 304ad7e9b0SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 314ad7e9b0SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 324ad7e9b0SAdrian Chadd */ 334ad7e9b0SAdrian Chadd 344ad7e9b0SAdrian Chadd #include <sys/cdefs.h> 354ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$"); 364ad7e9b0SAdrian Chadd 374ad7e9b0SAdrian Chadd /* 384ad7e9b0SAdrian Chadd * Broadcom Home Networking Division (HND) Bus Driver. 394ad7e9b0SAdrian Chadd * 404ad7e9b0SAdrian Chadd * The Broadcom HND family of devices consists of both SoCs and host-connected 414ad7e9b0SAdrian Chadd * networking chipsets containing a common family of Broadcom IP cores, 424ad7e9b0SAdrian Chadd * including an integrated MIPS and/or ARM cores. 434ad7e9b0SAdrian Chadd * 444ad7e9b0SAdrian Chadd * HND devices expose a nearly identical interface whether accessible over a 454ad7e9b0SAdrian Chadd * native SoC interconnect, or when connected via a host interface such as 464ad7e9b0SAdrian Chadd * PCIe. As a result, the majority of hardware support code should be re-usable 474ad7e9b0SAdrian Chadd * across host drivers for HND networking chipsets, as well as FreeBSD support 484ad7e9b0SAdrian Chadd * for Broadcom MIPS/ARM HND SoCs. 494ad7e9b0SAdrian Chadd * 504ad7e9b0SAdrian Chadd * Earlier HND models used the siba(4) on-chip interconnect, while later models 514ad7e9b0SAdrian Chadd * use bcma(4); the programming model is almost entirely independent 524ad7e9b0SAdrian Chadd * of the actual underlying interconect. 534ad7e9b0SAdrian Chadd */ 544ad7e9b0SAdrian Chadd 554ad7e9b0SAdrian Chadd #include <sys/param.h> 564ad7e9b0SAdrian Chadd #include <sys/kernel.h> 574ad7e9b0SAdrian Chadd #include <sys/bus.h> 584ad7e9b0SAdrian Chadd #include <sys/module.h> 594ad7e9b0SAdrian Chadd #include <sys/systm.h> 604ad7e9b0SAdrian Chadd 614ad7e9b0SAdrian Chadd #include <machine/bus.h> 624ad7e9b0SAdrian Chadd #include <sys/rman.h> 634ad7e9b0SAdrian Chadd #include <machine/resource.h> 644ad7e9b0SAdrian Chadd 65f90f4b65SLandon J. Fuller #include <dev/bhnd/cores/pmu/bhnd_pmu.h> 66f90f4b65SLandon J. Fuller 67fdedcd9fSLandon J. Fuller #include "bhnd_chipc_if.h" 68fdedcd9fSLandon J. Fuller #include "bhnd_nvram_if.h" 69fdedcd9fSLandon J. Fuller 704ad7e9b0SAdrian Chadd #include "bhnd.h" 71*4e96bf3aSLandon J. Fuller #include "bhndreg.h" 724ad7e9b0SAdrian Chadd #include "bhndvar.h" 734ad7e9b0SAdrian Chadd 748e35bf83SLandon J. Fuller #include "bhnd_private.h" 754ad7e9b0SAdrian Chadd 768e35bf83SLandon J. Fuller MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures"); 77fdedcd9fSLandon J. Fuller 784ad7e9b0SAdrian Chadd /** 794ad7e9b0SAdrian Chadd * bhnd_generic_probe_nomatch() reporting configuration. 804ad7e9b0SAdrian Chadd */ 814ad7e9b0SAdrian Chadd static const struct bhnd_nomatch { 824ad7e9b0SAdrian Chadd uint16_t vendor; /**< core designer */ 834ad7e9b0SAdrian Chadd uint16_t device; /**< core id */ 844ad7e9b0SAdrian Chadd bool if_verbose; /**< print when bootverbose is set. */ 854ad7e9b0SAdrian Chadd } bhnd_nomatch_table[] = { 864ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true }, 874ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_EROM, true }, 884ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_PL301, true }, 894ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true }, 904ad7e9b0SAdrian Chadd { BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false }, 914ad7e9b0SAdrian Chadd 924ad7e9b0SAdrian Chadd { BHND_MFGID_INVALID, BHND_COREID_INVALID, false } 934ad7e9b0SAdrian Chadd }; 944ad7e9b0SAdrian Chadd 95fdedcd9fSLandon J. Fuller static int bhnd_delete_children(struct bhnd_softc *sc); 96fdedcd9fSLandon J. Fuller 974ad7e9b0SAdrian Chadd /** 98386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of DEVICE_ATTACH(). 994ad7e9b0SAdrian Chadd * 100386fb140SAdrian Chadd * This implementation calls device_probe_and_attach() for each of the device's 101386fb140SAdrian Chadd * children, in bhnd probe order. 1024ad7e9b0SAdrian Chadd */ 1034ad7e9b0SAdrian Chadd int 1044ad7e9b0SAdrian Chadd bhnd_generic_attach(device_t dev) 1054ad7e9b0SAdrian Chadd { 106fdedcd9fSLandon J. Fuller struct bhnd_softc *sc; 1074ad7e9b0SAdrian Chadd int error; 1084ad7e9b0SAdrian Chadd 1094ad7e9b0SAdrian Chadd if (device_is_attached(dev)) 1104ad7e9b0SAdrian Chadd return (EBUSY); 1114ad7e9b0SAdrian Chadd 112fdedcd9fSLandon J. Fuller sc = device_get_softc(dev); 113fdedcd9fSLandon J. Fuller sc->dev = dev; 114fdedcd9fSLandon J. Fuller 115fdedcd9fSLandon J. Fuller /* Probe and attach all children */ 1168e35bf83SLandon J. Fuller if ((error = bhnd_bus_probe_children(dev))) { 117fdedcd9fSLandon J. Fuller bhnd_delete_children(sc); 118fdedcd9fSLandon J. Fuller return (error); 119fdedcd9fSLandon J. Fuller } 120fdedcd9fSLandon J. Fuller 1218e35bf83SLandon J. Fuller return (0); 1228e35bf83SLandon J. Fuller } 1238e35bf83SLandon J. Fuller 124fdedcd9fSLandon J. Fuller /** 125fdedcd9fSLandon J. Fuller * Detach and delete all children, in reverse of their attach order. 126fdedcd9fSLandon J. Fuller */ 127fdedcd9fSLandon J. Fuller static int 128fdedcd9fSLandon J. Fuller bhnd_delete_children(struct bhnd_softc *sc) 129fdedcd9fSLandon J. Fuller { 130fdedcd9fSLandon J. Fuller device_t *devs; 131fdedcd9fSLandon J. Fuller int ndevs; 132fdedcd9fSLandon J. Fuller int error; 133fdedcd9fSLandon J. Fuller 1348e35bf83SLandon J. Fuller /* Fetch children in detach order */ 1358e35bf83SLandon J. Fuller error = bhnd_bus_get_children(sc->dev, &devs, &ndevs, 1368e35bf83SLandon J. Fuller BHND_DEVICE_ORDER_DETACH); 1378e35bf83SLandon J. Fuller if (error) 138fdedcd9fSLandon J. Fuller return (error); 139fdedcd9fSLandon J. Fuller 1408e35bf83SLandon J. Fuller /* Perform detach */ 141fdedcd9fSLandon J. Fuller for (int i = 0; i < ndevs; i++) { 142fdedcd9fSLandon J. Fuller device_t child = devs[i]; 143fdedcd9fSLandon J. Fuller 144fdedcd9fSLandon J. Fuller /* Terminate on first error */ 145fdedcd9fSLandon J. Fuller if ((error = device_delete_child(sc->dev, child))) 146fdedcd9fSLandon J. Fuller goto cleanup; 147fdedcd9fSLandon J. Fuller } 148fdedcd9fSLandon J. Fuller 149fdedcd9fSLandon J. Fuller cleanup: 1508e35bf83SLandon J. Fuller bhnd_bus_free_children(devs); 151fdedcd9fSLandon J. Fuller return (error); 1524ad7e9b0SAdrian Chadd } 1534ad7e9b0SAdrian Chadd 1544ad7e9b0SAdrian Chadd /** 155386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of DEVICE_DETACH(). 1564ad7e9b0SAdrian Chadd * 157cef367e6SEitan Adler * This implementation calls device_detach() for each of the device's 158386fb140SAdrian Chadd * children, in reverse bhnd probe order, terminating if any call to 159386fb140SAdrian Chadd * device_detach() fails. 1604ad7e9b0SAdrian Chadd */ 1614ad7e9b0SAdrian Chadd int 1624ad7e9b0SAdrian Chadd bhnd_generic_detach(device_t dev) 1634ad7e9b0SAdrian Chadd { 164fdedcd9fSLandon J. Fuller struct bhnd_softc *sc; 1658e35bf83SLandon J. Fuller int error; 1664ad7e9b0SAdrian Chadd 1674ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 1684ad7e9b0SAdrian Chadd return (EBUSY); 1694ad7e9b0SAdrian Chadd 170fdedcd9fSLandon J. Fuller sc = device_get_softc(dev); 1718e35bf83SLandon J. Fuller 1728e35bf83SLandon J. Fuller if ((error = bhnd_delete_children(sc))) 1738e35bf83SLandon J. Fuller return (error); 1748e35bf83SLandon J. Fuller 1758e35bf83SLandon J. Fuller return (0); 1764ad7e9b0SAdrian Chadd } 1774ad7e9b0SAdrian Chadd 1784ad7e9b0SAdrian Chadd /** 179386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN(). 1804ad7e9b0SAdrian Chadd * 181386fb140SAdrian Chadd * This implementation calls device_shutdown() for each of the device's 182386fb140SAdrian Chadd * children, in reverse bhnd probe order, terminating if any call to 183386fb140SAdrian Chadd * device_shutdown() fails. 1844ad7e9b0SAdrian Chadd */ 1854ad7e9b0SAdrian Chadd int 1864ad7e9b0SAdrian Chadd bhnd_generic_shutdown(device_t dev) 1874ad7e9b0SAdrian Chadd { 1884ad7e9b0SAdrian Chadd device_t *devs; 1894ad7e9b0SAdrian Chadd int ndevs; 1904ad7e9b0SAdrian Chadd int error; 1914ad7e9b0SAdrian Chadd 1924ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 1934ad7e9b0SAdrian Chadd return (EBUSY); 1944ad7e9b0SAdrian Chadd 1958e35bf83SLandon J. Fuller /* Fetch children in detach order */ 1968e35bf83SLandon J. Fuller error = bhnd_bus_get_children(dev, &devs, &ndevs, 1978e35bf83SLandon J. Fuller BHND_DEVICE_ORDER_DETACH); 1988e35bf83SLandon J. Fuller if (error) 1994ad7e9b0SAdrian Chadd return (error); 2004ad7e9b0SAdrian Chadd 2018e35bf83SLandon J. Fuller /* Perform shutdown */ 2024ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 2034ad7e9b0SAdrian Chadd device_t child = devs[i]; 2044ad7e9b0SAdrian Chadd 2054ad7e9b0SAdrian Chadd /* Terminate on first error */ 2064ad7e9b0SAdrian Chadd if ((error = device_shutdown(child))) 2074ad7e9b0SAdrian Chadd goto cleanup; 2084ad7e9b0SAdrian Chadd } 2094ad7e9b0SAdrian Chadd 2104ad7e9b0SAdrian Chadd cleanup: 2118e35bf83SLandon J. Fuller bhnd_bus_free_children(devs); 2124ad7e9b0SAdrian Chadd return (error); 2134ad7e9b0SAdrian Chadd } 2144ad7e9b0SAdrian Chadd 2154ad7e9b0SAdrian Chadd /** 216386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of DEVICE_RESUME(). 2174ad7e9b0SAdrian Chadd * 218386fb140SAdrian Chadd * This implementation calls BUS_RESUME_CHILD() for each of the device's 219386fb140SAdrian Chadd * children in bhnd probe order, terminating if any call to BUS_RESUME_CHILD() 220386fb140SAdrian Chadd * fails. 2214ad7e9b0SAdrian Chadd */ 2224ad7e9b0SAdrian Chadd int 2234ad7e9b0SAdrian Chadd bhnd_generic_resume(device_t dev) 2244ad7e9b0SAdrian Chadd { 2254ad7e9b0SAdrian Chadd device_t *devs; 2264ad7e9b0SAdrian Chadd int ndevs; 2274ad7e9b0SAdrian Chadd int error; 2284ad7e9b0SAdrian Chadd 2294ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 2304ad7e9b0SAdrian Chadd return (EBUSY); 2314ad7e9b0SAdrian Chadd 2328e35bf83SLandon J. Fuller /* Fetch children in attach order */ 2338e35bf83SLandon J. Fuller error = bhnd_bus_get_children(dev, &devs, &ndevs, 2348e35bf83SLandon J. Fuller BHND_DEVICE_ORDER_ATTACH); 2358e35bf83SLandon J. Fuller if (error) 2364ad7e9b0SAdrian Chadd return (error); 2374ad7e9b0SAdrian Chadd 2388e35bf83SLandon J. Fuller /* Perform resume */ 2394ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 2404ad7e9b0SAdrian Chadd device_t child = devs[i]; 2414ad7e9b0SAdrian Chadd 2424ad7e9b0SAdrian Chadd /* Terminate on first error */ 2434ad7e9b0SAdrian Chadd if ((error = BUS_RESUME_CHILD(device_get_parent(child), child))) 2444ad7e9b0SAdrian Chadd goto cleanup; 2454ad7e9b0SAdrian Chadd } 2464ad7e9b0SAdrian Chadd 2474ad7e9b0SAdrian Chadd cleanup: 2488e35bf83SLandon J. Fuller bhnd_bus_free_children(devs); 2494ad7e9b0SAdrian Chadd return (error); 2504ad7e9b0SAdrian Chadd } 2514ad7e9b0SAdrian Chadd 2524ad7e9b0SAdrian Chadd /** 253386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of DEVICE_SUSPEND(). 2544ad7e9b0SAdrian Chadd * 255386fb140SAdrian Chadd * This implementation calls BUS_SUSPEND_CHILD() for each of the device's 256386fb140SAdrian Chadd * children in reverse bhnd probe order. If any call to BUS_SUSPEND_CHILD() 257386fb140SAdrian Chadd * fails, the suspend operation is terminated and any devices that were 258386fb140SAdrian Chadd * suspended are resumed immediately by calling their BUS_RESUME_CHILD() 259386fb140SAdrian Chadd * methods. 2604ad7e9b0SAdrian Chadd */ 2614ad7e9b0SAdrian Chadd int 2624ad7e9b0SAdrian Chadd bhnd_generic_suspend(device_t dev) 2634ad7e9b0SAdrian Chadd { 2644ad7e9b0SAdrian Chadd device_t *devs; 2654ad7e9b0SAdrian Chadd int ndevs; 2664ad7e9b0SAdrian Chadd int error; 2674ad7e9b0SAdrian Chadd 2684ad7e9b0SAdrian Chadd if (!device_is_attached(dev)) 2694ad7e9b0SAdrian Chadd return (EBUSY); 2704ad7e9b0SAdrian Chadd 2718e35bf83SLandon J. Fuller /* Fetch children in detach order */ 2728e35bf83SLandon J. Fuller error = bhnd_bus_get_children(dev, &devs, &ndevs, 2738e35bf83SLandon J. Fuller BHND_DEVICE_ORDER_DETACH); 2748e35bf83SLandon J. Fuller if (error) 2754ad7e9b0SAdrian Chadd return (error); 2764ad7e9b0SAdrian Chadd 2778e35bf83SLandon J. Fuller /* Perform suspend */ 2784ad7e9b0SAdrian Chadd for (int i = 0; i < ndevs; i++) { 2794ad7e9b0SAdrian Chadd device_t child = devs[i]; 2804ad7e9b0SAdrian Chadd error = BUS_SUSPEND_CHILD(device_get_parent(child), child); 2814ad7e9b0SAdrian Chadd 2824ad7e9b0SAdrian Chadd /* On error, resume suspended devices and then terminate */ 2834ad7e9b0SAdrian Chadd if (error) { 2844ad7e9b0SAdrian Chadd for (int j = 0; j < i; j++) { 2854ad7e9b0SAdrian Chadd BUS_RESUME_CHILD(device_get_parent(devs[j]), 2864ad7e9b0SAdrian Chadd devs[j]); 2874ad7e9b0SAdrian Chadd } 2884ad7e9b0SAdrian Chadd 2894ad7e9b0SAdrian Chadd goto cleanup; 2904ad7e9b0SAdrian Chadd } 2914ad7e9b0SAdrian Chadd } 2924ad7e9b0SAdrian Chadd 2934ad7e9b0SAdrian Chadd cleanup: 2948e35bf83SLandon J. Fuller bhnd_bus_free_children(devs); 2954ad7e9b0SAdrian Chadd return (error); 2964ad7e9b0SAdrian Chadd } 2974ad7e9b0SAdrian Chadd 2984ad7e9b0SAdrian Chadd /** 299386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of BHND_BUS_GET_PROBE_ORDER(). 3004ad7e9b0SAdrian Chadd * 3014ad7e9b0SAdrian Chadd * This implementation determines probe ordering based on the device's class 3024ad7e9b0SAdrian Chadd * and other properties, including whether the device is serving as a host 3034ad7e9b0SAdrian Chadd * bridge. 3044ad7e9b0SAdrian Chadd */ 3054ad7e9b0SAdrian Chadd int 3064ad7e9b0SAdrian Chadd bhnd_generic_get_probe_order(device_t dev, device_t child) 3074ad7e9b0SAdrian Chadd { 3084ad7e9b0SAdrian Chadd switch (bhnd_get_class(child)) { 3094ad7e9b0SAdrian Chadd case BHND_DEVCLASS_CC: 310d567592bSAdrian Chadd /* Must be early enough to provide NVRAM access to the 311d567592bSAdrian Chadd * host bridge */ 312d567592bSAdrian Chadd return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_FIRST); 3134ad7e9b0SAdrian Chadd 3144ad7e9b0SAdrian Chadd case BHND_DEVCLASS_CC_B: 3154ad7e9b0SAdrian Chadd /* fall through */ 3164ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PMU: 3174ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY); 3184ad7e9b0SAdrian Chadd 3194ad7e9b0SAdrian Chadd case BHND_DEVCLASS_SOC_ROUTER: 3204ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE); 3214ad7e9b0SAdrian Chadd 3224ad7e9b0SAdrian Chadd case BHND_DEVCLASS_SOC_BRIDGE: 3234ad7e9b0SAdrian Chadd return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST); 3244ad7e9b0SAdrian Chadd 3254ad7e9b0SAdrian Chadd case BHND_DEVCLASS_CPU: 3264ad7e9b0SAdrian Chadd return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST); 3274ad7e9b0SAdrian Chadd 3284ad7e9b0SAdrian Chadd case BHND_DEVCLASS_RAM: 3294ad7e9b0SAdrian Chadd /* fall through */ 3304ad7e9b0SAdrian Chadd case BHND_DEVCLASS_MEMC: 3314ad7e9b0SAdrian Chadd return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY); 3324ad7e9b0SAdrian Chadd 3334ad7e9b0SAdrian Chadd case BHND_DEVCLASS_NVRAM: 3344ad7e9b0SAdrian Chadd return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY); 3354ad7e9b0SAdrian Chadd 3364ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PCI: 3374ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PCIE: 3384ad7e9b0SAdrian Chadd case BHND_DEVCLASS_PCCARD: 3394ad7e9b0SAdrian Chadd case BHND_DEVCLASS_ENET: 3404ad7e9b0SAdrian Chadd case BHND_DEVCLASS_ENET_MAC: 3414ad7e9b0SAdrian Chadd case BHND_DEVCLASS_ENET_PHY: 3424ad7e9b0SAdrian Chadd case BHND_DEVCLASS_WLAN: 3434ad7e9b0SAdrian Chadd case BHND_DEVCLASS_WLAN_MAC: 3444ad7e9b0SAdrian Chadd case BHND_DEVCLASS_WLAN_PHY: 3454ad7e9b0SAdrian Chadd case BHND_DEVCLASS_EROM: 3464ad7e9b0SAdrian Chadd case BHND_DEVCLASS_OTHER: 3474ad7e9b0SAdrian Chadd case BHND_DEVCLASS_INVALID: 3488e35bf83SLandon J. Fuller if (bhnd_bus_find_hostb_device(dev) == child) 3494ad7e9b0SAdrian Chadd return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY); 3504ad7e9b0SAdrian Chadd 3514ad7e9b0SAdrian Chadd return (BHND_PROBE_DEFAULT); 352054ae231SAdrian Chadd default: 353054ae231SAdrian Chadd return (BHND_PROBE_DEFAULT); 3544ad7e9b0SAdrian Chadd } 3554ad7e9b0SAdrian Chadd } 3564ad7e9b0SAdrian Chadd 3574ad7e9b0SAdrian Chadd /** 358f90f4b65SLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_ALLOC_PMU(). 359f90f4b65SLandon J. Fuller */ 360f90f4b65SLandon J. Fuller int 361f90f4b65SLandon J. Fuller bhnd_generic_alloc_pmu(device_t dev, device_t child) 362f90f4b65SLandon J. Fuller { 363f90f4b65SLandon J. Fuller struct bhnd_softc *sc; 364*4e96bf3aSLandon J. Fuller struct bhnd_resource *r; 365*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 366f90f4b65SLandon J. Fuller struct resource_list *rl; 367f90f4b65SLandon J. Fuller struct resource_list_entry *rle; 368f90f4b65SLandon J. Fuller device_t pmu_dev; 369f90f4b65SLandon J. Fuller bhnd_addr_t r_addr; 370f90f4b65SLandon J. Fuller bhnd_size_t r_size; 371f90f4b65SLandon J. Fuller bus_size_t pmu_regs; 372*4e96bf3aSLandon J. Fuller u_int max_latency; 373f90f4b65SLandon J. Fuller int error; 374f90f4b65SLandon J. Fuller 375f90f4b65SLandon J. Fuller GIANT_REQUIRED; /* for newbus */ 376f90f4b65SLandon J. Fuller 377*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 378*4e96bf3aSLandon J. Fuller return (EINVAL); 379*4e96bf3aSLandon J. Fuller 380f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 381*4e96bf3aSLandon J. Fuller clkctl = bhnd_get_pmu_info(child); 382f90f4b65SLandon J. Fuller pmu_regs = BHND_CLK_CTL_ST; 383f90f4b65SLandon J. Fuller 384f90f4b65SLandon J. Fuller /* already allocated? */ 385*4e96bf3aSLandon J. Fuller if (clkctl != NULL) { 386f90f4b65SLandon J. Fuller panic("duplicate PMU allocation for %s", 387f90f4b65SLandon J. Fuller device_get_nameunit(child)); 388f90f4b65SLandon J. Fuller } 389f90f4b65SLandon J. Fuller 390f90f4b65SLandon J. Fuller /* Determine address+size of the core's PMU register block */ 391f90f4b65SLandon J. Fuller error = bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &r_addr, 392f90f4b65SLandon J. Fuller &r_size); 393f90f4b65SLandon J. Fuller if (error) { 394f90f4b65SLandon J. Fuller device_printf(sc->dev, "error fetching register block info for " 395f90f4b65SLandon J. Fuller "%s: %d\n", device_get_nameunit(child), error); 396f90f4b65SLandon J. Fuller return (error); 397f90f4b65SLandon J. Fuller } 398f90f4b65SLandon J. Fuller 399f90f4b65SLandon J. Fuller if (r_size < (pmu_regs + sizeof(uint32_t))) { 400f90f4b65SLandon J. Fuller device_printf(sc->dev, "pmu offset %#jx would overrun %s " 401f90f4b65SLandon J. Fuller "register block\n", (uintmax_t)pmu_regs, 402f90f4b65SLandon J. Fuller device_get_nameunit(child)); 403f90f4b65SLandon J. Fuller return (ENODEV); 404f90f4b65SLandon J. Fuller } 405f90f4b65SLandon J. Fuller 406f90f4b65SLandon J. Fuller /* Locate actual resource containing the core's register block */ 407f90f4b65SLandon J. Fuller if ((rl = BUS_GET_RESOURCE_LIST(dev, child)) == NULL) { 408f90f4b65SLandon J. Fuller device_printf(dev, "NULL resource list returned for %s\n", 409f90f4b65SLandon J. Fuller device_get_nameunit(child)); 410f90f4b65SLandon J. Fuller return (ENXIO); 411f90f4b65SLandon J. Fuller } 412f90f4b65SLandon J. Fuller 413f90f4b65SLandon J. Fuller if ((rle = resource_list_find(rl, SYS_RES_MEMORY, 0)) == NULL) { 414f90f4b65SLandon J. Fuller device_printf(dev, "cannot locate core register resource " 415f90f4b65SLandon J. Fuller "for %s\n", device_get_nameunit(child)); 416f90f4b65SLandon J. Fuller return (ENXIO); 417f90f4b65SLandon J. Fuller } 418f90f4b65SLandon J. Fuller 419f90f4b65SLandon J. Fuller if (rle->res == NULL) { 420f90f4b65SLandon J. Fuller device_printf(dev, "core register resource unallocated for " 421f90f4b65SLandon J. Fuller "%s\n", device_get_nameunit(child)); 422f90f4b65SLandon J. Fuller return (ENXIO); 423f90f4b65SLandon J. Fuller } 424f90f4b65SLandon J. Fuller 425f90f4b65SLandon J. Fuller if (r_addr+pmu_regs < rman_get_start(rle->res) || 426f90f4b65SLandon J. Fuller r_addr+pmu_regs >= rman_get_end(rle->res)) 427f90f4b65SLandon J. Fuller { 428f90f4b65SLandon J. Fuller device_printf(dev, "core register resource does not map PMU " 429f90f4b65SLandon J. Fuller "registers at %#jx\n for %s\n", r_addr+pmu_regs, 430f90f4b65SLandon J. Fuller device_get_nameunit(child)); 431f90f4b65SLandon J. Fuller return (ENXIO); 432f90f4b65SLandon J. Fuller } 433f90f4b65SLandon J. Fuller 434f90f4b65SLandon J. Fuller /* Adjust PMU register offset relative to the actual start address 435f90f4b65SLandon J. Fuller * of the core's register block allocation. 436f90f4b65SLandon J. Fuller * 437f90f4b65SLandon J. Fuller * XXX: The saved offset will be invalid if bus_adjust_resource is 438f90f4b65SLandon J. Fuller * used to modify the resource's start address. 439f90f4b65SLandon J. Fuller */ 440f90f4b65SLandon J. Fuller if (rman_get_start(rle->res) > r_addr) 441f90f4b65SLandon J. Fuller pmu_regs -= rman_get_start(rle->res) - r_addr; 442f90f4b65SLandon J. Fuller else 443f90f4b65SLandon J. Fuller pmu_regs -= r_addr - rman_get_start(rle->res); 444f90f4b65SLandon J. Fuller 445*4e96bf3aSLandon J. Fuller /* Retain a PMU reference for the clkctl instance state */ 4468e35bf83SLandon J. Fuller pmu_dev = bhnd_retain_provider(child, BHND_SERVICE_PMU); 4478e35bf83SLandon J. Fuller if (pmu_dev == NULL) { 448*4e96bf3aSLandon J. Fuller device_printf(sc->dev, "PMU not found\n"); 4498e35bf83SLandon J. Fuller return (ENXIO); 4508e35bf83SLandon J. Fuller } 4518e35bf83SLandon J. Fuller 452*4e96bf3aSLandon J. Fuller /* Fetch the maximum transition latency from our PMU */ 453*4e96bf3aSLandon J. Fuller max_latency = bhnd_pmu_get_max_transition_latency(pmu_dev); 454*4e96bf3aSLandon J. Fuller 455*4e96bf3aSLandon J. Fuller /* Allocate a new bhnd_resource wrapping the standard resource we 456*4e96bf3aSLandon J. Fuller * fetched from the resource list; we'll free this in 457*4e96bf3aSLandon J. Fuller * bhnd_generic_release_pmu() */ 458*4e96bf3aSLandon J. Fuller r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); 459*4e96bf3aSLandon J. Fuller if (r == NULL) { 4608e35bf83SLandon J. Fuller bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU); 461f90f4b65SLandon J. Fuller return (ENOMEM); 4628e35bf83SLandon J. Fuller } 463f90f4b65SLandon J. Fuller 464*4e96bf3aSLandon J. Fuller r->res = rle->res; 465*4e96bf3aSLandon J. Fuller r->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0); 466f90f4b65SLandon J. Fuller 467*4e96bf3aSLandon J. Fuller /* Allocate the clkctl instance */ 468*4e96bf3aSLandon J. Fuller clkctl = bhnd_alloc_core_clkctl(child, pmu_dev, r, pmu_regs, 469*4e96bf3aSLandon J. Fuller max_latency); 470*4e96bf3aSLandon J. Fuller if (clkctl == NULL) { 471*4e96bf3aSLandon J. Fuller free(r, M_BHND); 4728e35bf83SLandon J. Fuller bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU); 473f90f4b65SLandon J. Fuller return (ENOMEM); 474f90f4b65SLandon J. Fuller } 475f90f4b65SLandon J. Fuller 476*4e96bf3aSLandon J. Fuller bhnd_set_pmu_info(child, clkctl); 477f90f4b65SLandon J. Fuller return (0); 478f90f4b65SLandon J. Fuller } 479f90f4b65SLandon J. Fuller 480f90f4b65SLandon J. Fuller /** 481f90f4b65SLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_PMU(). 482f90f4b65SLandon J. Fuller */ 483f90f4b65SLandon J. Fuller int 484f90f4b65SLandon J. Fuller bhnd_generic_release_pmu(device_t dev, device_t child) 485f90f4b65SLandon J. Fuller { 486f90f4b65SLandon J. Fuller struct bhnd_softc *sc; 487*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 488*4e96bf3aSLandon J. Fuller struct bhnd_resource *r; 489*4e96bf3aSLandon J. Fuller device_t pmu_dev; 490f90f4b65SLandon J. Fuller 491f90f4b65SLandon J. Fuller GIANT_REQUIRED; /* for newbus */ 492f90f4b65SLandon J. Fuller 493f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 494f90f4b65SLandon J. Fuller 495*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 496*4e96bf3aSLandon J. Fuller return (EINVAL); 497*4e96bf3aSLandon J. Fuller 498*4e96bf3aSLandon J. Fuller clkctl = bhnd_get_pmu_info(child); 499*4e96bf3aSLandon J. Fuller if (clkctl == NULL) 500f90f4b65SLandon J. Fuller panic("pmu over-release for %s", device_get_nameunit(child)); 501f90f4b65SLandon J. Fuller 502*4e96bf3aSLandon J. Fuller /* Clear all FORCE, AREQ, and ERSRC flags, unless we're already in 503*4e96bf3aSLandon J. Fuller * RESET. Suspending a core clears clkctl automatically (and attempting 504*4e96bf3aSLandon J. Fuller * to access the PMU registers in a suspended core will trigger a 505*4e96bf3aSLandon J. Fuller * system livelock). */ 506*4e96bf3aSLandon J. Fuller if (!bhnd_is_hw_suspended(clkctl->cc_dev)) { 507*4e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK(clkctl); 508f90f4b65SLandon J. Fuller 509*4e96bf3aSLandon J. Fuller /* Clear all FORCE, AREQ, and ERSRC flags */ 510*4e96bf3aSLandon J. Fuller BHND_CLKCTL_SET_4(clkctl, 0x0, BHND_CCS_FORCE_MASK | 511*4e96bf3aSLandon J. Fuller BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK); 512*4e96bf3aSLandon J. Fuller 513*4e96bf3aSLandon J. Fuller BHND_CLKCTL_UNLOCK(clkctl); 514*4e96bf3aSLandon J. Fuller } 515*4e96bf3aSLandon J. Fuller 516*4e96bf3aSLandon J. Fuller /* Clear child's PMU info reference */ 5178a03f98aSLandon J. Fuller bhnd_set_pmu_info(child, NULL); 5188e35bf83SLandon J. Fuller 519*4e96bf3aSLandon J. Fuller /* Before freeing the clkctl instance, save a pointer to resources we 520*4e96bf3aSLandon J. Fuller * need to clean up manually */ 521*4e96bf3aSLandon J. Fuller r = clkctl->cc_res; 522*4e96bf3aSLandon J. Fuller pmu_dev = clkctl->cc_pmu_dev; 523*4e96bf3aSLandon J. Fuller 524*4e96bf3aSLandon J. Fuller /* Free the clkctl instance */ 525*4e96bf3aSLandon J. Fuller bhnd_free_core_clkctl(clkctl); 526*4e96bf3aSLandon J. Fuller 527*4e96bf3aSLandon J. Fuller /* Free the child's bhnd resource wrapper */ 528*4e96bf3aSLandon J. Fuller free(r, M_BHND); 529*4e96bf3aSLandon J. Fuller 530*4e96bf3aSLandon J. Fuller /* Release the child's PMU provider reference */ 531*4e96bf3aSLandon J. Fuller bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU); 532f90f4b65SLandon J. Fuller 533f90f4b65SLandon J. Fuller return (0); 534f90f4b65SLandon J. Fuller } 535f90f4b65SLandon J. Fuller 536f90f4b65SLandon J. Fuller /** 537*4e96bf3aSLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_LATENCY(). 538*4e96bf3aSLandon J. Fuller */ 539*4e96bf3aSLandon J. Fuller int 540*4e96bf3aSLandon J. Fuller bhnd_generic_get_clock_latency(device_t dev, device_t child, bhnd_clock clock, 541*4e96bf3aSLandon J. Fuller u_int *latency) 542*4e96bf3aSLandon J. Fuller { 543*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 544*4e96bf3aSLandon J. Fuller 545*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 546*4e96bf3aSLandon J. Fuller return (EINVAL); 547*4e96bf3aSLandon J. Fuller 548*4e96bf3aSLandon J. Fuller if ((clkctl = bhnd_get_pmu_info(child)) == NULL) 549*4e96bf3aSLandon J. Fuller panic("no active PMU allocation"); 550*4e96bf3aSLandon J. Fuller 551*4e96bf3aSLandon J. Fuller return (bhnd_pmu_get_clock_latency(clkctl->cc_pmu_dev, clock, latency)); 552*4e96bf3aSLandon J. Fuller } 553*4e96bf3aSLandon J. Fuller 554*4e96bf3aSLandon J. Fuller /** 555*4e96bf3aSLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_FREQ(). 556*4e96bf3aSLandon J. Fuller */ 557*4e96bf3aSLandon J. Fuller int 558*4e96bf3aSLandon J. Fuller bhnd_generic_get_clock_freq(device_t dev, device_t child, bhnd_clock clock, 559*4e96bf3aSLandon J. Fuller u_int *freq) 560*4e96bf3aSLandon J. Fuller { 561*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 562*4e96bf3aSLandon J. Fuller 563*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 564*4e96bf3aSLandon J. Fuller return (EINVAL); 565*4e96bf3aSLandon J. Fuller 566*4e96bf3aSLandon J. Fuller if ((clkctl = bhnd_get_pmu_info(child)) == NULL) 567*4e96bf3aSLandon J. Fuller panic("no active PMU allocation"); 568*4e96bf3aSLandon J. Fuller 569*4e96bf3aSLandon J. Fuller return (bhnd_pmu_get_clock_freq(clkctl->cc_pmu_dev, clock, freq)); 570*4e96bf3aSLandon J. Fuller } 571*4e96bf3aSLandon J. Fuller 572*4e96bf3aSLandon J. Fuller /** 573f90f4b65SLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK(). 574f90f4b65SLandon J. Fuller */ 575f90f4b65SLandon J. Fuller int 576f90f4b65SLandon J. Fuller bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock) 577f90f4b65SLandon J. Fuller { 578f90f4b65SLandon J. Fuller struct bhnd_softc *sc; 579*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 580*4e96bf3aSLandon J. Fuller uint32_t avail; 581*4e96bf3aSLandon J. Fuller uint32_t req; 582*4e96bf3aSLandon J. Fuller int error; 583f90f4b65SLandon J. Fuller 584f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 585f90f4b65SLandon J. Fuller 586*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 587*4e96bf3aSLandon J. Fuller return (EINVAL); 588f90f4b65SLandon J. Fuller 589*4e96bf3aSLandon J. Fuller if ((clkctl = bhnd_get_pmu_info(child)) == NULL) 590*4e96bf3aSLandon J. Fuller panic("no active PMU allocation"); 591*4e96bf3aSLandon J. Fuller 592*4e96bf3aSLandon J. Fuller BHND_ASSERT_CLKCTL_AVAIL(clkctl); 593*4e96bf3aSLandon J. Fuller 594*4e96bf3aSLandon J. Fuller avail = 0x0; 595*4e96bf3aSLandon J. Fuller req = 0x0; 596*4e96bf3aSLandon J. Fuller 597*4e96bf3aSLandon J. Fuller switch (clock) { 598*4e96bf3aSLandon J. Fuller case BHND_CLOCK_DYN: 599*4e96bf3aSLandon J. Fuller break; 600*4e96bf3aSLandon J. Fuller case BHND_CLOCK_ILP: 601*4e96bf3aSLandon J. Fuller req |= BHND_CCS_FORCEILP; 602*4e96bf3aSLandon J. Fuller break; 603*4e96bf3aSLandon J. Fuller case BHND_CLOCK_ALP: 604*4e96bf3aSLandon J. Fuller req |= BHND_CCS_FORCEALP; 605*4e96bf3aSLandon J. Fuller avail |= BHND_CCS_ALPAVAIL; 606*4e96bf3aSLandon J. Fuller break; 607*4e96bf3aSLandon J. Fuller case BHND_CLOCK_HT: 608*4e96bf3aSLandon J. Fuller req |= BHND_CCS_FORCEHT; 609*4e96bf3aSLandon J. Fuller avail |= BHND_CCS_HTAVAIL; 610*4e96bf3aSLandon J. Fuller break; 611*4e96bf3aSLandon J. Fuller default: 612*4e96bf3aSLandon J. Fuller device_printf(dev, "%s requested unknown clock: %#x\n", 613*4e96bf3aSLandon J. Fuller device_get_nameunit(clkctl->cc_dev), clock); 614*4e96bf3aSLandon J. Fuller return (ENODEV); 615*4e96bf3aSLandon J. Fuller } 616*4e96bf3aSLandon J. Fuller 617*4e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK(clkctl); 618*4e96bf3aSLandon J. Fuller 619*4e96bf3aSLandon J. Fuller /* Issue request */ 620*4e96bf3aSLandon J. Fuller BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_FORCE_MASK); 621*4e96bf3aSLandon J. Fuller 622*4e96bf3aSLandon J. Fuller /* Wait for clock availability */ 623*4e96bf3aSLandon J. Fuller error = bhnd_core_clkctl_wait(clkctl, avail, avail); 624*4e96bf3aSLandon J. Fuller 625*4e96bf3aSLandon J. Fuller BHND_CLKCTL_UNLOCK(clkctl); 626*4e96bf3aSLandon J. Fuller 627*4e96bf3aSLandon J. Fuller return (error); 628f90f4b65SLandon J. Fuller } 629f90f4b65SLandon J. Fuller 630f90f4b65SLandon J. Fuller /** 631f90f4b65SLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS(). 632f90f4b65SLandon J. Fuller */ 633f90f4b65SLandon J. Fuller int 634f90f4b65SLandon J. Fuller bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks) 635f90f4b65SLandon J. Fuller { 636f90f4b65SLandon J. Fuller struct bhnd_softc *sc; 637*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 638*4e96bf3aSLandon J. Fuller uint32_t avail; 639*4e96bf3aSLandon J. Fuller uint32_t req; 640*4e96bf3aSLandon J. Fuller int error; 641f90f4b65SLandon J. Fuller 642f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 643f90f4b65SLandon J. Fuller 644*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 645*4e96bf3aSLandon J. Fuller return (EINVAL); 646f90f4b65SLandon J. Fuller 647*4e96bf3aSLandon J. Fuller if ((clkctl = bhnd_get_pmu_info(child)) == NULL) 648*4e96bf3aSLandon J. Fuller panic("no active PMU allocation"); 649*4e96bf3aSLandon J. Fuller 650*4e96bf3aSLandon J. Fuller BHND_ASSERT_CLKCTL_AVAIL(clkctl); 651*4e96bf3aSLandon J. Fuller 652*4e96bf3aSLandon J. Fuller sc = device_get_softc(dev); 653*4e96bf3aSLandon J. Fuller 654*4e96bf3aSLandon J. Fuller avail = 0x0; 655*4e96bf3aSLandon J. Fuller req = 0x0; 656*4e96bf3aSLandon J. Fuller 657*4e96bf3aSLandon J. Fuller /* Build clock request flags */ 658*4e96bf3aSLandon J. Fuller if (clocks & BHND_CLOCK_DYN) /* nothing to enable */ 659*4e96bf3aSLandon J. Fuller clocks &= ~BHND_CLOCK_DYN; 660*4e96bf3aSLandon J. Fuller 661*4e96bf3aSLandon J. Fuller if (clocks & BHND_CLOCK_ILP) /* nothing to enable */ 662*4e96bf3aSLandon J. Fuller clocks &= ~BHND_CLOCK_ILP; 663*4e96bf3aSLandon J. Fuller 664*4e96bf3aSLandon J. Fuller if (clocks & BHND_CLOCK_ALP) { 665*4e96bf3aSLandon J. Fuller req |= BHND_CCS_ALPAREQ; 666*4e96bf3aSLandon J. Fuller avail |= BHND_CCS_ALPAVAIL; 667*4e96bf3aSLandon J. Fuller clocks &= ~BHND_CLOCK_ALP; 668*4e96bf3aSLandon J. Fuller } 669*4e96bf3aSLandon J. Fuller 670*4e96bf3aSLandon J. Fuller if (clocks & BHND_CLOCK_HT) { 671*4e96bf3aSLandon J. Fuller req |= BHND_CCS_HTAREQ; 672*4e96bf3aSLandon J. Fuller avail |= BHND_CCS_HTAVAIL; 673*4e96bf3aSLandon J. Fuller clocks &= ~BHND_CLOCK_HT; 674*4e96bf3aSLandon J. Fuller } 675*4e96bf3aSLandon J. Fuller 676*4e96bf3aSLandon J. Fuller /* Check for unknown clock values */ 677*4e96bf3aSLandon J. Fuller if (clocks != 0x0) { 678*4e96bf3aSLandon J. Fuller device_printf(dev, "%s requested unknown clocks: %#x\n", 679*4e96bf3aSLandon J. Fuller device_get_nameunit(clkctl->cc_dev), clocks); 680*4e96bf3aSLandon J. Fuller return (ENODEV); 681*4e96bf3aSLandon J. Fuller } 682*4e96bf3aSLandon J. Fuller 683*4e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK(clkctl); 684*4e96bf3aSLandon J. Fuller 685*4e96bf3aSLandon J. Fuller /* Issue request */ 686*4e96bf3aSLandon J. Fuller BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_AREQ_MASK); 687*4e96bf3aSLandon J. Fuller 688*4e96bf3aSLandon J. Fuller /* Wait for clock availability */ 689*4e96bf3aSLandon J. Fuller error = bhnd_core_clkctl_wait(clkctl, avail, avail); 690*4e96bf3aSLandon J. Fuller 691*4e96bf3aSLandon J. Fuller BHND_CLKCTL_UNLOCK(clkctl); 692*4e96bf3aSLandon J. Fuller 693*4e96bf3aSLandon J. Fuller return (error); 694f90f4b65SLandon J. Fuller } 695f90f4b65SLandon J. Fuller 696f90f4b65SLandon J. Fuller /** 697f90f4b65SLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC(). 698f90f4b65SLandon J. Fuller */ 699f90f4b65SLandon J. Fuller int 700f90f4b65SLandon J. Fuller bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc) 701f90f4b65SLandon J. Fuller { 702f90f4b65SLandon J. Fuller struct bhnd_softc *sc; 703*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 704*4e96bf3aSLandon J. Fuller uint32_t req; 705*4e96bf3aSLandon J. Fuller uint32_t avail; 706*4e96bf3aSLandon J. Fuller int error; 707f90f4b65SLandon J. Fuller 708f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 709f90f4b65SLandon J. Fuller 710*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 711*4e96bf3aSLandon J. Fuller return (EINVAL); 712f90f4b65SLandon J. Fuller 713*4e96bf3aSLandon J. Fuller if ((clkctl = bhnd_get_pmu_info(child)) == NULL) 714*4e96bf3aSLandon J. Fuller panic("no active PMU allocation"); 715*4e96bf3aSLandon J. Fuller 716*4e96bf3aSLandon J. Fuller BHND_ASSERT_CLKCTL_AVAIL(clkctl); 717*4e96bf3aSLandon J. Fuller 718*4e96bf3aSLandon J. Fuller sc = device_get_softc(dev); 719*4e96bf3aSLandon J. Fuller 720*4e96bf3aSLandon J. Fuller if (rsrc > BHND_CCS_ERSRC_MAX) 721*4e96bf3aSLandon J. Fuller return (EINVAL); 722*4e96bf3aSLandon J. Fuller 723*4e96bf3aSLandon J. Fuller req = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ); 724*4e96bf3aSLandon J. Fuller avail = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS); 725*4e96bf3aSLandon J. Fuller 726*4e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK(clkctl); 727*4e96bf3aSLandon J. Fuller 728*4e96bf3aSLandon J. Fuller /* Write request */ 729*4e96bf3aSLandon J. Fuller BHND_CLKCTL_SET_4(clkctl, req, req); 730*4e96bf3aSLandon J. Fuller 731*4e96bf3aSLandon J. Fuller /* Wait for resource availability */ 732*4e96bf3aSLandon J. Fuller error = bhnd_core_clkctl_wait(clkctl, avail, avail); 733*4e96bf3aSLandon J. Fuller 734*4e96bf3aSLandon J. Fuller BHND_CLKCTL_UNLOCK(clkctl); 735*4e96bf3aSLandon J. Fuller 736*4e96bf3aSLandon J. Fuller return (error); 737f90f4b65SLandon J. Fuller } 738f90f4b65SLandon J. Fuller 739f90f4b65SLandon J. Fuller /** 740f90f4b65SLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC(). 741f90f4b65SLandon J. Fuller */ 742f90f4b65SLandon J. Fuller int 743f90f4b65SLandon J. Fuller bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc) 744f90f4b65SLandon J. Fuller { 745f90f4b65SLandon J. Fuller struct bhnd_softc *sc; 746*4e96bf3aSLandon J. Fuller struct bhnd_core_clkctl *clkctl; 747*4e96bf3aSLandon J. Fuller uint32_t mask; 748f90f4b65SLandon J. Fuller 749f90f4b65SLandon J. Fuller sc = device_get_softc(dev); 750f90f4b65SLandon J. Fuller 751*4e96bf3aSLandon J. Fuller if (device_get_parent(child) != dev) 752*4e96bf3aSLandon J. Fuller return (EINVAL); 753f90f4b65SLandon J. Fuller 754*4e96bf3aSLandon J. Fuller if ((clkctl = bhnd_get_pmu_info(child)) == NULL) 755*4e96bf3aSLandon J. Fuller panic("no active PMU allocation"); 756*4e96bf3aSLandon J. Fuller 757*4e96bf3aSLandon J. Fuller 758*4e96bf3aSLandon J. Fuller BHND_ASSERT_CLKCTL_AVAIL(clkctl); 759*4e96bf3aSLandon J. Fuller 760*4e96bf3aSLandon J. Fuller sc = device_get_softc(dev); 761*4e96bf3aSLandon J. Fuller 762*4e96bf3aSLandon J. Fuller if (rsrc > BHND_CCS_ERSRC_MAX) 763*4e96bf3aSLandon J. Fuller return (EINVAL); 764*4e96bf3aSLandon J. Fuller 765*4e96bf3aSLandon J. Fuller mask = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ); 766*4e96bf3aSLandon J. Fuller 767*4e96bf3aSLandon J. Fuller /* Clear request */ 768*4e96bf3aSLandon J. Fuller BHND_CLKCTL_LOCK(clkctl); 769*4e96bf3aSLandon J. Fuller BHND_CLKCTL_SET_4(clkctl, 0x0, mask); 770*4e96bf3aSLandon J. Fuller BHND_CLKCTL_UNLOCK(clkctl); 771*4e96bf3aSLandon J. Fuller 772*4e96bf3aSLandon J. Fuller return (0); 773f90f4b65SLandon J. Fuller } 774f90f4b65SLandon J. Fuller 775f90f4b65SLandon J. Fuller /** 776386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID(). 7774ad7e9b0SAdrian Chadd * 7784ad7e9b0SAdrian Chadd * This implementation assumes that port and region numbers are 0-indexed and 7794ad7e9b0SAdrian Chadd * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and 7804ad7e9b0SAdrian Chadd * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall 7814ad7e9b0SAdrian Chadd * within the defined range. 7824ad7e9b0SAdrian Chadd */ 783386fb140SAdrian Chadd static bool 7844ad7e9b0SAdrian Chadd bhnd_generic_is_region_valid(device_t dev, device_t child, 7854ad7e9b0SAdrian Chadd bhnd_port_type type, u_int port, u_int region) 7864ad7e9b0SAdrian Chadd { 7874ad7e9b0SAdrian Chadd if (port >= bhnd_get_port_count(child, type)) 7884ad7e9b0SAdrian Chadd return (false); 7894ad7e9b0SAdrian Chadd 7904ad7e9b0SAdrian Chadd if (region >= bhnd_get_region_count(child, type, port)) 7914ad7e9b0SAdrian Chadd return (false); 7924ad7e9b0SAdrian Chadd 7934ad7e9b0SAdrian Chadd return (true); 7944ad7e9b0SAdrian Chadd } 7954ad7e9b0SAdrian Chadd 7964ad7e9b0SAdrian Chadd /** 797fdedcd9fSLandon J. Fuller * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR(). 798fdedcd9fSLandon J. Fuller * 7998e35bf83SLandon J. Fuller * This implementation searches @p dev for a registered NVRAM child device. 800fdedcd9fSLandon J. Fuller * 8018e35bf83SLandon J. Fuller * If no NVRAM device is registered with @p dev, the request is delegated to 802fdedcd9fSLandon J. Fuller * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev. 803fdedcd9fSLandon J. Fuller */ 804fdedcd9fSLandon J. Fuller int 805fdedcd9fSLandon J. Fuller bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name, 8061728aef2SLandon J. Fuller void *buf, size_t *size, bhnd_nvram_type type) 807fdedcd9fSLandon J. Fuller { 808fdedcd9fSLandon J. Fuller struct bhnd_softc *sc; 809fdedcd9fSLandon J. Fuller device_t nvram, parent; 8108e35bf83SLandon J. Fuller int error; 811fdedcd9fSLandon J. Fuller 812fdedcd9fSLandon J. Fuller sc = device_get_softc(dev); 813fdedcd9fSLandon J. Fuller 814fdedcd9fSLandon J. Fuller /* If a NVRAM device is available, consult it first */ 8158e35bf83SLandon J. Fuller nvram = bhnd_retain_provider(child, BHND_SERVICE_NVRAM); 8168e35bf83SLandon J. Fuller if (nvram != NULL) { 8178e35bf83SLandon J. Fuller error = BHND_NVRAM_GETVAR(nvram, name, buf, size, type); 8188e35bf83SLandon J. Fuller bhnd_release_provider(child, nvram, BHND_SERVICE_NVRAM); 8198e35bf83SLandon J. Fuller return (error); 8208e35bf83SLandon J. Fuller } 821fdedcd9fSLandon J. Fuller 822fdedcd9fSLandon J. Fuller /* Otherwise, try to delegate to parent */ 823fdedcd9fSLandon J. Fuller if ((parent = device_get_parent(dev)) == NULL) 824fdedcd9fSLandon J. Fuller return (ENODEV); 825fdedcd9fSLandon J. Fuller 826fdedcd9fSLandon J. Fuller return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child, 8271728aef2SLandon J. Fuller name, buf, size, type)); 828fdedcd9fSLandon J. Fuller } 829fdedcd9fSLandon J. Fuller 830fdedcd9fSLandon J. Fuller /** 831386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD(). 8324ad7e9b0SAdrian Chadd * 8334ad7e9b0SAdrian Chadd * This implementation requests the device's struct resource_list via 8344ad7e9b0SAdrian Chadd * BUS_GET_RESOURCE_LIST. 8354ad7e9b0SAdrian Chadd */ 8364ad7e9b0SAdrian Chadd int 8374ad7e9b0SAdrian Chadd bhnd_generic_print_child(device_t dev, device_t child) 8384ad7e9b0SAdrian Chadd { 8394ad7e9b0SAdrian Chadd struct resource_list *rl; 8404ad7e9b0SAdrian Chadd int retval = 0; 8414ad7e9b0SAdrian Chadd 8424ad7e9b0SAdrian Chadd retval += bus_print_child_header(dev, child); 8434ad7e9b0SAdrian Chadd 8444ad7e9b0SAdrian Chadd rl = BUS_GET_RESOURCE_LIST(dev, child); 845824b48efSLandon J. Fuller 846824b48efSLandon J. Fuller 8474ad7e9b0SAdrian Chadd if (rl != NULL) { 8484ad7e9b0SAdrian Chadd retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, 849f8fd3fb5SJustin Hibbits "%#jx"); 850824b48efSLandon J. Fuller 851824b48efSLandon J. Fuller retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, 852824b48efSLandon J. Fuller "%#jd"); 8534ad7e9b0SAdrian Chadd } 8544ad7e9b0SAdrian Chadd 8554ad7e9b0SAdrian Chadd retval += printf(" at core %u", bhnd_get_core_index(child)); 8564ad7e9b0SAdrian Chadd 8574ad7e9b0SAdrian Chadd retval += bus_print_child_domain(dev, child); 8584ad7e9b0SAdrian Chadd retval += bus_print_child_footer(dev, child); 8594ad7e9b0SAdrian Chadd 8604ad7e9b0SAdrian Chadd return (retval); 8614ad7e9b0SAdrian Chadd } 8624ad7e9b0SAdrian Chadd 8634ad7e9b0SAdrian Chadd /** 864386fb140SAdrian Chadd * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH(). 8654ad7e9b0SAdrian Chadd * 8664ad7e9b0SAdrian Chadd * This implementation requests the device's struct resource_list via 8674ad7e9b0SAdrian Chadd * BUS_GET_RESOURCE_LIST. 8684ad7e9b0SAdrian Chadd */ 8694ad7e9b0SAdrian Chadd void 8704ad7e9b0SAdrian Chadd bhnd_generic_probe_nomatch(device_t dev, device_t child) 8714ad7e9b0SAdrian Chadd { 8724ad7e9b0SAdrian Chadd struct resource_list *rl; 8734ad7e9b0SAdrian Chadd const struct bhnd_nomatch *nm; 8744ad7e9b0SAdrian Chadd bool report; 8754ad7e9b0SAdrian Chadd 8764ad7e9b0SAdrian Chadd /* Fetch reporting configuration for this device */ 8774ad7e9b0SAdrian Chadd report = true; 8784ad7e9b0SAdrian Chadd for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) { 8794ad7e9b0SAdrian Chadd if (nm->vendor != bhnd_get_vendor(child)) 8804ad7e9b0SAdrian Chadd continue; 8814ad7e9b0SAdrian Chadd 8824ad7e9b0SAdrian Chadd if (nm->device != bhnd_get_device(child)) 8834ad7e9b0SAdrian Chadd continue; 8844ad7e9b0SAdrian Chadd 8854ad7e9b0SAdrian Chadd report = false; 8864ad7e9b0SAdrian Chadd if (bootverbose && nm->if_verbose) 8874ad7e9b0SAdrian Chadd report = true; 8884ad7e9b0SAdrian Chadd break; 8894ad7e9b0SAdrian Chadd } 8904ad7e9b0SAdrian Chadd 8914ad7e9b0SAdrian Chadd if (!report) 8924ad7e9b0SAdrian Chadd return; 8934ad7e9b0SAdrian Chadd 8944ad7e9b0SAdrian Chadd /* Print the non-matched device info */ 8954ad7e9b0SAdrian Chadd device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child), 8964ad7e9b0SAdrian Chadd bhnd_get_device_name(child)); 8974ad7e9b0SAdrian Chadd 8984ad7e9b0SAdrian Chadd rl = BUS_GET_RESOURCE_LIST(dev, child); 899824b48efSLandon J. Fuller if (rl != NULL) { 900f8fd3fb5SJustin Hibbits resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 901824b48efSLandon J. Fuller resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%#jd"); 902824b48efSLandon J. Fuller } 9034ad7e9b0SAdrian Chadd 9044ad7e9b0SAdrian Chadd printf(" at core %u (no driver attached)\n", 9054ad7e9b0SAdrian Chadd bhnd_get_core_index(child)); 9064ad7e9b0SAdrian Chadd } 9074ad7e9b0SAdrian Chadd 9084ad7e9b0SAdrian Chadd /** 9094ad7e9b0SAdrian Chadd * Default implementation of BUS_CHILD_PNPINFO_STR(). 9104ad7e9b0SAdrian Chadd */ 9114ad7e9b0SAdrian Chadd static int 9124ad7e9b0SAdrian Chadd bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf, 9134ad7e9b0SAdrian Chadd size_t buflen) 9144ad7e9b0SAdrian Chadd { 9154ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) { 9164ad7e9b0SAdrian Chadd return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child, 9174ad7e9b0SAdrian Chadd buf, buflen)); 9184ad7e9b0SAdrian Chadd } 9194ad7e9b0SAdrian Chadd 9204ad7e9b0SAdrian Chadd snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx", 9214ad7e9b0SAdrian Chadd bhnd_get_vendor(child), bhnd_get_device(child), 9224ad7e9b0SAdrian Chadd bhnd_get_hwrev(child)); 9234ad7e9b0SAdrian Chadd 9244ad7e9b0SAdrian Chadd return (0); 9254ad7e9b0SAdrian Chadd } 9264ad7e9b0SAdrian Chadd 9274ad7e9b0SAdrian Chadd /** 928386fb140SAdrian Chadd * Default implementation of BUS_CHILD_LOCATION_STR(). 9294ad7e9b0SAdrian Chadd */ 9304ad7e9b0SAdrian Chadd static int 9314ad7e9b0SAdrian Chadd bhnd_child_location_str(device_t dev, device_t child, char *buf, 9324ad7e9b0SAdrian Chadd size_t buflen) 9334ad7e9b0SAdrian Chadd { 9344ad7e9b0SAdrian Chadd bhnd_addr_t addr; 9354ad7e9b0SAdrian Chadd bhnd_size_t size; 9364ad7e9b0SAdrian Chadd 9374ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) { 9384ad7e9b0SAdrian Chadd return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child, 9394ad7e9b0SAdrian Chadd buf, buflen)); 9404ad7e9b0SAdrian Chadd } 9414ad7e9b0SAdrian Chadd 9424ad7e9b0SAdrian Chadd 9434ad7e9b0SAdrian Chadd if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) { 9444ad7e9b0SAdrian Chadd /* No device default port/region */ 9454ad7e9b0SAdrian Chadd if (buflen > 0) 9464ad7e9b0SAdrian Chadd *buf = '\0'; 9474ad7e9b0SAdrian Chadd return (0); 9484ad7e9b0SAdrian Chadd } 9494ad7e9b0SAdrian Chadd 9504ad7e9b0SAdrian Chadd snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr); 9514ad7e9b0SAdrian Chadd return (0); 9524ad7e9b0SAdrian Chadd } 9534ad7e9b0SAdrian Chadd 9544ad7e9b0SAdrian Chadd /** 955688fc8c0SLandon J. Fuller * Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED(). 956688fc8c0SLandon J. Fuller * 957688fc8c0SLandon J. Fuller * This implementation manages internal bhnd(4) state, and must be called 958688fc8c0SLandon J. Fuller * by subclassing drivers. 959688fc8c0SLandon J. Fuller */ 960688fc8c0SLandon J. Fuller void 961688fc8c0SLandon J. Fuller bhnd_generic_child_deleted(device_t dev, device_t child) 962688fc8c0SLandon J. Fuller { 963688fc8c0SLandon J. Fuller struct bhnd_softc *sc; 964688fc8c0SLandon J. Fuller 965688fc8c0SLandon J. Fuller sc = device_get_softc(dev); 966688fc8c0SLandon J. Fuller 967688fc8c0SLandon J. Fuller /* Free device info */ 9688a03f98aSLandon J. Fuller if (bhnd_get_pmu_info(child) != NULL) { 969f90f4b65SLandon J. Fuller /* Releasing PMU requests automatically would be nice, 970f90f4b65SLandon J. Fuller * but we can't reference per-core PMU register 971f90f4b65SLandon J. Fuller * resource after driver detach */ 972f90f4b65SLandon J. Fuller panic("%s leaked device pmu state\n", 973f90f4b65SLandon J. Fuller device_get_nameunit(child)); 974f90f4b65SLandon J. Fuller } 975688fc8c0SLandon J. Fuller } 976688fc8c0SLandon J. Fuller 977688fc8c0SLandon J. Fuller /** 9784ad7e9b0SAdrian Chadd * Helper function for implementing BUS_SUSPEND_CHILD(). 9794ad7e9b0SAdrian Chadd * 9804ad7e9b0SAdrian Chadd * TODO: Power management 9814ad7e9b0SAdrian Chadd * 9824ad7e9b0SAdrian Chadd * If @p child is not a direct child of @p dev, suspension is delegated to 9834ad7e9b0SAdrian Chadd * the @p dev parent. 9844ad7e9b0SAdrian Chadd */ 9854ad7e9b0SAdrian Chadd int 9864ad7e9b0SAdrian Chadd bhnd_generic_suspend_child(device_t dev, device_t child) 9874ad7e9b0SAdrian Chadd { 9884ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 9894ad7e9b0SAdrian Chadd BUS_SUSPEND_CHILD(device_get_parent(dev), child); 9904ad7e9b0SAdrian Chadd 9914ad7e9b0SAdrian Chadd return bus_generic_suspend_child(dev, child); 9924ad7e9b0SAdrian Chadd } 9934ad7e9b0SAdrian Chadd 9944ad7e9b0SAdrian Chadd /** 9954ad7e9b0SAdrian Chadd * Helper function for implementing BUS_RESUME_CHILD(). 9964ad7e9b0SAdrian Chadd * 9974ad7e9b0SAdrian Chadd * TODO: Power management 9984ad7e9b0SAdrian Chadd * 9994ad7e9b0SAdrian Chadd * If @p child is not a direct child of @p dev, suspension is delegated to 10004ad7e9b0SAdrian Chadd * the @p dev parent. 10014ad7e9b0SAdrian Chadd */ 10024ad7e9b0SAdrian Chadd int 10034ad7e9b0SAdrian Chadd bhnd_generic_resume_child(device_t dev, device_t child) 10044ad7e9b0SAdrian Chadd { 10054ad7e9b0SAdrian Chadd if (device_get_parent(child) != dev) 10064ad7e9b0SAdrian Chadd BUS_RESUME_CHILD(device_get_parent(dev), child); 10074ad7e9b0SAdrian Chadd 10084ad7e9b0SAdrian Chadd return bus_generic_resume_child(dev, child); 10094ad7e9b0SAdrian Chadd } 10104ad7e9b0SAdrian Chadd 1011caeff9a3SLandon J. Fuller 1012caeff9a3SLandon J. Fuller /** 1013caeff9a3SLandon J. Fuller * Default bhnd(4) bus driver implementation of BUS_SETUP_INTR(). 1014caeff9a3SLandon J. Fuller * 1015caeff9a3SLandon J. Fuller * This implementation of BUS_SETUP_INTR() will delegate interrupt setup 1016caeff9a3SLandon J. Fuller * to the parent of @p dev, if any. 1017caeff9a3SLandon J. Fuller */ 1018caeff9a3SLandon J. Fuller int 1019caeff9a3SLandon J. Fuller bhnd_generic_setup_intr(device_t dev, device_t child, struct resource *irq, 1020caeff9a3SLandon J. Fuller int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, 1021caeff9a3SLandon J. Fuller void **cookiep) 1022caeff9a3SLandon J. Fuller { 1023caeff9a3SLandon J. Fuller return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr, 1024caeff9a3SLandon J. Fuller arg, cookiep)); 1025caeff9a3SLandon J. Fuller } 1026caeff9a3SLandon J. Fuller 10274ad7e9b0SAdrian Chadd /* 10284ad7e9b0SAdrian Chadd * Delegate all indirect I/O to the parent device. When inherited by 10294ad7e9b0SAdrian Chadd * non-bridged bus implementations, resources will never be marked as 10300e141e3cSAdrian Chadd * indirect, and these methods will never be called. 10314ad7e9b0SAdrian Chadd */ 1032a73ac06dSAdrian Chadd #define BHND_IO_READ(_type, _name, _method) \ 1033a73ac06dSAdrian Chadd static _type \ 1034a73ac06dSAdrian Chadd bhnd_read_ ## _name (device_t dev, device_t child, \ 1035a73ac06dSAdrian Chadd struct bhnd_resource *r, bus_size_t offset) \ 1036a73ac06dSAdrian Chadd { \ 1037a73ac06dSAdrian Chadd return (BHND_BUS_READ_ ## _method( \ 1038a73ac06dSAdrian Chadd device_get_parent(dev), child, r, offset)); \ 10394ad7e9b0SAdrian Chadd } 10404ad7e9b0SAdrian Chadd 1041a73ac06dSAdrian Chadd #define BHND_IO_WRITE(_type, _name, _method) \ 1042a73ac06dSAdrian Chadd static void \ 1043a73ac06dSAdrian Chadd bhnd_write_ ## _name (device_t dev, device_t child, \ 1044a73ac06dSAdrian Chadd struct bhnd_resource *r, bus_size_t offset, _type value) \ 1045a73ac06dSAdrian Chadd { \ 1046a73ac06dSAdrian Chadd return (BHND_BUS_WRITE_ ## _method( \ 1047a73ac06dSAdrian Chadd device_get_parent(dev), child, r, offset, \ 1048a73ac06dSAdrian Chadd value)); \ 10494ad7e9b0SAdrian Chadd } 10504ad7e9b0SAdrian Chadd 10510e141e3cSAdrian Chadd #define BHND_IO_MISC(_type, _op, _method) \ 1052a73ac06dSAdrian Chadd static void \ 10530e141e3cSAdrian Chadd bhnd_ ## _op (device_t dev, device_t child, \ 10540e141e3cSAdrian Chadd struct bhnd_resource *r, bus_size_t offset, _type datap, \ 1055a73ac06dSAdrian Chadd bus_size_t count) \ 1056a73ac06dSAdrian Chadd { \ 1057a73ac06dSAdrian Chadd BHND_BUS_ ## _method(device_get_parent(dev), child, r, \ 1058a73ac06dSAdrian Chadd offset, datap, count); \ 10594ad7e9b0SAdrian Chadd } 10604ad7e9b0SAdrian Chadd 1061a73ac06dSAdrian Chadd #define BHND_IO_METHODS(_type, _size) \ 1062a73ac06dSAdrian Chadd BHND_IO_READ(_type, _size, _size) \ 1063a73ac06dSAdrian Chadd BHND_IO_WRITE(_type, _size, _size) \ 1064a73ac06dSAdrian Chadd \ 1065a73ac06dSAdrian Chadd BHND_IO_READ(_type, stream_ ## _size, STREAM_ ## _size) \ 1066a73ac06dSAdrian Chadd BHND_IO_WRITE(_type, stream_ ## _size, STREAM_ ## _size) \ 1067a73ac06dSAdrian Chadd \ 10680e141e3cSAdrian Chadd BHND_IO_MISC(_type*, read_multi_ ## _size, \ 10690e141e3cSAdrian Chadd READ_MULTI_ ## _size) \ 10700e141e3cSAdrian Chadd BHND_IO_MISC(_type*, write_multi_ ## _size, \ 10710e141e3cSAdrian Chadd WRITE_MULTI_ ## _size) \ 1072a73ac06dSAdrian Chadd \ 10730e141e3cSAdrian Chadd BHND_IO_MISC(_type*, read_multi_stream_ ## _size, \ 1074a73ac06dSAdrian Chadd READ_MULTI_STREAM_ ## _size) \ 10750e141e3cSAdrian Chadd BHND_IO_MISC(_type*, write_multi_stream_ ## _size, \ 1076a73ac06dSAdrian Chadd WRITE_MULTI_STREAM_ ## _size) \ 10770e141e3cSAdrian Chadd \ 10780e141e3cSAdrian Chadd BHND_IO_MISC(_type, set_multi_ ## _size, SET_MULTI_ ## _size) \ 10790e141e3cSAdrian Chadd BHND_IO_MISC(_type, set_region_ ## _size, SET_REGION_ ## _size) \ 10800e141e3cSAdrian Chadd \ 10810e141e3cSAdrian Chadd BHND_IO_MISC(_type*, read_region_ ## _size, \ 10820e141e3cSAdrian Chadd READ_REGION_ ## _size) \ 10830e141e3cSAdrian Chadd BHND_IO_MISC(_type*, write_region_ ## _size, \ 10840e141e3cSAdrian Chadd WRITE_REGION_ ## _size) \ 10850e141e3cSAdrian Chadd \ 10860e141e3cSAdrian Chadd BHND_IO_MISC(_type*, read_region_stream_ ## _size, \ 10870e141e3cSAdrian Chadd READ_REGION_STREAM_ ## _size) \ 10880e141e3cSAdrian Chadd BHND_IO_MISC(_type*, write_region_stream_ ## _size, \ 10890e141e3cSAdrian Chadd WRITE_REGION_STREAM_ ## _size) \ 10904ad7e9b0SAdrian Chadd 1091a73ac06dSAdrian Chadd BHND_IO_METHODS(uint8_t, 1); 1092a73ac06dSAdrian Chadd BHND_IO_METHODS(uint16_t, 2); 1093a73ac06dSAdrian Chadd BHND_IO_METHODS(uint32_t, 4); 10944ad7e9b0SAdrian Chadd 10954ad7e9b0SAdrian Chadd static void 10964ad7e9b0SAdrian Chadd bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r, 10974ad7e9b0SAdrian Chadd bus_size_t offset, bus_size_t length, int flags) 10984ad7e9b0SAdrian Chadd { 10994ad7e9b0SAdrian Chadd BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length, 11004ad7e9b0SAdrian Chadd flags); 11014ad7e9b0SAdrian Chadd } 11024ad7e9b0SAdrian Chadd 11034ad7e9b0SAdrian Chadd static device_method_t bhnd_methods[] = { 11044ad7e9b0SAdrian Chadd /* Device interface */ \ 11054ad7e9b0SAdrian Chadd DEVMETHOD(device_attach, bhnd_generic_attach), 11064ad7e9b0SAdrian Chadd DEVMETHOD(device_detach, bhnd_generic_detach), 11074ad7e9b0SAdrian Chadd DEVMETHOD(device_shutdown, bhnd_generic_shutdown), 11084ad7e9b0SAdrian Chadd DEVMETHOD(device_suspend, bhnd_generic_suspend), 11094ad7e9b0SAdrian Chadd DEVMETHOD(device_resume, bhnd_generic_resume), 11104ad7e9b0SAdrian Chadd 11114ad7e9b0SAdrian Chadd /* Bus interface */ 1112688fc8c0SLandon J. Fuller DEVMETHOD(bus_child_deleted, bhnd_generic_child_deleted), 11134ad7e9b0SAdrian Chadd DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), 11144ad7e9b0SAdrian Chadd DEVMETHOD(bus_print_child, bhnd_generic_print_child), 11154ad7e9b0SAdrian Chadd DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str), 11164ad7e9b0SAdrian Chadd DEVMETHOD(bus_child_location_str, bhnd_child_location_str), 11174ad7e9b0SAdrian Chadd 11184ad7e9b0SAdrian Chadd DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child), 11194ad7e9b0SAdrian Chadd DEVMETHOD(bus_resume_child, bhnd_generic_resume_child), 11204ad7e9b0SAdrian Chadd 11214ad7e9b0SAdrian Chadd DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 11224ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 11234ad7e9b0SAdrian Chadd DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 11244ad7e9b0SAdrian Chadd DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 11254ad7e9b0SAdrian Chadd DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 11264ad7e9b0SAdrian Chadd DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 11274ad7e9b0SAdrian Chadd DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 11284ad7e9b0SAdrian Chadd DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 11294ad7e9b0SAdrian Chadd 1130caeff9a3SLandon J. Fuller DEVMETHOD(bus_setup_intr, bhnd_generic_setup_intr), 11314ad7e9b0SAdrian Chadd DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 11324ad7e9b0SAdrian Chadd DEVMETHOD(bus_config_intr, bus_generic_config_intr), 11334ad7e9b0SAdrian Chadd DEVMETHOD(bus_bind_intr, bus_generic_bind_intr), 11344ad7e9b0SAdrian Chadd DEVMETHOD(bus_describe_intr, bus_generic_describe_intr), 11354ad7e9b0SAdrian Chadd 11364ad7e9b0SAdrian Chadd DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), 11374ad7e9b0SAdrian Chadd 11384ad7e9b0SAdrian Chadd /* BHND interface */ 1139386fb140SAdrian Chadd DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid), 1140386fb140SAdrian Chadd DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), 1141f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_read_board_info, bhnd_bus_generic_read_board_info), 1142f90f4b65SLandon J. Fuller 1143f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), 1144f90f4b65SLandon J. Fuller 1145f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_alloc_pmu, bhnd_generic_alloc_pmu), 1146f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_release_pmu, bhnd_generic_release_pmu), 1147f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_request_clock, bhnd_generic_request_clock), 1148f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks), 1149f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc), 1150f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc), 1151*4e96bf3aSLandon J. Fuller DEVMETHOD(bhnd_bus_get_clock_latency, bhnd_generic_get_clock_latency), 1152*4e96bf3aSLandon J. Fuller DEVMETHOD(bhnd_bus_get_clock_freq, bhnd_generic_get_clock_freq), 1153f90f4b65SLandon J. Fuller 1154f90f4b65SLandon J. Fuller DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), 1155fdedcd9fSLandon J. Fuller DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var), 11560e141e3cSAdrian Chadd 11570e141e3cSAdrian Chadd /* BHND interface (bus I/O) */ 11584ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), 11594ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_read_2, bhnd_read_2), 11604ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_read_4, bhnd_read_4), 11614ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_write_1, bhnd_write_1), 11624ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_write_2, bhnd_write_2), 11634ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_write_4, bhnd_write_4), 11640e141e3cSAdrian Chadd 1165a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_stream_1, bhnd_read_stream_1), 1166a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_stream_2, bhnd_read_stream_2), 1167a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_stream_4, bhnd_read_stream_4), 1168a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_stream_1, bhnd_write_stream_1), 1169a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_stream_2, bhnd_write_stream_2), 1170a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_stream_4, bhnd_write_stream_4), 1171a73ac06dSAdrian Chadd 1172a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_multi_1, bhnd_read_multi_1), 1173a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_multi_2, bhnd_read_multi_2), 1174a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_multi_4, bhnd_read_multi_4), 1175a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_multi_1, bhnd_write_multi_1), 1176a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_multi_2, bhnd_write_multi_2), 1177a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_multi_4, bhnd_write_multi_4), 1178a73ac06dSAdrian Chadd 1179a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_multi_stream_1, bhnd_read_multi_stream_1), 1180a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_multi_stream_2, bhnd_read_multi_stream_2), 1181a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_read_multi_stream_4, bhnd_read_multi_stream_4), 1182a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_multi_stream_1,bhnd_write_multi_stream_1), 1183a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_multi_stream_2,bhnd_write_multi_stream_2), 1184a73ac06dSAdrian Chadd DEVMETHOD(bhnd_bus_write_multi_stream_4,bhnd_write_multi_stream_4), 1185a73ac06dSAdrian Chadd 11860e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_set_multi_1, bhnd_set_multi_1), 11870e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_set_multi_2, bhnd_set_multi_2), 11880e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_set_multi_4, bhnd_set_multi_4), 11890e141e3cSAdrian Chadd 11900e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_set_region_1, bhnd_set_region_1), 11910e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_set_region_2, bhnd_set_region_2), 11920e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_set_region_4, bhnd_set_region_4), 11930e141e3cSAdrian Chadd 11940e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_read_region_1, bhnd_read_region_1), 11950e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_read_region_2, bhnd_read_region_2), 11960e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_read_region_4, bhnd_read_region_4), 11970e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_write_region_1, bhnd_write_region_1), 11980e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_write_region_2, bhnd_write_region_2), 11990e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_write_region_4, bhnd_write_region_4), 12000e141e3cSAdrian Chadd 12010e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_read_region_stream_1,bhnd_read_region_stream_1), 12020e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_read_region_stream_2,bhnd_read_region_stream_2), 12030e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_read_region_stream_4,bhnd_read_region_stream_4), 12040e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_write_region_stream_1, bhnd_write_region_stream_1), 12050e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_write_region_stream_2, bhnd_write_region_stream_2), 12060e141e3cSAdrian Chadd DEVMETHOD(bhnd_bus_write_region_stream_4, bhnd_write_region_stream_4), 12070e141e3cSAdrian Chadd 12084ad7e9b0SAdrian Chadd DEVMETHOD(bhnd_bus_barrier, bhnd_barrier), 12094ad7e9b0SAdrian Chadd 12104ad7e9b0SAdrian Chadd DEVMETHOD_END 12114ad7e9b0SAdrian Chadd }; 12124ad7e9b0SAdrian Chadd 12134ad7e9b0SAdrian Chadd devclass_t bhnd_devclass; /**< bhnd bus. */ 12144ad7e9b0SAdrian Chadd devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */ 12154ad7e9b0SAdrian Chadd devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */ 12164ad7e9b0SAdrian Chadd 12174ad7e9b0SAdrian Chadd DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc)); 12184ad7e9b0SAdrian Chadd MODULE_VERSION(bhnd, 1); 1219