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