xref: /freebsd/sys/dev/fdt/simplebus.c (revision 58158742f29df24bb03270b22c54c8904e36457b)
1*58158742SRafal Jaworowski /*-
2*58158742SRafal Jaworowski  * Copyright (c) 2009-2010 The FreeBSD Foundation
3*58158742SRafal Jaworowski  * All rights reserved.
4*58158742SRafal Jaworowski  *
5*58158742SRafal Jaworowski  * This software was developed by Semihalf under sponsorship from
6*58158742SRafal Jaworowski  * the FreeBSD Foundation.
7*58158742SRafal Jaworowski  *
8*58158742SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
9*58158742SRafal Jaworowski  * modification, are permitted provided that the following conditions
10*58158742SRafal Jaworowski  * are met:
11*58158742SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
12*58158742SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
13*58158742SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
14*58158742SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
15*58158742SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
16*58158742SRafal Jaworowski  *
17*58158742SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*58158742SRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*58158742SRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*58158742SRafal Jaworowski  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*58158742SRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*58158742SRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*58158742SRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*58158742SRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*58158742SRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*58158742SRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*58158742SRafal Jaworowski  * SUCH DAMAGE.
28*58158742SRafal Jaworowski  */
29*58158742SRafal Jaworowski 
30*58158742SRafal Jaworowski #include <sys/cdefs.h>
31*58158742SRafal Jaworowski __FBSDID("$FreeBSD$");
32*58158742SRafal Jaworowski 
33*58158742SRafal Jaworowski #include "opt_platform.h"
34*58158742SRafal Jaworowski #include <sys/param.h>
35*58158742SRafal Jaworowski #include <sys/systm.h>
36*58158742SRafal Jaworowski #include <sys/ktr.h>
37*58158742SRafal Jaworowski #include <sys/kernel.h>
38*58158742SRafal Jaworowski #include <sys/module.h>
39*58158742SRafal Jaworowski #include <sys/bus.h>
40*58158742SRafal Jaworowski #include <sys/rman.h>
41*58158742SRafal Jaworowski #include <sys/malloc.h>
42*58158742SRafal Jaworowski 
43*58158742SRafal Jaworowski #include <machine/fdt.h>
44*58158742SRafal Jaworowski 
45*58158742SRafal Jaworowski #include <dev/ofw/ofw_bus.h>
46*58158742SRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
47*58158742SRafal Jaworowski #include <dev/ofw/openfirm.h>
48*58158742SRafal Jaworowski 
49*58158742SRafal Jaworowski #include "fdt_common.h"
50*58158742SRafal Jaworowski #include "ofw_bus_if.h"
51*58158742SRafal Jaworowski 
52*58158742SRafal Jaworowski #define DEBUG
53*58158742SRafal Jaworowski #undef DEBUG
54*58158742SRafal Jaworowski 
55*58158742SRafal Jaworowski #ifdef DEBUG
56*58158742SRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
57*58158742SRafal Jaworowski     printf(fmt,##args); } while (0)
58*58158742SRafal Jaworowski #else
59*58158742SRafal Jaworowski #define debugf(fmt, args...)
60*58158742SRafal Jaworowski #endif
61*58158742SRafal Jaworowski 
62*58158742SRafal Jaworowski static MALLOC_DEFINE(M_SIMPLEBUS, "simplebus", "simplebus devices information");
63*58158742SRafal Jaworowski 
64*58158742SRafal Jaworowski struct simplebus_softc {
65*58158742SRafal Jaworowski 	int	sc_addr_cells;
66*58158742SRafal Jaworowski 	int	sc_size_cells;
67*58158742SRafal Jaworowski 	u_long	sc_start_pa;
68*58158742SRafal Jaworowski 	u_long	sc_start_va;
69*58158742SRafal Jaworowski 	u_long	sc_size;
70*58158742SRafal Jaworowski };
71*58158742SRafal Jaworowski 
72*58158742SRafal Jaworowski struct simplebus_devinfo {
73*58158742SRafal Jaworowski 	struct ofw_bus_devinfo	di_ofw;
74*58158742SRafal Jaworowski 	struct resource_list	di_res;
75*58158742SRafal Jaworowski 
76*58158742SRafal Jaworowski 	/* Interrupts sense-level info for this device */
77*58158742SRafal Jaworowski 	struct fdt_sense_level	di_intr_sl[DI_MAX_INTR_NUM];
78*58158742SRafal Jaworowski };
79*58158742SRafal Jaworowski 
80*58158742SRafal Jaworowski /*
81*58158742SRafal Jaworowski  * Prototypes.
82*58158742SRafal Jaworowski  */
83*58158742SRafal Jaworowski static int simplebus_probe(device_t);
84*58158742SRafal Jaworowski static int simplebus_attach(device_t);
85*58158742SRafal Jaworowski 
86*58158742SRafal Jaworowski static int simplebus_print_child(device_t, device_t);
87*58158742SRafal Jaworowski static int simplebus_setup_intr(device_t, device_t, struct resource *, int,
88*58158742SRafal Jaworowski     driver_filter_t *, driver_intr_t *, void *, void **);
89*58158742SRafal Jaworowski 
90*58158742SRafal Jaworowski static struct resource *simplebus_alloc_resource(device_t, device_t, int,
91*58158742SRafal Jaworowski     int *, u_long, u_long, u_long, u_int);
92*58158742SRafal Jaworowski static struct resource_list *simplebus_get_resource_list(device_t, device_t);
93*58158742SRafal Jaworowski 
94*58158742SRafal Jaworowski static ofw_bus_get_devinfo_t simplebus_get_devinfo;
95*58158742SRafal Jaworowski 
96*58158742SRafal Jaworowski /*
97*58158742SRafal Jaworowski  * Bus interface definition.
98*58158742SRafal Jaworowski  */
99*58158742SRafal Jaworowski static device_method_t simplebus_methods[] = {
100*58158742SRafal Jaworowski 	/* Device interface */
101*58158742SRafal Jaworowski 	DEVMETHOD(device_probe,		simplebus_probe),
102*58158742SRafal Jaworowski 	DEVMETHOD(device_attach,	simplebus_attach),
103*58158742SRafal Jaworowski 	DEVMETHOD(device_detach,	bus_generic_detach),
104*58158742SRafal Jaworowski 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
105*58158742SRafal Jaworowski 	DEVMETHOD(device_suspend,	bus_generic_suspend),
106*58158742SRafal Jaworowski 	DEVMETHOD(device_resume,	bus_generic_resume),
107*58158742SRafal Jaworowski 
108*58158742SRafal Jaworowski 	/* Bus interface */
109*58158742SRafal Jaworowski 	DEVMETHOD(bus_print_child,	simplebus_print_child),
110*58158742SRafal Jaworowski 	DEVMETHOD(bus_alloc_resource,	simplebus_alloc_resource),
111*58158742SRafal Jaworowski 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
112*58158742SRafal Jaworowski 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
113*58158742SRafal Jaworowski 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
114*58158742SRafal Jaworowski 	DEVMETHOD(bus_setup_intr,	simplebus_setup_intr),
115*58158742SRafal Jaworowski 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
116*58158742SRafal Jaworowski 	DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list),
117*58158742SRafal Jaworowski 
118*58158742SRafal Jaworowski 	/* OFW bus interface */
119*58158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_devinfo,	simplebus_get_devinfo),
120*58158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
121*58158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
122*58158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
123*58158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
124*58158742SRafal Jaworowski 	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
125*58158742SRafal Jaworowski 
126*58158742SRafal Jaworowski 	{ 0, 0 }
127*58158742SRafal Jaworowski };
128*58158742SRafal Jaworowski 
129*58158742SRafal Jaworowski static driver_t simplebus_driver = {
130*58158742SRafal Jaworowski 	"simplebus",
131*58158742SRafal Jaworowski 	simplebus_methods,
132*58158742SRafal Jaworowski 	sizeof(struct simplebus_softc)
133*58158742SRafal Jaworowski };
134*58158742SRafal Jaworowski 
135*58158742SRafal Jaworowski devclass_t simplebus_devclass;
136*58158742SRafal Jaworowski 
137*58158742SRafal Jaworowski DRIVER_MODULE(simplebus, fdtbus, simplebus_driver, simplebus_devclass, 0, 0);
138*58158742SRafal Jaworowski 
139*58158742SRafal Jaworowski static int
140*58158742SRafal Jaworowski simplebus_probe(device_t dev)
141*58158742SRafal Jaworowski {
142*58158742SRafal Jaworowski 
143*58158742SRafal Jaworowski 	if (!ofw_bus_is_compatible_strict(dev, "simple-bus"))
144*58158742SRafal Jaworowski 		return (ENXIO);
145*58158742SRafal Jaworowski 
146*58158742SRafal Jaworowski 	device_set_desc(dev, "Flattened device tree simple bus");
147*58158742SRafal Jaworowski 
148*58158742SRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
149*58158742SRafal Jaworowski }
150*58158742SRafal Jaworowski 
151*58158742SRafal Jaworowski static int
152*58158742SRafal Jaworowski simplebus_attach(device_t dev)
153*58158742SRafal Jaworowski {
154*58158742SRafal Jaworowski 	device_t dev_child;
155*58158742SRafal Jaworowski 	struct simplebus_devinfo *di;
156*58158742SRafal Jaworowski 	struct simplebus_softc *sc;
157*58158742SRafal Jaworowski 	phandle_t dt_node, dt_child;
158*58158742SRafal Jaworowski 
159*58158742SRafal Jaworowski 	sc = device_get_softc(dev);
160*58158742SRafal Jaworowski 
161*58158742SRafal Jaworowski 	sc->sc_start_pa = fdt_immr_pa;
162*58158742SRafal Jaworowski 	sc->sc_start_va = fdt_immr_va;
163*58158742SRafal Jaworowski 	sc->sc_size = fdt_immr_size;
164*58158742SRafal Jaworowski 
165*58158742SRafal Jaworowski 	/*
166*58158742SRafal Jaworowski 	 * Walk simple-bus and add direct subordinates as our children.
167*58158742SRafal Jaworowski 	 */
168*58158742SRafal Jaworowski 	dt_node = ofw_bus_get_node(dev);
169*58158742SRafal Jaworowski 	for (dt_child = OF_child(dt_node); dt_child != 0;
170*58158742SRafal Jaworowski 	    dt_child = OF_peer(dt_child)) {
171*58158742SRafal Jaworowski 
172*58158742SRafal Jaworowski 		/* Check and process 'status' property. */
173*58158742SRafal Jaworowski 		if (!(fdt_is_enabled(dt_child)))
174*58158742SRafal Jaworowski 			continue;
175*58158742SRafal Jaworowski 
176*58158742SRafal Jaworowski 		if (!(fdt_pm_is_enabled(dt_child)))
177*58158742SRafal Jaworowski 			continue;
178*58158742SRafal Jaworowski 
179*58158742SRafal Jaworowski 		di = malloc(sizeof(*di), M_SIMPLEBUS, M_WAITOK | M_ZERO);
180*58158742SRafal Jaworowski 
181*58158742SRafal Jaworowski 		if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) {
182*58158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
183*58158742SRafal Jaworowski 			device_printf(dev, "could not set up devinfo\n");
184*58158742SRafal Jaworowski 			continue;
185*58158742SRafal Jaworowski 		}
186*58158742SRafal Jaworowski 
187*58158742SRafal Jaworowski 		resource_list_init(&di->di_res);
188*58158742SRafal Jaworowski 
189*58158742SRafal Jaworowski 		if (fdt_reg_to_rl(dt_child, &di->di_res, sc->sc_start_va)) {
190*58158742SRafal Jaworowski 			device_printf(dev, "could not process 'reg' "
191*58158742SRafal Jaworowski 			    "property\n");
192*58158742SRafal Jaworowski 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
193*58158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
194*58158742SRafal Jaworowski 			continue;
195*58158742SRafal Jaworowski 		}
196*58158742SRafal Jaworowski 
197*58158742SRafal Jaworowski 		if (fdt_intr_to_rl(dt_child, &di->di_res, di->di_intr_sl)) {
198*58158742SRafal Jaworowski 			device_printf(dev, "could not process 'interrupts' "
199*58158742SRafal Jaworowski 			    "property\n");
200*58158742SRafal Jaworowski 			resource_list_free(&di->di_res);
201*58158742SRafal Jaworowski 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
202*58158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
203*58158742SRafal Jaworowski 			continue;
204*58158742SRafal Jaworowski 		}
205*58158742SRafal Jaworowski 
206*58158742SRafal Jaworowski 		/* Add newbus device for this FDT node */
207*58158742SRafal Jaworowski 		dev_child = device_add_child(dev, NULL, -1);
208*58158742SRafal Jaworowski 		if (dev_child == NULL) {
209*58158742SRafal Jaworowski 			device_printf(dev, "could not add child: %s\n",
210*58158742SRafal Jaworowski 			    di->di_ofw.obd_name);
211*58158742SRafal Jaworowski 			resource_list_free(&di->di_res);
212*58158742SRafal Jaworowski 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
213*58158742SRafal Jaworowski 			free(di, M_SIMPLEBUS);
214*58158742SRafal Jaworowski 			continue;
215*58158742SRafal Jaworowski 		}
216*58158742SRafal Jaworowski 		device_set_ivars(dev_child, di);
217*58158742SRafal Jaworowski 	}
218*58158742SRafal Jaworowski 
219*58158742SRafal Jaworowski 	return (bus_generic_attach(dev));
220*58158742SRafal Jaworowski }
221*58158742SRafal Jaworowski 
222*58158742SRafal Jaworowski static int
223*58158742SRafal Jaworowski simplebus_print_child(device_t dev, device_t child)
224*58158742SRafal Jaworowski {
225*58158742SRafal Jaworowski 	struct simplebus_devinfo *di;
226*58158742SRafal Jaworowski 	struct resource_list *rl;
227*58158742SRafal Jaworowski 	int rv;
228*58158742SRafal Jaworowski 
229*58158742SRafal Jaworowski 	di = device_get_ivars(child);
230*58158742SRafal Jaworowski 	rl = &di->di_res;
231*58158742SRafal Jaworowski 
232*58158742SRafal Jaworowski 	rv = 0;
233*58158742SRafal Jaworowski 	rv += bus_print_child_header(dev, child);
234*58158742SRafal Jaworowski 	rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
235*58158742SRafal Jaworowski 	rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
236*58158742SRafal Jaworowski 	rv += bus_print_child_footer(dev, child);
237*58158742SRafal Jaworowski 
238*58158742SRafal Jaworowski 	return (rv);
239*58158742SRafal Jaworowski }
240*58158742SRafal Jaworowski 
241*58158742SRafal Jaworowski static struct resource *
242*58158742SRafal Jaworowski simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
243*58158742SRafal Jaworowski     u_long start, u_long end, u_long count, u_int flags)
244*58158742SRafal Jaworowski {
245*58158742SRafal Jaworowski 	struct simplebus_devinfo *di;
246*58158742SRafal Jaworowski 	struct resource_list_entry *rle;
247*58158742SRafal Jaworowski 
248*58158742SRafal Jaworowski 	/*
249*58158742SRafal Jaworowski 	 * Request for the default allocation with a given rid: use resource
250*58158742SRafal Jaworowski 	 * list stored in the local device info.
251*58158742SRafal Jaworowski 	 */
252*58158742SRafal Jaworowski 	if ((start == 0UL) && (end == ~0UL)) {
253*58158742SRafal Jaworowski 		if ((di = device_get_ivars(child)) == NULL)
254*58158742SRafal Jaworowski 			return (NULL);
255*58158742SRafal Jaworowski 
256*58158742SRafal Jaworowski 		if (type == SYS_RES_IOPORT)
257*58158742SRafal Jaworowski 			type = SYS_RES_MEMORY;
258*58158742SRafal Jaworowski 
259*58158742SRafal Jaworowski 		rle = resource_list_find(&di->di_res, type, *rid);
260*58158742SRafal Jaworowski 		if (rle == NULL) {
261*58158742SRafal Jaworowski 			device_printf(bus, "no default resources for "
262*58158742SRafal Jaworowski 			    "rid = %d, type = %d\n", *rid, type);
263*58158742SRafal Jaworowski 			return (NULL);
264*58158742SRafal Jaworowski 		}
265*58158742SRafal Jaworowski 		start = rle->start;
266*58158742SRafal Jaworowski 		end = rle->end;
267*58158742SRafal Jaworowski 		count = rle->count;
268*58158742SRafal Jaworowski 	}
269*58158742SRafal Jaworowski 
270*58158742SRafal Jaworowski 	return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
271*58158742SRafal Jaworowski 	    count, flags));
272*58158742SRafal Jaworowski }
273*58158742SRafal Jaworowski 
274*58158742SRafal Jaworowski static struct resource_list *
275*58158742SRafal Jaworowski simplebus_get_resource_list(device_t bus, device_t child)
276*58158742SRafal Jaworowski {
277*58158742SRafal Jaworowski 	struct simplebus_devinfo *di;
278*58158742SRafal Jaworowski 
279*58158742SRafal Jaworowski 	di = device_get_ivars(child);
280*58158742SRafal Jaworowski 	return (&di->di_res);
281*58158742SRafal Jaworowski }
282*58158742SRafal Jaworowski 
283*58158742SRafal Jaworowski static int
284*58158742SRafal Jaworowski simplebus_setup_intr(device_t bus, device_t child, struct resource *res,
285*58158742SRafal Jaworowski     int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg,
286*58158742SRafal Jaworowski     void **cookiep)
287*58158742SRafal Jaworowski {
288*58158742SRafal Jaworowski 	struct simplebus_devinfo *di;
289*58158742SRafal Jaworowski 	enum intr_trigger trig;
290*58158742SRafal Jaworowski 	enum intr_polarity pol;
291*58158742SRafal Jaworowski 	int irq, rid;
292*58158742SRafal Jaworowski 
293*58158742SRafal Jaworowski 	if (res == NULL)
294*58158742SRafal Jaworowski 		panic("simplebus_setup_intr: NULL irq resource!");
295*58158742SRafal Jaworowski 
296*58158742SRafal Jaworowski 	rid = rman_get_rid(res);
297*58158742SRafal Jaworowski 	if (rid > DI_MAX_INTR_NUM) {
298*58158742SRafal Jaworowski 		device_printf(child, "rid out of range rid = %d\n", rid);
299*58158742SRafal Jaworowski 		return (ERANGE);
300*58158742SRafal Jaworowski 	}
301*58158742SRafal Jaworowski 
302*58158742SRafal Jaworowski 	irq = rman_get_start(res);
303*58158742SRafal Jaworowski 
304*58158742SRafal Jaworowski 	if ((di = device_get_ivars(child)) == NULL) {
305*58158742SRafal Jaworowski 		device_printf(child, "could not retrieve devinfo\n");
306*58158742SRafal Jaworowski 		return (ENXIO);
307*58158742SRafal Jaworowski 	}
308*58158742SRafal Jaworowski 
309*58158742SRafal Jaworowski 	trig = di->di_intr_sl[rid].trig;
310*58158742SRafal Jaworowski 	pol = di->di_intr_sl[rid].pol;
311*58158742SRafal Jaworowski 
312*58158742SRafal Jaworowski 	debugf("intr config: irq = %d, trig = %d, pol = %d\n", irq, trig, pol);
313*58158742SRafal Jaworowski 
314*58158742SRafal Jaworowski #if defined(__powerpc__)
315*58158742SRafal Jaworowski 	int err;
316*58158742SRafal Jaworowski 
317*58158742SRafal Jaworowski 	err = powerpc_config_intr(irq, trig, pol);
318*58158742SRafal Jaworowski 	if (err)
319*58158742SRafal Jaworowski 		return (err);
320*58158742SRafal Jaworowski #endif
321*58158742SRafal Jaworowski 
322*58158742SRafal Jaworowski 	return (bus_generic_setup_intr(bus, child, res, flags, filter, ihand,
323*58158742SRafal Jaworowski 	    arg, cookiep));
324*58158742SRafal Jaworowski }
325*58158742SRafal Jaworowski 
326*58158742SRafal Jaworowski static const struct ofw_bus_devinfo *
327*58158742SRafal Jaworowski simplebus_get_devinfo(device_t bus, device_t child)
328*58158742SRafal Jaworowski {
329*58158742SRafal Jaworowski 	struct simplebus_devinfo *di;
330*58158742SRafal Jaworowski 
331*58158742SRafal Jaworowski 	di = device_get_ivars(child);
332*58158742SRafal Jaworowski 	return (&di->di_ofw);
333*58158742SRafal Jaworowski }
334