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