Pull bugzilla-5737 into release branch
[linux-2.6] / arch / mips / jazz / irq.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992 Linus Torvalds
7  * Copyright (C) 1994 - 2001, 2003 Ralf Baechle
8  */
9 #include <linux/init.h>
10 #include <linux/interrupt.h>
11 #include <linux/kernel.h>
12 #include <linux/spinlock.h>
13
14 #include <asm/i8259.h>
15 #include <asm/io.h>
16 #include <asm/jazz.h>
17
18 static DEFINE_SPINLOCK(r4030_lock);
19
20 static void enable_r4030_irq(unsigned int irq)
21 {
22         unsigned int mask = 1 << (irq - JAZZ_PARALLEL_IRQ);
23         unsigned long flags;
24
25         spin_lock_irqsave(&r4030_lock, flags);
26         mask |= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE);
27         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask);
28         spin_unlock_irqrestore(&r4030_lock, flags);
29 }
30
31 static unsigned int startup_r4030_irq(unsigned int irq)
32 {
33         enable_r4030_irq(irq);
34         return 0; /* never anything pending */
35 }
36
37 #define shutdown_r4030_irq      disable_r4030_irq
38
39 void disable_r4030_irq(unsigned int irq)
40 {
41         unsigned int mask = ~(1 << (irq - JAZZ_PARALLEL_IRQ));
42         unsigned long flags;
43
44         spin_lock_irqsave(&r4030_lock, flags);
45         mask &= r4030_read_reg16(JAZZ_IO_IRQ_ENABLE);
46         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, mask);
47         spin_unlock_irqrestore(&r4030_lock, flags);
48 }
49
50 #define mask_and_ack_r4030_irq disable_r4030_irq
51
52 static void end_r4030_irq(unsigned int irq)
53 {
54         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
55                 enable_r4030_irq(irq);
56 }
57
58 static struct hw_interrupt_type r4030_irq_type = {
59         .typename = "R4030",
60         .startup = startup_r4030_irq,
61         .shutdown = shutdown_r4030_irq,
62         .enable = enable_r4030_irq,
63         .disable = disable_r4030_irq,
64         .ack = mask_and_ack_r4030_irq,
65         .end = end_r4030_irq,
66 };
67
68 void __init init_r4030_ints(void)
69 {
70         int i;
71
72         for (i = JAZZ_PARALLEL_IRQ; i <= JAZZ_TIMER_IRQ; i++) {
73                 irq_desc[i].status     = IRQ_DISABLED;
74                 irq_desc[i].action     = 0;
75                 irq_desc[i].depth      = 1;
76                 irq_desc[i].handler    = &r4030_irq_type;
77         }
78
79         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 0);
80         r4030_read_reg16(JAZZ_IO_IRQ_SOURCE);           /* clear pending IRQs */
81         r4030_read_reg32(JAZZ_R4030_INVAL_ADDR);        /* clear error bits */
82 }
83
84 /*
85  * On systems with i8259-style interrupt controllers we assume for
86  * driver compatibility reasons interrupts 0 - 15 to be the i8259
87  * interrupts even if the hardware uses a different interrupt numbering.
88  */
89 void __init arch_init_irq(void)
90 {
91         init_i8259_irqs();                      /* Integrated i8259  */
92         init_r4030_ints();
93
94         change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
95 }
96
97 static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
98 {
99         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
100                           r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
101         do_IRQ(irq, regs);
102         r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
103                           r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
104 }
105
106 static void ll_local_dev(struct pt_regs *regs)
107 {
108         switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
109         case 0:
110                 panic("Unimplemented loc_no_irq handler");
111                 break;
112         case 4:
113                 loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
114                 break;
115         case 8:
116                 loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
117                 break;
118         case 12:
119                 panic("Unimplemented loc_sound handler");
120                 break;
121         case 16:
122                 panic("Unimplemented loc_video handler");
123                 break;
124         case 20:
125                 loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
126                 break;
127         case 24:
128                 loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
129                 break;
130         case 28:
131                 loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
132                 break;
133         case 32:
134                 loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
135                 break;
136         case 36:
137                 loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
138                 break;
139         case 40:
140                 loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
141                 break;
142         }
143 }
144
145 asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
146 {
147         unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
148
149         if (pending & IE_IRQ5)
150                 write_c0_compare(0);
151         else if (pending & IE_IRQ4) {
152                 r4030_read_reg32(JAZZ_TIMER_REGISTER);
153                 do_IRQ(JAZZ_TIMER_IRQ, regs);
154         } else if (pending & IE_IRQ3)
155                 panic("Unimplemented ISA NMI handler");
156         else if (pending & IE_IRQ2)
157                 do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
158         else if (pending & IE_IRQ1) {
159                 ll_local_dev(regs);
160         } else if (unlikely(pending & IE_IRQ0))
161                 panic("Unimplemented local_dma handler");
162         else if (pending & IE_SW1) {
163                 clear_c0_cause(IE_SW1);
164                 panic("Unimplemented sw1 handler");
165         } else if (pending & IE_SW0) {
166                 clear_c0_cause(IE_SW0);
167                 panic("Unimplemented sw0 handler");
168         }
169 }