au_icu.c revision 1.21.30.1 1 1.21.30.1 mjf /* $NetBSD: au_icu.c,v 1.21.30.1 2007/12/08 18:17:22 mjf Exp $ */
2 1.13 gdamore
3 1.13 gdamore /*-
4 1.13 gdamore * Copyright (c) 2006 Itronix Inc.
5 1.13 gdamore * All rights reserved.
6 1.13 gdamore *
7 1.13 gdamore * Written by Garrett D'Amore for Itronix Inc.
8 1.13 gdamore *
9 1.13 gdamore * Redistribution and use in source and binary forms, with or without
10 1.13 gdamore * modification, are permitted provided that the following conditions
11 1.13 gdamore * are met:
12 1.13 gdamore * 1. Redistributions of source code must retain the above copyright
13 1.13 gdamore * notice, this list of conditions and the following disclaimer.
14 1.13 gdamore * 2. Redistributions in binary form must reproduce the above copyright
15 1.13 gdamore * notice, this list of conditions and the following disclaimer in the
16 1.13 gdamore * documentation and/or other materials provided with the distribution.
17 1.13 gdamore * 3. The name of Itronix Inc. may not be used to endorse
18 1.13 gdamore * or promote products derived from this software without specific
19 1.13 gdamore * prior written permission.
20 1.13 gdamore *
21 1.13 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 1.13 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 1.13 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 1.13 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 1.13 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 1.13 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 1.13 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 1.13 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
29 1.13 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 1.13 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.13 gdamore * POSSIBILITY OF SUCH DAMAGE.
32 1.13 gdamore */
33 1.1 simonb
34 1.1 simonb /*-
35 1.1 simonb * Copyright (c) 2001 The NetBSD Foundation, Inc.
36 1.1 simonb * All rights reserved.
37 1.1 simonb *
38 1.1 simonb * This code is derived from software contributed to The NetBSD Foundation
39 1.1 simonb * by Jason R. Thorpe.
40 1.1 simonb *
41 1.1 simonb * Redistribution and use in source and binary forms, with or without
42 1.1 simonb * modification, are permitted provided that the following conditions
43 1.1 simonb * are met:
44 1.1 simonb * 1. Redistributions of source code must retain the above copyright
45 1.1 simonb * notice, this list of conditions and the following disclaimer.
46 1.1 simonb * 2. Redistributions in binary form must reproduce the above copyright
47 1.1 simonb * notice, this list of conditions and the following disclaimer in the
48 1.1 simonb * documentation and/or other materials provided with the distribution.
49 1.1 simonb * 3. All advertising materials mentioning features or use of this software
50 1.1 simonb * must display the following acknowledgement:
51 1.1 simonb * This product includes software developed by the NetBSD
52 1.1 simonb * Foundation, Inc. and its contributors.
53 1.1 simonb * 4. Neither the name of The NetBSD Foundation nor the names of its
54 1.1 simonb * contributors may be used to endorse or promote products derived
55 1.1 simonb * from this software without specific prior written permission.
56 1.1 simonb *
57 1.1 simonb * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58 1.1 simonb * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59 1.1 simonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60 1.1 simonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61 1.1 simonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62 1.1 simonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63 1.1 simonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64 1.1 simonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65 1.1 simonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66 1.1 simonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67 1.1 simonb * POSSIBILITY OF SUCH DAMAGE.
68 1.1 simonb */
69 1.1 simonb
70 1.1 simonb /*
71 1.1 simonb * Interrupt support for the Alchemy Semiconductor Au1x00 CPUs.
72 1.1 simonb *
73 1.1 simonb * The Alchemy Semiconductor Au1x00's interrupts are wired to two internal
74 1.1 simonb * interrupt controllers.
75 1.1 simonb */
76 1.7 lukem
77 1.7 lukem #include <sys/cdefs.h>
78 1.21.30.1 mjf __KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.21.30.1 2007/12/08 18:17:22 mjf Exp $");
79 1.1 simonb
80 1.1 simonb #include "opt_ddb.h"
81 1.1 simonb
82 1.1 simonb #include <sys/param.h>
83 1.1 simonb #include <sys/queue.h>
84 1.1 simonb #include <sys/malloc.h>
85 1.1 simonb #include <sys/systm.h>
86 1.1 simonb #include <sys/device.h>
87 1.1 simonb #include <sys/kernel.h>
88 1.1 simonb
89 1.1 simonb #include <machine/bus.h>
90 1.1 simonb #include <machine/intr.h>
91 1.1 simonb
92 1.1 simonb #include <mips/locore.h>
93 1.1 simonb #include <mips/alchemy/include/aureg.h>
94 1.1 simonb #include <mips/alchemy/include/auvar.h>
95 1.1 simonb
96 1.14 gdamore #define REGVAL(x) *((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
97 1.1 simonb
98 1.1 simonb /*
99 1.1 simonb * This is a mask of bits to clear in the SR when we go to a
100 1.1 simonb * given hardware interrupt priority level.
101 1.1 simonb */
102 1.1 simonb
103 1.14 gdamore const uint32_t ipl_sr_bits[_IPL_N] = {
104 1.1 simonb 0, /* 0: IPL_NONE */
105 1.21.30.1 mjf MIPS_SOFT_INT_MASK_0, /* 1: IPL_SOFTCLOCK */
106 1.21.30.1 mjf MIPS_SOFT_INT_MASK_0, /* 2: IPL_SOFTNET */
107 1.1 simonb MIPS_SOFT_INT_MASK_0|
108 1.1 simonb MIPS_SOFT_INT_MASK_1|
109 1.21.30.1 mjf MIPS_INT_MASK_0, /* 3: IPL_VM */
110 1.1 simonb MIPS_SOFT_INT_MASK_0|
111 1.1 simonb MIPS_SOFT_INT_MASK_1|
112 1.1 simonb MIPS_INT_MASK_0|
113 1.1 simonb MIPS_INT_MASK_1|
114 1.1 simonb MIPS_INT_MASK_2|
115 1.1 simonb MIPS_INT_MASK_3|
116 1.1 simonb MIPS_INT_MASK_4|
117 1.21.30.1 mjf MIPS_INT_MASK_5, /* 4: IPL_{SCHED,HIGH} */
118 1.1 simonb };
119 1.1 simonb
120 1.1 simonb #define NIRQS 64
121 1.1 simonb
122 1.13 gdamore struct au_icu_intrhead {
123 1.1 simonb struct evcnt intr_count;
124 1.1 simonb int intr_refcnt;
125 1.1 simonb };
126 1.13 gdamore struct au_icu_intrhead au_icu_intrtab[NIRQS];
127 1.1 simonb
128 1.1 simonb #define NINTRS 4 /* MIPS INT0 - INT3 */
129 1.1 simonb
130 1.14 gdamore struct au_intrhand {
131 1.14 gdamore LIST_ENTRY(au_intrhand) ih_q;
132 1.14 gdamore int (*ih_func)(void *);
133 1.14 gdamore void *ih_arg;
134 1.14 gdamore int ih_irq;
135 1.19 gdamore int ih_mask;
136 1.14 gdamore };
137 1.14 gdamore
138 1.13 gdamore struct au_cpuintr {
139 1.14 gdamore LIST_HEAD(, au_intrhand) cintr_list;
140 1.1 simonb struct evcnt cintr_count;
141 1.1 simonb };
142 1.1 simonb
143 1.13 gdamore struct au_cpuintr au_cpuintrs[NINTRS];
144 1.13 gdamore const char *au_cpuintrnames[NINTRS] = {
145 1.1 simonb "icu 0, req 0",
146 1.1 simonb "icu 0, req 1",
147 1.1 simonb "icu 1, req 0",
148 1.1 simonb "icu 1, req 1",
149 1.1 simonb };
150 1.1 simonb
151 1.13 gdamore static bus_addr_t ic0_base, ic1_base;
152 1.13 gdamore
153 1.1 simonb void
154 1.1 simonb au_intr_init(void)
155 1.1 simonb {
156 1.13 gdamore int i;
157 1.13 gdamore struct au_chipdep *chip;
158 1.1 simonb
159 1.1 simonb for (i = 0; i < NINTRS; i++) {
160 1.13 gdamore LIST_INIT(&au_cpuintrs[i].cintr_list);
161 1.13 gdamore evcnt_attach_dynamic(&au_cpuintrs[i].cintr_count,
162 1.13 gdamore EVCNT_TYPE_INTR, NULL, "mips", au_cpuintrnames[i]);
163 1.1 simonb }
164 1.1 simonb
165 1.13 gdamore chip = au_chipdep();
166 1.13 gdamore KASSERT(chip != NULL);
167 1.13 gdamore
168 1.13 gdamore ic0_base = chip->icus[0];
169 1.13 gdamore ic1_base = chip->icus[1];
170 1.13 gdamore
171 1.1 simonb for (i = 0; i < NIRQS; i++) {
172 1.13 gdamore au_icu_intrtab[i].intr_refcnt = 0;
173 1.13 gdamore evcnt_attach_dynamic(&au_icu_intrtab[i].intr_count,
174 1.13 gdamore EVCNT_TYPE_INTR, NULL, chip->name, chip->irqnames[i]);
175 1.1 simonb }
176 1.19 gdamore
177 1.19 gdamore /* start with all interrupts masked */
178 1.19 gdamore REGVAL(ic0_base + IC_MASK_CLEAR) = 0xffffffff;
179 1.19 gdamore REGVAL(ic0_base + IC_WAKEUP_CLEAR) = 0xffffffff;
180 1.19 gdamore REGVAL(ic0_base + IC_SOURCE_SET) = 0xffffffff;
181 1.19 gdamore REGVAL(ic0_base + IC_RISING_EDGE) = 0xffffffff;
182 1.19 gdamore REGVAL(ic0_base + IC_FALLING_EDGE) = 0xffffffff;
183 1.19 gdamore REGVAL(ic0_base + IC_TEST_BIT) = 0;
184 1.19 gdamore
185 1.19 gdamore REGVAL(ic1_base + IC_MASK_CLEAR) = 0xffffffff;
186 1.19 gdamore REGVAL(ic1_base + IC_WAKEUP_CLEAR) = 0xffffffff;
187 1.19 gdamore REGVAL(ic1_base + IC_SOURCE_SET) = 0xffffffff;
188 1.19 gdamore REGVAL(ic1_base + IC_RISING_EDGE) = 0xffffffff;
189 1.19 gdamore REGVAL(ic1_base + IC_FALLING_EDGE) = 0xffffffff;
190 1.19 gdamore REGVAL(ic1_base + IC_TEST_BIT) = 0;
191 1.1 simonb }
192 1.1 simonb
193 1.1 simonb void *
194 1.1 simonb au_intr_establish(int irq, int req, int level, int type,
195 1.1 simonb int (*func)(void *), void *arg)
196 1.1 simonb {
197 1.14 gdamore struct au_intrhand *ih;
198 1.13 gdamore uint32_t icu_base;
199 1.13 gdamore int cpu_int, s;
200 1.13 gdamore struct au_chipdep *chip;
201 1.13 gdamore
202 1.13 gdamore chip = au_chipdep();
203 1.13 gdamore KASSERT(chip != NULL);
204 1.1 simonb
205 1.1 simonb if (irq >= NIRQS)
206 1.3 provos panic("au_intr_establish: bogus IRQ %d", irq);
207 1.1 simonb if (req > 1)
208 1.3 provos panic("au_intr_establish: bogus request %d", req);
209 1.1 simonb
210 1.1 simonb ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
211 1.1 simonb if (ih == NULL)
212 1.1 simonb return (NULL);
213 1.1 simonb
214 1.1 simonb ih->ih_func = func;
215 1.1 simonb ih->ih_arg = arg;
216 1.1 simonb ih->ih_irq = irq;
217 1.19 gdamore ih->ih_mask = (1 << (irq & 31));
218 1.1 simonb
219 1.1 simonb s = splhigh();
220 1.1 simonb
221 1.1 simonb /*
222 1.1 simonb * First, link it into the tables.
223 1.1 simonb * XXX do we want a separate list (really, should only be one item, not
224 1.9 wiz * a list anyway) per irq, not per CPU interrupt?
225 1.1 simonb */
226 1.20 gdamore cpu_int = (irq < 32 ? 0 : 2) + req;
227 1.13 gdamore LIST_INSERT_HEAD(&au_cpuintrs[cpu_int].cintr_list, ih, ih_q);
228 1.1 simonb
229 1.1 simonb /*
230 1.1 simonb * Now enable it.
231 1.1 simonb */
232 1.13 gdamore if (au_icu_intrtab[irq].intr_refcnt++ == 0) {
233 1.13 gdamore icu_base = (irq < 32) ? ic0_base : ic1_base;
234 1.1 simonb
235 1.1 simonb irq &= 31; /* throw away high bit if set */
236 1.1 simonb irq = 1 << irq; /* only used as a mask from here on */
237 1.1 simonb
238 1.13 gdamore /* XXX Only level interrupts for now */
239 1.1 simonb switch (type) {
240 1.1 simonb case IST_NONE:
241 1.1 simonb case IST_PULSE:
242 1.1 simonb case IST_EDGE:
243 1.1 simonb panic("unsupported irq type %d", type);
244 1.5 hpeyerl /* NOTREACHED */
245 1.1 simonb case IST_LEVEL:
246 1.5 hpeyerl case IST_LEVEL_HIGH:
247 1.1 simonb REGVAL(icu_base + IC_CONFIG2_SET) = irq;
248 1.1 simonb REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
249 1.1 simonb REGVAL(icu_base + IC_CONFIG0_SET) = irq;
250 1.5 hpeyerl break;
251 1.5 hpeyerl case IST_LEVEL_LOW:
252 1.5 hpeyerl REGVAL(icu_base + IC_CONFIG2_SET) = irq;
253 1.5 hpeyerl REGVAL(icu_base + IC_CONFIG1_SET) = irq;
254 1.5 hpeyerl REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
255 1.5 hpeyerl break;
256 1.1 simonb }
257 1.18 gdamore wbflush();
258 1.1 simonb
259 1.1 simonb /* XXX handle GPIO interrupts - not done at all yet */
260 1.10 he if (cpu_int & 0x1)
261 1.1 simonb REGVAL(icu_base + IC_ASSIGN_REQUEST_CLEAR) = irq;
262 1.1 simonb else
263 1.1 simonb REGVAL(icu_base + IC_ASSIGN_REQUEST_SET) = irq;
264 1.1 simonb
265 1.1 simonb /* Associate interrupt with peripheral */
266 1.1 simonb REGVAL(icu_base + IC_SOURCE_SET) = irq;
267 1.1 simonb
268 1.1 simonb /* Actually enable the interrupt */
269 1.1 simonb REGVAL(icu_base + IC_MASK_SET) = irq;
270 1.1 simonb
271 1.1 simonb /* And allow the interrupt to interrupt idle */
272 1.1 simonb REGVAL(icu_base + IC_WAKEUP_SET) = irq;
273 1.18 gdamore
274 1.18 gdamore wbflush();
275 1.1 simonb }
276 1.1 simonb splx(s);
277 1.1 simonb
278 1.1 simonb return (ih);
279 1.1 simonb }
280 1.1 simonb
281 1.1 simonb void
282 1.1 simonb au_intr_disestablish(void *cookie)
283 1.1 simonb {
284 1.14 gdamore struct au_intrhand *ih = cookie;
285 1.1 simonb uint32_t icu_base;
286 1.1 simonb int irq, s;
287 1.1 simonb
288 1.1 simonb irq = ih->ih_irq;
289 1.1 simonb
290 1.1 simonb s = splhigh();
291 1.1 simonb
292 1.1 simonb /*
293 1.1 simonb * First, remove it from the table.
294 1.1 simonb */
295 1.1 simonb LIST_REMOVE(ih, ih_q);
296 1.1 simonb
297 1.1 simonb /*
298 1.1 simonb * Now, disable it, if there is nothing remaining on the
299 1.1 simonb * list.
300 1.1 simonb */
301 1.13 gdamore if (au_icu_intrtab[irq].intr_refcnt-- == 1) {
302 1.13 gdamore icu_base = (irq < 32) ? ic0_base : ic1_base;
303 1.1 simonb
304 1.1 simonb irq &= 31; /* throw away high bit if set */
305 1.1 simonb irq = 1 << irq; /* only used as a mask from here on */
306 1.1 simonb
307 1.1 simonb REGVAL(icu_base + IC_CONFIG2_CLEAR) = irq;
308 1.1 simonb REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
309 1.1 simonb REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
310 1.1 simonb
311 1.15 gdamore /* disable with MASK_CLEAR and WAKEUP_CLEAR */
312 1.15 gdamore REGVAL(icu_base + IC_MASK_CLEAR) = irq;
313 1.15 gdamore REGVAL(icu_base + IC_WAKEUP_CLEAR) = irq;
314 1.18 gdamore wbflush();
315 1.1 simonb }
316 1.1 simonb
317 1.1 simonb splx(s);
318 1.1 simonb
319 1.1 simonb free(ih, M_DEVBUF);
320 1.1 simonb }
321 1.1 simonb
322 1.1 simonb void
323 1.14 gdamore au_iointr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
324 1.1 simonb {
325 1.14 gdamore struct au_intrhand *ih;
326 1.1 simonb int level;
327 1.17 simonb uint32_t icu_base, irqstat, irqmask;
328 1.17 simonb
329 1.19 gdamore icu_base = irqstat = 0;
330 1.1 simonb
331 1.1 simonb for (level = 3; level >= 0; level--) {
332 1.1 simonb if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
333 1.1 simonb continue;
334 1.1 simonb
335 1.1 simonb /*
336 1.1 simonb * XXX the following may well be slow to execute.
337 1.1 simonb * investigate and possibly speed up.
338 1.1 simonb *
339 1.1 simonb * is something like:
340 1.1 simonb *
341 1.17 simonb * irqstat = REGVAL(
342 1.1 simonb * (level & 4 == 0) ? IC0_BASE ? IC1_BASE +
343 1.1 simonb * (level & 2 == 0) ? IC_REQUEST0_INT : IC_REQUEST1_INT);
344 1.1 simonb *
345 1.1 simonb * be any better?
346 1.1 simonb *
347 1.1 simonb */
348 1.1 simonb switch (level) {
349 1.1 simonb case 0:
350 1.13 gdamore icu_base = ic0_base;
351 1.15 gdamore irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
352 1.1 simonb break;
353 1.1 simonb case 1:
354 1.13 gdamore icu_base = ic0_base;
355 1.15 gdamore irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
356 1.1 simonb break;
357 1.1 simonb case 2:
358 1.13 gdamore icu_base = ic1_base;
359 1.15 gdamore irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
360 1.1 simonb break;
361 1.1 simonb case 3:
362 1.13 gdamore icu_base = ic1_base;
363 1.15 gdamore irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
364 1.1 simonb break;
365 1.1 simonb }
366 1.15 gdamore irqmask = REGVAL(icu_base + IC_MASK_READ);
367 1.13 gdamore au_cpuintrs[level].cintr_count.ev_count++;
368 1.13 gdamore LIST_FOREACH(ih, &au_cpuintrs[level].cintr_list, ih_q) {
369 1.19 gdamore int mask = ih->ih_mask;
370 1.15 gdamore
371 1.19 gdamore if (mask & irqmask & irqstat) {
372 1.13 gdamore au_icu_intrtab[ih->ih_irq].intr_count.ev_count++;
373 1.1 simonb (*ih->ih_func)(ih->ih_arg);
374 1.1 simonb
375 1.19 gdamore if (REGVAL(icu_base + IC_MASK_READ) & mask) {
376 1.19 gdamore REGVAL(icu_base + IC_MASK_CLEAR) = mask;
377 1.19 gdamore REGVAL(icu_base + IC_MASK_SET) = mask;
378 1.18 gdamore wbflush();
379 1.16 gdamore }
380 1.1 simonb }
381 1.1 simonb }
382 1.1 simonb cause &= ~(MIPS_INT_MASK_0 << level);
383 1.1 simonb }
384 1.1 simonb
385 1.1 simonb /* Re-enable anything that we have processed. */
386 1.1 simonb _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
387 1.1 simonb }
388 1.15 gdamore
389 1.15 gdamore /*
390 1.15 gdamore * Some devices (e.g. PCMCIA) want to be able to mask interrupts at
391 1.15 gdamore * the ICU, and leave them masked off until some later time
392 1.15 gdamore * (e.g. reenabled by a soft interrupt).
393 1.15 gdamore */
394 1.15 gdamore
395 1.15 gdamore void
396 1.15 gdamore au_intr_enable(int irq)
397 1.15 gdamore {
398 1.15 gdamore int s;
399 1.15 gdamore uint32_t icu_base, mask;
400 1.15 gdamore
401 1.15 gdamore if (irq >= NIRQS)
402 1.15 gdamore panic("au_intr_enable: bogus IRQ %d", irq);
403 1.15 gdamore
404 1.15 gdamore icu_base = (irq < 32) ? ic0_base : ic1_base;
405 1.15 gdamore mask = irq & 31;
406 1.15 gdamore mask = 1 << mask;
407 1.15 gdamore
408 1.15 gdamore s = splhigh();
409 1.15 gdamore /* only enable the interrupt if we have a handler */
410 1.18 gdamore if (au_icu_intrtab[irq].intr_refcnt) {
411 1.15 gdamore REGVAL(icu_base + IC_MASK_SET) = mask;
412 1.18 gdamore REGVAL(icu_base + IC_WAKEUP_SET) = mask;
413 1.18 gdamore wbflush();
414 1.18 gdamore }
415 1.15 gdamore splx(s);
416 1.15 gdamore }
417 1.15 gdamore
418 1.15 gdamore void
419 1.15 gdamore au_intr_disable(int irq)
420 1.15 gdamore {
421 1.15 gdamore int s;
422 1.15 gdamore uint32_t icu_base, mask;
423 1.15 gdamore
424 1.18 gdamore if (irq >= NIRQS)
425 1.18 gdamore panic("au_intr_disable: bogus IRQ %d", irq);
426 1.18 gdamore
427 1.15 gdamore icu_base = (irq < 32) ? ic0_base : ic1_base;
428 1.15 gdamore mask = irq & 31;
429 1.15 gdamore mask = 1 << mask;
430 1.15 gdamore
431 1.15 gdamore s = splhigh();
432 1.15 gdamore REGVAL(icu_base + IC_MASK_CLEAR) = mask;
433 1.18 gdamore REGVAL(icu_base + IC_WAKEUP_CLEAR) = mask;
434 1.18 gdamore wbflush();
435 1.15 gdamore splx(s);
436 1.15 gdamore }
437