]>
Commit | Line | Data |
---|---|---|
23fbee9d | 1 | /* |
f30c2269 | 2 | * linux/arch/mips/tx4938/common/irq.c |
23fbee9d RB |
3 | * |
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> | |
f5c70dd7 | 33 | #include <asm/wbflush.h> |
23fbee9d RB |
34 | #include <asm/tx4938/rbtx4938.h> |
35 | ||
36 | /**********************************************************************************/ | |
37 | /* Forwad definitions for all pic's */ | |
38 | /**********************************************************************************/ | |
39 | ||
23fbee9d RB |
40 | static void tx4938_irq_cp0_enable(unsigned int irq); |
41 | static void tx4938_irq_cp0_disable(unsigned int irq); | |
23fbee9d RB |
42 | static void tx4938_irq_cp0_end(unsigned int irq); |
43 | ||
23fbee9d RB |
44 | static void tx4938_irq_pic_enable(unsigned int irq); |
45 | static void tx4938_irq_pic_disable(unsigned int irq); | |
23fbee9d RB |
46 | static void tx4938_irq_pic_end(unsigned int irq); |
47 | ||
48 | /**********************************************************************************/ | |
49 | /* Kernel structs for all pic's */ | |
50 | /**********************************************************************************/ | |
23fbee9d RB |
51 | |
52 | #define TX4938_CP0_NAME "TX4938-CP0" | |
94dee171 | 53 | static struct irq_chip tx4938_irq_cp0_type = { |
23fbee9d | 54 | .typename = TX4938_CP0_NAME, |
1603b5ac AN |
55 | .ack = tx4938_irq_cp0_disable, |
56 | .mask = tx4938_irq_cp0_disable, | |
57 | .mask_ack = tx4938_irq_cp0_disable, | |
58 | .unmask = tx4938_irq_cp0_enable, | |
23fbee9d | 59 | .end = tx4938_irq_cp0_end, |
23fbee9d RB |
60 | }; |
61 | ||
62 | #define TX4938_PIC_NAME "TX4938-PIC" | |
94dee171 | 63 | static struct irq_chip tx4938_irq_pic_type = { |
23fbee9d | 64 | .typename = TX4938_PIC_NAME, |
1603b5ac AN |
65 | .ack = tx4938_irq_pic_disable, |
66 | .mask = tx4938_irq_pic_disable, | |
67 | .mask_ack = tx4938_irq_pic_disable, | |
68 | .unmask = tx4938_irq_pic_enable, | |
23fbee9d | 69 | .end = tx4938_irq_pic_end, |
23fbee9d RB |
70 | }; |
71 | ||
72 | static struct irqaction tx4938_irq_pic_action = { | |
73 | .handler = no_action, | |
74 | .flags = 0, | |
75 | .mask = CPU_MASK_NONE, | |
76 | .name = TX4938_PIC_NAME | |
77 | }; | |
78 | ||
79 | /**********************************************************************************/ | |
80 | /* Functions for cp0 */ | |
81 | /**********************************************************************************/ | |
82 | ||
83 | #define tx4938_irq_cp0_mask(irq) ( 1 << ( irq-TX4938_IRQ_CP0_BEG+8 ) ) | |
84 | ||
85 | static void __init | |
86 | tx4938_irq_cp0_init(void) | |
87 | { | |
88 | int i; | |
89 | ||
1603b5ac | 90 | for (i = TX4938_IRQ_CP0_BEG; i <= TX4938_IRQ_CP0_END; i++) |
1417836e AN |
91 | set_irq_chip_and_handler(i, &tx4938_irq_cp0_type, |
92 | handle_level_irq); | |
23fbee9d RB |
93 | } |
94 | ||
95 | static void | |
96 | tx4938_irq_cp0_enable(unsigned int irq) | |
97 | { | |
23fbee9d | 98 | set_c0_status(tx4938_irq_cp0_mask(irq)); |
23fbee9d RB |
99 | } |
100 | ||
101 | static void | |
102 | tx4938_irq_cp0_disable(unsigned int irq) | |
103 | { | |
23fbee9d | 104 | clear_c0_status(tx4938_irq_cp0_mask(irq)); |
23fbee9d RB |
105 | } |
106 | ||
107 | static void | |
108 | tx4938_irq_cp0_end(unsigned int irq) | |
109 | { | |
110 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | |
111 | tx4938_irq_cp0_enable(irq); | |
112 | } | |
23fbee9d RB |
113 | } |
114 | ||
115 | /**********************************************************************************/ | |
116 | /* Functions for pic */ | |
117 | /**********************************************************************************/ | |
118 | ||
119 | u32 | |
120 | tx4938_irq_pic_addr(int irq) | |
121 | { | |
122 | /* MVMCP -- need to formulize this */ | |
123 | irq -= TX4938_IRQ_PIC_BEG; | |
124 | ||
125 | switch (irq) { | |
126 | case 17: | |
127 | case 16: | |
128 | case 1: | |
129 | case 0:{ | |
130 | return (TX4938_MKA(TX4938_IRC_IRLVL0)); | |
131 | } | |
132 | case 19: | |
133 | case 18: | |
134 | case 3: | |
135 | case 2:{ | |
136 | return (TX4938_MKA(TX4938_IRC_IRLVL1)); | |
137 | } | |
138 | case 21: | |
139 | case 20: | |
140 | case 5: | |
141 | case 4:{ | |
142 | return (TX4938_MKA(TX4938_IRC_IRLVL2)); | |
143 | } | |
144 | case 23: | |
145 | case 22: | |
146 | case 7: | |
147 | case 6:{ | |
148 | return (TX4938_MKA(TX4938_IRC_IRLVL3)); | |
149 | } | |
150 | case 25: | |
151 | case 24: | |
152 | case 9: | |
153 | case 8:{ | |
154 | return (TX4938_MKA(TX4938_IRC_IRLVL4)); | |
155 | } | |
156 | case 27: | |
157 | case 26: | |
158 | case 11: | |
159 | case 10:{ | |
160 | return (TX4938_MKA(TX4938_IRC_IRLVL5)); | |
161 | } | |
162 | case 29: | |
163 | case 28: | |
164 | case 13: | |
165 | case 12:{ | |
166 | return (TX4938_MKA(TX4938_IRC_IRLVL6)); | |
167 | } | |
168 | case 31: | |
169 | case 30: | |
170 | case 15: | |
171 | case 14:{ | |
172 | return (TX4938_MKA(TX4938_IRC_IRLVL7)); | |
173 | } | |
174 | } | |
175 | ||
937a8015 | 176 | return 0; |
23fbee9d RB |
177 | } |
178 | ||
179 | u32 | |
180 | tx4938_irq_pic_mask(int irq) | |
181 | { | |
182 | /* MVMCP -- need to formulize this */ | |
183 | irq -= TX4938_IRQ_PIC_BEG; | |
184 | ||
185 | switch (irq) { | |
186 | case 31: | |
187 | case 29: | |
188 | case 27: | |
189 | case 25: | |
190 | case 23: | |
191 | case 21: | |
192 | case 19: | |
193 | case 17:{ | |
194 | return (0x07000000); | |
195 | } | |
196 | case 30: | |
197 | case 28: | |
198 | case 26: | |
199 | case 24: | |
200 | case 22: | |
201 | case 20: | |
202 | case 18: | |
203 | case 16:{ | |
204 | return (0x00070000); | |
205 | } | |
206 | case 15: | |
207 | case 13: | |
208 | case 11: | |
209 | case 9: | |
210 | case 7: | |
211 | case 5: | |
212 | case 3: | |
213 | case 1:{ | |
214 | return (0x00000700); | |
215 | } | |
216 | case 14: | |
217 | case 12: | |
218 | case 10: | |
219 | case 8: | |
220 | case 6: | |
221 | case 4: | |
222 | case 2: | |
223 | case 0:{ | |
224 | return (0x00000007); | |
225 | } | |
226 | } | |
937a8015 | 227 | return 0x00000000; |
23fbee9d RB |
228 | } |
229 | ||
230 | static void | |
231 | tx4938_irq_pic_modify(unsigned pic_reg, unsigned clr_bits, unsigned set_bits) | |
232 | { | |
233 | unsigned long val = 0; | |
234 | ||
235 | val = TX4938_RD(pic_reg); | |
236 | val &= (~clr_bits); | |
237 | val |= (set_bits); | |
238 | TX4938_WR(pic_reg, val); | |
239 | mmiowb(); | |
240 | TX4938_RD(pic_reg); | |
23fbee9d RB |
241 | } |
242 | ||
243 | static void __init | |
244 | tx4938_irq_pic_init(void) | |
245 | { | |
23fbee9d RB |
246 | int i; |
247 | ||
1603b5ac | 248 | for (i = TX4938_IRQ_PIC_BEG; i <= TX4938_IRQ_PIC_END; i++) |
1417836e AN |
249 | set_irq_chip_and_handler(i, &tx4938_irq_pic_type, |
250 | handle_level_irq); | |
23fbee9d RB |
251 | |
252 | setup_irq(TX4938_IRQ_NEST_PIC_ON_CP0, &tx4938_irq_pic_action); | |
253 | ||
23fbee9d RB |
254 | TX4938_WR(0xff1ff640, 0x6); /* irq level mask -- only accept hightest */ |
255 | TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */ | |
23fbee9d RB |
256 | } |
257 | ||
258 | static void | |
259 | tx4938_irq_pic_enable(unsigned int irq) | |
260 | { | |
23fbee9d RB |
261 | tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq), 0, |
262 | tx4938_irq_pic_mask(irq)); | |
23fbee9d RB |
263 | } |
264 | ||
265 | static void | |
266 | tx4938_irq_pic_disable(unsigned int irq) | |
267 | { | |
23fbee9d RB |
268 | tx4938_irq_pic_modify(tx4938_irq_pic_addr(irq), |
269 | tx4938_irq_pic_mask(irq), 0); | |
23fbee9d RB |
270 | } |
271 | ||
272 | static void | |
273 | tx4938_irq_pic_end(unsigned int irq) | |
274 | { | |
275 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { | |
276 | tx4938_irq_pic_enable(irq); | |
277 | } | |
23fbee9d RB |
278 | } |
279 | ||
280 | /**********************************************************************************/ | |
281 | /* Main init functions */ | |
282 | /**********************************************************************************/ | |
283 | ||
284 | void __init | |
285 | tx4938_irq_init(void) | |
286 | { | |
23fbee9d RB |
287 | tx4938_irq_cp0_init(); |
288 | tx4938_irq_pic_init(); | |
23fbee9d RB |
289 | } |
290 | ||
291 | int | |
292 | tx4938_irq_nested(void) | |
293 | { | |
294 | int sw_irq = 0; | |
295 | u32 level2; | |
296 | ||
297 | level2 = TX4938_RD(0xff1ff6a0); | |
298 | if ((level2 & 0x10000) == 0) { | |
299 | level2 &= 0x1f; | |
300 | sw_irq = TX4938_IRQ_PIC_BEG + level2; | |
301 | if (sw_irq == 26) { | |
302 | { | |
303 | extern int toshiba_rbtx4938_irq_nested(int sw_irq); | |
304 | sw_irq = toshiba_rbtx4938_irq_nested(sw_irq); | |
305 | } | |
306 | } | |
307 | } | |
308 | ||
309 | wbflush(); | |
937a8015 | 310 | return sw_irq; |
23fbee9d | 311 | } |
e4ac58af | 312 | |
937a8015 | 313 | asmlinkage void plat_irq_dispatch(void) |
e4ac58af RB |
314 | { |
315 | unsigned int pending = read_c0_cause() & read_c0_status(); | |
316 | ||
317 | if (pending & STATUSF_IP7) | |
937a8015 | 318 | do_IRQ(TX4938_IRQ_CPU_TIMER); |
e4ac58af RB |
319 | else if (pending & STATUSF_IP2) { |
320 | int irq = tx4938_irq_nested(); | |
321 | if (irq) | |
937a8015 | 322 | do_IRQ(irq); |
e4ac58af | 323 | else |
937a8015 | 324 | spurious_interrupt(); |
e4ac58af | 325 | } else if (pending & STATUSF_IP1) |
937a8015 | 326 | do_IRQ(TX4938_IRQ_USER1); |
e4ac58af | 327 | else if (pending & STATUSF_IP0) |
937a8015 | 328 | do_IRQ(TX4938_IRQ_USER0); |
e4ac58af | 329 | } |