1 /* $NetBSD: int.c,v 1.12 2006/09/01 03:33:41 rumble 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.12 2006/09/01 03:33:41 rumble 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 l0stat &= l0mask; 230 231 for (i = 0; i < 8; i++) { 232 if (l0stat & (1 << i)) { 233 for (ih = &intrtab[i]; ih != NULL; ih = ih->ih_next) { 234 if (ih->ih_fun != NULL) 235 (ih->ih_fun)(ih->ih_arg); 236 else 237 printf("int0: unexpected local0 " 238 "interrupt %d\n", i); 239 } 240 } 241 } 242 } 243 244 void 245 int_local1_intr(u_int32_t status, u_int32_t cause, u_int32_t pc, 246 u_int32_t ipending) 247 { 248 int i; 249 u_int32_t l1stat; 250 u_int32_t l1mask; 251 struct sgimips_intrhand *ih; 252 253 l1stat = bus_space_read_4(iot, ioh, INT2_LOCAL1_STATUS); 254 l1mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 255 256 l1stat &= l1mask; 257 258 for (i = 0; i < 8; i++) { 259 if (l1stat & (1 << i)) { 260 for (ih = &intrtab[8+i]; ih != NULL; ih = ih->ih_next) { 261 if (ih->ih_fun != NULL) 262 (ih->ih_fun)(ih->ih_arg); 263 else 264 printf("int0: unexpected local1 " 265 " interrupt %x\n", 8 + i); 266 } 267 } 268 } 269 } 270 271 void * 272 int_intr_establish(int level, int ipl, int (*handler) (void *), void *arg) 273 { 274 u_int32_t mask; 275 276 if (level < 0 || level >= NINTR) 277 panic("invalid interrupt level"); 278 279 if (intrtab[level].ih_fun == NULL) { 280 intrtab[level].ih_fun = handler; 281 intrtab[level].ih_arg = arg; 282 intrtab[level].ih_next = NULL; 283 } else { 284 struct sgimips_intrhand *n, *ih = malloc(sizeof *ih, 285 M_DEVBUF, M_NOWAIT); 286 287 if (ih == NULL) { 288 printf("int_intr_establish: can't allocate handler\n"); 289 return (void *)NULL; 290 } 291 292 ih->ih_fun = handler; 293 ih->ih_arg = arg; 294 ih->ih_next = NULL; 295 296 for (n = &intrtab[level]; n->ih_next != NULL; n = n->ih_next) 297 ; 298 299 n->ih_next = ih; 300 301 return (void *)NULL; /* vector already set */ 302 } 303 304 305 if (level < 8) { 306 mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 307 mask |= (1 << level); 308 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask); 309 } else if (level < 16) { 310 mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 311 mask |= (1 << (level - 8)); 312 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask); 313 } else if (level < 24) { 314 /* Map0 interrupt maps to l0 bit 7, so turn that on too */ 315 mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 316 mask |= (1 << 7); 317 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask); 318 319 mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0); 320 mask |= (1 << (level - 16)); 321 bus_space_write_4(iot, ioh, INT2_MAP_MASK0, mask); 322 } else { 323 /* Map1 interrupt maps to l1 bit 3, so turn that on too */ 324 mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 325 mask |= (1 << 3); 326 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask); 327 328 mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK1); 329 mask |= (1 << (level - 24)); 330 bus_space_write_4(iot, ioh, INT2_MAP_MASK1, mask); 331 } 332 333 return (void *)NULL; 334 } 335 336 #ifdef MIPS3 337 unsigned long 338 int_cal_timer(void) 339 { 340 int s; 341 int roundtime; 342 int sampletime; 343 int startmsb, lsb, msb; 344 unsigned long startctr, endctr; 345 346 /* 347 * NOTE: HZ must be greater than 15 for this to work, as otherwise 348 * we'll overflow the counter. We round the answer to hearest 1 349 * MHz of the master (2x) clock. 350 */ 351 roundtime = (1000000 / hz) / 2; 352 sampletime = (1000000 / hz) + 0xff; 353 startmsb = (sampletime >> 8); 354 355 s = splhigh(); 356 357 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, 358 ( TIMER_SEL2 | TIMER_16BIT | TIMER_RATEGEN) ); 359 bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime & 0xff)); 360 bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime >> 8)); 361 362 startctr = mips3_cp0_count_read(); 363 364 /* Wait for the MSB to count down to zero */ 365 do { 366 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, TIMER_SEL2 ); 367 lsb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff; 368 msb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff; 369 370 endctr = mips3_cp0_count_read(); 371 } while (msb); 372 373 /* Turn off timer */ 374 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, 375 ( TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE) ); 376 377 splx(s); 378 379 return (endctr - startctr) / roundtime * roundtime; 380 } 381 #endif /* MIPS3 */ 382 383 void 384 int_8254_cal(void) 385 { 386 int s; 387 388 s = splhigh(); 389 390 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 391 TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 392 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) % 256); 393 wbflush(); 394 delay(4); 395 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) / 256); 396 397 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 398 TIMER_SEL2|TIMER_RATEGEN|TIMER_16BIT); 399 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 50); 400 wbflush(); 401 delay(4); 402 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 0); 403 splx(s); 404 } 405 406 void 407 int2_wait_fifo(u_int32_t flag) 408 { 409 if (ioh == 0) 410 delay(5000); 411 else 412 while (bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS) & flag) 413 ; 414 } 415