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