1 /* $NetBSD: int.c,v 1.17 2008/01/09 20:38:36 wiz 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.17 2008/01/09 20:38:36 wiz 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/timetc.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 47 #include <dev/ic/i8253reg.h> 48 #include <machine/sysconf.h> 49 #include <machine/machtype.h> 50 #include <machine/bus.h> 51 #include <mips/locore.h> 52 53 #include <mips/cache.h> 54 55 #include <sgimips/dev/int2reg.h> 56 #include <sgimips/dev/int2var.h> 57 58 static bus_space_handle_t ioh; 59 static bus_space_tag_t iot; 60 61 struct int_softc { 62 struct device sc_dev; 63 }; 64 65 66 static int int_match(struct device *, struct cfdata *, void *); 67 static void int_attach(struct device *, struct device *, void *); 68 static void int_local0_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 69 static void int_local1_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 70 static int int_mappable_intr(void *); 71 static void *int_intr_establish(int, int, int (*)(void *), void *); 72 static void int_8254_cal(void); 73 static u_int int_8254_get_timecount(struct timecounter *); 74 static void int_8254_intr0(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 75 static void int_8254_intr1(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 76 77 #ifdef MIPS3 78 static u_long int_cal_timer(void); 79 #endif 80 81 static struct timecounter int_8254_timecounter = { 82 int_8254_get_timecount, /* get_timecount */ 83 0, /* no poll_pps */ 84 ~0u, /* counter_mask */ 85 500000, /* frequency */ 86 "int i8254", /* name */ 87 100, /* quality */ 88 NULL, /* prev */ 89 NULL, /* next */ 90 }; 91 92 static u_long int_8254_tc_count; 93 94 CFATTACH_DECL(int, sizeof(struct int_softc), 95 int_match, int_attach, NULL, NULL); 96 97 static int 98 int_match(struct device *parent, struct cfdata *match, void *aux) 99 { 100 101 if ((mach_type == MACH_SGI_IP12) || (mach_type == MACH_SGI_IP20) || 102 (mach_type == MACH_SGI_IP22) ) 103 return 1; 104 105 return 0; 106 } 107 108 static void 109 int_attach(struct device *parent, struct device *self, void *aux) 110 { 111 u_int32_t address; 112 113 if (mach_type == MACH_SGI_IP12) 114 address = INT_IP12; 115 else if (mach_type == MACH_SGI_IP20) 116 address = INT_IP20; 117 else if (mach_type == MACH_SGI_IP22) { 118 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) 119 address = INT_IP22; 120 else 121 address = INT_IP24; 122 } else 123 panic("\nint0: passed match, but failed attach?"); 124 125 printf(" addr 0x%x\n", address); 126 127 bus_space_map(iot, address, 0, 0, &ioh); 128 iot = SGIMIPS_BUS_SPACE_NORMAL; 129 130 /* Clean out interrupt masks */ 131 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, 0); 132 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, 0); 133 bus_space_write_4(iot, ioh, INT2_MAP_MASK0, 0); 134 bus_space_write_4(iot, ioh, INT2_MAP_MASK1, 0); 135 136 /* Reset timer interrupts */ 137 bus_space_write_4(iot, ioh, INT2_TIMER_CLEAR, 0x03); 138 139 switch (mach_type) { 140 case MACH_SGI_IP12: 141 platform.intr1 = int_local0_intr; 142 platform.intr2 = int_local1_intr; 143 platform.intr3 = int_8254_intr0; 144 platform.intr4 = int_8254_intr1; 145 int_8254_cal(); 146 tc_init(&int_8254_timecounter); 147 break; 148 #ifdef MIPS3 149 case MACH_SGI_IP20: 150 case MACH_SGI_IP22: 151 { 152 int i; 153 unsigned long cps; 154 unsigned long ctrdiff[3]; 155 156 platform.intr0 = int_local0_intr; 157 platform.intr1 = int_local1_intr; 158 159 /* calibrate timer */ 160 int_cal_timer(); 161 162 cps = 0; 163 for (i = 0; 164 i < sizeof(ctrdiff) / sizeof(ctrdiff[0]); i++) { 165 do { 166 ctrdiff[i] = int_cal_timer(); 167 } while (ctrdiff[i] == 0); 168 169 cps += ctrdiff[i]; 170 } 171 172 cps = cps / (sizeof(ctrdiff) / sizeof(ctrdiff[0])); 173 174 printf("%s: bus %luMHz, CPU %luMHz\n", 175 self->dv_xname, cps / 10000, cps / 5000); 176 177 /* R4k/R4400/R4600/R5k count at half CPU frequency */ 178 curcpu()->ci_cpu_freq = 2 * cps * hz; 179 } 180 #endif /* MIPS3 */ 181 182 break; 183 default: 184 panic("int0: unsupported machine type %i\n", mach_type); 185 break; 186 } 187 188 curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz); 189 curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000); 190 MIPS_SET_CI_RECIPROCAL(curcpu()); 191 192 if (mach_type == MACH_SGI_IP22) { 193 /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */ 194 intrtab[7].ih_fun = int_mappable_intr; 195 intrtab[7].ih_arg = (void*) 0; 196 197 intrtab[11].ih_fun = int_mappable_intr; 198 intrtab[11].ih_arg = (void*) 1; 199 } 200 201 platform.intr_establish = int_intr_establish; 202 } 203 204 int 205 int_mappable_intr(void *arg) 206 { 207 int i; 208 int ret; 209 int intnum; 210 u_int32_t mstat; 211 u_int32_t mmask; 212 int which = (int)arg; 213 struct sgimips_intrhand *ih; 214 215 ret = 0; 216 mstat = bus_space_read_4(iot, ioh, INT2_MAP_STATUS); 217 mmask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0 + (which << 2)); 218 219 mstat &= mmask; 220 221 for (i = 0; i < 8; i++) { 222 intnum = i + 16 + (which << 3); 223 if (mstat & (1 << i)) { 224 for (ih = &intrtab[intnum]; ih != NULL; 225 ih = ih->ih_next) { 226 if (ih->ih_fun != NULL) 227 ret |= (ih->ih_fun)(ih->ih_arg); 228 else 229 printf("int0: unexpected mapped " 230 "interrupt %d\n", intnum); 231 } 232 } 233 } 234 235 return ret; 236 } 237 238 void 239 int_local0_intr(u_int32_t status, u_int32_t cause, u_int32_t pc, 240 u_int32_t ipending) 241 { 242 int i; 243 u_int32_t l0stat; 244 u_int32_t l0mask; 245 struct sgimips_intrhand *ih; 246 247 l0stat = bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS); 248 l0mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 249 250 l0stat &= l0mask; 251 252 for (i = 0; i < 8; i++) { 253 if (l0stat & (1 << i)) { 254 for (ih = &intrtab[i]; ih != NULL; ih = ih->ih_next) { 255 if (ih->ih_fun != NULL) 256 (ih->ih_fun)(ih->ih_arg); 257 else 258 printf("int0: unexpected local0 " 259 "interrupt %d\n", i); 260 } 261 } 262 } 263 } 264 265 void 266 int_local1_intr(u_int32_t status, u_int32_t cause, u_int32_t pc, 267 u_int32_t ipending) 268 { 269 int i; 270 u_int32_t l1stat; 271 u_int32_t l1mask; 272 struct sgimips_intrhand *ih; 273 274 l1stat = bus_space_read_4(iot, ioh, INT2_LOCAL1_STATUS); 275 l1mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 276 277 l1stat &= l1mask; 278 279 for (i = 0; i < 8; i++) { 280 if (l1stat & (1 << i)) { 281 for (ih = &intrtab[8+i]; ih != NULL; ih = ih->ih_next) { 282 if (ih->ih_fun != NULL) 283 (ih->ih_fun)(ih->ih_arg); 284 else 285 printf("int0: unexpected local1 " 286 " interrupt %x\n", 8 + i); 287 } 288 } 289 } 290 } 291 292 void * 293 int_intr_establish(int level, int ipl, int (*handler) (void *), void *arg) 294 { 295 u_int32_t mask; 296 297 if (level < 0 || level >= NINTR) 298 panic("invalid interrupt level"); 299 300 if (intrtab[level].ih_fun == NULL) { 301 intrtab[level].ih_fun = handler; 302 intrtab[level].ih_arg = arg; 303 intrtab[level].ih_next = NULL; 304 } else { 305 struct sgimips_intrhand *n, *ih = malloc(sizeof *ih, 306 M_DEVBUF, M_NOWAIT); 307 308 if (ih == NULL) { 309 printf("int_intr_establish: can't allocate handler\n"); 310 return (void *)NULL; 311 } 312 313 ih->ih_fun = handler; 314 ih->ih_arg = arg; 315 ih->ih_next = NULL; 316 317 for (n = &intrtab[level]; n->ih_next != NULL; n = n->ih_next) 318 ; 319 320 n->ih_next = ih; 321 322 return (void *)NULL; /* vector already set */ 323 } 324 325 326 if (level < 8) { 327 mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 328 mask |= (1 << level); 329 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask); 330 } else if (level < 16) { 331 mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 332 mask |= (1 << (level - 8)); 333 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask); 334 } else if (level < 24) { 335 /* Map0 interrupt maps to l0 bit 7, so turn that on too */ 336 mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 337 mask |= (1 << 7); 338 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask); 339 340 mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0); 341 mask |= (1 << (level - 16)); 342 bus_space_write_4(iot, ioh, INT2_MAP_MASK0, mask); 343 } else { 344 /* Map1 interrupt maps to l1 bit 3, so turn that on too */ 345 mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 346 mask |= (1 << 3); 347 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask); 348 349 mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK1); 350 mask |= (1 << (level - 24)); 351 bus_space_write_4(iot, ioh, INT2_MAP_MASK1, mask); 352 } 353 354 return (void *)NULL; 355 } 356 357 #ifdef MIPS3 358 static u_long 359 int_cal_timer(void) 360 { 361 int s; 362 int roundtime; 363 int sampletime; 364 int startmsb, lsb, msb; 365 unsigned long startctr, endctr; 366 367 /* 368 * NOTE: HZ must be greater than 15 for this to work, as otherwise 369 * we'll overflow the counter. We round the answer to hearest 1 370 * MHz of the master (2x) clock. 371 */ 372 roundtime = (1000000 / hz) / 2; 373 sampletime = (1000000 / hz) + 0xff; 374 startmsb = (sampletime >> 8); 375 376 s = splhigh(); 377 378 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, 379 ( TIMER_SEL2 | TIMER_16BIT | TIMER_RATEGEN) ); 380 bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime & 0xff)); 381 bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime >> 8)); 382 383 startctr = mips3_cp0_count_read(); 384 385 /* Wait for the MSB to count down to zero */ 386 do { 387 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, TIMER_SEL2 ); 388 lsb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff; 389 msb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff; 390 391 endctr = mips3_cp0_count_read(); 392 } while (msb); 393 394 /* Turn off timer */ 395 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, 396 ( TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE) ); 397 398 splx(s); 399 400 return (endctr - startctr) / roundtime * roundtime; 401 } 402 #endif /* MIPS3 */ 403 404 /* 405 * A 1.000MHz master clock is wired to TIMER2, which in turn clocks the two 406 * other timers. On IP12 TIMER1 interrupts on MIPS interrupt 1 and TIMER2 407 * on MIPS interrupt 2. 408 * 409 * Apparently int2 doesn't like counting down from one, but two works, so 410 * we get a good 500000Hz. 411 */ 412 void 413 int_8254_cal(void) 414 { 415 int s; 416 417 s = splhigh(); 418 419 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 420 TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 421 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (500000 / hz) % 256); 422 wbflush(); 423 delay(4); 424 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (500000 / hz) / 256); 425 426 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 427 TIMER_SEL1|TIMER_RATEGEN|TIMER_16BIT); 428 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 7, 0xff); 429 wbflush(); 430 delay(4); 431 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 7, 0xff); 432 433 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 434 TIMER_SEL2|TIMER_RATEGEN|TIMER_16BIT); 435 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 2); 436 wbflush(); 437 delay(4); 438 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 0); 439 440 splx(s); 441 } 442 443 444 static u_int 445 int_8254_get_timecount(struct timecounter *tc) 446 { 447 int s; 448 u_int count; 449 u_char lo, hi; 450 451 s = splhigh(); 452 453 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 454 TIMER_SEL1 | TIMER_LATCH); 455 lo = bus_space_read_1(iot, ioh, INT2_TIMER_0 + 7); 456 hi = bus_space_read_1(iot, ioh, INT2_TIMER_0 + 7); 457 count = 0xffff - ((hi << 8) | lo); 458 459 splx(s); 460 461 return (int_8254_tc_count + count); 462 } 463 464 static void 465 int_8254_intr0(u_int32_t status, u_int32_t cause, u_int32_t pc, 466 u_int32_t ipending) 467 { 468 struct clockframe cf; 469 470 cf.pc = pc; 471 cf.sr = status; 472 473 hardclock(&cf); 474 475 bus_space_write_4(iot, ioh, INT2_TIMER_CLEAR, 1); 476 } 477 478 479 static void 480 int_8254_intr1(u_int32_t status, u_int32_t cause, u_int32_t pc, 481 u_int32_t ipending) 482 { 483 int s; 484 485 s = splhigh(); 486 487 int_8254_tc_count += 0xffff; 488 bus_space_write_4(iot, ioh, INT2_TIMER_CLEAR, 2); 489 490 splx(s); 491 } 492 493 void 494 int2_wait_fifo(u_int32_t flag) 495 { 496 if (ioh == 0) 497 delay(5000); 498 else 499 while (bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS) & flag) 500 ; 501 } 502