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