xref: /netbsd-src/sys/arch/algor/pci/pcib.c (revision 1ce7119f17bbe15fe77bc90d143ff45bb971dce6)
1 /*	$NetBSD: pcib.c,v 1.7 2001/06/21 19:00:18 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.7 2001/06/21 19:00:18 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(32)/*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(32 + 8)/*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)(XXX,
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 		/* XXX */
321 	    }
322 #endif
323 
324 	iba.iba_ic = &sc->sc_ic;
325 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
326 
327 	(void) config_found(&sc->sc_dev, &iba, pcib_print);
328 }
329 
330 int
331 pcib_print(void *aux, const char *pnp)
332 {
333 	struct isabus_attach_args *iba;
334 
335 	if (pnp)
336 		printf("%s at %s", iba->iba_busname, pnp);
337 	return (UNCONF);
338 }
339 
340 void
341 pcib_isa_attach_hook(struct device *parent, struct device *self,
342     struct isabus_attach_args *iba)
343 {
344 
345 	/* Nothing to do. */
346 }
347 
348 void
349 pcib_set_icus(struct pcib_softc *sc)
350 {
351 
352 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
353 	if ((sc->sc_imask & 0xff00) != 0xff00)
354 		sc->sc_imask &= ~(1U << 2);
355 	else
356 		sc->sc_imask |= (1U << 2);
357 
358 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
359 	    sc->sc_imask & 0xff);
360 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
361 	    (sc->sc_imask >> 8) & 0xff);
362 
363 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
364 	    sc->sc_elcr & 0xff);
365 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
366 	    (sc->sc_elcr >> 8) & 0xff);
367 }
368 
369 int
370 pcib_intr(void *v)
371 {
372 	struct pcib_softc *sc = v;
373 	struct algor_intrhand *ih;
374 	int irq;
375 
376 	for (;;) {
377 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
378 		    OCW3_SELECT | OCW3_POLL);
379 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
380 		if ((irq & OCW3_POLL_PENDING) == 0)
381 			return (1);
382 
383 		irq = OCW3_POLL_IRQ(irq);
384 
385 		if (irq == 2) {
386 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
387 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
388 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
389 			    PIC_OCW3);
390 			if (irq & OCW3_POLL_PENDING)
391 				irq = OCW3_POLL_IRQ(irq) + 8;
392 			else
393 				irq = 2;
394 		}
395 
396 		sc->sc_intrtab[irq].intr_count.ev_count++;
397 		for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
398 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
399 			(*ih->ih_func)(ih->ih_arg);
400 		}
401 
402 		/* Send a specific EOI to the 8259. */
403 		if (irq > 7) {
404 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
405 			    PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL |
406 			    OCW2_ILS(irq & 7));
407 			irq = 2;
408 		}
409 
410 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
411 		    OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq));
412 	}
413 }
414 
415 const struct evcnt *
416 pcib_isa_intr_evcnt(void *v, int irq)
417 {
418 	struct pcib_softc *sc = v;
419 
420 #if defined(ALGOR_P5064)
421 	if (p5064_isa_to_irqmap[irq] != -1)
422 		return (isa_intr_evcnt(sc->sc_parent_ic, irq));
423 #endif
424 
425 	return (&sc->sc_intrtab[irq].intr_count);
426 }
427 
428 void *
429 pcib_isa_intr_establish(void *v, int irq, int type, int level,
430     int (*func)(void *), void *arg)
431 {
432 	struct pcib_softc *sc = v;
433 	struct algor_intrhand *ih;
434 	int s;
435 
436 	if (irq > 15 || irq == 2 || type == IST_NONE)
437 		panic("pcib_isa_intr_establish: bad irq or type");
438 
439 #if defined(ALGOR_P5064)
440 	if (p5064_isa_to_irqmap[irq] != -1)
441 		return (isa_intr_establish(sc->sc_parent_ic, irq, type,
442 		    level, func, arg));
443 #endif
444 
445 	switch (sc->sc_intrtab[irq].intr_type) {
446 	case IST_NONE:
447 		sc->sc_intrtab[irq].intr_type = type;
448 		break;
449 
450 	case IST_EDGE:
451 	case IST_LEVEL:
452 		if (type == sc->sc_intrtab[irq].intr_type)
453 			break;
454 		/* FALLTHROUGH */
455 	case IST_PULSE:
456 		/*
457 		 * We can't share interrupts in this case.
458 		 */
459 		return (NULL);
460 	}
461 
462 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
463 	if (ih == NULL)
464 		return (NULL);
465 
466 	ih->ih_func = func;
467 	ih->ih_arg = arg;
468 	ih->ih_irq = irq;
469 	ih->ih_irqmap = NULL;
470 
471 	s = splhigh();
472 
473 	/* Insert the handler into the table. */
474 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
475 	sc->sc_intrtab[irq].intr_type = type;
476 
477 	/* Enable it, set trigger mode. */
478 	sc->sc_imask &= ~(1 << irq);
479 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
480 		sc->sc_elcr |= (1 << irq);
481 	else
482 		sc->sc_elcr &= ~(1 << irq);
483 
484 	pcib_set_icus(sc);
485 
486 	splx(s);
487 
488 	return (ih);
489 }
490 
491 void
492 pcib_isa_intr_disestablish(void *v, void *arg)
493 {
494 	struct pcib_softc *sc = v;
495 	struct algor_intrhand *ih = arg;
496 	int s;
497 
498 #if defined(ALGOR_P5064)
499 	if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
500 		isa_intr_disestablish(sc->sc_parent_ic, ih);
501 		return;
502 	}
503 #endif
504 
505 	s = splhigh();
506 
507 	LIST_REMOVE(ih, ih_q);
508 
509 	/* If there are no more handlers on this IRQ, disable it. */
510 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
511 		sc->sc_imask |= (1 << ih->ih_irq);
512 		pcib_set_icus(sc);
513 	}
514 
515 	splx(s);
516 
517 	free(ih, M_DEVBUF);
518 }
519 
520 int
521 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
522 {
523 	struct pcib_softc *sc = v;
524 	int i, tmp, bestirq, count;
525 	struct algor_intrhand *ih;
526 
527 	if (type == IST_NONE)
528 		panic("pcib_intr_alloc: bogus type");
529 
530 	bestirq = -1;
531 	count = -1;
532 
533 	mask &= ~sc->sc_reserved;
534 
535 #if 0
536 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
537 #endif
538 
539 	for (i = 0; i < 16; i++) {
540 		if ((mask & (1 << i)) == 0)
541 			continue;
542 
543 		switch (sc->sc_intrtab[i].intr_type) {
544 		case IST_NONE:
545 			/*
546 			 * If nothing's using the IRQ, just return it.
547 			 */
548 			*irq = i;
549 			return (0);
550 
551 		case IST_EDGE:
552 		case IST_LEVEL:
553 			if (type != sc->sc_intrtab[i].intr_type)
554 				continue;
555 			/*
556 			 * If the IRQ is sharable, count the number of
557 			 * other handlers, and if it's smaller than the
558 			 * last IRQ like this, remember it.
559 			 */
560 			tmp = 0;
561 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
562 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
563 				tmp++;
564 			if (bestirq == -1 || count > tmp) {
565 				bestirq = i;
566 				count = tmp;
567 			}
568 			break;
569 
570 		case IST_PULSE:
571 			/* This just isn't sharable. */
572 			continue;
573 		}
574 	}
575 
576 	if (bestirq == -1)
577 		return (1);
578 
579 	*irq = bestirq;
580 	return (0);
581 }
582