blob: 77fe2454f5b91f1509b8cc075f2faae183828473 [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>
Atsushi Nemotof5c70dd2006-08-20 22:55:52 +090033#include <asm/wbflush.h>
Ralf Baechle23fbee92005-07-25 22:45:45 +000034#include <asm/tx4938/rbtx4938.h>
35
36/**********************************************************************************/
37/* Forwad definitions for all pic's */
38/**********************************************************************************/
39
40static unsigned int tx4938_irq_cp0_startup(unsigned int irq);
41static void tx4938_irq_cp0_shutdown(unsigned int irq);
42static void tx4938_irq_cp0_enable(unsigned int irq);
43static void tx4938_irq_cp0_disable(unsigned int irq);
44static void tx4938_irq_cp0_mask_and_ack(unsigned int irq);
45static void tx4938_irq_cp0_end(unsigned int irq);
46
47static unsigned int tx4938_irq_pic_startup(unsigned int irq);
48static void tx4938_irq_pic_shutdown(unsigned int irq);
49static void tx4938_irq_pic_enable(unsigned int irq);
50static void tx4938_irq_pic_disable(unsigned int irq);
51static void tx4938_irq_pic_mask_and_ack(unsigned int irq);
52static void tx4938_irq_pic_end(unsigned int irq);
53
54/**********************************************************************************/
55/* Kernel structs for all pic's */
56/**********************************************************************************/
57DEFINE_SPINLOCK(tx4938_cp0_lock);
58DEFINE_SPINLOCK(tx4938_pic_lock);
59
60#define TX4938_CP0_NAME "TX4938-CP0"
Ralf Baechle94dee172006-07-02 14:41:42 +010061static struct irq_chip tx4938_irq_cp0_type = {
Ralf Baechle23fbee92005-07-25 22:45:45 +000062 .typename = TX4938_CP0_NAME,
63 .startup = tx4938_irq_cp0_startup,
64 .shutdown = tx4938_irq_cp0_shutdown,
65 .enable = tx4938_irq_cp0_enable,
66 .disable = tx4938_irq_cp0_disable,
67 .ack = tx4938_irq_cp0_mask_and_ack,
68 .end = tx4938_irq_cp0_end,
69 .set_affinity = NULL
70};
71
72#define TX4938_PIC_NAME "TX4938-PIC"
Ralf Baechle94dee172006-07-02 14:41:42 +010073static struct irq_chip tx4938_irq_pic_type = {
Ralf Baechle23fbee92005-07-25 22:45:45 +000074 .typename = TX4938_PIC_NAME,
75 .startup = tx4938_irq_pic_startup,
76 .shutdown = tx4938_irq_pic_shutdown,
77 .enable = tx4938_irq_pic_enable,
78 .disable = tx4938_irq_pic_disable,
79 .ack = tx4938_irq_pic_mask_and_ack,
80 .end = tx4938_irq_pic_end,
81 .set_affinity = NULL
82};
83
84static struct irqaction tx4938_irq_pic_action = {
85 .handler = no_action,
86 .flags = 0,
87 .mask = CPU_MASK_NONE,
88 .name = TX4938_PIC_NAME
89};
90
91/**********************************************************************************/
92/* Functions for cp0 */
93/**********************************************************************************/
94
95#define tx4938_irq_cp0_mask(irq) ( 1 << ( irq-TX4938_IRQ_CP0_BEG+8 ) )
96
97static void __init
98tx4938_irq_cp0_init(void)
99{
100 int i;
101
102 for (i = TX4938_IRQ_CP0_BEG; i <= TX4938_IRQ_CP0_END; i++) {
103 irq_desc[i].status = IRQ_DISABLED;
104 irq_desc[i].action = 0;
105 irq_desc[i].depth = 1;
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700106 irq_desc[i].chip = &tx4938_irq_cp0_type;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000107 }
Ralf Baechle23fbee92005-07-25 22:45:45 +0000108}
109
110static unsigned int
111tx4938_irq_cp0_startup(unsigned int irq)
112{
113 tx4938_irq_cp0_enable(irq);
114
Ralf Baechle937a8012006-10-07 19:44:33 +0100115 return 0;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000116}
117
118static void
119tx4938_irq_cp0_shutdown(unsigned int irq)
120{
121 tx4938_irq_cp0_disable(irq);
122}
123
124static void
125tx4938_irq_cp0_enable(unsigned int irq)
126{
127 unsigned long flags;
128
129 spin_lock_irqsave(&tx4938_cp0_lock, flags);
130
131 set_c0_status(tx4938_irq_cp0_mask(irq));
132
133 spin_unlock_irqrestore(&tx4938_cp0_lock, flags);
134}
135
136static void
137tx4938_irq_cp0_disable(unsigned int irq)
138{
139 unsigned long flags;
140
141 spin_lock_irqsave(&tx4938_cp0_lock, flags);
142
143 clear_c0_status(tx4938_irq_cp0_mask(irq));
144
145 spin_unlock_irqrestore(&tx4938_cp0_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000146}
147
148static void
149tx4938_irq_cp0_mask_and_ack(unsigned int irq)
150{
151 tx4938_irq_cp0_disable(irq);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000152}
153
154static void
155tx4938_irq_cp0_end(unsigned int irq)
156{
157 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
158 tx4938_irq_cp0_enable(irq);
159 }
Ralf Baechle23fbee92005-07-25 22:45:45 +0000160}
161
162/**********************************************************************************/
163/* Functions for pic */
164/**********************************************************************************/
165
166u32
167tx4938_irq_pic_addr(int irq)
168{
169 /* MVMCP -- need to formulize this */
170 irq -= TX4938_IRQ_PIC_BEG;
171
172 switch (irq) {
173 case 17:
174 case 16:
175 case 1:
176 case 0:{
177 return (TX4938_MKA(TX4938_IRC_IRLVL0));
178 }
179 case 19:
180 case 18:
181 case 3:
182 case 2:{
183 return (TX4938_MKA(TX4938_IRC_IRLVL1));
184 }
185 case 21:
186 case 20:
187 case 5:
188 case 4:{
189 return (TX4938_MKA(TX4938_IRC_IRLVL2));
190 }
191 case 23:
192 case 22:
193 case 7:
194 case 6:{
195 return (TX4938_MKA(TX4938_IRC_IRLVL3));
196 }
197 case 25:
198 case 24:
199 case 9:
200 case 8:{
201 return (TX4938_MKA(TX4938_IRC_IRLVL4));
202 }
203 case 27:
204 case 26:
205 case 11:
206 case 10:{
207 return (TX4938_MKA(TX4938_IRC_IRLVL5));
208 }
209 case 29:
210 case 28:
211 case 13:
212 case 12:{
213 return (TX4938_MKA(TX4938_IRC_IRLVL6));
214 }
215 case 31:
216 case 30:
217 case 15:
218 case 14:{
219 return (TX4938_MKA(TX4938_IRC_IRLVL7));
220 }
221 }
222
Ralf Baechle937a8012006-10-07 19:44:33 +0100223 return 0;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000224}
225
226u32
227tx4938_irq_pic_mask(int irq)
228{
229 /* MVMCP -- need to formulize this */
230 irq -= TX4938_IRQ_PIC_BEG;
231
232 switch (irq) {
233 case 31:
234 case 29:
235 case 27:
236 case 25:
237 case 23:
238 case 21:
239 case 19:
240 case 17:{
241 return (0x07000000);
242 }
243 case 30:
244 case 28:
245 case 26:
246 case 24:
247 case 22:
248 case 20:
249 case 18:
250 case 16:{
251 return (0x00070000);
252 }
253 case 15:
254 case 13:
255 case 11:
256 case 9:
257 case 7:
258 case 5:
259 case 3:
260 case 1:{
261 return (0x00000700);
262 }
263 case 14:
264 case 12:
265 case 10:
266 case 8:
267 case 6:
268 case 4:
269 case 2:
270 case 0:{
271 return (0x00000007);
272 }
273 }
Ralf Baechle937a8012006-10-07 19:44:33 +0100274 return 0x00000000;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000275}
276
277static void
278tx4938_irq_pic_modify(unsigned pic_reg, unsigned clr_bits, unsigned set_bits)
279{
280 unsigned long val = 0;
281
282 val = TX4938_RD(pic_reg);
283 val &= (~clr_bits);
284 val |= (set_bits);
285 TX4938_WR(pic_reg, val);
286 mmiowb();
287 TX4938_RD(pic_reg);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000288}
289
290static void __init
291tx4938_irq_pic_init(void)
292{
293 unsigned long flags;
294 int i;
295
296 for (i = TX4938_IRQ_PIC_BEG; i <= TX4938_IRQ_PIC_END; i++) {
297 irq_desc[i].status = IRQ_DISABLED;
298 irq_desc[i].action = 0;
299 irq_desc[i].depth = 2;
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700300 irq_desc[i].chip = &tx4938_irq_pic_type;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000301 }
302
303 setup_irq(TX4938_IRQ_NEST_PIC_ON_CP0, &tx4938_irq_pic_action);
304
305 spin_lock_irqsave(&tx4938_pic_lock, flags);
306
307 TX4938_WR(0xff1ff640, 0x6); /* irq level mask -- only accept hightest */
308 TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */
309
310 spin_unlock_irqrestore(&tx4938_pic_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000311}
312
313static unsigned int
314tx4938_irq_pic_startup(unsigned int irq)
315{
316 tx4938_irq_pic_enable(irq);
317
Ralf Baechle937a8012006-10-07 19:44:33 +0100318 return 0;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000319}
320
321static void
322tx4938_irq_pic_shutdown(unsigned int irq)
323{
324 tx4938_irq_pic_disable(irq);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000325}
326
327static void
328tx4938_irq_pic_enable(unsigned int irq)
329{
330 unsigned long flags;
331
332 spin_lock_irqsave(&tx4938_pic_lock, flags);
333
334 tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq), 0,
335 tx4938_irq_pic_mask(irq));
336
337 spin_unlock_irqrestore(&tx4938_pic_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000338}
339
340static void
341tx4938_irq_pic_disable(unsigned int irq)
342{
343 unsigned long flags;
344
345 spin_lock_irqsave(&tx4938_pic_lock, flags);
346
347 tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq),
348 tx4938_irq_pic_mask(irq), 0);
349
350 spin_unlock_irqrestore(&tx4938_pic_lock, flags);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000351}
352
353static void
354tx4938_irq_pic_mask_and_ack(unsigned int irq)
355{
356 tx4938_irq_pic_disable(irq);
Ralf Baechle23fbee92005-07-25 22:45:45 +0000357}
358
359static void
360tx4938_irq_pic_end(unsigned int irq)
361{
362 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
363 tx4938_irq_pic_enable(irq);
364 }
Ralf Baechle23fbee92005-07-25 22:45:45 +0000365}
366
367/**********************************************************************************/
368/* Main init functions */
369/**********************************************************************************/
370
371void __init
372tx4938_irq_init(void)
373{
Ralf Baechle23fbee92005-07-25 22:45:45 +0000374 tx4938_irq_cp0_init();
375 tx4938_irq_pic_init();
Ralf Baechle23fbee92005-07-25 22:45:45 +0000376}
377
378int
379tx4938_irq_nested(void)
380{
381 int sw_irq = 0;
382 u32 level2;
383
384 level2 = TX4938_RD(0xff1ff6a0);
385 if ((level2 & 0x10000) == 0) {
386 level2 &= 0x1f;
387 sw_irq = TX4938_IRQ_PIC_BEG + level2;
388 if (sw_irq == 26) {
389 {
390 extern int toshiba_rbtx4938_irq_nested(int sw_irq);
391 sw_irq = toshiba_rbtx4938_irq_nested(sw_irq);
392 }
393 }
394 }
395
396 wbflush();
Ralf Baechle937a8012006-10-07 19:44:33 +0100397 return sw_irq;
Ralf Baechle23fbee92005-07-25 22:45:45 +0000398}
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100399
Ralf Baechle937a8012006-10-07 19:44:33 +0100400asmlinkage void plat_irq_dispatch(void)
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100401{
402 unsigned int pending = read_c0_cause() & read_c0_status();
403
404 if (pending & STATUSF_IP7)
Ralf Baechle937a8012006-10-07 19:44:33 +0100405 do_IRQ(TX4938_IRQ_CPU_TIMER);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100406 else if (pending & STATUSF_IP2) {
407 int irq = tx4938_irq_nested();
408 if (irq)
Ralf Baechle937a8012006-10-07 19:44:33 +0100409 do_IRQ(irq);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100410 else
Ralf Baechle937a8012006-10-07 19:44:33 +0100411 spurious_interrupt();
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100412 } else if (pending & STATUSF_IP1)
Ralf Baechle937a8012006-10-07 19:44:33 +0100413 do_IRQ(TX4938_IRQ_USER1);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100414 else if (pending & STATUSF_IP0)
Ralf Baechle937a8012006-10-07 19:44:33 +0100415 do_IRQ(TX4938_IRQ_USER0);
Ralf Baechlee4ac58a2006-04-03 17:56:36 +0100416}