xref: /netbsd/sys/arch/sh3/sh3/interrupt.c (revision ccde4787)
1 /*	$NetBSD: interrupt.c,v 1.29 2010/12/20 00:25:43 matt Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.29 2010/12/20 00:25:43 matt Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/malloc.h>
37 #include <sys/intr.h>
38 #include <sys/cpu.h>
39 
40 #include <sh3/exception.h>
41 #include <sh3/clock.h>
42 #include <sh3/intcreg.h>
43 #include <sh3/tmureg.h>
44 
45 static void intc_intr_priority(int, int);
46 static struct intc_intrhand *intc_alloc_ih(void);
47 static void intc_free_ih(struct intc_intrhand *);
48 static int intc_unknown_intr(void *);
49 
50 #ifdef SH4
51 static void intpri_intr_enable(int);
52 static void intpri_intr_disable(int);
53 #endif
54 
55 /*
56  * EVTCODE to intc_intrhand mapper.
57  * max #76 is SH4_INTEVT_TMU4 (0xb80)
58  */
59 int8_t __intc_evtcode_to_ih[128];
60 
61 struct intc_intrhand __intc_intrhand[_INTR_N + 1] = {
62 	/* Place holder interrupt handler for unregistered interrupt. */
63 	[0] = { .ih_func = intc_unknown_intr, .ih_level = 0xf0 }
64 };
65 
66 /*
67  * SH INTC support.
68  */
69 void
intc_init(void)70 intc_init(void)
71 {
72 
73 	switch (cpu_product) {
74 #ifdef SH3
75 	case CPU_PRODUCT_7709:
76 	case CPU_PRODUCT_7709A:
77 	case CPU_PRODUCT_7706:
78 		_reg_write_2(SH7709_IPRC, 0);
79 		_reg_write_2(SH7709_IPRD, 0);
80 		_reg_write_2(SH7709_IPRE, 0);
81 		/* FALLTHROUGH */
82 	case CPU_PRODUCT_7708:
83 	case CPU_PRODUCT_7708S:
84 	case CPU_PRODUCT_7708R:
85 		_reg_write_2(SH3_IPRA, 0);
86 		_reg_write_2(SH3_IPRB, 0);
87 		break;
88 #endif /* SH3 */
89 
90 #ifdef SH4
91 	case CPU_PRODUCT_7751:
92 	case CPU_PRODUCT_7751R:
93 		_reg_write_4(SH4_INTPRI00, 0);
94 		_reg_write_4(SH4_INTMSK00, INTMSK00_MASK_ALL);
95 		/* FALLTHROUGH */
96 	case CPU_PRODUCT_7750S:
97 	case CPU_PRODUCT_7750R:
98 		_reg_write_2(SH4_IPRD, 0);
99 		/* FALLTHROUGH */
100 	case CPU_PRODUCT_7750:
101 		_reg_write_2(SH4_IPRA, 0);
102 		_reg_write_2(SH4_IPRB, 0);
103 		_reg_write_2(SH4_IPRC, 0);
104 		break;
105 #endif /* SH4 */
106 	}
107 }
108 
109 void *
intc_intr_establish(int evtcode,int trigger,int level,int (* ih_func)(void *),void * ih_arg)110 intc_intr_establish(int evtcode, int trigger, int level,
111     int (*ih_func)(void *), void *ih_arg)
112 {
113 	struct intc_intrhand *ih;
114 
115 	KDASSERT(evtcode >= 0x200 && level > 0);
116 
117 	ih = intc_alloc_ih();
118 	ih->ih_func	= ih_func;
119 	ih->ih_arg	= ih_arg;
120 	ih->ih_level	= level << 4;	/* convert to SR.IMASK format. */
121 	ih->ih_evtcode	= evtcode;
122 
123 	/* Map interrupt handler */
124 	EVTCODE_TO_IH_INDEX(evtcode) = ih->ih_idx;
125 
126 	/* Priority */
127 	intc_intr_priority(evtcode, level);
128 
129 	/* Sense select (SH7709, SH7709A only) XXX notyet */
130 
131 	return (ih);
132 }
133 
134 void
intc_intr_disestablish(void * arg)135 intc_intr_disestablish(void *arg)
136 {
137 	struct intc_intrhand *ih = arg;
138 	int evtcode = ih->ih_evtcode;
139 
140 	/* Mask interrupt if IPR can manage it. if not, cascaded ICU will do */
141 	intc_intr_priority(evtcode, 0);
142 
143 	/* Unmap interrupt handler */
144 	EVTCODE_TO_IH_INDEX(evtcode) = 0;
145 
146 	intc_free_ih(ih);
147 }
148 
149 void
intc_intr_disable(int evtcode)150 intc_intr_disable(int evtcode)
151 {
152 	int s;
153 
154 	s = _cpu_intr_suspend();
155 	KASSERT(EVTCODE_TO_IH_INDEX(evtcode) != 0); /* there is a handler */
156 	switch (evtcode) {
157 	default:
158 		intc_intr_priority(evtcode, 0);
159 		break;
160 
161 #ifdef SH4
162 	case SH4_INTEVT_PCISERR:
163 	case SH4_INTEVT_PCIDMA3:
164 	case SH4_INTEVT_PCIDMA2:
165 	case SH4_INTEVT_PCIDMA1:
166 	case SH4_INTEVT_PCIDMA0:
167 	case SH4_INTEVT_PCIPWON:
168 	case SH4_INTEVT_PCIPWDWN:
169 	case SH4_INTEVT_PCIERR:
170 	case SH4_INTEVT_TMU3:
171 	case SH4_INTEVT_TMU4:
172 		intpri_intr_disable(evtcode);
173 		break;
174 #endif
175 	}
176 	_cpu_intr_resume(s);
177 }
178 
179 void
intc_intr_enable(int evtcode)180 intc_intr_enable(int evtcode)
181 {
182 	struct intc_intrhand *ih;
183 	int s;
184 
185 	s = _cpu_intr_suspend();
186 	KASSERT(EVTCODE_TO_IH_INDEX(evtcode) != 0); /* there is a handler */
187 	switch (evtcode) {
188 	default:
189 		ih = EVTCODE_IH(evtcode);
190 		/* ih_level is in the SR.IMASK format */
191 		intc_intr_priority(evtcode, (ih->ih_level >> 4));
192 		break;
193 
194 #ifdef SH4
195 	case SH4_INTEVT_PCISERR:
196 	case SH4_INTEVT_PCIDMA3:
197 	case SH4_INTEVT_PCIDMA2:
198 	case SH4_INTEVT_PCIDMA1:
199 	case SH4_INTEVT_PCIDMA0:
200 	case SH4_INTEVT_PCIPWON:
201 	case SH4_INTEVT_PCIPWDWN:
202 	case SH4_INTEVT_PCIERR:
203 	case SH4_INTEVT_TMU3:
204 	case SH4_INTEVT_TMU4:
205 		intpri_intr_enable(evtcode);
206 		break;
207 #endif
208 	}
209 	_cpu_intr_resume(s);
210 }
211 
212 
213 /*
214  * int intc_intr_priority(int evtcode, int level)
215  *	Setup interrupt priority register.
216  *	SH7708, SH7708S, SH7708R, SH7750, SH7750S ... evtcode is INTEVT
217  *	SH7709, SH7709A, SH7706			  ... evtcode is INTEVT2
218  */
219 static void
intc_intr_priority(int evtcode,int level)220 intc_intr_priority(int evtcode, int level)
221 {
222 	volatile uint16_t *iprreg;
223 	int pos;
224 	uint16_t r;
225 
226 #define	__SH_IPR(_sh, _ipr, _pos)					   \
227 	do {								   \
228 		iprreg = (volatile uint16_t *)(SH ## _sh ## _IPR ## _ipr); \
229 		pos = (_pos);						   \
230 	} while (/*CONSTCOND*/0)
231 
232 #define	SH3_IPR(_ipr, _pos)		__SH_IPR(3, _ipr, _pos)
233 #define	SH4_IPR(_ipr, _pos)		__SH_IPR(4, _ipr, _pos)
234 #define	SH7709_IPR(_ipr, _pos)		__SH_IPR(7709, _ipr, _pos)
235 
236 #define	SH_IPR(_ipr, _pos)						\
237 	do {								\
238 		if (CPU_IS_SH3)						\
239 			SH3_IPR(_ipr, _pos);				\
240 		else							\
241 			SH4_IPR(_ipr, _pos);				\
242 	} while (/*CONSTCOND*/0)
243 
244 	iprreg = 0;
245 	pos = -1;
246 
247 	switch (evtcode) {
248 	case SH_INTEVT_TMU0_TUNI0:
249 		SH_IPR(A, 12);
250 		break;
251 	case SH_INTEVT_TMU1_TUNI1:
252 		SH_IPR(A, 8);
253 		break;
254 	case SH_INTEVT_TMU2_TUNI2:
255 		SH_IPR(A, 4);
256 		break;
257 	case SH_INTEVT_WDT_ITI:
258 		SH_IPR(B, 12);
259 		break;
260 	case SH_INTEVT_SCI_ERI:
261 	case SH_INTEVT_SCI_RXI:
262 	case SH_INTEVT_SCI_TXI:
263 	case SH_INTEVT_SCI_TEI:
264 		SH_IPR(B, 4);
265 		break;
266 	}
267 
268 #ifdef SH3
269 	if (CPU_IS_SH3) {
270 		switch (evtcode) {
271 		case SH7709_INTEVT2_IRQ3:
272 			SH7709_IPR(C, 12);
273 			break;
274 		case SH7709_INTEVT2_IRQ2:
275 			SH7709_IPR(C, 8);
276 			break;
277 		case SH7709_INTEVT2_IRQ1:
278 			SH7709_IPR(C, 4);
279 			break;
280 		case SH7709_INTEVT2_IRQ0:
281 			SH7709_IPR(C, 0);
282 			break;
283 		case SH7709_INTEVT2_PINT07:
284 			SH7709_IPR(D, 12);
285 			break;
286 		case SH7709_INTEVT2_PINT8F:
287 			SH7709_IPR(D, 8);
288 			break;
289 		case SH7709_INTEVT2_IRQ5:
290 			SH7709_IPR(D, 4);
291 			break;
292 		case SH7709_INTEVT2_IRQ4:
293 			SH7709_IPR(D, 0);
294 			break;
295 		case SH7709_INTEVT2_DEI0:
296 		case SH7709_INTEVT2_DEI1:
297 		case SH7709_INTEVT2_DEI2:
298 		case SH7709_INTEVT2_DEI3:
299 			SH7709_IPR(E, 12);
300 			break;
301 		case SH7709_INTEVT2_IRDA_ERI:
302 		case SH7709_INTEVT2_IRDA_RXI:
303 		case SH7709_INTEVT2_IRDA_BRI:
304 		case SH7709_INTEVT2_IRDA_TXI:
305 			SH7709_IPR(E, 8);
306 			break;
307 		case SH7709_INTEVT2_SCIF_ERI:
308 		case SH7709_INTEVT2_SCIF_RXI:
309 		case SH7709_INTEVT2_SCIF_BRI:
310 		case SH7709_INTEVT2_SCIF_TXI:
311 			SH7709_IPR(E, 4);
312 			break;
313 		case SH7709_INTEVT2_ADC:
314 			SH7709_IPR(E, 0);
315 			break;
316 		}
317 	}
318 #endif /* SH3 */
319 
320 #ifdef SH4
321 	if (CPU_IS_SH4) {
322 		switch (evtcode) {
323 		case SH4_INTEVT_SCIF_ERI:
324 		case SH4_INTEVT_SCIF_RXI:
325 		case SH4_INTEVT_SCIF_BRI:
326 		case SH4_INTEVT_SCIF_TXI:
327 			SH4_IPR(C, 4);
328 			break;
329 
330 #if 0
331 		case SH4_INTEVT_PCISERR:
332 		case SH4_INTEVT_PCIDMA3:
333 		case SH4_INTEVT_PCIDMA2:
334 		case SH4_INTEVT_PCIDMA1:
335 		case SH4_INTEVT_PCIDMA0:
336 		case SH4_INTEVT_PCIPWON:
337 		case SH4_INTEVT_PCIPWDWN:
338 		case SH4_INTEVT_PCIERR:
339 #endif
340 		case SH4_INTEVT_TMU3:
341 		case SH4_INTEVT_TMU4:
342 			intpri_intr_priority(evtcode, level);
343 			break;
344 		}
345 	}
346 #endif /* SH4 */
347 
348 	/*
349 	 * XXX: This function gets called even for interrupts that
350 	 * don't have their priority defined by IPR registers.
351 	 */
352 	if (pos < 0)
353 		return;
354 
355 	r = _reg_read_2(iprreg);
356 	r = (r & ~(0xf << (pos))) | (level << (pos));
357 	_reg_write_2(iprreg, r);
358 }
359 
360 /*
361  * Interrupt handler holder allocater.
362  */
363 static struct intc_intrhand *
intc_alloc_ih(void)364 intc_alloc_ih(void)
365 {
366 	/* #0 is reserved for unregistered interrupt. */
367 	struct intc_intrhand *ih = &__intc_intrhand[1];
368 	int i;
369 
370 	for (i = 1; i <= _INTR_N; i++, ih++)
371 		if (ih->ih_idx == 0) {	/* no driver uses this. */
372 			ih->ih_idx = i;	/* register myself */
373 			return (ih);
374 		}
375 
376 	panic("increase _INTR_N greater than %d", _INTR_N);
377 	return (NULL);
378 }
379 
380 static void
intc_free_ih(struct intc_intrhand * ih)381 intc_free_ih(struct intc_intrhand *ih)
382 {
383 
384 	memset(ih, 0, sizeof(*ih));
385 }
386 
387 /* Place-holder for debugging */
388 static int
intc_unknown_intr(void * arg)389 intc_unknown_intr(void *arg)
390 {
391 
392 	printf("INTEVT=0x%x", _reg_read_4(SH_(INTEVT)));
393 	if (cpu_product == CPU_PRODUCT_7709 ||
394 	    cpu_product == CPU_PRODUCT_7709A ||
395 	    cpu_product == CPU_PRODUCT_7706)
396 		printf(" INTEVT2=0x%x", _reg_read_4(SH7709_INTEVT2));
397 	printf("\n");
398 
399 	panic("unknown interrupt");
400 	/* NOTREACHED */
401 	return (0);
402 }
403 
404 #ifdef SH4 /* SH7751 support */
405 
406 /*
407  * INTPRIxx
408  */
409 void
intpri_intr_priority(int evtcode,int level)410 intpri_intr_priority(int evtcode, int level)
411 {
412 	volatile uint32_t *iprreg;
413 	uint32_t r;
414 	int pos;
415 
416 	if (!CPU_IS_SH4)
417 		return;
418 
419 	switch (cpu_product) {
420 	default:
421 		return;
422 
423 	case CPU_PRODUCT_7751:
424 	case CPU_PRODUCT_7751R:
425 		break;
426 	}
427 
428 	iprreg = (volatile uint32_t *)SH4_INTPRI00;
429 	pos = -1;
430 
431 	switch (evtcode) {
432 	case SH4_INTEVT_PCIDMA3:
433 	case SH4_INTEVT_PCIDMA2:
434 	case SH4_INTEVT_PCIDMA1:
435 	case SH4_INTEVT_PCIDMA0:
436 	case SH4_INTEVT_PCIPWDWN:
437 	case SH4_INTEVT_PCIPWON:
438 	case SH4_INTEVT_PCIERR:
439 		pos = 0;
440 		break;
441 
442 	case SH4_INTEVT_PCISERR:
443 		pos = 4;
444 		break;
445 
446 	case SH4_INTEVT_TMU3:
447 		pos = 8;
448 		break;
449 
450 	case SH4_INTEVT_TMU4:
451 		pos = 12;
452 		break;
453 	}
454 
455 	if (pos < 0) {
456 		return;
457 	}
458 
459 	r = _reg_read_4(iprreg);
460 	r = (r & ~(0xf << pos)) | (level << pos);
461 	_reg_write_4(iprreg, r);
462 }
463 
464 static void
intpri_intr_enable(int evtcode)465 intpri_intr_enable(int evtcode)
466 {
467 	volatile uint32_t *iprreg;
468 	uint32_t bit;
469 
470 	if (!CPU_IS_SH4)
471 		return;
472 
473 	switch (cpu_product) {
474 	default:
475 		return;
476 
477 	case CPU_PRODUCT_7751:
478 	case CPU_PRODUCT_7751R:
479 		break;
480 	}
481 
482 	iprreg = (volatile uint32_t *)SH4_INTMSKCLR00;
483 	bit = 0;
484 
485 	switch (evtcode) {
486 	case SH4_INTEVT_PCISERR:
487 	case SH4_INTEVT_PCIDMA3:
488 	case SH4_INTEVT_PCIDMA2:
489 	case SH4_INTEVT_PCIDMA1:
490 	case SH4_INTEVT_PCIDMA0:
491 	case SH4_INTEVT_PCIPWON:
492 	case SH4_INTEVT_PCIPWDWN:
493 	case SH4_INTEVT_PCIERR:
494 		bit = (1 << ((evtcode - SH4_INTEVT_PCISERR) >> 5));
495 		break;
496 
497 	case SH4_INTEVT_TMU3:
498 		bit = INTREQ00_TUNI3;
499 		break;
500 
501 	case SH4_INTEVT_TMU4:
502 		bit = INTREQ00_TUNI4;
503 		break;
504 	}
505 
506 	if ((bit == 0) || (iprreg == NULL)) {
507 		return;
508 	}
509 
510 	_reg_write_4(iprreg, bit);
511 }
512 
513 static void
intpri_intr_disable(int evtcode)514 intpri_intr_disable(int evtcode)
515 {
516 	volatile uint32_t *iprreg;
517 	uint32_t bit;
518 
519 	if (!CPU_IS_SH4)
520 		return;
521 
522 	switch (cpu_product) {
523 	default:
524 		return;
525 
526 	case CPU_PRODUCT_7751:
527 	case CPU_PRODUCT_7751R:
528 		break;
529 	}
530 
531 	iprreg = (volatile uint32_t *)SH4_INTMSK00;
532 	bit = 0;
533 
534 	switch (evtcode) {
535 	case SH4_INTEVT_PCISERR:
536 	case SH4_INTEVT_PCIDMA3:
537 	case SH4_INTEVT_PCIDMA2:
538 	case SH4_INTEVT_PCIDMA1:
539 	case SH4_INTEVT_PCIDMA0:
540 	case SH4_INTEVT_PCIPWON:
541 	case SH4_INTEVT_PCIPWDWN:
542 	case SH4_INTEVT_PCIERR:
543 		bit = (1 << ((evtcode - SH4_INTEVT_PCISERR) >> 5));
544 		break;
545 
546 	case SH4_INTEVT_TMU3:
547 		bit = INTREQ00_TUNI3;
548 		break;
549 
550 	case SH4_INTEVT_TMU4:
551 		bit = INTREQ00_TUNI4;
552 		break;
553 	}
554 
555 	if ((bit == 0) || (iprreg == NULL)) {
556 		return;
557 	}
558 
559 	_reg_write_4(iprreg, bit);
560 }
561 #endif /* SH4 */
562 
563 bool
cpu_intr_p(void)564 cpu_intr_p(void)
565 {
566 
567 	return curcpu()->ci_idepth >= 0;
568 }
569