convert aruba to the new structure
[openwrt/svn-archive/archive.git] / target / linux / aruba-2.6 / files / arch / mips / aruba / irq.c
1 #include <linux/errno.h>
2 #include <linux/init.h>
3 #include <linux/kernel_stat.h>
4 #include <linux/module.h>
5 #include <linux/signal.h>
6 #include <linux/sched.h>
7 #include <linux/types.h>
8 #include <linux/interrupt.h>
9 #include <linux/ioport.h>
10 #include <linux/timex.h>
11 #include <linux/slab.h>
12 #include <linux/random.h>
13 #include <linux/delay.h>
14
15 #include <asm/bitops.h>
16 #include <asm/bootinfo.h>
17 #include <asm/io.h>
18 #include <asm/mipsregs.h>
19 #include <asm/system.h>
20 #include <asm/idt-boards/rc32434/rc32434.h>
21 #include <asm/idt-boards/rc32434/rc32434_gpio.h>
22
23 #include <asm/irq.h>
24
25 extern void aruba_timer_interrupt(struct pt_regs *regs);
26
27 typedef struct {
28 u32 mask;
29 volatile u32 *base_addr;
30 } intr_group_t;
31
32 static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = {
33 {0x00000000, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
34 };
35
36 #define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
37 #define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014)))
38 #define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT())
39
40 static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = {
41 {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
42 {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
43 {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
44 {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
45 {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
46 };
47
48 #define READ_PEND_MUSCAT(base) (*(base))
49 #define READ_MASK_MUSCAT(base) (*(base + 2))
50 #define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
51
52 static inline int group_to_ip(unsigned int group)
53 {
54 switch (mips_machtype) {
55 case MACH_ARUBA_AP70:
56 return group + 2;
57 case MACH_ARUBA_AP65:
58 case MACH_ARUBA_AP60:
59 default:
60 return 6;
61 }
62 }
63
64 static inline void enable_local_irq(unsigned int irq)
65 {
66 clear_c0_cause(0x100 << irq);
67 set_c0_status(0x100 << irq);
68 irq_enable_hazard();
69 }
70
71 static inline void disable_local_irq(unsigned int irq)
72 {
73 clear_c0_status(0x100 << irq);
74 clear_c0_cause(0x100 << irq);
75 irq_disable_hazard();
76 }
77
78 static inline void aruba_irq_enable(unsigned int irq)
79 {
80 unsigned long flags;
81 unsigned int group, intr_bit;
82 volatile unsigned int *addr;
83
84 local_irq_save(flags);
85
86 if (irq < GROUP0_IRQ_BASE) {
87 enable_local_irq(irq);
88 } else {
89 int ip = irq - GROUP0_IRQ_BASE;
90 switch (mips_machtype) {
91 case MACH_ARUBA_AP70:
92 if (irq >= GROUP4_IRQ_BASE)
93 idt_gpio->gpioistat &= ~(1 << (irq - GROUP4_IRQ_BASE));
94
95 // irqs are in groups of 32
96 // ip is set to the remainder
97 group = ip >> 5;
98 ip &= 0x1f;
99
100 // bit -> 0 = unmask
101 intr_bit = 1 << ip;
102 addr = intr_group_muscat[group].base_addr;
103 WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
104 break;
105
106 case MACH_ARUBA_AP65:
107 case MACH_ARUBA_AP60:
108 group = 0;
109
110 // bit -> 1 = unmasked
111 intr_bit = 1 << ip;
112 addr = intr_group_merlot[group].base_addr;
113 WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
114 break;
115 }
116 enable_local_irq(group_to_ip(group));
117 }
118
119 back_to_back_c0_hazard();
120 local_irq_restore(flags);
121 }
122
123 static void aruba_irq_disable(unsigned int irq)
124 {
125 unsigned long flags;
126 unsigned int group, intr_bit, mask;
127 volatile unsigned int *addr;
128
129 local_irq_save(flags);
130
131 if (irq < GROUP0_IRQ_BASE) {
132 disable_local_irq(irq);
133 } else {
134 int ip = irq - GROUP0_IRQ_BASE;
135 switch (mips_machtype) {
136 case MACH_ARUBA_AP70:
137 idt_gpio->gpioistat &= ~(1 << ip);
138
139 // irqs are in groups of 32
140 // ip is set to the remainder
141 group = ip >> 5;
142 ip &= 0x1f;
143
144 // bit -> 1 = mask
145 intr_bit = 1 << ip;
146 addr = intr_group_muscat[group].base_addr;
147
148 mask = READ_MASK_MUSCAT(addr);
149 mask |= intr_bit;
150 WRITE_MASK_MUSCAT(addr, mask);
151
152 if (mask == intr_group_muscat[group].mask) {
153 disable_local_irq(group_to_ip(group));
154 }
155 break;
156
157 case MACH_ARUBA_AP65:
158 case MACH_ARUBA_AP60:
159 group = 0;
160
161 // bit -> 0 = masked
162 intr_bit = 1 << ip;
163 addr = intr_group_merlot[group].base_addr;
164
165 mask = READ_MASK_MERLOT(addr);
166 mask &= ~intr_bit;
167 WRITE_MASK_MERLOT(addr, mask);
168
169 if (mask == intr_group_merlot[group].mask) {
170 disable_local_irq(group_to_ip(group));
171 }
172 break;
173 }
174 }
175
176 back_to_back_c0_hazard();
177 local_irq_restore(flags);
178 }
179
180 static unsigned int aruba_irq_startup(unsigned int irq)
181 {
182 aruba_irq_enable(irq);
183 return 0;
184 }
185
186 #define aruba_irq_shutdown aruba_irq_disable
187
188 static void aruba_irq_ack(unsigned int irq)
189 {
190 aruba_irq_disable(irq);
191 }
192
193 static void aruba_irq_end(unsigned int irq)
194 {
195 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
196 aruba_irq_enable(irq);
197 }
198
199 static struct hw_interrupt_type aruba_irq_type = {
200 .typename = "ARUBA",
201 .startup = aruba_irq_startup,
202 .shutdown = aruba_irq_shutdown,
203 .enable = aruba_irq_enable,
204 .disable = aruba_irq_disable,
205 .ack = aruba_irq_ack,
206 .end = aruba_irq_end,
207 };
208
209 void __init arch_init_irq(void)
210 {
211 int i;
212 printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
213 memset(irq_desc, 0, sizeof(irq_desc));
214
215 for (i = 0; i < RC32434_NR_IRQS; i++) {
216 irq_desc[i].status = IRQ_DISABLED;
217 irq_desc[i].action = NULL;
218 irq_desc[i].depth = 1;
219 irq_desc[i].chip = &aruba_irq_type;
220 spin_lock_init(&irq_desc[i].lock);
221 }
222 }
223
224 /* Main Interrupt dispatcher */
225
226 void plat_irq_dispatch(struct pt_regs *regs)
227 {
228 unsigned int pend, group, ip;
229 volatile unsigned int *addr;
230 unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
231
232 if (cp0_cause & CAUSEF_IP7)
233 return aruba_timer_interrupt(regs);
234
235 if(cp0_cause == 0) {
236 printk("INTERRUPT(S) FIRED WHILE MASKED\n");
237 #ifdef ARUBA_DEBUG
238 // debuging use -- figure out which interrupt(s) fired
239 cp0_cause = read_c0_cause() & CAUSEF_IP;
240 while (cp0_cause) {
241 unsigned long intr_bit;
242 unsigned int irq_nr;
243 intr_bit = (31 - rc32434_clz(cp0_cause));
244 irq_nr = intr_bit - GROUP0_IRQ_BASE;
245 printk(" ---> MASKED IRQ %d\n",irq_nr);
246 cp0_cause &= ~(1 << intr_bit);
247 }
248 #endif
249 return;
250 }
251
252 switch (mips_machtype) {
253 case MACH_ARUBA_AP70:
254 if ((ip = (cp0_cause & 0x7c00))) {
255 group = 21 - rc32434_clz(ip);
256
257 addr = intr_group_muscat[group].base_addr;
258
259 pend = READ_PEND_MUSCAT(addr);
260 pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts
261 pend = 39 - rc32434_clz(pend);
262 do_IRQ(pend + (group << 5));
263 }
264 break;
265 case MACH_ARUBA_AP65:
266 case MACH_ARUBA_AP60:
267 default:
268 if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6
269 // Misc Interrupt
270 group = 0;
271
272 addr = intr_group_merlot[group].base_addr;
273
274 pend = READ_PEND_MERLOT(addr);
275 pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts
276 pend = 31 - rc32434_clz(pend);
277 do_IRQ(pend + GROUP0_IRQ_BASE);
278 }
279 if ((ip = (cp0_cause & 0x3c00))) { // irq 2-5
280 pend = 31 - rc32434_clz(ip);
281 do_IRQ(pend - GROUP0_IRQ_BASE);
282 }
283 break;
284 }
285 }