1 /* $NetBSD: int.c,v 1.20 2009/02/12 06:33:57 rumble Exp $ */
4 * Copyright (c) 2009 Stephen M. Rumble
5 * Copyright (c) 2004 Christopher SEKIYA
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * INT1/INT2/INT3 interrupt controllers (IP6, IP10, IP12, IP20, IP22, IP24...)
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: int.c,v 1.20 2009/02/12 06:33:57 rumble Exp $");
38 #include "opt_cputype.h"
40 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/timetc.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
48 #include <dev/ic/i8253reg.h>
49 #include <machine/sysconf.h>
50 #include <machine/machtype.h>
51 #include <machine/bus.h>
52 #include <mips/locore.h>
54 #include <mips/cache.h>
56 #include <sgimips/dev/int1reg.h>
57 #include <sgimips/dev/int2reg.h>
58 #include <sgimips/dev/int2var.h>
60 static bus_space_handle_t ioh
;
61 static bus_space_tag_t iot
;
68 static int int_match(struct device
*, struct cfdata
*, void *);
69 static void int_attach(struct device
*, struct device
*, void *);
70 static void int1_local_intr(uint32_t, uint32_t, uint32_t, uint32_t);
71 static void *int1_intr_establish(int, int, int (*)(void *), void *);
72 static void *int2_intr_establish(int, int, int (*)(void *), void *);
73 static void int2_local0_intr(uint32_t, uint32_t, uint32_t, uint32_t);
74 static void int2_local1_intr(uint32_t, uint32_t, uint32_t, uint32_t);
75 static int int2_mappable_intr(void *);
76 static void *int2_intr_establish(int, int, int (*)(void *), void *);
77 static void int_8254_cal(void);
78 static u_int
int_8254_get_timecount(struct timecounter
*);
79 static void int_8254_intr0(uint32_t, uint32_t, uint32_t, uint32_t);
80 static void int_8254_intr1(uint32_t, uint32_t, uint32_t, uint32_t);
83 static u_long
int2_cpu_freq(struct device
*);
84 static u_long
int2_cal_timer(void);
87 static struct timecounter int_8254_timecounter
= {
88 int_8254_get_timecount
, /* get_timecount */
90 ~0u, /* counter_mask */
91 0, /* frequency; set in int_8254_cal */
92 "int i8254", /* name */
98 static u_long int_8254_tc_count
;
100 CFATTACH_DECL(int, sizeof(struct int_softc
),
101 int_match
, int_attach
, NULL
, NULL
);
104 int_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
108 case MACH_SGI_IP6
| MACH_SGI_IP10
:
119 int_attach(struct device
*parent
, struct device
*self
, void *aux
)
124 case MACH_SGI_IP6
| MACH_SGI_IP10
:
125 address
= INT1_IP6_IP10
;
137 if (mach_subtype
== MACH_SGI_IP22_FULLHOUSE
)
144 panic("\nint0: passed match, but failed attach?");
147 printf(" addr 0x%x\n", address
);
149 bus_space_map(iot
, address
, 0, 0, &ioh
);
150 iot
= SGIMIPS_BUS_SPACE_NORMAL
;
153 case MACH_SGI_IP6
| MACH_SGI_IP10
:
154 /* Clean out interrupt masks */
155 bus_space_write_1(iot
, ioh
, INT1_LOCAL_MASK
, 0);
157 /* Turn off timers and clear interrupts */
158 bus_space_write_1(iot
, ioh
, INT1_TIMER_CONTROL
,
159 (TIMER_SEL0
| TIMER_16BIT
| TIMER_SWSTROBE
));
160 bus_space_write_1(iot
, ioh
, INT1_TIMER_CONTROL
,
161 (TIMER_SEL1
| TIMER_16BIT
| TIMER_SWSTROBE
));
162 bus_space_write_1(iot
, ioh
, INT1_TIMER_CONTROL
,
163 (TIMER_SEL2
| TIMER_16BIT
| TIMER_SWSTROBE
));
166 bus_space_read_1(iot
, ioh
, INT1_TIMER_0_ACK
);
167 bus_space_read_1(iot
, ioh
, INT1_TIMER_1_ACK
);
169 platform
.intr_establish
= int1_intr_establish
;
170 platform
.intr1
= int1_local_intr
;
171 platform
.intr2
= int_8254_intr0
;
172 platform
.intr4
= int_8254_intr1
;
179 /* Clean out interrupt masks */
180 bus_space_write_1(iot
, ioh
, INT2_LOCAL0_MASK
, 0);
181 bus_space_write_1(iot
, ioh
, INT2_LOCAL1_MASK
, 0);
182 bus_space_write_1(iot
, ioh
, INT2_MAP_MASK0
, 0);
183 bus_space_write_1(iot
, ioh
, INT2_MAP_MASK1
, 0);
185 /* Reset timer interrupts */
186 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
,
187 (TIMER_SEL0
| TIMER_16BIT
| TIMER_SWSTROBE
));
188 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
,
189 (TIMER_SEL1
| TIMER_16BIT
| TIMER_SWSTROBE
));
190 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
,
191 (TIMER_SEL2
| TIMER_16BIT
| TIMER_SWSTROBE
));
194 bus_space_write_1(iot
, ioh
, INT2_TIMER_CLEAR
, 0x03);
196 if (mach_type
== MACH_SGI_IP12
) {
197 platform
.intr_establish
= int2_intr_establish
;
198 platform
.intr1
= int2_local0_intr
;
199 platform
.intr2
= int2_local1_intr
;
200 platform
.intr3
= int_8254_intr0
;
201 platform
.intr4
= int_8254_intr1
;
204 platform
.intr_establish
= int2_intr_establish
;
205 platform
.intr0
= int2_local0_intr
;
206 platform
.intr1
= int2_local1_intr
;
208 curcpu()->ci_cpu_freq
= int2_cpu_freq(self
);
214 panic("int0: unsupported machine type %i\n", mach_type
);
217 curcpu()->ci_cycles_per_hz
= curcpu()->ci_cpu_freq
/ (2 * hz
);
218 curcpu()->ci_divisor_delay
= curcpu()->ci_cpu_freq
/ (2 * 1000000);
220 if (mach_type
== MACH_SGI_IP22
) {
221 /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */
222 intrtab
[7].ih_fun
= int2_mappable_intr
;
223 intrtab
[7].ih_arg
= (void*) 0;
225 intrtab
[11].ih_fun
= int2_mappable_intr
;
226 intrtab
[11].ih_arg
= (void*) 1;
231 int2_mappable_intr(void *arg
)
238 int which
= (intptr_t)arg
;
239 struct sgimips_intrhand
*ih
;
242 mstat
= bus_space_read_1(iot
, ioh
, INT2_MAP_STATUS
);
243 mmask
= bus_space_read_1(iot
, ioh
, INT2_MAP_MASK0
+ (which
<< 2));
247 for (i
= 0; i
< 8; i
++) {
248 intnum
= i
+ 16 + (which
<< 3);
249 if (mstat
& (1 << i
)) {
250 for (ih
= &intrtab
[intnum
]; ih
!= NULL
;
252 if (ih
->ih_fun
!= NULL
)
253 ret
|= (ih
->ih_fun
)(ih
->ih_arg
);
255 printf("int0: unexpected mapped "
256 "interrupt %d\n", intnum
);
265 int1_local_intr(uint32_t status
, uint32_t cause
, uint32_t pc
, uint32_t ipend
)
270 struct sgimips_intrhand
*ih
;
272 stat
= bus_space_read_2(iot
, ioh
, INT1_LOCAL_STATUS
);
273 mask
= bus_space_read_1(iot
, ioh
, INT1_LOCAL_MASK
);
275 /* for STATUS, a 0 bit means interrupt is pending */
278 for (i
= 0; i
< 16; i
++) {
279 if (stat
& (1 << i
)) {
280 for (ih
= &intrtab
[i
]; ih
!= NULL
; ih
= ih
->ih_next
) {
281 if (ih
->ih_fun
!= NULL
)
282 (ih
->ih_fun
)(ih
->ih_arg
);
284 printf("int0: unexpected local "
285 "interrupt %d\n", i
);
292 int2_local0_intr(uint32_t status
, uint32_t cause
, uint32_t pc
, uint32_t ipend
)
297 struct sgimips_intrhand
*ih
;
299 l0stat
= bus_space_read_1(iot
, ioh
, INT2_LOCAL0_STATUS
);
300 l0mask
= bus_space_read_1(iot
, ioh
, INT2_LOCAL0_MASK
);
304 for (i
= 0; i
< 8; i
++) {
305 if (l0stat
& (1 << i
)) {
306 for (ih
= &intrtab
[i
]; ih
!= NULL
; ih
= ih
->ih_next
) {
307 if (ih
->ih_fun
!= NULL
)
308 (ih
->ih_fun
)(ih
->ih_arg
);
310 printf("int0: unexpected local0 "
311 "interrupt %d\n", i
);
318 int2_local1_intr(uint32_t status
, uint32_t cause
, uint32_t pc
, uint32_t ipend
)
323 struct sgimips_intrhand
*ih
;
325 l1stat
= bus_space_read_1(iot
, ioh
, INT2_LOCAL1_STATUS
);
326 l1mask
= bus_space_read_1(iot
, ioh
, INT2_LOCAL1_MASK
);
330 for (i
= 0; i
< 8; i
++) {
331 if (l1stat
& (1 << i
)) {
332 for (ih
= &intrtab
[8+i
]; ih
!= NULL
; ih
= ih
->ih_next
) {
333 if (ih
->ih_fun
!= NULL
)
334 (ih
->ih_fun
)(ih
->ih_arg
);
336 printf("int0: unexpected local1 "
337 " interrupt %x\n", 8 + i
);
344 int1_intr_establish(int level
, int ipl
, int (*handler
) (void *), void *arg
)
348 if (level
< 0 || level
>= NINTR
)
349 panic("invalid interrupt level");
351 if (intrtab
[level
].ih_fun
== NULL
) {
352 intrtab
[level
].ih_fun
= handler
;
353 intrtab
[level
].ih_arg
= arg
;
354 intrtab
[level
].ih_next
= NULL
;
356 struct sgimips_intrhand
*n
, *ih
;
358 ih
= malloc(sizeof *ih
, M_DEVBUF
, M_NOWAIT
);
360 printf("int0: can't allocate handler\n");
364 ih
->ih_fun
= handler
;
368 for (n
= &intrtab
[level
]; n
->ih_next
!= NULL
; n
= n
->ih_next
)
373 return NULL
; /* vector already set */
377 mask
= bus_space_read_1(iot
, ioh
, INT1_LOCAL_MASK
);
378 mask
|= (1 << level
);
379 bus_space_write_1(iot
, ioh
, INT1_LOCAL_MASK
, mask
);
381 printf("int0: level >= 16 (%d)\n", level
);
388 int2_intr_establish(int level
, int ipl
, int (*handler
) (void *), void *arg
)
392 if (level
< 0 || level
>= NINTR
)
393 panic("invalid interrupt level");
395 if (intrtab
[level
].ih_fun
== NULL
) {
396 intrtab
[level
].ih_fun
= handler
;
397 intrtab
[level
].ih_arg
= arg
;
398 intrtab
[level
].ih_next
= NULL
;
400 struct sgimips_intrhand
*n
, *ih
;
402 ih
= malloc(sizeof *ih
, M_DEVBUF
, M_NOWAIT
);
404 printf("int0: can't allocate handler\n");
408 ih
->ih_fun
= handler
;
412 for (n
= &intrtab
[level
]; n
->ih_next
!= NULL
; n
= n
->ih_next
)
417 return NULL
; /* vector already set */
421 mask
= bus_space_read_1(iot
, ioh
, INT2_LOCAL0_MASK
);
422 mask
|= (1 << level
);
423 bus_space_write_1(iot
, ioh
, INT2_LOCAL0_MASK
, mask
);
424 } else if (level
< 16) {
425 mask
= bus_space_read_1(iot
, ioh
, INT2_LOCAL1_MASK
);
426 mask
|= (1 << (level
- 8));
427 bus_space_write_1(iot
, ioh
, INT2_LOCAL1_MASK
, mask
);
428 } else if (level
< 24) {
429 /* Map0 interrupt maps to l0 bit 7, so turn that on too */
430 mask
= bus_space_read_1(iot
, ioh
, INT2_LOCAL0_MASK
);
432 bus_space_write_1(iot
, ioh
, INT2_LOCAL0_MASK
, mask
);
434 mask
= bus_space_read_1(iot
, ioh
, INT2_MAP_MASK0
);
435 mask
|= (1 << (level
- 16));
436 bus_space_write_1(iot
, ioh
, INT2_MAP_MASK0
, mask
);
438 /* Map1 interrupt maps to l1 bit 3, so turn that on too */
439 mask
= bus_space_read_1(iot
, ioh
, INT2_LOCAL1_MASK
);
441 bus_space_write_1(iot
, ioh
, INT2_LOCAL1_MASK
, mask
);
443 mask
= bus_space_read_1(iot
, ioh
, INT2_MAP_MASK1
);
444 mask
|= (1 << (level
- 24));
445 bus_space_write_1(iot
, ioh
, INT2_MAP_MASK1
, mask
);
453 int2_cpu_freq(struct device
*self
)
457 unsigned long ctrdiff
[3];
459 /* calibrate timer */
464 i
< sizeof(ctrdiff
) / sizeof(ctrdiff
[0]); i
++) {
466 ctrdiff
[i
] = int2_cal_timer();
467 } while (ctrdiff
[i
] == 0);
472 cps
= cps
/ (sizeof(ctrdiff
) / sizeof(ctrdiff
[0]));
474 printf("%s: bus %luMHz, CPU %luMHz\n",
475 self
->dv_xname
, cps
/ 10000, cps
/ 5000);
477 /* R4k/R4400/R4600/R5k count at half CPU frequency */
478 return (2 * cps
* hz
);
487 int startmsb
, lsb
, msb
;
488 unsigned long startctr
, endctr
;
491 * NOTE: HZ must be greater than 15 for this to work, as otherwise
492 * we'll overflow the counter. We round the answer to nearest 1
493 * MHz of the master (2x) clock.
495 roundtime
= (1000000 / hz
) / 2;
496 sampletime
= (1000000 / hz
) + 0xff;
497 startmsb
= (sampletime
>> 8);
501 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
,
502 (TIMER_SEL2
| TIMER_16BIT
| TIMER_RATEGEN
));
503 bus_space_write_1(iot
, ioh
, INT2_TIMER_2
, (sampletime
& 0xff));
504 bus_space_write_1(iot
, ioh
, INT2_TIMER_2
, (sampletime
>> 8));
506 startctr
= mips3_cp0_count_read();
508 /* Wait for the MSB to count down to zero */
510 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
, TIMER_SEL2
);
511 lsb
= bus_space_read_1(iot
, ioh
, INT2_TIMER_2
) & 0xff;
512 msb
= bus_space_read_1(iot
, ioh
, INT2_TIMER_2
) & 0xff;
514 endctr
= mips3_cp0_count_read();
518 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
,
519 (TIMER_SEL2
| TIMER_16BIT
| TIMER_SWSTROBE
));
523 return (endctr
- startctr
) / roundtime
* roundtime
;
528 * A master clock is wired to TIMER_2, which in turn clocks the two other
529 * timers. The master frequencies are as follows:
530 * IP6, IP10: 3.6864MHz
531 * IP12, IP20, IP22: 1MHz
534 * TIMER_0 and TIMER_1 interrupts are tied to MIPS interrupts as follows:
535 * IP6, IP10: TIMER_0: INT2, TIMER_1: INT4
536 * IP12: TIMER_0: INT3, TIMER_1: INT4
537 * IP17, IP20, IP22: TIMER_0: INT2, TIMER_1: INT3
539 * NB: Apparently int2 doesn't like counting down from one, but two works.
544 bus_size_t timer_control
, timer_0
, timer_1
, timer_2
;
548 case MACH_SGI_IP6
| MACH_SGI_IP10
:
549 int_8254_timecounter
.tc_frequency
= 3686400 / 8;
550 timer_control
= INT1_TIMER_CONTROL
;
551 timer_0
= INT1_TIMER_0
;
552 timer_1
= INT1_TIMER_1
;
553 timer_2
= INT1_TIMER_2
;
557 int_8254_timecounter
.tc_frequency
= 1000000 / 8;
558 timer_control
= INT2_TIMER_CONTROL
;
559 timer_0
= INT2_TIMER_0
;
560 timer_1
= INT2_TIMER_1
;
561 timer_2
= INT2_TIMER_2
;
565 panic("int_8254_cal");
570 /* Timer0 is our hz. */
571 bus_space_write_1(iot
, ioh
, timer_control
,
572 TIMER_SEL0
| TIMER_RATEGEN
| TIMER_16BIT
);
573 bus_space_write_1(iot
, ioh
, timer_0
,
574 (int_8254_timecounter
.tc_frequency
/ hz
) % 256);
577 bus_space_write_1(iot
, ioh
, timer_0
,
578 (int_8254_timecounter
.tc_frequency
/ hz
) / 256);
580 /* Timer1 is for timecounting. */
581 bus_space_write_1(iot
, ioh
, timer_control
,
582 TIMER_SEL1
| TIMER_RATEGEN
| TIMER_16BIT
);
583 bus_space_write_1(iot
, ioh
, timer_1
, 0xff);
586 bus_space_write_1(iot
, ioh
, timer_1
, 0xff);
588 /* Timer2 clocks timer0 and timer1. */
589 bus_space_write_1(iot
, ioh
, timer_control
,
590 TIMER_SEL2
| TIMER_RATEGEN
| TIMER_16BIT
);
591 bus_space_write_1(iot
, ioh
, timer_2
, 8);
594 bus_space_write_1(iot
, ioh
, timer_2
, 0);
598 tc_init(&int_8254_timecounter
);
602 int_8254_get_timecount(struct timecounter
*tc
)
611 case MACH_SGI_IP6
| MACH_SGI_IP10
:
612 bus_space_write_1(iot
, ioh
, INT1_TIMER_CONTROL
,
613 TIMER_SEL1
| TIMER_LATCH
);
614 lo
= bus_space_read_1(iot
, ioh
, INT1_TIMER_1
);
615 hi
= bus_space_read_1(iot
, ioh
, INT1_TIMER_1
);
619 bus_space_write_1(iot
, ioh
, INT2_TIMER_CONTROL
,
620 TIMER_SEL1
| TIMER_LATCH
);
621 lo
= bus_space_read_1(iot
, ioh
, INT2_TIMER_1
);
622 hi
= bus_space_read_1(iot
, ioh
, INT2_TIMER_1
);
626 panic("int_8254_get_timecount");
629 count
= 0xffff - ((hi
<< 8) | lo
);
632 return (int_8254_tc_count
+ count
);
636 int_8254_intr0(uint32_t status
, uint32_t cause
, uint32_t pc
, uint32_t ipend
)
638 struct clockframe cf
;
646 case MACH_SGI_IP6
| MACH_SGI_IP10
:
647 bus_space_read_1(iot
, ioh
, INT1_TIMER_0_ACK
);
651 bus_space_write_1(iot
, ioh
, INT2_TIMER_CLEAR
, 0x01);
655 panic("int_8254_intr0");
660 int_8254_intr1(uint32_t status
, uint32_t cause
, uint32_t pc
, uint32_t ipend
)
666 int_8254_tc_count
+= 0xffff;
668 case MACH_SGI_IP6
| MACH_SGI_IP10
:
669 bus_space_read_1(iot
, ioh
, INT1_TIMER_1_ACK
);
673 bus_space_write_1(iot
, ioh
, INT2_TIMER_CLEAR
, 0x02);
677 panic("int_8254_intr1");
684 int2_wait_fifo(uint32_t flag
)
690 while (bus_space_read_1(iot
, ioh
, INT2_LOCAL0_STATUS
) & flag
)