1 /*
2 * FILE NAME
3 * arch/mips/vr41xx/common/icu.c
4 *
5 * BRIEF MODULE DESCRIPTION
6 * Interrupt Control Unit routines for the NEC VR4100 series.
7 *
8 * Author: Yoichi Yuasa
9 * yyuasa@mvista.com or source@mvista.com
10 *
11 * Copyright 2001,2002 MontaVista Software Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33 /*
34 * Changes:
35 * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
36 * - New creation, NEC VR4122 and VR4131 are supported.
37 * - Added support for NEC VR4111 and VR4121.
38 *
39 * Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
40 * - Coped with INTASSIGN of NEC VR4133.
41 */
42 #include <linux/errno.h>
43 #include <linux/init.h>
44 #include <linux/interrupt.h>
45 #include <linux/irq.h>
46 #include <linux/types.h>
47
48 #include <asm/cpu.h>
49 #include <asm/io.h>
50 #include <asm/irq.h>
51 #include <asm/irq_cpu.h>
52 #include <asm/vr41xx/vr41xx.h>
53
54 extern asmlinkage void vr41xx_handle_interrupt(void);
55
56 extern void vr41xx_giuint_init(void);
57 extern void vr41xx_enable_giuint(int pin);
58 extern void vr41xx_disable_giuint(int pin);
59 extern void vr41xx_clear_giuint(int pin);
60 extern unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs);
61
62 static uint32_t icu1_base;
63 static uint32_t icu2_base;
64
65 static unsigned char sysint1_assign[16] = {
66 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
67 static unsigned char sysint2_assign[16] = {
68 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
69
70 #define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080)
71 #define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200)
72
73 #define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080)
74 #define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0)
75
76 #define SYSINT1REG 0x00
77 #define INTASSIGN0 0x04
78 #define INTASSIGN1 0x06
79 #define GIUINTLREG 0x08
80 #define MSYSINT1REG 0x0c
81 #define MGIUINTLREG 0x14
82 #define NMIREG 0x18
83 #define SOFTREG 0x1a
84 #define INTASSIGN2 0x1c
85 #define INTASSIGN3 0x1e
86
87 #define SYSINT2REG 0x00
88 #define GIUINTHREG 0x02
89 #define MSYSINT2REG 0x06
90 #define MGIUINTHREG 0x08
91
92 #define SYSINT1_IRQ_TO_PIN(x) ((x) - SYSINT1_IRQ_BASE) /* Pin 0-15 */
93 #define SYSINT2_IRQ_TO_PIN(x) ((x) - SYSINT2_IRQ_BASE) /* Pin 0-15 */
94
95 #define read_icu1(offset) readw(icu1_base + (offset))
96 #define write_icu1(val, offset) writew((val), icu1_base + (offset))
97
98 #define read_icu2(offset) readw(icu2_base + (offset))
99 #define write_icu2(val, offset) writew((val), icu2_base + (offset))
100
101 #define INTASSIGN_MAX 4
102 #define INTASSIGN_MASK 0x0007
103
set_icu1(uint8_t offset,uint16_t set)104 static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
105 {
106 uint16_t res;
107
108 res = read_icu1(offset);
109 res |= set;
110 write_icu1(res, offset);
111
112 return res;
113 }
114
clear_icu1(uint8_t offset,uint16_t clear)115 static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
116 {
117 uint16_t res;
118
119 res = read_icu1(offset);
120 res &= ~clear;
121 write_icu1(res, offset);
122
123 return res;
124 }
125
set_icu2(uint8_t offset,uint16_t set)126 static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
127 {
128 uint16_t res;
129
130 res = read_icu2(offset);
131 res |= set;
132 write_icu2(res, offset);
133
134 return res;
135 }
136
clear_icu2(uint8_t offset,uint16_t clear)137 static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
138 {
139 uint16_t res;
140
141 res = read_icu2(offset);
142 res &= ~clear;
143 write_icu2(res, offset);
144
145 return res;
146 }
147
148 /*=======================================================================*/
149
enable_sysint1_irq(unsigned int irq)150 static void enable_sysint1_irq(unsigned int irq)
151 {
152 set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
153 }
154
disable_sysint1_irq(unsigned int irq)155 static void disable_sysint1_irq(unsigned int irq)
156 {
157 clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
158 }
159
startup_sysint1_irq(unsigned int irq)160 static unsigned int startup_sysint1_irq(unsigned int irq)
161 {
162 set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
163
164 return 0; /* never anything pending */
165 }
166
167 #define shutdown_sysint1_irq disable_sysint1_irq
168 #define ack_sysint1_irq disable_sysint1_irq
169
end_sysint1_irq(unsigned int irq)170 static void end_sysint1_irq(unsigned int irq)
171 {
172 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
173 set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
174 }
175
176 static struct hw_interrupt_type sysint1_irq_type = {
177 .typename = "SYSINT1",
178 .startup = startup_sysint1_irq,
179 .shutdown = shutdown_sysint1_irq,
180 .enable = enable_sysint1_irq,
181 .disable = disable_sysint1_irq,
182 .ack = ack_sysint1_irq,
183 .end = end_sysint1_irq,
184 };
185
186 /*=======================================================================*/
187
enable_sysint2_irq(unsigned int irq)188 static void enable_sysint2_irq(unsigned int irq)
189 {
190 set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
191 }
192
disable_sysint2_irq(unsigned int irq)193 static void disable_sysint2_irq(unsigned int irq)
194 {
195 clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
196 }
197
startup_sysint2_irq(unsigned int irq)198 static unsigned int startup_sysint2_irq(unsigned int irq)
199 {
200 set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
201
202 return 0; /* never anything pending */
203 }
204
205 #define shutdown_sysint2_irq disable_sysint2_irq
206 #define ack_sysint2_irq disable_sysint2_irq
207
end_sysint2_irq(unsigned int irq)208 static void end_sysint2_irq(unsigned int irq)
209 {
210 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
211 set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
212 }
213
214 static struct hw_interrupt_type sysint2_irq_type = {
215 .typename = "SYSINT2",
216 .startup = startup_sysint2_irq,
217 .shutdown = shutdown_sysint2_irq,
218 .enable = enable_sysint2_irq,
219 .disable = disable_sysint2_irq,
220 .ack = ack_sysint2_irq,
221 .end = end_sysint2_irq,
222 };
223
224 /*=======================================================================*/
225
enable_giuint_irq(unsigned int irq)226 static void enable_giuint_irq(unsigned int irq)
227 {
228 int pin;
229
230 pin = GIU_IRQ_TO_PIN(irq);
231 if (pin < 16)
232 set_icu1(MGIUINTLREG, (uint16_t)1 << pin);
233 else
234 set_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
235 vr41xx_enable_giuint(pin);
236 }
237
disable_giuint_irq(unsigned int irq)238 static void disable_giuint_irq(unsigned int irq)
239 {
240 int pin;
241
242 pin = GIU_IRQ_TO_PIN(irq);
243 vr41xx_disable_giuint(pin);
244 if (pin < 16)
245 clear_icu1(MGIUINTLREG, (uint16_t)1 << pin);
246 else
247 clear_icu2(MGIUINTHREG, (uint16_t)1 << (pin - 16));
248 }
249
startup_giuint_irq(unsigned int irq)250 static unsigned int startup_giuint_irq(unsigned int irq)
251 {
252 vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
253
254 enable_giuint_irq(irq);
255
256 return 0; /* never anything pending */
257 }
258
259 #define shutdown_giuint_irq disable_giuint_irq
260
ack_giuint_irq(unsigned int irq)261 static void ack_giuint_irq(unsigned int irq)
262 {
263 disable_giuint_irq(irq);
264
265 vr41xx_clear_giuint(GIU_IRQ_TO_PIN(irq));
266 }
267
end_giuint_irq(unsigned int irq)268 static void end_giuint_irq(unsigned int irq)
269 {
270 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
271 enable_giuint_irq(irq);
272 }
273
274 static struct hw_interrupt_type giuint_irq_type = {
275 .typename = "GIUINT",
276 .startup = startup_giuint_irq,
277 .shutdown = shutdown_giuint_irq,
278 .enable = enable_giuint_irq,
279 .disable = disable_giuint_irq,
280 .ack = ack_giuint_irq,
281 .end = end_giuint_irq,
282 };
283
284 /*=======================================================================*/
285
286 static struct irqaction icu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
287
vr41xx_icu_init(void)288 static void __init vr41xx_icu_init(void)
289 {
290 int i;
291
292 switch (current_cpu_data.cputype) {
293 case CPU_VR4111:
294 case CPU_VR4121:
295 icu1_base = SYSINT1REG_TYPE1;
296 icu2_base = SYSINT2REG_TYPE1;
297 break;
298 case CPU_VR4122:
299 case CPU_VR4131:
300 case CPU_VR4133:
301 icu1_base = SYSINT1REG_TYPE2;
302 icu2_base = SYSINT2REG_TYPE2;
303 break;
304 default:
305 panic("Unexpected CPU of NEC VR4100 series");
306 break;
307 }
308
309 write_icu1(0, MSYSINT1REG);
310 write_icu1(0, MGIUINTLREG);
311
312 write_icu2(0, MSYSINT2REG);
313 write_icu2(0, MGIUINTHREG);
314
315 for (i = SYSINT1_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
316 if (i >= SYSINT1_IRQ_BASE && i <= SYSINT1_IRQ_LAST)
317 irq_desc[i].handler = &sysint1_irq_type;
318 else if (i >= SYSINT2_IRQ_BASE && i <= SYSINT2_IRQ_LAST)
319 irq_desc[i].handler = &sysint2_irq_type;
320 else if (i >= GIU_IRQ_BASE && i <= GIU_IRQ_LAST)
321 irq_desc[i].handler = &giuint_irq_type;
322 }
323
324 setup_irq(INT0_CASCADE_IRQ, &icu_cascade);
325 setup_irq(INT1_CASCADE_IRQ, &icu_cascade);
326 setup_irq(INT2_CASCADE_IRQ, &icu_cascade);
327 setup_irq(INT3_CASCADE_IRQ, &icu_cascade);
328 setup_irq(INT4_CASCADE_IRQ, &icu_cascade);
329 }
330
init_IRQ(void)331 void __init init_IRQ(void)
332 {
333 memset(irq_desc, 0, sizeof(irq_desc));
334
335 init_generic_irq();
336 mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
337 vr41xx_icu_init();
338
339 vr41xx_giuint_init();
340
341 set_except_vector(0, vr41xx_handle_interrupt);
342 }
343
344 /*=======================================================================*/
345
set_sysint1_assign(unsigned int irq,unsigned char assign)346 static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
347 {
348 irq_desc_t *desc = irq_desc + irq;
349 uint16_t intassign0, intassign1;
350 unsigned int pin;
351
352 pin = SYSINT1_IRQ_TO_PIN(irq);
353
354 spin_lock_irq(&desc->lock);
355
356 intassign0 = read_icu1(INTASSIGN0);
357 intassign1 = read_icu1(INTASSIGN1);
358
359 switch (pin) {
360 case 0:
361 intassign0 &= ~INTASSIGN_MASK;
362 intassign0 |= (uint16_t)assign;
363 break;
364 case 1:
365 intassign0 &= ~(INTASSIGN_MASK << 3);
366 intassign0 |= (uint16_t)assign << 3;
367 break;
368 case 2:
369 intassign0 &= ~(INTASSIGN_MASK << 6);
370 intassign0 |= (uint16_t)assign << 6;
371 break;
372 case 3:
373 intassign0 &= ~(INTASSIGN_MASK << 9);
374 intassign0 |= (uint16_t)assign << 9;
375 break;
376 case 8:
377 intassign0 &= ~(INTASSIGN_MASK << 12);
378 intassign0 |= (uint16_t)assign << 12;
379 break;
380 case 9:
381 intassign1 &= ~INTASSIGN_MASK;
382 intassign1 |= (uint16_t)assign;
383 break;
384 case 11:
385 intassign1 &= ~(INTASSIGN_MASK << 6);
386 intassign1 |= (uint16_t)assign << 6;
387 break;
388 case 12:
389 intassign1 &= ~(INTASSIGN_MASK << 9);
390 intassign1 |= (uint16_t)assign << 9;
391 break;
392 default:
393 return -EINVAL;
394 }
395
396 sysint1_assign[pin] = assign;
397 write_icu1(intassign0, INTASSIGN0);
398 write_icu1(intassign1, INTASSIGN1);
399
400 spin_unlock_irq(&desc->lock);
401
402 return 0;
403 }
404
set_sysint2_assign(unsigned int irq,unsigned char assign)405 static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
406 {
407 irq_desc_t *desc = irq_desc + irq;
408 uint16_t intassign2, intassign3;
409 unsigned int pin;
410
411 pin = SYSINT2_IRQ_TO_PIN(irq);
412
413 spin_lock_irq(&desc->lock);
414
415 intassign2 = read_icu1(INTASSIGN2);
416 intassign3 = read_icu1(INTASSIGN3);
417
418 switch (pin) {
419 case 0:
420 intassign2 &= ~INTASSIGN_MASK;
421 intassign2 |= (uint16_t)assign;
422 break;
423 case 1:
424 intassign2 &= ~(INTASSIGN_MASK << 3);
425 intassign2 |= (uint16_t)assign << 3;
426 break;
427 case 3:
428 intassign2 &= ~(INTASSIGN_MASK << 6);
429 intassign2 |= (uint16_t)assign << 6;
430 break;
431 case 4:
432 intassign2 &= ~(INTASSIGN_MASK << 9);
433 intassign2 |= (uint16_t)assign << 9;
434 break;
435 case 5:
436 intassign2 &= ~(INTASSIGN_MASK << 12);
437 intassign2 |= (uint16_t)assign << 12;
438 break;
439 case 6:
440 intassign3 &= ~INTASSIGN_MASK;
441 intassign3 |= (uint16_t)assign;
442 break;
443 case 7:
444 intassign3 &= ~(INTASSIGN_MASK << 3);
445 intassign3 |= (uint16_t)assign << 3;
446 break;
447 case 8:
448 intassign3 &= ~(INTASSIGN_MASK << 6);
449 intassign3 |= (uint16_t)assign << 6;
450 break;
451 case 9:
452 intassign3 &= ~(INTASSIGN_MASK << 9);
453 intassign3 |= (uint16_t)assign << 9;
454 break;
455 case 10:
456 intassign3 &= ~(INTASSIGN_MASK << 12);
457 intassign3 |= (uint16_t)assign << 12;
458 break;
459 default:
460 return -EINVAL;
461 }
462
463 sysint2_assign[pin] = assign;
464 write_icu1(intassign2, INTASSIGN2);
465 write_icu1(intassign3, INTASSIGN3);
466
467 spin_unlock_irq(&desc->lock);
468
469 return 0;
470 }
471
vr41xx_set_intassign(unsigned int irq,unsigned char intassign)472 int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
473 {
474 int retval = -EINVAL;
475
476 if (current_cpu_data.cputype != CPU_VR4133)
477 return -EINVAL;
478
479 if (intassign > INTASSIGN_MAX)
480 return -EINVAL;
481
482 if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST)
483 retval = set_sysint1_assign(irq, intassign);
484 else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST)
485 retval = set_sysint2_assign(irq, intassign);
486
487 return retval;
488 }
489
490 /*=======================================================================*/
491
giuint_irq_dispatch(uint16_t pendl,uint16_t pendh,struct pt_regs * regs)492 static inline void giuint_irq_dispatch(uint16_t pendl, uint16_t pendh,
493 struct pt_regs *regs)
494 {
495 int i;
496
497 if (pendl) {
498 for (i = 0; i < 16; i++) {
499 if (pendl & ((uint16_t)1 << i)) {
500 giuint_do_IRQ(i, regs);
501 return;
502 }
503 }
504 } else {
505 for (i = 0; i < 16; i++) {
506 if (pendh & ((uint16_t)1 << i)) {
507 giuint_do_IRQ(i + 16, regs);
508 return;
509 }
510 }
511 }
512 }
513
irq_dispatch(unsigned char intnum,struct pt_regs * regs)514 asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
515 {
516 uint16_t pend1, pend2, pendl, pendh;
517 uint16_t mask1, mask2, maskl, maskh;
518 int i;
519
520 pend1 = read_icu1(SYSINT1REG);
521 mask1 = read_icu1(MSYSINT1REG);
522
523 pend2 = read_icu2(SYSINT2REG);
524 mask2 = read_icu2(MSYSINT2REG);
525
526 pendl = read_icu1(GIUINTLREG);
527 maskl = read_icu1(MGIUINTLREG);
528
529 pendh = read_icu2(GIUINTHREG);
530 maskh = read_icu2(MGIUINTHREG);
531
532 mask1 &= pend1;
533 mask2 &= pend2;
534 maskl &= pendl;
535 maskh &= pendh;
536
537 if (mask1) {
538 for (i = 0; i < 16; i++) {
539 if (intnum == sysint1_assign[i] &&
540 (mask1 & ((uint16_t)1 << i))) {
541 if (i == 8 && (maskl | maskh)) {
542 giuint_irq_dispatch(maskl, maskh, regs);
543 return;
544 } else {
545 do_IRQ(SYSINT1_IRQ(i), regs);
546 return;
547 }
548 }
549 }
550 }
551
552 if (mask2) {
553 for (i = 0; i < 16; i++) {
554 if (intnum == sysint2_assign[i] &&
555 (mask2 & ((uint16_t)1 << i))) {
556 do_IRQ(SYSINT2_IRQ(i), regs);
557 return;
558 }
559 }
560 }
561
562 printk(KERN_ERR "spurious interrupt: %04x,%04x,%04x,%04x\n", pend1, pend2, pendl, pendh);
563 atomic_inc(&irq_err_count);
564 }
565