ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / vr41xx / common / icu.c
1 /*
2  * FILE NAME
3  *      arch/mips/vr41xx/common/icu.c
4  *
5  * BRIEF MODULE DESCRIPTION
6  *      Interrupt Control Unit routines for the NEC VR4100 series.
7  *
8  * Author: Yoichi Yuasa
9  *         yyuasa@mvista.com or source@mvista.com
10  *
11  * Copyright 2001,2002 MontaVista Software Inc.
12  *
13  *  This program is free software; you can redistribute it and/or modify it
14  *  under the terms of the GNU General Public License as published by the
15  *  Free Software Foundation; either version 2 of the License, or (at your
16  *  option) any later version.
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU General Public License along
30  *  with this program; if not, write to the Free Software Foundation, Inc.,
31  *  675 Mass Ave, Cambridge, MA 02139, USA.
32  */
33 /*
34  * Changes:
35  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
36  *  - New creation, NEC VR4122 and VR4131 are supported.
37  *  - Added support for NEC VR4111 and VR4121.
38  *
39  *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
40  *  - Coped with INTASSIGN of NEC VR4133.
41  */
42 #include <linux/errno.h>
43 #include <linux/init.h>
44 #include <linux/interrupt.h>
45 #include <linux/irq.h>
46 #include <linux/smp.h>
47 #include <linux/types.h>
48
49 #include <asm/cpu.h>
50 #include <asm/io.h>
51 #include <asm/irq.h>
52 #include <asm/irq_cpu.h>
53 #include <asm/vr41xx/vr41xx.h>
54
55 extern asmlinkage void vr41xx_handle_interrupt(void);
56
57 extern void vr41xx_giuint_init(void);
58 extern void vr41xx_enable_giuint(int pin);
59 extern void vr41xx_disable_giuint(int pin);
60 extern void vr41xx_clear_giuint(int pin);
61 extern unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs);
62
63 static uint32_t icu1_base;
64 static uint32_t icu2_base;
65
66 static unsigned char sysint1_assign[16] = {
67         0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
68 static unsigned char sysint2_assign[16] = {
69         2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
70
71 #define SYSINT1REG_TYPE1        KSEG1ADDR(0x0b000080)
72 #define SYSINT2REG_TYPE1        KSEG1ADDR(0x0b000200)
73
74 #define SYSINT1REG_TYPE2        KSEG1ADDR(0x0f000080)
75 #define SYSINT2REG_TYPE2        KSEG1ADDR(0x0f0000a0)
76
77 #define SYSINT1REG      0x00
78 #define INTASSIGN0      0x04
79 #define INTASSIGN1      0x06
80 #define GIUINTLREG      0x08
81 #define MSYSINT1REG     0x0c
82 #define MGIUINTLREG     0x14
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 MSYSINT2REG     0x06
91 #define MGIUINTHREG     0x08
92
93 #define SYSINT1_IRQ_TO_PIN(x)   ((x) - SYSINT1_IRQ_BASE)        /* Pin 0-15 */
94 #define SYSINT2_IRQ_TO_PIN(x)   ((x) - SYSINT2_IRQ_BASE)        /* Pin 0-15 */
95
96 #define read_icu1(offset)       readw(icu1_base + (offset))
97 #define write_icu1(val, offset) writew((val), icu1_base + (offset))
98
99 #define read_icu2(offset)       readw(icu2_base + (offset))
100 #define write_icu2(val, offset) writew((val), icu2_base + (offset))
101
102 #define INTASSIGN_MAX   4
103 #define INTASSIGN_MASK  0x0007
104
105 static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
106 {
107         uint16_t res;
108
109         res = read_icu1(offset);
110         res |= set;
111         write_icu1(res, offset);
112
113         return res;
114 }
115
116 static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
117 {
118         uint16_t res;
119
120         res = read_icu1(offset);
121         res &= ~clear;
122         write_icu1(res, offset);
123
124         return res;
125 }
126
127 static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
128 {
129         uint16_t res;
130
131         res = read_icu2(offset);
132         res |= set;
133         write_icu2(res, offset);
134
135         return res;
136 }
137
138 static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
139 {
140         uint16_t res;
141
142         res = read_icu2(offset);
143         res &= ~clear;
144         write_icu2(res, offset);
145
146         return res;
147 }
148
149 /*=======================================================================*/
150
151 static void enable_sysint1_irq(unsigned int irq)
152 {
153         set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
154 }
155
156 static void disable_sysint1_irq(unsigned int irq)
157 {
158         clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
159 }
160
161 static unsigned int startup_sysint1_irq(unsigned int irq)
162 {
163         set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
164
165         return 0; /* never anything pending */
166 }
167
168 #define shutdown_sysint1_irq    disable_sysint1_irq
169 #define ack_sysint1_irq         disable_sysint1_irq
170
171 static void end_sysint1_irq(unsigned int irq)
172 {
173         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
174                 set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
175 }
176
177 static struct hw_interrupt_type sysint1_irq_type = {
178         .typename       = "SYSINT1",
179         .startup        = startup_sysint1_irq,
180         .shutdown       = shutdown_sysint1_irq,
181         .enable         = enable_sysint1_irq,
182         .disable        = disable_sysint1_irq,
183         .ack            = ack_sysint1_irq,
184         .end            = end_sysint1_irq,
185 };
186
187 /*=======================================================================*/
188
189 static void enable_sysint2_irq(unsigned int irq)
190 {
191         set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
192 }
193
194 static void disable_sysint2_irq(unsigned int irq)
195 {
196         clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
197 }
198
199 static unsigned int startup_sysint2_irq(unsigned int irq)
200 {
201         set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
202
203         return 0; /* never anything pending */
204 }
205
206 #define shutdown_sysint2_irq    disable_sysint2_irq
207 #define ack_sysint2_irq         disable_sysint2_irq
208
209 static void end_sysint2_irq(unsigned int irq)
210 {
211         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
212                 set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
213 }
214
215 static struct hw_interrupt_type sysint2_irq_type = {
216         .typename       = "SYSINT2",
217         .startup        = startup_sysint2_irq,
218         .shutdown       = shutdown_sysint2_irq,
219         .enable         = enable_sysint2_irq,
220         .disable        = disable_sysint2_irq,
221         .ack            = ack_sysint2_irq,
222         .end            = end_sysint2_irq,
223 };
224
225 /*=======================================================================*/
226
227 static void enable_giuint_irq(unsigned int irq)
228 {
229         int pin;
230
231         pin = GIU_IRQ_TO_PIN(irq);
232         if (pin < 16)
233                 set_icu1(MGIUINTLREG, (uint16_t)1 << pin);
234         else
235                 set_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
236         vr41xx_enable_giuint(pin);
237 }
238
239 static void disable_giuint_irq(unsigned int irq)
240 {
241         int pin;
242
243         pin = GIU_IRQ_TO_PIN(irq);
244         vr41xx_disable_giuint(pin);
245         if (pin < 16)
246                 clear_icu1(MGIUINTLREG, (uint16_t)1 << pin);
247         else
248                 clear_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
249 }
250
251 static unsigned int startup_giuint_irq(unsigned int irq)
252 {
253         vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
254
255         enable_giuint_irq(irq);
256
257         return 0; /* never anything pending */
258 }
259
260 #define shutdown_giuint_irq     disable_giuint_irq
261
262 static void ack_giuint_irq(unsigned int irq)
263 {
264         disable_giuint_irq(irq);
265
266         vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
267 }
268
269 static void end_giuint_irq(unsigned int irq)
270 {
271         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
272                 enable_giuint_irq(irq);
273 }
274
275 static struct hw_interrupt_type giuint_irq_type = {
276         .typename       = "GIUINT",
277         .startup        = startup_giuint_irq,
278         .shutdown       = shutdown_giuint_irq,
279         .enable         = enable_giuint_irq,
280         .disable        = disable_giuint_irq,
281         .ack            = ack_giuint_irq,
282         .end            = end_giuint_irq,
283 };
284
285 /*=======================================================================*/
286
287 static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
288
289 static void __init vr41xx_icu_init(void)
290 {
291         int i;
292
293         switch (current_cpu_data.cputype) {
294         case CPU_VR4111:
295         case CPU_VR4121:
296                 icu1_base = SYSINT1REG_TYPE1;
297                 icu2_base = SYSINT2REG_TYPE1;
298                 break;
299         case CPU_VR4122:
300         case CPU_VR4131:
301         case CPU_VR4133:
302                 icu1_base = SYSINT1REG_TYPE2;
303                 icu2_base = SYSINT2REG_TYPE2;
304                 break;
305         default:
306                 panic("Unexpected CPU of NEC VR4100 series");
307                 break;
308         }
309
310         write_icu1(0, MSYSINT1REG);
311         write_icu1(0, MGIUINTLREG);
312
313         write_icu2(0, MSYSINT2REG);
314         write_icu2(0, MGIUINTHREG);
315
316         for (i = SYSINT1_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
317                 if (i >= SYSINT1_IRQ_BASE && i <= SYSINT1_IRQ_LAST)
318                         irq_desc[i].handler = &sysint1_irq_type;
319                 else if (i >= SYSINT2_IRQ_BASE && i <= SYSINT2_IRQ_LAST)
320                         irq_desc[i].handler = &sysint2_irq_type;
321                 else if (i >= GIU_IRQ_BASE && i <= GIU_IRQ_LAST)
322                         irq_desc[i].handler = &giuint_irq_type;
323         }
324
325         setup_irq(INT0_CASCADE_IRQ, &icu_cascade);
326         setup_irq(INT1_CASCADE_IRQ, &icu_cascade);
327         setup_irq(INT2_CASCADE_IRQ, &icu_cascade);
328         setup_irq(INT3_CASCADE_IRQ, &icu_cascade);
329         setup_irq(INT4_CASCADE_IRQ, &icu_cascade);
330 }
331
332 void __init init_IRQ(void)
333 {
334         memset(irq_desc, 0, sizeof(irq_desc));
335
336         init_generic_irq();
337         mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
338         vr41xx_icu_init();
339
340         vr41xx_giuint_init();
341
342         set_except_vector(0, vr41xx_handle_interrupt);
343 }
344
345 /*=======================================================================*/
346
347 static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
348 {
349         irq_desc_t *desc = irq_desc + irq;
350         uint16_t intassign0, intassign1;
351         unsigned int pin;
352
353         pin = SYSINT1_IRQ_TO_PIN(irq);
354
355         spin_lock_irq(&desc->lock);
356
357         intassign0 = read_icu1(INTASSIGN0);
358         intassign1 = read_icu1(INTASSIGN1);
359
360         switch (pin) {
361         case 0:
362                 intassign0 &= ~INTASSIGN_MASK;
363                 intassign0 |= (uint16_t)assign;
364                 break;
365         case 1:
366                 intassign0 &= ~(INTASSIGN_MASK << 3);
367                 intassign0 |= (uint16_t)assign << 3;
368                 break;
369         case 2:
370                 intassign0 &= ~(INTASSIGN_MASK << 6);
371                 intassign0 |= (uint16_t)assign << 6;
372                 break;
373         case 3:
374                 intassign0 &= ~(INTASSIGN_MASK << 9);
375                 intassign0 |= (uint16_t)assign << 9;
376                 break;
377         case 8:
378                 intassign0 &= ~(INTASSIGN_MASK << 12);
379                 intassign0 |= (uint16_t)assign << 12;
380                 break;
381         case 9:
382                 intassign1 &= ~INTASSIGN_MASK;
383                 intassign1 |= (uint16_t)assign;
384                 break;
385         case 11:
386                 intassign1 &= ~(INTASSIGN_MASK << 6);
387                 intassign1 |= (uint16_t)assign << 6;
388                 break;
389         case 12:
390                 intassign1 &= ~(INTASSIGN_MASK << 9);
391                 intassign1 |= (uint16_t)assign << 9;
392                 break;
393         default:
394                 return -EINVAL;
395         }
396
397         sysint1_assign[pin] = assign;
398         write_icu1(intassign0, INTASSIGN0);
399         write_icu1(intassign1, INTASSIGN1);
400
401         spin_unlock_irq(&desc->lock);
402
403         return 0;
404 }
405
406 static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
407 {
408         irq_desc_t *desc = irq_desc + irq;
409         uint16_t intassign2, intassign3;
410         unsigned int pin;
411
412         pin = SYSINT2_IRQ_TO_PIN(irq);
413
414         spin_lock_irq(&desc->lock);
415
416         intassign2 = read_icu1(INTASSIGN2);
417         intassign3 = read_icu1(INTASSIGN3);
418
419         switch (pin) {
420         case 0:
421                 intassign2 &= ~INTASSIGN_MASK;
422                 intassign2 |= (uint16_t)assign;
423                 break;
424         case 1:
425                 intassign2 &= ~(INTASSIGN_MASK << 3);
426                 intassign2 |= (uint16_t)assign << 3;
427                 break;
428         case 3:
429                 intassign2 &= ~(INTASSIGN_MASK << 6);
430                 intassign2 |= (uint16_t)assign << 6;
431                 break;
432         case 4:
433                 intassign2 &= ~(INTASSIGN_MASK << 9);
434                 intassign2 |= (uint16_t)assign << 9;
435                 break;
436         case 5:
437                 intassign2 &= ~(INTASSIGN_MASK << 12);
438                 intassign2 |= (uint16_t)assign << 12;
439                 break;
440         case 6:
441                 intassign3 &= ~INTASSIGN_MASK;
442                 intassign3 |= (uint16_t)assign;
443                 break;
444         case 7:
445                 intassign3 &= ~(INTASSIGN_MASK << 3);
446                 intassign3 |= (uint16_t)assign << 3;
447                 break;
448         case 8:
449                 intassign3 &= ~(INTASSIGN_MASK << 6);
450                 intassign3 |= (uint16_t)assign << 6;
451                 break;
452         case 9:
453                 intassign3 &= ~(INTASSIGN_MASK << 9);
454                 intassign3 |= (uint16_t)assign << 9;
455                 break;
456         case 10:
457                 intassign3 &= ~(INTASSIGN_MASK << 12);
458                 intassign3 |= (uint16_t)assign << 12;
459                 break;
460         default:
461                 return -EINVAL;
462         }
463
464         sysint2_assign[pin] = assign;
465         write_icu1(intassign2, INTASSIGN2);
466         write_icu1(intassign3, INTASSIGN3);
467
468         spin_unlock_irq(&desc->lock);
469
470         return 0;
471 }
472
473 int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
474 {
475         int retval = -EINVAL;
476
477         if (current_cpu_data.cputype != CPU_VR4133)
478                 return -EINVAL;
479
480         if (intassign > INTASSIGN_MAX)
481                 return -EINVAL;
482
483         if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST)
484                 retval = set_sysint1_assign(irq, intassign);
485         else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST)
486                 retval = set_sysint2_assign(irq, intassign);
487
488         return retval;
489 }
490
491 /*=======================================================================*/
492
493 static inline void giuint_irq_dispatch(uint16_t pendl, uint16_t pendh,
494                                        struct pt_regs *regs)
495 {
496         int i;
497
498         if (pendl) {
499                 for (i = 0; i < 16; i++) {
500                         if (pendl & ((uint16_t)1 << i)) {
501                                 giuint_do_IRQ(i, regs);
502                                 return;
503                         }
504                 }
505         } else {
506                 for (i = 0; i < 16; i++) {
507                         if (pendh & ((uint16_t)1 << i)) {
508                                 giuint_do_IRQ(i + 16, regs);
509                                 return;
510                         }
511                 }
512         }
513 }
514
515 asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
516 {
517         uint16_t pend1, pend2, pendl, pendh;
518         uint16_t mask1, mask2, maskl, maskh;
519         int i;
520
521         pend1 = read_icu1(SYSINT1REG);
522         mask1 = read_icu1(MSYSINT1REG);
523
524         pend2 = read_icu2(SYSINT2REG);
525         mask2 = read_icu2(MSYSINT2REG);
526
527         pendl = read_icu1(GIUINTLREG);
528         maskl = read_icu1(MGIUINTLREG);
529
530         pendh = read_icu2(GIUINTHREG);
531         maskh = read_icu2(MGIUINTHREG);
532
533         mask1 &= pend1;
534         mask2 &= pend2;
535         maskl &= pendl;
536         maskh &= pendh;
537
538         if (mask1) {
539                 for (i = 0; i < 16; i++) {
540                         if (intnum == sysint1_assign[i] &&
541                             (mask1 & ((uint16_t)1 << i))) {
542                                 if (i == 8 && (maskl | maskh)) {
543                                         giuint_irq_dispatch(maskl, maskh, regs);
544                                         return;
545                                 } else {
546                                         do_IRQ(SYSINT1_IRQ(i), regs);
547                                         return;
548                                 }
549                         }
550                 }
551         }
552
553         if (mask2) {
554                 for (i = 0; i < 16; i++) {
555                         if (intnum == sysint2_assign[i] &&
556                             (mask2 & ((uint16_t)1 << i))) {
557                                 do_IRQ(SYSINT2_IRQ(i), regs);
558                                 return;
559                         }
560                 }
561         }
562
563         printk(KERN_ERR "spurious interrupt: %04x,%04x,%04x,%04x\n", pend1, pend2, pendl, pendh);
564         atomic_inc(&irq_err_count);
565 }