1*61a80495Sthorpej /* $NetBSD: int.c,v 1.32 2020/11/21 17:18:31 thorpej Exp $ */
290448f3fSsekiya
390448f3fSsekiya /*
485716c44Srumble * Copyright (c) 2009 Stephen M. Rumble
590448f3fSsekiya * Copyright (c) 2004 Christopher SEKIYA
690448f3fSsekiya * All rights reserved.
790448f3fSsekiya *
890448f3fSsekiya * Redistribution and use in source and binary forms, with or without
990448f3fSsekiya * modification, are permitted provided that the following conditions
1090448f3fSsekiya * are met:
1190448f3fSsekiya * 1. Redistributions of source code must retain the above copyright
1290448f3fSsekiya * notice, this list of conditions and the following disclaimer.
1390448f3fSsekiya * 2. Redistributions in binary form must reproduce the above copyright
1490448f3fSsekiya * notice, this list of conditions and the following disclaimer in the
1590448f3fSsekiya * documentation and/or other materials provided with the distribution.
1690448f3fSsekiya * 3. The name of the author may not be used to endorse or promote products
1790448f3fSsekiya * derived from this software without specific prior written permission.
1890448f3fSsekiya *
1990448f3fSsekiya * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2090448f3fSsekiya * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2190448f3fSsekiya * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2290448f3fSsekiya * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2390448f3fSsekiya * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2490448f3fSsekiya * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2590448f3fSsekiya * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2690448f3fSsekiya * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2790448f3fSsekiya * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2890448f3fSsekiya * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2990448f3fSsekiya */
3090448f3fSsekiya
3190448f3fSsekiya /*
3285716c44Srumble * INT1/INT2/INT3 interrupt controllers (IP6, IP10, IP12, IP20, IP22, IP24...)
3390448f3fSsekiya */
3490448f3fSsekiya
3590448f3fSsekiya #include <sys/cdefs.h>
36*61a80495Sthorpej __KERNEL_RCSID(0, "$NetBSD: int.c,v 1.32 2020/11/21 17:18:31 thorpej Exp $");
3790448f3fSsekiya
3823347d39Smatt #define __INTR_PRIVATE
3990448f3fSsekiya #include "opt_cputype.h"
4090448f3fSsekiya
4190448f3fSsekiya #include <sys/param.h>
4290448f3fSsekiya #include <sys/proc.h>
4390448f3fSsekiya #include <sys/systm.h>
440cc00310Srumble #include <sys/timetc.h>
4590448f3fSsekiya #include <sys/kernel.h>
4690448f3fSsekiya #include <sys/device.h>
47*61a80495Sthorpej #include <sys/kmem.h>
4890448f3fSsekiya
4990448f3fSsekiya #include <dev/ic/i8253reg.h>
5090448f3fSsekiya #include <machine/sysconf.h>
5190448f3fSsekiya #include <machine/machtype.h>
52cf10107dSdyoung #include <sys/bus.h>
5390448f3fSsekiya #include <mips/locore.h>
5490448f3fSsekiya
5590448f3fSsekiya #include <mips/cache.h>
5690448f3fSsekiya
5785716c44Srumble #include <sgimips/dev/int1reg.h>
5890448f3fSsekiya #include <sgimips/dev/int2reg.h>
594a4eccf8Ssekiya #include <sgimips/dev/int2var.h>
6090448f3fSsekiya
6190448f3fSsekiya static bus_space_handle_t ioh;
6290448f3fSsekiya static bus_space_tag_t iot;
6390448f3fSsekiya
64cbab9cadSchs static int int_match(device_t, cfdata_t, void *);
65cbab9cadSchs static void int_attach(device_t, device_t, void *);
6685716c44Srumble static void *int1_intr_establish(int, int, int (*)(void *), void *);
6785716c44Srumble static void *int2_intr_establish(int, int, int (*)(void *), void *);
6823347d39Smatt static void int1_local_intr(vaddr_t, uint32_t, uint32_t);
6923347d39Smatt static void int2_local0_intr(vaddr_t, uint32_t, uint32_t);
7023347d39Smatt static void int2_local1_intr(vaddr_t, uint32_t, uint32_t);
7185716c44Srumble static int int2_mappable_intr(void *);
72c4ba13a8Srumble static void int_8254_cal(void);
730cc00310Srumble static u_int int_8254_get_timecount(struct timecounter *);
7423347d39Smatt static void int_8254_intr0(vaddr_t, uint32_t, uint32_t);
7523347d39Smatt static void int_8254_intr1(vaddr_t, uint32_t, uint32_t);
76c4ba13a8Srumble
77c4ba13a8Srumble #ifdef MIPS3
78cbab9cadSchs static u_long int2_cpu_freq(device_t);
7985716c44Srumble static u_long int2_cal_timer(void);
80c4ba13a8Srumble #endif
8190448f3fSsekiya
820cc00310Srumble static struct timecounter int_8254_timecounter = {
83482eef70Srin .tc_get_timecount = int_8254_get_timecount,
84482eef70Srin .tc_counter_mask = ~0u,
85482eef70Srin .tc_name = "int i8254",
86482eef70Srin .tc_quality = 100,
870cc00310Srumble };
880cc00310Srumble
890cc00310Srumble static u_long int_8254_tc_count;
900cc00310Srumble
91cbab9cadSchs CFATTACH_DECL_NEW(int, 0,
9290448f3fSsekiya int_match, int_attach, NULL, NULL);
9390448f3fSsekiya
9490448f3fSsekiya static int
int_match(device_t parent,cfdata_t match,void * aux)95cbab9cadSchs int_match(device_t parent, cfdata_t match, void *aux)
9690448f3fSsekiya {
973b19c32cSpooka
9885716c44Srumble switch (mach_type) {
9985716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
10085716c44Srumble case MACH_SGI_IP12:
10185716c44Srumble case MACH_SGI_IP20:
10285716c44Srumble case MACH_SGI_IP22:
10390448f3fSsekiya return 1;
10485716c44Srumble }
10590448f3fSsekiya
10690448f3fSsekiya return 0;
10790448f3fSsekiya }
10890448f3fSsekiya
10990448f3fSsekiya static void
int_attach(device_t parent,device_t self,void * aux)110cbab9cadSchs int_attach(device_t parent, device_t self, void *aux)
11190448f3fSsekiya {
11234267609Stsutsui uint32_t address;
11325bb985eSmacallan int i;
11425bb985eSmacallan
11525bb985eSmacallan for (i = 0; i < NINTR; i++) {
11625bb985eSmacallan intrtab[i].ih_fun = NULL;
11725bb985eSmacallan snprintf(intrtab[i].ih_evname, 7, "%d", i);
11825bb985eSmacallan }
11990448f3fSsekiya
12085716c44Srumble switch (mach_type) {
12185716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
12285716c44Srumble address = INT1_IP6_IP10;
12385716c44Srumble break;
12485716c44Srumble
12585716c44Srumble case MACH_SGI_IP12:
12685716c44Srumble address = INT2_IP12;
12785716c44Srumble break;
12885716c44Srumble
12985716c44Srumble case MACH_SGI_IP20:
13085716c44Srumble address = INT2_IP20;
13185716c44Srumble break;
13285716c44Srumble
13385716c44Srumble case MACH_SGI_IP22:
13490448f3fSsekiya if (mach_subtype == MACH_SGI_IP22_FULLHOUSE)
13585716c44Srumble address = INT2_IP22;
13690448f3fSsekiya else
13785716c44Srumble address = INT2_IP24;
13885716c44Srumble break;
13985716c44Srumble
14085716c44Srumble default:
14190448f3fSsekiya panic("\nint0: passed match, but failed attach?");
14285716c44Srumble }
14390448f3fSsekiya
144e9e4c3f0Srumble printf(" addr 0x%x\n", address);
14590448f3fSsekiya
146eb488f67Smacallan iot = normal_memt;
147eb488f67Smacallan /*
148eb488f67Smacallan * XXX INT1 registers are spread *way* out, but for now this should
149eb488f67Smacallan * work
150eb488f67Smacallan */
151eb488f67Smacallan bus_space_map(iot, address, 0x100, 0, &ioh);
15290448f3fSsekiya
15385716c44Srumble switch (mach_type) {
15485716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
15590448f3fSsekiya /* Clean out interrupt masks */
15685716c44Srumble bus_space_write_1(iot, ioh, INT1_LOCAL_MASK, 0);
15785716c44Srumble
15885716c44Srumble /* Turn off timers and clear interrupts */
15985716c44Srumble bus_space_write_1(iot, ioh, INT1_TIMER_CONTROL,
16085716c44Srumble (TIMER_SEL0 | TIMER_16BIT | TIMER_SWSTROBE));
16185716c44Srumble bus_space_write_1(iot, ioh, INT1_TIMER_CONTROL,
16285716c44Srumble (TIMER_SEL1 | TIMER_16BIT | TIMER_SWSTROBE));
16385716c44Srumble bus_space_write_1(iot, ioh, INT1_TIMER_CONTROL,
16485716c44Srumble (TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE));
16585716c44Srumble wbflush();
16685716c44Srumble delay(4);
16785716c44Srumble bus_space_read_1(iot, ioh, INT1_TIMER_0_ACK);
16885716c44Srumble bus_space_read_1(iot, ioh, INT1_TIMER_1_ACK);
16985716c44Srumble
17085716c44Srumble platform.intr_establish = int1_intr_establish;
17185716c44Srumble platform.intr1 = int1_local_intr;
17285716c44Srumble platform.intr2 = int_8254_intr0;
17385716c44Srumble platform.intr4 = int_8254_intr1;
17485716c44Srumble int_8254_cal();
17585716c44Srumble break;
17685716c44Srumble
17785716c44Srumble case MACH_SGI_IP12:
17885716c44Srumble case MACH_SGI_IP20:
17985716c44Srumble case MACH_SGI_IP22:
18085716c44Srumble /* Clean out interrupt masks */
18185716c44Srumble bus_space_write_1(iot, ioh, INT2_LOCAL0_MASK, 0);
18285716c44Srumble bus_space_write_1(iot, ioh, INT2_LOCAL1_MASK, 0);
18385716c44Srumble bus_space_write_1(iot, ioh, INT2_MAP_MASK0, 0);
18485716c44Srumble bus_space_write_1(iot, ioh, INT2_MAP_MASK1, 0);
18590448f3fSsekiya
18690448f3fSsekiya /* Reset timer interrupts */
18785716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL,
18885716c44Srumble (TIMER_SEL0 | TIMER_16BIT | TIMER_SWSTROBE));
18985716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL,
19085716c44Srumble (TIMER_SEL1 | TIMER_16BIT | TIMER_SWSTROBE));
19185716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL,
19285716c44Srumble (TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE));
19385716c44Srumble wbflush();
19485716c44Srumble delay(4);
19585716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CLEAR, 0x03);
19690448f3fSsekiya
19785716c44Srumble if (mach_type == MACH_SGI_IP12) {
19885716c44Srumble platform.intr_establish = int2_intr_establish;
19985716c44Srumble platform.intr1 = int2_local0_intr;
20085716c44Srumble platform.intr2 = int2_local1_intr;
2014713534bSrumble platform.intr3 = int_8254_intr0;
2020cc00310Srumble platform.intr4 = int_8254_intr1;
20390448f3fSsekiya int_8254_cal();
20485716c44Srumble } else {
20585716c44Srumble platform.intr_establish = int2_intr_establish;
20685716c44Srumble platform.intr0 = int2_local0_intr;
20785716c44Srumble platform.intr1 = int2_local1_intr;
20839a22bd4Spooka #ifdef MIPS3
20985716c44Srumble curcpu()->ci_cpu_freq = int2_cpu_freq(self);
21085716c44Srumble #endif
21190448f3fSsekiya }
21290448f3fSsekiya break;
21385716c44Srumble
21490448f3fSsekiya default:
21590448f3fSsekiya panic("int0: unsupported machine type %i\n", mach_type);
21690448f3fSsekiya }
21790448f3fSsekiya
21890448f3fSsekiya curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz);
21990448f3fSsekiya curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000);
22090448f3fSsekiya
22190448f3fSsekiya if (mach_type == MACH_SGI_IP22) {
22290448f3fSsekiya /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */
22385716c44Srumble intrtab[7].ih_fun = int2_mappable_intr;
22490448f3fSsekiya intrtab[7].ih_arg = (void*) 0;
22525bb985eSmacallan snprintf(intrtab[7].ih_evname, 7, "map0");
22690448f3fSsekiya
22785716c44Srumble intrtab[11].ih_fun = int2_mappable_intr;
22890448f3fSsekiya intrtab[11].ih_arg = (void*) 1;
22925bb985eSmacallan snprintf(intrtab[11].ih_evname, 7, "map1");
23025bb985eSmacallan }
23125bb985eSmacallan
23225bb985eSmacallan for (i = 0; i < NINTR; i++) {
23325bb985eSmacallan evcnt_attach_dynamic(&intrtab[i].ih_evcnt,
23425bb985eSmacallan EVCNT_TYPE_INTR, NULL,
23525bb985eSmacallan "int", intrtab[i].ih_evname);
23690448f3fSsekiya }
23790448f3fSsekiya }
23890448f3fSsekiya
23990448f3fSsekiya int
int2_mappable_intr(void * arg)24085716c44Srumble int2_mappable_intr(void *arg)
24190448f3fSsekiya {
24290448f3fSsekiya int i;
24390448f3fSsekiya int ret;
24490448f3fSsekiya int intnum;
24534267609Stsutsui uint32_t mstat;
24634267609Stsutsui uint32_t mmask;
247290a34a0Smatt int which = (intptr_t)arg;
248432805bbSsekiya struct sgimips_intrhand *ih;
24990448f3fSsekiya
25090448f3fSsekiya ret = 0;
25185716c44Srumble mstat = bus_space_read_1(iot, ioh, INT2_MAP_STATUS);
25285716c44Srumble mmask = bus_space_read_1(iot, ioh, INT2_MAP_MASK0 + (which << 2));
25390448f3fSsekiya
25490448f3fSsekiya mstat &= mmask;
25590448f3fSsekiya
25690448f3fSsekiya for (i = 0; i < 8; i++) {
25790448f3fSsekiya intnum = i + 16 + (which << 3);
25890448f3fSsekiya if (mstat & (1 << i)) {
25925bb985eSmacallan intrtab[intnum].ih_evcnt.ev_count++;
260432805bbSsekiya for (ih = &intrtab[intnum]; ih != NULL;
261432805bbSsekiya ih = ih->ih_next) {
262432805bbSsekiya if (ih->ih_fun != NULL)
263432805bbSsekiya ret |= (ih->ih_fun)(ih->ih_arg);
26490448f3fSsekiya else
265432805bbSsekiya printf("int0: unexpected mapped "
266432805bbSsekiya "interrupt %d\n", intnum);
267432805bbSsekiya }
26890448f3fSsekiya }
26990448f3fSsekiya }
27090448f3fSsekiya
27190448f3fSsekiya return ret;
27290448f3fSsekiya }
27390448f3fSsekiya
27485716c44Srumble static void
int1_local_intr(vaddr_t pc,uint32_t status,uint32_t ipend)27523347d39Smatt int1_local_intr(vaddr_t pc, uint32_t status, uint32_t ipend)
27685716c44Srumble {
27785716c44Srumble int i;
27885716c44Srumble uint16_t stat;
27985716c44Srumble uint8_t mask;
28085716c44Srumble struct sgimips_intrhand *ih;
28185716c44Srumble
28285716c44Srumble stat = bus_space_read_2(iot, ioh, INT1_LOCAL_STATUS);
28385716c44Srumble mask = bus_space_read_1(iot, ioh, INT1_LOCAL_MASK);
28485716c44Srumble
28585716c44Srumble /* for STATUS, a 0 bit means interrupt is pending */
28685716c44Srumble stat = ~stat & mask;
28785716c44Srumble
28823347d39Smatt for (i = 0; stat != 0; i++, stat >>= 1) {
28923347d39Smatt if (stat & 1) {
29025bb985eSmacallan intrtab[i].ih_evcnt.ev_count++;
29185716c44Srumble for (ih = &intrtab[i]; ih != NULL; ih = ih->ih_next) {
29285716c44Srumble if (ih->ih_fun != NULL)
29385716c44Srumble (ih->ih_fun)(ih->ih_arg);
29485716c44Srumble else
29585716c44Srumble printf("int0: unexpected local "
29685716c44Srumble "interrupt %d\n", i);
29785716c44Srumble }
29885716c44Srumble }
29985716c44Srumble }
30085716c44Srumble }
30185716c44Srumble
30290448f3fSsekiya void
int2_local0_intr(vaddr_t pc,uint32_t status,uint32_t ipending)30323347d39Smatt int2_local0_intr(vaddr_t pc, uint32_t status, uint32_t ipending)
30490448f3fSsekiya {
30590448f3fSsekiya int i;
30634267609Stsutsui uint32_t l0stat;
30734267609Stsutsui uint32_t l0mask;
308432805bbSsekiya struct sgimips_intrhand *ih;
30990448f3fSsekiya
31085716c44Srumble l0stat = bus_space_read_1(iot, ioh, INT2_LOCAL0_STATUS);
31185716c44Srumble l0mask = bus_space_read_1(iot, ioh, INT2_LOCAL0_MASK);
31290448f3fSsekiya
31367e8288bSrumble l0stat &= l0mask;
31490448f3fSsekiya
31590448f3fSsekiya for (i = 0; i < 8; i++) {
31667e8288bSrumble if (l0stat & (1 << i)) {
31725bb985eSmacallan intrtab[i].ih_evcnt.ev_count++;
318432805bbSsekiya for (ih = &intrtab[i]; ih != NULL; ih = ih->ih_next) {
319432805bbSsekiya if (ih->ih_fun != NULL)
320432805bbSsekiya (ih->ih_fun)(ih->ih_arg);
32190448f3fSsekiya else
322432805bbSsekiya printf("int0: unexpected local0 "
323432805bbSsekiya "interrupt %d\n", i);
32490448f3fSsekiya }
32590448f3fSsekiya }
32690448f3fSsekiya }
327432805bbSsekiya }
328432805bbSsekiya
32990448f3fSsekiya void
int2_local1_intr(vaddr_t pc,uint32_t status,uint32_t ipending)33023347d39Smatt int2_local1_intr(vaddr_t pc, uint32_t status, uint32_t ipending)
33190448f3fSsekiya {
33290448f3fSsekiya int i;
33334267609Stsutsui uint32_t l1stat;
33434267609Stsutsui uint32_t l1mask;
335432805bbSsekiya struct sgimips_intrhand *ih;
33690448f3fSsekiya
33785716c44Srumble l1stat = bus_space_read_1(iot, ioh, INT2_LOCAL1_STATUS);
33885716c44Srumble l1mask = bus_space_read_1(iot, ioh, INT2_LOCAL1_MASK);
33990448f3fSsekiya
34090448f3fSsekiya l1stat &= l1mask;
34190448f3fSsekiya
34290448f3fSsekiya for (i = 0; i < 8; i++) {
34390448f3fSsekiya if (l1stat & (1 << i)) {
34425bb985eSmacallan intrtab[i].ih_evcnt.ev_count++;
345432805bbSsekiya for (ih = &intrtab[8+i]; ih != NULL; ih = ih->ih_next) {
346432805bbSsekiya if (ih->ih_fun != NULL)
347432805bbSsekiya (ih->ih_fun)(ih->ih_arg);
34890448f3fSsekiya else
349432805bbSsekiya printf("int0: unexpected local1 "
350432805bbSsekiya " interrupt %x\n", 8 + i);
351432805bbSsekiya }
35290448f3fSsekiya }
35390448f3fSsekiya }
35490448f3fSsekiya }
35590448f3fSsekiya
35690448f3fSsekiya void *
int1_intr_establish(int level,int ipl,int (* handler)(void *),void * arg)35785716c44Srumble int1_intr_establish(int level, int ipl, int (*handler) (void *), void *arg)
35885716c44Srumble {
35985716c44Srumble uint8_t mask;
36085716c44Srumble
36185716c44Srumble if (level < 0 || level >= NINTR)
36285716c44Srumble panic("invalid interrupt level");
36385716c44Srumble
36485716c44Srumble if (intrtab[level].ih_fun == NULL) {
36585716c44Srumble intrtab[level].ih_fun = handler;
36685716c44Srumble intrtab[level].ih_arg = arg;
36785716c44Srumble intrtab[level].ih_next = NULL;
36885716c44Srumble } else {
36985716c44Srumble struct sgimips_intrhand *n, *ih;
37085716c44Srumble
371*61a80495Sthorpej ih = kmem_alloc(sizeof *ih, KM_SLEEP);
37285716c44Srumble ih->ih_fun = handler;
37385716c44Srumble ih->ih_arg = arg;
37485716c44Srumble ih->ih_next = NULL;
37585716c44Srumble
37685716c44Srumble for (n = &intrtab[level]; n->ih_next != NULL; n = n->ih_next)
37785716c44Srumble ;
37885716c44Srumble
37985716c44Srumble n->ih_next = ih;
38085716c44Srumble
38185716c44Srumble return NULL; /* vector already set */
38285716c44Srumble }
38385716c44Srumble
38485716c44Srumble if (level < 8) {
38585716c44Srumble mask = bus_space_read_1(iot, ioh, INT1_LOCAL_MASK);
38685716c44Srumble mask |= (1 << level);
38785716c44Srumble bus_space_write_1(iot, ioh, INT1_LOCAL_MASK, mask);
38885716c44Srumble } else {
38985716c44Srumble printf("int0: level >= 16 (%d)\n", level);
39085716c44Srumble }
39185716c44Srumble
39285716c44Srumble return NULL;
39385716c44Srumble }
39485716c44Srumble
39585716c44Srumble void *
int2_intr_establish(int level,int ipl,int (* handler)(void *),void * arg)39685716c44Srumble int2_intr_establish(int level, int ipl, int (*handler) (void *), void *arg)
39790448f3fSsekiya {
39834267609Stsutsui uint32_t mask;
39990448f3fSsekiya
40090448f3fSsekiya if (level < 0 || level >= NINTR)
40190448f3fSsekiya panic("invalid interrupt level");
40290448f3fSsekiya
403432805bbSsekiya if (intrtab[level].ih_fun == NULL) {
404432805bbSsekiya intrtab[level].ih_fun = handler;
405432805bbSsekiya intrtab[level].ih_arg = arg;
406432805bbSsekiya intrtab[level].ih_next = NULL;
407432805bbSsekiya } else {
40834267609Stsutsui struct sgimips_intrhand *n, *ih;
409432805bbSsekiya
410*61a80495Sthorpej ih = kmem_alloc(sizeof *ih, KM_SLEEP);
411432805bbSsekiya ih->ih_fun = handler;
412432805bbSsekiya ih->ih_arg = arg;
413432805bbSsekiya ih->ih_next = NULL;
414432805bbSsekiya
415432805bbSsekiya for (n = &intrtab[level]; n->ih_next != NULL; n = n->ih_next)
416432805bbSsekiya ;
417432805bbSsekiya
418432805bbSsekiya n->ih_next = ih;
419432805bbSsekiya
42034267609Stsutsui return NULL; /* vector already set */
421432805bbSsekiya }
422432805bbSsekiya
42390448f3fSsekiya if (level < 8) {
42485716c44Srumble mask = bus_space_read_1(iot, ioh, INT2_LOCAL0_MASK);
42590448f3fSsekiya mask |= (1 << level);
42685716c44Srumble bus_space_write_1(iot, ioh, INT2_LOCAL0_MASK, mask);
42790448f3fSsekiya } else if (level < 16) {
42885716c44Srumble mask = bus_space_read_1(iot, ioh, INT2_LOCAL1_MASK);
42990448f3fSsekiya mask |= (1 << (level - 8));
43085716c44Srumble bus_space_write_1(iot, ioh, INT2_LOCAL1_MASK, mask);
43190448f3fSsekiya } else if (level < 24) {
43290448f3fSsekiya /* Map0 interrupt maps to l0 bit 7, so turn that on too */
43385716c44Srumble mask = bus_space_read_1(iot, ioh, INT2_LOCAL0_MASK);
43490448f3fSsekiya mask |= (1 << 7);
43585716c44Srumble bus_space_write_1(iot, ioh, INT2_LOCAL0_MASK, mask);
43690448f3fSsekiya
43785716c44Srumble mask = bus_space_read_1(iot, ioh, INT2_MAP_MASK0);
43890448f3fSsekiya mask |= (1 << (level - 16));
43985716c44Srumble bus_space_write_1(iot, ioh, INT2_MAP_MASK0, mask);
44090448f3fSsekiya } else {
44190448f3fSsekiya /* Map1 interrupt maps to l1 bit 3, so turn that on too */
44285716c44Srumble mask = bus_space_read_1(iot, ioh, INT2_LOCAL1_MASK);
44390448f3fSsekiya mask |= (1 << 3);
44485716c44Srumble bus_space_write_1(iot, ioh, INT2_LOCAL1_MASK, mask);
44590448f3fSsekiya
44685716c44Srumble mask = bus_space_read_1(iot, ioh, INT2_MAP_MASK1);
44790448f3fSsekiya mask |= (1 << (level - 24));
44885716c44Srumble bus_space_write_1(iot, ioh, INT2_MAP_MASK1, mask);
44990448f3fSsekiya }
45090448f3fSsekiya
45134267609Stsutsui return NULL;
45290448f3fSsekiya }
45390448f3fSsekiya
45439a22bd4Spooka #ifdef MIPS3
455c4ba13a8Srumble static u_long
int2_cpu_freq(device_t self)456cbab9cadSchs int2_cpu_freq(device_t self)
45785716c44Srumble {
45885716c44Srumble int i;
45985716c44Srumble unsigned long cps;
46085716c44Srumble unsigned long ctrdiff[3];
46185716c44Srumble
46285716c44Srumble /* calibrate timer */
46385716c44Srumble int2_cal_timer();
46485716c44Srumble
46585716c44Srumble cps = 0;
46685716c44Srumble for (i = 0;
46785716c44Srumble i < sizeof(ctrdiff) / sizeof(ctrdiff[0]); i++) {
46885716c44Srumble do {
46985716c44Srumble ctrdiff[i] = int2_cal_timer();
47085716c44Srumble } while (ctrdiff[i] == 0);
47185716c44Srumble
47285716c44Srumble cps += ctrdiff[i];
47385716c44Srumble }
47485716c44Srumble
47585716c44Srumble cps = cps / (sizeof(ctrdiff) / sizeof(ctrdiff[0]));
47685716c44Srumble
47785716c44Srumble printf("%s: bus %luMHz, CPU %luMHz\n",
478cbab9cadSchs device_xname(self), cps / 10000, cps / 5000);
47985716c44Srumble
48085716c44Srumble /* R4k/R4400/R4600/R5k count at half CPU frequency */
48185716c44Srumble return (2 * cps * hz);
48285716c44Srumble }
48385716c44Srumble
48485716c44Srumble static u_long
int2_cal_timer(void)48585716c44Srumble int2_cal_timer(void)
48690448f3fSsekiya {
48790448f3fSsekiya int s;
48890448f3fSsekiya int roundtime;
48990448f3fSsekiya int sampletime;
4905dbd45e4Smacallan int msb;
49190448f3fSsekiya unsigned long startctr, endctr;
49290448f3fSsekiya
49390448f3fSsekiya /*
49490448f3fSsekiya * NOTE: HZ must be greater than 15 for this to work, as otherwise
49585716c44Srumble * we'll overflow the counter. We round the answer to nearest 1
49690448f3fSsekiya * MHz of the master (2x) clock.
49790448f3fSsekiya */
49890448f3fSsekiya roundtime = (1000000 / hz) / 2;
49990448f3fSsekiya sampletime = (1000000 / hz) + 0xff;
50090448f3fSsekiya
50190448f3fSsekiya s = splhigh();
50290448f3fSsekiya
50385716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL,
50490448f3fSsekiya (TIMER_SEL2 | TIMER_16BIT | TIMER_RATEGEN));
50585716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_2, (sampletime & 0xff));
50685716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_2, (sampletime >> 8));
50790448f3fSsekiya
50890448f3fSsekiya startctr = mips3_cp0_count_read();
50990448f3fSsekiya
51090448f3fSsekiya /* Wait for the MSB to count down to zero */
51190448f3fSsekiya do {
51285716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL, TIMER_SEL2);
5135dbd45e4Smacallan (void)bus_space_read_1(iot, ioh, INT2_TIMER_2);
51485716c44Srumble msb = bus_space_read_1(iot, ioh, INT2_TIMER_2) & 0xff;
51590448f3fSsekiya
51690448f3fSsekiya endctr = mips3_cp0_count_read();
51790448f3fSsekiya } while (msb);
51890448f3fSsekiya
51990448f3fSsekiya /* Turn off timer */
52085716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL,
52190448f3fSsekiya (TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE));
52290448f3fSsekiya
52390448f3fSsekiya splx(s);
52490448f3fSsekiya
52590448f3fSsekiya return (endctr - startctr) / roundtime * roundtime;
52690448f3fSsekiya }
52739a22bd4Spooka #endif /* MIPS3 */
52890448f3fSsekiya
5290cc00310Srumble /*
53085716c44Srumble * A master clock is wired to TIMER_2, which in turn clocks the two other
53185716c44Srumble * timers. The master frequencies are as follows:
53285716c44Srumble * IP6, IP10: 3.6864MHz
53385716c44Srumble * IP12, IP20, IP22: 1MHz
53485716c44Srumble * IP17: 10MHz
5350cc00310Srumble *
53685716c44Srumble * TIMER_0 and TIMER_1 interrupts are tied to MIPS interrupts as follows:
53785716c44Srumble * IP6, IP10: TIMER_0: INT2, TIMER_1: INT4
53885716c44Srumble * IP12: TIMER_0: INT3, TIMER_1: INT4
53985716c44Srumble * IP17, IP20, IP22: TIMER_0: INT2, TIMER_1: INT3
54085716c44Srumble *
54185716c44Srumble * NB: Apparently int2 doesn't like counting down from one, but two works.
5420cc00310Srumble */
54390448f3fSsekiya void
int_8254_cal(void)54490448f3fSsekiya int_8254_cal(void)
54590448f3fSsekiya {
54685716c44Srumble bus_size_t timer_control, timer_0, timer_1, timer_2;
54790448f3fSsekiya int s;
54890448f3fSsekiya
54985716c44Srumble switch (mach_type) {
55085716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
55185716c44Srumble int_8254_timecounter.tc_frequency = 3686400 / 8;
55285716c44Srumble timer_control = INT1_TIMER_CONTROL;
55385716c44Srumble timer_0 = INT1_TIMER_0;
55485716c44Srumble timer_1 = INT1_TIMER_1;
55585716c44Srumble timer_2 = INT1_TIMER_2;
55685716c44Srumble break;
55785716c44Srumble
55885716c44Srumble case MACH_SGI_IP12:
55985716c44Srumble int_8254_timecounter.tc_frequency = 1000000 / 8;
56085716c44Srumble timer_control = INT2_TIMER_CONTROL;
56185716c44Srumble timer_0 = INT2_TIMER_0;
56285716c44Srumble timer_1 = INT2_TIMER_1;
56385716c44Srumble timer_2 = INT2_TIMER_2;
56485716c44Srumble break;
56585716c44Srumble
56685716c44Srumble default:
56785716c44Srumble panic("int_8254_cal");
56885716c44Srumble }
56985716c44Srumble
57090448f3fSsekiya s = splhigh();
57190448f3fSsekiya
57285716c44Srumble /* Timer0 is our hz. */
57385716c44Srumble bus_space_write_1(iot, ioh, timer_control,
57490448f3fSsekiya TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
57585716c44Srumble bus_space_write_1(iot, ioh, timer_0,
57685716c44Srumble (int_8254_timecounter.tc_frequency / hz) % 256);
57790448f3fSsekiya wbflush();
57890448f3fSsekiya delay(4);
57985716c44Srumble bus_space_write_1(iot, ioh, timer_0,
58085716c44Srumble (int_8254_timecounter.tc_frequency / hz) / 256);
5810cc00310Srumble
58285716c44Srumble /* Timer1 is for timecounting. */
58385716c44Srumble bus_space_write_1(iot, ioh, timer_control,
5840cc00310Srumble TIMER_SEL1 | TIMER_RATEGEN | TIMER_16BIT);
58585716c44Srumble bus_space_write_1(iot, ioh, timer_1, 0xff);
5860cc00310Srumble wbflush();
5870cc00310Srumble delay(4);
58885716c44Srumble bus_space_write_1(iot, ioh, timer_1, 0xff);
58990448f3fSsekiya
59085716c44Srumble /* Timer2 clocks timer0 and timer1. */
59185716c44Srumble bus_space_write_1(iot, ioh, timer_control,
59290448f3fSsekiya TIMER_SEL2 | TIMER_RATEGEN | TIMER_16BIT);
59385716c44Srumble bus_space_write_1(iot, ioh, timer_2, 8);
59490448f3fSsekiya wbflush();
59590448f3fSsekiya delay(4);
59685716c44Srumble bus_space_write_1(iot, ioh, timer_2, 0);
5970cc00310Srumble
5980cc00310Srumble splx(s);
5990cc00310Srumble
60085716c44Srumble tc_init(&int_8254_timecounter);
60185716c44Srumble }
6020cc00310Srumble
6030cc00310Srumble static u_int
int_8254_get_timecount(struct timecounter * tc)6040cc00310Srumble int_8254_get_timecount(struct timecounter *tc)
6050cc00310Srumble {
6060cc00310Srumble int s;
6070cc00310Srumble u_int count;
60885716c44Srumble u_char lo, hi;
6090cc00310Srumble
6100cc00310Srumble s = splhigh();
6110cc00310Srumble
61285716c44Srumble switch (mach_type) {
61385716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
61485716c44Srumble bus_space_write_1(iot, ioh, INT1_TIMER_CONTROL,
6150cc00310Srumble TIMER_SEL1 | TIMER_LATCH);
61685716c44Srumble lo = bus_space_read_1(iot, ioh, INT1_TIMER_1);
61785716c44Srumble hi = bus_space_read_1(iot, ioh, INT1_TIMER_1);
61885716c44Srumble break;
6190cc00310Srumble
62085716c44Srumble case MACH_SGI_IP12:
62185716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CONTROL,
62285716c44Srumble TIMER_SEL1 | TIMER_LATCH);
62385716c44Srumble lo = bus_space_read_1(iot, ioh, INT2_TIMER_1);
62485716c44Srumble hi = bus_space_read_1(iot, ioh, INT2_TIMER_1);
62585716c44Srumble break;
62685716c44Srumble
62785716c44Srumble default:
62885716c44Srumble panic("int_8254_get_timecount");
62985716c44Srumble }
63085716c44Srumble
63185716c44Srumble count = 0xffff - ((hi << 8) | lo);
6320cc00310Srumble splx(s);
6330cc00310Srumble
63485716c44Srumble return (int_8254_tc_count + count);
6350cc00310Srumble }
6360cc00310Srumble
6370cc00310Srumble static void
int_8254_intr0(vaddr_t pc,uint32_t status,uint32_t ipending)63823347d39Smatt int_8254_intr0(vaddr_t pc, uint32_t status, uint32_t ipending)
6394713534bSrumble {
6404713534bSrumble struct clockframe cf;
6414713534bSrumble
6424713534bSrumble cf.pc = pc;
6434713534bSrumble cf.sr = status;
6447567d86eStsutsui cf.intr = (curcpu()->ci_idepth > 1);
6454713534bSrumble
6464713534bSrumble hardclock(&cf);
6474713534bSrumble
64885716c44Srumble switch (mach_type) {
64985716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
65085716c44Srumble bus_space_read_1(iot, ioh, INT1_TIMER_0_ACK);
65185716c44Srumble break;
65285716c44Srumble
65385716c44Srumble case MACH_SGI_IP12:
65485716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CLEAR, 0x01);
65585716c44Srumble break;
65685716c44Srumble
65785716c44Srumble default:
65885716c44Srumble panic("int_8254_intr0");
65985716c44Srumble }
6604713534bSrumble }
6614713534bSrumble
6624713534bSrumble static void
int_8254_intr1(vaddr_t pc,uint32_t status,uint32_t ipending)66323347d39Smatt int_8254_intr1(vaddr_t pc, uint32_t status, uint32_t ipending)
6640cc00310Srumble {
6650cc00310Srumble int s;
6660cc00310Srumble
6670cc00310Srumble s = splhigh();
6680cc00310Srumble
6690cc00310Srumble int_8254_tc_count += 0xffff;
67085716c44Srumble switch (mach_type) {
67185716c44Srumble case MACH_SGI_IP6 | MACH_SGI_IP10:
67285716c44Srumble bus_space_read_1(iot, ioh, INT1_TIMER_1_ACK);
67385716c44Srumble break;
67485716c44Srumble
67585716c44Srumble case MACH_SGI_IP12:
67685716c44Srumble bus_space_write_1(iot, ioh, INT2_TIMER_CLEAR, 0x02);
67785716c44Srumble break;
67885716c44Srumble
67985716c44Srumble default:
68085716c44Srumble panic("int_8254_intr1");
68185716c44Srumble }
6820cc00310Srumble
68390448f3fSsekiya splx(s);
68490448f3fSsekiya }
6854a4eccf8Ssekiya
6864a4eccf8Ssekiya void
int2_wait_fifo(uint32_t flag)68734267609Stsutsui int2_wait_fifo(uint32_t flag)
6884a4eccf8Ssekiya {
68934267609Stsutsui
690432805bbSsekiya if (ioh == 0)
691432805bbSsekiya delay(5000);
692432805bbSsekiya else
69385716c44Srumble while (bus_space_read_1(iot, ioh, INT2_LOCAL0_STATUS) & flag)
6944a4eccf8Ssekiya ;
6954a4eccf8Ssekiya }
696