apb.c revision 276684
1155324Simp/*-
2155324Simp * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
3155324Simp * All rights reserved.
4155324Simp *
5155324Simp * Redistribution and use in source and binary forms, with or without
6155324Simp * modification, are permitted provided that the following conditions
7155324Simp * are met:
8155324Simp * 1. Redistributions of source code must retain the above copyright
9155324Simp *    notice unmodified, this list of conditions, and the following
10155324Simp *    disclaimer.
11155324Simp * 2. Redistributions in binary form must reproduce the above copyright
12155324Simp *    notice, this list of conditions and the following disclaimer in the
13155324Simp *    documentation and/or other materials provided with the distribution.
14155324Simp *
15155324Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16155324Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17155324Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18155324Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19155324Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20155324Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21155324Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22155324Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23155324Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24155324Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25155324Simp * SUCH DAMAGE.
26155324Simp */
27155324Simp
28155324Simp#include <sys/cdefs.h>
29155324Simp__FBSDID("$FreeBSD: head/sys/mips/atheros/apb.c 276684 2015-01-05 02:00:41Z adrian $");
30155324Simp
31155324Simp#include <sys/param.h>
32155324Simp#include <sys/systm.h>
33155324Simp#include <sys/bus.h>
34155324Simp#include <sys/interrupt.h>
35155324Simp#include <sys/kernel.h>
36155324Simp#include <sys/module.h>
37155324Simp#include <sys/rman.h>
38155324Simp#include <sys/malloc.h>
39155324Simp#include <sys/pcpu.h>
40155324Simp#include <sys/proc.h>
41155324Simp#include <sys/pmc.h>
42155324Simp#include <sys/pmckern.h>
43155324Simp
44155324Simp#include <machine/bus.h>
45155324Simp#include <machine/intr_machdep.h>
46155324Simp
47155324Simp#include <mips/atheros/apbvar.h>
48155324Simp#include <mips/atheros/ar71xxreg.h>
49155324Simp#include <mips/atheros/ar71xx_setup.h>
50155324Simp
51155324Simp#define	APB_INTR_PMC	5
52155324Simp
53155324Simp#undef APB_DEBUG
54155324Simp#ifdef APB_DEBUG
55155324Simp#define dprintf printf
56155324Simp#else
57155324Simp#define dprintf(x, arg...)
58155324Simp#endif  /* APB_DEBUG */
59155324Simp
60155324Simp#define	DEVTOAPB(dev)	((struct apb_ivar *) device_get_ivars(dev))
61155324Simp
62155324Simpstatic int	apb_activate_resource(device_t, device_t, int, int,
63155324Simp		    struct resource *);
64155324Simpstatic device_t	apb_add_child(device_t, u_int, const char *, int);
65155324Simpstatic struct resource *
66155324Simp		apb_alloc_resource(device_t, device_t, int, int *, u_long,
67155324Simp		    u_long, u_long, u_int);
68155324Simpstatic int	apb_attach(device_t);
69155324Simpstatic int	apb_deactivate_resource(device_t, device_t, int, int,
70155324Simp		    struct resource *);
71155324Simpstatic struct resource_list *
72155324Simp		apb_get_resource_list(device_t, device_t);
73155324Simpstatic void	apb_hinted_child(device_t, const char *, int);
74155324Simpstatic int	apb_filter(void *);
75155324Simpstatic int	apb_probe(device_t);
76155324Simpstatic int	apb_release_resource(device_t, device_t, int, int,
77155324Simp		    struct resource *);
78155324Simpstatic int	apb_setup_intr(device_t, device_t, struct resource *, int,
79155324Simp		    driver_filter_t *, driver_intr_t *, void *, void **);
80155324Simpstatic int	apb_teardown_intr(device_t, device_t, struct resource *,
81155324Simp		    void *);
82155324Simp
83155324Simpstatic void
84155324Simpapb_mask_irq(void *source)
85155324Simp{
86155324Simp	unsigned int irq = (unsigned int)source;
87155324Simp	uint32_t reg;
88155324Simp
89155324Simp	reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK);
90155324Simp	ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg & ~(1 << irq));
91155324Simp
92155324Simp}
93155324Simp
94155324Simpstatic void
95155324Simpapb_unmask_irq(void *source)
96155324Simp{
97155324Simp	uint32_t reg;
98155324Simp	unsigned int irq = (unsigned int)source;
99155324Simp
100155324Simp	reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK);
101155324Simp	ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg | (1 << irq));
102155324Simp}
103155324Simp
104155324Simpstatic int
105155324Simpapb_probe(device_t dev)
106155324Simp{
107155324Simp
108155324Simp	return (BUS_PROBE_NOWILDCARD);
109155324Simp}
110155324Simp
111155324Simpstatic int
112155324Simpapb_attach(device_t dev)
113155324Simp{
114155324Simp	struct apb_softc *sc = device_get_softc(dev);
115155324Simp	int rid = 0;
116155324Simp
117155324Simp	device_set_desc(dev, "APB Bus bridge");
118155324Simp
119155324Simp	sc->apb_mem_rman.rm_type = RMAN_ARRAY;
120155324Simp	sc->apb_mem_rman.rm_descr = "APB memory window";
121155324Simp
122155324Simp	if (rman_init(&sc->apb_mem_rman) != 0 ||
123155324Simp	    rman_manage_region(&sc->apb_mem_rman,
124155324Simp			AR71XX_APB_BASE,
125155324Simp			AR71XX_APB_BASE + AR71XX_APB_SIZE - 1) != 0)
126155324Simp		panic("apb_attach: failed to set up memory rman");
127155324Simp
128155324Simp	sc->apb_irq_rman.rm_type = RMAN_ARRAY;
129155324Simp	sc->apb_irq_rman.rm_descr = "APB IRQ";
130155324Simp
131155324Simp	if (rman_init(&sc->apb_irq_rman) != 0 ||
132155324Simp	    rman_manage_region(&sc->apb_irq_rman,
133155324Simp			APB_IRQ_BASE, APB_IRQ_END) != 0)
134155324Simp		panic("apb_attach: failed to set up IRQ rman");
135155324Simp
136155324Simp	if ((sc->sc_misc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
137155324Simp	    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
138155324Simp		device_printf(dev, "unable to allocate IRQ resource\n");
139155324Simp		return (ENXIO);
140155324Simp	}
141155324Simp
142155324Simp	if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC,
143155324Simp	    apb_filter, NULL, sc, &sc->sc_misc_ih))) {
144155324Simp		device_printf(dev,
145155324Simp		    "WARNING: unable to register interrupt handler\n");
146155324Simp		return (ENXIO);
147155324Simp	}
148155324Simp
149155324Simp	bus_generic_probe(dev);
150155324Simp	bus_enumerate_hinted_children(dev);
151155324Simp	bus_generic_attach(dev);
152155324Simp
153155324Simp	/*
154155324Simp	 * Unmask performance counter IRQ
155155324Simp	 */
156155324Simp	apb_unmask_irq((void*)APB_INTR_PMC);
157155324Simp	sc->sc_intr_counter[APB_INTR_PMC] = mips_intrcnt_create("apb irq5: pmc");
158155324Simp
159155324Simp	return (0);
160155324Simp}
161155324Simp
162155324Simpstatic struct resource *
163155324Simpapb_alloc_resource(device_t bus, device_t child, int type, int *rid,
164155324Simp    u_long start, u_long end, u_long count, u_int flags)
165155324Simp{
166155324Simp	struct apb_softc		*sc = device_get_softc(bus);
167155324Simp	struct apb_ivar			*ivar = device_get_ivars(child);
168155324Simp	struct resource			*rv;
169155324Simp	struct resource_list_entry	*rle;
170155324Simp	struct rman			*rm;
171155324Simp	int				 isdefault, needactivate, passthrough;
172155324Simp
173155324Simp	isdefault = (start == 0UL && end == ~0UL);
174155324Simp	needactivate = flags & RF_ACTIVE;
175155324Simp	/*
176155324Simp	 * Pass memory requests to nexus device
177155324Simp	 */
178155324Simp	passthrough = (device_get_parent(child) != bus);
179155324Simp	rle = NULL;
180155324Simp
181155324Simp	dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %ld, %d)\n",
182155324Simp	    __func__, bus, child, type, *rid, (void *)(intptr_t)start,
183155324Simp	    (void *)(intptr_t)end, count, flags);
184155324Simp
185155324Simp	if (passthrough)
186155324Simp		return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
187155324Simp		    rid, start, end, count, flags));
188155324Simp
189155324Simp	/*
190155324Simp	 * If this is an allocation of the "default" range for a given RID,
191155324Simp	 * and we know what the resources for this device are (ie. they aren't
192155324Simp	 * maintained by a child bus), then work out the start/end values.
193155324Simp	 */
194155324Simp
195155324Simp	if (isdefault) {
196155324Simp		rle = resource_list_find(&ivar->resources, type, *rid);
197155324Simp		if (rle == NULL) {
198155324Simp			return (NULL);
199155324Simp		}
200155324Simp
201155324Simp		if (rle->res != NULL) {
202155324Simp			panic("%s: resource entry is busy", __func__);
203155324Simp		}
204155324Simp		start = rle->start;
205155324Simp		end = rle->end;
206155324Simp		count = rle->count;
207155324Simp
208155324Simp		dprintf("%s: default resource (%p, %p, %ld)\n",
209155324Simp		    __func__, (void *)(intptr_t)start,
210155324Simp		    (void *)(intptr_t)end, count);
211155324Simp	}
212155324Simp
213155324Simp	switch (type) {
214155324Simp	case SYS_RES_IRQ:
215155324Simp		rm = &sc->apb_irq_rman;
216155324Simp		break;
217155324Simp	case SYS_RES_MEMORY:
218155324Simp		rm = &sc->apb_mem_rman;
219155324Simp		break;
220155324Simp	default:
221155324Simp		printf("%s: unknown resource type %d\n", __func__, type);
222155324Simp		return (0);
223155324Simp	}
224155324Simp
225155324Simp	rv = rman_reserve_resource(rm, start, end, count, flags, child);
226155324Simp	if (rv == 0) {
227155324Simp		printf("%s: could not reserve resource\n", __func__);
228155324Simp		return (0);
229155324Simp	}
230155324Simp
231155324Simp	rman_set_rid(rv, *rid);
232155324Simp
233155324Simp	if (needactivate) {
234155324Simp		if (bus_activate_resource(child, type, *rid, rv)) {
235155324Simp			printf("%s: could not activate resource\n", __func__);
236155324Simp			rman_release_resource(rv);
237155324Simp			return (0);
238155324Simp		}
239155324Simp	}
240155324Simp
241155324Simp	return (rv);
242155324Simp}
243155324Simp
244155324Simpstatic int
245155324Simpapb_activate_resource(device_t bus, device_t child, int type, int rid,
246155324Simp    struct resource *r)
247155324Simp{
248155324Simp
249155324Simp	/* XXX: should we mask/unmask IRQ here? */
250155324Simp	return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
251155324Simp		type, rid, r));
252155324Simp}
253155324Simp
254155324Simpstatic int
255155324Simpapb_deactivate_resource(device_t bus, device_t child, int type, int rid,
256155324Simp    struct resource *r)
257155324Simp{
258155324Simp
259155324Simp	/* XXX: should we mask/unmask IRQ here? */
260155324Simp	return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
261155324Simp		type, rid, r));
262155324Simp}
263155324Simp
264155324Simpstatic int
265155324Simpapb_release_resource(device_t dev, device_t child, int type,
266155324Simp    int rid, struct resource *r)
267155324Simp{
268155324Simp	struct resource_list *rl;
269155324Simp	struct resource_list_entry *rle;
270155324Simp
271155324Simp	rl = apb_get_resource_list(dev, child);
272155324Simp	if (rl == NULL)
273155324Simp		return (EINVAL);
274155324Simp	rle = resource_list_find(rl, type, rid);
275155324Simp	if (rle == NULL)
276155324Simp		return (EINVAL);
277155324Simp	rman_release_resource(r);
278155324Simp	rle->res = NULL;
279155324Simp
280155324Simp	return (0);
281155324Simp}
282155324Simp
283155324Simpstatic int
284155324Simpapb_setup_intr(device_t bus, device_t child, struct resource *ires,
285155324Simp		int flags, driver_filter_t *filt, driver_intr_t *handler,
286155324Simp		void *arg, void **cookiep)
287155324Simp{
288155324Simp	struct apb_softc *sc = device_get_softc(bus);
289155324Simp	struct intr_event *event;
290155324Simp	int irq, error;
291155324Simp
292155324Simp	irq = rman_get_start(ires);
293155324Simp
294155324Simp	if (irq > APB_IRQ_END)
295155324Simp		panic("%s: bad irq %d", __func__, irq);
296155324Simp
297155324Simp	event = sc->sc_eventstab[irq];
298155324Simp	if (event == NULL) {
299155324Simp		error = intr_event_create(&event, (void *)irq, 0, irq,
300155324Simp		    apb_mask_irq, apb_unmask_irq,
301155324Simp		    NULL, NULL,
302155324Simp		    "apb intr%d:", irq);
303155324Simp
304155324Simp		if (error == 0) {
305155324Simp			sc->sc_eventstab[irq] = event;
306155324Simp			sc->sc_intr_counter[irq] =
307155324Simp			    mips_intrcnt_create(event->ie_name);
308155324Simp		}
309155324Simp		else
310155324Simp			return (error);
311155324Simp	}
312155324Simp
313155324Simp	intr_event_add_handler(event, device_get_nameunit(child), filt,
314155324Simp	    handler, arg, intr_priority(flags), flags, cookiep);
315155324Simp	mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname);
316155324Simp
317155324Simp	apb_unmask_irq((void*)irq);
318155324Simp
319155324Simp	return (0);
320155324Simp}
321155324Simp
322155324Simpstatic int
323155324Simpapb_teardown_intr(device_t dev, device_t child, struct resource *ires,
324155324Simp    void *cookie)
325155324Simp{
326155324Simp	struct apb_softc *sc = device_get_softc(dev);
327155324Simp	int irq, result;
328155324Simp
329155324Simp	irq = rman_get_start(ires);
330155324Simp	if (irq > APB_IRQ_END)
331155324Simp		panic("%s: bad irq %d", __func__, irq);
332155324Simp
333155324Simp	if (sc->sc_eventstab[irq] == NULL)
334155324Simp		panic("Trying to teardown unoccupied IRQ");
335155324Simp
336155324Simp	apb_mask_irq((void*)irq);
337155324Simp
338155324Simp	result = intr_event_remove_handler(cookie);
339155324Simp	if (!result)
340155324Simp		sc->sc_eventstab[irq] = NULL;
341155324Simp
342155324Simp	return (result);
343155324Simp}
344155324Simp
345155324Simpstatic int
346155324Simpapb_filter(void *arg)
347155324Simp{
348155324Simp	struct apb_softc *sc = arg;
349155324Simp	struct intr_event *event;
350155324Simp	uint32_t reg, irq;
351155324Simp	struct thread *td;
352155324Simp	struct trapframe *tf;
353155324Simp
354155324Simp	reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS);
355155324Simp	for (irq = 0; irq < APB_NIRQS; irq++) {
356155324Simp		if (reg & (1 << irq)) {
357155324Simp
358155324Simp			switch (ar71xx_soc) {
359155324Simp			case AR71XX_SOC_AR7240:
360155324Simp			case AR71XX_SOC_AR7241:
361155324Simp			case AR71XX_SOC_AR7242:
362155324Simp			case AR71XX_SOC_AR9330:
363155324Simp			case AR71XX_SOC_AR9331:
364155324Simp			case AR71XX_SOC_AR9341:
365155324Simp			case AR71XX_SOC_AR9342:
366155324Simp			case AR71XX_SOC_AR9344:
367155324Simp			case AR71XX_SOC_QCA9556:
368155324Simp			case AR71XX_SOC_QCA9558:
369155324Simp				/* ACK/clear the given interrupt */
370155324Simp				ATH_WRITE_REG(AR71XX_MISC_INTR_STATUS,
371155324Simp				    (1 << irq));
372155324Simp				break;
373155324Simp			default:
374155324Simp				/* fallthrough */
375155324Simp				break;
376155324Simp			}
377155324Simp
378155324Simp			event = sc->sc_eventstab[irq];
379155324Simp			if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
380155324Simp				if (irq == APB_INTR_PMC) {
381155324Simp					td = PCPU_GET(curthread);
382155324Simp					tf = td->td_intr_frame;
383155324Simp
384155324Simp					if (pmc_intr)
385155324Simp						(*pmc_intr)(PCPU_GET(cpuid), tf);
386155324Simp
387155324Simp					mips_intrcnt_inc(sc->sc_intr_counter[irq]);
388155324Simp
389155324Simp					continue;
390155324Simp				}
391155324Simp				/* Ignore timer interrupts */
392155324Simp				if (irq != 0 && irq != 8 && irq != 9 && irq != 10)
393155324Simp					printf("Stray APB IRQ %d\n", irq);
394155324Simp				continue;
395155324Simp			}
396155324Simp
397155324Simp			intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame);
398155324Simp			mips_intrcnt_inc(sc->sc_intr_counter[irq]);
399155324Simp		}
400155324Simp	}
401155324Simp
402155324Simp	return (FILTER_HANDLED);
403155324Simp}
404155324Simp
405155324Simpstatic void
406155324Simpapb_hinted_child(device_t bus, const char *dname, int dunit)
407155324Simp{
408155324Simp	device_t		child;
409155324Simp	long			maddr;
410155324Simp	int			msize;
411155324Simp	int			irq;
412155324Simp	int			result;
413155324Simp	int			mem_hints_count;
414155324Simp
415155324Simp	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
416155324Simp
417155324Simp	/*
418155324Simp	 * Set hard-wired resources for hinted child using
419155324Simp	 * specific RIDs.
420155324Simp	 */
421155324Simp	mem_hints_count = 0;
422155324Simp	if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
423155324Simp		mem_hints_count++;
424155324Simp	if (resource_int_value(dname, dunit, "msize", &msize) == 0)
425155324Simp		mem_hints_count++;
426155324Simp
427155324Simp	/* check if all info for mem resource has been provided */
428155324Simp	if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
429155324Simp		printf("Either maddr or msize hint is missing for %s%d\n",
430155324Simp		    dname, dunit);
431155324Simp	} else if (mem_hints_count) {
432155324Simp		result = bus_set_resource(child, SYS_RES_MEMORY, 0,
433155324Simp		    maddr, msize);
434155324Simp		if (result != 0)
435155324Simp			device_printf(bus,
436155324Simp			    "warning: bus_set_resource() failed\n");
437155324Simp	}
438155324Simp
439155324Simp	if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
440155324Simp		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
441155324Simp		if (result != 0)
442155324Simp			device_printf(bus,
443155324Simp			    "warning: bus_set_resource() failed\n");
444155324Simp	}
445155324Simp}
446155324Simp
447155324Simpstatic device_t
448155324Simpapb_add_child(device_t bus, u_int order, const char *name, int unit)
449155324Simp{
450155324Simp	device_t		child;
451155324Simp	struct apb_ivar	*ivar;
452155324Simp
453155324Simp	ivar = malloc(sizeof(struct apb_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
454155324Simp	if (ivar == NULL) {
455155324Simp		printf("Failed to allocate ivar\n");
456155324Simp		return (0);
457155324Simp	}
458155324Simp	resource_list_init(&ivar->resources);
459155324Simp
460155324Simp	child = device_add_child_ordered(bus, order, name, unit);
461155324Simp	if (child == NULL) {
462155324Simp		printf("Can't add child %s%d ordered\n", name, unit);
463155324Simp		return (0);
464155324Simp	}
465155324Simp
466155324Simp	device_set_ivars(child, ivar);
467155324Simp
468155324Simp	return (child);
469155324Simp}
470155324Simp
471155324Simp/*
472155324Simp * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
473155324Simp * Provides pointer to resource_list for these routines
474155324Simp */
475155324Simpstatic struct resource_list *
476155324Simpapb_get_resource_list(device_t dev, device_t child)
477155324Simp{
478155324Simp	struct apb_ivar *ivar;
479155324Simp
480155324Simp	ivar = device_get_ivars(child);
481155324Simp	return (&(ivar->resources));
482155324Simp}
483155324Simp
484155324Simpstatic int
485155324Simpapb_print_all_resources(device_t dev)
486155324Simp{
487155324Simp	struct apb_ivar *ndev = DEVTOAPB(dev);
488155324Simp	struct resource_list *rl = &ndev->resources;
489155324Simp	int retval = 0;
490155324Simp
491155324Simp	if (STAILQ_FIRST(rl))
492155324Simp		retval += printf(" at");
493155324Simp
494155324Simp	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
495155324Simp	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
496155324Simp
497155324Simp	return (retval);
498155324Simp}
499155324Simp
500155324Simpstatic int
501155324Simpapb_print_child(device_t bus, device_t child)
502155324Simp{
503155324Simp	int retval = 0;
504155324Simp
505155324Simp	retval += bus_print_child_header(bus, child);
506155324Simp	retval += apb_print_all_resources(child);
507155324Simp	if (device_get_flags(child))
508155324Simp		retval += printf(" flags %#x", device_get_flags(child));
509155324Simp	retval += printf(" on %s\n", device_get_nameunit(bus));
510155324Simp
511155324Simp	return (retval);
512155324Simp}
513155324Simp
514155324Simp
515155324Simpstatic device_method_t apb_methods[] = {
516155324Simp	DEVMETHOD(bus_activate_resource,	apb_activate_resource),
517155324Simp	DEVMETHOD(bus_add_child,		apb_add_child),
518155324Simp	DEVMETHOD(bus_alloc_resource,		apb_alloc_resource),
519155324Simp	DEVMETHOD(bus_deactivate_resource,	apb_deactivate_resource),
520155324Simp	DEVMETHOD(bus_get_resource_list,	apb_get_resource_list),
521155324Simp	DEVMETHOD(bus_hinted_child,		apb_hinted_child),
522155324Simp	DEVMETHOD(bus_release_resource,		apb_release_resource),
523155324Simp	DEVMETHOD(bus_setup_intr,		apb_setup_intr),
524155324Simp	DEVMETHOD(bus_teardown_intr,		apb_teardown_intr),
525155324Simp	DEVMETHOD(device_attach,		apb_attach),
526155324Simp	DEVMETHOD(device_probe,			apb_probe),
527155324Simp	DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
528155324Simp	DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
529155324Simp	DEVMETHOD(bus_print_child,		apb_print_child),
530155324Simp
531155324Simp	DEVMETHOD_END
532155324Simp};
533155324Simp
534155324Simpstatic driver_t apb_driver = {
535155324Simp	"apb",
536155324Simp	apb_methods,
537155324Simp	sizeof(struct apb_softc),
538155324Simp};
539155324Simpstatic devclass_t apb_devclass;
540155324Simp
541155324SimpDRIVER_MODULE(apb, nexus, apb_driver, apb_devclass, 0, 0);
542155324Simp