xref: /freebsd/sys/dev/bhnd/bhnd.c (revision 4e96bf3a37e326dcb741f289d8adfac8884cca78)
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