split patch; start irq cleanup
[openwrt/svn-archive/archive.git] / openwrt / target / linux / aruba-2.6 / patches / 002-irq.patch
1 diff -Nur linux-2.6.15/arch/mips/aruba/idtIRQ.S linux-2.6.15-openwrt/arch/mips/aruba/idtIRQ.S
2 --- linux-2.6.15/arch/mips/aruba/idtIRQ.S 1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.15-openwrt/arch/mips/aruba/idtIRQ.S 2006-01-10 00:32:32.000000000 +0100
4 @@ -0,0 +1,87 @@
5 +/**************************************************************************
6 + *
7 + * BRIEF MODULE DESCRIPTION
8 + * Intterrupt dispatcher code for IDT boards
9 + *
10 + * Copyright 2004 IDT Inc. (rischelp@idt.com)
11 + *
12 + * This program is free software; you can redistribute it and/or modify it
13 + * under the terms of the GNU General Public License as published by the
14 + * Free Software Foundation; either version 2 of the License, or (at your
15 + * option) any later version.
16 + *
17 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
20 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 + *
28 + * You should have received a copy of the GNU General Public License along
29 + * with this program; if not, write to the Free Software Foundation, Inc.,
30 + * 675 Mass Ave, Cambridge, MA 02139, USA.
31 + *
32 + *
33 + **************************************************************************
34 + * May 2004 rkt, neb
35 + *
36 + * Initial Release
37 + *
38 + *
39 + *
40 + **************************************************************************
41 + */
42 +
43 +
44 +#include <asm/asm.h>
45 +#include <asm/mipsregs.h>
46 +#include <asm/regdef.h>
47 +#include <asm/stackframe.h>
48 +
49 + .text
50 + .set noreorder
51 + .set noat
52 + .align 5
53 + NESTED(idtIRQ, PT_SIZE, sp)
54 + .set noat
55 + SAVE_ALL
56 + CLI
57 +
58 + .set at
59 + .set noreorder
60 +
61 + /* Get the pending interrupts */
62 + mfc0 t0, CP0_CAUSE
63 + nop
64 +
65 + /* Isolate the allowed ones by anding the irq mask */
66 + mfc0 t2, CP0_STATUS
67 + move a1, sp /* need a nop here, hence we anticipate */
68 + andi t0, CAUSEF_IP
69 + and t0, t2
70 +
71 + /* check for r4k counter/timer IRQ. */
72 +
73 + andi t1, t0, CAUSEF_IP7
74 + beqz t1, 1f
75 + nop
76 +
77 + jal aruba_timer_interrupt
78 +
79 + li a0, 7
80 +
81 + j ret_from_irq
82 + nop
83 +1:
84 + jal aruba_irqdispatch
85 + move a0, t0
86 + j ret_from_irq
87 + nop
88 +
89 + END(idtIRQ)
90 +
91 +
92 diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/aruba/irq.c
93 --- linux-2.6.15/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100
94 +++ linux-2.6.15-openwrt/arch/mips/aruba/irq.c 2006-01-10 00:32:32.000000000 +0100
95 @@ -0,0 +1,393 @@
96 +/**************************************************************************
97 + *
98 + * BRIEF MODULE DESCRIPTION
99 + * Interrupt routines for IDT EB434 boards
100 + *
101 + * Copyright 2004 IDT Inc. (rischelp@idt.com)
102 + *
103 + * This program is free software; you can redistribute it and/or modify it
104 + * under the terms of the GNU General Public License as published by the
105 + * Free Software Foundation; either version 2 of the License, or (at your
106 + * option) any later version.
107 + *
108 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
109 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
110 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
111 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
112 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
113 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
114 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
115 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
116 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
117 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
118 + *
119 + * You should have received a copy of the GNU General Public License along
120 + * with this program; if not, write to the Free Software Foundation, Inc.,
121 + * 675 Mass Ave, Cambridge, MA 02139, USA.
122 + *
123 + *
124 + **************************************************************************
125 + * May 2004 rkt, neb
126 + *
127 + * Initial Release
128 + *
129 + *
130 + *
131 + **************************************************************************
132 + */
133 +
134 +#include <linux/errno.h>
135 +#include <linux/init.h>
136 +#include <linux/kernel_stat.h>
137 +#include <linux/module.h>
138 +#include <linux/signal.h>
139 +#include <linux/sched.h>
140 +#include <linux/types.h>
141 +#include <linux/interrupt.h>
142 +#include <linux/ioport.h>
143 +#include <linux/timex.h>
144 +#include <linux/slab.h>
145 +#include <linux/random.h>
146 +#include <linux/delay.h>
147 +
148 +#include <asm/bitops.h>
149 +#include <asm/bootinfo.h>
150 +#include <asm/io.h>
151 +#include <asm/mipsregs.h>
152 +#include <asm/system.h>
153 +#include <asm/idt-boards/rc32434/rc32434.h>
154 +#include <asm/idt-boards/rc32434/rc32434_gpio.h>
155 +
156 +#include <asm/irq.h>
157 +
158 +#undef DEBUG_IRQ
159 +#ifdef DEBUG_IRQ
160 +/* note: prints function name for you */
161 +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
162 +#else
163 +#define DPRINTK(fmt, args...)
164 +#endif
165 +
166 +extern asmlinkage void idtIRQ(void);
167 +static unsigned int startup_irq(unsigned int irq);
168 +static void end_irq(unsigned int irq_nr);
169 +static void mask_and_ack_irq(unsigned int irq_nr);
170 +static void aruba_enable_irq(unsigned int irq_nr);
171 +static void aruba_disable_irq(unsigned int irq_nr);
172 +
173 +extern void __init init_generic_irq(void);
174 +
175 +typedef struct {
176 + u32 mask;
177 + volatile u32 *base_addr;
178 +} intr_group_t;
179 +
180 +static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = {
181 + {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
182 +};
183 +
184 +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
185 +#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003010 + 4)))
186 +#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)((0xbc003010) + 4))) = (val))
187 +
188 +static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = {
189 + {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
190 + {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
191 + {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
192 + {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
193 + {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
194 +};
195 +
196 +#define READ_PEND_MUSCAT(base) (*(base))
197 +#define READ_MASK_MUSCAT(base) (*(base + 2))
198 +#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
199 +
200 +static inline int irq_to_group(unsigned int irq_nr)
201 +{
202 + switch (mips_machtype) {
203 + case MACH_ARUBA_AP70:
204 + return ((irq_nr - GROUP0_IRQ_BASE) >> 5);
205 + case MACH_ARUBA_AP65:
206 + case MACH_ARUBA_AP60:
207 + default:
208 + return 0;
209 + }
210 +}
211 +
212 +static inline int group_to_ip(unsigned int group)
213 +{
214 + switch (mips_machtype) {
215 + case MACH_ARUBA_AP70:
216 + return group + 2;
217 + case MACH_ARUBA_AP65:
218 + case MACH_ARUBA_AP60:
219 + default:
220 + return 6;
221 + }
222 +}
223 +
224 +static inline void enable_local_irq(unsigned int ip)
225 +{
226 + int ipnum = 0x100 << ip;
227 + clear_c0_cause(ipnum);
228 + set_c0_status(ipnum);
229 +}
230 +
231 +static inline void disable_local_irq(unsigned int ip)
232 +{
233 + int ipnum = 0x100 << ip;
234 + clear_c0_status(ipnum);
235 +}
236 +
237 +static inline void ack_local_irq(unsigned int ip)
238 +{
239 + int ipnum = 0x100 << ip;
240 + clear_c0_cause(ipnum);
241 +}
242 +
243 +static void aruba_enable_irq(unsigned int irq_nr)
244 +{
245 + int ip = irq_nr - GROUP0_IRQ_BASE;
246 + unsigned int group, intr_bit;
247 + volatile unsigned int *addr;
248 + if (ip < 0) {
249 + enable_local_irq(irq_nr);
250 + } else {
251 + // calculate group
252 + switch (mips_machtype) {
253 + case MACH_ARUBA_AP70:
254 + group = ip >> 5;
255 + break;
256 + case MACH_ARUBA_AP65:
257 + case MACH_ARUBA_AP60:
258 + default:
259 + group = 0;
260 + break;
261 + }
262 +
263 + // calc interrupt bit within group
264 + ip -= (group << 5);
265 + intr_bit = 1 << ip;
266 +
267 + // first enable the IP mapped to this IRQ
268 + enable_local_irq(group_to_ip(group));
269 +
270 + switch (mips_machtype) {
271 + case MACH_ARUBA_AP70:
272 + addr = intr_group_muscat[group].base_addr;
273 + // unmask intr within group
274 + WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
275 + break;
276 + case MACH_ARUBA_AP65:
277 + case MACH_ARUBA_AP60:
278 + default:
279 + addr = intr_group_merlot[group].base_addr;
280 + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
281 + break;
282 + }
283 + }
284 +}
285 +
286 +static void aruba_disable_irq(unsigned int irq_nr)
287 +{
288 + int ip = irq_nr - GROUP0_IRQ_BASE;
289 + unsigned int group, intr_bit, mask;
290 + volatile unsigned int *addr;
291 +
292 + // calculate group
293 + switch (mips_machtype) {
294 + case MACH_ARUBA_AP70:
295 + group = ip >> 5;
296 + break;
297 + case MACH_ARUBA_AP65:
298 + case MACH_ARUBA_AP60:
299 + default:
300 + group = 0;
301 + break;
302 + }
303 +
304 + // calc interrupt bit within group
305 + ip -= group << 5;
306 + intr_bit = 1 << ip;
307 +
308 + switch (mips_machtype) {
309 + case MACH_ARUBA_AP70:
310 + addr = intr_group_muscat[group].base_addr;
311 + // mask intr within group
312 + mask = READ_MASK_MUSCAT(addr);
313 + mask |= intr_bit;
314 + WRITE_MASK_MUSCAT(addr, mask);
315 +
316 + /*
317 + if there are no more interrupts enabled in this
318 + group, disable corresponding IP
319 + */
320 + if (mask == intr_group_muscat[group].mask)
321 + disable_local_irq(group_to_ip(group));
322 + break;
323 + case MACH_ARUBA_AP65:
324 + case MACH_ARUBA_AP60:
325 + default:
326 + addr = intr_group_merlot[group].base_addr;
327 + // mask intr within group
328 + mask = READ_MASK_MERLOT(addr);
329 + mask &= ~intr_bit;
330 + WRITE_MASK_MERLOT(addr, mask);
331 + if (!mask)
332 + disable_local_irq(group_to_ip(group));
333 + break;
334 + }
335 +}
336 +
337 +static unsigned int startup_irq(unsigned int irq_nr)
338 +{
339 + aruba_enable_irq(irq_nr);
340 + return 0;
341 +}
342 +
343 +static void shutdown_irq(unsigned int irq_nr)
344 +{
345 + aruba_disable_irq(irq_nr);
346 + return;
347 +}
348 +
349 +static void mask_and_ack_irq(unsigned int irq_nr)
350 +{
351 + aruba_disable_irq(irq_nr);
352 + ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
353 +}
354 +
355 +static void end_irq(unsigned int irq_nr)
356 +{
357 +
358 + int ip = irq_nr - GROUP0_IRQ_BASE;
359 + unsigned int intr_bit, group;
360 + volatile unsigned int *addr;
361 +
362 + if (irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
363 + printk("warning: end_irq %d did not enable (%x)\n",
364 + irq_nr, irq_desc[irq_nr].status);
365 + }
366 +
367 + switch (mips_machtype) {
368 + case MACH_ARUBA_AP70:
369 + if (irq_nr == GROUP4_IRQ_BASE + 9) idt_gpio->gpioistat &= 0xfffffdff;
370 + else if (irq_nr == GROUP4_IRQ_BASE + 10) idt_gpio->gpioistat &= 0xfffffbff;
371 + else if (irq_nr == GROUP4_IRQ_BASE + 11) idt_gpio->gpioistat &= 0xfffff7ff;
372 + else if (irq_nr == GROUP4_IRQ_BASE + 12) idt_gpio->gpioistat &= 0xffffefff;
373 +
374 + group = ip >> 5;
375 +
376 + // calc interrupt bit within group
377 + ip -= (group << 5);
378 + intr_bit = 1 << ip;
379 +
380 + // first enable the IP mapped to this IRQ
381 + enable_local_irq(group_to_ip(group));
382 +
383 + addr = intr_group_muscat[group].base_addr;
384 + // unmask intr within group
385 + WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
386 + break;
387 + case MACH_ARUBA_AP65:
388 + case MACH_ARUBA_AP60:
389 + group = 0;
390 +
391 + // calc interrupt bit within group
392 + intr_bit = 1 << ip;
393 +
394 + // first enable the IP mapped to this IRQ
395 + enable_local_irq(group_to_ip(group));
396 +
397 + addr = intr_group_merlot[group].base_addr;
398 + // unmask intr within group
399 + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
400 + break;
401 + }
402 +}
403 +
404 +static struct hw_interrupt_type aruba_irq_type = {
405 + .typename = "IDT434",
406 + .startup = startup_irq,
407 + .shutdown = shutdown_irq,
408 + .enable = aruba_enable_irq,
409 + .disable = aruba_disable_irq,
410 + .ack = mask_and_ack_irq,
411 + .end = end_irq,
412 +};
413 +
414 +void __init arch_init_irq(void)
415 +{
416 + int i;
417 + printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
418 + memset(irq_desc, 0, sizeof(irq_desc));
419 + set_except_vector(0, idtIRQ);
420 +
421 + for (i = 0; i < RC32434_NR_IRQS; i++) {
422 + irq_desc[i].status = IRQ_DISABLED;
423 + irq_desc[i].action = NULL;
424 + irq_desc[i].depth = 1;
425 + irq_desc[i].handler = &aruba_irq_type;
426 + spin_lock_init(&irq_desc[i].lock);
427 + }
428 +
429 + switch (mips_machtype) {
430 + case MACH_ARUBA_AP70:
431 + break;
432 + case MACH_ARUBA_AP65:
433 + case MACH_ARUBA_AP60:
434 + default:
435 + WRITE_MASK_MERLOT(intr_group_merlot[0].base_addr, 0);
436 + *((volatile unsigned long *)0xbc003014) = 0x10;
437 + break;
438 + }
439 +}
440 +
441 +/* Main Interrupt dispatcher */
442 +void aruba_irqdispatch(unsigned long cp0_cause, struct pt_regs *regs)
443 +{
444 + unsigned int pend, group, ip;
445 + volatile unsigned int *addr;
446 + switch (mips_machtype) {
447 + case MACH_ARUBA_AP70:
448 + if ((ip = (cp0_cause & 0x7c00))) {
449 + group = 21 - rc32434_clz(ip);
450 +
451 + addr = intr_group_muscat[group].base_addr;
452 +
453 + pend = READ_PEND_MUSCAT(addr);
454 + pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts
455 + pend = 39 - rc32434_clz(pend);
456 + do_IRQ((group << 5) + pend, regs);
457 + }
458 + break;
459 + case MACH_ARUBA_AP65:
460 + case MACH_ARUBA_AP60:
461 + default:
462 + if (cp0_cause & 0x4000) {
463 + // Misc Interrupt
464 + group = 0;
465 + addr = intr_group_merlot[group].base_addr;
466 + pend = READ_PEND_MERLOT(addr);
467 + pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts
468 + /* handle one misc interrupt at a time */
469 + while (pend) {
470 + unsigned int intr_bit, irq_nr;
471 + intr_bit = pend ^ (pend - 1);
472 + irq_nr = ((31 - rc32434_clz(pend)) + GROUP0_IRQ_BASE);
473 + do_IRQ(irq_nr, regs);
474 + pend &= ~intr_bit;
475 + }
476 + }
477 + if (cp0_cause & 0x3c00) {
478 + while (cp0_cause) {
479 + unsigned int intr_bit, irq_nr;
480 + intr_bit = cp0_cause ^ (cp0_cause - 1);
481 + irq_nr = ((31 - rc32434_clz(cp0_cause)) - GROUP0_IRQ_BASE);
482 + do_IRQ(irq_nr, regs);
483 + cp0_cause &= ~intr_bit;
484 + }
485 + }
486 + break;
487 + }
488 +}