1 /* $NetBSD: pcib.c,v 1.20 2009/03/14 15:35:59 dsl Exp $ */
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
58 #include <algor/algor/algor_p5064var.h>
62 #include <algor/algor/algor_p6032var.h>
65 const char *pcib_intrnames
[16] = {
84 struct pcib_intrhead
{
85 LIST_HEAD(, algor_intrhand
) intr_q
;
86 struct evcnt intr_count
;
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];
105 #if defined(ALGOR_P5064)
106 isa_chipset_tag_t sc_parent_ic
;
109 u_int16_t sc_reserved
;
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
)
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
;
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. */
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
,
192 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh_icu1
, PIC_ICW4
,
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
,
214 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh_icu2
, PIC_ICW4
,
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,
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.
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. */
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
,
281 #elif defined(ALGOR_P6032)
282 sc
->sc_ih
= (*algor_intr_establish
)(P6032_IRQ_ISABRIDGE
,
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
);
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
;
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
);
326 pcib_isa_attach_hook(struct device
*parent
, struct device
*self
,
327 struct isabus_attach_args
*iba
)
334 pcib_isa_detach_hook(isa_chipset_tag_t ic
, device_t self
)
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);
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,
357 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh_elcr
, 1,
358 (sc
->sc_elcr
>> 8) & 0xff);
364 struct pcib_softc
*sc
= v
;
365 struct algor_intrhand
*ih
;
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)
375 irq
= OCW3_POLL_IRQ(irq
);
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
,
382 if (irq
& OCW3_POLL_PENDING
)
383 irq
= OCW3_POLL_IRQ(irq
) + 8;
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. */
396 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh_icu2
,
397 PIC_OCW2
, OCW2_SELECT
| OCW2_EOI
| OCW2_SL
|
402 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh_icu1
, PIC_OCW2
,
403 OCW2_SELECT
| OCW2_EOI
| OCW2_SL
| OCW2_ILS(irq
));
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
));
417 return (&sc
->sc_intrtab
[irq
].intr_count
);
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
;
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
,
437 switch (sc
->sc_intrtab
[irq
].intr_type
) {
439 sc
->sc_intrtab
[irq
].intr_type
= type
;
444 if (type
== sc
->sc_intrtab
[irq
].intr_type
)
449 * We can't share interrupts in this case.
454 ih
= malloc(sizeof(*ih
), M_DEVBUF
, M_NOWAIT
);
461 ih
->ih_irqmap
= NULL
;
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
);
474 sc
->sc_elcr
&= ~(1 << irq
);
484 pcib_isa_intr_disestablish(void *v
, void *arg
)
486 struct pcib_softc
*sc
= v
;
487 struct algor_intrhand
*ih
= arg
;
490 #if defined(ALGOR_P5064)
491 if (p5064_isa_to_irqmap
[ih
->ih_irq
] != -1) {
492 isa_intr_disestablish(sc
->sc_parent_ic
, ih
);
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
);
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");
525 mask
&= ~sc
->sc_reserved
;
528 printf("pcib_intr_alloc: mask = 0x%04x\n", mask
);
531 for (i
= 0; i
< 16; i
++) {
532 if ((mask
& (1 << i
)) == 0)
535 switch (sc
->sc_intrtab
[i
].intr_type
) {
538 * If nothing's using the IRQ, just return it.
545 if (type
!= sc
->sc_intrtab
[i
].intr_type
)
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.
553 for (ih
= LIST_FIRST(&sc
->sc_intrtab
[i
].intr_q
);
554 ih
!= NULL
; ih
= LIST_NEXT(ih
, ih_q
))
556 if (bestirq
== -1 || count
> tmp
) {
563 /* This just isn't sharable. */