diff options
Diffstat (limited to 'arch/mips/vr41xx/common/icu.c')
-rw-r--r-- | arch/mips/vr41xx/common/icu.c | 757 |
1 files changed, 757 insertions, 0 deletions
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c new file mode 100644 index 000000000000..c842661144cb --- /dev/null +++ b/arch/mips/vr41xx/common/icu.c | |||
@@ -0,0 +1,757 @@ | |||
1 | /* | ||
2 | * icu.c, Interrupt Control Unit routines for the NEC VR4100 series. | ||
3 | * | ||
4 | * Copyright (C) 2001-2002 MontaVista Software Inc. | ||
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> | ||
6 | * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
7 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | /* | ||
24 | * Changes: | ||
25 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | ||
26 | * - New creation, NEC VR4122 and VR4131 are supported. | ||
27 | * - Added support for NEC VR4111 and VR4121. | ||
28 | * | ||
29 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | ||
30 | * - Coped with INTASSIGN of NEC VR4133. | ||
31 | */ | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/irq.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/smp.h> | ||
38 | #include <linux/types.h> | ||
39 | |||
40 | #include <asm/cpu.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/irq_cpu.h> | ||
44 | #include <asm/vr41xx/vr41xx.h> | ||
45 | |||
46 | extern asmlinkage void vr41xx_handle_interrupt(void); | ||
47 | |||
48 | extern void init_vr41xx_giuint_irq(void); | ||
49 | extern void giuint_irq_dispatch(struct pt_regs *regs); | ||
50 | |||
51 | static uint32_t icu1_base; | ||
52 | static uint32_t icu2_base; | ||
53 | |||
54 | static struct irqaction icu_cascade = { | ||
55 | .handler = no_action, | ||
56 | .mask = CPU_MASK_NONE, | ||
57 | .name = "cascade", | ||
58 | }; | ||
59 | |||
60 | static unsigned char sysint1_assign[16] = { | ||
61 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
62 | static unsigned char sysint2_assign[16] = { | ||
63 | 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
64 | |||
65 | #define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080) | ||
66 | #define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200) | ||
67 | |||
68 | #define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080) | ||
69 | #define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0) | ||
70 | |||
71 | #define SYSINT1REG 0x00 | ||
72 | #define PIUINTREG 0x02 | ||
73 | #define INTASSIGN0 0x04 | ||
74 | #define INTASSIGN1 0x06 | ||
75 | #define GIUINTLREG 0x08 | ||
76 | #define DSIUINTREG 0x0a | ||
77 | #define MSYSINT1REG 0x0c | ||
78 | #define MPIUINTREG 0x0e | ||
79 | #define MAIUINTREG 0x10 | ||
80 | #define MKIUINTREG 0x12 | ||
81 | #define MGIUINTLREG 0x14 | ||
82 | #define MDSIUINTREG 0x16 | ||
83 | #define NMIREG 0x18 | ||
84 | #define SOFTREG 0x1a | ||
85 | #define INTASSIGN2 0x1c | ||
86 | #define INTASSIGN3 0x1e | ||
87 | |||
88 | #define SYSINT2REG 0x00 | ||
89 | #define GIUINTHREG 0x02 | ||
90 | #define FIRINTREG 0x04 | ||
91 | #define MSYSINT2REG 0x06 | ||
92 | #define MGIUINTHREG 0x08 | ||
93 | #define MFIRINTREG 0x0a | ||
94 | #define PCIINTREG 0x0c | ||
95 | #define PCIINT0 0x0001 | ||
96 | #define SCUINTREG 0x0e | ||
97 | #define SCUINT0 0x0001 | ||
98 | #define CSIINTREG 0x10 | ||
99 | #define MPCIINTREG 0x12 | ||
100 | #define MSCUINTREG 0x14 | ||
101 | #define MCSIINTREG 0x16 | ||
102 | #define BCUINTREG 0x18 | ||
103 | #define BCUINTR 0x0001 | ||
104 | #define MBCUINTREG 0x1a | ||
105 | |||
106 | #define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */ | ||
107 | #define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */ | ||
108 | |||
109 | #define read_icu1(offset) readw(icu1_base + (offset)) | ||
110 | #define write_icu1(val, offset) writew((val), icu1_base + (offset)) | ||
111 | |||
112 | #define read_icu2(offset) readw(icu2_base + (offset)) | ||
113 | #define write_icu2(val, offset) writew((val), icu2_base + (offset)) | ||
114 | |||
115 | #define INTASSIGN_MAX 4 | ||
116 | #define INTASSIGN_MASK 0x0007 | ||
117 | |||
118 | static inline uint16_t set_icu1(uint8_t offset, uint16_t set) | ||
119 | { | ||
120 | uint16_t res; | ||
121 | |||
122 | res = read_icu1(offset); | ||
123 | res |= set; | ||
124 | write_icu1(res, offset); | ||
125 | |||
126 | return res; | ||
127 | } | ||
128 | |||
129 | static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear) | ||
130 | { | ||
131 | uint16_t res; | ||
132 | |||
133 | res = read_icu1(offset); | ||
134 | res &= ~clear; | ||
135 | write_icu1(res, offset); | ||
136 | |||
137 | return res; | ||
138 | } | ||
139 | |||
140 | static inline uint16_t set_icu2(uint8_t offset, uint16_t set) | ||
141 | { | ||
142 | uint16_t res; | ||
143 | |||
144 | res = read_icu2(offset); | ||
145 | res |= set; | ||
146 | write_icu2(res, offset); | ||
147 | |||
148 | return res; | ||
149 | } | ||
150 | |||
151 | static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear) | ||
152 | { | ||
153 | uint16_t res; | ||
154 | |||
155 | res = read_icu2(offset); | ||
156 | res &= ~clear; | ||
157 | write_icu2(res, offset); | ||
158 | |||
159 | return res; | ||
160 | } | ||
161 | |||
162 | /*=======================================================================*/ | ||
163 | |||
164 | void vr41xx_enable_piuint(uint16_t mask) | ||
165 | { | ||
166 | irq_desc_t *desc = irq_desc + PIU_IRQ; | ||
167 | unsigned long flags; | ||
168 | |||
169 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
170 | current_cpu_data.cputype == CPU_VR4121) { | ||
171 | spin_lock_irqsave(&desc->lock, flags); | ||
172 | set_icu1(MPIUINTREG, mask); | ||
173 | spin_unlock_irqrestore(&desc->lock, flags); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | EXPORT_SYMBOL(vr41xx_enable_piuint); | ||
178 | |||
179 | void vr41xx_disable_piuint(uint16_t mask) | ||
180 | { | ||
181 | irq_desc_t *desc = irq_desc + PIU_IRQ; | ||
182 | unsigned long flags; | ||
183 | |||
184 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
185 | current_cpu_data.cputype == CPU_VR4121) { | ||
186 | spin_lock_irqsave(&desc->lock, flags); | ||
187 | clear_icu1(MPIUINTREG, mask); | ||
188 | spin_unlock_irqrestore(&desc->lock, flags); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | EXPORT_SYMBOL(vr41xx_disable_piuint); | ||
193 | |||
194 | void vr41xx_enable_aiuint(uint16_t mask) | ||
195 | { | ||
196 | irq_desc_t *desc = irq_desc + AIU_IRQ; | ||
197 | unsigned long flags; | ||
198 | |||
199 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
200 | current_cpu_data.cputype == CPU_VR4121) { | ||
201 | spin_lock_irqsave(&desc->lock, flags); | ||
202 | set_icu1(MAIUINTREG, mask); | ||
203 | spin_unlock_irqrestore(&desc->lock, flags); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | EXPORT_SYMBOL(vr41xx_enable_aiuint); | ||
208 | |||
209 | void vr41xx_disable_aiuint(uint16_t mask) | ||
210 | { | ||
211 | irq_desc_t *desc = irq_desc + AIU_IRQ; | ||
212 | unsigned long flags; | ||
213 | |||
214 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
215 | current_cpu_data.cputype == CPU_VR4121) { | ||
216 | spin_lock_irqsave(&desc->lock, flags); | ||
217 | clear_icu1(MAIUINTREG, mask); | ||
218 | spin_unlock_irqrestore(&desc->lock, flags); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | EXPORT_SYMBOL(vr41xx_disable_aiuint); | ||
223 | |||
224 | void vr41xx_enable_kiuint(uint16_t mask) | ||
225 | { | ||
226 | irq_desc_t *desc = irq_desc + KIU_IRQ; | ||
227 | unsigned long flags; | ||
228 | |||
229 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
230 | current_cpu_data.cputype == CPU_VR4121) { | ||
231 | spin_lock_irqsave(&desc->lock, flags); | ||
232 | set_icu1(MKIUINTREG, mask); | ||
233 | spin_unlock_irqrestore(&desc->lock, flags); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | EXPORT_SYMBOL(vr41xx_enable_kiuint); | ||
238 | |||
239 | void vr41xx_disable_kiuint(uint16_t mask) | ||
240 | { | ||
241 | irq_desc_t *desc = irq_desc + KIU_IRQ; | ||
242 | unsigned long flags; | ||
243 | |||
244 | if (current_cpu_data.cputype == CPU_VR4111 || | ||
245 | current_cpu_data.cputype == CPU_VR4121) { | ||
246 | spin_lock_irqsave(&desc->lock, flags); | ||
247 | clear_icu1(MKIUINTREG, mask); | ||
248 | spin_unlock_irqrestore(&desc->lock, flags); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | EXPORT_SYMBOL(vr41xx_disable_kiuint); | ||
253 | |||
254 | void vr41xx_enable_dsiuint(uint16_t mask) | ||
255 | { | ||
256 | irq_desc_t *desc = irq_desc + DSIU_IRQ; | ||
257 | unsigned long flags; | ||
258 | |||
259 | spin_lock_irqsave(&desc->lock, flags); | ||
260 | set_icu1(MDSIUINTREG, mask); | ||
261 | spin_unlock_irqrestore(&desc->lock, flags); | ||
262 | } | ||
263 | |||
264 | EXPORT_SYMBOL(vr41xx_enable_dsiuint); | ||
265 | |||
266 | void vr41xx_disable_dsiuint(uint16_t mask) | ||
267 | { | ||
268 | irq_desc_t *desc = irq_desc + DSIU_IRQ; | ||
269 | unsigned long flags; | ||
270 | |||
271 | spin_lock_irqsave(&desc->lock, flags); | ||
272 | clear_icu1(MDSIUINTREG, mask); | ||
273 | spin_unlock_irqrestore(&desc->lock, flags); | ||
274 | } | ||
275 | |||
276 | EXPORT_SYMBOL(vr41xx_disable_dsiuint); | ||
277 | |||
278 | void vr41xx_enable_firint(uint16_t mask) | ||
279 | { | ||
280 | irq_desc_t *desc = irq_desc + FIR_IRQ; | ||
281 | unsigned long flags; | ||
282 | |||
283 | spin_lock_irqsave(&desc->lock, flags); | ||
284 | set_icu2(MFIRINTREG, mask); | ||
285 | spin_unlock_irqrestore(&desc->lock, flags); | ||
286 | } | ||
287 | |||
288 | EXPORT_SYMBOL(vr41xx_enable_firint); | ||
289 | |||
290 | void vr41xx_disable_firint(uint16_t mask) | ||
291 | { | ||
292 | irq_desc_t *desc = irq_desc + FIR_IRQ; | ||
293 | unsigned long flags; | ||
294 | |||
295 | spin_lock_irqsave(&desc->lock, flags); | ||
296 | clear_icu2(MFIRINTREG, mask); | ||
297 | spin_unlock_irqrestore(&desc->lock, flags); | ||
298 | } | ||
299 | |||
300 | EXPORT_SYMBOL(vr41xx_disable_firint); | ||
301 | |||
302 | void vr41xx_enable_pciint(void) | ||
303 | { | ||
304 | irq_desc_t *desc = irq_desc + PCI_IRQ; | ||
305 | unsigned long flags; | ||
306 | |||
307 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
308 | current_cpu_data.cputype == CPU_VR4131 || | ||
309 | current_cpu_data.cputype == CPU_VR4133) { | ||
310 | spin_lock_irqsave(&desc->lock, flags); | ||
311 | write_icu2(PCIINT0, MPCIINTREG); | ||
312 | spin_unlock_irqrestore(&desc->lock, flags); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | EXPORT_SYMBOL(vr41xx_enable_pciint); | ||
317 | |||
318 | void vr41xx_disable_pciint(void) | ||
319 | { | ||
320 | irq_desc_t *desc = irq_desc + PCI_IRQ; | ||
321 | unsigned long flags; | ||
322 | |||
323 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
324 | current_cpu_data.cputype == CPU_VR4131 || | ||
325 | current_cpu_data.cputype == CPU_VR4133) { | ||
326 | spin_lock_irqsave(&desc->lock, flags); | ||
327 | write_icu2(0, MPCIINTREG); | ||
328 | spin_unlock_irqrestore(&desc->lock, flags); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | EXPORT_SYMBOL(vr41xx_disable_pciint); | ||
333 | |||
334 | void vr41xx_enable_scuint(void) | ||
335 | { | ||
336 | irq_desc_t *desc = irq_desc + SCU_IRQ; | ||
337 | unsigned long flags; | ||
338 | |||
339 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
340 | current_cpu_data.cputype == CPU_VR4131 || | ||
341 | current_cpu_data.cputype == CPU_VR4133) { | ||
342 | spin_lock_irqsave(&desc->lock, flags); | ||
343 | write_icu2(SCUINT0, MSCUINTREG); | ||
344 | spin_unlock_irqrestore(&desc->lock, flags); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | EXPORT_SYMBOL(vr41xx_enable_scuint); | ||
349 | |||
350 | void vr41xx_disable_scuint(void) | ||
351 | { | ||
352 | irq_desc_t *desc = irq_desc + SCU_IRQ; | ||
353 | unsigned long flags; | ||
354 | |||
355 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
356 | current_cpu_data.cputype == CPU_VR4131 || | ||
357 | current_cpu_data.cputype == CPU_VR4133) { | ||
358 | spin_lock_irqsave(&desc->lock, flags); | ||
359 | write_icu2(0, MSCUINTREG); | ||
360 | spin_unlock_irqrestore(&desc->lock, flags); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | EXPORT_SYMBOL(vr41xx_disable_scuint); | ||
365 | |||
366 | void vr41xx_enable_csiint(uint16_t mask) | ||
367 | { | ||
368 | irq_desc_t *desc = irq_desc + CSI_IRQ; | ||
369 | unsigned long flags; | ||
370 | |||
371 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
372 | current_cpu_data.cputype == CPU_VR4131 || | ||
373 | current_cpu_data.cputype == CPU_VR4133) { | ||
374 | spin_lock_irqsave(&desc->lock, flags); | ||
375 | set_icu2(MCSIINTREG, mask); | ||
376 | spin_unlock_irqrestore(&desc->lock, flags); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | EXPORT_SYMBOL(vr41xx_enable_csiint); | ||
381 | |||
382 | void vr41xx_disable_csiint(uint16_t mask) | ||
383 | { | ||
384 | irq_desc_t *desc = irq_desc + CSI_IRQ; | ||
385 | unsigned long flags; | ||
386 | |||
387 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
388 | current_cpu_data.cputype == CPU_VR4131 || | ||
389 | current_cpu_data.cputype == CPU_VR4133) { | ||
390 | spin_lock_irqsave(&desc->lock, flags); | ||
391 | clear_icu2(MCSIINTREG, mask); | ||
392 | spin_unlock_irqrestore(&desc->lock, flags); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | EXPORT_SYMBOL(vr41xx_disable_csiint); | ||
397 | |||
398 | void vr41xx_enable_bcuint(void) | ||
399 | { | ||
400 | irq_desc_t *desc = irq_desc + BCU_IRQ; | ||
401 | unsigned long flags; | ||
402 | |||
403 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
404 | current_cpu_data.cputype == CPU_VR4131 || | ||
405 | current_cpu_data.cputype == CPU_VR4133) { | ||
406 | spin_lock_irqsave(&desc->lock, flags); | ||
407 | write_icu2(BCUINTR, MBCUINTREG); | ||
408 | spin_unlock_irqrestore(&desc->lock, flags); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | EXPORT_SYMBOL(vr41xx_enable_bcuint); | ||
413 | |||
414 | void vr41xx_disable_bcuint(void) | ||
415 | { | ||
416 | irq_desc_t *desc = irq_desc + BCU_IRQ; | ||
417 | unsigned long flags; | ||
418 | |||
419 | if (current_cpu_data.cputype == CPU_VR4122 || | ||
420 | current_cpu_data.cputype == CPU_VR4131 || | ||
421 | current_cpu_data.cputype == CPU_VR4133) { | ||
422 | spin_lock_irqsave(&desc->lock, flags); | ||
423 | write_icu2(0, MBCUINTREG); | ||
424 | spin_unlock_irqrestore(&desc->lock, flags); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | EXPORT_SYMBOL(vr41xx_disable_bcuint); | ||
429 | |||
430 | /*=======================================================================*/ | ||
431 | |||
432 | static unsigned int startup_sysint1_irq(unsigned int irq) | ||
433 | { | ||
434 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
435 | |||
436 | return 0; /* never anything pending */ | ||
437 | } | ||
438 | |||
439 | static void shutdown_sysint1_irq(unsigned int irq) | ||
440 | { | ||
441 | clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
442 | } | ||
443 | |||
444 | static void enable_sysint1_irq(unsigned int irq) | ||
445 | { | ||
446 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
447 | } | ||
448 | |||
449 | #define disable_sysint1_irq shutdown_sysint1_irq | ||
450 | #define ack_sysint1_irq shutdown_sysint1_irq | ||
451 | |||
452 | static void end_sysint1_irq(unsigned int irq) | ||
453 | { | ||
454 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
455 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | ||
456 | } | ||
457 | |||
458 | static struct hw_interrupt_type sysint1_irq_type = { | ||
459 | .typename = "SYSINT1", | ||
460 | .startup = startup_sysint1_irq, | ||
461 | .shutdown = shutdown_sysint1_irq, | ||
462 | .enable = enable_sysint1_irq, | ||
463 | .disable = disable_sysint1_irq, | ||
464 | .ack = ack_sysint1_irq, | ||
465 | .end = end_sysint1_irq, | ||
466 | }; | ||
467 | |||
468 | /*=======================================================================*/ | ||
469 | |||
470 | static unsigned int startup_sysint2_irq(unsigned int irq) | ||
471 | { | ||
472 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
473 | |||
474 | return 0; /* never anything pending */ | ||
475 | } | ||
476 | |||
477 | static void shutdown_sysint2_irq(unsigned int irq) | ||
478 | { | ||
479 | clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
480 | } | ||
481 | |||
482 | static void enable_sysint2_irq(unsigned int irq) | ||
483 | { | ||
484 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
485 | } | ||
486 | |||
487 | #define disable_sysint2_irq shutdown_sysint2_irq | ||
488 | #define ack_sysint2_irq shutdown_sysint2_irq | ||
489 | |||
490 | static void end_sysint2_irq(unsigned int irq) | ||
491 | { | ||
492 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
493 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | ||
494 | } | ||
495 | |||
496 | static struct hw_interrupt_type sysint2_irq_type = { | ||
497 | .typename = "SYSINT2", | ||
498 | .startup = startup_sysint2_irq, | ||
499 | .shutdown = shutdown_sysint2_irq, | ||
500 | .enable = enable_sysint2_irq, | ||
501 | .disable = disable_sysint2_irq, | ||
502 | .ack = ack_sysint2_irq, | ||
503 | .end = end_sysint2_irq, | ||
504 | }; | ||
505 | |||
506 | /*=======================================================================*/ | ||
507 | |||
508 | static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) | ||
509 | { | ||
510 | irq_desc_t *desc = irq_desc + irq; | ||
511 | uint16_t intassign0, intassign1; | ||
512 | unsigned int pin; | ||
513 | |||
514 | pin = SYSINT1_IRQ_TO_PIN(irq); | ||
515 | |||
516 | spin_lock_irq(&desc->lock); | ||
517 | |||
518 | intassign0 = read_icu1(INTASSIGN0); | ||
519 | intassign1 = read_icu1(INTASSIGN1); | ||
520 | |||
521 | switch (pin) { | ||
522 | case 0: | ||
523 | intassign0 &= ~INTASSIGN_MASK; | ||
524 | intassign0 |= (uint16_t)assign; | ||
525 | break; | ||
526 | case 1: | ||
527 | intassign0 &= ~(INTASSIGN_MASK << 3); | ||
528 | intassign0 |= (uint16_t)assign << 3; | ||
529 | break; | ||
530 | case 2: | ||
531 | intassign0 &= ~(INTASSIGN_MASK << 6); | ||
532 | intassign0 |= (uint16_t)assign << 6; | ||
533 | break; | ||
534 | case 3: | ||
535 | intassign0 &= ~(INTASSIGN_MASK << 9); | ||
536 | intassign0 |= (uint16_t)assign << 9; | ||
537 | break; | ||
538 | case 8: | ||
539 | intassign0 &= ~(INTASSIGN_MASK << 12); | ||
540 | intassign0 |= (uint16_t)assign << 12; | ||
541 | break; | ||
542 | case 9: | ||
543 | intassign1 &= ~INTASSIGN_MASK; | ||
544 | intassign1 |= (uint16_t)assign; | ||
545 | break; | ||
546 | case 11: | ||
547 | intassign1 &= ~(INTASSIGN_MASK << 6); | ||
548 | intassign1 |= (uint16_t)assign << 6; | ||
549 | break; | ||
550 | case 12: | ||
551 | intassign1 &= ~(INTASSIGN_MASK << 9); | ||
552 | intassign1 |= (uint16_t)assign << 9; | ||
553 | break; | ||
554 | default: | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | sysint1_assign[pin] = assign; | ||
559 | write_icu1(intassign0, INTASSIGN0); | ||
560 | write_icu1(intassign1, INTASSIGN1); | ||
561 | |||
562 | spin_unlock_irq(&desc->lock); | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) | ||
568 | { | ||
569 | irq_desc_t *desc = irq_desc + irq; | ||
570 | uint16_t intassign2, intassign3; | ||
571 | unsigned int pin; | ||
572 | |||
573 | pin = SYSINT2_IRQ_TO_PIN(irq); | ||
574 | |||
575 | spin_lock_irq(&desc->lock); | ||
576 | |||
577 | intassign2 = read_icu1(INTASSIGN2); | ||
578 | intassign3 = read_icu1(INTASSIGN3); | ||
579 | |||
580 | switch (pin) { | ||
581 | case 0: | ||
582 | intassign2 &= ~INTASSIGN_MASK; | ||
583 | intassign2 |= (uint16_t)assign; | ||
584 | break; | ||
585 | case 1: | ||
586 | intassign2 &= ~(INTASSIGN_MASK << 3); | ||
587 | intassign2 |= (uint16_t)assign << 3; | ||
588 | break; | ||
589 | case 3: | ||
590 | intassign2 &= ~(INTASSIGN_MASK << 6); | ||
591 | intassign2 |= (uint16_t)assign << 6; | ||
592 | break; | ||
593 | case 4: | ||
594 | intassign2 &= ~(INTASSIGN_MASK << 9); | ||
595 | intassign2 |= (uint16_t)assign << 9; | ||
596 | break; | ||
597 | case 5: | ||
598 | intassign2 &= ~(INTASSIGN_MASK << 12); | ||
599 | intassign2 |= (uint16_t)assign << 12; | ||
600 | break; | ||
601 | case 6: | ||
602 | intassign3 &= ~INTASSIGN_MASK; | ||
603 | intassign3 |= (uint16_t)assign; | ||
604 | break; | ||
605 | case 7: | ||
606 | intassign3 &= ~(INTASSIGN_MASK << 3); | ||
607 | intassign3 |= (uint16_t)assign << 3; | ||
608 | break; | ||
609 | case 8: | ||
610 | intassign3 &= ~(INTASSIGN_MASK << 6); | ||
611 | intassign3 |= (uint16_t)assign << 6; | ||
612 | break; | ||
613 | case 9: | ||
614 | intassign3 &= ~(INTASSIGN_MASK << 9); | ||
615 | intassign3 |= (uint16_t)assign << 9; | ||
616 | break; | ||
617 | case 10: | ||
618 | intassign3 &= ~(INTASSIGN_MASK << 12); | ||
619 | intassign3 |= (uint16_t)assign << 12; | ||
620 | break; | ||
621 | default: | ||
622 | return -EINVAL; | ||
623 | } | ||
624 | |||
625 | sysint2_assign[pin] = assign; | ||
626 | write_icu1(intassign2, INTASSIGN2); | ||
627 | write_icu1(intassign3, INTASSIGN3); | ||
628 | |||
629 | spin_unlock_irq(&desc->lock); | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) | ||
635 | { | ||
636 | int retval = -EINVAL; | ||
637 | |||
638 | if (current_cpu_data.cputype != CPU_VR4133) | ||
639 | return -EINVAL; | ||
640 | |||
641 | if (intassign > INTASSIGN_MAX) | ||
642 | return -EINVAL; | ||
643 | |||
644 | if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST) | ||
645 | retval = set_sysint1_assign(irq, intassign); | ||
646 | else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST) | ||
647 | retval = set_sysint2_assign(irq, intassign); | ||
648 | |||
649 | return retval; | ||
650 | } | ||
651 | |||
652 | EXPORT_SYMBOL(vr41xx_set_intassign); | ||
653 | |||
654 | /*=======================================================================*/ | ||
655 | |||
656 | asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs) | ||
657 | { | ||
658 | uint16_t pend1, pend2; | ||
659 | uint16_t mask1, mask2; | ||
660 | int i; | ||
661 | |||
662 | pend1 = read_icu1(SYSINT1REG); | ||
663 | mask1 = read_icu1(MSYSINT1REG); | ||
664 | |||
665 | pend2 = read_icu2(SYSINT2REG); | ||
666 | mask2 = read_icu2(MSYSINT2REG); | ||
667 | |||
668 | mask1 &= pend1; | ||
669 | mask2 &= pend2; | ||
670 | |||
671 | if (mask1) { | ||
672 | for (i = 0; i < 16; i++) { | ||
673 | if (intnum == sysint1_assign[i] && | ||
674 | (mask1 & ((uint16_t)1 << i))) { | ||
675 | if (i == 8) | ||
676 | giuint_irq_dispatch(regs); | ||
677 | else | ||
678 | do_IRQ(SYSINT1_IRQ(i), regs); | ||
679 | return; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | |||
684 | if (mask2) { | ||
685 | for (i = 0; i < 16; i++) { | ||
686 | if (intnum == sysint2_assign[i] && | ||
687 | (mask2 & ((uint16_t)1 << i))) { | ||
688 | do_IRQ(SYSINT2_IRQ(i), regs); | ||
689 | return; | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | |||
694 | printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); | ||
695 | |||
696 | atomic_inc(&irq_err_count); | ||
697 | } | ||
698 | |||
699 | /*=======================================================================*/ | ||
700 | |||
701 | static int __init vr41xx_icu_init(void) | ||
702 | { | ||
703 | switch (current_cpu_data.cputype) { | ||
704 | case CPU_VR4111: | ||
705 | case CPU_VR4121: | ||
706 | icu1_base = SYSINT1REG_TYPE1; | ||
707 | icu2_base = SYSINT2REG_TYPE1; | ||
708 | break; | ||
709 | case CPU_VR4122: | ||
710 | case CPU_VR4131: | ||
711 | case CPU_VR4133: | ||
712 | icu1_base = SYSINT1REG_TYPE2; | ||
713 | icu2_base = SYSINT2REG_TYPE2; | ||
714 | break; | ||
715 | default: | ||
716 | printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n"); | ||
717 | return -EINVAL; | ||
718 | } | ||
719 | |||
720 | write_icu1(0, MSYSINT1REG); | ||
721 | write_icu1(0xffff, MGIUINTLREG); | ||
722 | |||
723 | write_icu2(0, MSYSINT2REG); | ||
724 | write_icu2(0xffff, MGIUINTHREG); | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | early_initcall(vr41xx_icu_init); | ||
730 | |||
731 | /*=======================================================================*/ | ||
732 | |||
733 | static inline void init_vr41xx_icu_irq(void) | ||
734 | { | ||
735 | int i; | ||
736 | |||
737 | for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++) | ||
738 | irq_desc[i].handler = &sysint1_irq_type; | ||
739 | |||
740 | for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++) | ||
741 | irq_desc[i].handler = &sysint2_irq_type; | ||
742 | |||
743 | setup_irq(INT0_CASCADE_IRQ, &icu_cascade); | ||
744 | setup_irq(INT1_CASCADE_IRQ, &icu_cascade); | ||
745 | setup_irq(INT2_CASCADE_IRQ, &icu_cascade); | ||
746 | setup_irq(INT3_CASCADE_IRQ, &icu_cascade); | ||
747 | setup_irq(INT4_CASCADE_IRQ, &icu_cascade); | ||
748 | } | ||
749 | |||
750 | void __init arch_init_irq(void) | ||
751 | { | ||
752 | mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); | ||
753 | init_vr41xx_icu_irq(); | ||
754 | init_vr41xx_giuint_irq(); | ||
755 | |||
756 | set_except_vector(0, vr41xx_handle_interrupt); | ||
757 | } | ||