1208747Sraj/*-
2208747Sraj * Copyright (c) 2009-2010 The FreeBSD Foundation
3208747Sraj * All rights reserved.
4208747Sraj *
5208747Sraj * This software was developed by Semihalf under sponsorship from
6208747Sraj * the FreeBSD Foundation.
7208747Sraj *
8208747Sraj * Redistribution and use in source and binary forms, with or without
9208747Sraj * modification, are permitted provided that the following conditions
10208747Sraj * are met:
11208747Sraj * 1. Redistributions of source code must retain the above copyright
12208747Sraj *    notice, this list of conditions and the following disclaimer.
13208747Sraj * 2. Redistributions in binary form must reproduce the above copyright
14208747Sraj *    notice, this list of conditions and the following disclaimer in the
15208747Sraj *    documentation and/or other materials provided with the distribution.
16208747Sraj *
17208747Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18208747Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19208747Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20208747Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21208747Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22208747Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23208747Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24208747Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25208747Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26208747Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27208747Sraj * SUCH DAMAGE.
28208747Sraj */
29208747Sraj
30208747Sraj#include <sys/cdefs.h>
31208747Sraj__FBSDID("$FreeBSD$");
32208747Sraj
33208747Sraj#include <sys/param.h>
34208747Sraj#include <sys/systm.h>
35208747Sraj#include <sys/ktr.h>
36208747Sraj#include <sys/kernel.h>
37208747Sraj#include <sys/module.h>
38208747Sraj#include <sys/bus.h>
39208747Sraj#include <sys/rman.h>
40208747Sraj#include <sys/malloc.h>
41208747Sraj
42218076Smarcel#include <machine/fdt.h>
43218076Smarcel
44208747Sraj#include <dev/ofw/openfirm.h>
45208747Sraj
46208747Sraj#include "fdt_common.h"
47208747Sraj#include "ofw_bus_if.h"
48208747Sraj
49208747Sraj#ifdef DEBUG
50208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
51208747Sraj    printf(fmt,##args); } while (0)
52208747Sraj#else
53208747Sraj#define debugf(fmt, args...)
54208747Sraj#endif
55208747Sraj
56208747Srajstatic MALLOC_DEFINE(M_FDTBUS, "fdtbus", "FDTbus devices information");
57208747Sraj
58208747Srajstruct fdtbus_devinfo {
59208747Sraj	phandle_t		di_node;
60208747Sraj	char			*di_name;
61208747Sraj	char			*di_type;
62208747Sraj	char			*di_compat;
63208747Sraj	struct resource_list	di_res;
64208747Sraj
65208747Sraj	/* Interrupts sense-level info for this device */
66208747Sraj	struct fdt_sense_level	di_intr_sl[DI_MAX_INTR_NUM];
67208747Sraj};
68208747Sraj
69208747Srajstruct fdtbus_softc {
70208747Sraj	struct rman	sc_irq;
71208747Sraj	struct rman	sc_mem;
72208747Sraj};
73208747Sraj
74208747Sraj/*
75208747Sraj * Prototypes.
76208747Sraj */
77209127Srajstatic void fdtbus_identify(driver_t *, device_t);
78208747Srajstatic int fdtbus_probe(device_t);
79208747Srajstatic int fdtbus_attach(device_t);
80208747Sraj
81208747Srajstatic int fdtbus_print_child(device_t, device_t);
82208747Srajstatic struct resource *fdtbus_alloc_resource(device_t, device_t, int,
83208747Sraj    int *, u_long, u_long, u_long, u_int);
84208747Srajstatic int fdtbus_release_resource(device_t, device_t, int, int,
85208747Sraj    struct resource *);
86208747Srajstatic int fdtbus_activate_resource(device_t, device_t, int, int,
87208747Sraj    struct resource *);
88208747Srajstatic int fdtbus_deactivate_resource(device_t, device_t, int, int,
89208747Sraj    struct resource *);
90208747Srajstatic int fdtbus_setup_intr(device_t, device_t, struct resource *, int,
91208747Sraj    driver_filter_t *, driver_intr_t *, void *, void **);
92208747Sraj
93208747Srajstatic const char *fdtbus_ofw_get_name(device_t, device_t);
94208747Srajstatic phandle_t fdtbus_ofw_get_node(device_t, device_t);
95208747Srajstatic const char *fdtbus_ofw_get_type(device_t, device_t);
96208747Srajstatic const char *fdtbus_ofw_get_compat(device_t, device_t);
97208747Sraj
98208747Sraj/*
99208747Sraj * Local routines.
100208747Sraj */
101208747Srajstatic void newbus_device_from_fdt_node(device_t, phandle_t);
102208747Sraj
103208747Sraj/*
104208747Sraj * Bus interface definition.
105208747Sraj */
106208747Srajstatic device_method_t fdtbus_methods[] = {
107208747Sraj	/* Device interface */
108209127Sraj	DEVMETHOD(device_identify,	fdtbus_identify),
109208747Sraj	DEVMETHOD(device_probe,		fdtbus_probe),
110208747Sraj	DEVMETHOD(device_attach,	fdtbus_attach),
111208747Sraj	DEVMETHOD(device_detach,	bus_generic_detach),
112208747Sraj	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
113208747Sraj	DEVMETHOD(device_suspend,	bus_generic_suspend),
114208747Sraj	DEVMETHOD(device_resume,	bus_generic_resume),
115208747Sraj
116208747Sraj	/* Bus interface */
117208747Sraj	DEVMETHOD(bus_print_child,	fdtbus_print_child),
118208747Sraj	DEVMETHOD(bus_alloc_resource,	fdtbus_alloc_resource),
119208747Sraj	DEVMETHOD(bus_release_resource,	fdtbus_release_resource),
120208747Sraj	DEVMETHOD(bus_activate_resource, fdtbus_activate_resource),
121208747Sraj	DEVMETHOD(bus_deactivate_resource, fdtbus_deactivate_resource),
122238043Smarcel	DEVMETHOD(bus_config_intr,	bus_generic_config_intr),
123208747Sraj	DEVMETHOD(bus_setup_intr,	fdtbus_setup_intr),
124238043Smarcel	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
125208747Sraj
126208747Sraj	/* OFW bus interface */
127208747Sraj	DEVMETHOD(ofw_bus_get_node,	fdtbus_ofw_get_node),
128208747Sraj	DEVMETHOD(ofw_bus_get_name,	fdtbus_ofw_get_name),
129208747Sraj	DEVMETHOD(ofw_bus_get_type,	fdtbus_ofw_get_type),
130208747Sraj	DEVMETHOD(ofw_bus_get_compat,	fdtbus_ofw_get_compat),
131208747Sraj
132208747Sraj	{ 0, 0 }
133208747Sraj};
134208747Sraj
135208747Srajstatic driver_t fdtbus_driver = {
136208747Sraj	"fdtbus",
137208747Sraj	fdtbus_methods,
138208747Sraj	sizeof(struct fdtbus_softc)
139208747Sraj};
140208747Sraj
141208747Srajdevclass_t fdtbus_devclass;
142208747Sraj
143208747SrajDRIVER_MODULE(fdtbus, nexus, fdtbus_driver, fdtbus_devclass, 0, 0);
144208747Sraj
145209127Srajstatic void
146209127Srajfdtbus_identify(driver_t *driver, device_t parent)
147209127Sraj{
148209127Sraj
149218076Smarcel	debugf("%s(driver=%p, parent=%p)\n", __func__, driver, parent);
150218076Smarcel
151209127Sraj	if (device_find_child(parent, "fdtbus", -1) == NULL)
152209127Sraj		BUS_ADD_CHILD(parent, 0, "fdtbus", -1);
153209127Sraj}
154209127Sraj
155208747Srajstatic int
156208747Srajfdtbus_probe(device_t dev)
157208747Sraj{
158208747Sraj
159218076Smarcel	debugf("%s(dev=%p); pass=%u\n", __func__, dev, bus_current_pass);
160218076Smarcel
161208747Sraj	device_set_desc(dev, "FDT main bus");
162208747Sraj	if (!bootverbose)
163208747Sraj		device_quiet(dev);
164208747Sraj	return (BUS_PROBE_DEFAULT);
165208747Sraj}
166208747Sraj
167208747Srajstatic int
168208747Srajfdtbus_attach(device_t dev)
169208747Sraj{
170208747Sraj	phandle_t root;
171208747Sraj	phandle_t child;
172208747Sraj	struct fdtbus_softc *sc;
173208747Sraj	u_long start, end;
174208747Sraj	int error;
175208747Sraj
176228201Sjchandra	if ((root = OF_finddevice("/")) == -1)
177208747Sraj		panic("fdtbus_attach: no root node.");
178208747Sraj
179208747Sraj	sc = device_get_softc(dev);
180208747Sraj
181208747Sraj	/*
182208747Sraj	 * IRQ rman.
183208747Sraj	 */
184208747Sraj	start = 0;
185208747Sraj	end = FDT_INTR_MAX - 1;
186208747Sraj	sc->sc_irq.rm_start = start;
187208747Sraj	sc->sc_irq.rm_end = end;
188208747Sraj	sc->sc_irq.rm_type = RMAN_ARRAY;
189208747Sraj	sc->sc_irq.rm_descr = "Interrupt request lines";
190208747Sraj	if ((error = rman_init(&sc->sc_irq)) != 0) {
191208747Sraj		device_printf(dev, "could not init IRQ rman, error = %d\n",
192208747Sraj		    error);
193208747Sraj		return (error);
194208747Sraj	}
195208747Sraj	if ((error = rman_manage_region(&sc->sc_irq, start, end)) != 0) {
196208747Sraj		device_printf(dev, "could not manage IRQ region, error = %d\n",
197208747Sraj		    error);
198208747Sraj		return (error);
199208747Sraj	}
200208747Sraj
201208747Sraj	/*
202208747Sraj	 * Mem-mapped I/O space rman.
203208747Sraj	 */
204208747Sraj	start = 0;
205221218Sjhb	end = ~0ul;
206208747Sraj	sc->sc_mem.rm_start = start;
207208747Sraj	sc->sc_mem.rm_end = end;
208208747Sraj	sc->sc_mem.rm_type = RMAN_ARRAY;
209208747Sraj	sc->sc_mem.rm_descr = "I/O memory";
210208747Sraj	if ((error = rman_init(&sc->sc_mem)) != 0) {
211208747Sraj		device_printf(dev, "could not init I/O mem rman, error = %d\n",
212208747Sraj		    error);
213208747Sraj		return (error);
214208747Sraj	}
215208747Sraj	if ((error = rman_manage_region(&sc->sc_mem, start, end)) != 0) {
216208747Sraj		device_printf(dev, "could not manage I/O mem region, "
217208747Sraj		    "error = %d\n", error);
218208747Sraj		return (error);
219208747Sraj	}
220208747Sraj
221208747Sraj	/*
222208747Sraj	 * Walk the FDT root node and add top-level devices as our children.
223208747Sraj	 */
224208747Sraj	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
225208747Sraj		/* Check and process 'status' property. */
226208747Sraj		if (!(fdt_is_enabled(child)))
227208747Sraj			continue;
228208747Sraj
229208747Sraj		newbus_device_from_fdt_node(dev, child);
230208747Sraj	}
231208747Sraj
232208747Sraj	return (bus_generic_attach(dev));
233208747Sraj}
234208747Sraj
235208747Srajstatic int
236208747Srajfdtbus_print_child(device_t dev, device_t child)
237208747Sraj{
238208747Sraj	struct fdtbus_devinfo *di;
239208747Sraj	struct resource_list *rl;
240208747Sraj	int rv;
241208747Sraj
242208747Sraj	di = device_get_ivars(child);
243208747Sraj	rl = &di->di_res;
244208747Sraj
245208747Sraj	rv = 0;
246208747Sraj	rv += bus_print_child_header(dev, child);
247208747Sraj	rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
248208747Sraj	rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
249208747Sraj	rv += bus_print_child_footer(dev, child);
250208747Sraj
251208747Sraj	return (rv);
252208747Sraj}
253208747Sraj
254208747Srajstatic void
255208747Srajnewbus_device_destroy(device_t dev)
256208747Sraj{
257208747Sraj	struct fdtbus_devinfo *di;
258208747Sraj
259208747Sraj	di = device_get_ivars(dev);
260244871Srwatson	if (di == NULL)
261244871Srwatson		return;
262208747Sraj
263208747Sraj	free(di->di_name, M_OFWPROP);
264208747Sraj	free(di->di_type, M_OFWPROP);
265208747Sraj	free(di->di_compat, M_OFWPROP);
266208747Sraj
267208747Sraj	resource_list_free(&di->di_res);
268208747Sraj	free(di, M_FDTBUS);
269208747Sraj}
270208747Sraj
271208747Srajstatic device_t
272208747Srajnewbus_device_create(device_t dev_par, phandle_t node, char *name, char *type,
273208747Sraj    char *compat)
274208747Sraj{
275208747Sraj	device_t child;
276208747Sraj	struct fdtbus_devinfo *di;
277208747Sraj
278208747Sraj	child = device_add_child(dev_par, NULL, -1);
279208747Sraj	if (child == NULL) {
280208747Sraj		free(name, M_OFWPROP);
281208747Sraj		free(type, M_OFWPROP);
282208747Sraj		free(compat, M_OFWPROP);
283208747Sraj		return (NULL);
284208747Sraj	}
285208747Sraj
286208747Sraj	di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK);
287208747Sraj	di->di_node = node;
288208747Sraj	di->di_name = name;
289208747Sraj	di->di_type = type;
290208747Sraj	di->di_compat = compat;
291208747Sraj
292208747Sraj	resource_list_init(&di->di_res);
293208747Sraj
294239274Sgonzo	if (fdt_reg_to_rl(node, &di->di_res)) {
295208747Sraj		device_printf(child, "could not process 'reg' property\n");
296208747Sraj		newbus_device_destroy(child);
297208747Sraj		child = NULL;
298208747Sraj		goto out;
299208747Sraj	}
300208747Sraj
301208747Sraj	if (fdt_intr_to_rl(node, &di->di_res, di->di_intr_sl)) {
302208747Sraj		device_printf(child, "could not process 'interrupts' "
303208747Sraj		    "property\n");
304208747Sraj		newbus_device_destroy(child);
305208747Sraj		child = NULL;
306208747Sraj		goto out;
307208747Sraj	}
308208747Sraj
309208747Sraj	device_set_ivars(child, di);
310208747Sraj	debugf("added child name='%s', node=%p\n", name, (void *)node);
311208747Sraj
312208747Srajout:
313208747Sraj	return (child);
314208747Sraj}
315208747Sraj
316208747Srajstatic device_t
317208747Srajnewbus_pci_create(device_t dev_par, phandle_t dt_node, u_long par_base,
318208747Sraj    u_long par_size)
319208747Sraj{
320208747Sraj	pcell_t reg[3 + 2];
321208747Sraj	device_t dev_child;
322208747Sraj	u_long start, end, count;
323208747Sraj	struct fdtbus_devinfo *di;
324208747Sraj	char *name, *type, *compat;
325208747Sraj	int len;
326208747Sraj
327208747Sraj	OF_getprop_alloc(dt_node, "device_type", 1, (void **)&type);
328208747Sraj	if (!(type != NULL && strcmp(type, "pci") == 0)) {
329208747Sraj		/* Only process 'pci' subnodes. */
330208747Sraj		free(type, M_OFWPROP);
331208747Sraj		return (NULL);
332208747Sraj	}
333208747Sraj
334208747Sraj	OF_getprop_alloc(dt_node, "name", 1, (void **)&name);
335208747Sraj	OF_getprop_alloc(OF_parent(dt_node), "compatible", 1,
336208747Sraj	    (void **)&compat);
337208747Sraj
338208747Sraj	dev_child = device_add_child(dev_par, NULL, -1);
339208747Sraj	if (dev_child == NULL) {
340208747Sraj		free(name, M_OFWPROP);
341208747Sraj		free(type, M_OFWPROP);
342208747Sraj		free(compat, M_OFWPROP);
343208747Sraj		return (NULL);
344208747Sraj	}
345208747Sraj
346208747Sraj	di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK);
347208747Sraj	di->di_node = dt_node;
348208747Sraj	di->di_name = name;
349208747Sraj	di->di_type = type;
350208747Sraj	di->di_compat = compat;
351208747Sraj
352208747Sraj	resource_list_init(&di->di_res);
353208747Sraj
354208747Sraj	/*
355208747Sraj	 * Produce and set SYS_RES_MEMORY resources.
356208747Sraj	 */
357208747Sraj	start = 0;
358208747Sraj	count = 0;
359208747Sraj
360208747Sraj	len = OF_getprop(dt_node, "reg", &reg, sizeof(reg));
361208747Sraj	if (len > 0) {
362208747Sraj		if (fdt_data_verify((void *)&reg[1], 2) != 0) {
363208747Sraj			device_printf(dev_child, "'reg' address value out of "
364208747Sraj			    "range\n");
365208747Sraj			newbus_device_destroy(dev_child);
366208747Sraj			dev_child = NULL;
367208747Sraj			goto out;
368208747Sraj		}
369208747Sraj		start = fdt_data_get((void *)&reg[1], 2);
370208747Sraj
371208747Sraj		if (fdt_data_verify((void *)&reg[3], 2) != 0) {
372208747Sraj			device_printf(dev_child, "'reg' size value out of "
373208747Sraj			    "range\n");
374208747Sraj			newbus_device_destroy(dev_child);
375208747Sraj			dev_child = NULL;
376208747Sraj			goto out;
377208747Sraj		}
378208747Sraj		count = fdt_data_get((void *)&reg[3], 2);
379208747Sraj	}
380208747Sraj
381208747Sraj	/* Calculate address range relative to base. */
382208747Sraj	par_base &= 0x000ffffful;
383208747Sraj	start &= 0x000ffffful;
384208747Sraj	start += par_base + fdt_immr_va;
385208747Sraj	if (count == 0)
386208747Sraj		count = par_size;
387208747Sraj	end = start + count - 1;
388208747Sraj
389208747Sraj	debugf("start = 0x%08lx, end = 0x%08lx, count = 0x%08lx\n",
390208747Sraj	    start, end, count);
391208747Sraj
392208747Sraj	if (count > par_size) {
393208747Sraj		device_printf(dev_child, "'reg' size value out of range\n");
394208747Sraj		newbus_device_destroy(dev_child);
395208747Sraj		dev_child = NULL;
396208747Sraj		goto out;
397208747Sraj	}
398208747Sraj
399208747Sraj	resource_list_add(&di->di_res, SYS_RES_MEMORY, 0, start, end, count);
400208747Sraj
401208747Sraj	/*
402208747Sraj	 * Set SYS_RES_IRQ resources.
403208747Sraj	 */
404208747Sraj	if (fdt_intr_to_rl(OF_parent(dt_node), &di->di_res, di->di_intr_sl)) {
405208747Sraj		device_printf(dev_child, "could not process 'interrupts' "
406208747Sraj		    "property\n");
407208747Sraj		newbus_device_destroy(dev_child);
408208747Sraj		dev_child = NULL;
409208747Sraj		goto out;
410208747Sraj	}
411208747Sraj
412208747Sraj	device_set_ivars(dev_child, di);
413208747Sraj	debugf("added child name='%s', node=%p\n", name,
414208747Sraj	    (void *)dt_node);
415208747Sraj
416208747Srajout:
417208747Sraj	return (dev_child);
418208747Sraj}
419208747Sraj
420208747Srajstatic void
421208747Srajpci_from_fdt_node(device_t dev_par, phandle_t dt_node, char *name,
422208747Sraj    char *type, char *compat)
423208747Sraj{
424208747Sraj	u_long reg_base, reg_size;
425208747Sraj	phandle_t dt_child;
426208747Sraj
427208747Sraj	/*
428208747Sraj	 * Retrieve 'reg' property.
429208747Sraj	 */
430208747Sraj	if (fdt_regsize(dt_node, &reg_base, &reg_size) != 0) {
431208747Sraj		device_printf(dev_par, "could not retrieve 'reg' prop\n");
432208747Sraj		return;
433208747Sraj	}
434208747Sraj
435208747Sraj	/*
436208747Sraj	 * Walk the PCI node and instantiate newbus devices representing
437208747Sraj	 * logical resources (bridges / ports).
438208747Sraj	 */
439208747Sraj	for (dt_child = OF_child(dt_node); dt_child != 0;
440208747Sraj	    dt_child = OF_peer(dt_child)) {
441208747Sraj
442208747Sraj		if (!(fdt_is_enabled(dt_child)))
443208747Sraj			continue;
444208747Sraj
445208747Sraj		newbus_pci_create(dev_par, dt_child, reg_base, reg_size);
446208747Sraj	}
447208747Sraj}
448208747Sraj
449208747Sraj/*
450208747Sraj * These FDT nodes do not need a corresponding newbus device object.
451208747Sraj */
452208747Srajstatic char *fdt_devices_skip[] = {
453208747Sraj	"aliases",
454208747Sraj	"chosen",
455208747Sraj	"memory",
456208747Sraj	NULL
457208747Sraj};
458208747Sraj
459208747Srajstatic void
460208747Srajnewbus_device_from_fdt_node(device_t dev_par, phandle_t node)
461208747Sraj{
462208747Sraj	char *name, *type, *compat;
463208747Sraj	device_t child;
464208747Sraj	int i;
465208747Sraj
466208747Sraj	OF_getprop_alloc(node, "name", 1, (void **)&name);
467208747Sraj	OF_getprop_alloc(node, "device_type", 1, (void **)&type);
468208747Sraj	OF_getprop_alloc(node, "compatible", 1, (void **)&compat);
469208747Sraj
470208747Sraj	for (i = 0; fdt_devices_skip[i] != NULL; i++)
471208747Sraj		if (name != NULL && strcmp(name, fdt_devices_skip[i]) == 0) {
472208747Sraj			debugf("skipping instantiating FDT device='%s'\n",
473208747Sraj			    name);
474208747Sraj			return;
475208747Sraj		}
476208747Sraj
477208747Sraj	child = newbus_device_create(dev_par, node, name, type, compat);
478218076Smarcel	if (type != NULL && strcmp(type, "pci") == 0)
479218076Smarcel		pci_from_fdt_node(child, node, name, type, compat);
480208747Sraj}
481208747Sraj
482208747Srajstatic struct resource *
483208747Srajfdtbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
484208747Sraj    u_long start, u_long end, u_long count, u_int flags)
485208747Sraj{
486208747Sraj	struct fdtbus_softc *sc;
487208747Sraj	struct resource *res;
488208747Sraj	struct rman *rm;
489208747Sraj	struct fdtbus_devinfo *di;
490208747Sraj	struct resource_list_entry *rle;
491208747Sraj	int needactivate;
492208747Sraj
493208747Sraj	/*
494208747Sraj	 * Request for the default allocation with a given rid: use resource
495208747Sraj	 * list stored in the local device info.
496208747Sraj	 */
497208747Sraj	if ((start == 0UL) && (end == ~0UL)) {
498208747Sraj		if ((di = device_get_ivars(child)) == NULL)
499208747Sraj			return (NULL);
500208747Sraj
501208747Sraj		if (type == SYS_RES_IOPORT)
502208747Sraj			type = SYS_RES_MEMORY;
503208747Sraj
504208747Sraj		rle = resource_list_find(&di->di_res, type, *rid);
505208747Sraj		if (rle == NULL) {
506208747Sraj			device_printf(bus, "no default resources for "
507208747Sraj			    "rid = %d, type = %d\n", *rid, type);
508208747Sraj			return (NULL);
509208747Sraj		}
510208747Sraj		start = rle->start;
511208747Sraj		end = rle->end;
512208747Sraj		count = rle->count;
513208747Sraj	}
514208747Sraj
515208747Sraj	sc = device_get_softc(bus);
516208747Sraj
517208747Sraj	needactivate = flags & RF_ACTIVE;
518208747Sraj	flags &= ~RF_ACTIVE;
519208747Sraj
520208747Sraj	switch (type) {
521208747Sraj	case SYS_RES_IRQ:
522208747Sraj		rm = &sc->sc_irq;
523208747Sraj		break;
524208747Sraj
525208747Sraj	case SYS_RES_IOPORT:
526208747Sraj	case SYS_RES_MEMORY:
527208747Sraj		rm = &sc->sc_mem;
528208747Sraj		break;
529208747Sraj
530208747Sraj	default:
531208747Sraj		return (NULL);
532208747Sraj	}
533208747Sraj
534208747Sraj	res = rman_reserve_resource(rm, start, end, count, flags, child);
535208747Sraj	if (res == NULL) {
536208747Sraj		device_printf(bus, "failed to reserve resource %#lx - %#lx "
537208747Sraj		    "(%#lx)\n", start, end, count);
538208747Sraj		return (NULL);
539208747Sraj	}
540208747Sraj
541208747Sraj	rman_set_rid(res, *rid);
542208747Sraj
543208747Sraj	if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) {
544208747Sraj		/* XXX endianess should be set based on SOC node */
545208747Sraj		rman_set_bustag(res, fdtbus_bs_tag);
546208747Sraj		rman_set_bushandle(res, rman_get_start(res));
547208747Sraj	}
548208747Sraj
549208747Sraj	if (needactivate)
550208747Sraj		if (bus_activate_resource(child, type, *rid, res)) {
551208747Sraj			device_printf(child, "resource activation failed\n");
552208747Sraj			rman_release_resource(res);
553208747Sraj			return (NULL);
554208747Sraj		}
555208747Sraj
556208747Sraj	return (res);
557208747Sraj}
558208747Sraj
559208747Srajstatic int
560208747Srajfdtbus_release_resource(device_t bus, device_t child, int type, int rid,
561208747Sraj    struct resource *res)
562208747Sraj{
563208747Sraj	int err;
564208747Sraj
565208747Sraj	if (rman_get_flags(res) & RF_ACTIVE) {
566208747Sraj		err = bus_deactivate_resource(child, type, rid, res);
567208747Sraj		if (err)
568208747Sraj			return (err);
569208747Sraj	}
570208747Sraj
571208747Sraj	return (rman_release_resource(res));
572208747Sraj}
573208747Sraj
574208747Srajstatic int
575208747Srajfdtbus_setup_intr(device_t bus, device_t child, struct resource *res,
576208747Sraj    int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg,
577208747Sraj    void **cookiep)
578208747Sraj{
579238043Smarcel	struct fdtbus_devinfo *di;
580238043Smarcel	enum intr_trigger trig;
581238043Smarcel	enum intr_polarity pol;
582238043Smarcel	int error, rid;
583208747Sraj
584238043Smarcel	if (res == NULL)
585238043Smarcel		return (EINVAL);
586208747Sraj
587238043Smarcel	/*
588238043Smarcel	 * We are responsible for configuring the interrupts of our direct
589238043Smarcel	 * children.
590238043Smarcel	 */
591238043Smarcel	if (device_get_parent(child) == bus) {
592238043Smarcel		di = device_get_ivars(child);
593238043Smarcel		if (di == NULL)
594238043Smarcel			return (ENXIO);
595208747Sraj
596238043Smarcel		rid = rman_get_rid(res);
597238043Smarcel		if (rid >= DI_MAX_INTR_NUM)
598238043Smarcel			return (ENOENT);
599208747Sraj
600238043Smarcel		trig = di->di_intr_sl[rid].trig;
601238043Smarcel		pol = di->di_intr_sl[rid].pol;
602238043Smarcel		if (trig != INTR_TRIGGER_CONFORM ||
603238043Smarcel		    pol != INTR_POLARITY_CONFORM) {
604238043Smarcel			error = bus_generic_config_intr(bus,
605238043Smarcel			    rman_get_start(res), trig, pol);
606238043Smarcel			if (error)
607238043Smarcel				return (error);
608238043Smarcel		}
609238043Smarcel	}
610238043Smarcel
611238043Smarcel	error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand,
612238043Smarcel	    arg, cookiep);
613238043Smarcel	return (error);
614208747Sraj}
615208747Sraj
616208747Srajstatic int
617208747Srajfdtbus_activate_resource(device_t bus, device_t child, int type, int rid,
618208747Sraj    struct resource *res)
619208747Sraj{
620248467Sray	bus_space_handle_t p;
621248467Sray	int error;
622208747Sraj
623248467Sray	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
624248467Sray		error = bus_space_map(rman_get_bustag(res),
625248467Sray		    rman_get_bushandle(res), rman_get_size(res), 0, &p);
626248467Sray		if (error)
627248467Sray			return (error);
628248467Sray		rman_set_bushandle(res, p);
629248467Sray	}
630248467Sray
631208747Sraj	return (rman_activate_resource(res));
632208747Sraj}
633208747Sraj
634208747Srajstatic int
635208747Srajfdtbus_deactivate_resource(device_t bus, device_t child, int type, int rid,
636208747Sraj    struct resource *res)
637208747Sraj{
638208747Sraj
639208747Sraj	return (rman_deactivate_resource(res));
640208747Sraj}
641208747Sraj
642208747Srajstatic const char *
643208747Srajfdtbus_ofw_get_name(device_t bus, device_t dev)
644208747Sraj{
645208747Sraj	struct fdtbus_devinfo *di;
646208747Sraj
647208747Sraj	return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_name);
648208747Sraj}
649208747Sraj
650208747Srajstatic phandle_t
651208747Srajfdtbus_ofw_get_node(device_t bus, device_t dev)
652208747Sraj{
653208747Sraj	struct fdtbus_devinfo *di;
654208747Sraj
655208747Sraj	return ((di = device_get_ivars(dev)) == NULL ? 0 : di->di_node);
656208747Sraj}
657208747Sraj
658208747Srajstatic const char *
659208747Srajfdtbus_ofw_get_type(device_t bus, device_t dev)
660208747Sraj{
661208747Sraj	struct fdtbus_devinfo *di;
662208747Sraj
663208747Sraj	return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_type);
664208747Sraj}
665208747Sraj
666208747Srajstatic const char *
667208747Srajfdtbus_ofw_get_compat(device_t bus, device_t dev)
668208747Sraj{
669208747Sraj	struct fdtbus_devinfo *di;
670208747Sraj
671208747Sraj	return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_compat);
672208747Sraj}
673208747Sraj
674208747Sraj
675