1/* $NetBSD: pcib.c,v 1.23 2011/07/08 18:48:59 matt Exp $ */ 2 3/*- 4 * Copyright (c) 2000, 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#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.23 2011/07/08 18:48:59 matt Exp $"); 35 36#include "opt_algor_p5064.h" 37#include "opt_algor_p6032.h" 38 39#include <sys/param.h> 40#include <sys/bus.h> 41#include <sys/device.h> 42#include <sys/intr.h> 43#include <sys/kernel.h> 44#include <sys/malloc.h> 45#include <sys/systm.h> 46 47#include <algor/autoconf.h> 48 49#include <dev/isa/isareg.h> 50#include <dev/isa/isavar.h> 51 52#include <dev/pci/pcireg.h> 53#include <dev/pci/pcivar.h> 54#include <dev/pci/pcidevs.h> 55 56#include <dev/ic/i8259reg.h> 57 58#ifdef ALGOR_P5064 59#include <algor/algor/algor_p5064var.h> 60#endif 61 62#ifdef ALGOR_P6032 63#include <algor/algor/algor_p6032var.h> 64#endif 65 66const char * const pcib_intrnames[16] = { 67 "irq 0", 68 "irq 1", 69 "irq 2", 70 "irq 3", 71 "irq 4", 72 "irq 5", 73 "irq 6", 74 "irq 7", 75 "irq 8", 76 "irq 9", 77 "irq 10", 78 "irq 11", 79 "irq 12", 80 "irq 13", 81 "irq 14", 82 "irq 15", 83}; 84 85struct pcib_intrhead { 86 LIST_HEAD(, evbmips_intrhand) intr_q; 87 struct evcnt intr_count; 88 int intr_type; 89}; 90 91struct pcib_softc { 92 device_t sc_dev; 93 94 bus_space_tag_t sc_iot; 95 bus_space_handle_t sc_ioh_icu1; 96 bus_space_handle_t sc_ioh_icu2; 97 bus_space_handle_t sc_ioh_elcr; 98 99 struct mips_isa_chipset sc_ic; 100 101 struct pcib_intrhead sc_intrtab[16]; 102 103 u_int16_t sc_imask; 104 u_int16_t sc_elcr; 105 106#if defined(ALGOR_P5064) 107 isa_chipset_tag_t sc_parent_ic; 108#endif 109 110 u_int16_t sc_reserved; 111 112 void *sc_ih; 113}; 114 115int pcib_match(device_t, cfdata_t, void *); 116void pcib_attach(device_t, device_t, void *); 117 118CFATTACH_DECL_NEW(pcib, sizeof(struct pcib_softc), 119 pcib_match, pcib_attach, NULL, NULL); 120 121void pcib_isa_attach_hook(device_t, device_t, struct isabus_attach_args *); 122void pcib_isa_detach_hook(isa_chipset_tag_t, device_t); 123 124int pcib_intr(void *); 125 126void pcib_bridge_callback(device_t); 127 128const struct evcnt *pcib_isa_intr_evcnt(void *, int); 129void *pcib_isa_intr_establish(void *, int, int, int, 130 int (*)(void *), void *); 131void pcib_isa_intr_disestablish(void *, void *); 132int pcib_isa_intr_alloc(void *, int, int, int *); 133 134void pcib_set_icus(struct pcib_softc *); 135 136int 137pcib_match(device_t parent, cfdata_t match, void *aux) 138{ 139 struct pci_attach_args *pa = aux; 140 141 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 142 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) 143 return (1); 144 145 return (0); 146} 147 148void 149pcib_attach(device_t parent, device_t self, void *aux) 150{ 151 struct pcib_softc *sc = device_private(self); 152 struct pci_attach_args *pa = aux; 153 char devinfo[256]; 154 int i; 155 156 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 157 aprint_normal(": %s (rev. 0x%02x)\n", devinfo, 158 PCI_REVISION(pa->pa_class)); 159 160 sc->sc_dev = self; 161 sc->sc_iot = pa->pa_iot; 162 163 /* 164 * Map the PIC/ELCR registers. 165 */ 166 if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0) 167 aprint_error_dev(self, "unable to map ELCR registers\n"); 168 if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0) 169 aprint_error_dev(self, "unable to map ICU1 registers\n"); 170 if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0) 171 aprint_error_dev(self, "unable to map ICU2 registers\n"); 172 173 /* All interrupts default to "masked off". */ 174 sc->sc_imask = 0xffff; 175 176 /* All interrupts default to edge-triggered. */ 177 sc->sc_elcr = 0; 178 179 /* 180 * Initialize the 8259s. 181 */ 182 183 /* reset, program device, 4 bytes */ 184 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1, 185 ICW1_SELECT | ICW1_IC4); 186 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2, 187 ICW2_VECTOR(0)/*XXX*/); 188 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3, 189 ICW3_CASCADE(2)); 190 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4, 191 ICW4_8086); 192 193 /* mask all interrupts */ 194 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 195 sc->sc_imask & 0xff); 196 197 /* enable special mask mode */ 198 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 199 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 200 201 /* read IRR by default */ 202 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 203 OCW3_SELECT | OCW3_RR); 204 205 /* reset; program device, 4 bytes */ 206 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1, 207 ICW1_SELECT | ICW1_IC4); 208 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2, 209 ICW2_VECTOR(0)/*XXX*/); 210 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3, 211 ICW3_SIC(2)); 212 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4, 213 ICW4_8086); 214 215 /* mask all interrupts */ 216 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 217 (sc->sc_imask >> 8) & 0xff); 218 219 /* enable special mask mode */ 220 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3, 221 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 222 223 /* read IRR by default */ 224 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3, 225 OCW3_SELECT | OCW3_RR); 226 227 /* 228 * Default all interrupts to edge-triggered. 229 */ 230 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 231 sc->sc_elcr & 0xff); 232 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 233 (sc->sc_elcr >> 8) & 0xff); 234 235 /* 236 * Some ISA interrupts are reserved for devices that 237 * we know are hard-wired to certain IRQs. 238 */ 239 sc->sc_reserved = 240 (1U << 0) | /* timer */ 241 (1U << 1) | /* keyboard controller */ 242 (1U << 2) | /* PIC cascade */ 243 (1U << 3) | /* COM 2 */ 244 (1U << 4) | /* COM 1 */ 245 (1U << 6) | /* floppy */ 246 (1U << 7) | /* centronics */ 247 (1U << 8) | /* RTC */ 248 (1U << 12) | /* keyboard controller */ 249 (1U << 14) | /* IDE 0 */ 250 (1U << 15); /* IDE 1 */ 251 252#if defined(ALGOR_P5064) 253 /* 254 * Some "ISA" interrupts are a little wacky, wired up directly 255 * to the P-5064 interrupt controller. 256 */ 257 sc->sc_parent_ic = &p5064_configuration.ac_ic; 258#endif /* ALGOR_P5064 */ 259 260 /* Set up our ISA chipset. */ 261 sc->sc_ic.ic_v = sc; 262 sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt; 263 sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish; 264 sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish; 265 sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc; 266 267 /* Initialize our interrupt table. */ 268 for (i = 0; i < 16; i++) { 269 LIST_INIT(&sc->sc_intrtab[i].intr_q); 270 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count, 271 EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]); 272 sc->sc_intrtab[i].intr_type = IST_NONE; 273 } 274 275 /* Hook up our interrupt handler. */ 276#if defined(ALGOR_P5064) 277 sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE, 278 pcib_intr, sc); 279#elif defined(ALGOR_P6032) 280 sc->sc_ih = (*algor_intr_establish)(P6032_IRQ_ISABRIDGE, 281 pcib_intr, sc); 282#endif 283 if (sc->sc_ih == NULL) 284 printf("%s: WARNING: unable to register interrupt handler\n", 285 device_xname(sc->sc_dev)); 286 287 config_defer(self, pcib_bridge_callback); 288} 289 290void 291pcib_bridge_callback(device_t self) 292{ 293 struct pcib_softc *sc = device_private(self); 294 struct isabus_attach_args iba; 295 296 memset(&iba, 0, sizeof(iba)); 297 298#if defined(ALGOR_P5064) 299 { 300 struct p5064_config *acp = &p5064_configuration; 301 302 iba.iba_iot = &acp->ac_iot; 303 iba.iba_memt = &acp->ac_memt; 304 iba.iba_dmat = &acp->ac_isa_dmat; 305 } 306#elif defined(ALGOR_P6032) 307 { 308 struct p6032_config *acp = &p6032_configuration; 309 310 iba.iba_iot = &acp->ac_iot; 311 iba.iba_memt = &acp->ac_memt; 312 iba.iba_dmat = &acp->ac_isa_dmat; 313 } 314#endif 315 316 iba.iba_ic = &sc->sc_ic; 317 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook; 318 iba.iba_ic->ic_detach_hook = pcib_isa_detach_hook; 319 320 (void) config_found_ia(sc->sc_dev, "isabus", &iba, isabusprint); 321} 322 323void 324pcib_isa_attach_hook(device_t parent, device_t self, 325 struct isabus_attach_args *iba) 326{ 327 328 /* Nothing to do. */ 329} 330 331void 332pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self) 333{ 334 335 /* Nothing to do. */ 336} 337 338void 339pcib_set_icus(struct pcib_softc *sc) 340{ 341 342 /* Enable the cascade IRQ (2) if 8-15 is enabled. */ 343 if ((sc->sc_imask & 0xff00) != 0xff00) 344 sc->sc_imask &= ~(1U << 2); 345 else 346 sc->sc_imask |= (1U << 2); 347 348 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 349 sc->sc_imask & 0xff); 350 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 351 (sc->sc_imask >> 8) & 0xff); 352 353 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 354 sc->sc_elcr & 0xff); 355 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 356 (sc->sc_elcr >> 8) & 0xff); 357} 358 359int 360pcib_intr(void *v) 361{ 362 struct pcib_softc *sc = v; 363 struct evbmips_intrhand *ih; 364 int irq; 365 366 for (;;) { 367 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 368 OCW3_SELECT | OCW3_POLL); 369 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3); 370 if ((irq & OCW3_POLL_PENDING) == 0) 371 return (1); 372 373 irq = OCW3_POLL_IRQ(irq); 374 375 if (irq == 2) { 376 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 377 PIC_OCW3, OCW3_SELECT | OCW3_POLL); 378 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 379 PIC_OCW3); 380 if (irq & OCW3_POLL_PENDING) 381 irq = OCW3_POLL_IRQ(irq) + 8; 382 else 383 irq = 2; 384 } 385 386 sc->sc_intrtab[irq].intr_count.ev_count++; 387 for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q); 388 ih != NULL; ih = LIST_NEXT(ih, ih_q)) { 389 (*ih->ih_func)(ih->ih_arg); 390 } 391 392 /* Send a specific EOI to the 8259. */ 393 if (irq > 7) { 394 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 395 PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL | 396 OCW2_ILS(irq & 7)); 397 irq = 2; 398 } 399 400 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2, 401 OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq)); 402 } 403} 404 405const struct evcnt * 406pcib_isa_intr_evcnt(void *v, int irq) 407{ 408 struct pcib_softc *sc = v; 409 410#if defined(ALGOR_P5064) 411 if (p5064_isa_to_irqmap[irq] != -1) 412 return (isa_intr_evcnt(sc->sc_parent_ic, irq)); 413#endif 414 415 return (&sc->sc_intrtab[irq].intr_count); 416} 417 418void * 419pcib_isa_intr_establish(void *v, int irq, int type, int level, 420 int (*func)(void *), void *arg) 421{ 422 struct pcib_softc *sc = v; 423 struct evbmips_intrhand *ih; 424 int s; 425 426 if (irq > 15 || irq == 2 || type == IST_NONE) 427 panic("pcib_isa_intr_establish: bad irq or type"); 428 429#if defined(ALGOR_P5064) 430 if (p5064_isa_to_irqmap[irq] != -1) 431 return (isa_intr_establish(sc->sc_parent_ic, irq, type, 432 level, func, arg)); 433#endif 434 435 switch (sc->sc_intrtab[irq].intr_type) { 436 case IST_NONE: 437 sc->sc_intrtab[irq].intr_type = type; 438 break; 439 440 case IST_EDGE: 441 case IST_LEVEL: 442 if (type == sc->sc_intrtab[irq].intr_type) 443 break; 444 /* FALLTHROUGH */ 445 case IST_PULSE: 446 /* 447 * We can't share interrupts in this case. 448 */ 449 return (NULL); 450 } 451 452 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 453 if (ih == NULL) 454 return (NULL); 455 456 ih->ih_func = func; 457 ih->ih_arg = arg; 458 ih->ih_irq = irq; 459 ih->ih_irqmap = NULL; 460 461 s = splhigh(); 462 463 /* Insert the handler into the table. */ 464 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q); 465 sc->sc_intrtab[irq].intr_type = type; 466 467 /* Enable it, set trigger mode. */ 468 sc->sc_imask &= ~(1 << irq); 469 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL) 470 sc->sc_elcr |= (1 << irq); 471 else 472 sc->sc_elcr &= ~(1 << irq); 473 474 pcib_set_icus(sc); 475 476 splx(s); 477 478 return (ih); 479} 480 481void 482pcib_isa_intr_disestablish(void *v, void *arg) 483{ 484 struct pcib_softc *sc = v; 485 struct evbmips_intrhand *ih = arg; 486 int s; 487 488#if defined(ALGOR_P5064) 489 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) { 490 isa_intr_disestablish(sc->sc_parent_ic, ih); 491 return; 492 } 493#endif 494 495 s = splhigh(); 496 497 LIST_REMOVE(ih, ih_q); 498 499 /* If there are no more handlers on this IRQ, disable it. */ 500 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) { 501 sc->sc_imask |= (1 << ih->ih_irq); 502 pcib_set_icus(sc); 503 } 504 505 splx(s); 506 507 free(ih, M_DEVBUF); 508} 509 510int 511pcib_isa_intr_alloc(void *v, int mask, int type, int *irq) 512{ 513 struct pcib_softc *sc = v; 514 int i, tmp, bestirq, count; 515 struct evbmips_intrhand *ih; 516 517 if (type == IST_NONE) 518 panic("pcib_intr_alloc: bogus type"); 519 520 bestirq = -1; 521 count = -1; 522 523 mask &= ~sc->sc_reserved; 524 525#if 0 526 printf("pcib_intr_alloc: mask = 0x%04x\n", mask); 527#endif 528 529 for (i = 0; i < 16; i++) { 530 if ((mask & (1 << i)) == 0) 531 continue; 532 533 switch (sc->sc_intrtab[i].intr_type) { 534 case IST_NONE: 535 /* 536 * If nothing's using the IRQ, just return it. 537 */ 538 *irq = i; 539 return (0); 540 541 case IST_EDGE: 542 case IST_LEVEL: 543 if (type != sc->sc_intrtab[i].intr_type) 544 continue; 545 /* 546 * If the IRQ is sharable, count the number of 547 * other handlers, and if it's smaller than the 548 * last IRQ like this, remember it. 549 */ 550 tmp = 0; 551 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q); 552 ih != NULL; ih = LIST_NEXT(ih, ih_q)) 553 tmp++; 554 if (bestirq == -1 || count > tmp) { 555 bestirq = i; 556 count = tmp; 557 } 558 break; 559 560 case IST_PULSE: 561 /* This just isn't sharable. */ 562 continue; 563 } 564 } 565 566 if (bestirq == -1) 567 return (1); 568 569 *irq = bestirq; 570 return (0); 571} 572