xref: /freebsd/sys/dev/fdt/simplebus.c (revision 089dfb09f124d937403ec980793a7edf9dfd2bbd)
158158742SRafal Jaworowski /*-
258158742SRafal Jaworowski  * Copyright (c) 2009-2010 The FreeBSD Foundation
358158742SRafal Jaworowski  * All rights reserved.
458158742SRafal Jaworowski  *
558158742SRafal Jaworowski  * This software was developed by Semihalf under sponsorship from
658158742SRafal Jaworowski  * the FreeBSD Foundation.
758158742SRafal Jaworowski  *
858158742SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
958158742SRafal Jaworowski  * modification, are permitted provided that the following conditions
1058158742SRafal Jaworowski  * are met:
1158158742SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
1258158742SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
1358158742SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
1458158742SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
1558158742SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
1658158742SRafal Jaworowski  *
1758158742SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1858158742SRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1958158742SRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2058158742SRafal Jaworowski  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2158158742SRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2258158742SRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2358158742SRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2458158742SRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2558158742SRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2658158742SRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2758158742SRafal Jaworowski  * SUCH DAMAGE.
2858158742SRafal Jaworowski  */
2958158742SRafal Jaworowski 
3058158742SRafal Jaworowski #include <sys/cdefs.h>
3158158742SRafal Jaworowski __FBSDID("$FreeBSD$");
3258158742SRafal Jaworowski 
3358158742SRafal Jaworowski #include "opt_platform.h"
3458158742SRafal Jaworowski #include <sys/param.h>
3558158742SRafal Jaworowski #include <sys/systm.h>
3658158742SRafal Jaworowski #include <sys/ktr.h>
3758158742SRafal Jaworowski #include <sys/kernel.h>
3858158742SRafal Jaworowski #include <sys/module.h>
3958158742SRafal Jaworowski #include <sys/bus.h>
4058158742SRafal Jaworowski #include <sys/rman.h>
4158158742SRafal Jaworowski #include <sys/malloc.h>
4258158742SRafal Jaworowski 
4358158742SRafal Jaworowski #include <machine/fdt.h>
4458158742SRafal Jaworowski 
4558158742SRafal Jaworowski #include <dev/ofw/ofw_bus.h>
4658158742SRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
4758158742SRafal Jaworowski #include <dev/ofw/openfirm.h>
4858158742SRafal Jaworowski 
4958158742SRafal Jaworowski #include "fdt_common.h"
5058158742SRafal Jaworowski #include "ofw_bus_if.h"
5158158742SRafal Jaworowski 
5258158742SRafal Jaworowski #ifdef DEBUG
5358158742SRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
5458158742SRafal Jaworowski     printf(fmt,##args); } while (0)
5558158742SRafal Jaworowski #else
5658158742SRafal Jaworowski #define debugf(fmt, args...)
5758158742SRafal Jaworowski #endif
5858158742SRafal Jaworowski 
5958158742SRafal Jaworowski static MALLOC_DEFINE(M_SIMPLEBUS, "simplebus", "simplebus devices information");
6058158742SRafal Jaworowski 
6158158742SRafal Jaworowski struct simplebus_softc {
6258158742SRafal Jaworowski 	int	sc_addr_cells;
6358158742SRafal Jaworowski 	int	sc_size_cells;
6458158742SRafal Jaworowski };
6558158742SRafal Jaworowski 
6658158742SRafal Jaworowski struct simplebus_devinfo {
6758158742SRafal Jaworowski 	struct ofw_bus_devinfo	di_ofw;
6858158742SRafal Jaworowski 	struct resource_list	di_res;
6958158742SRafal Jaworowski 
7058158742SRafal Jaworowski 	/* Interrupts sense-level info for this device */
7158158742SRafal Jaworowski 	struct fdt_sense_level	di_intr_sl[DI_MAX_INTR_NUM];
7258158742SRafal Jaworowski };
7358158742SRafal Jaworowski 
7458158742SRafal Jaworowski /*
7558158742SRafal Jaworowski  * Prototypes.
7658158742SRafal Jaworowski  */
7758158742SRafal Jaworowski static int simplebus_probe(device_t);
7858158742SRafal Jaworowski static int simplebus_attach(device_t);
7958158742SRafal Jaworowski 
8058158742SRafal Jaworowski static int simplebus_print_child(device_t, device_t);
8158158742SRafal Jaworowski static int simplebus_setup_intr(device_t, device_t, struct resource *, int,
8258158742SRafal Jaworowski     driver_filter_t *, driver_intr_t *, void *, void **);
8358158742SRafal Jaworowski 
8458158742SRafal Jaworowski static struct resource *simplebus_alloc_resource(device_t, device_t, int,
8558158742SRafal Jaworowski     int *, u_long, u_long, u_long, u_int);
8658158742SRafal Jaworowski static struct resource_list *simplebus_get_resource_list(device_t, device_t);
8758158742SRafal Jaworowski 
8858158742SRafal Jaworowski static ofw_bus_get_devinfo_t simplebus_get_devinfo;
8958158742SRafal Jaworowski 
9058158742SRafal Jaworowski /*
9158158742SRafal Jaworowski  * Bus interface definition.
9258158742SRafal Jaworowski  */
9358158742SRafal Jaworowski static device_method_t simplebus_methods[] = {
9458158742SRafal Jaworowski 	/* Device interface */
9558158742SRafal Jaworowski 	DEVMETHOD(device_probe,		simplebus_probe),
9658158742SRafal Jaworowski 	DEVMETHOD(device_attach,	simplebus_attach),
9758158742SRafal Jaworowski 	DEVMETHOD(device_detach,	bus_generic_detach),
9858158742SRafal Jaworowski 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
9958158742SRafal Jaworowski 	DEVMETHOD(device_suspend,	bus_generic_suspend),
10058158742SRafal Jaworowski 	DEVMETHOD(device_resume,	bus_generic_resume),
10158158742SRafal Jaworowski 
10258158742SRafal Jaworowski 	/* Bus interface */
10358158742SRafal Jaworowski 	DEVMETHOD(bus_print_child,	simplebus_print_child),
10458158742SRafal Jaworowski 	DEVMETHOD(bus_alloc_resource,	simplebus_alloc_resource),
10558158742SRafal Jaworowski 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
10658158742SRafal Jaworowski 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
10758158742SRafal Jaworowski 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
10858158742SRafal Jaworowski 	DEVMETHOD(bus_setup_intr,	simplebus_setup_intr),
10958158742SRafal Jaworowski 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
11058158742SRafal Jaworowski 	DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list),
11158158742SRafal Jaworowski 
11258158742SRafal Jaworowski 	/* OFW bus interface */
11358158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_devinfo,	simplebus_get_devinfo),
11458158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
11558158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
11658158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
11758158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
11858158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
11958158742SRafal Jaworowski 
12058158742SRafal Jaworowski 	{ 0, 0 }
12158158742SRafal Jaworowski };
12258158742SRafal Jaworowski 
12358158742SRafal Jaworowski static driver_t simplebus_driver = {
12458158742SRafal Jaworowski 	"simplebus",
12558158742SRafal Jaworowski 	simplebus_methods,
12658158742SRafal Jaworowski 	sizeof(struct simplebus_softc)
12758158742SRafal Jaworowski };
12858158742SRafal Jaworowski 
12958158742SRafal Jaworowski devclass_t simplebus_devclass;
13058158742SRafal Jaworowski 
13158158742SRafal Jaworowski DRIVER_MODULE(simplebus, fdtbus, simplebus_driver, simplebus_devclass, 0, 0);
13258158742SRafal Jaworowski 
13358158742SRafal Jaworowski static int
13458158742SRafal Jaworowski simplebus_probe(device_t dev)
13558158742SRafal Jaworowski {
13658158742SRafal Jaworowski 
1372737a5a9SAleksandr Rybalko 	if (!ofw_bus_is_compatible(dev, "simple-bus"))
13858158742SRafal Jaworowski 		return (ENXIO);
13958158742SRafal Jaworowski 
14058158742SRafal Jaworowski 	device_set_desc(dev, "Flattened device tree simple bus");
14158158742SRafal Jaworowski 
1422737a5a9SAleksandr Rybalko 	return (BUS_PROBE_GENERIC);
14358158742SRafal Jaworowski }
14458158742SRafal Jaworowski 
14558158742SRafal Jaworowski static int
14658158742SRafal Jaworowski simplebus_attach(device_t dev)
14758158742SRafal Jaworowski {
14858158742SRafal Jaworowski 	device_t dev_child;
14958158742SRafal Jaworowski 	struct simplebus_devinfo *di;
15058158742SRafal Jaworowski 	struct simplebus_softc *sc;
15158158742SRafal Jaworowski 	phandle_t dt_node, dt_child;
15258158742SRafal Jaworowski 
15358158742SRafal Jaworowski 	sc = device_get_softc(dev);
15458158742SRafal Jaworowski 
15558158742SRafal Jaworowski 	/*
15658158742SRafal Jaworowski 	 * Walk simple-bus and add direct subordinates as our children.
15758158742SRafal Jaworowski 	 */
15858158742SRafal Jaworowski 	dt_node = ofw_bus_get_node(dev);
15958158742SRafal Jaworowski 	for (dt_child = OF_child(dt_node); dt_child != 0;
16058158742SRafal Jaworowski 	    dt_child = OF_peer(dt_child)) {
16158158742SRafal Jaworowski 
16258158742SRafal Jaworowski 		/* Check and process 'status' property. */
16358158742SRafal Jaworowski 		if (!(fdt_is_enabled(dt_child)))
16458158742SRafal Jaworowski 			continue;
16558158742SRafal Jaworowski 
16658158742SRafal Jaworowski 		if (!(fdt_pm_is_enabled(dt_child)))
16758158742SRafal Jaworowski 			continue;
16858158742SRafal Jaworowski 
16958158742SRafal Jaworowski 		di = malloc(sizeof(*di), M_SIMPLEBUS, M_WAITOK | M_ZERO);
17058158742SRafal Jaworowski 
17158158742SRafal Jaworowski 		if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) {
17258158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
17358158742SRafal Jaworowski 			device_printf(dev, "could not set up devinfo\n");
17458158742SRafal Jaworowski 			continue;
17558158742SRafal Jaworowski 		}
17658158742SRafal Jaworowski 
17758158742SRafal Jaworowski 		resource_list_init(&di->di_res);
1788bb93637SOleksandr Tymoshenko 		if (fdt_reg_to_rl(dt_child, &di->di_res)) {
1798bb93637SOleksandr Tymoshenko 			device_printf(dev,
1808bb93637SOleksandr Tymoshenko 			    "%s: could not process 'reg' "
181a22cd1e6SRafal Jaworowski 			    "property\n", di->di_ofw.obd_name);
18258158742SRafal Jaworowski 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
18358158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
18458158742SRafal Jaworowski 			continue;
18558158742SRafal Jaworowski 		}
18658158742SRafal Jaworowski 
18758158742SRafal Jaworowski 		if (fdt_intr_to_rl(dt_child, &di->di_res, di->di_intr_sl)) {
188a22cd1e6SRafal Jaworowski 			device_printf(dev, "%s: could not process "
189a22cd1e6SRafal Jaworowski 			    "'interrupts' property\n", di->di_ofw.obd_name);
19058158742SRafal Jaworowski 			resource_list_free(&di->di_res);
19158158742SRafal Jaworowski 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
19258158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
19358158742SRafal Jaworowski 			continue;
19458158742SRafal Jaworowski 		}
19558158742SRafal Jaworowski 
19658158742SRafal Jaworowski 		/* Add newbus device for this FDT node */
19758158742SRafal Jaworowski 		dev_child = device_add_child(dev, NULL, -1);
19858158742SRafal Jaworowski 		if (dev_child == NULL) {
19958158742SRafal Jaworowski 			device_printf(dev, "could not add child: %s\n",
20058158742SRafal Jaworowski 			    di->di_ofw.obd_name);
20158158742SRafal Jaworowski 			resource_list_free(&di->di_res);
20258158742SRafal Jaworowski 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
20358158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
20458158742SRafal Jaworowski 			continue;
20558158742SRafal Jaworowski 		}
206a22cd1e6SRafal Jaworowski #ifdef DEBUG
207a22cd1e6SRafal Jaworowski 		device_printf(dev, "added child: %s\n\n", di->di_ofw.obd_name);
208a22cd1e6SRafal Jaworowski #endif
20958158742SRafal Jaworowski 		device_set_ivars(dev_child, di);
21058158742SRafal Jaworowski 	}
21158158742SRafal Jaworowski 
21258158742SRafal Jaworowski 	return (bus_generic_attach(dev));
21358158742SRafal Jaworowski }
21458158742SRafal Jaworowski 
21558158742SRafal Jaworowski static int
21658158742SRafal Jaworowski simplebus_print_child(device_t dev, device_t child)
21758158742SRafal Jaworowski {
21858158742SRafal Jaworowski 	struct simplebus_devinfo *di;
21958158742SRafal Jaworowski 	struct resource_list *rl;
22058158742SRafal Jaworowski 	int rv;
22158158742SRafal Jaworowski 
22258158742SRafal Jaworowski 	di = device_get_ivars(child);
22358158742SRafal Jaworowski 	rl = &di->di_res;
22458158742SRafal Jaworowski 
22558158742SRafal Jaworowski 	rv = 0;
22658158742SRafal Jaworowski 	rv += bus_print_child_header(dev, child);
22758158742SRafal Jaworowski 	rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
22858158742SRafal Jaworowski 	rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
22958158742SRafal Jaworowski 	rv += bus_print_child_footer(dev, child);
23058158742SRafal Jaworowski 
23158158742SRafal Jaworowski 	return (rv);
23258158742SRafal Jaworowski }
23358158742SRafal Jaworowski 
23458158742SRafal Jaworowski static struct resource *
23558158742SRafal Jaworowski simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
23658158742SRafal Jaworowski     u_long start, u_long end, u_long count, u_int flags)
23758158742SRafal Jaworowski {
23858158742SRafal Jaworowski 	struct simplebus_devinfo *di;
23958158742SRafal Jaworowski 	struct resource_list_entry *rle;
24058158742SRafal Jaworowski 
24158158742SRafal Jaworowski 	/*
24258158742SRafal Jaworowski 	 * Request for the default allocation with a given rid: use resource
24358158742SRafal Jaworowski 	 * list stored in the local device info.
24458158742SRafal Jaworowski 	 */
24558158742SRafal Jaworowski 	if ((start == 0UL) && (end == ~0UL)) {
24658158742SRafal Jaworowski 		if ((di = device_get_ivars(child)) == NULL)
24758158742SRafal Jaworowski 			return (NULL);
24858158742SRafal Jaworowski 
24958158742SRafal Jaworowski 		if (type == SYS_RES_IOPORT)
25058158742SRafal Jaworowski 			type = SYS_RES_MEMORY;
25158158742SRafal Jaworowski 
25258158742SRafal Jaworowski 		rle = resource_list_find(&di->di_res, type, *rid);
25358158742SRafal Jaworowski 		if (rle == NULL) {
254*089dfb09SAleksandr Rybalko 			if (bootverbose)
25558158742SRafal Jaworowski 				device_printf(bus, "no default resources for "
25658158742SRafal Jaworowski 				    "rid = %d, type = %d\n", *rid, type);
25758158742SRafal Jaworowski 			return (NULL);
25858158742SRafal Jaworowski 		}
25958158742SRafal Jaworowski 		start = rle->start;
26058158742SRafal Jaworowski 		end = rle->end;
26158158742SRafal Jaworowski 		count = rle->count;
26258158742SRafal Jaworowski 	}
26358158742SRafal Jaworowski 
26458158742SRafal Jaworowski 	return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
26558158742SRafal Jaworowski 	    count, flags));
26658158742SRafal Jaworowski }
26758158742SRafal Jaworowski 
26858158742SRafal Jaworowski static struct resource_list *
26958158742SRafal Jaworowski simplebus_get_resource_list(device_t bus, device_t child)
27058158742SRafal Jaworowski {
27158158742SRafal Jaworowski 	struct simplebus_devinfo *di;
27258158742SRafal Jaworowski 
27358158742SRafal Jaworowski 	di = device_get_ivars(child);
27458158742SRafal Jaworowski 	return (&di->di_res);
27558158742SRafal Jaworowski }
27658158742SRafal Jaworowski 
27758158742SRafal Jaworowski static int
27858158742SRafal Jaworowski simplebus_setup_intr(device_t bus, device_t child, struct resource *res,
27958158742SRafal Jaworowski     int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg,
28058158742SRafal Jaworowski     void **cookiep)
28158158742SRafal Jaworowski {
28258158742SRafal Jaworowski 	struct simplebus_devinfo *di;
28358158742SRafal Jaworowski 	enum intr_trigger trig;
28458158742SRafal Jaworowski 	enum intr_polarity pol;
285120c7e2eSMarcel Moolenaar 	int error, rid;
286120c7e2eSMarcel Moolenaar 
287120c7e2eSMarcel Moolenaar 	if (device_get_parent(child) != bus)
288120c7e2eSMarcel Moolenaar 		return (ECHILD);
289120c7e2eSMarcel Moolenaar 
290120c7e2eSMarcel Moolenaar 	di = device_get_ivars(child);
291120c7e2eSMarcel Moolenaar 	if (di == NULL)
292120c7e2eSMarcel Moolenaar 		return (ENXIO);
29358158742SRafal Jaworowski 
29458158742SRafal Jaworowski 	if (res == NULL)
295120c7e2eSMarcel Moolenaar 		return (EINVAL);
29658158742SRafal Jaworowski 
29758158742SRafal Jaworowski 	rid = rman_get_rid(res);
298120c7e2eSMarcel Moolenaar 	if (rid >= DI_MAX_INTR_NUM)
299120c7e2eSMarcel Moolenaar 		return (ENOENT);
30058158742SRafal Jaworowski 
30158158742SRafal Jaworowski 	trig = di->di_intr_sl[rid].trig;
30258158742SRafal Jaworowski 	pol = di->di_intr_sl[rid].pol;
303120c7e2eSMarcel Moolenaar 	if (trig != INTR_TRIGGER_CONFORM || pol != INTR_POLARITY_CONFORM) {
304120c7e2eSMarcel Moolenaar 		error = bus_generic_config_intr(bus, rman_get_start(res),
305120c7e2eSMarcel Moolenaar 		    trig, pol);
306120c7e2eSMarcel Moolenaar 		if (error)
307120c7e2eSMarcel Moolenaar 			return (error);
308120c7e2eSMarcel Moolenaar 	}
30958158742SRafal Jaworowski 
310120c7e2eSMarcel Moolenaar 	error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand,
311120c7e2eSMarcel Moolenaar 	    arg, cookiep);
312120c7e2eSMarcel Moolenaar 	return (error);
31358158742SRafal Jaworowski }
31458158742SRafal Jaworowski 
31558158742SRafal Jaworowski static const struct ofw_bus_devinfo *
31658158742SRafal Jaworowski simplebus_get_devinfo(device_t bus, device_t child)
31758158742SRafal Jaworowski {
31858158742SRafal Jaworowski 	struct simplebus_devinfo *di;
31958158742SRafal Jaworowski 
32058158742SRafal Jaworowski 	di = device_get_ivars(child);
32158158742SRafal Jaworowski 	return (&di->di_ofw);
32258158742SRafal Jaworowski }
323