158158742SRafal Jaworowski /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 406763f5eSNathan Whitehorn * Copyright (c) 2013 Nathan Whitehorn 558158742SRafal Jaworowski * All rights reserved. 658158742SRafal Jaworowski * 758158742SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 858158742SRafal Jaworowski * modification, are permitted provided that the following conditions 958158742SRafal Jaworowski * are met: 1058158742SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 1158158742SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 1258158742SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 1358158742SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 1458158742SRafal Jaworowski * documentation and/or other materials provided with the distribution. 1558158742SRafal Jaworowski * 1658158742SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1758158742SRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1858158742SRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1958158742SRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2058158742SRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2158158742SRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2258158742SRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2358158742SRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2458158742SRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2558158742SRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2658158742SRafal Jaworowski * SUCH DAMAGE. 2758158742SRafal Jaworowski */ 2858158742SRafal Jaworowski 2958158742SRafal Jaworowski #include <sys/param.h> 3058158742SRafal Jaworowski #include <sys/systm.h> 3158158742SRafal Jaworowski #include <sys/module.h> 3258158742SRafal Jaworowski #include <sys/bus.h> 3306763f5eSNathan Whitehorn #include <sys/conf.h> 3406763f5eSNathan Whitehorn #include <sys/kernel.h> 3558158742SRafal Jaworowski #include <sys/rman.h> 3658158742SRafal Jaworowski 3706763f5eSNathan Whitehorn #include <dev/ofw/openfirm.h> 3858158742SRafal Jaworowski #include <dev/ofw/ofw_bus.h> 3958158742SRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 4058158742SRafal Jaworowski 412cc1ad9cSJayachandran C. #include <dev/fdt/simplebus.h> 4258158742SRafal Jaworowski 4358158742SRafal Jaworowski /* 4406763f5eSNathan Whitehorn * Bus interface. 4558158742SRafal Jaworowski */ 4606763f5eSNathan Whitehorn static int simplebus_probe(device_t dev); 4758158742SRafal Jaworowski static struct resource *simplebus_alloc_resource(device_t, device_t, int, 482dd1bdf1SJustin Hibbits int *, rman_res_t, rman_res_t, rman_res_t, u_int); 493cf55328SJohn Baldwin static int simplebus_release_resource(device_t bus, device_t child, 503cf55328SJohn Baldwin int type, int rid, struct resource *r); 5106763f5eSNathan Whitehorn static void simplebus_probe_nomatch(device_t bus, device_t child); 5206763f5eSNathan Whitehorn static int simplebus_print_child(device_t bus, device_t child); 53ecaecbc7SIan Lepore static device_t simplebus_add_child(device_t dev, u_int order, 54ecaecbc7SIan Lepore const char *name, int unit); 55ecaecbc7SIan Lepore static struct resource_list *simplebus_get_resource_list(device_t bus, 56ecaecbc7SIan Lepore device_t child); 573f9a00e3SBartlomiej Grzesik 583f9a00e3SBartlomiej Grzesik static ssize_t simplebus_get_property(device_t bus, device_t child, 59b344de4dSKornel Duleba const char *propname, void *propvalue, size_t size, 60b344de4dSKornel Duleba device_property_type_t type); 6158158742SRafal Jaworowski /* 6206763f5eSNathan Whitehorn * ofw_bus interface 6306763f5eSNathan Whitehorn */ 6406763f5eSNathan Whitehorn static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus, 6506763f5eSNathan Whitehorn device_t child); 6606763f5eSNathan Whitehorn 6706763f5eSNathan Whitehorn /* 6806763f5eSNathan Whitehorn * Driver methods. 6958158742SRafal Jaworowski */ 7058158742SRafal Jaworowski static device_method_t simplebus_methods[] = { 7158158742SRafal Jaworowski /* Device interface */ 7258158742SRafal Jaworowski DEVMETHOD(device_probe, simplebus_probe), 7358158742SRafal Jaworowski DEVMETHOD(device_attach, simplebus_attach), 74b95a8021SMichal Meloun DEVMETHOD(device_detach, simplebus_detach), 75ecaecbc7SIan Lepore DEVMETHOD(device_shutdown, bus_generic_shutdown), 76ecaecbc7SIan Lepore DEVMETHOD(device_suspend, bus_generic_suspend), 77ecaecbc7SIan Lepore DEVMETHOD(device_resume, bus_generic_resume), 7858158742SRafal Jaworowski 7958158742SRafal Jaworowski /* Bus interface */ 80ecaecbc7SIan Lepore DEVMETHOD(bus_add_child, simplebus_add_child), 8158158742SRafal Jaworowski DEVMETHOD(bus_print_child, simplebus_print_child), 8206763f5eSNathan Whitehorn DEVMETHOD(bus_probe_nomatch, simplebus_probe_nomatch), 83ecaecbc7SIan Lepore DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 84ecaecbc7SIan Lepore DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 8506763f5eSNathan Whitehorn DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 8606763f5eSNathan Whitehorn DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 8758158742SRafal Jaworowski DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource), 883cf55328SJohn Baldwin DEVMETHOD(bus_release_resource, simplebus_release_resource), 89*2baed46eSJohn Baldwin DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 90*2baed46eSJohn Baldwin DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 91fef01f04SJohn Baldwin DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 92d77f2092SJohn Baldwin DEVMETHOD(bus_map_resource, bus_generic_map_resource), 93d77f2092SJohn Baldwin DEVMETHOD(bus_unmap_resource, bus_generic_unmap_resource), 94ecaecbc7SIan Lepore DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 95ecaecbc7SIan Lepore DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 96e89d0785SJohn Baldwin DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 97ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, ofw_bus_gen_child_pnpinfo), 98ecaecbc7SIan Lepore DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list), 993f9a00e3SBartlomiej Grzesik DEVMETHOD(bus_get_property, simplebus_get_property), 1007b5d62bbSTakanori Watanabe DEVMETHOD(bus_get_device_path, ofw_bus_gen_get_device_path), 10158158742SRafal Jaworowski 10206763f5eSNathan Whitehorn /* ofw_bus interface */ 10358158742SRafal Jaworowski DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo), 10458158742SRafal Jaworowski DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 10558158742SRafal Jaworowski DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 10658158742SRafal Jaworowski DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 10758158742SRafal Jaworowski DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 10858158742SRafal Jaworowski DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 10958158742SRafal Jaworowski 11006763f5eSNathan Whitehorn DEVMETHOD_END 11158158742SRafal Jaworowski }; 11258158742SRafal Jaworowski 1132cc1ad9cSJayachandran C. DEFINE_CLASS_0(simplebus, simplebus_driver, simplebus_methods, 1142cc1ad9cSJayachandran C. sizeof(struct simplebus_softc)); 1152cc1ad9cSJayachandran C. 1160a73fdb9SJohn Baldwin EARLY_DRIVER_MODULE(simplebus, ofwbus, simplebus_driver, 0, 0, BUS_PASS_BUS); 1170a73fdb9SJohn Baldwin EARLY_DRIVER_MODULE(simplebus, simplebus, simplebus_driver, 0, 0, 1180a73fdb9SJohn Baldwin BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 11958158742SRafal Jaworowski 12058158742SRafal Jaworowski static int 12158158742SRafal Jaworowski simplebus_probe(device_t dev) 12258158742SRafal Jaworowski { 12358158742SRafal Jaworowski 124add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 125add35ed5SIan Lepore return (ENXIO); 1268dc348a4SMichal Meloun /* 1278dc348a4SMichal Meloun * XXX We should attach only to pure' compatible = "simple-bus"', 1288dc348a4SMichal Meloun * without any other compatible string. 1298dc348a4SMichal Meloun * For now, filter only know cases: 1308dc348a4SMichal Meloun * "syscon", "simple-bus"; is handled by fdt/syscon driver 1318dc348a4SMichal Meloun * "simple-mfd", "simple-bus"; is handled by fdt/simple-mfd driver 1328dc348a4SMichal Meloun */ 1338dc348a4SMichal Meloun if (ofw_bus_is_compatible(dev, "syscon") || 1348dc348a4SMichal Meloun ofw_bus_is_compatible(dev, "simple-mfd")) 1358dc348a4SMichal Meloun return (ENXIO); 136add35ed5SIan Lepore 1372a74fe2cSIan Lepore /* 1382a74fe2cSIan Lepore * FDT data puts a "simple-bus" compatible string on many things that 139db4fcadfSConrad Meyer * have children but aren't really buses in our world. Without a 1402a74fe2cSIan Lepore * ranges property we will fail to attach, so just fail to probe too. 1412a74fe2cSIan Lepore */ 1422a74fe2cSIan Lepore if (!(ofw_bus_is_compatible(dev, "simple-bus") && 1432a74fe2cSIan Lepore ofw_bus_has_prop(dev, "ranges")) && 14406763f5eSNathan Whitehorn (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev), 14506763f5eSNathan Whitehorn "soc") != 0)) 14658158742SRafal Jaworowski return (ENXIO); 14758158742SRafal Jaworowski 14858158742SRafal Jaworowski device_set_desc(dev, "Flattened device tree simple bus"); 14958158742SRafal Jaworowski 1502737a5a9SAleksandr Rybalko return (BUS_PROBE_GENERIC); 15158158742SRafal Jaworowski } 15258158742SRafal Jaworowski 153bc9b178cSAndrew Turner int 154b95a8021SMichal Meloun simplebus_attach_impl(device_t dev) 15558158742SRafal Jaworowski { 15658158742SRafal Jaworowski struct simplebus_softc *sc; 15706763f5eSNathan Whitehorn phandle_t node; 15858158742SRafal Jaworowski 15958158742SRafal Jaworowski sc = device_get_softc(dev); 160ecaecbc7SIan Lepore simplebus_init(dev, 0); 161bc9b178cSAndrew Turner if ((sc->flags & SB_FLAG_NO_RANGES) == 0 && 162bc9b178cSAndrew Turner simplebus_fill_ranges(sc->node, sc) < 0) { 163ecaecbc7SIan Lepore device_printf(dev, "could not get ranges\n"); 164ecaecbc7SIan Lepore return (ENXIO); 165ecaecbc7SIan Lepore } 16658158742SRafal Jaworowski 167ecaecbc7SIan Lepore /* 168ecaecbc7SIan Lepore * In principle, simplebus could have an interrupt map, but ignore that 169ecaecbc7SIan Lepore * for now 170ecaecbc7SIan Lepore */ 171ecaecbc7SIan Lepore 172ecaecbc7SIan Lepore for (node = OF_child(sc->node); node > 0; node = OF_peer(node)) 173ecaecbc7SIan Lepore simplebus_add_device(dev, node, 0, NULL, -1, NULL); 174b95a8021SMichal Meloun 175b95a8021SMichal Meloun return (0); 176b95a8021SMichal Meloun } 177b95a8021SMichal Meloun 178b95a8021SMichal Meloun int 179b95a8021SMichal Meloun simplebus_attach(device_t dev) 180b95a8021SMichal Meloun { 181b95a8021SMichal Meloun int rv; 182b95a8021SMichal Meloun 183b95a8021SMichal Meloun rv = simplebus_attach_impl(dev); 184b95a8021SMichal Meloun if (rv != 0) 185b95a8021SMichal Meloun return (rv); 186b95a8021SMichal Meloun 187ecaecbc7SIan Lepore return (bus_generic_attach(dev)); 188ecaecbc7SIan Lepore } 189ecaecbc7SIan Lepore 190b95a8021SMichal Meloun int 191b95a8021SMichal Meloun simplebus_detach(device_t dev) 192b95a8021SMichal Meloun { 193b95a8021SMichal Meloun struct simplebus_softc *sc; 194b95a8021SMichal Meloun 195b95a8021SMichal Meloun sc = device_get_softc(dev); 196b95a8021SMichal Meloun if (sc->ranges != NULL) 197b95a8021SMichal Meloun free(sc->ranges, M_DEVBUF); 198b95a8021SMichal Meloun 199b95a8021SMichal Meloun return (bus_generic_detach(dev)); 200b95a8021SMichal Meloun } 201b95a8021SMichal Meloun 202ecaecbc7SIan Lepore void 203ecaecbc7SIan Lepore simplebus_init(device_t dev, phandle_t node) 204ecaecbc7SIan Lepore { 205ecaecbc7SIan Lepore struct simplebus_softc *sc; 206ecaecbc7SIan Lepore 207ecaecbc7SIan Lepore sc = device_get_softc(dev); 208ecaecbc7SIan Lepore if (node == 0) 209ecaecbc7SIan Lepore node = ofw_bus_get_node(dev); 21006763f5eSNathan Whitehorn sc->dev = dev; 21106763f5eSNathan Whitehorn sc->node = node; 21206763f5eSNathan Whitehorn 21358158742SRafal Jaworowski /* 21406763f5eSNathan Whitehorn * Some important numbers 21558158742SRafal Jaworowski */ 21606763f5eSNathan Whitehorn sc->acells = 2; 21706763f5eSNathan Whitehorn OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); 21806763f5eSNathan Whitehorn sc->scells = 1; 21906763f5eSNathan Whitehorn OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); 22058158742SRafal Jaworowski } 22158158742SRafal Jaworowski 2222091650bSEmmanuel Vadot int 22306763f5eSNathan Whitehorn simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc) 22458158742SRafal Jaworowski { 22506763f5eSNathan Whitehorn int host_address_cells; 22606763f5eSNathan Whitehorn cell_t *base_ranges; 22706763f5eSNathan Whitehorn ssize_t nbase_ranges; 22806763f5eSNathan Whitehorn int err; 22906763f5eSNathan Whitehorn int i, j, k; 23058158742SRafal Jaworowski 23106763f5eSNathan Whitehorn err = OF_searchencprop(OF_parent(node), "#address-cells", 23206763f5eSNathan Whitehorn &host_address_cells, sizeof(host_address_cells)); 23306763f5eSNathan Whitehorn if (err <= 0) 23406763f5eSNathan Whitehorn return (-1); 23558158742SRafal Jaworowski 23606763f5eSNathan Whitehorn nbase_ranges = OF_getproplen(node, "ranges"); 23706763f5eSNathan Whitehorn if (nbase_ranges < 0) 23806763f5eSNathan Whitehorn return (-1); 23906763f5eSNathan Whitehorn sc->nranges = nbase_ranges / sizeof(cell_t) / 24006763f5eSNathan Whitehorn (sc->acells + host_address_cells + sc->scells); 24106763f5eSNathan Whitehorn if (sc->nranges == 0) 24206763f5eSNathan Whitehorn return (0); 24358158742SRafal Jaworowski 24406763f5eSNathan Whitehorn sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), 24506763f5eSNathan Whitehorn M_DEVBUF, M_WAITOK); 24606763f5eSNathan Whitehorn base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); 24706763f5eSNathan Whitehorn OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 24806763f5eSNathan Whitehorn 24906763f5eSNathan Whitehorn for (i = 0, j = 0; i < sc->nranges; i++) { 25006763f5eSNathan Whitehorn sc->ranges[i].bus = 0; 25106763f5eSNathan Whitehorn for (k = 0; k < sc->acells; k++) { 25206763f5eSNathan Whitehorn sc->ranges[i].bus <<= 32; 25306763f5eSNathan Whitehorn sc->ranges[i].bus |= base_ranges[j++]; 25406763f5eSNathan Whitehorn } 25506763f5eSNathan Whitehorn sc->ranges[i].host = 0; 25606763f5eSNathan Whitehorn for (k = 0; k < host_address_cells; k++) { 25706763f5eSNathan Whitehorn sc->ranges[i].host <<= 32; 25806763f5eSNathan Whitehorn sc->ranges[i].host |= base_ranges[j++]; 25906763f5eSNathan Whitehorn } 26006763f5eSNathan Whitehorn sc->ranges[i].size = 0; 26106763f5eSNathan Whitehorn for (k = 0; k < sc->scells; k++) { 26206763f5eSNathan Whitehorn sc->ranges[i].size <<= 32; 26306763f5eSNathan Whitehorn sc->ranges[i].size |= base_ranges[j++]; 26406763f5eSNathan Whitehorn } 26506763f5eSNathan Whitehorn } 26606763f5eSNathan Whitehorn 26706763f5eSNathan Whitehorn free(base_ranges, M_DEVBUF); 26806763f5eSNathan Whitehorn return (sc->nranges); 26906763f5eSNathan Whitehorn } 27006763f5eSNathan Whitehorn 271ecaecbc7SIan Lepore struct simplebus_devinfo * 272ecaecbc7SIan Lepore simplebus_setup_dinfo(device_t dev, phandle_t node, 273ecaecbc7SIan Lepore struct simplebus_devinfo *di) 27406763f5eSNathan Whitehorn { 27506763f5eSNathan Whitehorn struct simplebus_softc *sc; 27606763f5eSNathan Whitehorn struct simplebus_devinfo *ndi; 27706763f5eSNathan Whitehorn 27806763f5eSNathan Whitehorn sc = device_get_softc(dev); 279ecaecbc7SIan Lepore if (di == NULL) 28006763f5eSNathan Whitehorn ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 281ecaecbc7SIan Lepore else 282ecaecbc7SIan Lepore ndi = di; 28306763f5eSNathan Whitehorn if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { 284ecaecbc7SIan Lepore if (di == NULL) 28506763f5eSNathan Whitehorn free(ndi, M_DEVBUF); 28606763f5eSNathan Whitehorn return (NULL); 28706763f5eSNathan Whitehorn } 28806763f5eSNathan Whitehorn 28906763f5eSNathan Whitehorn resource_list_init(&ndi->rl); 2904b3d9160SZbigniew Bodek ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl); 291a8c5ea04SRuslan Bukin ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL); 29206763f5eSNathan Whitehorn 29306763f5eSNathan Whitehorn return (ndi); 29406763f5eSNathan Whitehorn } 29506763f5eSNathan Whitehorn 296ecaecbc7SIan Lepore device_t 297ecaecbc7SIan Lepore simplebus_add_device(device_t dev, phandle_t node, u_int order, 298ecaecbc7SIan Lepore const char *name, int unit, struct simplebus_devinfo *di) 299ecaecbc7SIan Lepore { 300ecaecbc7SIan Lepore struct simplebus_devinfo *ndi; 301ecaecbc7SIan Lepore device_t cdev; 302ecaecbc7SIan Lepore 303ecaecbc7SIan Lepore if ((ndi = simplebus_setup_dinfo(dev, node, di)) == NULL) 304ecaecbc7SIan Lepore return (NULL); 305ecaecbc7SIan Lepore cdev = device_add_child_ordered(dev, order, name, unit); 306ecaecbc7SIan Lepore if (cdev == NULL) { 307ecaecbc7SIan Lepore device_printf(dev, "<%s>: device_add_child failed\n", 308ecaecbc7SIan Lepore ndi->obdinfo.obd_name); 309ecaecbc7SIan Lepore resource_list_free(&ndi->rl); 310ecaecbc7SIan Lepore ofw_bus_gen_destroy_devinfo(&ndi->obdinfo); 311ecaecbc7SIan Lepore if (di == NULL) 312ecaecbc7SIan Lepore free(ndi, M_DEVBUF); 313ecaecbc7SIan Lepore return (NULL); 314ecaecbc7SIan Lepore } 315ecaecbc7SIan Lepore device_set_ivars(cdev, ndi); 316ecaecbc7SIan Lepore 317ecaecbc7SIan Lepore return(cdev); 318ecaecbc7SIan Lepore } 319ecaecbc7SIan Lepore 320ecaecbc7SIan Lepore static device_t 321ecaecbc7SIan Lepore simplebus_add_child(device_t dev, u_int order, const char *name, int unit) 322ecaecbc7SIan Lepore { 323ecaecbc7SIan Lepore device_t cdev; 324ecaecbc7SIan Lepore struct simplebus_devinfo *ndi; 325ecaecbc7SIan Lepore 326ecaecbc7SIan Lepore cdev = device_add_child_ordered(dev, order, name, unit); 327ecaecbc7SIan Lepore if (cdev == NULL) 328ecaecbc7SIan Lepore return (NULL); 329ecaecbc7SIan Lepore 330ecaecbc7SIan Lepore ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 331ecaecbc7SIan Lepore ndi->obdinfo.obd_node = -1; 332ecaecbc7SIan Lepore resource_list_init(&ndi->rl); 333ecaecbc7SIan Lepore device_set_ivars(cdev, ndi); 334ecaecbc7SIan Lepore 335ecaecbc7SIan Lepore return (cdev); 336ecaecbc7SIan Lepore } 337ecaecbc7SIan Lepore 33806763f5eSNathan Whitehorn static const struct ofw_bus_devinfo * 33906763f5eSNathan Whitehorn simplebus_get_devinfo(device_t bus __unused, device_t child) 34006763f5eSNathan Whitehorn { 34106763f5eSNathan Whitehorn struct simplebus_devinfo *ndi; 34206763f5eSNathan Whitehorn 34306763f5eSNathan Whitehorn ndi = device_get_ivars(child); 3446fc608bfSMichal Meloun if (ndi == NULL) 3456fc608bfSMichal Meloun return (NULL); 34606763f5eSNathan Whitehorn return (&ndi->obdinfo); 34758158742SRafal Jaworowski } 34858158742SRafal Jaworowski 349ecaecbc7SIan Lepore static struct resource_list * 350ecaecbc7SIan Lepore simplebus_get_resource_list(device_t bus __unused, device_t child) 351ecaecbc7SIan Lepore { 352ecaecbc7SIan Lepore struct simplebus_devinfo *ndi; 353ecaecbc7SIan Lepore 354ecaecbc7SIan Lepore ndi = device_get_ivars(child); 3556fc608bfSMichal Meloun if (ndi == NULL) 3566fc608bfSMichal Meloun return (NULL); 357ecaecbc7SIan Lepore return (&ndi->rl); 358ecaecbc7SIan Lepore } 359ecaecbc7SIan Lepore 3603f9a00e3SBartlomiej Grzesik static ssize_t 3613f9a00e3SBartlomiej Grzesik simplebus_get_property(device_t bus, device_t child, const char *propname, 362b344de4dSKornel Duleba void *propvalue, size_t size, device_property_type_t type) 3633f9a00e3SBartlomiej Grzesik { 36499e6980fSBjoern A. Zeeb phandle_t node, xref; 365b344de4dSKornel Duleba ssize_t ret, i; 366b344de4dSKornel Duleba uint32_t *buffer; 367b344de4dSKornel Duleba uint64_t val; 368b344de4dSKornel Duleba 369b344de4dSKornel Duleba switch (type) { 370b344de4dSKornel Duleba case DEVICE_PROP_ANY: 371b344de4dSKornel Duleba case DEVICE_PROP_BUFFER: 372b344de4dSKornel Duleba case DEVICE_PROP_UINT32: 373b344de4dSKornel Duleba case DEVICE_PROP_UINT64: 37499e6980fSBjoern A. Zeeb case DEVICE_PROP_HANDLE: 375b344de4dSKornel Duleba break; 376b344de4dSKornel Duleba default: 377b344de4dSKornel Duleba return (-1); 378b344de4dSKornel Duleba } 3793f9a00e3SBartlomiej Grzesik 38099e6980fSBjoern A. Zeeb node = ofw_bus_get_node(child); 3813f9a00e3SBartlomiej Grzesik if (propvalue == NULL || size == 0) 3823f9a00e3SBartlomiej Grzesik return (OF_getproplen(node, propname)); 3833f9a00e3SBartlomiej Grzesik 384b344de4dSKornel Duleba /* 385b344de4dSKornel Duleba * Integer values are stored in BE format. 386b344de4dSKornel Duleba * If caller declared that the underlying property type is uint32_t 387b344de4dSKornel Duleba * we need to do the conversion to match host endianness. 388b344de4dSKornel Duleba */ 389b344de4dSKornel Duleba if (type == DEVICE_PROP_UINT32) 3903f9a00e3SBartlomiej Grzesik return (OF_getencprop(node, propname, propvalue, size)); 391b344de4dSKornel Duleba 392b344de4dSKornel Duleba /* 393b344de4dSKornel Duleba * uint64_t also requires endianness handling. 394b344de4dSKornel Duleba * In FDT every 8 byte value is stored using two uint32_t variables 395b344de4dSKornel Duleba * in BE format. Now, since the upper bits are stored as the first 396b344de4dSKornel Duleba * of the pair, both halves require swapping. 397b344de4dSKornel Duleba */ 398b344de4dSKornel Duleba if (type == DEVICE_PROP_UINT64) { 399b344de4dSKornel Duleba ret = OF_getencprop(node, propname, propvalue, size); 400b344de4dSKornel Duleba if (ret <= 0) { 401b344de4dSKornel Duleba return (ret); 402b344de4dSKornel Duleba } 403b344de4dSKornel Duleba 404b344de4dSKornel Duleba buffer = (uint32_t *)propvalue; 405b344de4dSKornel Duleba 406b344de4dSKornel Duleba for (i = 0; i < size / 4; i += 2) { 407b344de4dSKornel Duleba val = (uint64_t)buffer[i] << 32 | buffer[i + 1]; 408b344de4dSKornel Duleba ((uint64_t *)buffer)[i / 2] = val; 409b344de4dSKornel Duleba } 410b344de4dSKornel Duleba return (ret); 411b344de4dSKornel Duleba } 412b344de4dSKornel Duleba 41399e6980fSBjoern A. Zeeb if (type == DEVICE_PROP_HANDLE) { 41499e6980fSBjoern A. Zeeb if (size < sizeof(node)) 41599e6980fSBjoern A. Zeeb return (-1); 41699e6980fSBjoern A. Zeeb ret = OF_getencprop(node, propname, &xref, sizeof(xref)); 41799e6980fSBjoern A. Zeeb if (ret <= 0) 41899e6980fSBjoern A. Zeeb return (ret); 41999e6980fSBjoern A. Zeeb 42099e6980fSBjoern A. Zeeb node = OF_node_from_xref(xref); 42199e6980fSBjoern A. Zeeb if (propvalue != NULL) 42299e6980fSBjoern A. Zeeb *(uint32_t *)propvalue = node; 42399e6980fSBjoern A. Zeeb return (ret); 42499e6980fSBjoern A. Zeeb } 42599e6980fSBjoern A. Zeeb 426b344de4dSKornel Duleba return (OF_getprop(node, propname, propvalue, size)); 4273f9a00e3SBartlomiej Grzesik } 4283f9a00e3SBartlomiej Grzesik 42958158742SRafal Jaworowski static struct resource * 43058158742SRafal Jaworowski simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid, 4312dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 43258158742SRafal Jaworowski { 43306763f5eSNathan Whitehorn struct simplebus_softc *sc; 43458158742SRafal Jaworowski struct simplebus_devinfo *di; 43558158742SRafal Jaworowski struct resource_list_entry *rle; 43606763f5eSNathan Whitehorn int j; 43706763f5eSNathan Whitehorn 43806763f5eSNathan Whitehorn sc = device_get_softc(bus); 43958158742SRafal Jaworowski 44058158742SRafal Jaworowski /* 44158158742SRafal Jaworowski * Request for the default allocation with a given rid: use resource 44258158742SRafal Jaworowski * list stored in the local device info. 44358158742SRafal Jaworowski */ 4447915adb5SJustin Hibbits if (RMAN_IS_DEFAULT_RANGE(start, end)) { 44558158742SRafal Jaworowski if ((di = device_get_ivars(child)) == NULL) 44658158742SRafal Jaworowski return (NULL); 44758158742SRafal Jaworowski 44806763f5eSNathan Whitehorn rle = resource_list_find(&di->rl, type, *rid); 44958158742SRafal Jaworowski if (rle == NULL) { 450089dfb09SAleksandr Rybalko if (bootverbose) 45158158742SRafal Jaworowski device_printf(bus, "no default resources for " 45258158742SRafal Jaworowski "rid = %d, type = %d\n", *rid, type); 45358158742SRafal Jaworowski return (NULL); 45458158742SRafal Jaworowski } 45558158742SRafal Jaworowski start = rle->start; 45658158742SRafal Jaworowski end = rle->end; 45758158742SRafal Jaworowski count = rle->count; 45858158742SRafal Jaworowski } 45958158742SRafal Jaworowski 4604505c892SJohn Baldwin if (type == SYS_RES_IOPORT) 4614505c892SJohn Baldwin type = SYS_RES_MEMORY; 4624505c892SJohn Baldwin 46306763f5eSNathan Whitehorn if (type == SYS_RES_MEMORY) { 46406763f5eSNathan Whitehorn /* Remap through ranges property */ 46506763f5eSNathan Whitehorn for (j = 0; j < sc->nranges; j++) { 46606763f5eSNathan Whitehorn if (start >= sc->ranges[j].bus && end < 46706763f5eSNathan Whitehorn sc->ranges[j].bus + sc->ranges[j].size) { 46806763f5eSNathan Whitehorn start -= sc->ranges[j].bus; 46906763f5eSNathan Whitehorn start += sc->ranges[j].host; 47006763f5eSNathan Whitehorn end -= sc->ranges[j].bus; 47106763f5eSNathan Whitehorn end += sc->ranges[j].host; 47206763f5eSNathan Whitehorn break; 47306763f5eSNathan Whitehorn } 47406763f5eSNathan Whitehorn } 47506763f5eSNathan Whitehorn if (j == sc->nranges && sc->nranges != 0) { 47606763f5eSNathan Whitehorn if (bootverbose) 47706763f5eSNathan Whitehorn device_printf(bus, "Could not map resource " 478da1b038aSJustin Hibbits "%#jx-%#jx\n", start, end); 47906763f5eSNathan Whitehorn 48006763f5eSNathan Whitehorn return (NULL); 48106763f5eSNathan Whitehorn } 48206763f5eSNathan Whitehorn } 4831f40dbc8SBrooks Davis 48458158742SRafal Jaworowski return (bus_generic_alloc_resource(bus, child, type, rid, start, end, 48558158742SRafal Jaworowski count, flags)); 48658158742SRafal Jaworowski } 48758158742SRafal Jaworowski 4881f40dbc8SBrooks Davis static int 4893cf55328SJohn Baldwin simplebus_release_resource(device_t bus, device_t child, int type, int rid, 4903cf55328SJohn Baldwin struct resource *r) 4913cf55328SJohn Baldwin { 4923cf55328SJohn Baldwin 4933cf55328SJohn Baldwin if (type == SYS_RES_IOPORT) 4943cf55328SJohn Baldwin type = SYS_RES_MEMORY; 4953cf55328SJohn Baldwin return (bus_generic_release_resource(bus, child, type, rid, r)); 4963cf55328SJohn Baldwin } 4973cf55328SJohn Baldwin 4983cf55328SJohn Baldwin static int 49906763f5eSNathan Whitehorn simplebus_print_res(struct simplebus_devinfo *di) 5001f40dbc8SBrooks Davis { 50106763f5eSNathan Whitehorn int rv; 5021f40dbc8SBrooks Davis 5036fc608bfSMichal Meloun if (di == NULL) 5046fc608bfSMichal Meloun return (0); 50506763f5eSNathan Whitehorn rv = 0; 506da1b038aSJustin Hibbits rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx"); 507da1b038aSJustin Hibbits rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd"); 50806763f5eSNathan Whitehorn return (rv); 50906763f5eSNathan Whitehorn } 5101f40dbc8SBrooks Davis 51106763f5eSNathan Whitehorn static void 51206763f5eSNathan Whitehorn simplebus_probe_nomatch(device_t bus, device_t child) 51306763f5eSNathan Whitehorn { 514cca75397SWarner Losh const char *name, *type, *compat; 51506763f5eSNathan Whitehorn 51606763f5eSNathan Whitehorn if (!bootverbose) 51706763f5eSNathan Whitehorn return; 51806763f5eSNathan Whitehorn 519ecaecbc7SIan Lepore compat = ofw_bus_get_compat(child); 520ecaecbc7SIan Lepore if (compat == NULL) 521ecaecbc7SIan Lepore return; 52206763f5eSNathan Whitehorn name = ofw_bus_get_name(child); 52306763f5eSNathan Whitehorn type = ofw_bus_get_type(child); 52406763f5eSNathan Whitehorn 52506763f5eSNathan Whitehorn device_printf(bus, "<%s>", name != NULL ? name : "unknown"); 52606763f5eSNathan Whitehorn simplebus_print_res(device_get_ivars(child)); 527cca75397SWarner Losh if (!ofw_bus_status_okay(child)) 528cca75397SWarner Losh printf(" disabled"); 529cca75397SWarner Losh if (type) 530cca75397SWarner Losh printf(" type %s", type); 531ecaecbc7SIan Lepore printf(" compat %s (no driver attached)\n", compat); 5321f40dbc8SBrooks Davis } 5331f40dbc8SBrooks Davis 5341f40dbc8SBrooks Davis static int 53506763f5eSNathan Whitehorn simplebus_print_child(device_t bus, device_t child) 5361f40dbc8SBrooks Davis { 53706763f5eSNathan Whitehorn int rv; 5381f40dbc8SBrooks Davis 53906763f5eSNathan Whitehorn rv = bus_print_child_header(bus, child); 54006763f5eSNathan Whitehorn rv += simplebus_print_res(device_get_ivars(child)); 541cca75397SWarner Losh if (!ofw_bus_status_okay(child)) 542cca75397SWarner Losh rv += printf(" disabled"); 54306763f5eSNathan Whitehorn rv += bus_print_child_footer(bus, child); 54406763f5eSNathan Whitehorn return (rv); 5451f40dbc8SBrooks Davis } 546