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