2 * Copyright (c) 2013 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/module.h>
34 #include <sys/kernel.h>
37 #include <dev/ofw/openfirm.h>
38 #include <dev/ofw/ofw_bus.h>
39 #include <dev/ofw/ofw_bus_subr.h>
41 struct simplebus_range {
47 struct simplebus_softc {
51 struct simplebus_range *ranges;
54 pcell_t acells, scells;
57 struct simplebus_devinfo {
58 struct ofw_bus_devinfo obdinfo;
59 struct resource_list rl;
65 static int simplebus_probe(device_t dev);
66 static int simplebus_attach(device_t dev);
67 static struct resource *simplebus_alloc_resource(device_t, device_t, int,
68 int *, u_long, u_long, u_long, u_int);
69 static void simplebus_probe_nomatch(device_t bus, device_t child);
70 static int simplebus_print_child(device_t bus, device_t child);
75 static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus,
82 static int simplebus_fill_ranges(phandle_t node,
83 struct simplebus_softc *sc);
84 static struct simplebus_devinfo *simplebus_setup_dinfo(device_t dev,
90 static device_method_t simplebus_methods[] = {
91 /* Device interface */
92 DEVMETHOD(device_probe, simplebus_probe),
93 DEVMETHOD(device_attach, simplebus_attach),
96 DEVMETHOD(bus_print_child, simplebus_print_child),
97 DEVMETHOD(bus_probe_nomatch, simplebus_probe_nomatch),
98 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
99 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
100 DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource),
101 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
102 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
103 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
104 DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
105 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
107 /* ofw_bus interface */
108 DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo),
109 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
110 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
111 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
112 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
113 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
118 static driver_t simplebus_driver = {
121 sizeof(struct simplebus_softc)
123 static devclass_t simplebus_devclass;
124 EARLY_DRIVER_MODULE(simplebus, ofwbus, simplebus_driver, simplebus_devclass,
126 EARLY_DRIVER_MODULE(simplebus, simplebus, simplebus_driver, simplebus_devclass,
127 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
130 simplebus_probe(device_t dev)
133 if (!ofw_bus_status_okay(dev))
137 * FDT data puts a "simple-bus" compatible string on many things that
138 * have children but aren't really busses in our world. Without a
139 * ranges property we will fail to attach, so just fail to probe too.
141 if (!(ofw_bus_is_compatible(dev, "simple-bus") &&
142 ofw_bus_has_prop(dev, "ranges")) &&
143 (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev),
147 device_set_desc(dev, "Flattened device tree simple bus");
149 return (BUS_PROBE_GENERIC);
153 simplebus_attach(device_t dev)
155 struct simplebus_softc *sc;
156 struct simplebus_devinfo *di;
160 node = ofw_bus_get_node(dev);
161 sc = device_get_softc(dev);
167 * Some important numbers
170 OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells));
172 OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells));
174 if (simplebus_fill_ranges(node, sc) < 0) {
175 device_printf(dev, "could not get ranges\n");
180 * In principle, simplebus could have an interrupt map, but ignore that
184 for (node = OF_child(node); node > 0; node = OF_peer(node)) {
185 if ((di = simplebus_setup_dinfo(dev, node)) == NULL)
187 cdev = device_add_child(dev, NULL, -1);
189 device_printf(dev, "<%s>: device_add_child failed\n",
190 di->obdinfo.obd_name);
191 resource_list_free(&di->rl);
192 ofw_bus_gen_destroy_devinfo(&di->obdinfo);
196 device_set_ivars(cdev, di);
199 return (bus_generic_attach(dev));
203 simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc)
205 int host_address_cells;
207 ssize_t nbase_ranges;
211 err = OF_searchencprop(OF_parent(node), "#address-cells",
212 &host_address_cells, sizeof(host_address_cells));
216 nbase_ranges = OF_getproplen(node, "ranges");
217 if (nbase_ranges < 0)
219 sc->nranges = nbase_ranges / sizeof(cell_t) /
220 (sc->acells + host_address_cells + sc->scells);
221 if (sc->nranges == 0)
224 sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
226 base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
227 OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
229 for (i = 0, j = 0; i < sc->nranges; i++) {
230 sc->ranges[i].bus = 0;
231 for (k = 0; k < sc->acells; k++) {
232 sc->ranges[i].bus <<= 32;
233 sc->ranges[i].bus |= base_ranges[j++];
235 sc->ranges[i].host = 0;
236 for (k = 0; k < host_address_cells; k++) {
237 sc->ranges[i].host <<= 32;
238 sc->ranges[i].host |= base_ranges[j++];
240 sc->ranges[i].size = 0;
241 for (k = 0; k < sc->scells; k++) {
242 sc->ranges[i].size <<= 32;
243 sc->ranges[i].size |= base_ranges[j++];
247 free(base_ranges, M_DEVBUF);
248 return (sc->nranges);
251 static struct simplebus_devinfo *
252 simplebus_setup_dinfo(device_t dev, phandle_t node)
254 struct simplebus_softc *sc;
255 struct simplebus_devinfo *ndi;
257 sc = device_get_softc(dev);
259 ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
260 if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) {
265 resource_list_init(&ndi->rl);
266 ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl);
267 ofw_bus_intr_to_rl(dev, node, &ndi->rl);
272 static const struct ofw_bus_devinfo *
273 simplebus_get_devinfo(device_t bus __unused, device_t child)
275 struct simplebus_devinfo *ndi;
277 ndi = device_get_ivars(child);
278 return (&ndi->obdinfo);
281 static struct resource *
282 simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
283 u_long start, u_long end, u_long count, u_int flags)
285 struct simplebus_softc *sc;
286 struct simplebus_devinfo *di;
287 struct resource_list_entry *rle;
290 sc = device_get_softc(bus);
293 * Request for the default allocation with a given rid: use resource
294 * list stored in the local device info.
296 if ((start == 0UL) && (end == ~0UL)) {
297 if ((di = device_get_ivars(child)) == NULL)
300 if (type == SYS_RES_IOPORT)
301 type = SYS_RES_MEMORY;
303 rle = resource_list_find(&di->rl, type, *rid);
306 device_printf(bus, "no default resources for "
307 "rid = %d, type = %d\n", *rid, type);
315 if (type == SYS_RES_MEMORY) {
316 /* Remap through ranges property */
317 for (j = 0; j < sc->nranges; j++) {
318 if (start >= sc->ranges[j].bus && end <
319 sc->ranges[j].bus + sc->ranges[j].size) {
320 start -= sc->ranges[j].bus;
321 start += sc->ranges[j].host;
322 end -= sc->ranges[j].bus;
323 end += sc->ranges[j].host;
327 if (j == sc->nranges && sc->nranges != 0) {
329 device_printf(bus, "Could not map resource "
330 "%#lx-%#lx\n", start, end);
336 return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
341 simplebus_print_res(struct simplebus_devinfo *di)
346 rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx");
347 rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld");
352 simplebus_probe_nomatch(device_t bus, device_t child)
354 const char *name, *type, *compat;
359 name = ofw_bus_get_name(child);
360 type = ofw_bus_get_type(child);
361 compat = ofw_bus_get_compat(child);
363 device_printf(bus, "<%s>", name != NULL ? name : "unknown");
364 simplebus_print_res(device_get_ivars(child));
365 if (!ofw_bus_status_okay(child))
368 printf(" type %s", type);
370 printf(" compat %s", compat);
371 printf(" (no driver attached)\n");
375 simplebus_print_child(device_t bus, device_t child)
379 rv = bus_print_child_header(bus, child);
380 rv += simplebus_print_res(device_get_ivars(child));
381 if (!ofw_bus_status_okay(child))
382 rv += printf(" disabled");
383 rv += bus_print_child_footer(bus, child);