No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / algor / pci / pcib.c
blob149d2040028abc14a6f1ccea6b16f4988a13960a
1 /* $NetBSD: pcib.c,v 1.20 2009/03/14 15:35:59 dsl Exp $ */
3 /*-
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
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.
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.
32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34 __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.20 2009/03/14 15:35:59 dsl Exp $");
36 #include "opt_algor_p5064.h"
37 #include "opt_algor_p6032.h"
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/malloc.h>
45 #include <machine/intr.h>
46 #include <machine/bus.h>
48 #include <dev/isa/isareg.h>
49 #include <dev/isa/isavar.h>
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/pcidevs.h>
55 #include <dev/ic/i8259reg.h>
57 #ifdef ALGOR_P5064
58 #include <algor/algor/algor_p5064var.h>
59 #endif
61 #ifdef ALGOR_P6032
62 #include <algor/algor/algor_p6032var.h>
63 #endif
65 const char *pcib_intrnames[16] = {
66 "irq 0",
67 "irq 1",
68 "irq 2",
69 "irq 3",
70 "irq 4",
71 "irq 5",
72 "irq 6",
73 "irq 7",
74 "irq 8",
75 "irq 9",
76 "irq 10",
77 "irq 11",
78 "irq 12",
79 "irq 13",
80 "irq 14",
81 "irq 15",
84 struct pcib_intrhead {
85 LIST_HEAD(, algor_intrhand) intr_q;
86 struct evcnt intr_count;
87 int intr_type;
90 struct pcib_softc {
91 struct device sc_dev;
93 bus_space_tag_t sc_iot;
94 bus_space_handle_t sc_ioh_icu1;
95 bus_space_handle_t sc_ioh_icu2;
96 bus_space_handle_t sc_ioh_elcr;
98 struct algor_isa_chipset sc_ic;
100 struct pcib_intrhead sc_intrtab[16];
102 u_int16_t sc_imask;
103 u_int16_t sc_elcr;
105 #if defined(ALGOR_P5064)
106 isa_chipset_tag_t sc_parent_ic;
107 #endif
109 u_int16_t sc_reserved;
111 void *sc_ih;
114 int pcib_match(struct device *, struct cfdata *, void *);
115 void pcib_attach(struct device *, struct device *, void *);
117 CFATTACH_DECL(pcib, sizeof(struct pcib_softc),
118 pcib_match, pcib_attach, NULL, NULL);
120 void pcib_isa_attach_hook(struct device *, struct device *,
121 struct isabus_attach_args *);
122 void pcib_isa_detach_hook(isa_chipset_tag_t, device_t);
124 int pcib_intr(void *);
126 void pcib_bridge_callback(struct device *);
128 const struct evcnt *pcib_isa_intr_evcnt(void *, int);
129 void *pcib_isa_intr_establish(void *, int, int, int,
130 int (*)(void *), void *);
131 void pcib_isa_intr_disestablish(void *, void *);
132 int pcib_isa_intr_alloc(void *, int, int, int *);
134 void pcib_set_icus(struct pcib_softc *);
137 pcib_match(struct device *parent, struct cfdata *match, void *aux)
139 struct pci_attach_args *pa = aux;
141 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
142 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
143 return (1);
145 return (0);
148 void
149 pcib_attach(struct device *parent, struct device *self, void *aux)
151 struct pcib_softc *sc = (void *) self;
152 struct pci_attach_args *pa = aux;
153 char devinfo[256];
154 int i;
156 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
157 printf(": %s (rev. 0x%02x)\n", devinfo,
158 PCI_REVISION(pa->pa_class));
160 sc->sc_iot = pa->pa_iot;
163 * Map the PIC/ELCR registers.
165 if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
166 printf("%s: unable to map ELCR registers\n",
167 sc->sc_dev.dv_xname);
168 if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
169 printf("%s: unable to map ICU1 registers\n",
170 sc->sc_dev.dv_xname);
171 if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
172 printf("%s: unable to map ICU2 registers\n",
173 sc->sc_dev.dv_xname);
175 /* All interrupts default to "masked off". */
176 sc->sc_imask = 0xffff;
178 /* All interrupts default to edge-triggered. */
179 sc->sc_elcr = 0;
182 * Initialize the 8259s.
185 /* reset, program device, 4 bytes */
186 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1,
187 ICW1_SELECT | ICW1_IC4);
188 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2,
189 ICW2_VECTOR(0)/*XXX*/);
190 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3,
191 ICW3_CASCADE(2));
192 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4,
193 ICW4_8086);
195 /* mask all interrupts */
196 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
197 sc->sc_imask & 0xff);
199 /* enable special mask mode */
200 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
201 OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
203 /* read IRR by default */
204 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
205 OCW3_SELECT | OCW3_RR);
207 /* reset; program device, 4 bytes */
208 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
209 ICW1_SELECT | ICW1_IC4);
210 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
211 ICW2_VECTOR(0)/*XXX*/);
212 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
213 ICW3_SIC(2));
214 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
215 ICW4_8086);
217 /* mask all interrupts */
218 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
219 (sc->sc_imask >> 8) & 0xff);
221 /* enable special mask mode */
222 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
223 OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
225 /* read IRR by default */
226 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
227 OCW3_SELECT | OCW3_RR);
230 * Default all interrupts to edge-triggered.
232 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
233 sc->sc_elcr & 0xff);
234 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
235 (sc->sc_elcr >> 8) & 0xff);
238 * Some ISA interrupts are reserved for devices that
239 * we know are hard-wired to certain IRQs.
241 sc->sc_reserved =
242 (1U << 0) | /* timer */
243 (1U << 1) | /* keyboard controller */
244 (1U << 2) | /* PIC cascade */
245 (1U << 3) | /* COM 2 */
246 (1U << 4) | /* COM 1 */
247 (1U << 6) | /* floppy */
248 (1U << 7) | /* centronics */
249 (1U << 8) | /* RTC */
250 (1U << 12) | /* keyboard controller */
251 (1U << 14) | /* IDE 0 */
252 (1U << 15); /* IDE 1 */
254 #if defined(ALGOR_P5064)
256 * Some "ISA" interrupts are a little wacky, wired up directly
257 * to the P-5064 interrupt controller.
259 sc->sc_parent_ic = &p5064_configuration.ac_ic;
260 #endif /* ALGOR_P5064 */
262 /* Set up our ISA chipset. */
263 sc->sc_ic.ic_v = sc;
264 sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
265 sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
266 sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
267 sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
269 /* Initialize our interrupt table. */
270 for (i = 0; i < 16; i++) {
271 LIST_INIT(&sc->sc_intrtab[i].intr_q);
272 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
273 EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
274 sc->sc_intrtab[i].intr_type = IST_NONE;
277 /* Hook up our interrupt handler. */
278 #if defined(ALGOR_P5064)
279 sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE,
280 pcib_intr, sc);
281 #elif defined(ALGOR_P6032)
282 sc->sc_ih = (*algor_intr_establish)(P6032_IRQ_ISABRIDGE,
283 pcib_intr, sc);
284 #endif
285 if (sc->sc_ih == NULL)
286 printf("%s: WARNING: unable to register interrupt handler\n",
287 sc->sc_dev.dv_xname);
289 config_defer(self, pcib_bridge_callback);
292 void
293 pcib_bridge_callback(struct device *self)
295 struct pcib_softc *sc = (struct pcib_softc *)self;
296 struct isabus_attach_args iba;
298 memset(&iba, 0, sizeof(iba));
300 #if defined(ALGOR_P5064)
302 struct p5064_config *acp = &p5064_configuration;
304 iba.iba_iot = &acp->ac_iot;
305 iba.iba_memt = &acp->ac_memt;
306 iba.iba_dmat = &acp->ac_isa_dmat;
308 #elif defined(ALGOR_P6032)
310 struct p6032_config *acp = &p6032_configuration;
312 iba.iba_iot = &acp->ac_iot;
313 iba.iba_memt = &acp->ac_memt;
314 iba.iba_dmat = &acp->ac_isa_dmat;
316 #endif
318 iba.iba_ic = &sc->sc_ic;
319 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
320 iba.iba_ic->ic_detach_hook = pcib_isa_detach_hook;
322 (void) config_found_ia(&sc->sc_dev, "isabus", &iba, isabusprint);
325 void
326 pcib_isa_attach_hook(struct device *parent, struct device *self,
327 struct isabus_attach_args *iba)
330 /* Nothing to do. */
333 void
334 pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self)
337 /* Nothing to do. */
340 void
341 pcib_set_icus(struct pcib_softc *sc)
344 /* Enable the cascade IRQ (2) if 8-15 is enabled. */
345 if ((sc->sc_imask & 0xff00) != 0xff00)
346 sc->sc_imask &= ~(1U << 2);
347 else
348 sc->sc_imask |= (1U << 2);
350 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
351 sc->sc_imask & 0xff);
352 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
353 (sc->sc_imask >> 8) & 0xff);
355 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
356 sc->sc_elcr & 0xff);
357 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
358 (sc->sc_elcr >> 8) & 0xff);
362 pcib_intr(void *v)
364 struct pcib_softc *sc = v;
365 struct algor_intrhand *ih;
366 int irq;
368 for (;;) {
369 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
370 OCW3_SELECT | OCW3_POLL);
371 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
372 if ((irq & OCW3_POLL_PENDING) == 0)
373 return (1);
375 irq = OCW3_POLL_IRQ(irq);
377 if (irq == 2) {
378 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
379 PIC_OCW3, OCW3_SELECT | OCW3_POLL);
380 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
381 PIC_OCW3);
382 if (irq & OCW3_POLL_PENDING)
383 irq = OCW3_POLL_IRQ(irq) + 8;
384 else
385 irq = 2;
388 sc->sc_intrtab[irq].intr_count.ev_count++;
389 for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
390 ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
391 (*ih->ih_func)(ih->ih_arg);
394 /* Send a specific EOI to the 8259. */
395 if (irq > 7) {
396 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
397 PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
398 OCW2_ILS(irq & 7));
399 irq = 2;
402 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
403 OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
407 const struct evcnt *
408 pcib_isa_intr_evcnt(void *v, int irq)
410 struct pcib_softc *sc = v;
412 #if defined(ALGOR_P5064)
413 if (p5064_isa_to_irqmap[irq] != -1)
414 return (isa_intr_evcnt(sc->sc_parent_ic, irq));
415 #endif
417 return (&sc->sc_intrtab[irq].intr_count);
420 void *
421 pcib_isa_intr_establish(void *v, int irq, int type, int level,
422 int (*func)(void *), void *arg)
424 struct pcib_softc *sc = v;
425 struct algor_intrhand *ih;
426 int s;
428 if (irq > 15 || irq == 2 || type == IST_NONE)
429 panic("pcib_isa_intr_establish: bad irq or type");
431 #if defined(ALGOR_P5064)
432 if (p5064_isa_to_irqmap[irq] != -1)
433 return (isa_intr_establish(sc->sc_parent_ic, irq, type,
434 level, func, arg));
435 #endif
437 switch (sc->sc_intrtab[irq].intr_type) {
438 case IST_NONE:
439 sc->sc_intrtab[irq].intr_type = type;
440 break;
442 case IST_EDGE:
443 case IST_LEVEL:
444 if (type == sc->sc_intrtab[irq].intr_type)
445 break;
446 /* FALLTHROUGH */
447 case IST_PULSE:
449 * We can't share interrupts in this case.
451 return (NULL);
454 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
455 if (ih == NULL)
456 return (NULL);
458 ih->ih_func = func;
459 ih->ih_arg = arg;
460 ih->ih_irq = irq;
461 ih->ih_irqmap = NULL;
463 s = splhigh();
465 /* Insert the handler into the table. */
466 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
467 sc->sc_intrtab[irq].intr_type = type;
469 /* Enable it, set trigger mode. */
470 sc->sc_imask &= ~(1 << irq);
471 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
472 sc->sc_elcr |= (1 << irq);
473 else
474 sc->sc_elcr &= ~(1 << irq);
476 pcib_set_icus(sc);
478 splx(s);
480 return (ih);
483 void
484 pcib_isa_intr_disestablish(void *v, void *arg)
486 struct pcib_softc *sc = v;
487 struct algor_intrhand *ih = arg;
488 int s;
490 #if defined(ALGOR_P5064)
491 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
492 isa_intr_disestablish(sc->sc_parent_ic, ih);
493 return;
495 #endif
497 s = splhigh();
499 LIST_REMOVE(ih, ih_q);
501 /* If there are no more handlers on this IRQ, disable it. */
502 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
503 sc->sc_imask |= (1 << ih->ih_irq);
504 pcib_set_icus(sc);
507 splx(s);
509 free(ih, M_DEVBUF);
513 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
515 struct pcib_softc *sc = v;
516 int i, tmp, bestirq, count;
517 struct algor_intrhand *ih;
519 if (type == IST_NONE)
520 panic("pcib_intr_alloc: bogus type");
522 bestirq = -1;
523 count = -1;
525 mask &= ~sc->sc_reserved;
527 #if 0
528 printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
529 #endif
531 for (i = 0; i < 16; i++) {
532 if ((mask & (1 << i)) == 0)
533 continue;
535 switch (sc->sc_intrtab[i].intr_type) {
536 case IST_NONE:
538 * If nothing's using the IRQ, just return it.
540 *irq = i;
541 return (0);
543 case IST_EDGE:
544 case IST_LEVEL:
545 if (type != sc->sc_intrtab[i].intr_type)
546 continue;
548 * If the IRQ is sharable, count the number of
549 * other handlers, and if it's smaller than the
550 * last IRQ like this, remember it.
552 tmp = 0;
553 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
554 ih != NULL; ih = LIST_NEXT(ih, ih_q))
555 tmp++;
556 if (bestirq == -1 || count > tmp) {
557 bestirq = i;
558 count = tmp;
560 break;
562 case IST_PULSE:
563 /* This just isn't sharable. */
564 continue;
568 if (bestirq == -1)
569 return (1);
571 *irq = bestirq;
572 return (0);