blob: b6024749b8f49c33287e22c9011a38e520015d0a [file] [log] [blame]
Ralf Baechle23fbee92005-07-25 22:45:45 +00001/*
Uwe Zeisbergerf30c2262006-10-03 23:01:26 +02002 * linux/arch/mips/tx4938/common/irq.c
Ralf Baechle23fbee92005-07-25 22:45:45 +00003 *
4 * Common tx4938 irq handler
5 * Copyright (C) 2000-2001 Toshiba Corporation
6 *
7 * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
8 * terms of the GNU General Public License version 2. This program is
9 * licensed "as is" without any warranty of any kind, whether express
10 * or implied.
11 *
12 * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
13 */
14#include <linux/errno.h>
15#include <linux/init.h>
16#include <linux/kernel_stat.h>
17#include <linux/module.h>
18#include <linux/signal.h>
19#include <linux/sched.h>
20#include <linux/types.h>
21#include <linux/interrupt.h>
22#include <linux/ioport.h>
23#include <linux/timex.h>
24#include <linux/slab.h>
25#include <linux/random.h>
26#include <linux/irq.h>
27#include <asm/bitops.h>
28#include <asm/bootinfo.h>
29#include <asm/io.h>
30#include <asm/irq.h>
31#include <asm/mipsregs.h>
32#include <asm/system.h>
33#include <asm/tx4938/rbtx4938.h>
34
35/**********************************************************************************/
36/* Forwad definitions for all pic's */
37/**********************************************************************************/
38
39static unsigned int tx4938_irq_cp0_startup(unsigned int irq);
40static void tx4938_irq_cp0_shutdown(unsigned int irq);
41static void tx4938_irq_cp0_enable(unsigned int irq);
42static void tx4938_irq_cp0_disable(unsigned int irq);
43static void tx4938_irq_cp0_mask_and_ack(unsigned int irq);
44static void tx4938_irq_cp0_end(unsigned int irq);
45
46static unsigned int tx4938_irq_pic_startup(unsigned int irq);
47static void tx4938_irq_pic_shutdown(unsigned int irq);
48static void tx4938_irq_pic_enable(unsigned int irq);
49static void tx4938_irq_pic_disable(unsigned int irq);
50static void tx4938_irq_pic_mask_and_ack(unsigned int irq);
51static void tx4938_irq_pic_end(unsigned int irq);
52
53/**********************************************************************************/
54/* Kernel structs for all pic's */
55/**********************************************************************************/
56DEFINE_SPINLOCK(tx4938_cp0_lock);
57DEFINE_SPINLOCK(tx4938_pic_lock);
58
59#define TX4938_CP0_NAME "TX4938-CP0"
Ralf Baechle94dee172006-07-02 14:41:42 +010060static struct irq_chip tx4938_irq_cp0_type = {
Ralf Baechle23fbee92005-07-25 22:45:45 +000061 .typename = TX4938_CP0_NAME,
62 .startup = tx4938_irq_cp0_startup,
63 .shutdown = tx4938_irq_cp0_shutdown,
64 .enable = tx4938_irq_cp0_enable,
65 .disable = tx4938_irq_cp0_disable,
66 .ack = tx4938_irq_cp0_mask_and_ack,
67 .end = tx4938_irq_cp0_end,
68 .set_affinity = NULL
69};
70
71#define TX4938_PIC_NAME "TX4938-PIC"
Ralf Baechle94dee172006-07-02 14:41:42 +010072static struct irq_chip tx4938_irq_pic_type = {
Ralf Baechle23fbee92005-07-25 22:45:45 +000073 .typename = TX4938_PIC_NAME,
74 .startup = tx4938_irq_pic_startup,
75 .shutdown = tx4938_irq_pic_shutdown,
76 .enable = tx4938_irq_pic_enable,
77 .disable = tx4938_irq_pic_disable,
78 .ack = tx4938_irq_pic_mask_and_ack,
79 .end = tx4938_irq_pic_end,
80 .set_affinity = NULL
81};
82
83static struct irqaction tx4938_irq_pic_action = {
84 .handler = no_action,
85 .flags = 0,
86 .mask = CPU_MASK_NONE,
87 .name = TX4938_PIC_NAME
88};
89
90/**********************************************************************************/
91/* Functions for cp0 */
92/**********************************************************************************/
93
94#define tx4938_irq_cp0_mask(irq) ( 1 << ( irq-TX4938_IRQ_CP0_BEG+8 ) )
95
96static void __init
97tx4938_irq_cp0_init(void)
98{
99 int i;
100
101 for (i = TX4938_IRQ_CP0_BEG; i <= TX4938_IRQ_CP0_END; i++) {
102 irq_desc[i].status = IRQ_DISABLED;
103 irq_desc[i].action = 0;
104 irq_desc[i].depth = 1;
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700105 irq_desc[i].chip = &tx4938_irq_cp0_type;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000106 }
Ralf Baechle23fbee92005-07-25 22:45:45 +0000107}
108
109static unsigned int
110tx4938_irq_cp0_startup(unsigned int irq)
111{
112 tx4938_irq_cp0_enable(irq);
113
Ralf Baechle937a8012006-10-07 19:44:33 +0100114 return 0;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000115}
116
117static void
118tx4938_irq_cp0_shutdown(unsigned int irq)
119{
120 tx4938_irq_cp0_disable(irq);
121}
122
123static void
124tx4938_irq_cp0_enable(unsigned int irq)
125{
126 unsigned long flags;
127
128 spin_lock_irqsave(&tx4938_cp0_lock, flags);
129
130 set_c0_status(tx4938_irq_cp0_mask(irq));
131
132 spin_unlock_irqrestore(&tx4938_cp0_lock, flags);
133}
134
135static void
136tx4938_irq_cp0_disable(unsigned int irq)
137{
138 unsigned long flags;
139
140 spin_lock_irqsave(&tx4938_cp0_lock, flags);
141
142 clear_c0_status(tx4938_irq_cp0_mask(irq));
143
144 spin_unlock_irqrestore(&tx4938_cp0_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000145}
146
147static void
148tx4938_irq_cp0_mask_and_ack(unsigned int irq)
149{
150 tx4938_irq_cp0_disable(irq);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000151}
152
153static void
154tx4938_irq_cp0_end(unsigned int irq)
155{
156 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
157 tx4938_irq_cp0_enable(irq);
158 }
Ralf Baechle23fbee92005-07-25 22:45:45 +0000159}
160
161/**********************************************************************************/
162/* Functions for pic */
163/**********************************************************************************/
164
165u32
166tx4938_irq_pic_addr(int irq)
167{
168 /* MVMCP -- need to formulize this */
169 irq -= TX4938_IRQ_PIC_BEG;
170
171 switch (irq) {
172 case 17:
173 case 16:
174 case 1:
175 case 0:{
176 return (TX4938_MKA(TX4938_IRC_IRLVL0));
177 }
178 case 19:
179 case 18:
180 case 3:
181 case 2:{
182 return (TX4938_MKA(TX4938_IRC_IRLVL1));
183 }
184 case 21:
185 case 20:
186 case 5:
187 case 4:{
188 return (TX4938_MKA(TX4938_IRC_IRLVL2));
189 }
190 case 23:
191 case 22:
192 case 7:
193 case 6:{
194 return (TX4938_MKA(TX4938_IRC_IRLVL3));
195 }
196 case 25:
197 case 24:
198 case 9:
199 case 8:{
200 return (TX4938_MKA(TX4938_IRC_IRLVL4));
201 }
202 case 27:
203 case 26:
204 case 11:
205 case 10:{
206 return (TX4938_MKA(TX4938_IRC_IRLVL5));
207 }
208 case 29:
209 case 28:
210 case 13:
211 case 12:{
212 return (TX4938_MKA(TX4938_IRC_IRLVL6));
213 }
214 case 31:
215 case 30:
216 case 15:
217 case 14:{
218 return (TX4938_MKA(TX4938_IRC_IRLVL7));
219 }
220 }
221
Ralf Baechle937a8012006-10-07 19:44:33 +0100222 return 0;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000223}
224
225u32
226tx4938_irq_pic_mask(int irq)
227{
228 /* MVMCP -- need to formulize this */
229 irq -= TX4938_IRQ_PIC_BEG;
230
231 switch (irq) {
232 case 31:
233 case 29:
234 case 27:
235 case 25:
236 case 23:
237 case 21:
238 case 19:
239 case 17:{
240 return (0x07000000);
241 }
242 case 30:
243 case 28:
244 case 26:
245 case 24:
246 case 22:
247 case 20:
248 case 18:
249 case 16:{
250 return (0x00070000);
251 }
252 case 15:
253 case 13:
254 case 11:
255 case 9:
256 case 7:
257 case 5:
258 case 3:
259 case 1:{
260 return (0x00000700);
261 }
262 case 14:
263 case 12:
264 case 10:
265 case 8:
266 case 6:
267 case 4:
268 case 2:
269 case 0:{
270 return (0x00000007);
271 }
272 }
Ralf Baechle937a8012006-10-07 19:44:33 +0100273 return 0x00000000;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000274}
275
276static void
277tx4938_irq_pic_modify(unsigned pic_reg, unsigned clr_bits, unsigned set_bits)
278{
279 unsigned long val = 0;
280
281 val = TX4938_RD(pic_reg);
282 val &= (~clr_bits);
283 val |= (set_bits);
284 TX4938_WR(pic_reg, val);
285 mmiowb();
286 TX4938_RD(pic_reg);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000287}
288
289static void __init
290tx4938_irq_pic_init(void)
291{
292 unsigned long flags;
293 int i;
294
295 for (i = TX4938_IRQ_PIC_BEG; i <= TX4938_IRQ_PIC_END; i++) {
296 irq_desc[i].status = IRQ_DISABLED;
297 irq_desc[i].action = 0;
298 irq_desc[i].depth = 2;
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700299 irq_desc[i].chip = &tx4938_irq_pic_type;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000300 }
301
302 setup_irq(TX4938_IRQ_NEST_PIC_ON_CP0, &tx4938_irq_pic_action);
303
304 spin_lock_irqsave(&tx4938_pic_lock, flags);
305
306 TX4938_WR(0xff1ff640, 0x6); /* irq level mask -- only accept hightest */
307 TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */
308
309 spin_unlock_irqrestore(&tx4938_pic_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000310}
311
312static unsigned int
313tx4938_irq_pic_startup(unsigned int irq)
314{
315 tx4938_irq_pic_enable(irq);
316
Ralf Baechle937a8012006-10-07 19:44:33 +0100317 return 0;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000318}
319
320static void
321tx4938_irq_pic_shutdown(unsigned int irq)
322{
323 tx4938_irq_pic_disable(irq);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000324}
325
326static void
327tx4938_irq_pic_enable(unsigned int irq)
328{
329 unsigned long flags;
330
331 spin_lock_irqsave(&tx4938_pic_lock, flags);
332
333 tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq), 0,
334 tx4938_irq_pic_mask(irq));
335
336 spin_unlock_irqrestore(&tx4938_pic_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000337}
338
339static void
340tx4938_irq_pic_disable(unsigned int irq)
341{
342 unsigned long flags;
343
344 spin_lock_irqsave(&tx4938_pic_lock, flags);
345
346 tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq),
347 tx4938_irq_pic_mask(irq), 0);
348
349 spin_unlock_irqrestore(&tx4938_pic_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000350}
351
352static void
353tx4938_irq_pic_mask_and_ack(unsigned int irq)
354{
355 tx4938_irq_pic_disable(irq);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000356}
357
358static void
359tx4938_irq_pic_end(unsigned int irq)
360{
361 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
362 tx4938_irq_pic_enable(irq);
363 }
Ralf Baechle23fbee92005-07-25 22:45:45 +0000364}
365
366/**********************************************************************************/
367/* Main init functions */
368/**********************************************************************************/
369
370void __init
371tx4938_irq_init(void)
372{
Ralf Baechle23fbee92005-07-25 22:45:45 +0000373 tx4938_irq_cp0_init();
374 tx4938_irq_pic_init();
Ralf Baechle23fbee92005-07-25 22:45:45 +0000375}
376
377int
378tx4938_irq_nested(void)
379{
380 int sw_irq = 0;
381 u32 level2;
382
383 level2 = TX4938_RD(0xff1ff6a0);
384 if ((level2 & 0x10000) == 0) {
385 level2 &= 0x1f;
386 sw_irq = TX4938_IRQ_PIC_BEG + level2;
387 if (sw_irq == 26) {
388 {
389 extern int toshiba_rbtx4938_irq_nested(int sw_irq);
390 sw_irq = toshiba_rbtx4938_irq_nested(sw_irq);
391 }
392 }
393 }
394
395 wbflush();
Ralf Baechle937a8012006-10-07 19:44:33 +0100396 return sw_irq;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000397}
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100398
Ralf Baechle937a8012006-10-07 19:44:33 +0100399asmlinkage void plat_irq_dispatch(void)
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100400{
401 unsigned int pending = read_c0_cause() & read_c0_status();
402
403 if (pending & STATUSF_IP7)
Ralf Baechle937a8012006-10-07 19:44:33 +0100404 do_IRQ(TX4938_IRQ_CPU_TIMER);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100405 else if (pending & STATUSF_IP2) {
406 int irq = tx4938_irq_nested();
407 if (irq)
Ralf Baechle937a8012006-10-07 19:44:33 +0100408 do_IRQ(irq);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100409 else
Ralf Baechle937a8012006-10-07 19:44:33 +0100410 spurious_interrupt();
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100411 } else if (pending & STATUSF_IP1)
Ralf Baechle937a8012006-10-07 19:44:33 +0100412 do_IRQ(TX4938_IRQ_USER1);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100413 else if (pending & STATUSF_IP0)
Ralf Baechle937a8012006-10-07 19:44:33 +0100414 do_IRQ(TX4938_IRQ_USER0);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100415}