Home | History | Annotate | Line # | Download | only in dev
int.c revision 1.10
      1 /*	$NetBSD: int.c,v 1.10 2005/10/18 11:31:12 tsutsui Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2004 Christopher SEKIYA
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF 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, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 /*
     31  * INT/INT2/INT3 interrupt controller (used in Indy's, Indigo's, etc..)
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: int.c,v 1.10 2005/10/18 11:31:12 tsutsui Exp $");
     36 
     37 #include "opt_cputype.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/proc.h>
     41 #include <sys/systm.h>
     42 #include <sys/kernel.h>
     43 #include <sys/device.h>
     44 #include <sys/malloc.h>
     45 
     46 #include <dev/ic/i8253reg.h>
     47 #include <machine/sysconf.h>
     48 #include <machine/machtype.h>
     49 #include <machine/bus.h>
     50 #include <mips/locore.h>
     51 
     52 #include <mips/cache.h>
     53 
     54 #include <sgimips/dev/int2reg.h>
     55 #include <sgimips/dev/int2var.h>
     56 
     57 static bus_space_handle_t ioh;
     58 static bus_space_tag_t iot;
     59 
     60 struct int_softc {
     61 	struct device sc_dev;
     62 };
     63 
     64 
     65 static int	int_match(struct device *, struct cfdata *, void *);
     66 static void	int_attach(struct device *, struct device *, void *);
     67 void 		int_local0_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
     68 void		int_local1_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
     69 int 		int_mappable_intr(void *);
     70 void		*int_intr_establish(int, int, int (*)(void *), void *);
     71 unsigned long	int_cal_timer(void);
     72 void		int_8254_cal(void);
     73 
     74 CFATTACH_DECL(int, sizeof(struct int_softc),
     75 	int_match, int_attach, NULL, NULL);
     76 
     77 static int
     78 int_match(struct device *parent, struct cfdata *match, void *aux)
     79 {
     80 
     81 	if ((mach_type == MACH_SGI_IP12) || (mach_type == MACH_SGI_IP20) ||
     82 	    (mach_type == MACH_SGI_IP22) )
     83 		return 1;
     84 
     85 	return 0;
     86 }
     87 
     88 static void
     89 int_attach(struct device *parent, struct device *self, void *aux)
     90 {
     91 	u_int32_t address;
     92 
     93 	if (mach_type == MACH_SGI_IP12)
     94 		address = INT_IP12;
     95 	else if (mach_type == MACH_SGI_IP20)
     96 		address = INT_IP20;
     97 	else if (mach_type == MACH_SGI_IP22) {
     98 		if (mach_subtype == MACH_SGI_IP22_FULLHOUSE)
     99 			address = INT_IP22;
    100 		else
    101 			address = INT_IP24;
    102 	} else
    103 		panic("\nint0: passed match, but failed attach?");
    104 
    105 	printf(" addr 0x%x", address);
    106 
    107 	bus_space_map(iot, address, 0, 0, &ioh);
    108 	iot = SGIMIPS_BUS_SPACE_NORMAL;
    109 
    110 	/* Clean out interrupt masks */
    111 	bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, 0);
    112 	bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, 0);
    113 	bus_space_write_4(iot, ioh, INT2_MAP_MASK0, 0);
    114 	bus_space_write_4(iot, ioh, INT2_MAP_MASK1, 0);
    115 
    116 	/* Reset timer interrupts */
    117 	bus_space_write_4(iot, ioh, INT2_TIMER_CLEAR, 0x03);
    118 
    119 	switch (mach_type) {
    120 		case MACH_SGI_IP12:
    121 			platform.intr1 = int_local0_intr;
    122 			platform.intr2 = int_local1_intr;
    123 			int_8254_cal();
    124 			break;
    125 #ifdef MIPS3
    126 		case MACH_SGI_IP20:
    127 		case MACH_SGI_IP22:
    128 		{
    129 			int i;
    130 			unsigned long cps;
    131 			unsigned long ctrdiff[3];
    132 
    133 			platform.intr0 = int_local0_intr;
    134 			platform.intr1 = int_local1_intr;
    135 
    136 			/* calibrate timer */
    137 			int_cal_timer();
    138 
    139 			cps = 0;
    140 			for (i = 0;
    141 			    i < sizeof(ctrdiff) / sizeof(ctrdiff[0]); i++) {
    142 				do {
    143 					ctrdiff[i] = int_cal_timer();
    144 				} while (ctrdiff[i] == 0);
    145 
    146 				cps += ctrdiff[i];
    147 			}
    148 
    149 			cps = cps / (sizeof(ctrdiff) / sizeof(ctrdiff[0]));
    150 
    151 			printf(": bus %luMHz, CPU %luMHz",
    152 			    cps / 10000, cps / 5000);
    153 
    154 			/* R4k/R4400/R4600/R5k count at half CPU frequency */
    155 			curcpu()->ci_cpu_freq = 2 * cps * hz;
    156 		}
    157 #endif /* MIPS3 */
    158 
    159 			break;
    160 		default:
    161 			panic("int0: unsupported machine type %i\n", mach_type);
    162 			break;
    163 	}
    164 
    165 	printf("\n");
    166 
    167 	curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz);
    168 	curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000);
    169 	MIPS_SET_CI_RECIPRICAL(curcpu());
    170 
    171 	if (mach_type == MACH_SGI_IP22) {
    172 		/* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */
    173 		intrtab[7].ih_fun = int_mappable_intr;
    174 		intrtab[7].ih_arg = (void*) 0;
    175 
    176 		intrtab[11].ih_fun = int_mappable_intr;
    177 		intrtab[11].ih_arg = (void*) 1;
    178 	}
    179 
    180 	platform.intr_establish = int_intr_establish;
    181 }
    182 
    183 int
    184 int_mappable_intr(void *arg)
    185 {
    186 	int i;
    187 	int ret;
    188 	int intnum;
    189 	u_int32_t mstat;
    190 	u_int32_t mmask;
    191 	int which = (int)arg;
    192 	struct sgimips_intrhand *ih;
    193 
    194 	ret = 0;
    195 	mstat = bus_space_read_4(iot, ioh, INT2_MAP_STATUS);
    196 	mmask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0 + (which << 2));
    197 
    198 	mstat &= mmask;
    199 
    200 	for (i = 0; i < 8; i++) {
    201 		intnum = i + 16 + (which << 3);
    202 		if (mstat & (1 << i)) {
    203 			for (ih = &intrtab[intnum]; ih != NULL;
    204 							ih = ih->ih_next) {
    205 				if (ih->ih_fun != NULL)
    206 					ret |= (ih->ih_fun)(ih->ih_arg);
    207 				else
    208 					printf("int0: unexpected mapped "
    209 					       "interrupt %d\n", intnum);
    210 			}
    211 		}
    212 	}
    213 
    214 	return ret;
    215 }
    216 
    217 void
    218 int_local0_intr(u_int32_t status, u_int32_t cause, u_int32_t pc,
    219 		u_int32_t ipending)
    220 {
    221 	int i;
    222 	u_int32_t l0stat;
    223 	u_int32_t l0mask;
    224 	struct sgimips_intrhand *ih;
    225 
    226 	l0stat = bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS);
    227 	l0mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK);
    228 
    229 	/* The "FIFO full" bit is apparently not latched in the ISR, which
    230 	   means that it won't be present in l0stat unless we're very lucky.
    231 	   If no interrupts are pending, assume that it was caused by a full
    232 	   FIFO and dispatch.
    233 	 */
    234 	bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, l0mask & (0xfe));
    235 	if ( (l0mask & 0x01) && ((l0stat & l0mask) == 0) )
    236 	  l0stat = 0x01;
    237 
    238 	for (i = 0; i < 8; i++) {
    239 		if ( (l0stat & l0mask) & (1 << i)) {
    240 			for (ih = &intrtab[i]; ih != NULL; ih = ih->ih_next) {
    241 				if (ih->ih_fun != NULL)
    242 					(ih->ih_fun)(ih->ih_arg);
    243 				else
    244 					printf("int0: unexpected local0 "
    245 					       "interrupt %d\n", i);
    246 			}
    247 		}
    248 	}
    249 
    250 	/* Unmask FIFO */
    251 	bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, l0mask | 0x01);
    252 }
    253 
    254 void
    255 int_local1_intr(u_int32_t status, u_int32_t cause, u_int32_t pc,
    256 		u_int32_t ipending)
    257 {
    258 	int i;
    259 	u_int32_t l1stat;
    260 	u_int32_t l1mask;
    261 	struct sgimips_intrhand *ih;
    262 
    263 	l1stat = bus_space_read_4(iot, ioh, INT2_LOCAL1_STATUS);
    264 	l1mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK);
    265 
    266 	l1stat &= l1mask;
    267 
    268 	for (i = 0; i < 8; i++) {
    269 		if (l1stat & (1 << i)) {
    270 			for (ih = &intrtab[8+i]; ih != NULL; ih = ih->ih_next) {
    271 				if (ih->ih_fun != NULL)
    272 					(ih->ih_fun)(ih->ih_arg);
    273 				else
    274 					printf("int0: unexpected local1 "
    275 					       " interrupt %x\n", 8 + i);
    276 			}
    277 		}
    278 	}
    279 }
    280 
    281 void *
    282 int_intr_establish(int level, int ipl, int (*handler) (void *), void *arg)
    283 {
    284 	u_int32_t mask;
    285 
    286 	if (level < 0 || level >= NINTR)
    287 		panic("invalid interrupt level");
    288 
    289 	if (intrtab[level].ih_fun == NULL) {
    290 		intrtab[level].ih_fun = handler;
    291 		intrtab[level].ih_arg = arg;
    292 		intrtab[level].ih_next = NULL;
    293 	} else {
    294 		struct sgimips_intrhand *n, *ih = malloc(sizeof *ih,
    295 							 M_DEVBUF, M_NOWAIT);
    296 
    297 		if (ih == NULL) {
    298 			printf("int_intr_establish: can't allocate handler\n");
    299 			return (void *)NULL;
    300 		}
    301 
    302 		ih->ih_fun = handler;
    303 		ih->ih_arg = arg;
    304 		ih->ih_next = NULL;
    305 
    306 		for (n = &intrtab[level]; n->ih_next != NULL; n = n->ih_next)
    307 			;
    308 
    309 		n->ih_next = ih;
    310 
    311 		return (void *)NULL;	/* vector already set */
    312 	}
    313 
    314 
    315 	if (level < 8) {
    316 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK);
    317 		mask |= (1 << level);
    318 		bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask);
    319 	} else if (level < 16) {
    320 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK);
    321 		mask |= (1 << (level - 8));
    322 		bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask);
    323 	} else if (level < 24) {
    324 		/* Map0 interrupt maps to l0 bit 7, so turn that on too */
    325 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK);
    326 		mask |= (1 << 7);
    327 		bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask);
    328 
    329 		mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0);
    330 		mask |= (1 << (level - 16));
    331 		bus_space_write_4(iot, ioh, INT2_MAP_MASK0, mask);
    332 	} else {
    333 		/* Map1 interrupt maps to l1 bit 3, so turn that on too */
    334 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK);
    335 		mask |= (1 << 3);
    336 		bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask);
    337 
    338 		mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK1);
    339 		mask |= (1 << (level - 24));
    340 		bus_space_write_4(iot, ioh, INT2_MAP_MASK1, mask);
    341 	}
    342 
    343 	return (void *)NULL;
    344 }
    345 
    346 #ifdef MIPS3
    347 unsigned long
    348 int_cal_timer(void)
    349 {
    350 	int s;
    351 	int roundtime;
    352 	int sampletime;
    353 	int startmsb, lsb, msb;
    354 	unsigned long startctr, endctr;
    355 
    356 	/*
    357 	 * NOTE: HZ must be greater than 15 for this to work, as otherwise
    358 	 * we'll overflow the counter.  We round the answer to hearest 1
    359 	 * MHz of the master (2x) clock.
    360 	 */
    361 	roundtime = (1000000 / hz) / 2;
    362 	sampletime = (1000000 / hz) + 0xff;
    363 	startmsb = (sampletime >> 8);
    364 
    365 	s = splhigh();
    366 
    367 	bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL,
    368 		( TIMER_SEL2 | TIMER_16BIT | TIMER_RATEGEN) );
    369 	bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime & 0xff));
    370 	bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime >> 8));
    371 
    372 	startctr = mips3_cp0_count_read();
    373 
    374 	/* Wait for the MSB to count down to zero */
    375 	do {
    376 		bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, TIMER_SEL2 );
    377 		lsb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff;
    378 		msb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff;
    379 
    380 		endctr = mips3_cp0_count_read();
    381 	} while (msb);
    382 
    383 	/* Turn off timer */
    384 	bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL,
    385 		( TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE) );
    386 
    387 	splx(s);
    388 
    389 	return (endctr - startctr) / roundtime * roundtime;
    390 }
    391 #endif /* MIPS3 */
    392 
    393 void
    394 int_8254_cal(void)
    395 {
    396 	int s;
    397 
    398 	s = splhigh();
    399 
    400 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15,
    401 	    TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    402 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) % 256);
    403 	wbflush();
    404 	delay(4);
    405 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) / 256);
    406 
    407 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15,
    408 	    TIMER_SEL2|TIMER_RATEGEN|TIMER_16BIT);
    409 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 50);
    410 	wbflush();
    411 	delay(4);
    412 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 0);
    413 	splx(s);
    414 }
    415 
    416 void
    417 int2_wait_fifo(u_int32_t flag)
    418 {
    419 	if (ioh == 0)
    420 		delay(5000);
    421 	else
    422 		while (bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS) & flag)
    423 			;
    424 }
    425