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