ixp425.c revision 189632
1164426Ssam/*	$NetBSD: ixp425.c,v 1.10 2005/12/11 12:16:51 christos Exp $ */
2164426Ssam
3164426Ssam/*
4164426Ssam * Copyright (c) 2003
5164426Ssam *	Ichiro FUKUHARA <ichiro@ichiro.org>.
6164426Ssam * All rights reserved.
7164426Ssam *
8164426Ssam * Redistribution and use in source and binary forms, with or without
9164426Ssam * modification, are permitted provided that the following conditions
10164426Ssam * are met:
11164426Ssam * 1. Redistributions of source code must retain the above copyright
12164426Ssam *    notice, this list of conditions and the following disclaimer.
13164426Ssam * 2. Redistributions in binary form must reproduce the above copyright
14164426Ssam *    notice, this list of conditions and the following disclaimer in the
15164426Ssam *    documentation and/or other materials provided with the distribution.
16164426Ssam * 3. All advertising materials mentioning features or use of this software
17164426Ssam *    must display the following acknowledgement:
18164426Ssam *	This product includes software developed by Ichiro FUKUHARA.
19164426Ssam * 4. The name of the company nor the name of the author may be used to
20164426Ssam *    endorse or promote products derived from this software without specific
21164426Ssam *    prior written permission.
22164426Ssam *
23164426Ssam * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
24164426Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25164426Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26164426Ssam * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
27164426Ssam * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28164426Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29164426Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30164426Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31164426Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32164426Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33164426Ssam * SUCH DAMAGE.
34164426Ssam */
35164426Ssam
36164426Ssam#include <sys/cdefs.h>
37164426Ssam__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/ixp425.c 189632 2009-03-10 17:16:16Z sam $");
38164426Ssam
39164426Ssam#define _ARM32_BUS_DMA_PRIVATE
40164426Ssam#include <sys/param.h>
41164426Ssam#include <sys/systm.h>
42164426Ssam#include <sys/bus.h>
43164426Ssam#include <sys/kernel.h>
44164426Ssam#include <sys/module.h>
45164426Ssam#include <sys/malloc.h>
46164426Ssam#include <sys/rman.h>
47164426Ssam#include <machine/bus.h>
48164426Ssam#include <machine/intr.h>
49164426Ssam
50164426Ssam#include <vm/vm.h>
51164426Ssam#include <vm/pmap.h>
52164426Ssam#include <arm/xscale/ixp425/ixp425reg.h>
53164426Ssam#include <arm/xscale/ixp425/ixp425var.h>
54164426Ssam#include <arm/xscale/ixp425/ixp425_intr.h>
55164426Ssam
56164426Ssam#include <dev/pci/pcireg.h>
57164426Ssam
58164426Ssamvolatile uint32_t intr_enabled;
59164426Ssamuint32_t intr_steer = 0;
60164426Ssam
61186352Ssam/* ixp43x et. al have +32 IRQ's */
62186352Ssamvolatile uint32_t intr_enabled2;
63186352Ssamuint32_t intr_steer2 = 0;
64186352Ssam
65164426Ssamstruct	ixp425_softc *ixp425_softc = NULL;
66164426Ssam
67164426Ssamstatic int	ixp425_probe(device_t);
68164426Ssamstatic void	ixp425_identify(driver_t *, device_t);
69164426Ssamstatic int	ixp425_attach(device_t);
70164426Ssam
71186418Ssam/*
72186418Ssam * Return a mask of the "fuse" bits that identify
73186418Ssam * which h/w features are present.
74186418Ssam * NB: assumes the expansion bus is mapped.
75186418Ssam */
76186418Ssamuint32_t
77186418Ssamixp4xx_read_feature_bits(void)
78186418Ssam{
79186418Ssam	uint32_t bits = ~IXPREG(IXP425_EXP_VBASE + EXP_FCTRL_OFFSET);
80186418Ssam	bits &= ~EXP_FCTRL_RESVD;
81186418Ssam	if (!cpu_is_ixp46x())
82186418Ssam		bits &= ~EXP_FCTRL_IXP46X_ONLY;
83186418Ssam	return bits;
84186418Ssam}
85186418Ssam
86164426Ssamstruct arm32_dma_range *
87164426Ssambus_dma_get_range(void)
88164426Ssam{
89164426Ssam	return (NULL);
90164426Ssam}
91164426Ssam
92164426Ssamint
93164426Ssambus_dma_get_range_nb(void)
94164426Ssam{
95164426Ssam	return (0);
96164426Ssam}
97164426Ssam
98164426Ssamstatic __inline u_int32_t
99164426Ssamixp425_irq2gpio_bit(int irq)
100164426Ssam{
101164426Ssam
102164426Ssam	static const uint8_t int2gpio[32] __attribute__ ((aligned(32))) = {
103164426Ssam		0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* INT#0 -> INT#5 */
104164426Ssam		0x00, 0x01,				/* GPIO#0 -> GPIO#1 */
105164426Ssam		0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	/* INT#8 -> INT#13 */
106164426Ssam		0xff, 0xff, 0xff, 0xff, 0xff,		/* INT#14 -> INT#18 */
107164426Ssam		0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* GPIO#2 -> GPIO#7 */
108164426Ssam		0x08, 0x09, 0x0a, 0x0b, 0x0c,		/* GPIO#8 -> GPIO#12 */
109164426Ssam		0xff, 0xff				/* INT#30 -> INT#31 */
110164426Ssam	};
111164426Ssam
112164426Ssam	return (1U << int2gpio[irq]);
113164426Ssam}
114164426Ssam
115164426Ssamvoid
116164426Ssamarm_mask_irq(uintptr_t nb)
117164426Ssam{
118182946Scognet	int i;
119182946Scognet
120182946Scognet	i = disable_interrupts(I32_bit);
121186352Ssam	if (nb < 32) {
122186352Ssam		intr_enabled &= ~(1 << nb);
123186352Ssam		ixp425_set_intrmask();
124186352Ssam	} else {
125186352Ssam		intr_enabled2 &= ~(1 << (nb - 32));
126186352Ssam		ixp435_set_intrmask();
127186352Ssam	}
128182946Scognet	restore_interrupts(i);
129164426Ssam	/*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/
130186352Ssam	if (nb < 32 && ((1 << nb) & IXP425_INT_GPIOMASK))
131164426Ssam		IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) =
132164426Ssam		    ixp425_irq2gpio_bit(nb);
133164426Ssam}
134164426Ssam
135164426Ssamvoid
136164426Ssamarm_unmask_irq(uintptr_t nb)
137164426Ssam{
138182946Scognet	int i;
139182946Scognet
140182946Scognet	i = disable_interrupts(I32_bit);
141186352Ssam	if (nb < 32) {
142186352Ssam		intr_enabled |= (1 << nb);
143186352Ssam		ixp425_set_intrmask();
144186352Ssam	} else {
145186352Ssam		intr_enabled2 |= (1 << (nb - 32));
146186352Ssam		ixp435_set_intrmask();
147186352Ssam	}
148182946Scognet	restore_interrupts(i);
149164426Ssam}
150164426Ssam
151164426Ssamstatic __inline uint32_t
152164426Ssamixp425_irq_read(void)
153164426Ssam{
154164426Ssam	return IXPREG(IXP425_INT_STATUS) & intr_enabled;
155164426Ssam}
156164426Ssam
157186352Ssamstatic __inline uint32_t
158186352Ssamixp435_irq_read(void)
159186352Ssam{
160186352Ssam	return IXPREG(IXP435_INT_STATUS2) & intr_enabled2;
161186352Ssam}
162186352Ssam
163164426Ssamint
164164426Ssamarm_get_next_irq(void)
165164426Ssam{
166186352Ssam	uint32_t irq;
167164426Ssam
168164426Ssam	if ((irq = ixp425_irq_read()))
169164426Ssam		return (ffs(irq) - 1);
170186352Ssam	if (cpu_is_ixp43x() && (irq = ixp435_irq_read()))
171186352Ssam		return (32 + ffs(irq) - 1);
172164426Ssam	return (-1);
173164426Ssam}
174164426Ssam
175164426Ssamvoid
176164426Ssamcpu_reset(void)
177164426Ssam{
178164426Ssam
179164426Ssam	bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE,
180164426Ssam	    IXP425_OST_WDOG_KEY, OST_WDOG_KEY_MAJICK);
181164426Ssam	bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE,
182164426Ssam	    IXP425_OST_WDOG, 0);
183164426Ssam	bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE,
184164426Ssam	    IXP425_OST_WDOG_ENAB, OST_WDOG_ENAB_RST_ENA |
185164426Ssam	    OST_WDOG_ENAB_CNT_ENA);
186164426Ssam	printf("Reset failed!\n");
187164426Ssam	for(;;);
188164426Ssam}
189164426Ssam
190164426Ssamstatic void
191164426Ssamixp425_identify(driver_t *driver, device_t parent)
192164426Ssam{
193164426Ssam	BUS_ADD_CHILD(parent, 0, "ixp", 0);
194164426Ssam}
195164426Ssam
196164426Ssamstatic int
197164426Ssamixp425_probe(device_t dev)
198164426Ssam{
199186352Ssam	device_set_desc(dev, "Intel IXP4XX");
200164426Ssam	return (0);
201164426Ssam}
202164426Ssam
203164426Ssamstatic int
204164426Ssamixp425_attach(device_t dev)
205164426Ssam{
206164426Ssam	struct ixp425_softc *sc;
207164426Ssam
208186418Ssam	device_printf(dev, "%b\n", ixp4xx_read_feature_bits(), EXP_FCTRL_BITS);
209186418Ssam
210164426Ssam	sc = device_get_softc(dev);
211164426Ssam	sc->sc_iot = &ixp425_bs_tag;
212186352Ssam	KASSERT(ixp425_softc == NULL, ("%s called twice?", __func__));
213164426Ssam	ixp425_softc = sc;
214164426Ssam
215164426Ssam	intr_enabled = 0;
216164426Ssam	ixp425_set_intrmask();
217164426Ssam	ixp425_set_intrsteer();
218186352Ssam	if (cpu_is_ixp43x()) {
219186352Ssam		intr_enabled2 = 0;
220186352Ssam		ixp435_set_intrmask();
221186352Ssam		ixp435_set_intrsteer();
222186352Ssam	}
223164426Ssam
224166064Scognet	if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
225166064Scognet	    BUS_SPACE_MAXADDR, NULL, NULL,  0xffffffff, 0xff, 0xffffffff, 0,
226166064Scognet	    NULL, NULL, &sc->sc_dmat))
227186352Ssam		panic("%s: failed to create dma tag", __func__);
228166064Scognet
229164426Ssam	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
230186352Ssam	sc->sc_irq_rman.rm_descr = "IXP4XX IRQs";
231164426Ssam	if (rman_init(&sc->sc_irq_rman) != 0 ||
232186352Ssam	    rman_manage_region(&sc->sc_irq_rman, 0, cpu_is_ixp43x() ? 63 : 31) != 0)
233186352Ssam		panic("%s: failed to set up IRQ rman", __func__);
234164426Ssam
235164426Ssam	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
236186352Ssam	sc->sc_mem_rman.rm_descr = "IXP4XX Memory";
237164426Ssam	if (rman_init(&sc->sc_mem_rman) != 0 ||
238164426Ssam	    rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0)
239186352Ssam		panic("%s: failed to set up memory rman", __func__);
240164426Ssam
241169952Ssam	BUS_ADD_CHILD(dev, 0, "pcib", 0);
242169952Ssam	BUS_ADD_CHILD(dev, 0, "ixpclk", 0);
243169952Ssam	BUS_ADD_CHILD(dev, 0, "ixpiic", 0);
244169952Ssam	/* XXX move to hints? */
245169952Ssam	BUS_ADD_CHILD(dev, 0, "ixpwdog", 0);
246164426Ssam
247169952Ssam	/* attach wired devices via hints */
248169952Ssam	bus_enumerate_hinted_children(dev);
249169952Ssam
250164426Ssam	if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE,
251164426Ssam	    0, &sc->sc_gpio_ioh))
252186352Ssam		panic("%s: unable to map GPIO registers", __func__);
253164426Ssam	if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE,
254164426Ssam	    0, &sc->sc_exp_ioh))
255186352Ssam		panic("%s: unable to map Expansion Bus registers", __func__);
256164426Ssam
257164426Ssam	bus_generic_probe(dev);
258164426Ssam	bus_generic_attach(dev);
259164426Ssam
260164426Ssam	return (0);
261164426Ssam}
262164426Ssam
263169952Ssamstatic void
264169952Ssamixp425_hinted_child(device_t bus, const char *dname, int dunit)
265169952Ssam{
266169952Ssam	device_t child;
267169952Ssam	struct ixp425_ivar *ivar;
268169952Ssam
269169952Ssam	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
270169952Ssam	ivar = IXP425_IVAR(child);
271169952Ssam	resource_int_value(dname, dunit, "addr", &ivar->addr);
272169952Ssam	resource_int_value(dname, dunit, "irq", &ivar->irq);
273169952Ssam}
274169952Ssam
275169952Ssamstatic device_t
276169952Ssamixp425_add_child(device_t dev, int order, const char *name, int unit)
277169952Ssam{
278169952Ssam	device_t child;
279169952Ssam	struct ixp425_ivar *ivar;
280169952Ssam
281169952Ssam	child = device_add_child_ordered(dev, order, name, unit);
282169952Ssam	if (child == NULL)
283169952Ssam		return NULL;
284169952Ssam	ivar = malloc(sizeof(struct ixp425_ivar), M_DEVBUF, M_NOWAIT);
285169952Ssam	if (ivar == NULL) {
286169952Ssam		device_delete_child(dev, child);
287169952Ssam		return NULL;
288169952Ssam	}
289169952Ssam	ivar->addr = 0;
290169952Ssam	ivar->irq = -1;
291169952Ssam	device_set_ivars(child, ivar);
292169952Ssam	return child;
293169952Ssam}
294169952Ssam
295169952Ssamstatic int
296169952Ssamixp425_read_ivar(device_t bus, device_t child, int which, u_char *result)
297169952Ssam{
298169952Ssam	struct ixp425_ivar *ivar = IXP425_IVAR(child);
299169952Ssam
300169952Ssam	switch (which) {
301169952Ssam	case IXP425_IVAR_ADDR:
302169952Ssam		if (ivar->addr != 0) {
303169952Ssam			*(uint32_t *)result = ivar->addr;
304169952Ssam			return 0;
305169952Ssam		}
306169952Ssam		break;
307169952Ssam	case IXP425_IVAR_IRQ:
308169952Ssam		if (ivar->irq != -1) {
309169952Ssam			*(int *)result = ivar->irq;
310169952Ssam			return 0;
311169952Ssam		}
312169952Ssam		break;
313169952Ssam	}
314169952Ssam	return EINVAL;
315169952Ssam}
316169952Ssam
317186352Ssam/*
318189632Ssam * NB: This table handles P->V translations for regions setup with
319189632Ssam * static mappings in initarm.  This is used solely for calls to
320189632Ssam * bus_alloc_resource_any; anything done with bus_space_map is
321189632Ssam * handled elsewhere and does not require an entry here.
322186352Ssam *
323189632Ssam * XXX this table is also used by uart_cpu_getdev via getvbase
324189632Ssam *    (hence the public api)
325186352Ssam */
326189632Ssamstruct hwvtrans {
327186352Ssam	uint32_t	hwbase;
328186352Ssam	uint32_t	size;
329186352Ssam	uint32_t	vbase;
330189632Ssam	int		isa4x;	/* XXX needs special bus space tag */
331186352Ssam};
332186352Ssam
333189632Ssamstatic const struct hwvtrans *
334189632Ssamgethwvtrans(uint32_t hwbase, uint32_t size)
335186352Ssam{
336189632Ssam	static const struct hwvtrans hwvtrans[] = {
337189632Ssam	    /* NB: needed only for uart_cpu_getdev */
338189632Ssam	    { .hwbase	= IXP425_UART0_HWBASE,
339189632Ssam	      .size 	= IXP425_REG_SIZE,
340189632Ssam	      .vbase	= IXP425_UART0_VBASE,
341189632Ssam	      .isa4x	= 1 },
342189632Ssam	    { .hwbase	= IXP425_UART1_HWBASE,
343189632Ssam	      .size 	= IXP425_REG_SIZE,
344189632Ssam	      .vbase	= IXP425_UART1_VBASE,
345189632Ssam	      .isa4x	= 1 },
346189632Ssam	    { .hwbase	= IXP425_PCI_HWBASE,
347189632Ssam	      .size 	= IXP425_PCI_SIZE,
348189632Ssam	      .vbase	= IXP425_PCI_VBASE },
349189632Ssam	    { .hwbase	= IXP425_PCI_MEM_HWBASE,
350189632Ssam	      .size 	= IXP425_PCI_MEM_SIZE,
351189632Ssam	      .vbase	= IXP425_PCI_MEM_VBASE },
352189632Ssam	    { .hwbase	= IXP425_EXP_BUS_CS0_HWBASE,
353189632Ssam	      .size 	= IXP425_EXP_BUS_CS0_SIZE,
354189632Ssam	      .vbase	= IXP425_EXP_BUS_CS0_VBASE },
355189632Ssam	    /* NB: needed for ixp435 ehci controllers */
356189632Ssam	    { .hwbase	= IXP435_USB1_HWBASE,
357189632Ssam	      .size 	= IXP435_USB1_SIZE,
358189632Ssam	      .vbase	= IXP435_USB1_VBASE },
359189632Ssam	    { .hwbase	= IXP435_USB2_HWBASE,
360189632Ssam	      .size 	= IXP435_USB2_SIZE,
361189632Ssam	      .vbase	= IXP435_USB2_VBASE },
362189632Ssam#ifdef CAMBRIA_GPS_VBASE
363189632Ssam	    { .hwbase	= CAMBRIA_GPS_HWBASE,
364189632Ssam	      .size 	= CAMBRIA_GPS_SIZE,
365189632Ssam	      .vbase	= CAMBRIA_GPS_VBASE },
366189632Ssam#endif
367189632Ssam#ifdef CAMBRIA_RS485_VBASE
368189632Ssam	    { .hwbase	= CAMBRIA_RS485_HWBASE,
369189632Ssam	      .size 	= CAMBRIA_RS485_SIZE,
370189632Ssam	      .vbase	= CAMBRIA_RS485_VBASE },
371189632Ssam#endif
372189632Ssam	};
373186352Ssam	int i;
374186352Ssam
375186352Ssam	for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) {
376186352Ssam		if (hwbase >= hwvtrans[i].hwbase &&
377189632Ssam		    hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size)
378189632Ssam			return &hwvtrans[i];
379186352Ssam	}
380189632Ssam	return NULL;
381186352Ssam}
382186352Ssam
383189632Ssam/* XXX for uart_cpu_getdev */
384189632Ssamint
385189632Ssamgetvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase)
386189632Ssam{
387189632Ssam	const struct hwvtrans *hw;
388189632Ssam
389189632Ssam	hw = gethwvtrans(hwbase, size);
390189632Ssam	if (hw == NULL)
391189632Ssam		return (ENOENT);
392189632Ssam	*vbase = hwbase - hw->hwbase + hw->vbase;
393189632Ssam	return (0);
394189632Ssam}
395189632Ssam
396164426Ssamstatic struct resource *
397164426Ssamixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
398164426Ssam    u_long start, u_long end, u_long count, u_int flags)
399164426Ssam{
400164426Ssam	struct ixp425_softc *sc = device_get_softc(dev);
401189632Ssam	const struct hwvtrans *vtrans;
402164426Ssam	struct rman *rmanp;
403164426Ssam	struct resource *rv;
404189632Ssam	uint32_t addr;
405189630Ssam	int needactivate = flags & RF_ACTIVE;
406169952Ssam	int irq;
407164426Ssam
408189630Ssam	flags &= ~RF_ACTIVE;
409164426Ssam	switch (type) {
410164426Ssam	case SYS_RES_IRQ:
411164426Ssam		rmanp = &sc->sc_irq_rman;
412169952Ssam		/* override per hints */
413169952Ssam		if (BUS_READ_IVAR(dev, child, IXP425_IVAR_IRQ, &irq) == 0)
414169952Ssam			start = end = irq;
415169952Ssam		rv = rman_reserve_resource(rmanp, start, end, count,
416169952Ssam			flags, child);
417169952Ssam		if (rv != NULL)
418169952Ssam			rman_set_rid(rv, *rid);
419164426Ssam		break;
420164426Ssam
421164426Ssam	case SYS_RES_MEMORY:
422164426Ssam		rmanp = &sc->sc_mem_rman;
423169952Ssam		/* override per hints */
424169952Ssam		if (BUS_READ_IVAR(dev, child, IXP425_IVAR_ADDR, &addr) == 0) {
425169952Ssam			start = addr;
426189632Ssam			/* XXX use nominal window to check for mapping */
427189632Ssam			vtrans = gethwvtrans(start, 0x1000);
428189632Ssam			if (vtrans != NULL) {
429189632Ssam				/*
430189632Ssam				 * Assign the entire mapped region; this may
431189632Ssam				 * not be correct but without more info from
432189632Ssam				 * the caller we cannot tell.
433189632Ssam				 */
434189632Ssam				end = start + vtrans->size -
435189632Ssam				    (start - vtrans->hwbase);
436189632Ssam				if (bootverbose)
437189632Ssam					device_printf(child,
438189632Ssam					    "%s: assign 0x%lx:0x%lx%s\n",
439189632Ssam					    __func__, start, end - start,
440189632Ssam					    vtrans->isa4x ? " A4X" : "");
441189632Ssam			}
442189632Ssam		} else
443189632Ssam			vtrans = gethwvtrans(start, end - start);
444189632Ssam		if (vtrans == NULL) {
445186352Ssam			/* likely means above table needs to be updated */
446189632Ssam			device_printf(child, "%s: no mapping for 0x%lx:0x%lx\n",
447186352Ssam			    __func__, start, end-start);
448169952Ssam			return NULL;
449186352Ssam		}
450189632Ssam		rv = rman_reserve_resource(rmanp, start, end, end - start,
451169952Ssam			flags, child);
452189630Ssam		if (rv != NULL)
453169952Ssam			rman_set_rid(rv, *rid);
454164426Ssam		break;
455164426Ssam	default:
456169952Ssam		rv = NULL;
457169952Ssam		break;
458164426Ssam	}
459189630Ssam	if (rv != NULL && needactivate) {
460189630Ssam		if (bus_activate_resource(child, type, *rid, rv)) {
461189630Ssam			rman_release_resource(rv);
462189630Ssam			return (NULL);
463189630Ssam		}
464189630Ssam	}
465189630Ssam	return (rv);
466164426Ssam}
467164426Ssam
468189630Ssamstatic int
469189630Ssamixp425_activate_resource(device_t dev, device_t child, int type, int rid,
470189630Ssam    struct resource *r)
471189630Ssam{
472189630Ssam	struct ixp425_softc *sc = device_get_softc(dev);
473189632Ssam	const struct hwvtrans *vtrans;
474189630Ssam
475189630Ssam	if (type == SYS_RES_MEMORY) {
476189632Ssam		vtrans = gethwvtrans(rman_get_start(r), rman_get_size(r));
477189632Ssam		if (vtrans == NULL)		/* NB: should not happen */
478189632Ssam			return (ENOENT);
479189632Ssam		if (vtrans->isa4x)
480189630Ssam			rman_set_bustag(r, &ixp425_a4x_bs_tag);
481189630Ssam		else
482189630Ssam			rman_set_bustag(r, sc->sc_iot);
483189632Ssam		rman_set_bushandle(r, vtrans->vbase);
484189630Ssam	}
485189630Ssam	return (rman_activate_resource(r));
486189630Ssam}
487189630Ssam
488186352Ssamstatic __inline void
489186352Ssamget_masks(struct resource *res, uint32_t *mask, uint32_t *mask2)
490186352Ssam{
491186352Ssam	int i;
492186352Ssam
493186352Ssam	*mask = 0;
494186352Ssam	for (i = rman_get_start(res); i < 32 && i <= rman_get_end(res); i++)
495186352Ssam		*mask |= 1 << i;
496186352Ssam	*mask2 = 0;
497186352Ssam	for (; i <= rman_get_end(res); i++)
498186352Ssam		*mask2 |= 1 << (i - 32);
499186352Ssam}
500186352Ssam
501186352Ssamstatic __inline void
502186352Ssamupdate_masks(uint32_t mask, uint32_t mask2)
503186352Ssam{
504186352Ssam
505186352Ssam	intr_enabled = mask;
506186352Ssam	ixp425_set_intrmask();
507186352Ssam	if (cpu_is_ixp43x()) {
508186352Ssam		intr_enabled2 = mask2;
509186352Ssam		ixp435_set_intrmask();
510186352Ssam	}
511186352Ssam}
512186352Ssam
513164426Ssamstatic int
514164426Ssamixp425_setup_intr(device_t dev, device_t child,
515186352Ssam    struct resource *res, int flags, driver_filter_t *filt,
516166901Spiso    driver_intr_t *intr, void *arg, void **cookiep)
517164426Ssam{
518186352Ssam	uint32_t mask, mask2;
519164426Ssam
520186352Ssam	BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, filt, intr,
521166901Spiso	     arg, cookiep);
522164426Ssam
523186352Ssam	get_masks(res, &mask, &mask2);
524186352Ssam	update_masks(intr_enabled | mask, intr_enabled2 | mask2);
525164426Ssam
526164426Ssam	return (0);
527164426Ssam}
528164426Ssam
529164426Ssamstatic int
530164426Ssamixp425_teardown_intr(device_t dev, device_t child, struct resource *res,
531164426Ssam    void *cookie)
532164426Ssam{
533186352Ssam	uint32_t mask, mask2;
534164426Ssam
535186352Ssam	get_masks(res, &mask, &mask2);
536186352Ssam	update_masks(intr_enabled &~ mask, intr_enabled2 &~ mask2);
537164426Ssam
538164426Ssam	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
539164426Ssam}
540164426Ssam
541164426Ssamstatic device_method_t ixp425_methods[] = {
542164426Ssam	/* Device interface */
543164426Ssam	DEVMETHOD(device_probe, ixp425_probe),
544164426Ssam	DEVMETHOD(device_attach, ixp425_attach),
545164426Ssam	DEVMETHOD(device_identify, ixp425_identify),
546164426Ssam
547164426Ssam	/* Bus interface */
548169952Ssam	DEVMETHOD(bus_add_child, ixp425_add_child),
549169952Ssam	DEVMETHOD(bus_hinted_child, ixp425_hinted_child),
550169952Ssam	DEVMETHOD(bus_read_ivar, ixp425_read_ivar),
551169952Ssam
552164426Ssam	DEVMETHOD(bus_alloc_resource, ixp425_alloc_resource),
553189630Ssam	DEVMETHOD(bus_activate_resource, ixp425_activate_resource),
554164426Ssam	DEVMETHOD(bus_setup_intr, ixp425_setup_intr),
555164426Ssam	DEVMETHOD(bus_teardown_intr, ixp425_teardown_intr),
556164426Ssam
557164426Ssam	{0, 0},
558164426Ssam};
559164426Ssam
560164426Ssamstatic driver_t ixp425_driver = {
561164426Ssam	"ixp",
562164426Ssam	ixp425_methods,
563164426Ssam	sizeof(struct ixp425_softc),
564164426Ssam};
565164426Ssamstatic devclass_t ixp425_devclass;
566164426Ssam
567164426SsamDRIVER_MODULE(ixp, nexus, ixp425_driver, ixp425_devclass, 0, 0);
568