]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * icu.c, Interrupt Control Unit routines for the NEC VR4100 series. | |
3 | * | |
4 | * Copyright (C) 2001-2002 MontaVista Software Inc. | |
5 | * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> | |
6 | * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | |
7 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | /* | |
24 | * Changes: | |
25 | * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com> | |
26 | * - New creation, NEC VR4122 and VR4131 are supported. | |
27 | * - Added support for NEC VR4111 and VR4121. | |
28 | * | |
29 | * Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | |
30 | * - Coped with INTASSIGN of NEC VR4133. | |
31 | */ | |
32 | #include <linux/errno.h> | |
33 | #include <linux/init.h> | |
34 | #include <linux/interrupt.h> | |
35 | #include <linux/irq.h> | |
36 | #include <linux/module.h> | |
37 | #include <linux/smp.h> | |
38 | #include <linux/types.h> | |
39 | ||
40 | #include <asm/cpu.h> | |
41 | #include <asm/io.h> | |
42 | #include <asm/irq.h> | |
43 | #include <asm/irq_cpu.h> | |
44 | #include <asm/vr41xx/vr41xx.h> | |
45 | ||
46 | extern asmlinkage void vr41xx_handle_interrupt(void); | |
47 | ||
48 | extern void init_vr41xx_giuint_irq(void); | |
49 | extern void giuint_irq_dispatch(struct pt_regs *regs); | |
50 | ||
51 | static uint32_t icu1_base; | |
52 | static uint32_t icu2_base; | |
53 | ||
54 | static struct irqaction icu_cascade = { | |
55 | .handler = no_action, | |
56 | .mask = CPU_MASK_NONE, | |
57 | .name = "cascade", | |
58 | }; | |
59 | ||
60 | static unsigned char sysint1_assign[16] = { | |
61 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
62 | static unsigned char sysint2_assign[16] = { | |
63 | 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
64 | ||
65 | #define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080) | |
66 | #define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200) | |
67 | ||
68 | #define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080) | |
69 | #define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0) | |
70 | ||
71 | #define SYSINT1REG 0x00 | |
72 | #define PIUINTREG 0x02 | |
73 | #define INTASSIGN0 0x04 | |
74 | #define INTASSIGN1 0x06 | |
75 | #define GIUINTLREG 0x08 | |
76 | #define DSIUINTREG 0x0a | |
77 | #define MSYSINT1REG 0x0c | |
78 | #define MPIUINTREG 0x0e | |
79 | #define MAIUINTREG 0x10 | |
80 | #define MKIUINTREG 0x12 | |
81 | #define MGIUINTLREG 0x14 | |
82 | #define MDSIUINTREG 0x16 | |
83 | #define NMIREG 0x18 | |
84 | #define SOFTREG 0x1a | |
85 | #define INTASSIGN2 0x1c | |
86 | #define INTASSIGN3 0x1e | |
87 | ||
88 | #define SYSINT2REG 0x00 | |
89 | #define GIUINTHREG 0x02 | |
90 | #define FIRINTREG 0x04 | |
91 | #define MSYSINT2REG 0x06 | |
92 | #define MGIUINTHREG 0x08 | |
93 | #define MFIRINTREG 0x0a | |
94 | #define PCIINTREG 0x0c | |
95 | #define PCIINT0 0x0001 | |
96 | #define SCUINTREG 0x0e | |
97 | #define SCUINT0 0x0001 | |
98 | #define CSIINTREG 0x10 | |
99 | #define MPCIINTREG 0x12 | |
100 | #define MSCUINTREG 0x14 | |
101 | #define MCSIINTREG 0x16 | |
102 | #define BCUINTREG 0x18 | |
103 | #define BCUINTR 0x0001 | |
104 | #define MBCUINTREG 0x1a | |
105 | ||
106 | #define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */ | |
107 | #define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */ | |
108 | ||
109 | #define read_icu1(offset) readw(icu1_base + (offset)) | |
110 | #define write_icu1(val, offset) writew((val), icu1_base + (offset)) | |
111 | ||
112 | #define read_icu2(offset) readw(icu2_base + (offset)) | |
113 | #define write_icu2(val, offset) writew((val), icu2_base + (offset)) | |
114 | ||
115 | #define INTASSIGN_MAX 4 | |
116 | #define INTASSIGN_MASK 0x0007 | |
117 | ||
118 | static inline uint16_t set_icu1(uint8_t offset, uint16_t set) | |
119 | { | |
120 | uint16_t res; | |
121 | ||
122 | res = read_icu1(offset); | |
123 | res |= set; | |
124 | write_icu1(res, offset); | |
125 | ||
126 | return res; | |
127 | } | |
128 | ||
129 | static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear) | |
130 | { | |
131 | uint16_t res; | |
132 | ||
133 | res = read_icu1(offset); | |
134 | res &= ~clear; | |
135 | write_icu1(res, offset); | |
136 | ||
137 | return res; | |
138 | } | |
139 | ||
140 | static inline uint16_t set_icu2(uint8_t offset, uint16_t set) | |
141 | { | |
142 | uint16_t res; | |
143 | ||
144 | res = read_icu2(offset); | |
145 | res |= set; | |
146 | write_icu2(res, offset); | |
147 | ||
148 | return res; | |
149 | } | |
150 | ||
151 | static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear) | |
152 | { | |
153 | uint16_t res; | |
154 | ||
155 | res = read_icu2(offset); | |
156 | res &= ~clear; | |
157 | write_icu2(res, offset); | |
158 | ||
159 | return res; | |
160 | } | |
161 | ||
162 | /*=======================================================================*/ | |
163 | ||
164 | void vr41xx_enable_piuint(uint16_t mask) | |
165 | { | |
166 | irq_desc_t *desc = irq_desc + PIU_IRQ; | |
167 | unsigned long flags; | |
168 | ||
169 | if (current_cpu_data.cputype == CPU_VR4111 || | |
170 | current_cpu_data.cputype == CPU_VR4121) { | |
171 | spin_lock_irqsave(&desc->lock, flags); | |
172 | set_icu1(MPIUINTREG, mask); | |
173 | spin_unlock_irqrestore(&desc->lock, flags); | |
174 | } | |
175 | } | |
176 | ||
177 | EXPORT_SYMBOL(vr41xx_enable_piuint); | |
178 | ||
179 | void vr41xx_disable_piuint(uint16_t mask) | |
180 | { | |
181 | irq_desc_t *desc = irq_desc + PIU_IRQ; | |
182 | unsigned long flags; | |
183 | ||
184 | if (current_cpu_data.cputype == CPU_VR4111 || | |
185 | current_cpu_data.cputype == CPU_VR4121) { | |
186 | spin_lock_irqsave(&desc->lock, flags); | |
187 | clear_icu1(MPIUINTREG, mask); | |
188 | spin_unlock_irqrestore(&desc->lock, flags); | |
189 | } | |
190 | } | |
191 | ||
192 | EXPORT_SYMBOL(vr41xx_disable_piuint); | |
193 | ||
194 | void vr41xx_enable_aiuint(uint16_t mask) | |
195 | { | |
196 | irq_desc_t *desc = irq_desc + AIU_IRQ; | |
197 | unsigned long flags; | |
198 | ||
199 | if (current_cpu_data.cputype == CPU_VR4111 || | |
200 | current_cpu_data.cputype == CPU_VR4121) { | |
201 | spin_lock_irqsave(&desc->lock, flags); | |
202 | set_icu1(MAIUINTREG, mask); | |
203 | spin_unlock_irqrestore(&desc->lock, flags); | |
204 | } | |
205 | } | |
206 | ||
207 | EXPORT_SYMBOL(vr41xx_enable_aiuint); | |
208 | ||
209 | void vr41xx_disable_aiuint(uint16_t mask) | |
210 | { | |
211 | irq_desc_t *desc = irq_desc + AIU_IRQ; | |
212 | unsigned long flags; | |
213 | ||
214 | if (current_cpu_data.cputype == CPU_VR4111 || | |
215 | current_cpu_data.cputype == CPU_VR4121) { | |
216 | spin_lock_irqsave(&desc->lock, flags); | |
217 | clear_icu1(MAIUINTREG, mask); | |
218 | spin_unlock_irqrestore(&desc->lock, flags); | |
219 | } | |
220 | } | |
221 | ||
222 | EXPORT_SYMBOL(vr41xx_disable_aiuint); | |
223 | ||
224 | void vr41xx_enable_kiuint(uint16_t mask) | |
225 | { | |
226 | irq_desc_t *desc = irq_desc + KIU_IRQ; | |
227 | unsigned long flags; | |
228 | ||
229 | if (current_cpu_data.cputype == CPU_VR4111 || | |
230 | current_cpu_data.cputype == CPU_VR4121) { | |
231 | spin_lock_irqsave(&desc->lock, flags); | |
232 | set_icu1(MKIUINTREG, mask); | |
233 | spin_unlock_irqrestore(&desc->lock, flags); | |
234 | } | |
235 | } | |
236 | ||
237 | EXPORT_SYMBOL(vr41xx_enable_kiuint); | |
238 | ||
239 | void vr41xx_disable_kiuint(uint16_t mask) | |
240 | { | |
241 | irq_desc_t *desc = irq_desc + KIU_IRQ; | |
242 | unsigned long flags; | |
243 | ||
244 | if (current_cpu_data.cputype == CPU_VR4111 || | |
245 | current_cpu_data.cputype == CPU_VR4121) { | |
246 | spin_lock_irqsave(&desc->lock, flags); | |
247 | clear_icu1(MKIUINTREG, mask); | |
248 | spin_unlock_irqrestore(&desc->lock, flags); | |
249 | } | |
250 | } | |
251 | ||
252 | EXPORT_SYMBOL(vr41xx_disable_kiuint); | |
253 | ||
254 | void vr41xx_enable_dsiuint(uint16_t mask) | |
255 | { | |
256 | irq_desc_t *desc = irq_desc + DSIU_IRQ; | |
257 | unsigned long flags; | |
258 | ||
259 | spin_lock_irqsave(&desc->lock, flags); | |
260 | set_icu1(MDSIUINTREG, mask); | |
261 | spin_unlock_irqrestore(&desc->lock, flags); | |
262 | } | |
263 | ||
264 | EXPORT_SYMBOL(vr41xx_enable_dsiuint); | |
265 | ||
266 | void vr41xx_disable_dsiuint(uint16_t mask) | |
267 | { | |
268 | irq_desc_t *desc = irq_desc + DSIU_IRQ; | |
269 | unsigned long flags; | |
270 | ||
271 | spin_lock_irqsave(&desc->lock, flags); | |
272 | clear_icu1(MDSIUINTREG, mask); | |
273 | spin_unlock_irqrestore(&desc->lock, flags); | |
274 | } | |
275 | ||
276 | EXPORT_SYMBOL(vr41xx_disable_dsiuint); | |
277 | ||
278 | void vr41xx_enable_firint(uint16_t mask) | |
279 | { | |
280 | irq_desc_t *desc = irq_desc + FIR_IRQ; | |
281 | unsigned long flags; | |
282 | ||
283 | spin_lock_irqsave(&desc->lock, flags); | |
284 | set_icu2(MFIRINTREG, mask); | |
285 | spin_unlock_irqrestore(&desc->lock, flags); | |
286 | } | |
287 | ||
288 | EXPORT_SYMBOL(vr41xx_enable_firint); | |
289 | ||
290 | void vr41xx_disable_firint(uint16_t mask) | |
291 | { | |
292 | irq_desc_t *desc = irq_desc + FIR_IRQ; | |
293 | unsigned long flags; | |
294 | ||
295 | spin_lock_irqsave(&desc->lock, flags); | |
296 | clear_icu2(MFIRINTREG, mask); | |
297 | spin_unlock_irqrestore(&desc->lock, flags); | |
298 | } | |
299 | ||
300 | EXPORT_SYMBOL(vr41xx_disable_firint); | |
301 | ||
302 | void vr41xx_enable_pciint(void) | |
303 | { | |
304 | irq_desc_t *desc = irq_desc + PCI_IRQ; | |
305 | unsigned long flags; | |
306 | ||
307 | if (current_cpu_data.cputype == CPU_VR4122 || | |
308 | current_cpu_data.cputype == CPU_VR4131 || | |
309 | current_cpu_data.cputype == CPU_VR4133) { | |
310 | spin_lock_irqsave(&desc->lock, flags); | |
311 | write_icu2(PCIINT0, MPCIINTREG); | |
312 | spin_unlock_irqrestore(&desc->lock, flags); | |
313 | } | |
314 | } | |
315 | ||
316 | EXPORT_SYMBOL(vr41xx_enable_pciint); | |
317 | ||
318 | void vr41xx_disable_pciint(void) | |
319 | { | |
320 | irq_desc_t *desc = irq_desc + PCI_IRQ; | |
321 | unsigned long flags; | |
322 | ||
323 | if (current_cpu_data.cputype == CPU_VR4122 || | |
324 | current_cpu_data.cputype == CPU_VR4131 || | |
325 | current_cpu_data.cputype == CPU_VR4133) { | |
326 | spin_lock_irqsave(&desc->lock, flags); | |
327 | write_icu2(0, MPCIINTREG); | |
328 | spin_unlock_irqrestore(&desc->lock, flags); | |
329 | } | |
330 | } | |
331 | ||
332 | EXPORT_SYMBOL(vr41xx_disable_pciint); | |
333 | ||
334 | void vr41xx_enable_scuint(void) | |
335 | { | |
336 | irq_desc_t *desc = irq_desc + SCU_IRQ; | |
337 | unsigned long flags; | |
338 | ||
339 | if (current_cpu_data.cputype == CPU_VR4122 || | |
340 | current_cpu_data.cputype == CPU_VR4131 || | |
341 | current_cpu_data.cputype == CPU_VR4133) { | |
342 | spin_lock_irqsave(&desc->lock, flags); | |
343 | write_icu2(SCUINT0, MSCUINTREG); | |
344 | spin_unlock_irqrestore(&desc->lock, flags); | |
345 | } | |
346 | } | |
347 | ||
348 | EXPORT_SYMBOL(vr41xx_enable_scuint); | |
349 | ||
350 | void vr41xx_disable_scuint(void) | |
351 | { | |
352 | irq_desc_t *desc = irq_desc + SCU_IRQ; | |
353 | unsigned long flags; | |
354 | ||
355 | if (current_cpu_data.cputype == CPU_VR4122 || | |
356 | current_cpu_data.cputype == CPU_VR4131 || | |
357 | current_cpu_data.cputype == CPU_VR4133) { | |
358 | spin_lock_irqsave(&desc->lock, flags); | |
359 | write_icu2(0, MSCUINTREG); | |
360 | spin_unlock_irqrestore(&desc->lock, flags); | |
361 | } | |
362 | } | |
363 | ||
364 | EXPORT_SYMBOL(vr41xx_disable_scuint); | |
365 | ||
366 | void vr41xx_enable_csiint(uint16_t mask) | |
367 | { | |
368 | irq_desc_t *desc = irq_desc + CSI_IRQ; | |
369 | unsigned long flags; | |
370 | ||
371 | if (current_cpu_data.cputype == CPU_VR4122 || | |
372 | current_cpu_data.cputype == CPU_VR4131 || | |
373 | current_cpu_data.cputype == CPU_VR4133) { | |
374 | spin_lock_irqsave(&desc->lock, flags); | |
375 | set_icu2(MCSIINTREG, mask); | |
376 | spin_unlock_irqrestore(&desc->lock, flags); | |
377 | } | |
378 | } | |
379 | ||
380 | EXPORT_SYMBOL(vr41xx_enable_csiint); | |
381 | ||
382 | void vr41xx_disable_csiint(uint16_t mask) | |
383 | { | |
384 | irq_desc_t *desc = irq_desc + CSI_IRQ; | |
385 | unsigned long flags; | |
386 | ||
387 | if (current_cpu_data.cputype == CPU_VR4122 || | |
388 | current_cpu_data.cputype == CPU_VR4131 || | |
389 | current_cpu_data.cputype == CPU_VR4133) { | |
390 | spin_lock_irqsave(&desc->lock, flags); | |
391 | clear_icu2(MCSIINTREG, mask); | |
392 | spin_unlock_irqrestore(&desc->lock, flags); | |
393 | } | |
394 | } | |
395 | ||
396 | EXPORT_SYMBOL(vr41xx_disable_csiint); | |
397 | ||
398 | void vr41xx_enable_bcuint(void) | |
399 | { | |
400 | irq_desc_t *desc = irq_desc + BCU_IRQ; | |
401 | unsigned long flags; | |
402 | ||
403 | if (current_cpu_data.cputype == CPU_VR4122 || | |
404 | current_cpu_data.cputype == CPU_VR4131 || | |
405 | current_cpu_data.cputype == CPU_VR4133) { | |
406 | spin_lock_irqsave(&desc->lock, flags); | |
407 | write_icu2(BCUINTR, MBCUINTREG); | |
408 | spin_unlock_irqrestore(&desc->lock, flags); | |
409 | } | |
410 | } | |
411 | ||
412 | EXPORT_SYMBOL(vr41xx_enable_bcuint); | |
413 | ||
414 | void vr41xx_disable_bcuint(void) | |
415 | { | |
416 | irq_desc_t *desc = irq_desc + BCU_IRQ; | |
417 | unsigned long flags; | |
418 | ||
419 | if (current_cpu_data.cputype == CPU_VR4122 || | |
420 | current_cpu_data.cputype == CPU_VR4131 || | |
421 | current_cpu_data.cputype == CPU_VR4133) { | |
422 | spin_lock_irqsave(&desc->lock, flags); | |
423 | write_icu2(0, MBCUINTREG); | |
424 | spin_unlock_irqrestore(&desc->lock, flags); | |
425 | } | |
426 | } | |
427 | ||
428 | EXPORT_SYMBOL(vr41xx_disable_bcuint); | |
429 | ||
430 | /*=======================================================================*/ | |
431 | ||
432 | static unsigned int startup_sysint1_irq(unsigned int irq) | |
433 | { | |
434 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | |
435 | ||
436 | return 0; /* never anything pending */ | |
437 | } | |
438 | ||
439 | static void shutdown_sysint1_irq(unsigned int irq) | |
440 | { | |
441 | clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | |
442 | } | |
443 | ||
444 | static void enable_sysint1_irq(unsigned int irq) | |
445 | { | |
446 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | |
447 | } | |
448 | ||
449 | #define disable_sysint1_irq shutdown_sysint1_irq | |
450 | #define ack_sysint1_irq shutdown_sysint1_irq | |
451 | ||
452 | static void end_sysint1_irq(unsigned int irq) | |
453 | { | |
454 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | |
455 | set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq)); | |
456 | } | |
457 | ||
458 | static struct hw_interrupt_type sysint1_irq_type = { | |
459 | .typename = "SYSINT1", | |
460 | .startup = startup_sysint1_irq, | |
461 | .shutdown = shutdown_sysint1_irq, | |
462 | .enable = enable_sysint1_irq, | |
463 | .disable = disable_sysint1_irq, | |
464 | .ack = ack_sysint1_irq, | |
465 | .end = end_sysint1_irq, | |
466 | }; | |
467 | ||
468 | /*=======================================================================*/ | |
469 | ||
470 | static unsigned int startup_sysint2_irq(unsigned int irq) | |
471 | { | |
472 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | |
473 | ||
474 | return 0; /* never anything pending */ | |
475 | } | |
476 | ||
477 | static void shutdown_sysint2_irq(unsigned int irq) | |
478 | { | |
479 | clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | |
480 | } | |
481 | ||
482 | static void enable_sysint2_irq(unsigned int irq) | |
483 | { | |
484 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | |
485 | } | |
486 | ||
487 | #define disable_sysint2_irq shutdown_sysint2_irq | |
488 | #define ack_sysint2_irq shutdown_sysint2_irq | |
489 | ||
490 | static void end_sysint2_irq(unsigned int irq) | |
491 | { | |
492 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | |
493 | set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq)); | |
494 | } | |
495 | ||
496 | static struct hw_interrupt_type sysint2_irq_type = { | |
497 | .typename = "SYSINT2", | |
498 | .startup = startup_sysint2_irq, | |
499 | .shutdown = shutdown_sysint2_irq, | |
500 | .enable = enable_sysint2_irq, | |
501 | .disable = disable_sysint2_irq, | |
502 | .ack = ack_sysint2_irq, | |
503 | .end = end_sysint2_irq, | |
504 | }; | |
505 | ||
506 | /*=======================================================================*/ | |
507 | ||
508 | static inline int set_sysint1_assign(unsigned int irq, unsigned char assign) | |
509 | { | |
510 | irq_desc_t *desc = irq_desc + irq; | |
511 | uint16_t intassign0, intassign1; | |
512 | unsigned int pin; | |
513 | ||
514 | pin = SYSINT1_IRQ_TO_PIN(irq); | |
515 | ||
516 | spin_lock_irq(&desc->lock); | |
517 | ||
518 | intassign0 = read_icu1(INTASSIGN0); | |
519 | intassign1 = read_icu1(INTASSIGN1); | |
520 | ||
521 | switch (pin) { | |
522 | case 0: | |
523 | intassign0 &= ~INTASSIGN_MASK; | |
524 | intassign0 |= (uint16_t)assign; | |
525 | break; | |
526 | case 1: | |
527 | intassign0 &= ~(INTASSIGN_MASK << 3); | |
528 | intassign0 |= (uint16_t)assign << 3; | |
529 | break; | |
530 | case 2: | |
531 | intassign0 &= ~(INTASSIGN_MASK << 6); | |
532 | intassign0 |= (uint16_t)assign << 6; | |
533 | break; | |
534 | case 3: | |
535 | intassign0 &= ~(INTASSIGN_MASK << 9); | |
536 | intassign0 |= (uint16_t)assign << 9; | |
537 | break; | |
538 | case 8: | |
539 | intassign0 &= ~(INTASSIGN_MASK << 12); | |
540 | intassign0 |= (uint16_t)assign << 12; | |
541 | break; | |
542 | case 9: | |
543 | intassign1 &= ~INTASSIGN_MASK; | |
544 | intassign1 |= (uint16_t)assign; | |
545 | break; | |
546 | case 11: | |
547 | intassign1 &= ~(INTASSIGN_MASK << 6); | |
548 | intassign1 |= (uint16_t)assign << 6; | |
549 | break; | |
550 | case 12: | |
551 | intassign1 &= ~(INTASSIGN_MASK << 9); | |
552 | intassign1 |= (uint16_t)assign << 9; | |
553 | break; | |
554 | default: | |
555 | return -EINVAL; | |
556 | } | |
557 | ||
558 | sysint1_assign[pin] = assign; | |
559 | write_icu1(intassign0, INTASSIGN0); | |
560 | write_icu1(intassign1, INTASSIGN1); | |
561 | ||
562 | spin_unlock_irq(&desc->lock); | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
567 | static inline int set_sysint2_assign(unsigned int irq, unsigned char assign) | |
568 | { | |
569 | irq_desc_t *desc = irq_desc + irq; | |
570 | uint16_t intassign2, intassign3; | |
571 | unsigned int pin; | |
572 | ||
573 | pin = SYSINT2_IRQ_TO_PIN(irq); | |
574 | ||
575 | spin_lock_irq(&desc->lock); | |
576 | ||
577 | intassign2 = read_icu1(INTASSIGN2); | |
578 | intassign3 = read_icu1(INTASSIGN3); | |
579 | ||
580 | switch (pin) { | |
581 | case 0: | |
582 | intassign2 &= ~INTASSIGN_MASK; | |
583 | intassign2 |= (uint16_t)assign; | |
584 | break; | |
585 | case 1: | |
586 | intassign2 &= ~(INTASSIGN_MASK << 3); | |
587 | intassign2 |= (uint16_t)assign << 3; | |
588 | break; | |
589 | case 3: | |
590 | intassign2 &= ~(INTASSIGN_MASK << 6); | |
591 | intassign2 |= (uint16_t)assign << 6; | |
592 | break; | |
593 | case 4: | |
594 | intassign2 &= ~(INTASSIGN_MASK << 9); | |
595 | intassign2 |= (uint16_t)assign << 9; | |
596 | break; | |
597 | case 5: | |
598 | intassign2 &= ~(INTASSIGN_MASK << 12); | |
599 | intassign2 |= (uint16_t)assign << 12; | |
600 | break; | |
601 | case 6: | |
602 | intassign3 &= ~INTASSIGN_MASK; | |
603 | intassign3 |= (uint16_t)assign; | |
604 | break; | |
605 | case 7: | |
606 | intassign3 &= ~(INTASSIGN_MASK << 3); | |
607 | intassign3 |= (uint16_t)assign << 3; | |
608 | break; | |
609 | case 8: | |
610 | intassign3 &= ~(INTASSIGN_MASK << 6); | |
611 | intassign3 |= (uint16_t)assign << 6; | |
612 | break; | |
613 | case 9: | |
614 | intassign3 &= ~(INTASSIGN_MASK << 9); | |
615 | intassign3 |= (uint16_t)assign << 9; | |
616 | break; | |
617 | case 10: | |
618 | intassign3 &= ~(INTASSIGN_MASK << 12); | |
619 | intassign3 |= (uint16_t)assign << 12; | |
620 | break; | |
621 | default: | |
622 | return -EINVAL; | |
623 | } | |
624 | ||
625 | sysint2_assign[pin] = assign; | |
626 | write_icu1(intassign2, INTASSIGN2); | |
627 | write_icu1(intassign3, INTASSIGN3); | |
628 | ||
629 | spin_unlock_irq(&desc->lock); | |
630 | ||
631 | return 0; | |
632 | } | |
633 | ||
634 | int vr41xx_set_intassign(unsigned int irq, unsigned char intassign) | |
635 | { | |
636 | int retval = -EINVAL; | |
637 | ||
638 | if (current_cpu_data.cputype != CPU_VR4133) | |
639 | return -EINVAL; | |
640 | ||
641 | if (intassign > INTASSIGN_MAX) | |
642 | return -EINVAL; | |
643 | ||
644 | if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST) | |
645 | retval = set_sysint1_assign(irq, intassign); | |
646 | else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST) | |
647 | retval = set_sysint2_assign(irq, intassign); | |
648 | ||
649 | return retval; | |
650 | } | |
651 | ||
652 | EXPORT_SYMBOL(vr41xx_set_intassign); | |
653 | ||
654 | /*=======================================================================*/ | |
655 | ||
656 | asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs) | |
657 | { | |
658 | uint16_t pend1, pend2; | |
659 | uint16_t mask1, mask2; | |
660 | int i; | |
661 | ||
662 | pend1 = read_icu1(SYSINT1REG); | |
663 | mask1 = read_icu1(MSYSINT1REG); | |
664 | ||
665 | pend2 = read_icu2(SYSINT2REG); | |
666 | mask2 = read_icu2(MSYSINT2REG); | |
667 | ||
668 | mask1 &= pend1; | |
669 | mask2 &= pend2; | |
670 | ||
671 | if (mask1) { | |
672 | for (i = 0; i < 16; i++) { | |
673 | if (intnum == sysint1_assign[i] && | |
674 | (mask1 & ((uint16_t)1 << i))) { | |
675 | if (i == 8) | |
676 | giuint_irq_dispatch(regs); | |
677 | else | |
678 | do_IRQ(SYSINT1_IRQ(i), regs); | |
679 | return; | |
680 | } | |
681 | } | |
682 | } | |
683 | ||
684 | if (mask2) { | |
685 | for (i = 0; i < 16; i++) { | |
686 | if (intnum == sysint2_assign[i] && | |
687 | (mask2 & ((uint16_t)1 << i))) { | |
688 | do_IRQ(SYSINT2_IRQ(i), regs); | |
689 | return; | |
690 | } | |
691 | } | |
692 | } | |
693 | ||
694 | printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2); | |
695 | ||
696 | atomic_inc(&irq_err_count); | |
697 | } | |
698 | ||
699 | /*=======================================================================*/ | |
700 | ||
701 | static int __init vr41xx_icu_init(void) | |
702 | { | |
703 | switch (current_cpu_data.cputype) { | |
704 | case CPU_VR4111: | |
705 | case CPU_VR4121: | |
706 | icu1_base = SYSINT1REG_TYPE1; | |
707 | icu2_base = SYSINT2REG_TYPE1; | |
708 | break; | |
709 | case CPU_VR4122: | |
710 | case CPU_VR4131: | |
711 | case CPU_VR4133: | |
712 | icu1_base = SYSINT1REG_TYPE2; | |
713 | icu2_base = SYSINT2REG_TYPE2; | |
714 | break; | |
715 | default: | |
716 | printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n"); | |
717 | return -EINVAL; | |
718 | } | |
719 | ||
720 | write_icu1(0, MSYSINT1REG); | |
721 | write_icu1(0xffff, MGIUINTLREG); | |
722 | ||
723 | write_icu2(0, MSYSINT2REG); | |
724 | write_icu2(0xffff, MGIUINTHREG); | |
725 | ||
726 | return 0; | |
727 | } | |
728 | ||
729 | early_initcall(vr41xx_icu_init); | |
730 | ||
731 | /*=======================================================================*/ | |
732 | ||
733 | static inline void init_vr41xx_icu_irq(void) | |
734 | { | |
735 | int i; | |
736 | ||
737 | for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++) | |
738 | irq_desc[i].handler = &sysint1_irq_type; | |
739 | ||
740 | for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++) | |
741 | irq_desc[i].handler = &sysint2_irq_type; | |
742 | ||
743 | setup_irq(INT0_CASCADE_IRQ, &icu_cascade); | |
744 | setup_irq(INT1_CASCADE_IRQ, &icu_cascade); | |
745 | setup_irq(INT2_CASCADE_IRQ, &icu_cascade); | |
746 | setup_irq(INT3_CASCADE_IRQ, &icu_cascade); | |
747 | setup_irq(INT4_CASCADE_IRQ, &icu_cascade); | |
748 | } | |
749 | ||
750 | void __init arch_init_irq(void) | |
751 | { | |
752 | mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); | |
753 | init_vr41xx_icu_irq(); | |
754 | init_vr41xx_giuint_irq(); | |
755 | ||
756 | set_except_vector(0, vr41xx_handle_interrupt); | |
757 | } |