xref: /netbsd-src/sys/arch/mips/alchemy/au_icu.c (revision 9e26d3f35bec42a735e4f9727e8d4fd54e4716f5)
1*9e26d3f3Sthorpej /*	$NetBSD: au_icu.c,v 1.31 2021/01/04 17:35:12 thorpej Exp $	*/
2eab2d456Sgdamore 
3eab2d456Sgdamore /*-
4eab2d456Sgdamore  * Copyright (c) 2006 Itronix Inc.
5eab2d456Sgdamore  * All rights reserved.
6eab2d456Sgdamore  *
7eab2d456Sgdamore  * Written by Garrett D'Amore for Itronix Inc.
8eab2d456Sgdamore  *
9eab2d456Sgdamore  * Redistribution and use in source and binary forms, with or without
10eab2d456Sgdamore  * modification, are permitted provided that the following conditions
11eab2d456Sgdamore  * are met:
12eab2d456Sgdamore  * 1. Redistributions of source code must retain the above copyright
13eab2d456Sgdamore  *    notice, this list of conditions and the following disclaimer.
14eab2d456Sgdamore  * 2. Redistributions in binary form must reproduce the above copyright
15eab2d456Sgdamore  *    notice, this list of conditions and the following disclaimer in the
16eab2d456Sgdamore  *    documentation and/or other materials provided with the distribution.
17eab2d456Sgdamore  * 3. The name of Itronix Inc. may not be used to endorse
18eab2d456Sgdamore  *    or promote products derived from this software without specific
19eab2d456Sgdamore  *    prior written permission.
20eab2d456Sgdamore  *
21eab2d456Sgdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22eab2d456Sgdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23eab2d456Sgdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24eab2d456Sgdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25eab2d456Sgdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26eab2d456Sgdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27eab2d456Sgdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28eab2d456Sgdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
29eab2d456Sgdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30eab2d456Sgdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31eab2d456Sgdamore  * POSSIBILITY OF SUCH DAMAGE.
32eab2d456Sgdamore  */
33ca42af5eSsimonb 
34ca42af5eSsimonb /*-
35ca42af5eSsimonb  * Copyright (c) 2001 The NetBSD Foundation, Inc.
36ca42af5eSsimonb  * All rights reserved.
37ca42af5eSsimonb  *
38ca42af5eSsimonb  * This code is derived from software contributed to The NetBSD Foundation
39ca42af5eSsimonb  * by Jason R. Thorpe.
40ca42af5eSsimonb  *
41ca42af5eSsimonb  * Redistribution and use in source and binary forms, with or without
42ca42af5eSsimonb  * modification, are permitted provided that the following conditions
43ca42af5eSsimonb  * are met:
44ca42af5eSsimonb  * 1. Redistributions of source code must retain the above copyright
45ca42af5eSsimonb  *    notice, this list of conditions and the following disclaimer.
46ca42af5eSsimonb  * 2. Redistributions in binary form must reproduce the above copyright
47ca42af5eSsimonb  *    notice, this list of conditions and the following disclaimer in the
48ca42af5eSsimonb  *    documentation and/or other materials provided with the distribution.
49ca42af5eSsimonb  *
50ca42af5eSsimonb  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51ca42af5eSsimonb  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52ca42af5eSsimonb  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53ca42af5eSsimonb  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54ca42af5eSsimonb  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55ca42af5eSsimonb  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56ca42af5eSsimonb  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57ca42af5eSsimonb  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58ca42af5eSsimonb  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59ca42af5eSsimonb  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60ca42af5eSsimonb  * POSSIBILITY OF SUCH DAMAGE.
61ca42af5eSsimonb  */
62ca42af5eSsimonb 
63ca42af5eSsimonb /*
64ca42af5eSsimonb  * Interrupt support for the Alchemy Semiconductor Au1x00 CPUs.
65ca42af5eSsimonb  *
66ca42af5eSsimonb  * The Alchemy Semiconductor Au1x00's interrupts are wired to two internal
67ca42af5eSsimonb  * interrupt controllers.
68ca42af5eSsimonb  */
69ca42af5eSsimonb 
704b2744bfSlukem #include <sys/cdefs.h>
71*9e26d3f3Sthorpej __KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.31 2021/01/04 17:35:12 thorpej Exp $");
724b2744bfSlukem 
73ca42af5eSsimonb #include "opt_ddb.h"
743e67b512Smatt #define __INTR_PRIVATE
75ca42af5eSsimonb 
76ca42af5eSsimonb #include <sys/param.h>
77b6185cbdSmatt #include <sys/bus.h>
78b6185cbdSmatt #include <sys/device.h>
79b6185cbdSmatt #include <sys/intr.h>
80b6185cbdSmatt #include <sys/kernel.h>
81*9e26d3f3Sthorpej #include <sys/kmem.h>
82ca42af5eSsimonb #include <sys/systm.h>
83ca42af5eSsimonb 
84ca42af5eSsimonb #include <mips/locore.h>
85ca42af5eSsimonb #include <mips/alchemy/include/aureg.h>
86ca42af5eSsimonb #include <mips/alchemy/include/auvar.h>
87ca42af5eSsimonb 
880cf592aaSgdamore #define	REGVAL(x)	*((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
89ca42af5eSsimonb 
90ca42af5eSsimonb /*
91ca42af5eSsimonb  * This is a mask of bits to clear in the SR when we go to a
92ca42af5eSsimonb  * given hardware interrupt priority level.
93ca42af5eSsimonb  */
94ca42af5eSsimonb 
953e67b512Smatt static const struct ipl_sr_map alchemy_ipl_sr_map = {
963e67b512Smatt     .sr_bits = {
973e67b512Smatt 	[IPL_NONE] =		0,
983e67b512Smatt 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
993e67b512Smatt 	[IPL_SOFTBIO] =		MIPS_SOFT_INT_MASK_0,
1003e67b512Smatt 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK,
1013e67b512Smatt 	[IPL_SOFTSERIAL] =	MIPS_SOFT_INT_MASK,
102c3832bc1Skiyohara 	[IPL_VM] =		MIPS_SOFT_INT_MASK |
103c3832bc1Skiyohara 				MIPS_INT_MASK_0	|
104c3832bc1Skiyohara 				MIPS_INT_MASK_1	|
105c3832bc1Skiyohara 				MIPS_INT_MASK_2 |
106c3832bc1Skiyohara 				MIPS_INT_MASK_3,
1073e67b512Smatt 	[IPL_SCHED] =		MIPS_INT_MASK,
108c3832bc1Skiyohara 	[IPL_DDB] =		MIPS_INT_MASK,
1093e67b512Smatt 	[IPL_HIGH] =		MIPS_INT_MASK,
1103e67b512Smatt     },
111ca42af5eSsimonb };
112ca42af5eSsimonb 
113ca42af5eSsimonb #define	NIRQS		64
114ca42af5eSsimonb 
115eab2d456Sgdamore struct au_icu_intrhead {
116ca42af5eSsimonb 	struct evcnt intr_count;
117ca42af5eSsimonb 	int intr_refcnt;
118ca42af5eSsimonb };
119eab2d456Sgdamore struct au_icu_intrhead au_icu_intrtab[NIRQS];
120ca42af5eSsimonb 
121ca42af5eSsimonb #define	NINTRS			4	/* MIPS INT0 - INT3 */
122ca42af5eSsimonb 
1230cf592aaSgdamore struct au_intrhand {
1240cf592aaSgdamore 	LIST_ENTRY(au_intrhand) ih_q;
1250cf592aaSgdamore 	int (*ih_func)(void *);
1260cf592aaSgdamore 	void *ih_arg;
1270cf592aaSgdamore 	int ih_irq;
1281ef49ecbSgdamore 	int ih_mask;
1290cf592aaSgdamore };
1300cf592aaSgdamore 
131eab2d456Sgdamore struct au_cpuintr {
1320cf592aaSgdamore 	LIST_HEAD(, au_intrhand) cintr_list;
133ca42af5eSsimonb 	struct evcnt cintr_count;
134ca42af5eSsimonb };
135ca42af5eSsimonb 
136eab2d456Sgdamore struct au_cpuintr au_cpuintrs[NINTRS];
1373e67b512Smatt const char * const au_cpuintrnames[NINTRS] = {
138ca42af5eSsimonb 	"icu 0, req 0",
139ca42af5eSsimonb 	"icu 0, req 1",
140ca42af5eSsimonb 	"icu 1, req 0",
141ca42af5eSsimonb 	"icu 1, req 1",
142ca42af5eSsimonb };
143ca42af5eSsimonb 
144eab2d456Sgdamore static bus_addr_t ic0_base, ic1_base;
145eab2d456Sgdamore 
146ca42af5eSsimonb void
au_intr_init(void)147ca42af5eSsimonb au_intr_init(void)
148ca42af5eSsimonb {
1493e67b512Smatt 	ipl_sr_map = alchemy_ipl_sr_map;
150ca42af5eSsimonb 
1513e67b512Smatt 	for (size_t i = 0; i < NINTRS; i++) {
152eab2d456Sgdamore 		LIST_INIT(&au_cpuintrs[i].cintr_list);
153eab2d456Sgdamore 		evcnt_attach_dynamic(&au_cpuintrs[i].cintr_count,
154eab2d456Sgdamore 		    EVCNT_TYPE_INTR, NULL, "mips", au_cpuintrnames[i]);
155ca42af5eSsimonb 	}
156ca42af5eSsimonb 
1573e67b512Smatt 	struct au_chipdep * const chip = au_chipdep();
158eab2d456Sgdamore 	KASSERT(chip != NULL);
159ca42af5eSsimonb 
160eab2d456Sgdamore 	ic0_base = chip->icus[0];
161eab2d456Sgdamore 	ic1_base = chip->icus[1];
162eab2d456Sgdamore 
1633e67b512Smatt 	for (size_t i = 0; i < NIRQS; i++) {
164eab2d456Sgdamore 		au_icu_intrtab[i].intr_refcnt = 0;
165eab2d456Sgdamore 		evcnt_attach_dynamic(&au_icu_intrtab[i].intr_count,
166eab2d456Sgdamore 		    EVCNT_TYPE_INTR, NULL, chip->name, chip->irqnames[i]);
167ca42af5eSsimonb 	}
1681ef49ecbSgdamore 
1691ef49ecbSgdamore 	/* start with all interrupts masked */
1701ef49ecbSgdamore 	REGVAL(ic0_base + IC_MASK_CLEAR) = 0xffffffff;
1711ef49ecbSgdamore 	REGVAL(ic0_base + IC_WAKEUP_CLEAR) = 0xffffffff;
1721ef49ecbSgdamore 	REGVAL(ic0_base + IC_SOURCE_SET) = 0xffffffff;
1731ef49ecbSgdamore 	REGVAL(ic0_base + IC_RISING_EDGE) = 0xffffffff;
1741ef49ecbSgdamore 	REGVAL(ic0_base + IC_FALLING_EDGE) = 0xffffffff;
1751ef49ecbSgdamore 	REGVAL(ic0_base + IC_TEST_BIT) = 0;
1761ef49ecbSgdamore 
1771ef49ecbSgdamore 	REGVAL(ic1_base + IC_MASK_CLEAR) = 0xffffffff;
1781ef49ecbSgdamore 	REGVAL(ic1_base + IC_WAKEUP_CLEAR) = 0xffffffff;
1791ef49ecbSgdamore 	REGVAL(ic1_base + IC_SOURCE_SET) = 0xffffffff;
1801ef49ecbSgdamore 	REGVAL(ic1_base + IC_RISING_EDGE) = 0xffffffff;
1811ef49ecbSgdamore 	REGVAL(ic1_base + IC_FALLING_EDGE) = 0xffffffff;
1821ef49ecbSgdamore 	REGVAL(ic1_base + IC_TEST_BIT) = 0;
183ca42af5eSsimonb }
184ca42af5eSsimonb 
185ca42af5eSsimonb void *
au_intr_establish(int irq,int req,int level,int type,int (* func)(void *),void * arg)186ca42af5eSsimonb au_intr_establish(int irq, int req, int level, int type,
187ca42af5eSsimonb     int (*func)(void *), void *arg)
188ca42af5eSsimonb {
1890cf592aaSgdamore 	struct au_intrhand	*ih;
190ca42af5eSsimonb 	uint32_t		icu_base;
191253884a9She 	int			cpu_int, s;
192eab2d456Sgdamore 	struct au_chipdep	*chip;
193eab2d456Sgdamore 
194eab2d456Sgdamore 	chip = au_chipdep();
195eab2d456Sgdamore 	KASSERT(chip != NULL);
196ca42af5eSsimonb 
197ca42af5eSsimonb 	if (irq >= NIRQS)
1980f09ed48Sprovos 		panic("au_intr_establish: bogus IRQ %d", irq);
199ca42af5eSsimonb 	if (req > 1)
2000f09ed48Sprovos 		panic("au_intr_establish: bogus request %d", req);
201ca42af5eSsimonb 
202*9e26d3f3Sthorpej 	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
203ca42af5eSsimonb 	ih->ih_func = func;
204ca42af5eSsimonb 	ih->ih_arg = arg;
205ca42af5eSsimonb 	ih->ih_irq = irq;
2061ef49ecbSgdamore 	ih->ih_mask = (1 << (irq & 31));
207ca42af5eSsimonb 
208ca42af5eSsimonb 	s = splhigh();
209ca42af5eSsimonb 
210ca42af5eSsimonb 	/*
211ca42af5eSsimonb 	 * First, link it into the tables.
212ca42af5eSsimonb 	 * XXX do we want a separate list (really, should only be one item, not
213d20841bbSwiz 	 *     a list anyway) per irq, not per CPU interrupt?
214ca42af5eSsimonb 	 */
2154d15d9ebSgdamore 	cpu_int = (irq < 32 ? 0 : 2) + req;
216eab2d456Sgdamore 	LIST_INSERT_HEAD(&au_cpuintrs[cpu_int].cintr_list, ih, ih_q);
217ca42af5eSsimonb 
218ca42af5eSsimonb 	/*
219ca42af5eSsimonb 	 * Now enable it.
220ca42af5eSsimonb 	 */
221eab2d456Sgdamore 	if (au_icu_intrtab[irq].intr_refcnt++ == 0) {
222eab2d456Sgdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
223ca42af5eSsimonb 
224ca42af5eSsimonb 		irq &= 31;	/* throw away high bit if set */
225ca42af5eSsimonb 		irq = 1 << irq;	/* only used as a mask from here on */
226ca42af5eSsimonb 
227eab2d456Sgdamore 		/* XXX Only level interrupts for now */
228ca42af5eSsimonb 		switch (type) {
229ca42af5eSsimonb 		case IST_NONE:
230ca42af5eSsimonb 		case IST_PULSE:
231ca42af5eSsimonb 		case IST_EDGE:
232ca42af5eSsimonb 			panic("unsupported irq type %d", type);
2339cda7676Shpeyerl 			/* NOTREACHED */
234ca42af5eSsimonb 		case IST_LEVEL:
2359cda7676Shpeyerl 		case IST_LEVEL_HIGH:
236ca42af5eSsimonb 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
237ca42af5eSsimonb 			REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
238ca42af5eSsimonb 			REGVAL(icu_base + IC_CONFIG0_SET) = irq;
2399cda7676Shpeyerl 			break;
2409cda7676Shpeyerl 		case IST_LEVEL_LOW:
2419cda7676Shpeyerl 			REGVAL(icu_base + IC_CONFIG2_SET) = irq;
2429cda7676Shpeyerl 			REGVAL(icu_base + IC_CONFIG1_SET) = irq;
2439cda7676Shpeyerl 			REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
2449cda7676Shpeyerl 			break;
245ca42af5eSsimonb 		}
246f964209aSgdamore 		wbflush();
247ca42af5eSsimonb 
248ca42af5eSsimonb 		/* XXX handle GPIO interrupts - not done at all yet */
249253884a9She 		if (cpu_int & 0x1)
250ca42af5eSsimonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_CLEAR) = irq;
251ca42af5eSsimonb 		else
252ca42af5eSsimonb 			REGVAL(icu_base + IC_ASSIGN_REQUEST_SET) = irq;
253ca42af5eSsimonb 
254ca42af5eSsimonb 		/* Associate interrupt with peripheral */
255ca42af5eSsimonb 		REGVAL(icu_base + IC_SOURCE_SET) = irq;
256ca42af5eSsimonb 
257ca42af5eSsimonb 		/* Actually enable the interrupt */
258ca42af5eSsimonb 		REGVAL(icu_base + IC_MASK_SET) = irq;
259ca42af5eSsimonb 
260ca42af5eSsimonb 		/* And allow the interrupt to interrupt idle */
261ca42af5eSsimonb 		REGVAL(icu_base + IC_WAKEUP_SET) = irq;
262f964209aSgdamore 
263f964209aSgdamore 		wbflush();
264ca42af5eSsimonb 	}
265ca42af5eSsimonb 	splx(s);
266ca42af5eSsimonb 
267ca42af5eSsimonb 	return (ih);
268ca42af5eSsimonb }
269ca42af5eSsimonb 
270ca42af5eSsimonb void
au_intr_disestablish(void * cookie)271ca42af5eSsimonb au_intr_disestablish(void *cookie)
272ca42af5eSsimonb {
2730cf592aaSgdamore 	struct au_intrhand *ih = cookie;
274ca42af5eSsimonb 	uint32_t icu_base;
275ca42af5eSsimonb 	int irq, s;
276ca42af5eSsimonb 
277ca42af5eSsimonb 	irq = ih->ih_irq;
278ca42af5eSsimonb 
279ca42af5eSsimonb 	s = splhigh();
280ca42af5eSsimonb 
281ca42af5eSsimonb 	/*
282ca42af5eSsimonb 	 * First, remove it from the table.
283ca42af5eSsimonb 	 */
284ca42af5eSsimonb 	LIST_REMOVE(ih, ih_q);
285ca42af5eSsimonb 
286ca42af5eSsimonb 	/*
287ca42af5eSsimonb 	 * Now, disable it, if there is nothing remaining on the
288ca42af5eSsimonb 	 * list.
289ca42af5eSsimonb 	 */
290eab2d456Sgdamore 	if (au_icu_intrtab[irq].intr_refcnt-- == 1) {
291eab2d456Sgdamore 		icu_base = (irq < 32) ? ic0_base : ic1_base;
292ca42af5eSsimonb 
293ca42af5eSsimonb 		irq &= 31;	/* throw away high bit if set */
294ca42af5eSsimonb 		irq = 1 << irq;	/* only used as a mask from here on */
295ca42af5eSsimonb 
296ca42af5eSsimonb 		REGVAL(icu_base + IC_CONFIG2_CLEAR) = irq;
297ca42af5eSsimonb 		REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
298ca42af5eSsimonb 		REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
299ca42af5eSsimonb 
30007fe2e72Sgdamore 		/* disable with MASK_CLEAR and WAKEUP_CLEAR */
30107fe2e72Sgdamore 		REGVAL(icu_base + IC_MASK_CLEAR) = irq;
30207fe2e72Sgdamore 		REGVAL(icu_base + IC_WAKEUP_CLEAR) = irq;
303f964209aSgdamore 		wbflush();
304ca42af5eSsimonb 	}
305ca42af5eSsimonb 
306ca42af5eSsimonb 	splx(s);
307ca42af5eSsimonb 
308*9e26d3f3Sthorpej 	kmem_free(ih, sizeof(*ih));
309ca42af5eSsimonb }
310ca42af5eSsimonb 
311ca42af5eSsimonb void
au_iointr(int ipl,vaddr_t pc,uint32_t ipending)3123e67b512Smatt au_iointr(int ipl, vaddr_t pc, uint32_t ipending)
313ca42af5eSsimonb {
3140cf592aaSgdamore 	struct au_intrhand *ih;
315ca42af5eSsimonb 	int level;
31645da43deSsimonb 	uint32_t icu_base, irqstat, irqmask;
31745da43deSsimonb 
3181ef49ecbSgdamore 	icu_base = irqstat = 0;
319ca42af5eSsimonb 
320ca42af5eSsimonb 	for (level = 3; level >= 0; level--) {
321ca42af5eSsimonb 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
322ca42af5eSsimonb 			continue;
323ca42af5eSsimonb 
324ca42af5eSsimonb 		/*
325ca42af5eSsimonb 		 * XXX	the following may well be slow to execute.
326ca42af5eSsimonb 		 *	investigate and possibly speed up.
327ca42af5eSsimonb 		 *
328ca42af5eSsimonb 		 * is something like:
329ca42af5eSsimonb 		 *
33045da43deSsimonb 		 *    irqstat = REGVAL(
331ca42af5eSsimonb 		 *	 (level & 4 == 0) ? IC0_BASE ? IC1_BASE +
332ca42af5eSsimonb 		 *	 (level & 2 == 0) ? IC_REQUEST0_INT : IC_REQUEST1_INT);
333ca42af5eSsimonb 		 *
334ca42af5eSsimonb 		 * be any better?
335ca42af5eSsimonb 		 *
336ca42af5eSsimonb 		 */
337ca42af5eSsimonb 		switch (level) {
338ca42af5eSsimonb 		case 0:
339eab2d456Sgdamore 			icu_base = ic0_base;
34007fe2e72Sgdamore 			irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
341ca42af5eSsimonb 			break;
342ca42af5eSsimonb 		case 1:
343eab2d456Sgdamore 			icu_base = ic0_base;
34407fe2e72Sgdamore 			irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
345ca42af5eSsimonb 			break;
346ca42af5eSsimonb 		case 2:
347eab2d456Sgdamore 			icu_base = ic1_base;
34807fe2e72Sgdamore 			irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
349ca42af5eSsimonb 			break;
350ca42af5eSsimonb 		case 3:
351eab2d456Sgdamore 			icu_base = ic1_base;
35207fe2e72Sgdamore 			irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
353ca42af5eSsimonb 			break;
354ca42af5eSsimonb 		}
35507fe2e72Sgdamore 		irqmask = REGVAL(icu_base + IC_MASK_READ);
356eab2d456Sgdamore 		au_cpuintrs[level].cintr_count.ev_count++;
357eab2d456Sgdamore 		LIST_FOREACH(ih, &au_cpuintrs[level].cintr_list, ih_q) {
3581ef49ecbSgdamore 			int mask = ih->ih_mask;
35907fe2e72Sgdamore 
3601ef49ecbSgdamore 			if (mask & irqmask & irqstat) {
361eab2d456Sgdamore 				au_icu_intrtab[ih->ih_irq].intr_count.ev_count++;
362ca42af5eSsimonb 				(*ih->ih_func)(ih->ih_arg);
363ca42af5eSsimonb 
3641ef49ecbSgdamore 				if (REGVAL(icu_base + IC_MASK_READ) & mask) {
3651ef49ecbSgdamore 					REGVAL(icu_base + IC_MASK_CLEAR) = mask;
3661ef49ecbSgdamore 					REGVAL(icu_base + IC_MASK_SET) = mask;
367f964209aSgdamore 					wbflush();
368ca42af5eSsimonb 				}
369ca42af5eSsimonb 			}
370d7b576a5Sgdamore 		}
371ca42af5eSsimonb 	}
372ca42af5eSsimonb }
37307fe2e72Sgdamore 
37407fe2e72Sgdamore /*
37507fe2e72Sgdamore  * Some devices (e.g. PCMCIA) want to be able to mask interrupts at
37607fe2e72Sgdamore  * the ICU, and leave them masked off until some later time
37707fe2e72Sgdamore  * (e.g. reenabled by a soft interrupt).
37807fe2e72Sgdamore  */
37907fe2e72Sgdamore 
38007fe2e72Sgdamore void
au_intr_enable(int irq)38107fe2e72Sgdamore au_intr_enable(int irq)
38207fe2e72Sgdamore {
38307fe2e72Sgdamore 	int		s;
38407fe2e72Sgdamore 	uint32_t	icu_base, mask;
38507fe2e72Sgdamore 
38607fe2e72Sgdamore 	if (irq >= NIRQS)
38707fe2e72Sgdamore 		panic("au_intr_enable: bogus IRQ %d", irq);
38807fe2e72Sgdamore 
38907fe2e72Sgdamore 	icu_base = (irq < 32) ? ic0_base : ic1_base;
39007fe2e72Sgdamore 	mask = irq & 31;
39107fe2e72Sgdamore 	mask = 1 << mask;
39207fe2e72Sgdamore 
39307fe2e72Sgdamore 	s = splhigh();
39407fe2e72Sgdamore 	/* only enable the interrupt if we have a handler */
395f964209aSgdamore 	if (au_icu_intrtab[irq].intr_refcnt) {
39607fe2e72Sgdamore 		REGVAL(icu_base + IC_MASK_SET) = mask;
397f964209aSgdamore 		REGVAL(icu_base + IC_WAKEUP_SET) = mask;
398f964209aSgdamore 		wbflush();
399f964209aSgdamore 	}
40007fe2e72Sgdamore 	splx(s);
40107fe2e72Sgdamore }
40207fe2e72Sgdamore 
40307fe2e72Sgdamore void
au_intr_disable(int irq)40407fe2e72Sgdamore au_intr_disable(int irq)
40507fe2e72Sgdamore {
40607fe2e72Sgdamore 	int		s;
40707fe2e72Sgdamore 	uint32_t	icu_base, mask;
40807fe2e72Sgdamore 
409f964209aSgdamore 	if (irq >= NIRQS)
410f964209aSgdamore 		panic("au_intr_disable: bogus IRQ %d", irq);
411f964209aSgdamore 
41207fe2e72Sgdamore 	icu_base = (irq < 32) ? ic0_base : ic1_base;
41307fe2e72Sgdamore 	mask = irq & 31;
41407fe2e72Sgdamore 	mask = 1 << mask;
41507fe2e72Sgdamore 
41607fe2e72Sgdamore 	s = splhigh();
41707fe2e72Sgdamore 	REGVAL(icu_base + IC_MASK_CLEAR) = mask;
418f964209aSgdamore 	REGVAL(icu_base + IC_WAKEUP_CLEAR) = mask;
419f964209aSgdamore 	wbflush();
42007fe2e72Sgdamore 	splx(s);
42107fe2e72Sgdamore }
422