1 /* $NetBSD: algor_p6032_intr.c,v 1.16 2008/05/26 15:59:29 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Platform-specific interrupt support for the Algorithmics P-6032. 34 * 35 * The Algorithmics P-6032's interrupts are wired to GPIO pins 36 * on the BONITO system controller. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: algor_p6032_intr.c,v 1.16 2008/05/26 15:59:29 tsutsui Exp $"); 41 42 #include "opt_ddb.h" 43 44 #include <sys/param.h> 45 #include <sys/queue.h> 46 #include <sys/malloc.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 #include <sys/kernel.h> 50 #include <sys/cpu.h> 51 52 #include <machine/bus.h> 53 #include <machine/autoconf.h> 54 #include <machine/intr.h> 55 56 #include <mips/locore.h> 57 58 #include <dev/ic/mc146818reg.h> 59 60 #include <algor/algor/algor_p6032reg.h> 61 #include <algor/algor/algor_p6032var.h> 62 63 #include <dev/pci/pcireg.h> 64 #include <dev/pci/pcivar.h> 65 66 #include <dev/isa/isavar.h> 67 68 /* 69 * The P-6032 interrupts are wired up in the following way: 70 * 71 * GPIN0 ISA_NMI (in) 72 * GPIN1 ISA_INTR (in) 73 * GPIN2 ETH_INT~ (in) 74 * GPIN3 BONIDE_INT (in) 75 * 76 * GPIN4 ISA IRQ3 (in, also on piix4) 77 * GPIN5 ISA IRQ4 (in, also on piix4) 78 * 79 * GPIO0 PIRQ A~ (in) 80 * GPIO1 PIRQ B~ (in) 81 * GPIO2 PIRQ C~ (in) 82 * GPIO3 PIRQ D~ (in) 83 */ 84 85 #define NIRQMAPS 10 86 87 const char *p6032_intrnames[NIRQMAPS] = { 88 "gpin 0", 89 "gpin 1", 90 "gpin 2", 91 "gpin 3", 92 93 "gpin 4", 94 "gpin 5", 95 96 "gpio 0", 97 "gpio 1", 98 "gpio 2", 99 "gpio 3", 100 }; 101 102 struct p6032_irqmap { 103 int irqidx; 104 uint32_t intbit; 105 uint32_t gpioiebit; 106 int flags; 107 }; 108 109 #define IRQ_F_INVERT 0x01 /* invert polarity */ 110 #define IRQ_F_EDGE 0x02 /* edge trigger */ 111 #define IRQ_F_INT1 0x04 /* INT1, else INT0 */ 112 113 const struct p6032_irqmap p6032_irqmap[NIRQMAPS] = { 114 /* ISA NMI */ 115 { P6032_IRQ_GPIN0, BONITO_ICU_GPIN(0), 116 BONITO_GPIO_INR(0), IRQ_F_INT1 }, 117 118 /* ISA bridge */ 119 { P6032_IRQ_GPIN1, BONITO_ICU_GPIN(1), 120 BONITO_GPIO_INR(1), IRQ_F_INT1 }, 121 122 /* Ethernet */ 123 { P6032_IRQ_GPIN2, BONITO_ICU_GPIN(2), 124 BONITO_GPIO_INR(2), IRQ_F_INVERT }, 125 126 /* BONITO IDE */ 127 { P6032_IRQ_GPIN3, BONITO_ICU_GPIN(3), 128 BONITO_GPIO_INR(3), 0 }, 129 130 /* ISA IRQ3 */ 131 { P6032_IRQ_GPIN4, BONITO_ICU_GPIN(4), 132 BONITO_GPIO_INR(4), IRQ_F_INT1 }, 133 134 /* ISA IRQ4 */ 135 { P6032_IRQ_GPIN5, BONITO_ICU_GPIN(5), 136 BONITO_GPIO_INR(5), IRQ_F_INT1 }, 137 138 /* PIRQ A */ 139 { P6032_IRQ_GPIO0, BONITO_ICU_GPIO(0), 140 BONITO_GPIO_IOW(0), IRQ_F_INVERT }, 141 142 /* PIRQ B */ 143 { P6032_IRQ_GPIO1, BONITO_ICU_GPIO(1), 144 BONITO_GPIO_IOW(1), IRQ_F_INVERT }, 145 146 /* PIRQ C */ 147 { P6032_IRQ_GPIO2, BONITO_ICU_GPIO(2), 148 BONITO_GPIO_IOW(2), IRQ_F_INVERT }, 149 150 /* PIRQ D */ 151 { P6032_IRQ_GPIO3, BONITO_ICU_GPIO(3), 152 BONITO_GPIO_IOW(3), IRQ_F_INVERT }, 153 }; 154 155 struct p6032_intrhead { 156 struct evcnt intr_count; 157 int intr_refcnt; 158 }; 159 struct p6032_intrhead p6032_intrtab[NIRQMAPS]; 160 161 #define NINTRS 2 /* MIPS INT0 - INT1 */ 162 163 struct p6032_cpuintr { 164 LIST_HEAD(, algor_intrhand) cintr_list; 165 struct evcnt cintr_count; 166 }; 167 168 struct p6032_cpuintr p6032_cpuintrs[NINTRS]; 169 const char *p6032_cpuintrnames[NINTRS] = { 170 "int 0 (pci)", 171 "int 1 (isa)", 172 }; 173 174 void *algor_p6032_intr_establish(int, int (*)(void *), void *); 175 void algor_p6032_intr_disestablish(void *); 176 177 int algor_p6032_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 178 const char *algor_p6032_pci_intr_string(void *, pci_intr_handle_t); 179 const struct evcnt *algor_p6032_pci_intr_evcnt(void *, pci_intr_handle_t); 180 void *algor_p6032_pci_intr_establish(void *, pci_intr_handle_t, int, 181 int (*)(void *), void *); 182 void algor_p6032_pci_intr_disestablish(void *, void *); 183 void algor_p6032_pci_conf_interrupt(void *, int, int, int, int, int *); 184 185 void algor_p6032_iointr(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 186 187 void 188 algor_p6032_intr_init(struct p6032_config *acp) 189 { 190 struct bonito_config *bc = &acp->ac_bonito; 191 const struct p6032_irqmap *irqmap; 192 int i; 193 194 for (i = 0; i < NINTRS; i++) { 195 LIST_INIT(&p6032_cpuintrs[i].cintr_list); 196 evcnt_attach_dynamic(&p6032_cpuintrs[i].cintr_count, 197 EVCNT_TYPE_INTR, NULL, "mips", p6032_cpuintrnames[i]); 198 } 199 evcnt_attach_static(&mips_int5_evcnt); 200 201 for (i = 0; i <= NIRQMAPS; i++) { 202 irqmap = &p6032_irqmap[i]; 203 204 evcnt_attach_dynamic(&p6032_intrtab[i].intr_count, 205 EVCNT_TYPE_INTR, NULL, "bonito", p6032_intrnames[i]); 206 207 bc->bc_gpioIE |= irqmap->gpioiebit; 208 if (irqmap->flags & IRQ_F_INVERT) 209 bc->bc_intPol |= irqmap->intbit; 210 if (irqmap->flags & IRQ_F_EDGE) 211 bc->bc_intEdge |= irqmap->intbit; 212 if (irqmap->flags & IRQ_F_INT1) 213 bc->bc_intSteer |= irqmap->intbit; 214 215 REGVAL(BONITO_INTENCLR) = irqmap->intbit; 216 } 217 218 REGVAL(BONITO_GPIOIE) = bc->bc_gpioIE; 219 REGVAL(BONITO_INTEDGE) = bc->bc_intEdge; 220 REGVAL(BONITO_INTSTEER) = bc->bc_intSteer; 221 REGVAL(BONITO_INTPOL) = bc->bc_intPol; 222 223 acp->ac_pc.pc_intr_v = NULL; 224 acp->ac_pc.pc_intr_map = algor_p6032_pci_intr_map; 225 acp->ac_pc.pc_intr_string = algor_p6032_pci_intr_string; 226 acp->ac_pc.pc_intr_evcnt = algor_p6032_pci_intr_evcnt; 227 acp->ac_pc.pc_intr_establish = algor_p6032_pci_intr_establish; 228 acp->ac_pc.pc_intr_disestablish = algor_p6032_pci_intr_disestablish; 229 acp->ac_pc.pc_conf_interrupt = algor_p6032_pci_conf_interrupt; 230 231 /* We let the PCI-ISA bridge code handle this. */ 232 acp->ac_pc.pc_pciide_compat_intr_establish = NULL; 233 234 algor_intr_establish = algor_p6032_intr_establish; 235 algor_intr_disestablish = algor_p6032_intr_disestablish; 236 algor_iointr = algor_p6032_iointr; 237 } 238 239 void 240 algor_p6032_cal_timer(bus_space_tag_t st, bus_space_handle_t sh) 241 { 242 u_long ctrdiff[4], startctr, endctr, cps; 243 u_int8_t regc; 244 int i; 245 246 /* Disable interrupts first. */ 247 bus_space_write_1(st, sh, 0, MC_REGB); 248 bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY | 249 MC_REGB_24HR); 250 251 /* Initialize for 16Hz. */ 252 bus_space_write_1(st, sh, 0, MC_REGA); 253 bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz); 254 255 /* Run the loop an extra time to prime the cache. */ 256 for (i = 0; i < 4; i++) { 257 led_display('h', 'z', '0' + i, ' '); 258 259 /* Enable the interrupt. */ 260 bus_space_write_1(st, sh, 0, MC_REGB); 261 bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE | 262 MC_REGB_BINARY | MC_REGB_24HR); 263 264 /* Go to REGC. */ 265 bus_space_write_1(st, sh, 0, MC_REGC); 266 267 /* Wait for it to happen. */ 268 startctr = mips3_cp0_count_read(); 269 do { 270 regc = bus_space_read_1(st, sh, 1); 271 endctr = mips3_cp0_count_read(); 272 } while ((regc & MC_REGC_IRQF) == 0); 273 274 /* Already ACK'd. */ 275 276 /* Disable. */ 277 bus_space_write_1(st, sh, 0, MC_REGB); 278 bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY | 279 MC_REGB_24HR); 280 281 ctrdiff[i] = endctr - startctr; 282 } 283 284 /* Update CPU frequency values */ 285 cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16; 286 /* XXX mips_cpu_flags isn't set here; assume CPU_MIPS_DOUBLE_COUNT */ 287 curcpu()->ci_cpu_freq = cps * 2; 288 curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz; 289 curcpu()->ci_divisor_delay = 290 ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000); 291 /* XXX assume CPU_MIPS_DOUBLE_COUNT */ 292 curcpu()->ci_cycles_per_hz /= 2; 293 curcpu()->ci_divisor_delay /= 2; 294 295 printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n", 296 cps, ctrdiff[2], ctrdiff[3]); 297 printf("CPU clock speed = %lu.%02luMHz " 298 "(hz cycles = %lu, delay divisor = %lu)\n", 299 curcpu()->ci_cpu_freq / 1000000, 300 (curcpu()->ci_cpu_freq % 1000000) / 10000, 301 curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay); 302 } 303 304 void * 305 algor_p6032_intr_establish(int irq, int (*func)(void *), void *arg) 306 { 307 const struct p6032_irqmap *irqmap; 308 struct algor_intrhand *ih; 309 int s; 310 311 irqmap = &p6032_irqmap[irq]; 312 313 KASSERT(irq == irqmap->irqidx); 314 315 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 316 if (ih == NULL) 317 return (NULL); 318 319 ih->ih_func = func; 320 ih->ih_arg = arg; 321 ih->ih_irq = 0; 322 ih->ih_irqmap = irqmap; 323 324 s = splhigh(); 325 326 /* 327 * First, link it into the tables. 328 */ 329 if (irqmap->flags & IRQ_F_INT1) 330 LIST_INSERT_HEAD(&p6032_cpuintrs[1].cintr_list, ih, ih_q); 331 else 332 LIST_INSERT_HEAD(&p6032_cpuintrs[0].cintr_list, ih, ih_q); 333 334 /* 335 * Now enable it. 336 */ 337 if (p6032_intrtab[irqmap->irqidx].intr_refcnt++ == 0) 338 REGVAL(BONITO_INTENSET) = irqmap->intbit; 339 340 splx(s); 341 342 return (ih); 343 } 344 345 void 346 algor_p6032_intr_disestablish(void *cookie) 347 { 348 const struct p6032_irqmap *irqmap; 349 struct algor_intrhand *ih = cookie; 350 int s; 351 352 irqmap = ih->ih_irqmap; 353 354 s = splhigh(); 355 356 /* 357 * First, remove it from the table. 358 */ 359 LIST_REMOVE(ih, ih_q); 360 361 /* 362 * Now, disable it, if there is nothing remaining on the 363 * list. 364 */ 365 if (p6032_intrtab[irqmap->irqidx].intr_refcnt-- == 1) 366 REGVAL(BONITO_INTENCLR) = irqmap->intbit; 367 368 splx(s); 369 370 free(ih, M_DEVBUF); 371 } 372 373 void 374 algor_p6032_iointr(u_int32_t status, u_int32_t cause, u_int32_t pc, 375 u_int32_t ipending) 376 { 377 const struct p6032_irqmap *irqmap; 378 struct algor_intrhand *ih; 379 int level; 380 u_int32_t isr; 381 382 /* Check for DEBUG interrupts. */ 383 if (ipending & MIPS_INT_MASK_3) { 384 #ifdef DDB 385 printf("Debug switch -- entering debugger\n"); 386 led_display('D','D','B',' '); 387 Debugger(); 388 led_display('N','B','S','D'); 389 #else 390 printf("Debug switch ignored -- " 391 "no debugger configured\n"); 392 #endif 393 394 cause &= ~MIPS_INT_MASK_3; 395 } 396 397 /* 398 * Read the interrupt pending registers, mask them with the 399 * ones we have enabled, and service them in order of decreasing 400 * priority. 401 */ 402 isr = REGVAL(BONITO_INTISR) & REGVAL(BONITO_INTEN); 403 404 for (level = 1; level >= 0; level--) { 405 if ((ipending & (MIPS_INT_MASK_0 << level)) == 0) 406 continue; 407 p6032_cpuintrs[level].cintr_count.ev_count++; 408 for (ih = LIST_FIRST(&p6032_cpuintrs[level].cintr_list); 409 ih != NULL; ih = LIST_NEXT(ih, ih_q)) { 410 irqmap = ih->ih_irqmap; 411 if (isr & irqmap->intbit) { 412 p6032_intrtab[ 413 irqmap->irqidx].intr_count.ev_count++; 414 (*ih->ih_func)(ih->ih_arg); 415 } 416 } 417 cause &= ~(MIPS_INT_MASK_0 << level); 418 } 419 420 /* Re-enable anything that we have processed. */ 421 _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK)); 422 } 423 424 /***************************************************************************** 425 * PCI interrupt support 426 *****************************************************************************/ 427 428 int 429 algor_p6032_pci_intr_map(struct pci_attach_args *pa, 430 pci_intr_handle_t *ihp) 431 { 432 static const int pciirqmap[6/*device*/][4/*pin*/] = { 433 { P6032_IRQ_GPIO0, P6032_IRQ_GPIO1, 434 P6032_IRQ_GPIO2, P6032_IRQ_GPIO3 }, /* 13: slot 2 (p9) */ 435 436 { P6032_IRQ_GPIO1, P6032_IRQ_GPIO2, 437 P6032_IRQ_GPIO3, P6032_IRQ_GPIO0 }, /* 14: slot 3 (p10) */ 438 439 { P6032_IRQ_GPIO2, P6032_IRQ_GPIO3, 440 P6032_IRQ_GPIO0, P6032_IRQ_GPIO1 }, /* 15: slot 4 (p11) */ 441 442 { P6032_IRQ_GPIN2, -1, 443 -1, -1 }, /* 16: Ethernet */ 444 445 { P6032_IRQ_GPIO0, P6032_IRQ_GPIO1, 446 P6032_IRQ_GPIO2, P6032_IRQ_GPIO3 }, /* 17: southbridge */ 447 448 { P6032_IRQ_GPIO3, P6032_IRQ_GPIO0, 449 P6032_IRQ_GPIO1, P6032_IRQ_GPIO2 }, /* 18: slot 1 (p8) */ 450 }; 451 pcitag_t bustag = pa->pa_intrtag; 452 int buspin = pa->pa_intrpin; 453 pci_chipset_tag_t pc = pa->pa_pc; 454 int device, irq; 455 456 if (buspin == 0) { 457 /* No IRQ used. */ 458 return (1); 459 } 460 461 if (buspin > 4) { 462 printf("algor_p6032_pci_intr_map: bad interrupt pin %d\n", 463 buspin); 464 return (1); 465 } 466 467 pci_decompose_tag(pc, bustag, NULL, &device, NULL); 468 if (device < 13 || device > 18) { 469 printf("algor_p6032_pci_intr_map: bad device %d\n", 470 device); 471 return (1); 472 } 473 474 irq = pciirqmap[device - 13][buspin - 1]; 475 if (irq == -1) { 476 printf("algor_p6032_pci_intr_map: no mapping for " 477 "device %d pin %d\n", device, buspin); 478 return (1); 479 } 480 481 *ihp = irq; 482 return (0); 483 } 484 485 const char * 486 algor_p6032_pci_intr_string(void *v, pci_intr_handle_t ih) 487 { 488 489 if (ih >= NIRQMAPS) 490 panic("algor_p6032_intr_string: bogus IRQ %ld", ih); 491 492 return (p6032_intrnames[ih]); 493 } 494 495 const struct evcnt * 496 algor_p6032_pci_intr_evcnt(void *v, pci_intr_handle_t ih) 497 { 498 499 return (&p6032_intrtab[ih].intr_count); 500 } 501 502 void * 503 algor_p6032_pci_intr_establish(void *v, pci_intr_handle_t ih, int level, 504 int (*func)(void *), void *arg) 505 { 506 507 if (ih >= NIRQMAPS) 508 panic("algor_p6032_intr_establish: bogus IRQ %ld", ih); 509 510 return (algor_p6032_intr_establish(ih, func, arg)); 511 } 512 513 void 514 algor_p6032_pci_intr_disestablish(void *v, void *cookie) 515 { 516 517 return (algor_p6032_intr_disestablish(cookie)); 518 } 519 520 void 521 algor_p6032_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz, 522 int *iline) 523 { 524 525 /* 526 * We actually don't need to do anything; everything is handled 527 * in pci_intr_map(). 528 */ 529 *iline = 0; 530 } 531