patch-2_6_7-vs1_9_1_12
[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/errno.h>
32 #include <linux/init.h>
33 #include <linux/interrupt.h>
34 #include <linux/irq.h>
35 #include <linux/smp.h>
36 #include <linux/types.h>
37
38 #include <asm/cpu.h>
39 #include <asm/io.h>
40 #include <asm/irq.h>
41 #include <asm/irq_cpu.h>
42 #include <asm/vr41xx/vr41xx.h>
43
44 extern asmlinkage void vr41xx_handle_interrupt(void);
45
46 extern void vr41xx_giuint_init(void);
47 extern void vr41xx_enable_giuint(int pin);
48 extern void vr41xx_disable_giuint(int pin);
49 extern void vr41xx_clear_giuint(int pin);
50 extern unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs);
51
52 static uint32_t icu1_base;
53 static uint32_t icu2_base;
54
55 static unsigned char sysint1_assign[16] = {
56         0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
57 static unsigned char sysint2_assign[16] = {
58         2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
59
60 #define SYSINT1REG_TYPE1        KSEG1ADDR(0x0b000080)
61 #define SYSINT2REG_TYPE1        KSEG1ADDR(0x0b000200)
62
63 #define SYSINT1REG_TYPE2        KSEG1ADDR(0x0f000080)
64 #define SYSINT2REG_TYPE2        KSEG1ADDR(0x0f0000a0)
65
66 #define SYSINT1REG      0x00
67 #define INTASSIGN0      0x04
68 #define INTASSIGN1      0x06
69 #define GIUINTLREG      0x08
70 #define MSYSINT1REG     0x0c
71 #define MGIUINTLREG     0x14
72 #define NMIREG          0x18
73 #define SOFTREG         0x1a
74 #define INTASSIGN2      0x1c
75 #define INTASSIGN3      0x1e
76
77 #define SYSINT2REG      0x00
78 #define GIUINTHREG      0x02
79 #define MSYSINT2REG     0x06
80 #define MGIUINTHREG     0x08
81
82 #define MDSIUINTREG     KSEG1ADDR(0x0f000096)
83  #define INTDSIU        0x0800
84
85 #define SYSINT1_IRQ_TO_PIN(x)   ((x) - SYSINT1_IRQ_BASE)        /* Pin 0-15 */
86 #define SYSINT2_IRQ_TO_PIN(x)   ((x) - SYSINT2_IRQ_BASE)        /* Pin 0-15 */
87
88 #define read_icu1(offset)       readw(icu1_base + (offset))
89 #define write_icu1(val, offset) writew((val), icu1_base + (offset))
90
91 #define read_icu2(offset)       readw(icu2_base + (offset))
92 #define write_icu2(val, offset) writew((val), icu2_base + (offset))
93
94 #define INTASSIGN_MAX   4
95 #define INTASSIGN_MASK  0x0007
96
97 static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
98 {
99         uint16_t res;
100
101         res = read_icu1(offset);
102         res |= set;
103         write_icu1(res, offset);
104
105         return res;
106 }
107
108 static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
109 {
110         uint16_t res;
111
112         res = read_icu1(offset);
113         res &= ~clear;
114         write_icu1(res, offset);
115
116         return res;
117 }
118
119 static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
120 {
121         uint16_t res;
122
123         res = read_icu2(offset);
124         res |= set;
125         write_icu2(res, offset);
126
127         return res;
128 }
129
130 static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
131 {
132         uint16_t res;
133
134         res = read_icu2(offset);
135         res &= ~clear;
136         write_icu2(res, offset);
137
138         return res;
139 }
140
141 /*=======================================================================*/
142
143 void vr41xx_enable_dsiuint(void)
144 {
145         writew(INTDSIU, MDSIUINTREG);
146 }
147
148 void vr41xx_disable_dsiuint(void)
149 {
150         writew(0, MDSIUINTREG);
151 }
152
153 /*=======================================================================*/
154
155 static void enable_sysint1_irq(unsigned int irq)
156 {
157         set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
158 }
159
160 static void disable_sysint1_irq(unsigned int irq)
161 {
162         clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
163 }
164
165 static unsigned int startup_sysint1_irq(unsigned int irq)
166 {
167         set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
168
169         return 0; /* never anything pending */
170 }
171
172 #define shutdown_sysint1_irq    disable_sysint1_irq
173 #define ack_sysint1_irq         disable_sysint1_irq
174
175 static void end_sysint1_irq(unsigned int irq)
176 {
177         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
178                 set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
179 }
180
181 static struct hw_interrupt_type sysint1_irq_type = {
182         .typename       = "SYSINT1",
183         .startup        = startup_sysint1_irq,
184         .shutdown       = shutdown_sysint1_irq,
185         .enable         = enable_sysint1_irq,
186         .disable        = disable_sysint1_irq,
187         .ack            = ack_sysint1_irq,
188         .end            = end_sysint1_irq,
189 };
190
191 /*=======================================================================*/
192
193 static void enable_sysint2_irq(unsigned int irq)
194 {
195         set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
196 }
197
198 static void disable_sysint2_irq(unsigned int irq)
199 {
200         clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
201 }
202
203 static unsigned int startup_sysint2_irq(unsigned int irq)
204 {
205         set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
206
207         return 0; /* never anything pending */
208 }
209
210 #define shutdown_sysint2_irq    disable_sysint2_irq
211 #define ack_sysint2_irq         disable_sysint2_irq
212
213 static void end_sysint2_irq(unsigned int irq)
214 {
215         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
216                 set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
217 }
218
219 static struct hw_interrupt_type sysint2_irq_type = {
220         .typename       = "SYSINT2",
221         .startup        = startup_sysint2_irq,
222         .shutdown       = shutdown_sysint2_irq,
223         .enable         = enable_sysint2_irq,
224         .disable        = disable_sysint2_irq,
225         .ack            = ack_sysint2_irq,
226         .end            = end_sysint2_irq,
227 };
228
229 /*=======================================================================*/
230
231 static void enable_giuint_irq(unsigned int irq)
232 {
233         int pin;
234
235         pin = GIU_IRQ_TO_PIN(irq);
236         if (pin < 16)
237                 set_icu1(MGIUINTLREG, (uint16_t)1 << pin);
238         else
239                 set_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
240         vr41xx_enable_giuint(pin);
241 }
242
243 static void disable_giuint_irq(unsigned int irq)
244 {
245         int pin;
246
247         pin = GIU_IRQ_TO_PIN(irq);
248         vr41xx_disable_giuint(pin);
249         if (pin < 16)
250                 clear_icu1(MGIUINTLREG, (uint16_t)1 << pin);
251         else
252                 clear_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
253 }
254
255 static unsigned int startup_giuint_irq(unsigned int irq)
256 {
257         vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
258
259         enable_giuint_irq(irq);
260
261         return 0; /* never anything pending */
262 }
263
264 #define shutdown_giuint_irq     disable_giuint_irq
265
266 static void ack_giuint_irq(unsigned int irq)
267 {
268         disable_giuint_irq(irq);
269
270         vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
271 }
272
273 static void end_giuint_irq(unsigned int irq)
274 {
275         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
276                 enable_giuint_irq(irq);
277 }
278
279 static struct hw_interrupt_type giuint_irq_type = {
280         .typename       = "GIUINT",
281         .startup        = startup_giuint_irq,
282         .shutdown       = shutdown_giuint_irq,
283         .enable         = enable_giuint_irq,
284         .disable        = disable_giuint_irq,
285         .ack            = ack_giuint_irq,
286         .end            = end_giuint_irq,
287 };
288
289 /*=======================================================================*/
290
291 static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
292
293 static void __init vr41xx_icu_init(void)
294 {
295         int i;
296
297         switch (current_cpu_data.cputype) {
298         case CPU_VR4111:
299         case CPU_VR4121:
300                 icu1_base = SYSINT1REG_TYPE1;
301                 icu2_base = SYSINT2REG_TYPE1;
302                 break;
303         case CPU_VR4122:
304         case CPU_VR4131:
305         case CPU_VR4133:
306                 icu1_base = SYSINT1REG_TYPE2;
307                 icu2_base = SYSINT2REG_TYPE2;
308                 break;
309         default:
310                 panic("Unexpected CPU of NEC VR4100 series");
311                 break;
312         }
313
314         write_icu1(0, MSYSINT1REG);
315         write_icu1(0, MGIUINTLREG);
316
317         write_icu2(0, MSYSINT2REG);
318         write_icu2(0, MGIUINTHREG);
319
320         for (i = SYSINT1_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
321                 if (i >= SYSINT1_IRQ_BASE && i <= SYSINT1_IRQ_LAST)
322                         irq_desc[i].handler = &sysint1_irq_type;
323                 else if (i >= SYSINT2_IRQ_BASE && i <= SYSINT2_IRQ_LAST)
324                         irq_desc[i].handler = &sysint2_irq_type;
325                 else if (i >= GIU_IRQ_BASE && i <= GIU_IRQ_LAST)
326                         irq_desc[i].handler = &giuint_irq_type;
327         }
328
329         setup_irq(INT0_CASCADE_IRQ, &icu_cascade);
330         setup_irq(INT1_CASCADE_IRQ, &icu_cascade);
331         setup_irq(INT2_CASCADE_IRQ, &icu_cascade);
332         setup_irq(INT3_CASCADE_IRQ, &icu_cascade);
333         setup_irq(INT4_CASCADE_IRQ, &icu_cascade);
334 }
335
336 void __init init_IRQ(void)
337 {
338         memset(irq_desc, 0, sizeof(irq_desc));
339
340         init_generic_irq();
341         mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
342         vr41xx_icu_init();
343
344         vr41xx_giuint_init();
345
346         set_except_vector(0, vr41xx_handle_interrupt);
347 }
348
349 /*=======================================================================*/
350
351 static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
352 {
353         irq_desc_t *desc = irq_desc + irq;
354         uint16_t intassign0, intassign1;
355         unsigned int pin;
356
357         pin = SYSINT1_IRQ_TO_PIN(irq);
358
359         spin_lock_irq(&desc->lock);
360
361         intassign0 = read_icu1(INTASSIGN0);
362         intassign1 = read_icu1(INTASSIGN1);
363
364         switch (pin) {
365         case 0:
366                 intassign0 &= ~INTASSIGN_MASK;
367                 intassign0 |= (uint16_t)assign;
368                 break;
369         case 1:
370                 intassign0 &= ~(INTASSIGN_MASK << 3);
371                 intassign0 |= (uint16_t)assign << 3;
372                 break;
373         case 2:
374                 intassign0 &= ~(INTASSIGN_MASK << 6);
375                 intassign0 |= (uint16_t)assign << 6;
376                 break;
377         case 3:
378                 intassign0 &= ~(INTASSIGN_MASK << 9);
379                 intassign0 |= (uint16_t)assign << 9;
380                 break;
381         case 8:
382                 intassign0 &= ~(INTASSIGN_MASK << 12);
383                 intassign0 |= (uint16_t)assign << 12;
384                 break;
385         case 9:
386                 intassign1 &= ~INTASSIGN_MASK;
387                 intassign1 |= (uint16_t)assign;
388                 break;
389         case 11:
390                 intassign1 &= ~(INTASSIGN_MASK << 6);
391                 intassign1 |= (uint16_t)assign << 6;
392                 break;
393         case 12:
394                 intassign1 &= ~(INTASSIGN_MASK << 9);
395                 intassign1 |= (uint16_t)assign << 9;
396                 break;
397         default:
398                 return -EINVAL;
399         }
400
401         sysint1_assign[pin] = assign;
402         write_icu1(intassign0, INTASSIGN0);
403         write_icu1(intassign1, INTASSIGN1);
404
405         spin_unlock_irq(&desc->lock);
406
407         return 0;
408 }
409
410 static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
411 {
412         irq_desc_t *desc = irq_desc + irq;
413         uint16_t intassign2, intassign3;
414         unsigned int pin;
415
416         pin = SYSINT2_IRQ_TO_PIN(irq);
417
418         spin_lock_irq(&desc->lock);
419
420         intassign2 = read_icu1(INTASSIGN2);
421         intassign3 = read_icu1(INTASSIGN3);
422
423         switch (pin) {
424         case 0:
425                 intassign2 &= ~INTASSIGN_MASK;
426                 intassign2 |= (uint16_t)assign;
427                 break;
428         case 1:
429                 intassign2 &= ~(INTASSIGN_MASK << 3);
430                 intassign2 |= (uint16_t)assign << 3;
431                 break;
432         case 3:
433                 intassign2 &= ~(INTASSIGN_MASK << 6);
434                 intassign2 |= (uint16_t)assign << 6;
435                 break;
436         case 4:
437                 intassign2 &= ~(INTASSIGN_MASK << 9);
438                 intassign2 |= (uint16_t)assign << 9;
439                 break;
440         case 5:
441                 intassign2 &= ~(INTASSIGN_MASK << 12);
442                 intassign2 |= (uint16_t)assign << 12;
443                 break;
444         case 6:
445                 intassign3 &= ~INTASSIGN_MASK;
446                 intassign3 |= (uint16_t)assign;
447                 break;
448         case 7:
449                 intassign3 &= ~(INTASSIGN_MASK << 3);
450                 intassign3 |= (uint16_t)assign << 3;
451                 break;
452         case 8:
453                 intassign3 &= ~(INTASSIGN_MASK << 6);
454                 intassign3 |= (uint16_t)assign << 6;
455                 break;
456         case 9:
457                 intassign3 &= ~(INTASSIGN_MASK << 9);
458                 intassign3 |= (uint16_t)assign << 9;
459                 break;
460         case 10:
461                 intassign3 &= ~(INTASSIGN_MASK << 12);
462                 intassign3 |= (uint16_t)assign << 12;
463                 break;
464         default:
465                 return -EINVAL;
466         }
467
468         sysint2_assign[pin] = assign;
469         write_icu1(intassign2, INTASSIGN2);
470         write_icu1(intassign3, INTASSIGN3);
471
472         spin_unlock_irq(&desc->lock);
473
474         return 0;
475 }
476
477 int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
478 {
479         int retval = -EINVAL;
480
481         if (current_cpu_data.cputype != CPU_VR4133)
482                 return -EINVAL;
483
484         if (intassign > INTASSIGN_MAX)
485                 return -EINVAL;
486
487         if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST)
488                 retval = set_sysint1_assign(irq, intassign);
489         else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST)
490                 retval = set_sysint2_assign(irq, intassign);
491
492         return retval;
493 }
494
495 /*=======================================================================*/
496
497 static inline void giuint_irq_dispatch(uint16_t pendl, uint16_t pendh,
498                                        struct pt_regs *regs)
499 {
500         int i;
501
502         if (pendl) {
503                 for (i = 0; i < 16; i++) {
504                         if (pendl & ((uint16_t)1 << i)) {
505                                 giuint_do_IRQ(i, regs);
506                                 return;
507                         }
508                 }
509         } else {
510                 for (i = 0; i < 16; i++) {
511                         if (pendh & ((uint16_t)1 << i)) {
512                                 giuint_do_IRQ(i + 16, regs);
513                                 return;
514                         }
515                 }
516         }
517 }
518
519 asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
520 {
521         uint16_t pend1, pend2, pendl, pendh;
522         uint16_t mask1, mask2, maskl, maskh;
523         int i;
524
525         pend1 = read_icu1(SYSINT1REG);
526         mask1 = read_icu1(MSYSINT1REG);
527
528         pend2 = read_icu2(SYSINT2REG);
529         mask2 = read_icu2(MSYSINT2REG);
530
531         pendl = read_icu1(GIUINTLREG);
532         maskl = read_icu1(MGIUINTLREG);
533
534         pendh = read_icu2(GIUINTHREG);
535         maskh = read_icu2(MGIUINTHREG);
536
537         mask1 &= pend1;
538         mask2 &= pend2;
539         maskl &= pendl;
540         maskh &= pendh;
541
542         if (mask1) {
543                 for (i = 0; i < 16; i++) {
544                         if (intnum == sysint1_assign[i] &&
545                             (mask1 & ((uint16_t)1 << i))) {
546                                 if (i == 8 && (maskl | maskh)) {
547                                         giuint_irq_dispatch(maskl, maskh, regs);
548                                         return;
549                                 } else {
550                                         do_IRQ(SYSINT1_IRQ(i), regs);
551                                         return;
552                                 }
553                         }
554                 }
555         }
556
557         if (mask2) {
558                 for (i = 0; i < 16; i++) {
559                         if (intnum == sysint2_assign[i] &&
560                             (mask2 & ((uint16_t)1 << i))) {
561                                 do_IRQ(SYSINT2_IRQ(i), regs);
562                                 return;
563                         }
564                 }
565         }
566
567         printk(KERN_ERR "spurious interrupt: %04x,%04x,%04x,%04x\n", pend1, pend2, pendl, pendh);
568         atomic_inc(&irq_err_count);
569 }