don't dispatch spurious irq0 events
[openwrt.git] / target / linux / atheros / files / arch / mips / atheros / ar5315 / 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) 2003 Atheros Communications, Inc.,  All Rights Reserved.
7  * Copyright (C) 2006 FON Technology, SL.
8  * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
9  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
10  */
11
12 /*
13  * Platform devices for Atheros SoCs
14  */
15
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/types.h>
19 #include <linux/string.h>
20 #include <linux/kernel.h>
21 #include <linux/reboot.h>
22 #include <linux/interrupt.h>
23 #include <asm/bootinfo.h>
24 #include <asm/irq_cpu.h>
25 #include <asm/io.h>
26 #include "../ar531x.h"
27
28 static u32 gpiointmask = 0, gpiointval = 0;
29
30 static inline void ar5315_gpio_irq(void)
31 {
32         u32 pend;
33         sysRegWrite(AR5315_ISR, sysRegRead(AR5315_IMR) | ~AR5315_ISR_GPIO);
34
35         /* only do one gpio interrupt at a time */
36         pend = (sysRegRead(AR5315_GPIO_DI) ^ gpiointval) & gpiointmask;
37         if (!pend)
38                 return;
39
40         do_IRQ(AR531X_GPIO_IRQ_BASE + 31 - clz(pend));
41 }
42
43
44 /*
45  * Called when an interrupt is received, this function
46  * determines exactly which interrupt it was, and it
47  * invokes the appropriate handler.
48  *
49  * Implicitly, we also define interrupt priority by
50  * choosing which to dispatch first.
51  */
52 asmlinkage void ar5315_irq_dispatch(void)
53 {
54         int pending = read_c0_status() & read_c0_cause();
55
56         if (pending & CAUSEF_IP3)
57                 do_IRQ(AR5315_IRQ_WLAN0_INTRS);
58         else if (pending & CAUSEF_IP4)
59                 do_IRQ(AR5315_IRQ_ENET0_INTRS);
60         else if (pending & CAUSEF_IP2) {
61                 unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
62
63                 if (ar531x_misc_intrs & AR5315_ISR_SPI)
64                         do_IRQ(AR531X_MISC_IRQ_SPI);
65                 else if (ar531x_misc_intrs & AR5315_ISR_TIMER)
66                         do_IRQ(AR531X_MISC_IRQ_TIMER);
67                 else if (ar531x_misc_intrs & AR5315_ISR_AHB)
68                         do_IRQ(AR531X_MISC_IRQ_AHB_PROC);
69                 else if (ar531x_misc_intrs & AR5315_ISR_GPIO)
70                         ar5315_gpio_irq();
71                 else if (ar531x_misc_intrs & AR5315_ISR_UART0)
72                         do_IRQ(AR531X_MISC_IRQ_UART0);
73                 else if (ar531x_misc_intrs & AR5315_ISR_WD)
74                         do_IRQ(AR531X_MISC_IRQ_WATCHDOG);
75                 else
76                         do_IRQ(AR531X_MISC_IRQ_NONE);
77         } else if (pending & CAUSEF_IP7)
78                 do_IRQ(AR531X_IRQ_CPU_CLOCK);
79 }
80
81 static void ar5315_gpio_intr_enable(unsigned int irq)
82 {
83         u32 gpio, mask;
84         gpio = irq - AR531X_GPIO_IRQ_BASE;
85         mask = 1 << gpio;
86         gpiointmask |= mask;
87
88         /* reconfigure GPIO line as input */
89         sysRegMask(AR5315_GPIO_CR, AR5315_GPIO_CR_M(gpio), AR5315_GPIO_CR_I(gpio));
90         
91         /* Enable interrupt with edge detection */
92         sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(3));
93 }
94
95 static void ar5315_gpio_intr_disable(unsigned int irq)
96 {
97         u32 gpio, mask;
98         gpio = irq - AR531X_GPIO_IRQ_BASE;
99         mask = 1 << gpio;
100
101         gpiointmask &= ~mask;
102
103         /* Disable interrupt with edge detection */
104         sysRegMask(AR5315_GPIO_INT, AR5315_GPIO_INT_M | AR5315_GPIO_INT_LVL_M, gpio | AR5315_GPIO_INT_LVL(0));
105 }
106
107 /* Turn on the specified AR531X_MISC_IRQ interrupt */
108 static unsigned int ar5315_gpio_intr_startup(unsigned int irq)
109 {
110         ar5315_gpio_intr_enable(irq);
111         return 0;
112 }
113
114 /* Turn off the specified AR531X_MISC_IRQ interrupt */
115 static void
116 ar5315_gpio_intr_shutdown(unsigned int irq)
117 {
118         ar5315_gpio_intr_disable(irq);
119 }
120
121 static void
122 ar5315_gpio_intr_ack(unsigned int irq)
123 {
124         ar5315_gpio_intr_disable(irq);
125 }
126
127 static void
128 ar5315_gpio_intr_end(unsigned int irq)
129 {
130         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
131                 ar5315_gpio_intr_enable(irq);
132 }
133
134 static struct irq_chip ar5315_gpio_intr_controller = {
135         .typename       = "AR5315 GPIO",
136         .startup        = ar5315_gpio_intr_startup,
137         .shutdown       = ar5315_gpio_intr_shutdown,
138         .enable         = ar5315_gpio_intr_enable,
139         .disable        = ar5315_gpio_intr_disable,
140         .ack            = ar5315_gpio_intr_ack,
141         .end            = ar5315_gpio_intr_end,
142 };
143
144
145 /* Enable the specified AR531X_MISC_IRQ interrupt */
146 static void
147 ar5315_misc_intr_enable(unsigned int irq)
148 {
149         unsigned int imr;
150
151         imr = sysRegRead(AR5315_IMR);
152         switch(irq)
153         {
154            case AR531X_MISC_IRQ_SPI:
155                  imr |= AR5315_ISR_SPI;
156                  break;
157
158            case AR531X_MISC_IRQ_TIMER:
159              imr |= AR5315_ISR_TIMER;
160              break;
161
162            case AR531X_MISC_IRQ_AHB_PROC:
163              imr |= AR5315_ISR_AHB;
164              break;
165
166            case AR531X_MISC_IRQ_AHB_DMA:
167              imr |= 0/* ?? */;
168              break;
169
170            case AR531X_MISC_IRQ_GPIO:
171              imr |= AR5315_ISR_GPIO;
172              break;
173
174            case AR531X_MISC_IRQ_UART0:
175              imr |= AR5315_ISR_UART0;
176              break;
177
178
179            case AR531X_MISC_IRQ_WATCHDOG:
180              imr |= AR5315_ISR_WD;
181              break;
182
183            case AR531X_MISC_IRQ_LOCAL:
184              imr |= 0/* ?? */;
185              break;
186
187         }
188         sysRegWrite(AR5315_IMR, imr);
189         imr=sysRegRead(AR5315_IMR); /* flush write buffer */
190 }
191
192 /* Disable the specified AR531X_MISC_IRQ interrupt */
193 static void
194 ar5315_misc_intr_disable(unsigned int irq)
195 {
196         unsigned int imr;
197
198         imr = sysRegRead(AR5315_IMR);
199         switch(irq)
200         {
201            case AR531X_MISC_IRQ_SPI:
202                  imr &= ~AR5315_ISR_SPI;
203                  break;
204                  
205            case AR531X_MISC_IRQ_TIMER:
206              imr &= (~AR5315_ISR_TIMER);
207              break;
208
209            case AR531X_MISC_IRQ_AHB_PROC:
210              imr &= (~AR5315_ISR_AHB);
211              break;
212
213            case AR531X_MISC_IRQ_AHB_DMA:
214              imr &= 0/* ?? */;
215              break;
216
217            case AR531X_MISC_IRQ_GPIO:
218              imr &= ~AR5315_ISR_GPIO;
219              break;
220
221            case AR531X_MISC_IRQ_UART0:
222              imr &= (~AR5315_ISR_UART0);
223              break;
224
225            case AR531X_MISC_IRQ_WATCHDOG:
226              imr &= (~AR5315_ISR_WD);
227              break;
228
229            case AR531X_MISC_IRQ_LOCAL:
230              imr &= ~0/* ?? */;
231              break;
232
233         }
234         sysRegWrite(AR5315_IMR, imr);
235         sysRegRead(AR5315_IMR); /* flush write buffer */
236 }
237
238 /* Turn on the specified AR531X_MISC_IRQ interrupt */
239 static unsigned int
240 ar5315_misc_intr_startup(unsigned int irq)
241 {
242         ar5315_misc_intr_enable(irq);
243         return 0;
244 }
245
246 /* Turn off the specified AR531X_MISC_IRQ interrupt */
247 static void
248 ar5315_misc_intr_shutdown(unsigned int irq)
249 {
250         ar5315_misc_intr_disable(irq);
251 }
252
253 static void
254 ar5315_misc_intr_ack(unsigned int irq)
255 {
256         ar5315_misc_intr_disable(irq);
257 }
258
259 static void
260 ar5315_misc_intr_end(unsigned int irq)
261 {
262         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
263                 ar5315_misc_intr_enable(irq);
264 }
265
266 static struct irq_chip ar5315_misc_intr_controller = {
267         .typename       = "AR5315 misc",
268         .startup        = ar5315_misc_intr_startup,
269         .shutdown       = ar5315_misc_intr_shutdown,
270         .enable         = ar5315_misc_intr_enable,
271         .disable        = ar5315_misc_intr_disable,
272         .ack            = ar5315_misc_intr_ack,
273         .end            = ar5315_misc_intr_end,
274 };
275
276 static irqreturn_t ar5315_ahb_proc_handler(int cpl, void *dev_id)
277 {
278     sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
279     sysRegRead(AR5315_AHB_ERR1);
280
281     printk("AHB fatal error\n");
282     machine_restart("AHB error"); /* Catastrophic failure */
283
284     return IRQ_HANDLED;
285 }
286
287 static struct irqaction ar5315_ahb_proc_interrupt  = {
288         .handler        = ar5315_ahb_proc_handler,
289         .flags          = IRQF_DISABLED,
290         .name           = "ar5315_ahb_proc_interrupt",
291 };
292
293
294 static struct irqaction cascade  = {
295         .handler        = no_action,
296         .flags          = IRQF_DISABLED,
297         .name           = "cascade",
298 };
299
300 static void ar5315_gpio_intr_init(int irq_base)
301 {
302         int i;
303
304         for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) {
305                 irq_desc[i].status = IRQ_DISABLED;
306                 irq_desc[i].action = NULL;
307                 irq_desc[i].depth = 1;
308                 irq_desc[i].chip = &ar5315_gpio_intr_controller;
309         }
310         setup_irq(AR531X_MISC_IRQ_GPIO, &cascade);
311         gpiointval = sysRegRead(AR5315_GPIO_DI);
312 }
313
314 void ar5315_misc_intr_init(int irq_base)
315 {
316         int i;
317
318         for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
319                 irq_desc[i].status = IRQ_DISABLED;
320                 irq_desc[i].action = NULL;
321                 irq_desc[i].depth = 1;
322                 irq_desc[i].chip = &ar5315_misc_intr_controller;
323         }
324         setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar5315_ahb_proc_interrupt);
325         setup_irq(AR5315_IRQ_MISC_INTRS, &cascade);
326         ar5315_gpio_intr_init(AR531X_GPIO_IRQ_BASE);
327 }
328