1 /* $OpenBSD: sio_pic.c,v 1.29 2008/08/09 16:41:21 miod Exp $ */ 2 /* $NetBSD: sio_pic.c,v 1.28 2000/06/06 03:10:13 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 * NASA Ames Research Center. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 36 * All rights reserved. 37 * 38 * Author: Chris G. Demetriou 39 * 40 * Permission to use, copy, modify and distribute this software and 41 * its documentation is hereby granted, provided that both the copyright 42 * notice and this permission notice appear in all copies of the 43 * software, derivative works or modified versions, and any portions 44 * thereof, and that both notices appear in supporting documentation. 45 * 46 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 47 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 48 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 49 * 50 * Carnegie Mellon requests users of this software to return to 51 * 52 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 53 * School of Computer Science 54 * Carnegie Mellon University 55 * Pittsburgh PA 15213-3890 56 * 57 * any improvements or extensions that they make and grant Carnegie the 58 * rights to redistribute these changes. 59 */ 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 64 #include <sys/device.h> 65 #include <sys/malloc.h> 66 #include <sys/syslog.h> 67 68 #include <machine/intr.h> 69 #include <machine/bus.h> 70 71 #include <dev/pci/pcireg.h> 72 #include <dev/pci/pcivar.h> 73 #include <dev/pci/pcidevs.h> 74 75 #include <dev/pci/cy82c693reg.h> 76 #include <dev/pci/cy82c693var.h> 77 78 #include <dev/isa/isareg.h> 79 #include <dev/isa/isavar.h> 80 #include <alpha/pci/siovar.h> 81 82 #include "sio.h" 83 84 /* 85 * To add to the long history of wonderful PROM console traits, 86 * AlphaStation PROMs don't reset themselves completely on boot! 87 * Therefore, if an interrupt was turned on when the kernel was 88 * started, we're not going to EVER turn it off... I don't know 89 * what will happen if new interrupts (that the PROM console doesn't 90 * want) are turned on. I'll burn that bridge when I come to it. 91 */ 92 #define BROKEN_PROM_CONSOLE 93 94 /* 95 * Private functions and variables. 96 */ 97 98 bus_space_tag_t sio_iot; 99 pci_chipset_tag_t sio_pc; 100 bus_space_handle_t sio_ioh_icu1, sio_ioh_icu2; 101 102 #define ICU_LEN 16 /* number of ISA IRQs */ 103 104 static struct alpha_shared_intr *sio_intr; 105 106 #ifndef STRAY_MAX 107 #define STRAY_MAX 5 108 #endif 109 110 #ifdef BROKEN_PROM_CONSOLE 111 /* 112 * If prom console is broken, must remember the initial interrupt 113 * settings and enforce them. WHEE! 114 */ 115 u_int8_t initial_ocw1[2]; 116 u_int8_t initial_elcr[2]; 117 #endif 118 119 void sio_setirqstat(int, int, int); 120 int sio_intr_alloc(void *, int, int, int *); 121 122 u_int8_t (*sio_read_elcr)(int); 123 void (*sio_write_elcr)(int, u_int8_t); 124 static void specific_eoi(int); 125 #ifdef BROKEN_PROM_CONSOLE 126 void sio_intr_shutdown(void *); 127 #endif 128 129 /******************** i82378 SIO ELCR functions ********************/ 130 131 int i82378_setup_elcr(void); 132 u_int8_t i82378_read_elcr(int); 133 void i82378_write_elcr(int, u_int8_t); 134 135 bus_space_handle_t sio_ioh_elcr; 136 137 int 138 i82378_setup_elcr() 139 { 140 int rv; 141 142 /* 143 * We could probe configuration space to see that there's 144 * actually an SIO present, but we are using this as a 145 * fall-back in case nothing else matches. 146 */ 147 148 rv = bus_space_map(sio_iot, 0x4d0, 2, 0, &sio_ioh_elcr); 149 150 if (rv == 0) { 151 sio_read_elcr = i82378_read_elcr; 152 sio_write_elcr = i82378_write_elcr; 153 } 154 155 return (rv); 156 } 157 158 u_int8_t 159 i82378_read_elcr(elcr) 160 int elcr; 161 { 162 163 return (bus_space_read_1(sio_iot, sio_ioh_elcr, elcr)); 164 } 165 166 void 167 i82378_write_elcr(elcr, val) 168 int elcr; 169 u_int8_t val; 170 { 171 172 bus_space_write_1(sio_iot, sio_ioh_elcr, elcr, val); 173 } 174 175 /******************** Cypress CY82C693 ELCR functions ********************/ 176 177 int cy82c693_setup_elcr(void); 178 u_int8_t cy82c693_read_elcr(int); 179 void cy82c693_write_elcr(int, u_int8_t); 180 181 const struct cy82c693_handle *sio_cy82c693_handle; 182 183 int 184 cy82c693_setup_elcr() 185 { 186 int device, maxndevs; 187 pcitag_t tag; 188 pcireg_t id; 189 190 /* 191 * Search PCI configuration space for a Cypress CY82C693. 192 * 193 * Note we can make some assumptions about our bus number 194 * here, because: 195 * 196 * (1) there can be at most one ISA/EISA bridge per PCI bus, and 197 * 198 * (2) any ISA/EISA bridges must be attached to primary PCI 199 * busses (i.e. bus zero). 200 */ 201 202 maxndevs = pci_bus_maxdevs(sio_pc, 0); 203 204 for (device = 0; device < maxndevs; device++) { 205 tag = pci_make_tag(sio_pc, 0, device, 0); 206 id = pci_conf_read(sio_pc, tag, PCI_ID_REG); 207 208 /* Invalid vendor ID value? */ 209 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 210 continue; 211 /* XXX Not invalid, but we've done this ~forever. */ 212 if (PCI_VENDOR(id) == 0) 213 continue; 214 215 if (PCI_VENDOR(id) != PCI_VENDOR_CONTAQ || 216 PCI_PRODUCT(id) != PCI_PRODUCT_CONTAQ_82C693) 217 continue; 218 219 /* 220 * Found one! 221 */ 222 223 #if 0 224 printf("cy82c693_setup_elcr: found 82C693 at device %d\n", 225 device); 226 #endif 227 228 sio_cy82c693_handle = cy82c693_init(sio_iot); 229 sio_read_elcr = cy82c693_read_elcr; 230 sio_write_elcr = cy82c693_write_elcr; 231 232 return (0); 233 } 234 235 /* 236 * Didn't find a CY82C693. 237 */ 238 return (ENODEV); 239 } 240 241 u_int8_t 242 cy82c693_read_elcr(elcr) 243 int elcr; 244 { 245 246 return (cy82c693_read(sio_cy82c693_handle, CONFIG_ELCR1 + elcr)); 247 } 248 249 void 250 cy82c693_write_elcr(elcr, val) 251 int elcr; 252 u_int8_t val; 253 { 254 255 cy82c693_write(sio_cy82c693_handle, CONFIG_ELCR1 + elcr, val); 256 } 257 258 /******************** ELCR access function configuration ********************/ 259 260 /* 261 * Put the Intel SIO at the end, so we fall back on it if we don't 262 * find anything else. If any of the non-Intel functions find a 263 * matching device, but are unable to map it for whatever reason, 264 * they should panic. 265 */ 266 267 int (*sio_elcr_setup_funcs[])(void) = { 268 cy82c693_setup_elcr, 269 i82378_setup_elcr, 270 NULL, 271 }; 272 273 /******************** Shared SIO/Cypress functions ********************/ 274 275 void 276 sio_setirqstat(irq, enabled, type) 277 int irq, enabled; 278 int type; 279 { 280 u_int8_t ocw1[2], elcr[2]; 281 int icu, bit; 282 283 #if 0 284 printf("sio_setirqstat: irq %d: %s, %s\n", irq, 285 enabled ? "enabled" : "disabled", isa_intr_typename(type)); 286 #endif 287 288 icu = irq / 8; 289 bit = irq % 8; 290 291 ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1); 292 ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1); 293 elcr[0] = (*sio_read_elcr)(0); /* XXX */ 294 elcr[1] = (*sio_read_elcr)(1); /* XXX */ 295 296 /* 297 * interrupt enable: set bit to mask (disable) interrupt. 298 */ 299 if (enabled) 300 ocw1[icu] &= ~(1 << bit); 301 else 302 ocw1[icu] |= 1 << bit; 303 304 /* 305 * interrupt type select: set bit to get level-triggered. 306 */ 307 if (type == IST_LEVEL) 308 elcr[icu] |= 1 << bit; 309 else 310 elcr[icu] &= ~(1 << bit); 311 312 #ifdef not_here 313 /* see the init function... */ 314 ocw1[0] &= ~0x04; /* always enable IRQ2 on first PIC */ 315 elcr[0] &= ~0x07; /* IRQ[0-2] must be edge-triggered */ 316 elcr[1] &= ~0x21; /* IRQ[13,8] must be edge-triggered */ 317 #endif 318 319 bus_space_write_1(sio_iot, sio_ioh_icu1, 1, ocw1[0]); 320 bus_space_write_1(sio_iot, sio_ioh_icu2, 1, ocw1[1]); 321 (*sio_write_elcr)(0, elcr[0]); /* XXX */ 322 (*sio_write_elcr)(1, elcr[1]); /* XXX */ 323 } 324 325 void 326 sio_intr_setup(pc, iot) 327 pci_chipset_tag_t pc; 328 bus_space_tag_t iot; 329 { 330 #ifdef notyet 331 char *cp; 332 #endif 333 int i; 334 335 sio_iot = iot; 336 sio_pc = pc; 337 338 if (bus_space_map(sio_iot, IO_ICU1, 2, 0, &sio_ioh_icu1) || 339 bus_space_map(sio_iot, IO_ICU2, 2, 0, &sio_ioh_icu2)) 340 panic("sio_intr_setup: can't map ICU I/O ports"); 341 342 for (i = 0; sio_elcr_setup_funcs[i] != NULL; i++) 343 if ((*sio_elcr_setup_funcs[i])() == 0) 344 break; 345 if (sio_elcr_setup_funcs[i] == NULL) 346 panic("sio_intr_setup: can't map ELCR"); 347 348 #ifdef BROKEN_PROM_CONSOLE 349 /* 350 * Remember the initial values, so we can restore them later. 351 */ 352 initial_ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1); 353 initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1); 354 initial_elcr[0] = (*sio_read_elcr)(0); /* XXX */ 355 initial_elcr[1] = (*sio_read_elcr)(1); /* XXX */ 356 shutdownhook_establish(sio_intr_shutdown, 0); 357 #endif 358 359 sio_intr = alpha_shared_intr_alloc(ICU_LEN); 360 361 /* 362 * set up initial values for interrupt enables. 363 */ 364 for (i = 0; i < ICU_LEN; i++) { 365 alpha_shared_intr_set_maxstrays(sio_intr, i, STRAY_MAX); 366 367 switch (i) { 368 case 0: 369 case 1: 370 case 8: 371 case 13: 372 /* 373 * IRQs 0, 1, 8, and 13 must always be 374 * edge-triggered. 375 */ 376 sio_setirqstat(i, 0, IST_EDGE); 377 alpha_shared_intr_set_dfltsharetype(sio_intr, i, 378 IST_EDGE); 379 specific_eoi(i); 380 break; 381 382 case 2: 383 /* 384 * IRQ 2 must be edge-triggered, and should be 385 * enabled (otherwise IRQs 8-15 are ignored). 386 */ 387 sio_setirqstat(i, 1, IST_EDGE); 388 alpha_shared_intr_set_dfltsharetype(sio_intr, i, 389 IST_UNUSABLE); 390 break; 391 392 default: 393 /* 394 * Otherwise, disable the IRQ and set its 395 * type to (effectively) "unknown." 396 */ 397 sio_setirqstat(i, 0, IST_NONE); 398 alpha_shared_intr_set_dfltsharetype(sio_intr, i, 399 IST_NONE); 400 specific_eoi(i); 401 break; 402 } 403 } 404 } 405 406 #ifdef BROKEN_PROM_CONSOLE 407 void 408 sio_intr_shutdown(arg) 409 void *arg; 410 { 411 /* 412 * Restore the initial values, to make the PROM happy. 413 */ 414 bus_space_write_1(sio_iot, sio_ioh_icu1, 1, initial_ocw1[0]); 415 bus_space_write_1(sio_iot, sio_ioh_icu2, 1, initial_ocw1[1]); 416 (*sio_write_elcr)(0, initial_elcr[0]); /* XXX */ 417 (*sio_write_elcr)(1, initial_elcr[1]); /* XXX */ 418 } 419 #endif 420 421 const char * 422 sio_intr_string(v, irq) 423 void *v; 424 int irq; 425 { 426 static char irqstr[12]; /* 8 + 2 + NULL + sanity */ 427 428 if (irq == 0 || irq >= ICU_LEN || irq == 2) 429 panic("sio_intr_string: bogus isa irq 0x%x", irq); 430 431 snprintf(irqstr, sizeof irqstr, "isa irq %d", irq); 432 return (irqstr); 433 } 434 435 int 436 sio_intr_line(v, irq) 437 void *v; 438 int irq; 439 { 440 return (irq); 441 } 442 443 void * 444 sio_intr_establish(v, irq, type, level, fn, arg, name) 445 void *v, *arg; 446 int irq; 447 int type; 448 int level; 449 int (*fn)(void *); 450 char *name; 451 { 452 void *cookie; 453 454 if (irq >= ICU_LEN || type == IST_NONE) 455 panic("sio_intr_establish: bogus irq or type"); 456 457 cookie = alpha_shared_intr_establish(sio_intr, irq, type, level, fn, 458 arg, name); 459 460 if (cookie != NULL && 461 alpha_shared_intr_firstactive(sio_intr, irq)) { 462 scb_set(0x800 + SCB_IDXTOVEC(irq), sio_iointr, NULL); 463 sio_setirqstat(irq, 1, 464 alpha_shared_intr_get_sharetype(sio_intr, irq)); 465 } 466 467 return (cookie); 468 } 469 470 void 471 sio_intr_disestablish(v, cookie) 472 void *v; 473 void *cookie; 474 { 475 struct alpha_shared_intrhand *ih = cookie; 476 int s, ist, irq = ih->ih_num; 477 478 s = splhigh(); 479 480 /* Remove it from the link. */ 481 alpha_shared_intr_disestablish(sio_intr, cookie, "isa irq"); 482 483 /* 484 * Decide if we should disable the interrupt. We must ensure 485 * that: 486 * 487 * - An initially-enabled interrupt is never disabled. 488 * - An initially-LT interrupt is never untyped. 489 */ 490 if (alpha_shared_intr_isactive(sio_intr, irq) == 0) { 491 /* 492 * IRQs 0, 1, 8, and 13 must always be edge-triggered 493 * (see setup). 494 */ 495 switch (irq) { 496 case 0: 497 case 1: 498 case 8: 499 case 13: 500 /* 501 * If the interrupt was initially level-triggered 502 * a warning was printed in setup. 503 */ 504 ist = IST_EDGE; 505 break; 506 507 default: 508 ist = IST_NONE; 509 break; 510 } 511 sio_setirqstat(irq, 0, ist); 512 alpha_shared_intr_set_dfltsharetype(sio_intr, irq, ist); 513 514 /* Release our SCB vector. */ 515 scb_free(0x800 + SCB_IDXTOVEC(irq)); 516 } 517 518 splx(s); 519 } 520 521 void 522 sio_iointr(arg, vec) 523 void *arg; 524 unsigned long vec; 525 { 526 int irq; 527 528 irq = SCB_VECTOIDX(vec - 0x800); 529 530 #ifdef DIAGNOSTIC 531 if (irq >= ICU_LEN || irq < 0) 532 panic("sio_iointr: irq out of range (%d)", irq); 533 #endif 534 535 if (!alpha_shared_intr_dispatch(sio_intr, irq)) 536 alpha_shared_intr_stray(sio_intr, irq, "isa irq"); 537 else 538 alpha_shared_intr_reset_strays(sio_intr, irq); 539 540 /* 541 * Some versions of the machines which use the SIO 542 * (or is it some PALcode revisions on those machines?) 543 * require the non-specific EOI to be fed to the PIC(s) 544 * by the interrupt handler. 545 */ 546 specific_eoi(irq); 547 } 548 549 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2) 550 551 int 552 sio_intr_alloc(v, mask, type, irq) 553 void *v; 554 int mask; 555 int type; 556 int *irq; 557 { 558 int i, tmp, bestirq, count; 559 struct alpha_shared_intrhand **p, *q; 560 561 if (type == IST_NONE) 562 panic("intr_alloc: bogus type"); 563 564 bestirq = -1; 565 count = -1; 566 567 /* some interrupts should never be dynamically allocated */ 568 mask &= 0xdef8; 569 570 /* 571 * XXX some interrupts will be used later (6 for fdc, 12 for pms). 572 * the right answer is to do "breadth-first" searching of devices. 573 */ 574 mask &= 0xefbf; 575 576 for (i = 0; i < ICU_LEN; i++) { 577 if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0) 578 continue; 579 580 switch(sio_intr[i].intr_sharetype) { 581 case IST_NONE: 582 /* 583 * if nothing's using the irq, just return it 584 */ 585 *irq = i; 586 return (0); 587 588 case IST_EDGE: 589 case IST_LEVEL: 590 if (type != sio_intr[i].intr_sharetype) 591 continue; 592 /* 593 * if the irq is shareable, count the number of other 594 * handlers, and if it's smaller than the last irq like 595 * this, remember it 596 * 597 * XXX We should probably also consider the 598 * interrupt level and stick IPL_TTY with other 599 * IPL_TTY, etc. 600 */ 601 for (p = &TAILQ_FIRST(&sio_intr[i].intr_q), tmp = 0; 602 (q = *p) != NULL; p = &TAILQ_NEXT(q, ih_q), tmp++) 603 ; 604 if ((bestirq == -1) || (count > tmp)) { 605 bestirq = i; 606 count = tmp; 607 } 608 break; 609 610 case IST_PULSE: 611 /* this just isn't shareable */ 612 continue; 613 } 614 } 615 616 if (bestirq == -1) 617 return (1); 618 619 *irq = bestirq; 620 621 return (0); 622 } 623 624 static void 625 specific_eoi(irq) 626 int irq; 627 { 628 if (irq > 7) { 629 bus_space_write_1(sio_iot, 630 sio_ioh_icu2, 0, 0x60 | (irq & 0x07)); /* XXX */ 631 irq = 2; 632 } 633 bus_space_write_1(sio_iot, sio_ioh_icu1, 0, 0x60 | irq); 634 } 635