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