[adm5120] remove unused empty files
[openwrt.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 }