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