1 /* $NetBSD: int.c,v 1.9 2004/07/08 10:10:49 sekiya 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.9 2004/07/08 10:10:49 sekiya 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