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