ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / vr4181 / common / irq.c
1 /*
2  * Copyright (C) 2001 MontaVista Software Inc.
3  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
4  *
5  * linux/arch/mips/vr4181/common/irq.c
6  *      Completely re-written to use the new irq.c
7  *
8  * Credits to Bradley D. LaRonde and Michael Klar for writing the original
9  * irq.c file which was derived from the common irq.c file.
10  *
11  * This file is subject to the terms and conditions of the GNU General Public
12  * License.  See the file "COPYING" in the main directory of this archive
13  * for more details.
14  */
15 #include <linux/config.h>
16 #include <linux/types.h>
17 #include <linux/init.h>
18 #include <linux/kernel_stat.h>
19 #include <linux/signal.h>
20 #include <linux/sched.h>
21 #include <linux/interrupt.h>
22 #include <linux/slab.h>
23 #include <linux/random.h>
24
25 #include <asm/irq.h>
26 #include <asm/mipsregs.h>
27 #include <asm/gdb-stub.h>
28
29 #include <asm/vr4181/vr4181.h>
30
31 /*
32  * Strategy:
33  *
34  * We essentially have three irq controllers, CPU, system, and gpio.
35  *
36  * CPU irq controller is taken care by arch/mips/kernel/irq_cpu.c and
37  * CONFIG_IRQ_CPU config option.
38  *
39  * We here provide sys_irq and gpio_irq controller code.
40  */
41
42 static int sys_irq_base;
43 static int gpio_irq_base;
44
45 /* ---------------------- sys irq ------------------------ */
46 static void
47 sys_irq_enable(unsigned int irq)
48 {
49         irq -= sys_irq_base;
50         if (irq < 16) {
51                 *VR4181_MSYSINT1REG |= (u16)(1 << irq);
52         } else {
53                 irq -= 16;
54                 *VR4181_MSYSINT2REG |= (u16)(1 << irq);
55         }
56 }
57
58 static void
59 sys_irq_disable(unsigned int irq)
60 {
61         irq -= sys_irq_base;
62         if (irq < 16) {
63                 *VR4181_MSYSINT1REG &= ~((u16)(1 << irq));
64         } else {
65                 irq -= 16;
66                 *VR4181_MSYSINT2REG &= ~((u16)(1 << irq));
67         }
68
69 }
70
71 static unsigned int
72 sys_irq_startup(unsigned int irq)
73 {
74         sys_irq_enable(irq);
75         return 0;
76 }
77
78 #define sys_irq_shutdown        sys_irq_disable
79 #define sys_irq_ack             sys_irq_disable
80
81 static void
82 sys_irq_end(unsigned int irq)
83 {
84         if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
85                 sys_irq_enable(irq);
86 }
87
88 static hw_irq_controller sys_irq_controller = {
89         "vr4181_sys_irq",
90         sys_irq_startup,
91         sys_irq_shutdown,
92         sys_irq_enable,
93         sys_irq_disable,
94         sys_irq_ack,
95         sys_irq_end,
96         NULL                    /* no affinity stuff for UP */
97 };
98
99 /* ---------------------- gpio irq ------------------------ */
100 /* gpio irq lines use reverse logic */
101 static void
102 gpio_irq_enable(unsigned int irq)
103 {
104         irq -= gpio_irq_base;
105         *VR4181_GPINTMSK &= ~((u16)(1 << irq));
106 }
107
108 static void
109 gpio_irq_disable(unsigned int irq)
110 {
111         irq -= gpio_irq_base;
112         *VR4181_GPINTMSK |= (u16)(1 << irq);
113 }
114
115 static unsigned int
116 gpio_irq_startup(unsigned int irq)
117 {
118         gpio_irq_enable(irq);
119
120         irq -= gpio_irq_base;
121         *VR4181_GPINTEN |= (u16)(1 << irq );
122
123         return 0;
124 }
125
126 static void
127 gpio_irq_shutdown(unsigned int irq)
128 {
129         gpio_irq_disable(irq);
130
131         irq -= gpio_irq_base;
132         *VR4181_GPINTEN &= ~((u16)(1 << irq ));
133 }
134
135 static void
136 gpio_irq_ack(unsigned int irq)
137 {
138         u16 irqtype;
139         u16 irqshift;
140
141         gpio_irq_disable(irq);
142
143         /* we clear interrupt if it is edge triggered */
144         irq -= gpio_irq_base;
145         if (irq < 8) {
146                 irqtype = *VR4181_GPINTTYPL;
147                 irqshift = 2 << (irq*2);
148         } else {
149                 irqtype = *VR4181_GPINTTYPH;
150                 irqshift = 2 << ((irq-8)*2);
151         }
152         if ( ! (irqtype & irqshift) ) {
153                 *VR4181_GPINTSTAT = (u16) (1 << irq);
154         }
155 }
156
157 static void
158 gpio_irq_end(unsigned int irq)
159 {
160         if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
161                 gpio_irq_enable(irq);
162 }
163
164 static hw_irq_controller gpio_irq_controller = {
165         "vr4181_gpio_irq",
166         gpio_irq_startup,
167         gpio_irq_shutdown,
168         gpio_irq_enable,
169         gpio_irq_disable,
170         gpio_irq_ack,
171         gpio_irq_end,
172         NULL                    /* no affinity stuff for UP */
173 };
174
175 /* ---------------------  IRQ init stuff ---------------------- */
176
177 extern asmlinkage void vr4181_handle_irq(void);
178 extern void breakpoint(void);
179 extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
180 extern void mips_cpu_irq_init(u32 irq_base);
181
182 static struct irqaction cascade =
183         { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL };
184 static struct irqaction reserved =
185         { no_action, SA_INTERRUPT, 0, "cascade", NULL, NULL };
186
187 void __init init_IRQ(void)
188 {
189         int i;
190         extern irq_desc_t irq_desc[];
191
192         set_except_vector(0, vr4181_handle_irq);
193
194         /* init CPU irqs */
195         mips_cpu_irq_init(VR4181_CPU_IRQ_BASE);
196
197         /* init sys irqs */
198         sys_irq_base = VR4181_SYS_IRQ_BASE;
199         for (i=sys_irq_base; i < sys_irq_base + VR4181_NUM_SYS_IRQ; i++) {
200                 irq_desc[i].status = IRQ_DISABLED;
201                 irq_desc[i].action = NULL;
202                 irq_desc[i].depth = 1;
203                 irq_desc[i].handler = &sys_irq_controller;
204         }
205
206         /* init gpio irqs */
207         gpio_irq_base = VR4181_GPIO_IRQ_BASE;
208         for (i=gpio_irq_base; i < gpio_irq_base + VR4181_NUM_GPIO_IRQ; i++) {
209                 irq_desc[i].status = IRQ_DISABLED;
210                 irq_desc[i].action = NULL;
211                 irq_desc[i].depth = 1;
212                 irq_desc[i].handler = &gpio_irq_controller;
213         }
214
215         /* Default all ICU IRQs to off ... */
216         *VR4181_MSYSINT1REG = 0;
217         *VR4181_MSYSINT2REG = 0;
218
219         /* We initialize the level 2 ICU registers to all bits disabled. */
220         *VR4181_MPIUINTREG = 0;
221         *VR4181_MAIUINTREG = 0;
222         *VR4181_MKIUINTREG = 0;
223
224         /* disable all GPIO intrs */
225         *VR4181_GPINTMSK = 0xffff;
226
227         /* vector handler.  What these do is register the IRQ as non-sharable */
228         setup_irq(VR4181_IRQ_INT0, &cascade);
229         setup_irq(VR4181_IRQ_GIU, &cascade);
230
231         /*
232          * RTC interrupts are interesting.  They have two destinations.
233          * One is at sys irq controller, and the other is at CPU IP3 and IP4.
234          * RTC timer is used as system timer.
235          * We enable them here, but timer routine will register later
236          * with CPU IP3/IP4.
237          */
238         setup_irq(VR4181_IRQ_RTCL1, &reserved);
239         setup_irq(VR4181_IRQ_RTCL2, &reserved);
240
241 #ifdef CONFIG_KGDB
242         printk("Setting debug traps - please connect the remote debugger.\n");
243
244         set_debug_traps();
245
246         // you may move this line to whereever you want
247         breakpoint();
248 #endif
249 }