xref: /freebsd/sys/dev/bhnd/bhnd.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
14ad7e9b0SAdrian Chadd /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
36e778a7eSPedro F. Giffuni  *
4f90f4b65SLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
58e35bf83SLandon J. Fuller  * Copyright (c) 2017 The FreeBSD Foundation
64ad7e9b0SAdrian Chadd  * All rights reserved.
74ad7e9b0SAdrian Chadd  *
88e35bf83SLandon J. Fuller  * Portions of this software were developed by Landon Fuller
98e35bf83SLandon J. Fuller  * under sponsorship from the FreeBSD Foundation.
108e35bf83SLandon J. Fuller  *
114ad7e9b0SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
124ad7e9b0SAdrian Chadd  * modification, are permitted provided that the following conditions
134ad7e9b0SAdrian Chadd  * are met:
144ad7e9b0SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
154ad7e9b0SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
164ad7e9b0SAdrian Chadd  *    without modification.
174ad7e9b0SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
184ad7e9b0SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
194ad7e9b0SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
204ad7e9b0SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
214ad7e9b0SAdrian Chadd  *
224ad7e9b0SAdrian Chadd  * NO WARRANTY
234ad7e9b0SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
244ad7e9b0SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
254ad7e9b0SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
264ad7e9b0SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
274ad7e9b0SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
284ad7e9b0SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
294ad7e9b0SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
304ad7e9b0SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
314ad7e9b0SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
324ad7e9b0SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
334ad7e9b0SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
344ad7e9b0SAdrian Chadd  */
354ad7e9b0SAdrian Chadd 
364ad7e9b0SAdrian Chadd #include <sys/cdefs.h>
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>
59ddfc9c4cSWarner Losh #include <sys/sbuf.h>
604ad7e9b0SAdrian Chadd #include <sys/systm.h>
614ad7e9b0SAdrian Chadd 
624ad7e9b0SAdrian Chadd #include <machine/bus.h>
634ad7e9b0SAdrian Chadd #include <sys/rman.h>
644ad7e9b0SAdrian Chadd #include <machine/resource.h>
654ad7e9b0SAdrian Chadd 
66f90f4b65SLandon J. Fuller #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
67f90f4b65SLandon J. Fuller 
68fdedcd9fSLandon J. Fuller #include "bhnd_chipc_if.h"
69fdedcd9fSLandon J. Fuller #include "bhnd_nvram_if.h"
70fdedcd9fSLandon J. Fuller 
714ad7e9b0SAdrian Chadd #include "bhnd.h"
724e96bf3aSLandon J. Fuller #include "bhndreg.h"
734ad7e9b0SAdrian Chadd #include "bhndvar.h"
744ad7e9b0SAdrian Chadd 
758e35bf83SLandon J. Fuller #include "bhnd_private.h"
764ad7e9b0SAdrian Chadd 
778e35bf83SLandon J. Fuller MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures");
78fdedcd9fSLandon J. Fuller 
794ad7e9b0SAdrian Chadd /**
804ad7e9b0SAdrian Chadd  * bhnd_generic_probe_nomatch() reporting configuration.
814ad7e9b0SAdrian Chadd  */
824ad7e9b0SAdrian Chadd static const struct bhnd_nomatch {
834ad7e9b0SAdrian Chadd 	uint16_t	vendor;		/**< core designer */
844ad7e9b0SAdrian Chadd 	uint16_t	device;		/**< core id */
854ad7e9b0SAdrian Chadd 	bool		if_verbose;	/**< print when bootverbose is set. */
864ad7e9b0SAdrian Chadd } bhnd_nomatch_table[] = {
874ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_OOB_ROUTER,		true	},
884ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_EROM,		true	},
894ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_PL301,		true	},
904ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_APB_BRIDGE,		true	},
914ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_AXI_UNMAPPED,	false	},
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
bhnd_generic_attach(device_t dev)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
bhnd_delete_children(struct bhnd_softc * sc)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
bhnd_generic_detach(device_t dev)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
bhnd_generic_shutdown(device_t dev)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
bhnd_generic_resume(device_t dev)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
bhnd_generic_suspend(device_t dev)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
bhnd_generic_get_probe_order(device_t dev,device_t child)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
bhnd_generic_alloc_pmu(device_t dev,device_t child)361f90f4b65SLandon J. Fuller bhnd_generic_alloc_pmu(device_t dev, device_t child)
362f90f4b65SLandon J. Fuller {
363f90f4b65SLandon J. Fuller 	struct bhnd_softc		*sc;
3644e96bf3aSLandon J. Fuller 	struct bhnd_resource		*r;
3654e96bf3aSLandon 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;
3724e96bf3aSLandon J. Fuller 	u_int				 max_latency;
373f90f4b65SLandon J. Fuller 	int				 error;
374f90f4b65SLandon J. Fuller 
375d14bc723SWarner Losh 	bus_topo_assert();
376f90f4b65SLandon J. Fuller 
3774e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
3784e96bf3aSLandon J. Fuller 		return (EINVAL);
3794e96bf3aSLandon J. Fuller 
380f90f4b65SLandon J. Fuller 	sc = device_get_softc(dev);
3814e96bf3aSLandon 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? */
3854e96bf3aSLandon 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 
4454e96bf3aSLandon 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) {
4484e96bf3aSLandon J. Fuller 		device_printf(sc->dev, "PMU not found\n");
4498e35bf83SLandon J. Fuller 		return (ENXIO);
4508e35bf83SLandon J. Fuller 	}
4518e35bf83SLandon J. Fuller 
4524e96bf3aSLandon J. Fuller 	/* Fetch the maximum transition latency from our PMU */
4534e96bf3aSLandon J. Fuller 	max_latency = bhnd_pmu_get_max_transition_latency(pmu_dev);
4544e96bf3aSLandon J. Fuller 
4554e96bf3aSLandon J. Fuller 	/* Allocate a new bhnd_resource wrapping the standard resource we
4564e96bf3aSLandon J. Fuller 	 * fetched from the resource list; we'll free this in
4574e96bf3aSLandon J. Fuller 	 * bhnd_generic_release_pmu() */
4584e96bf3aSLandon J. Fuller 	r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
4594e96bf3aSLandon 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 
4644e96bf3aSLandon J. Fuller 	r->res = rle->res;
4654e96bf3aSLandon J. Fuller 	r->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
466f90f4b65SLandon J. Fuller 
4674e96bf3aSLandon J. Fuller 	/* Allocate the clkctl instance */
4684e96bf3aSLandon J. Fuller 	clkctl = bhnd_alloc_core_clkctl(child, pmu_dev, r, pmu_regs,
4694e96bf3aSLandon J. Fuller 	    max_latency);
4704e96bf3aSLandon J. Fuller 	if (clkctl == NULL) {
4714e96bf3aSLandon 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 
4764e96bf3aSLandon 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
bhnd_generic_release_pmu(device_t dev,device_t child)484f90f4b65SLandon J. Fuller bhnd_generic_release_pmu(device_t dev, device_t child)
485f90f4b65SLandon J. Fuller {
4864e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl	*clkctl;
4874e96bf3aSLandon J. Fuller 	struct bhnd_resource	*r;
4884e96bf3aSLandon J. Fuller 	device_t		 pmu_dev;
489f90f4b65SLandon J. Fuller 
490d14bc723SWarner Losh 	bus_topo_assert();
491f90f4b65SLandon J. Fuller 
4924e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
4934e96bf3aSLandon J. Fuller 		return (EINVAL);
4944e96bf3aSLandon J. Fuller 
4954e96bf3aSLandon J. Fuller 	clkctl = bhnd_get_pmu_info(child);
4964e96bf3aSLandon J. Fuller 	if (clkctl == NULL)
497f90f4b65SLandon J. Fuller 		panic("pmu over-release for %s", device_get_nameunit(child));
498f90f4b65SLandon J. Fuller 
4994e96bf3aSLandon J. Fuller 	/* Clear all FORCE, AREQ, and ERSRC flags, unless we're already in
5004e96bf3aSLandon J. Fuller 	 * RESET. Suspending a core clears clkctl automatically (and attempting
5014e96bf3aSLandon J. Fuller 	 * to access the PMU registers in a suspended core will trigger a
5024e96bf3aSLandon J. Fuller 	 * system livelock). */
5034e96bf3aSLandon J. Fuller 	if (!bhnd_is_hw_suspended(clkctl->cc_dev)) {
5044e96bf3aSLandon J. Fuller 		BHND_CLKCTL_LOCK(clkctl);
505f90f4b65SLandon J. Fuller 
5064e96bf3aSLandon J. Fuller 		/* Clear all FORCE, AREQ, and ERSRC flags */
5074e96bf3aSLandon J. Fuller 		BHND_CLKCTL_SET_4(clkctl, 0x0, BHND_CCS_FORCE_MASK |
5084e96bf3aSLandon J. Fuller 		    BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
5094e96bf3aSLandon J. Fuller 
5104e96bf3aSLandon J. Fuller 		BHND_CLKCTL_UNLOCK(clkctl);
5114e96bf3aSLandon J. Fuller 	}
5124e96bf3aSLandon J. Fuller 
5134e96bf3aSLandon J. Fuller 	/* Clear child's PMU info reference */
5148a03f98aSLandon J. Fuller 	bhnd_set_pmu_info(child, NULL);
5158e35bf83SLandon J. Fuller 
5164e96bf3aSLandon J. Fuller 	/* Before freeing the clkctl instance, save a pointer to resources we
5174e96bf3aSLandon J. Fuller 	 * need to clean up manually */
5184e96bf3aSLandon J. Fuller 	r = clkctl->cc_res;
5194e96bf3aSLandon J. Fuller 	pmu_dev = clkctl->cc_pmu_dev;
5204e96bf3aSLandon J. Fuller 
5214e96bf3aSLandon J. Fuller 	/* Free the clkctl instance */
5224e96bf3aSLandon J. Fuller 	bhnd_free_core_clkctl(clkctl);
5234e96bf3aSLandon J. Fuller 
5244e96bf3aSLandon J. Fuller 	/* Free the child's bhnd resource wrapper */
5254e96bf3aSLandon J. Fuller 	free(r, M_BHND);
5264e96bf3aSLandon J. Fuller 
5274e96bf3aSLandon J. Fuller 	/* Release the child's PMU provider reference */
5284e96bf3aSLandon J. Fuller 	bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
529f90f4b65SLandon J. Fuller 
530f90f4b65SLandon J. Fuller 	return (0);
531f90f4b65SLandon J. Fuller }
532f90f4b65SLandon J. Fuller 
533f90f4b65SLandon J. Fuller /**
5344e96bf3aSLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_LATENCY().
5354e96bf3aSLandon J. Fuller  */
5364e96bf3aSLandon J. Fuller int
bhnd_generic_get_clock_latency(device_t dev,device_t child,bhnd_clock clock,u_int * latency)5374e96bf3aSLandon J. Fuller bhnd_generic_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
5384e96bf3aSLandon J. Fuller     u_int *latency)
5394e96bf3aSLandon J. Fuller {
5404e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl *clkctl;
5414e96bf3aSLandon J. Fuller 
5424e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
5434e96bf3aSLandon J. Fuller 		return (EINVAL);
5444e96bf3aSLandon J. Fuller 
5454e96bf3aSLandon J. Fuller 	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
5464e96bf3aSLandon J. Fuller 		panic("no active PMU allocation");
5474e96bf3aSLandon J. Fuller 
5484e96bf3aSLandon J. Fuller 	return (bhnd_pmu_get_clock_latency(clkctl->cc_pmu_dev, clock, latency));
5494e96bf3aSLandon J. Fuller }
5504e96bf3aSLandon J. Fuller 
5514e96bf3aSLandon J. Fuller /**
5524e96bf3aSLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_FREQ().
5534e96bf3aSLandon J. Fuller  */
5544e96bf3aSLandon J. Fuller int
bhnd_generic_get_clock_freq(device_t dev,device_t child,bhnd_clock clock,u_int * freq)5554e96bf3aSLandon J. Fuller bhnd_generic_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
5564e96bf3aSLandon J. Fuller     u_int *freq)
5574e96bf3aSLandon J. Fuller {
5584e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl *clkctl;
5594e96bf3aSLandon J. Fuller 
5604e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
5614e96bf3aSLandon J. Fuller 		return (EINVAL);
5624e96bf3aSLandon J. Fuller 
5634e96bf3aSLandon J. Fuller 	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
5644e96bf3aSLandon J. Fuller 		panic("no active PMU allocation");
5654e96bf3aSLandon J. Fuller 
5664e96bf3aSLandon J. Fuller 	return (bhnd_pmu_get_clock_freq(clkctl->cc_pmu_dev, clock, freq));
5674e96bf3aSLandon J. Fuller }
5684e96bf3aSLandon J. Fuller 
5694e96bf3aSLandon J. Fuller /**
570f90f4b65SLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK().
571f90f4b65SLandon J. Fuller  */
572f90f4b65SLandon J. Fuller int
bhnd_generic_request_clock(device_t dev,device_t child,bhnd_clock clock)573f90f4b65SLandon J. Fuller bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock)
574f90f4b65SLandon J. Fuller {
5754e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl	*clkctl;
5764e96bf3aSLandon J. Fuller 	uint32_t		 avail;
5774e96bf3aSLandon J. Fuller 	uint32_t		 req;
5784e96bf3aSLandon J. Fuller 	int			 error;
579f90f4b65SLandon J. Fuller 
5804e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
5814e96bf3aSLandon J. Fuller 		return (EINVAL);
582f90f4b65SLandon J. Fuller 
5834e96bf3aSLandon J. Fuller 	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
5844e96bf3aSLandon J. Fuller 		panic("no active PMU allocation");
5854e96bf3aSLandon J. Fuller 
5864e96bf3aSLandon J. Fuller 	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
5874e96bf3aSLandon J. Fuller 
5884e96bf3aSLandon J. Fuller 	avail = 0x0;
5894e96bf3aSLandon J. Fuller 	req = 0x0;
5904e96bf3aSLandon J. Fuller 
5914e96bf3aSLandon J. Fuller 	switch (clock) {
5924e96bf3aSLandon J. Fuller 	case BHND_CLOCK_DYN:
5934e96bf3aSLandon J. Fuller 		break;
5944e96bf3aSLandon J. Fuller 	case BHND_CLOCK_ILP:
5954e96bf3aSLandon J. Fuller 		req |= BHND_CCS_FORCEILP;
5964e96bf3aSLandon J. Fuller 		break;
5974e96bf3aSLandon J. Fuller 	case BHND_CLOCK_ALP:
5984e96bf3aSLandon J. Fuller 		req |= BHND_CCS_FORCEALP;
5994e96bf3aSLandon J. Fuller 		avail |= BHND_CCS_ALPAVAIL;
6004e96bf3aSLandon J. Fuller 		break;
6014e96bf3aSLandon J. Fuller 	case BHND_CLOCK_HT:
6024e96bf3aSLandon J. Fuller 		req |= BHND_CCS_FORCEHT;
6034e96bf3aSLandon J. Fuller 		avail |= BHND_CCS_HTAVAIL;
6044e96bf3aSLandon J. Fuller 		break;
6054e96bf3aSLandon J. Fuller 	default:
6064e96bf3aSLandon J. Fuller 		device_printf(dev, "%s requested unknown clock: %#x\n",
6074e96bf3aSLandon J. Fuller 		    device_get_nameunit(clkctl->cc_dev), clock);
6084e96bf3aSLandon J. Fuller 		return (ENODEV);
6094e96bf3aSLandon J. Fuller 	}
6104e96bf3aSLandon J. Fuller 
6114e96bf3aSLandon J. Fuller 	BHND_CLKCTL_LOCK(clkctl);
6124e96bf3aSLandon J. Fuller 
6134e96bf3aSLandon J. Fuller 	/* Issue request */
6144e96bf3aSLandon J. Fuller 	BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_FORCE_MASK);
6154e96bf3aSLandon J. Fuller 
6164e96bf3aSLandon J. Fuller 	/* Wait for clock availability */
6174e96bf3aSLandon J. Fuller 	error = bhnd_core_clkctl_wait(clkctl, avail, avail);
6184e96bf3aSLandon J. Fuller 
6194e96bf3aSLandon J. Fuller 	BHND_CLKCTL_UNLOCK(clkctl);
6204e96bf3aSLandon J. Fuller 
6214e96bf3aSLandon J. Fuller 	return (error);
622f90f4b65SLandon J. Fuller }
623f90f4b65SLandon J. Fuller 
624f90f4b65SLandon J. Fuller /**
625f90f4b65SLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS().
626f90f4b65SLandon J. Fuller  */
627f90f4b65SLandon J. Fuller int
bhnd_generic_enable_clocks(device_t dev,device_t child,uint32_t clocks)628f90f4b65SLandon J. Fuller bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks)
629f90f4b65SLandon J. Fuller {
6304e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl	*clkctl;
6314e96bf3aSLandon J. Fuller 	uint32_t		 avail;
6324e96bf3aSLandon J. Fuller 	uint32_t		 req;
6334e96bf3aSLandon J. Fuller 	int			 error;
634f90f4b65SLandon J. Fuller 
6354e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
6364e96bf3aSLandon J. Fuller 		return (EINVAL);
637f90f4b65SLandon J. Fuller 
6384e96bf3aSLandon J. Fuller 	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
6394e96bf3aSLandon J. Fuller 		panic("no active PMU allocation");
6404e96bf3aSLandon J. Fuller 
6414e96bf3aSLandon J. Fuller 	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
6424e96bf3aSLandon J. Fuller 
6434e96bf3aSLandon J. Fuller 	avail = 0x0;
6444e96bf3aSLandon J. Fuller 	req = 0x0;
6454e96bf3aSLandon J. Fuller 
6464e96bf3aSLandon J. Fuller 	/* Build clock request flags */
6474e96bf3aSLandon J. Fuller 	if (clocks & BHND_CLOCK_DYN)		/* nothing to enable */
6484e96bf3aSLandon J. Fuller 		clocks &= ~BHND_CLOCK_DYN;
6494e96bf3aSLandon J. Fuller 
6504e96bf3aSLandon J. Fuller 	if (clocks & BHND_CLOCK_ILP)		/* nothing to enable */
6514e96bf3aSLandon J. Fuller 		clocks &= ~BHND_CLOCK_ILP;
6524e96bf3aSLandon J. Fuller 
6534e96bf3aSLandon J. Fuller 	if (clocks & BHND_CLOCK_ALP) {
6544e96bf3aSLandon J. Fuller 		req |= BHND_CCS_ALPAREQ;
6554e96bf3aSLandon J. Fuller 		avail |= BHND_CCS_ALPAVAIL;
6564e96bf3aSLandon J. Fuller 		clocks &= ~BHND_CLOCK_ALP;
6574e96bf3aSLandon J. Fuller 	}
6584e96bf3aSLandon J. Fuller 
6594e96bf3aSLandon J. Fuller 	if (clocks & BHND_CLOCK_HT) {
6604e96bf3aSLandon J. Fuller 		req |= BHND_CCS_HTAREQ;
6614e96bf3aSLandon J. Fuller 		avail |= BHND_CCS_HTAVAIL;
6624e96bf3aSLandon J. Fuller 		clocks &= ~BHND_CLOCK_HT;
6634e96bf3aSLandon J. Fuller 	}
6644e96bf3aSLandon J. Fuller 
6654e96bf3aSLandon J. Fuller 	/* Check for unknown clock values */
6664e96bf3aSLandon J. Fuller 	if (clocks != 0x0) {
6674e96bf3aSLandon J. Fuller 		device_printf(dev, "%s requested unknown clocks: %#x\n",
6684e96bf3aSLandon J. Fuller 		    device_get_nameunit(clkctl->cc_dev), clocks);
6694e96bf3aSLandon J. Fuller 		return (ENODEV);
6704e96bf3aSLandon J. Fuller 	}
6714e96bf3aSLandon J. Fuller 
6724e96bf3aSLandon J. Fuller 	BHND_CLKCTL_LOCK(clkctl);
6734e96bf3aSLandon J. Fuller 
6744e96bf3aSLandon J. Fuller 	/* Issue request */
6754e96bf3aSLandon J. Fuller 	BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_AREQ_MASK);
6764e96bf3aSLandon J. Fuller 
6774e96bf3aSLandon J. Fuller 	/* Wait for clock availability */
6784e96bf3aSLandon J. Fuller 	error = bhnd_core_clkctl_wait(clkctl, avail, avail);
6794e96bf3aSLandon J. Fuller 
6804e96bf3aSLandon J. Fuller 	BHND_CLKCTL_UNLOCK(clkctl);
6814e96bf3aSLandon J. Fuller 
6824e96bf3aSLandon J. Fuller 	return (error);
683f90f4b65SLandon J. Fuller }
684f90f4b65SLandon J. Fuller 
685f90f4b65SLandon J. Fuller /**
686f90f4b65SLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC().
687f90f4b65SLandon J. Fuller  */
688f90f4b65SLandon J. Fuller int
bhnd_generic_request_ext_rsrc(device_t dev,device_t child,u_int rsrc)689f90f4b65SLandon J. Fuller bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
690f90f4b65SLandon J. Fuller {
6914e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl	*clkctl;
6924e96bf3aSLandon J. Fuller 	uint32_t		 req;
6934e96bf3aSLandon J. Fuller 	uint32_t		 avail;
6944e96bf3aSLandon J. Fuller 	int			 error;
695f90f4b65SLandon J. Fuller 
6964e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
6974e96bf3aSLandon J. Fuller 		return (EINVAL);
698f90f4b65SLandon J. Fuller 
6994e96bf3aSLandon J. Fuller 	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
7004e96bf3aSLandon J. Fuller 		panic("no active PMU allocation");
7014e96bf3aSLandon J. Fuller 
7024e96bf3aSLandon J. Fuller 	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
7034e96bf3aSLandon J. Fuller 
7044e96bf3aSLandon J. Fuller 	if (rsrc > BHND_CCS_ERSRC_MAX)
7054e96bf3aSLandon J. Fuller 		return (EINVAL);
7064e96bf3aSLandon J. Fuller 
7074e96bf3aSLandon J. Fuller 	req = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
7084e96bf3aSLandon J. Fuller 	avail = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
7094e96bf3aSLandon J. Fuller 
7104e96bf3aSLandon J. Fuller 	BHND_CLKCTL_LOCK(clkctl);
7114e96bf3aSLandon J. Fuller 
7124e96bf3aSLandon J. Fuller 	/* Write request */
7134e96bf3aSLandon J. Fuller 	BHND_CLKCTL_SET_4(clkctl, req, req);
7144e96bf3aSLandon J. Fuller 
7154e96bf3aSLandon J. Fuller 	/* Wait for resource availability */
7164e96bf3aSLandon J. Fuller 	error = bhnd_core_clkctl_wait(clkctl, avail, avail);
7174e96bf3aSLandon J. Fuller 
7184e96bf3aSLandon J. Fuller 	BHND_CLKCTL_UNLOCK(clkctl);
7194e96bf3aSLandon J. Fuller 
7204e96bf3aSLandon J. Fuller 	return (error);
721f90f4b65SLandon J. Fuller }
722f90f4b65SLandon J. Fuller 
723f90f4b65SLandon J. Fuller /**
724f90f4b65SLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC().
725f90f4b65SLandon J. Fuller  */
726f90f4b65SLandon J. Fuller int
bhnd_generic_release_ext_rsrc(device_t dev,device_t child,u_int rsrc)727f90f4b65SLandon J. Fuller bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
728f90f4b65SLandon J. Fuller {
7294e96bf3aSLandon J. Fuller 	struct bhnd_core_clkctl	*clkctl;
7304e96bf3aSLandon J. Fuller 	uint32_t		 mask;
731f90f4b65SLandon J. Fuller 
7324e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
7334e96bf3aSLandon J. Fuller 		return (EINVAL);
734f90f4b65SLandon J. Fuller 
7354e96bf3aSLandon J. Fuller 	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
7364e96bf3aSLandon J. Fuller 		panic("no active PMU allocation");
7374e96bf3aSLandon J. Fuller 
7384e96bf3aSLandon J. Fuller 	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
7394e96bf3aSLandon J. Fuller 
7404e96bf3aSLandon J. Fuller 	if (rsrc > BHND_CCS_ERSRC_MAX)
7414e96bf3aSLandon J. Fuller 		return (EINVAL);
7424e96bf3aSLandon J. Fuller 
7434e96bf3aSLandon J. Fuller 	mask = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
7444e96bf3aSLandon J. Fuller 
7454e96bf3aSLandon J. Fuller 	/* Clear request */
7464e96bf3aSLandon J. Fuller 	BHND_CLKCTL_LOCK(clkctl);
7474e96bf3aSLandon J. Fuller 	BHND_CLKCTL_SET_4(clkctl, 0x0, mask);
7484e96bf3aSLandon J. Fuller 	BHND_CLKCTL_UNLOCK(clkctl);
7494e96bf3aSLandon J. Fuller 
7504e96bf3aSLandon J. Fuller 	return (0);
751f90f4b65SLandon J. Fuller }
752f90f4b65SLandon J. Fuller 
753f90f4b65SLandon J. Fuller /**
754386fb140SAdrian Chadd  * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID().
7554ad7e9b0SAdrian Chadd  *
7564ad7e9b0SAdrian Chadd  * This implementation assumes that port and region numbers are 0-indexed and
7574ad7e9b0SAdrian Chadd  * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and
7584ad7e9b0SAdrian Chadd  * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall
7594ad7e9b0SAdrian Chadd  * within the defined range.
7604ad7e9b0SAdrian Chadd  */
761386fb140SAdrian Chadd static bool
bhnd_generic_is_region_valid(device_t dev,device_t child,bhnd_port_type type,u_int port,u_int region)7624ad7e9b0SAdrian Chadd bhnd_generic_is_region_valid(device_t dev, device_t child,
7634ad7e9b0SAdrian Chadd     bhnd_port_type type, u_int port, u_int region)
7644ad7e9b0SAdrian Chadd {
7654ad7e9b0SAdrian Chadd 	if (port >= bhnd_get_port_count(child, type))
7664ad7e9b0SAdrian Chadd 		return (false);
7674ad7e9b0SAdrian Chadd 
7684ad7e9b0SAdrian Chadd 	if (region >= bhnd_get_region_count(child, type, port))
7694ad7e9b0SAdrian Chadd 		return (false);
7704ad7e9b0SAdrian Chadd 
7714ad7e9b0SAdrian Chadd 	return (true);
7724ad7e9b0SAdrian Chadd }
7734ad7e9b0SAdrian Chadd 
7744ad7e9b0SAdrian Chadd /**
775fdedcd9fSLandon J. Fuller  * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR().
776fdedcd9fSLandon J. Fuller  *
7778e35bf83SLandon J. Fuller  * This implementation searches @p dev for a registered NVRAM child device.
778fdedcd9fSLandon J. Fuller  *
7798e35bf83SLandon J. Fuller  * If no NVRAM device is registered with @p dev, the request is delegated to
780fdedcd9fSLandon J. Fuller  * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
781fdedcd9fSLandon J. Fuller  */
782fdedcd9fSLandon J. Fuller int
bhnd_generic_get_nvram_var(device_t dev,device_t child,const char * name,void * buf,size_t * size,bhnd_nvram_type type)783fdedcd9fSLandon J. Fuller bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name,
7841728aef2SLandon J. Fuller     void *buf, size_t *size, bhnd_nvram_type type)
785fdedcd9fSLandon J. Fuller {
786fdedcd9fSLandon J. Fuller 	device_t		 nvram, parent;
7878e35bf83SLandon J. Fuller 	int			 error;
788fdedcd9fSLandon J. Fuller 
789fdedcd9fSLandon J. Fuller 	/* If a NVRAM device is available, consult it first */
7908e35bf83SLandon J. Fuller 	nvram = bhnd_retain_provider(child, BHND_SERVICE_NVRAM);
7918e35bf83SLandon J. Fuller 	if (nvram != NULL) {
7928e35bf83SLandon J. Fuller 		error = BHND_NVRAM_GETVAR(nvram, name, buf, size, type);
7938e35bf83SLandon J. Fuller 		bhnd_release_provider(child, nvram, BHND_SERVICE_NVRAM);
7948e35bf83SLandon J. Fuller 		return (error);
7958e35bf83SLandon J. Fuller 	}
796fdedcd9fSLandon J. Fuller 
797fdedcd9fSLandon J. Fuller 	/* Otherwise, try to delegate to parent */
798fdedcd9fSLandon J. Fuller 	if ((parent = device_get_parent(dev)) == NULL)
799fdedcd9fSLandon J. Fuller 		return (ENODEV);
800fdedcd9fSLandon J. Fuller 
801fdedcd9fSLandon J. Fuller 	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
8021728aef2SLandon J. Fuller 	    name, buf, size, type));
803fdedcd9fSLandon J. Fuller }
804fdedcd9fSLandon J. Fuller 
805fdedcd9fSLandon J. Fuller /**
806386fb140SAdrian Chadd  * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD().
8074ad7e9b0SAdrian Chadd  *
8084ad7e9b0SAdrian Chadd  * This implementation requests the device's struct resource_list via
8094ad7e9b0SAdrian Chadd  * BUS_GET_RESOURCE_LIST.
8104ad7e9b0SAdrian Chadd  */
8114ad7e9b0SAdrian Chadd int
bhnd_generic_print_child(device_t dev,device_t child)8124ad7e9b0SAdrian Chadd bhnd_generic_print_child(device_t dev, device_t child)
8134ad7e9b0SAdrian Chadd {
8144ad7e9b0SAdrian Chadd 	struct resource_list	*rl;
8154ad7e9b0SAdrian Chadd 	int			retval = 0;
8164ad7e9b0SAdrian Chadd 
8174ad7e9b0SAdrian Chadd 	retval += bus_print_child_header(dev, child);
8184ad7e9b0SAdrian Chadd 
8194ad7e9b0SAdrian Chadd 	rl = BUS_GET_RESOURCE_LIST(dev, child);
820824b48efSLandon J. Fuller 
8214ad7e9b0SAdrian Chadd 	if (rl != NULL) {
8224ad7e9b0SAdrian Chadd 		retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
823f8fd3fb5SJustin Hibbits 		    "%#jx");
824824b48efSLandon J. Fuller 
825824b48efSLandon J. Fuller 		retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
826824b48efSLandon J. Fuller 		    "%#jd");
8274ad7e9b0SAdrian Chadd 	}
8284ad7e9b0SAdrian Chadd 
8294ad7e9b0SAdrian Chadd 	retval += printf(" at core %u", bhnd_get_core_index(child));
8304ad7e9b0SAdrian Chadd 
8314ad7e9b0SAdrian Chadd 	retval += bus_print_child_domain(dev, child);
8324ad7e9b0SAdrian Chadd 	retval += bus_print_child_footer(dev, child);
8334ad7e9b0SAdrian Chadd 
8344ad7e9b0SAdrian Chadd 	return (retval);
8354ad7e9b0SAdrian Chadd }
8364ad7e9b0SAdrian Chadd 
8374ad7e9b0SAdrian Chadd /**
838386fb140SAdrian Chadd  * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH().
8394ad7e9b0SAdrian Chadd  *
8404ad7e9b0SAdrian Chadd  * This implementation requests the device's struct resource_list via
8414ad7e9b0SAdrian Chadd  * BUS_GET_RESOURCE_LIST.
8424ad7e9b0SAdrian Chadd  */
8434ad7e9b0SAdrian Chadd void
bhnd_generic_probe_nomatch(device_t dev,device_t child)8444ad7e9b0SAdrian Chadd bhnd_generic_probe_nomatch(device_t dev, device_t child)
8454ad7e9b0SAdrian Chadd {
8464ad7e9b0SAdrian Chadd 	struct resource_list		*rl;
8474ad7e9b0SAdrian Chadd 	const struct bhnd_nomatch	*nm;
8484ad7e9b0SAdrian Chadd 	bool				 report;
8494ad7e9b0SAdrian Chadd 
8504ad7e9b0SAdrian Chadd 	/* Fetch reporting configuration for this device */
8514ad7e9b0SAdrian Chadd 	report = true;
8524ad7e9b0SAdrian Chadd 	for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) {
8534ad7e9b0SAdrian Chadd 		if (nm->vendor != bhnd_get_vendor(child))
8544ad7e9b0SAdrian Chadd 			continue;
8554ad7e9b0SAdrian Chadd 
8564ad7e9b0SAdrian Chadd 		if (nm->device != bhnd_get_device(child))
8574ad7e9b0SAdrian Chadd 			continue;
8584ad7e9b0SAdrian Chadd 
8594ad7e9b0SAdrian Chadd 		report = false;
8604ad7e9b0SAdrian Chadd 		if (bootverbose && nm->if_verbose)
8614ad7e9b0SAdrian Chadd 			report = true;
8624ad7e9b0SAdrian Chadd 		break;
8634ad7e9b0SAdrian Chadd 	}
8644ad7e9b0SAdrian Chadd 
8654ad7e9b0SAdrian Chadd 	if (!report)
8664ad7e9b0SAdrian Chadd 		return;
8674ad7e9b0SAdrian Chadd 
8684ad7e9b0SAdrian Chadd 	/* Print the non-matched device info */
8693fcd245eSLandon J. Fuller 	device_printf(dev, "<%s %s, rev %hhu>", bhnd_get_vendor_name(child),
8703fcd245eSLandon J. Fuller 		bhnd_get_device_name(child), bhnd_get_hwrev(child));
8714ad7e9b0SAdrian Chadd 
8724ad7e9b0SAdrian Chadd 	rl = BUS_GET_RESOURCE_LIST(dev, child);
873824b48efSLandon J. Fuller 	if (rl != NULL) {
874f8fd3fb5SJustin Hibbits 		resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
875824b48efSLandon J. Fuller 		resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%#jd");
876824b48efSLandon J. Fuller 	}
8774ad7e9b0SAdrian Chadd 
8784ad7e9b0SAdrian Chadd 	printf(" at core %u (no driver attached)\n",
8794ad7e9b0SAdrian Chadd 	    bhnd_get_core_index(child));
8804ad7e9b0SAdrian Chadd }
8814ad7e9b0SAdrian Chadd 
8824ad7e9b0SAdrian Chadd static int
bhnd_child_pnpinfo(device_t dev,device_t child,struct sbuf * sb)883ddfc9c4cSWarner Losh bhnd_child_pnpinfo(device_t dev, device_t child, struct sbuf *sb)
8844ad7e9b0SAdrian Chadd {
885ddfc9c4cSWarner Losh 	if (device_get_parent(child) != dev)
886ddfc9c4cSWarner Losh 		return (BUS_CHILD_PNPINFO(device_get_parent(dev), child, sb));
8874ad7e9b0SAdrian Chadd 
888ddfc9c4cSWarner Losh 	sbuf_printf(sb, "vendor=0x%hx device=0x%hx rev=0x%hhx",
8894ad7e9b0SAdrian Chadd 	    bhnd_get_vendor(child), bhnd_get_device(child),
8904ad7e9b0SAdrian Chadd 	    bhnd_get_hwrev(child));
8914ad7e9b0SAdrian Chadd 
8924ad7e9b0SAdrian Chadd 	return (0);
8934ad7e9b0SAdrian Chadd }
8944ad7e9b0SAdrian Chadd 
8954ad7e9b0SAdrian Chadd static int
bhnd_child_location(device_t dev,device_t child,struct sbuf * sb)896ddfc9c4cSWarner Losh bhnd_child_location(device_t dev, device_t child, struct sbuf *sb)
8974ad7e9b0SAdrian Chadd {
8984ad7e9b0SAdrian Chadd 	bhnd_addr_t	addr;
8994ad7e9b0SAdrian Chadd 	bhnd_size_t	size;
9004ad7e9b0SAdrian Chadd 
901ddfc9c4cSWarner Losh 	if (device_get_parent(child) != dev)
902ddfc9c4cSWarner Losh 		return (BUS_CHILD_LOCATION(device_get_parent(dev), child, sb));
9034ad7e9b0SAdrian Chadd 
904ddfc9c4cSWarner Losh 	if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size))
9054ad7e9b0SAdrian Chadd 		return (0);
9064ad7e9b0SAdrian Chadd 
907ddfc9c4cSWarner Losh 	sbuf_printf(sb, "port0.0=0x%llx", (unsigned long long) addr);
9084ad7e9b0SAdrian Chadd 	return (0);
9094ad7e9b0SAdrian Chadd }
9104ad7e9b0SAdrian Chadd 
9114ad7e9b0SAdrian Chadd /**
912688fc8c0SLandon J. Fuller  * Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED().
913688fc8c0SLandon J. Fuller  *
914688fc8c0SLandon J. Fuller  * This implementation manages internal bhnd(4) state, and must be called
915688fc8c0SLandon J. Fuller  * by subclassing drivers.
916688fc8c0SLandon J. Fuller  */
917688fc8c0SLandon J. Fuller void
bhnd_generic_child_deleted(device_t dev,device_t child)918688fc8c0SLandon J. Fuller bhnd_generic_child_deleted(device_t dev, device_t child)
919688fc8c0SLandon J. Fuller {
920688fc8c0SLandon J. Fuller 
921688fc8c0SLandon J. Fuller 	/* Free device info */
9228a03f98aSLandon J. Fuller 	if (bhnd_get_pmu_info(child) != NULL) {
923f90f4b65SLandon J. Fuller 		/* Releasing PMU requests automatically would be nice,
924f90f4b65SLandon J. Fuller 		 * but we can't reference per-core PMU register
925f90f4b65SLandon J. Fuller 		 * resource after driver detach */
926f90f4b65SLandon J. Fuller 		panic("%s leaked device pmu state\n",
927f90f4b65SLandon J. Fuller 		    device_get_nameunit(child));
928f90f4b65SLandon J. Fuller 	}
929688fc8c0SLandon J. Fuller }
930688fc8c0SLandon J. Fuller 
931688fc8c0SLandon J. Fuller /**
9324ad7e9b0SAdrian Chadd  * Helper function for implementing BUS_SUSPEND_CHILD().
9334ad7e9b0SAdrian Chadd  *
9344ad7e9b0SAdrian Chadd  * TODO: Power management
9354ad7e9b0SAdrian Chadd  *
9364ad7e9b0SAdrian Chadd  * If @p child is not a direct child of @p dev, suspension is delegated to
9374ad7e9b0SAdrian Chadd  * the @p dev parent.
9384ad7e9b0SAdrian Chadd  */
9394ad7e9b0SAdrian Chadd int
bhnd_generic_suspend_child(device_t dev,device_t child)9404ad7e9b0SAdrian Chadd bhnd_generic_suspend_child(device_t dev, device_t child)
9414ad7e9b0SAdrian Chadd {
9424ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
9434ad7e9b0SAdrian Chadd 		BUS_SUSPEND_CHILD(device_get_parent(dev), child);
9444ad7e9b0SAdrian Chadd 
9454ad7e9b0SAdrian Chadd 	return bus_generic_suspend_child(dev, child);
9464ad7e9b0SAdrian Chadd }
9474ad7e9b0SAdrian Chadd 
9484ad7e9b0SAdrian Chadd /**
9494ad7e9b0SAdrian Chadd  * Helper function for implementing BUS_RESUME_CHILD().
9504ad7e9b0SAdrian Chadd  *
9514ad7e9b0SAdrian Chadd  * TODO: Power management
9524ad7e9b0SAdrian Chadd  *
9534ad7e9b0SAdrian Chadd  * If @p child is not a direct child of @p dev, suspension is delegated to
9544ad7e9b0SAdrian Chadd  * the @p dev parent.
9554ad7e9b0SAdrian Chadd  */
9564ad7e9b0SAdrian Chadd int
bhnd_generic_resume_child(device_t dev,device_t child)9574ad7e9b0SAdrian Chadd bhnd_generic_resume_child(device_t dev, device_t child)
9584ad7e9b0SAdrian Chadd {
9594ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
9604ad7e9b0SAdrian Chadd 		BUS_RESUME_CHILD(device_get_parent(dev), child);
9614ad7e9b0SAdrian Chadd 
9624ad7e9b0SAdrian Chadd 	return bus_generic_resume_child(dev, child);
9634ad7e9b0SAdrian Chadd }
9644ad7e9b0SAdrian Chadd 
965caeff9a3SLandon J. Fuller /**
966caeff9a3SLandon J. Fuller  * Default bhnd(4) bus driver implementation of BUS_SETUP_INTR().
967caeff9a3SLandon J. Fuller  *
968caeff9a3SLandon J. Fuller  * This implementation of BUS_SETUP_INTR() will delegate interrupt setup
969caeff9a3SLandon J. Fuller  * to the parent of @p dev, if any.
970caeff9a3SLandon J. Fuller  */
971caeff9a3SLandon J. Fuller int
bhnd_generic_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_filter_t * filter,driver_intr_t * intr,void * arg,void ** cookiep)972caeff9a3SLandon J. Fuller bhnd_generic_setup_intr(device_t dev, device_t child, struct resource *irq,
973caeff9a3SLandon J. Fuller     int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
974caeff9a3SLandon J. Fuller     void **cookiep)
975caeff9a3SLandon J. Fuller {
976caeff9a3SLandon J. Fuller 	return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr,
977caeff9a3SLandon J. Fuller 	    arg, cookiep));
978caeff9a3SLandon J. Fuller }
979caeff9a3SLandon J. Fuller 
9804ad7e9b0SAdrian Chadd /*
9814ad7e9b0SAdrian Chadd  * Delegate all indirect I/O to the parent device. When inherited by
9824ad7e9b0SAdrian Chadd  * non-bridged bus implementations, resources will never be marked as
9830e141e3cSAdrian Chadd  * indirect, and these methods will never be called.
9844ad7e9b0SAdrian Chadd  */
985a73ac06dSAdrian Chadd #define	BHND_IO_READ(_type, _name, _method)				\
986a73ac06dSAdrian Chadd static _type								\
987a73ac06dSAdrian Chadd bhnd_read_ ## _name (device_t dev, device_t child,			\
988a73ac06dSAdrian Chadd     struct bhnd_resource *r, bus_size_t offset)				\
989a73ac06dSAdrian Chadd {									\
990a73ac06dSAdrian Chadd 	return (BHND_BUS_READ_ ## _method(				\
991a73ac06dSAdrian Chadd 		    device_get_parent(dev), child, r, offset));		\
9924ad7e9b0SAdrian Chadd }
9934ad7e9b0SAdrian Chadd 
994a73ac06dSAdrian Chadd #define	BHND_IO_WRITE(_type, _name, _method)				\
995a73ac06dSAdrian Chadd static void								\
996a73ac06dSAdrian Chadd bhnd_write_ ## _name (device_t dev, device_t child,			\
997a73ac06dSAdrian Chadd     struct bhnd_resource *r, bus_size_t offset, _type value)		\
998a73ac06dSAdrian Chadd {									\
999a73ac06dSAdrian Chadd 	return (BHND_BUS_WRITE_ ## _method(				\
1000a73ac06dSAdrian Chadd 		    device_get_parent(dev), child, r, offset,		\
1001a73ac06dSAdrian Chadd 		    value));	\
10024ad7e9b0SAdrian Chadd }
10034ad7e9b0SAdrian Chadd 
10040e141e3cSAdrian Chadd #define	BHND_IO_MISC(_type, _op, _method)				\
1005a73ac06dSAdrian Chadd static void								\
10060e141e3cSAdrian Chadd bhnd_ ## _op (device_t dev, device_t child,				\
10070e141e3cSAdrian Chadd     struct bhnd_resource *r, bus_size_t offset, _type datap,		\
1008a73ac06dSAdrian Chadd     bus_size_t count)							\
1009a73ac06dSAdrian Chadd {									\
1010a73ac06dSAdrian Chadd 	BHND_BUS_ ## _method(device_get_parent(dev), child, r,		\
1011a73ac06dSAdrian Chadd 	    offset, datap, count);					\
10124ad7e9b0SAdrian Chadd }
10134ad7e9b0SAdrian Chadd 
1014a73ac06dSAdrian Chadd #define	BHND_IO_METHODS(_type, _size)					\
1015a73ac06dSAdrian Chadd 	BHND_IO_READ(_type, _size, _size)				\
1016a73ac06dSAdrian Chadd 	BHND_IO_WRITE(_type, _size, _size)				\
1017a73ac06dSAdrian Chadd 									\
1018a73ac06dSAdrian Chadd 	BHND_IO_READ(_type, stream_ ## _size, STREAM_ ## _size)		\
1019a73ac06dSAdrian Chadd 	BHND_IO_WRITE(_type, stream_ ## _size, STREAM_ ## _size)	\
1020a73ac06dSAdrian Chadd 									\
10210e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, read_multi_ ## _size,			\
10220e141e3cSAdrian Chadd 	    READ_MULTI_ ## _size)					\
10230e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, write_multi_ ## _size,			\
10240e141e3cSAdrian Chadd 	    WRITE_MULTI_ ## _size)					\
1025a73ac06dSAdrian Chadd 									\
10260e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, read_multi_stream_ ## _size,		\
1027a73ac06dSAdrian Chadd 	   READ_MULTI_STREAM_ ## _size)					\
10280e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, write_multi_stream_ ## _size,		\
1029a73ac06dSAdrian Chadd 	   WRITE_MULTI_STREAM_ ## _size)				\
10300e141e3cSAdrian Chadd 									\
10310e141e3cSAdrian Chadd 	BHND_IO_MISC(_type, set_multi_ ## _size, SET_MULTI_ ## _size)	\
10320e141e3cSAdrian Chadd 	BHND_IO_MISC(_type, set_region_ ## _size, SET_REGION_ ## _size)	\
10330e141e3cSAdrian Chadd 									\
10340e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, read_region_ ## _size,			\
10350e141e3cSAdrian Chadd 	    READ_REGION_ ## _size)					\
10360e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, write_region_ ## _size,			\
10370e141e3cSAdrian Chadd 	    WRITE_REGION_ ## _size)					\
10380e141e3cSAdrian Chadd 									\
10390e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, read_region_stream_ ## _size,		\
10400e141e3cSAdrian Chadd 	    READ_REGION_STREAM_ ## _size)				\
10410e141e3cSAdrian Chadd 	BHND_IO_MISC(_type*, write_region_stream_ ## _size,		\
10420e141e3cSAdrian Chadd 	    WRITE_REGION_STREAM_ ## _size)				\
10434ad7e9b0SAdrian Chadd 
1044a73ac06dSAdrian Chadd BHND_IO_METHODS(uint8_t, 1);
1045a73ac06dSAdrian Chadd BHND_IO_METHODS(uint16_t, 2);
1046a73ac06dSAdrian Chadd BHND_IO_METHODS(uint32_t, 4);
10474ad7e9b0SAdrian Chadd 
10484ad7e9b0SAdrian Chadd static void
bhnd_barrier(device_t dev,device_t child,struct bhnd_resource * r,bus_size_t offset,bus_size_t length,int flags)10494ad7e9b0SAdrian Chadd bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r,
10504ad7e9b0SAdrian Chadd     bus_size_t offset, bus_size_t length, int flags)
10514ad7e9b0SAdrian Chadd {
10524ad7e9b0SAdrian Chadd 	BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length,
10534ad7e9b0SAdrian Chadd 	    flags);
10544ad7e9b0SAdrian Chadd }
10554ad7e9b0SAdrian Chadd 
10564ad7e9b0SAdrian Chadd static device_method_t bhnd_methods[] = {
10574ad7e9b0SAdrian Chadd 	/* Device interface */ \
10584ad7e9b0SAdrian Chadd 	DEVMETHOD(device_attach,		bhnd_generic_attach),
10594ad7e9b0SAdrian Chadd 	DEVMETHOD(device_detach,		bhnd_generic_detach),
10604ad7e9b0SAdrian Chadd 	DEVMETHOD(device_shutdown,		bhnd_generic_shutdown),
10614ad7e9b0SAdrian Chadd 	DEVMETHOD(device_suspend,		bhnd_generic_suspend),
10624ad7e9b0SAdrian Chadd 	DEVMETHOD(device_resume,		bhnd_generic_resume),
10634ad7e9b0SAdrian Chadd 
10644ad7e9b0SAdrian Chadd 	/* Bus interface */
1065688fc8c0SLandon J. Fuller 	DEVMETHOD(bus_child_deleted,		bhnd_generic_child_deleted),
10664ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_probe_nomatch,		bhnd_generic_probe_nomatch),
10674ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_print_child,		bhnd_generic_print_child),
1068ddfc9c4cSWarner Losh 	DEVMETHOD(bus_child_pnpinfo,		bhnd_child_pnpinfo),
1069ddfc9c4cSWarner Losh 	DEVMETHOD(bus_child_location,		bhnd_child_location),
10704ad7e9b0SAdrian Chadd 
10714ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_suspend_child,		bhnd_generic_suspend_child),
10724ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_resume_child,		bhnd_generic_resume_child),
10734ad7e9b0SAdrian Chadd 
10744ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
10754ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
10764ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_delete_resource,		bus_generic_rl_delete_resource),
10774ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_alloc_resource,		bus_generic_rl_alloc_resource),
10784ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_adjust_resource,		bus_generic_adjust_resource),
10794ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_release_resource,		bus_generic_rl_release_resource),
10804ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
10814ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
10824ad7e9b0SAdrian Chadd 
1083caeff9a3SLandon J. Fuller 	DEVMETHOD(bus_setup_intr,		bhnd_generic_setup_intr),
10844ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
10854ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_config_intr,		bus_generic_config_intr),
10864ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_bind_intr,		bus_generic_bind_intr),
10874ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_describe_intr,		bus_generic_describe_intr),
10884ad7e9b0SAdrian Chadd 
10894ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_get_dma_tag,		bus_generic_get_dma_tag),
10904ad7e9b0SAdrian Chadd 
10914ad7e9b0SAdrian Chadd 	/* BHND interface */
1092386fb140SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_chipid,		bhnd_bus_generic_get_chipid),
1093386fb140SAdrian Chadd 	DEVMETHOD(bhnd_bus_is_hw_disabled,	bhnd_bus_generic_is_hw_disabled),
1094f90f4b65SLandon J. Fuller 
1095f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_probe_order,	bhnd_generic_get_probe_order),
1096f90f4b65SLandon J. Fuller 
1097f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_alloc_pmu,		bhnd_generic_alloc_pmu),
1098f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_release_pmu,		bhnd_generic_release_pmu),
1099f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_request_clock,	bhnd_generic_request_clock),
1100f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_enable_clocks,	bhnd_generic_enable_clocks),
1101f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_request_ext_rsrc,	bhnd_generic_request_ext_rsrc),
1102f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_release_ext_rsrc,	bhnd_generic_release_ext_rsrc),
11034e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_clock_latency,	bhnd_generic_get_clock_latency),
11044e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_clock_freq,	bhnd_generic_get_clock_freq),
1105f90f4b65SLandon J. Fuller 
1106f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_is_region_valid,	bhnd_generic_is_region_valid),
1107fdedcd9fSLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_nvram_var,	bhnd_generic_get_nvram_var),
11080e141e3cSAdrian Chadd 
11090e141e3cSAdrian Chadd 	/* BHND interface (bus I/O) */
11104ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_read_1,		bhnd_read_1),
11114ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_read_2,		bhnd_read_2),
11124ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_read_4,		bhnd_read_4),
11134ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_write_1,		bhnd_write_1),
11144ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_write_2,		bhnd_write_2),
11154ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_write_4,		bhnd_write_4),
11160e141e3cSAdrian Chadd 
1117a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_stream_1,	bhnd_read_stream_1),
1118a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_stream_2,	bhnd_read_stream_2),
1119a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_stream_4,	bhnd_read_stream_4),
1120a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_stream_1,	bhnd_write_stream_1),
1121a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_stream_2,	bhnd_write_stream_2),
1122a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_stream_4,	bhnd_write_stream_4),
1123a73ac06dSAdrian Chadd 
1124a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_multi_1,	bhnd_read_multi_1),
1125a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_multi_2,	bhnd_read_multi_2),
1126a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_multi_4,	bhnd_read_multi_4),
1127a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_multi_1,	bhnd_write_multi_1),
1128a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_multi_2,	bhnd_write_multi_2),
1129a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_multi_4,	bhnd_write_multi_4),
1130a73ac06dSAdrian Chadd 
1131a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_multi_stream_1,	bhnd_read_multi_stream_1),
1132a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_multi_stream_2,	bhnd_read_multi_stream_2),
1133a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_multi_stream_4,	bhnd_read_multi_stream_4),
1134a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_multi_stream_1,bhnd_write_multi_stream_1),
1135a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_multi_stream_2,bhnd_write_multi_stream_2),
1136a73ac06dSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_multi_stream_4,bhnd_write_multi_stream_4),
1137a73ac06dSAdrian Chadd 
11380e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_set_multi_1,		bhnd_set_multi_1),
11390e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_set_multi_2,		bhnd_set_multi_2),
11400e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_set_multi_4,		bhnd_set_multi_4),
11410e141e3cSAdrian Chadd 
11420e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_set_region_1,	bhnd_set_region_1),
11430e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_set_region_2,	bhnd_set_region_2),
11440e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_set_region_4,	bhnd_set_region_4),
11450e141e3cSAdrian Chadd 
11460e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_region_1,	bhnd_read_region_1),
11470e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_region_2,	bhnd_read_region_2),
11480e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_region_4,	bhnd_read_region_4),
11490e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_region_1,	bhnd_write_region_1),
11500e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_region_2,	bhnd_write_region_2),
11510e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_region_4,	bhnd_write_region_4),
11520e141e3cSAdrian Chadd 
11530e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_region_stream_1,bhnd_read_region_stream_1),
11540e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_region_stream_2,bhnd_read_region_stream_2),
11550e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_read_region_stream_4,bhnd_read_region_stream_4),
11560e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_region_stream_1, bhnd_write_region_stream_1),
11570e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_region_stream_2, bhnd_write_region_stream_2),
11580e141e3cSAdrian Chadd 	DEVMETHOD(bhnd_bus_write_region_stream_4, bhnd_write_region_stream_4),
11590e141e3cSAdrian Chadd 
11604ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_barrier,			bhnd_barrier),
11614ad7e9b0SAdrian Chadd 
11624ad7e9b0SAdrian Chadd 	DEVMETHOD_END
11634ad7e9b0SAdrian Chadd };
11644ad7e9b0SAdrian Chadd 
11654ad7e9b0SAdrian Chadd DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc));
11664ad7e9b0SAdrian Chadd MODULE_VERSION(bhnd, 1);
1167