vserver 1.9.3
[linux-2.6.git] / arch / mips / vr41xx / common / icu.c
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  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 /*
23  * Changes:
24  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
25  *  - New creation, NEC VR4122 and VR4131 are supported.
26  *  - Added support for NEC VR4111 and VR4121.
27  *
28  *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
29  *  - Coped with INTASSIGN of NEC VR4133.
30  */
31 #include <linux/config.h>
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 init_IRQ(void)
751 {
752         memset(irq_desc, 0, sizeof(irq_desc));
753
754         init_generic_irq();
755         mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
756         init_vr41xx_icu_irq();
757         init_vr41xx_giuint_irq();
758
759         set_except_vector(0, vr41xx_handle_interrupt);
760 }