apb.c revision 298053
11558Srgrimes/*-
21558Srgrimes * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
31558Srgrimes * All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice unmodified, this list of conditions, and the following
101558Srgrimes *    disclaimer.
111558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer in the
131558Srgrimes *    documentation and/or other materials provided with the distribution.
141558Srgrimes *
151558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251558Srgrimes * SUCH DAMAGE.
261558Srgrimes */
271558Srgrimes
281558Srgrimes#include <sys/cdefs.h>
2950476Speter__FBSDID("$FreeBSD: head/sys/mips/atheros/apb.c 298053 2016-04-15 14:26:24Z pfg $");
301558Srgrimes
31157535Sglebius#include <sys/param.h>
321558Srgrimes#include <sys/systm.h>
3379530Sru#include <sys/bus.h>
341558Srgrimes#include <sys/interrupt.h>
351558Srgrimes#include <sys/kernel.h>
361558Srgrimes#include <sys/module.h>
371558Srgrimes#include <sys/rman.h>
381558Srgrimes#include <sys/malloc.h>
391558Srgrimes#include <sys/pcpu.h>
4068960Sru#include <sys/proc.h>
41112985Smdodd#include <sys/pmc.h>
421558Srgrimes#include <sys/pmckern.h>
43149086Sglebius
44149086Sglebius#include <machine/bus.h>
45149086Sglebius#include <machine/intr_machdep.h>
461558Srgrimes
471558Srgrimes#include <mips/atheros/apbvar.h>
48112110Sru#include <mips/atheros/ar71xxreg.h>
4974029Sru#include <mips/atheros/ar71xx_setup.h>
50111287Sru
511558Srgrimes#define	APB_INTR_PMC	5
52111287Sru
531558Srgrimes#undef APB_DEBUG
5456342Sbillf#ifdef APB_DEBUG
55157535Sglebius#define dprintf printf
56109731Smaxim#else
57112110Sru#define dprintf(x, arg...)
58112110Sru#endif  /* APB_DEBUG */
59112985Smdodd
60112110Sru#define	DEVTOAPB(dev)	((struct apb_ivar *) device_get_ivars(dev))
61112110Sru
62112110Srustatic int	apb_activate_resource(device_t, device_t, int, int,
63112110Sru		    struct resource *);
64112110Srustatic device_t	apb_add_child(device_t, u_int, const char *, int);
65112110Srustatic struct resource *
66112110Sru		apb_alloc_resource(device_t, device_t, int, int *, rman_res_t,
67112110Sru		    rman_res_t, rman_res_t, u_int);
68112110Srustatic int	apb_attach(device_t);
69112110Srustatic int	apb_deactivate_resource(device_t, device_t, int, int,
7020540Sfenner		    struct resource *);
71112110Srustatic struct resource_list *
72157535Sglebius		apb_get_resource_list(device_t, device_t);
73112110Srustatic void	apb_hinted_child(device_t, const char *, int);
7423251Simpstatic int	apb_filter(void *);
751558Srgrimesstatic int	apb_probe(device_t);
7699501Scharnierstatic int	apb_release_resource(device_t, device_t, int, int,
7799501Scharnier		    struct resource *);
7899501Scharnierstatic int	apb_setup_intr(device_t, device_t, struct resource *, int,
791558Srgrimes		    driver_filter_t *, driver_intr_t *, void *, void **);
8023304Sjmgstatic int	apb_teardown_intr(device_t, device_t, struct resource *,
811558Srgrimes		    void *);
821558Srgrimes
831558Srgrimesstatic void
841558Srgrimesapb_mask_irq(void *source)
851558Srgrimes{
8623304Sjmg	unsigned int irq = (unsigned int)source;
8723304Sjmg	uint32_t reg;
8823304Sjmg
891558Srgrimes	reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK);
9023304Sjmg	ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg & ~(1 << irq));
911558Srgrimes
9223304Sjmg}
9323304Sjmg
94111287Srustatic void
95111287Sruapb_unmask_irq(void *source)
9637671Scharnier{
9777119Sphk	uint32_t reg;
9877119Sphk	unsigned int irq = (unsigned int)source;
9983940Siedowse
10081251Sru	reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK);
10181251Sru	ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg | (1 << irq));
10283940Siedowse}
10377119Sphk
10483940Siedowsestatic int
10583940Siedowseapb_probe(device_t dev)
10683940Siedowse{
10722417Sdanny
10857668Ssheldonh	return (BUS_PROBE_NOWILDCARD);
10957668Ssheldonh}
11081251Sru
11181251Srustatic int
11257668Ssheldonhapb_attach(device_t dev)
11357668Ssheldonh{
11423304Sjmg	struct apb_softc *sc = device_get_softc(dev);
1151558Srgrimes	int rid = 0;
11623304Sjmg
11781251Sru	device_set_desc(dev, "APB Bus bridge");
1181558Srgrimes
1191558Srgrimes	sc->apb_mem_rman.rm_type = RMAN_ARRAY;
12041409Sbde	sc->apb_mem_rman.rm_descr = "APB memory window";
12141409Sbde
12241409Sbde	if (rman_init(&sc->apb_mem_rman) != 0 ||
12341409Sbde	    rman_manage_region(&sc->apb_mem_rman,
124149086Sglebius			AR71XX_APB_BASE,
125149086Sglebius			AR71XX_APB_BASE + AR71XX_APB_SIZE - 1) != 0)
126149086Sglebius		panic("apb_attach: failed to set up memory rman");
127149086Sglebius
128111287Sru	sc->apb_irq_rman.rm_type = RMAN_ARRAY;
129111287Sru	sc->apb_irq_rman.rm_descr = "APB IRQ";
1301558Srgrimes
1311558Srgrimes	if (rman_init(&sc->apb_irq_rman) != 0 ||
1321558Srgrimes	    rman_manage_region(&sc->apb_irq_rman,
1331558Srgrimes			APB_IRQ_BASE, APB_IRQ_END) != 0)
1341558Srgrimes		panic("apb_attach: failed to set up IRQ rman");
1351558Srgrimes
1361558Srgrimes	if ((sc->sc_misc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1371558Srgrimes	    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1381558Srgrimes		device_printf(dev, "unable to allocate IRQ resource\n");
1391558Srgrimes		return (ENXIO);
14079754Sdd	}
14170152Sru
14223304Sjmg	if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC,
1431558Srgrimes	    apb_filter, NULL, sc, &sc->sc_misc_ih))) {
14441409Sbde		device_printf(dev,
1451558Srgrimes		    "WARNING: unable to register interrupt handler\n");
1461558Srgrimes		return (ENXIO);
1471558Srgrimes	}
1481558Srgrimes
1491558Srgrimes	bus_generic_probe(dev);
150149086Sglebius	bus_enumerate_hinted_children(dev);
151149086Sglebius	bus_generic_attach(dev);
152149086Sglebius
153149086Sglebius	/*
154152568Sru	 * Unmask performance counter IRQ
155149086Sglebius	 */
156149086Sglebius	apb_unmask_irq((void*)APB_INTR_PMC);
157149086Sglebius	sc->sc_intr_counter[APB_INTR_PMC] = mips_intrcnt_create("apb irq5: pmc");
158152568Sru
159149086Sglebius	return (0);
160149086Sglebius}
161149086Sglebius
162149086Sglebiusstatic struct resource *
163149086Sglebiusapb_alloc_resource(device_t bus, device_t child, int type, int *rid,
164152568Sru    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
165152568Sru{
166112110Sru	struct apb_softc		*sc = device_get_softc(bus);
167111287Sru	struct apb_ivar			*ivar = device_get_ivars(child);
168111287Sru	struct resource			*rv;
1691558Srgrimes	struct resource_list_entry	*rle;
1701558Srgrimes	struct rman			*rm;
1711558Srgrimes	int				 isdefault, needactivate, passthrough;
1721558Srgrimes
1731558Srgrimes	isdefault = (RMAN_IS_DEFAULT_RANGE(start, end));
17441409Sbde	needactivate = flags & RF_ACTIVE;
17541409Sbde	/*
176108260Sru	 * Pass memory requests to nexus device
17741409Sbde	 */
1781558Srgrimes	passthrough = (device_get_parent(child) != bus);
1791558Srgrimes	rle = NULL;
180111287Sru
181111287Sru	dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %jd, %d)\n",
18220540Sfenner	    __func__, bus, child, type, *rid, (void *)(intptr_t)start,
1831558Srgrimes	    (void *)(intptr_t)end, count, flags);
1841558Srgrimes
1851558Srgrimes	if (passthrough)
1861558Srgrimes		return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
18737671Scharnier		    rid, start, end, count, flags));
1881558Srgrimes
1891558Srgrimes	/*
19023295Simp	 * If this is an allocation of the "default" range for a given RID,
191112110Sru	 * and we know what the resources for this device are (ie. they aren't
192112110Sru	 * maintained by a child bus), then work out the start/end values.
193112110Sru	 */
194112110Sru
195112110Sru	if (isdefault) {
196112110Sru		rle = resource_list_find(&ivar->resources, type, *rid);
197112110Sru		if (rle == NULL) {
198112110Sru			return (NULL);
199112110Sru		}
200112110Sru
201112110Sru		if (rle->res != NULL) {
202111765Smdodd			panic("%s: resource entry is busy", __func__);
203112110Sru		}
204112110Sru		start = rle->start;
205111765Smdodd		end = rle->end;
206112110Sru		count = rle->count;
207111930Smdodd
208111927Smdodd		dprintf("%s: default resource (%p, %p, %ld)\n",
209111927Smdodd		    __func__, (void *)(intptr_t)start,
210111927Smdodd		    (void *)(intptr_t)end, count);
211111927Smdodd	}
212111927Smdodd
2131558Srgrimes	switch (type) {
2141558Srgrimes	case SYS_RES_IRQ:
2151558Srgrimes		rm = &sc->apb_irq_rman;
216104339Sdd		break;
217104339Sdd	case SYS_RES_MEMORY:
218111287Sru		rm = &sc->apb_mem_rman;
219111287Sru		break;
220111287Sru	default:
221111287Sru		printf("%s: unknown resource type %d\n", __func__, type);
222111287Sru		return (0);
223111287Sru	}
224111287Sru
2251558Srgrimes	rv = rman_reserve_resource(rm, start, end, count, flags, child);
22623304Sjmg	if (rv == NULL) {
22723304Sjmg		printf("%s: could not reserve resource\n", __func__);
22823304Sjmg		return (0);
2291558Srgrimes	}
2301558Srgrimes
2311558Srgrimes	rman_set_rid(rv, *rid);
2321558Srgrimes
2331558Srgrimes	if (needactivate) {
23417724Sfenner		if (bus_activate_resource(child, type, *rid, rv)) {
23517724Sfenner			printf("%s: could not activate resource\n", __func__);
23623304Sjmg			rman_release_resource(rv);
23723304Sjmg			return (0);
23817724Sfenner		}
23917724Sfenner	}
24017724Sfenner
24117724Sfenner	return (rv);
242111287Sru}
243111287Sru
244111287Srustatic int
24517724Sfennerapb_activate_resource(device_t bus, device_t child, int type, int rid,
24679754Sdd    struct resource *r)
24717724Sfenner{
24817724Sfenner
24917724Sfenner	/* XXX: should we mask/unmask IRQ here? */
2501558Srgrimes	return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
2511558Srgrimes		type, rid, r));
2521558Srgrimes}
2531558Srgrimes
2541558Srgrimesstatic int
2551558Srgrimesapb_deactivate_resource(device_t bus, device_t child, int type, int rid,
2561558Srgrimes    struct resource *r)
2571558Srgrimes{
2581558Srgrimes
2591558Srgrimes	/* XXX: should we mask/unmask IRQ here? */
2601558Srgrimes	return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
2611558Srgrimes		type, rid, r));
26223247Swollman}
26323247Swollman
26423247Swollmanstatic int
26523247Swollmanapb_release_resource(device_t dev, device_t child, int type,
26623247Swollman    int rid, struct resource *r)
26734976Simp{
26834976Simp	struct resource_list *rl;
26934976Simp	struct resource_list_entry *rle;
27023247Swollman
27123247Swollman	rl = apb_get_resource_list(dev, child);
27223247Swollman	if (rl == NULL)
2731558Srgrimes		return (EINVAL);
2741558Srgrimes	rle = resource_list_find(rl, type, rid);
2751558Srgrimes	if (rle == NULL)
2761558Srgrimes		return (EINVAL);
2771558Srgrimes	rman_release_resource(r);
27879754Sdd	rle->res = NULL;
27981251Sru
28081251Sru	return (0);
281111287Sru}
282111287Sru
283111287Srustatic int
284111287Sruapb_setup_intr(device_t bus, device_t child, struct resource *ires,
285111287Sru		int flags, driver_filter_t *filt, driver_intr_t *handler,
286111287Sru		void *arg, void **cookiep)
287111287Sru{
288111287Sru	struct apb_softc *sc = device_get_softc(bus);
2891558Srgrimes	struct intr_event *event;
29079754Sdd	int irq, error;
2911558Srgrimes
2921558Srgrimes	irq = rman_get_start(ires);
2931558Srgrimes
2941558Srgrimes	if (irq > APB_IRQ_END)
2951558Srgrimes		panic("%s: bad irq %d", __func__, irq);
29641409Sbde
297109734Smaxim	event = sc->sc_eventstab[irq];
298149086Sglebius	if (event == NULL) {
299111287Sru		error = intr_event_create(&event, (void *)irq, 0, irq,
300111287Sru		    apb_mask_irq, apb_unmask_irq,
301111287Sru		    NULL, NULL,
30255996Sbillf		    "apb intr%d:", irq);
30355996Sbillf
304108317Sschweikh		if (error == 0) {
3051558Srgrimes			sc->sc_eventstab[irq] = event;
3061558Srgrimes			sc->sc_intr_counter[irq] =
3071558Srgrimes			    mips_intrcnt_create(event->ie_name);
3081558Srgrimes		}
3091558Srgrimes		else
3101558Srgrimes			return (error);
311157535Sglebius	}
312157535Sglebius
313157535Sglebius	intr_event_add_handler(event, device_get_nameunit(child), filt,
314157535Sglebius	    handler, arg, intr_priority(flags), flags, cookiep);
315109731Smaxim	mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname);
316109731Smaxim
3171558Srgrimes	apb_unmask_irq((void*)irq);
3181558Srgrimes
3191558Srgrimes	return (0);
32023304Sjmg}
3211558Srgrimes
3221558Srgrimesstatic int
32379754Sddapb_teardown_intr(device_t dev, device_t child, struct resource *ires,
32423304Sjmg    void *cookie)
3251558Srgrimes{
3261558Srgrimes	struct apb_softc *sc = device_get_softc(dev);
3271558Srgrimes	int irq, result;
32827508Swollman
32923304Sjmg	irq = rman_get_start(ires);
33081251Sru	if (irq > APB_IRQ_END)
33123304Sjmg		panic("%s: bad irq %d", __func__, irq);
3321558Srgrimes
33327508Swollman	if (sc->sc_eventstab[irq] == NULL)
33490351Smaxim		panic("Trying to teardown unoccupied IRQ");
33527508Swollman
3361558Srgrimes	apb_mask_irq((void*)irq);
33790351Smaxim
33890351Smaxim	result = intr_event_remove_handler(cookie);
33990351Smaxim	if (!result)
34090351Smaxim		sc->sc_eventstab[irq] = NULL;
34190351Smaxim
34290351Smaxim	return (result);
34390351Smaxim}
34490351Smaxim
34590351Smaximstatic int
34690351Smaximapb_filter(void *arg)
34790351Smaxim{
34890351Smaxim	struct apb_softc *sc = arg;
3491558Srgrimes	struct intr_event *event;
3501558Srgrimes	uint32_t reg, irq;
3511558Srgrimes	struct thread *td;
35223304Sjmg	struct trapframe *tf;
3531558Srgrimes
3541558Srgrimes	reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS);
3551558Srgrimes	for (irq = 0; irq < APB_NIRQS; irq++) {
3561558Srgrimes		if (reg & (1 << irq)) {
3571558Srgrimes
3581558Srgrimes			switch (ar71xx_soc) {
35923304Sjmg			case AR71XX_SOC_AR7240:
3601558Srgrimes			case AR71XX_SOC_AR7241:
3611558Srgrimes			case AR71XX_SOC_AR7242:
3621558Srgrimes			case AR71XX_SOC_AR9330:
3631558Srgrimes			case AR71XX_SOC_AR9331:
36423304Sjmg			case AR71XX_SOC_AR9341:
36581251Sru			case AR71XX_SOC_AR9342:
3661558Srgrimes			case AR71XX_SOC_AR9344:
3671558Srgrimes			case AR71XX_SOC_QCA9533:
3681558Srgrimes			case AR71XX_SOC_QCA9533_V2:
3691558Srgrimes			case AR71XX_SOC_QCA9556:
37081251Sru			case AR71XX_SOC_QCA9558:
37181251Sru				/* ACK/clear the given interrupt */
37281251Sru				ATH_WRITE_REG(AR71XX_MISC_INTR_STATUS,
3731558Srgrimes				    (1 << irq));
3741558Srgrimes				break;
37523304Sjmg			default:
3761558Srgrimes				/* fallthrough */
3771558Srgrimes				break;
3781558Srgrimes			}
3791558Srgrimes
3801558Srgrimes			event = sc->sc_eventstab[irq];
38199501Scharnier			/* always count interrupts; spurious or otherwise */
38299501Scharnier			mips_intrcnt_inc(sc->sc_intr_counter[irq]);
38399501Scharnier			if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
38420540Sfenner				if (irq == APB_INTR_PMC) {
38520540Sfenner					td = PCPU_GET(curthread);
3861558Srgrimes					tf = td->td_intr_frame;
38723304Sjmg
38881251Sru					if (pmc_intr)
38923304Sjmg						(*pmc_intr)(PCPU_GET(cpuid), tf);
3901558Srgrimes					continue;
39120540Sfenner				}
39220540Sfenner				/* Ignore timer interrupts */
39320540Sfenner				if (irq != 0 && irq != 8 && irq != 9 && irq != 10)
3941558Srgrimes					printf("Stray APB IRQ %d\n", irq);
3951558Srgrimes				continue;
3961558Srgrimes			}
39737671Scharnier
39827508Swollman			intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame);
3991558Srgrimes		}
40023304Sjmg	}
40127508Swollman
40223304Sjmg	return (FILTER_HANDLED);
40323304Sjmg}
4041558Srgrimes
4051558Srgrimesstatic void
4061558Srgrimesapb_hinted_child(device_t bus, const char *dname, int dunit)
40727508Swollman{
40823304Sjmg	device_t		child;
40923304Sjmg	long			maddr;
41023304Sjmg	int			msize;
41127508Swollman	int			irq;
41227508Swollman	int			result;
41323304Sjmg	int			mem_hints_count;
4141558Srgrimes
4151558Srgrimes	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
4161558Srgrimes
4171558Srgrimes	/*
4181558Srgrimes	 * Set hard-wired resources for hinted child using
41923304Sjmg	 * specific RIDs.
42027508Swollman	 */
42123304Sjmg	mem_hints_count = 0;
42223304Sjmg	if (resource_long_value(dname, dunit, "maddr", &maddr) == 0)
4231558Srgrimes		mem_hints_count++;
4241558Srgrimes	if (resource_int_value(dname, dunit, "msize", &msize) == 0)
4251558Srgrimes		mem_hints_count++;
4261558Srgrimes
42768960Sru	/* check if all info for mem resource has been provided */
4281558Srgrimes	if ((mem_hints_count > 0) && (mem_hints_count < 2)) {
4291558Srgrimes		printf("Either maddr or msize hint is missing for %s%d\n",
4301558Srgrimes		    dname, dunit);
4311558Srgrimes	} else if (mem_hints_count) {
4321558Srgrimes		result = bus_set_resource(child, SYS_RES_MEMORY, 0,
4331558Srgrimes		    maddr, msize);
4341558Srgrimes		if (result != 0)
4351558Srgrimes			device_printf(bus,
4361558Srgrimes			    "warning: bus_set_resource() failed\n");
4371558Srgrimes	}
4381558Srgrimes
4391558Srgrimes	if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
440116806Sru		result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
4411558Srgrimes		if (result != 0)
4421558Srgrimes			device_printf(bus,
443116806Sru			    "warning: bus_set_resource() failed\n");
444116806Sru	}
44581251Sru}
44627508Swollman
44727508Swollmanstatic device_t
44881251Sruapb_add_child(device_t bus, u_int order, const char *name, int unit)
4491558Srgrimes{
45037671Scharnier	device_t		child;
45137671Scharnier	struct apb_ivar	*ivar;
45237671Scharnier
4531558Srgrimes	ivar = malloc(sizeof(struct apb_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
4541558Srgrimes	if (ivar == NULL) {
4551558Srgrimes		printf("Failed to allocate ivar\n");
4561558Srgrimes		return (0);
4571558Srgrimes	}
45879754Sdd	resource_list_init(&ivar->resources);
45923304Sjmg
46023304Sjmg	child = device_add_child_ordered(bus, order, name, unit);
4611558Srgrimes	if (child == NULL) {
4621558Srgrimes		printf("Can't add child %s%d ordered\n", name, unit);
4631558Srgrimes		return (0);
4641558Srgrimes	}
46537671Scharnier
46637671Scharnier	device_set_ivars(child, ivar);
46737671Scharnier
4681558Srgrimes	return (child);
4691558Srgrimes}
4701558Srgrimes
4711558Srgrimes/*
4721558Srgrimes * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
4731558Srgrimes * Provides pointer to resource_list for these routines
47437671Scharnier */
47537671Scharnierstatic struct resource_list *
47637671Scharnierapb_get_resource_list(device_t dev, device_t child)
4771558Srgrimes{
4781558Srgrimes	struct apb_ivar *ivar;
4791558Srgrimes
4801558Srgrimes	ivar = device_get_ivars(child);
4811558Srgrimes	return (&(ivar->resources));
4821558Srgrimes}
4831558Srgrimes
48479754Sddstatic int
48537671Scharnierapb_print_all_resources(device_t dev)
48627508Swollman{
4871558Srgrimes	struct apb_ivar *ndev = DEVTOAPB(dev);
4881558Srgrimes	struct resource_list *rl = &ndev->resources;
4891558Srgrimes	int retval = 0;
4901558Srgrimes
49123304Sjmg	if (STAILQ_FIRST(rl))
4921558Srgrimes		retval += printf(" at");
4931558Srgrimes
4941558Srgrimes	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
49523304Sjmg	retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
4961558Srgrimes
4971558Srgrimes	return (retval);
4981558Srgrimes}
4991558Srgrimes
5001558Srgrimesstatic int
5011558Srgrimesapb_print_child(device_t bus, device_t child)
5021558Srgrimes{
5031558Srgrimes	int retval = 0;
5041558Srgrimes
5051558Srgrimes	retval += bus_print_child_header(bus, child);
506186843Sdanger	retval += apb_print_all_resources(child);
50723247Swollman	if (device_get_flags(child))
50823304Sjmg		retval += printf(" flags %#x", device_get_flags(child));
509187067Sdanger	retval += printf(" on %s\n", device_get_nameunit(bus));
510187067Sdanger
511187067Sdanger	return (retval);
512187067Sdanger}
513187067Sdanger
514187067Sdanger
515187067Sdangerstatic device_method_t apb_methods[] = {
516187067Sdanger	DEVMETHOD(bus_activate_resource,	apb_activate_resource),
517187067Sdanger	DEVMETHOD(bus_add_child,		apb_add_child),
518187067Sdanger	DEVMETHOD(bus_alloc_resource,		apb_alloc_resource),
519187067Sdanger	DEVMETHOD(bus_deactivate_resource,	apb_deactivate_resource),
520187067Sdanger	DEVMETHOD(bus_get_resource_list,	apb_get_resource_list),
52123247Swollman	DEVMETHOD(bus_hinted_child,		apb_hinted_child),
52223247Swollman	DEVMETHOD(bus_release_resource,		apb_release_resource),
52323247Swollman	DEVMETHOD(bus_setup_intr,		apb_setup_intr),
52423247Swollman	DEVMETHOD(bus_teardown_intr,		apb_teardown_intr),
52523247Swollman	DEVMETHOD(device_attach,		apb_attach),
52623247Swollman	DEVMETHOD(device_probe,			apb_probe),
52723247Swollman	DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
52823247Swollman	DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
52999501Scharnier	DEVMETHOD(bus_print_child,		apb_print_child),
53023247Swollman
53123247Swollman	DEVMETHOD_END
53223247Swollman};
53323247Swollman
53499501Scharnierstatic driver_t apb_driver = {
53534673Scharnier	"apb",
53634673Scharnier	apb_methods,
53723247Swollman	sizeof(struct apb_softc),
5381558Srgrimes};
5391558Srgrimesstatic devclass_t apb_devclass;
5401558Srgrimes
5411558SrgrimesDRIVER_MODULE(apb, nexus, apb_driver, apb_devclass, 0, 0);
5421558Srgrimes