1 /* $NetBSD: int.c,v 1.7 2004/04/11 12:05:37 pooka 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.7 2004/04/11 12:05:37 pooka 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 45 #include <dev/ic/i8253reg.h> 46 #include <machine/sysconf.h> 47 #include <machine/machtype.h> 48 #include <machine/bus.h> 49 #include <mips/locore.h> 50 51 #include <mips/cache.h> 52 53 #include <sgimips/dev/int2reg.h> 54 #include <sgimips/dev/int2var.h> 55 56 static bus_space_handle_t ioh; 57 static bus_space_tag_t iot; 58 59 struct int_softc { 60 struct device sc_dev; 61 }; 62 63 64 static int int_match(struct device *, struct cfdata *, void *); 65 static void int_attach(struct device *, struct device *, void *); 66 void int_local0_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 67 void int_local1_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 68 int int_mappable_intr(void *); 69 void *int_intr_establish(int, int, int (*)(void *), void *); 70 unsigned long int_cal_timer(void); 71 void int_8254_cal(void); 72 73 CFATTACH_DECL(int, sizeof(struct int_softc), 74 int_match, int_attach, NULL, NULL); 75 76 static int 77 int_match(struct device *parent, struct cfdata *match, void *aux) 78 { 79 80 if ((mach_type == MACH_SGI_IP12) || (mach_type == MACH_SGI_IP20) || 81 (mach_type == MACH_SGI_IP22) ) 82 return 1; 83 84 return 0; 85 } 86 87 static void 88 int_attach(struct device *parent, struct device *self, void *aux) 89 { 90 u_int32_t address; 91 92 if (mach_type == MACH_SGI_IP12) 93 address = INT_IP12; 94 else if (mach_type == MACH_SGI_IP20) 95 address = INT_IP20; 96 else if (mach_type == MACH_SGI_IP22) { 97 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) 98 address = INT_IP22; 99 else 100 address = INT_IP24; 101 } else 102 panic("\nint0: passed match, but failed attach?"); 103 104 printf(" addr 0x%x", address); 105 106 bus_space_map(iot, address, 0, 0, &ioh); 107 iot = SGIMIPS_BUS_SPACE_NORMAL; 108 109 /* Clean out interrupt masks */ 110 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, 0); 111 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, 0); 112 bus_space_write_4(iot, ioh, INT2_MAP_MASK0, 0); 113 bus_space_write_4(iot, ioh, INT2_MAP_MASK1, 0); 114 115 /* Reset timer interrupts */ 116 bus_space_write_4(iot, ioh, INT2_TIMER_CLEAR, 0x03); 117 118 switch (mach_type) { 119 case MACH_SGI_IP12: 120 platform.intr1 = int_local0_intr; 121 platform.intr2 = int_local1_intr; 122 int_8254_cal(); 123 break; 124 #ifdef MIPS3 125 case MACH_SGI_IP20: 126 case MACH_SGI_IP22: 127 { 128 int i; 129 unsigned long cps; 130 unsigned long ctrdiff[3]; 131 132 platform.intr0 = int_local0_intr; 133 platform.intr1 = int_local1_intr; 134 135 /* calibrate timer */ 136 int_cal_timer(); 137 138 cps = 0; 139 for (i = 0; 140 i < sizeof(ctrdiff) / sizeof(ctrdiff[0]); i++) { 141 do { 142 ctrdiff[i] = int_cal_timer(); 143 } while (ctrdiff[i] == 0); 144 145 cps += ctrdiff[i]; 146 } 147 148 cps = cps / (sizeof(ctrdiff) / sizeof(ctrdiff[0])); 149 150 printf(": bus %luMHz, CPU %luMHz", 151 cps / 10000, cps / 5000); 152 153 /* R4k/R4400/R4600/R5k count at half CPU frequency */ 154 curcpu()->ci_cpu_freq = 2 * cps * hz; 155 } 156 #endif /* MIPS3 */ 157 158 break; 159 default: 160 panic("int0: unsupported machine type %i\n", mach_type); 161 break; 162 } 163 164 printf("\n"); 165 166 curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz); 167 curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000); 168 MIPS_SET_CI_RECIPRICAL(curcpu()); 169 170 if (mach_type == MACH_SGI_IP22) { 171 /* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */ 172 intrtab[7].ih_fun = int_mappable_intr; 173 intrtab[7].ih_arg = (void*) 0; 174 175 intrtab[11].ih_fun = int_mappable_intr; 176 intrtab[11].ih_arg = (void*) 1; 177 } 178 179 platform.intr_establish = int_intr_establish; 180 } 181 182 int 183 int_mappable_intr(void *arg) 184 { 185 int i; 186 int ret; 187 int intnum; 188 u_int32_t mstat; 189 u_int32_t mmask; 190 int which = (int)arg; 191 192 ret = 0; 193 mstat = bus_space_read_4(iot, ioh, INT2_MAP_STATUS); 194 mmask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0 + (which << 2)); 195 196 mstat &= mmask; 197 198 for (i = 0; i < 8; i++) { 199 intnum = i + 16 + (which << 3); 200 if (mstat & (1 << i)) { 201 if (intrtab[intnum].ih_fun != NULL) 202 ret |= (intrtab[intnum].ih_fun) 203 (intrtab[intnum].ih_arg); 204 else 205 printf("int0: unexpected mapped interrupt %d\n", 206 intnum); 207 } 208 } 209 210 return ret; 211 } 212 213 void 214 int_local0_intr(u_int32_t status, u_int32_t cause, u_int32_t pc, 215 u_int32_t ipending) 216 { 217 int i; 218 int ret; 219 u_int32_t l0stat; 220 u_int32_t l0mask; 221 222 ret = 0; 223 l0stat = bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS); 224 l0mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 225 226 l0stat &= l0mask; 227 228 for (i = 0; i < 8; i++) { 229 if (l0stat & (1 << i)) { 230 if (intrtab[i].ih_fun != NULL) 231 ret |= (intrtab[i].ih_fun)(intrtab[i].ih_arg); 232 else 233 printf("int0: unexpected local0 interrupt %d\n", 234 i); 235 } 236 } 237 } 238 239 void 240 int_local1_intr(u_int32_t status, u_int32_t cause, u_int32_t pc, 241 u_int32_t ipending) 242 { 243 int i; 244 int ret; 245 u_int32_t l1stat; 246 u_int32_t l1mask; 247 248 l1stat = bus_space_read_4(iot, ioh, INT2_LOCAL1_STATUS); 249 l1mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 250 251 l1stat &= l1mask; 252 253 ret = 0; 254 for (i = 0; i < 8; i++) { 255 if (l1stat & (1 << i)) { 256 if (intrtab[8 + i].ih_fun != NULL) 257 ret |= (intrtab[8 + i].ih_fun) 258 (intrtab[8 + i].ih_arg); 259 else 260 printf("int0: unexpected local1 interrupt %x\n", 261 8 + i); 262 } 263 } 264 } 265 266 void * 267 int_intr_establish(int level, int ipl, int (*handler) (void *), void *arg) 268 { 269 u_int32_t mask; 270 271 if (level < 0 || level >= NINTR) 272 panic("invalid interrupt level"); 273 274 if (intrtab[level].ih_fun != NULL) 275 { 276 printf("int0: cannot share interrupts yet.\n"); 277 return (void *)NULL; 278 } 279 280 intrtab[level].ih_fun = handler; 281 intrtab[level].ih_arg = arg; 282 283 if (level < 8) { 284 mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 285 mask |= (1 << level); 286 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask); 287 } else if (level < 16) { 288 mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 289 mask |= (1 << (level - 8)); 290 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask); 291 } else if (level < 24) { 292 /* Map0 interrupt maps to l0 bit 7, so turn that on too */ 293 mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK); 294 mask |= (1 << 7); 295 bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask); 296 297 mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0); 298 mask |= (1 << (level - 16)); 299 bus_space_write_4(iot, ioh, INT2_MAP_MASK0, mask); 300 } else { 301 /* Map1 interrupt maps to l1 bit 3, so turn that on too */ 302 mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK); 303 mask |= (1 << 3); 304 bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask); 305 306 mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK1); 307 mask |= (1 << (level - 24)); 308 bus_space_write_4(iot, ioh, INT2_MAP_MASK1, mask); 309 } 310 311 return (void *)NULL; 312 } 313 314 #ifdef MIPS3 315 unsigned long 316 int_cal_timer(void) 317 { 318 int s; 319 int roundtime; 320 int sampletime; 321 int startmsb, lsb, msb; 322 unsigned long startctr, endctr; 323 324 /* 325 * NOTE: HZ must be greater than 15 for this to work, as otherwise 326 * we'll overflow the counter. We round the answer to hearest 1 327 * MHz of the master (2x) clock. 328 */ 329 roundtime = (1000000 / hz) / 2; 330 sampletime = (1000000 / hz) + 0xff; 331 startmsb = (sampletime >> 8); 332 333 s = splhigh(); 334 335 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, 336 ( TIMER_SEL2 | TIMER_16BIT | TIMER_RATEGEN) ); 337 bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime & 0xff)); 338 bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime >> 8)); 339 340 startctr = mips3_cp0_count_read(); 341 342 /* Wait for the MSB to count down to zero */ 343 do { 344 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, TIMER_SEL2 ); 345 lsb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff; 346 msb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff; 347 348 endctr = mips3_cp0_count_read(); 349 } while (msb); 350 351 /* Turn off timer */ 352 bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, 353 ( TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE) ); 354 355 splx(s); 356 357 return (endctr - startctr) / roundtime * roundtime; 358 } 359 #endif /* MIPS3 */ 360 361 void 362 int_8254_cal(void) 363 { 364 int s; 365 366 s = splhigh(); 367 368 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 369 TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 370 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) % 256); 371 wbflush(); 372 delay(4); 373 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) / 256); 374 375 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15, 376 TIMER_SEL2|TIMER_RATEGEN|TIMER_16BIT); 377 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 50); 378 wbflush(); 379 delay(4); 380 bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 0); 381 splx(s); 382 } 383 384 void 385 int2_wait_fifo(u_int32_t flag) 386 { 387 while (bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS) & flag) 388 ; 389 } 390