http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / kernel / linux / arch / arm / mach-iop3xx / iq80310-irq.c
1 /*
2  * linux/arch/arm/mach-iop3xx/iq80310-irq.c
3  *
4  * IRQ hadling/demuxing for IQ80310 board
5  *
6  * Author:  Nicolas Pitre
7  * Copyright:   (C) 2001 MontaVista Software Inc.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * 2.4.7-rmk1-iop310.1
14  *     Moved demux from asm to C - DS
15  *     Fixes for various revision boards - DS
16  */
17 #include <linux/init.h>
18 #include <linux/list.h>
19
20 #include <asm/irq.h>
21 #include <asm/mach/irq.h>
22 #include <asm/hardware.h>
23 #include <asm/system.h>
24
25 extern void iop310_init_irq(void);
26 extern void iop310_irq_demux(unsigned int, struct irqdesc *, struct pt_regs *);
27
28 static void iq80310_irq_mask(unsigned int irq)
29 {
30         *(volatile char *)IQ80310_INT_MASK |= (1 << (irq - IQ80310_IRQ_OFS));
31 }
32
33 static void iq80310_irq_unmask(unsigned int irq)
34 {
35         *(volatile char *)IQ80310_INT_MASK &= ~(1 << (irq - IQ80310_IRQ_OFS));
36 }
37
38 static struct irqchip iq80310_irq_chip = {
39         .ack    = iq80310_irq_mask,
40         .mask   = iq80310_irq_mask,
41         .unmask = iq80310_irq_unmask,
42 };
43
44 extern struct irqchip ext_chip;
45
46 static void
47 iq80310_cpld_irq_handler(unsigned int irq, struct irqdesc *desc,
48                          struct pt_regs *regs)
49 {
50         unsigned int irq_stat = *(volatile u8*)IQ80310_INT_STAT;
51         unsigned int irq_mask = *(volatile u8*)IQ80310_INT_MASK;
52         unsigned int i, handled = 0;
53         struct irqdesc *d;
54
55         desc->chip->ack(irq);
56
57         /*
58          * Mask out the interrupts which aren't enabled.
59          */
60         irq_stat &= 0x1f & ~irq_mask;
61
62         /*
63          * Test each IQ80310 CPLD interrupt
64          */
65         for (i = IRQ_IQ80310_TIMER, d = irq_desc + IRQ_IQ80310_TIMER;
66              irq_stat; i++, d++, irq_stat >>= 1)
67                 if (irq_stat & 1) {
68                         d->handle(i, d, regs);
69                         handled++;
70                 }
71
72         /*
73          * If running on a board later than REV D.1, we can
74          * decode the PCI interrupt status.
75          */
76         if (system_rev) {
77                 irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 7;
78
79                 for (i = IRQ_IQ80310_INTA, d = irq_desc + IRQ_IQ80310_INTA;
80                      irq_stat; i++, d++, irq_stat >>= 1)
81                         if (irq_stat & 0x1) {
82                                 d->handle(i, d, regs);
83                                 handled++;
84                         }
85         }
86
87         /*
88          * If on a REV D.1 or lower board, we just assumed INTA
89          * since PCI is not routed, and it may actually be an
90          * on-chip interrupt.
91          *
92          * Note that we're giving on-chip interrupts slightly
93          * higher priority than PCI by handling them first.
94          *
95          * On boards later than REV D.1, if we didn't read a
96          * CPLD interrupt, we assume it's from a device on the
97          * chipset itself.
98          */
99         if (system_rev == 0 || handled == 0)
100                 iop310_irq_demux(irq, desc, regs);
101
102         desc->chip->unmask(irq);
103 }
104
105 void __init iq80310_init_irq(void)
106 {
107         volatile char *mask = (volatile char *)IQ80310_INT_MASK;
108         unsigned int i;
109
110         iop310_init_irq();
111
112         /*
113          * Setup PIRSR to route PCI interrupts into xs80200
114          */
115         *IOP310_PIRSR = 0xff;
116
117         /*
118          * Setup the IRQs in the FE820000/FE860000 registers
119          */
120         for (i = IQ80310_IRQ_OFS; i <= IRQ_IQ80310_INTD; i++) {
121                 set_irq_chip(i, &iq80310_irq_chip);
122                 set_irq_handler(i, do_level_IRQ);
123                 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
124         }
125
126         /*
127          * Setup the PCI IRQs
128          */
129         for (i = IRQ_IQ80310_INTA; i < IRQ_IQ80310_INTC; i++) {
130                 set_irq_chip(i, &ext_chip);
131                 set_irq_handler(i, do_level_IRQ);
132                 set_irq_flags(i, IRQF_VALID);
133         }
134
135         *mask = 0xff;  /* mask all sources */
136
137         set_irq_chained_handler(IRQ_XS80200_EXTIRQ,
138                                 &iq80310_cpld_irq_handler);
139 }