xref: /netbsd-src/sys/arch/algor/pci/pcib.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: pcib.c,v 1.21 2009/08/19 15:17:00 dyoung 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  *
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.
30  */
31 
32 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.21 2009/08/19 15:17:00 dyoung Exp $");
35 
36 #include "opt_algor_p5064.h"
37 #include "opt_algor_p6032.h"
38 
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>
44 
45 #include <machine/intr.h>
46 #include <machine/bus.h>
47 
48 #include <dev/isa/isareg.h>
49 #include <dev/isa/isavar.h>
50 
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 #include <dev/pci/pcidevs.h>
54 
55 #include <dev/ic/i8259reg.h>
56 
57 #ifdef ALGOR_P5064
58 #include <algor/algor/algor_p5064var.h>
59 #endif
60 
61 #ifdef ALGOR_P6032
62 #include <algor/algor/algor_p6032var.h>
63 #endif
64 
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",
82 };
83 
84 struct pcib_intrhead {
85 	LIST_HEAD(, algor_intrhand) intr_q;
86 	struct evcnt intr_count;
87 	int intr_type;
88 };
89 
90 struct pcib_softc {
91 	struct device	sc_dev;
92 
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;
97 
98 	struct algor_isa_chipset sc_ic;
99 
100 	struct pcib_intrhead sc_intrtab[16];
101 
102 	u_int16_t	sc_imask;
103 	u_int16_t	sc_elcr;
104 
105 #if defined(ALGOR_P5064)
106 	isa_chipset_tag_t sc_parent_ic;
107 #endif
108 
109 	u_int16_t	sc_reserved;
110 
111 	void		*sc_ih;
112 };
113 
114 int	pcib_match(struct device *, struct cfdata *, void *);
115 void	pcib_attach(struct device *, struct device *, void *);
116 
117 CFATTACH_DECL(pcib, sizeof(struct pcib_softc),
118     pcib_match, pcib_attach, NULL, NULL);
119 
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);
123 
124 int	pcib_intr(void *);
125 
126 void	pcib_bridge_callback(struct device *);
127 
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 *);
133 
134 void	pcib_set_icus(struct pcib_softc *);
135 
136 int
137 pcib_match(struct device *parent, struct cfdata *match, void *aux)
138 {
139 	struct pci_attach_args *pa = aux;
140 
141 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
142 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA)
143 		return (1);
144 
145 	return (0);
146 }
147 
148 void
149 pcib_attach(struct device *parent, struct device *self, void *aux)
150 {
151 	struct pcib_softc *sc = (void *) self;
152 	struct pci_attach_args *pa = aux;
153 	char devinfo[256];
154 	int i;
155 
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));
159 
160 	sc->sc_iot = pa->pa_iot;
161 
162 	/*
163 	 * Map the PIC/ELCR registers.
164 	 */
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);
174 
175 	/* All interrupts default to "masked off". */
176 	sc->sc_imask = 0xffff;
177 
178 	/* All interrupts default to edge-triggered. */
179 	sc->sc_elcr = 0;
180 
181 	/*
182 	 * Initialize the 8259s.
183 	 */
184 
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);
194 
195 	/* mask all interrupts */
196 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
197 	    sc->sc_imask & 0xff);
198 
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);
202 
203 	/* read IRR by default */
204 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
205 	    OCW3_SELECT | OCW3_RR);
206 
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);
216 
217 	/* mask all interrupts */
218 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
219 	    (sc->sc_imask >> 8) & 0xff);
220 
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);
224 
225 	/* read IRR by default */
226 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
227 	    OCW3_SELECT | OCW3_RR);
228 
229 	/*
230 	 * Default all interrupts to edge-triggered.
231 	 */
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);
236 
237 	/*
238 	 * Some ISA interrupts are reserved for devices that
239 	 * we know are hard-wired to certain IRQs.
240 	 */
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 */
253 
254 #if defined(ALGOR_P5064)
255 	/*
256 	 * Some "ISA" interrupts are a little wacky, wired up directly
257 	 * to the P-5064 interrupt controller.
258 	 */
259 	sc->sc_parent_ic = &p5064_configuration.ac_ic;
260 #endif /* ALGOR_P5064 */
261 
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;
268 
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;
275 	}
276 
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);
288 
289 	config_defer(self, pcib_bridge_callback);
290 }
291 
292 void
293 pcib_bridge_callback(struct device *self)
294 {
295 	struct pcib_softc *sc = (struct pcib_softc *)self;
296 	struct isabus_attach_args iba;
297 
298 	memset(&iba, 0, sizeof(iba));
299 
300 #if defined(ALGOR_P5064)
301 	    {
302 		struct p5064_config *acp = &p5064_configuration;
303 
304 		iba.iba_iot = &acp->ac_iot;
305 		iba.iba_memt = &acp->ac_memt;
306 		iba.iba_dmat = &acp->ac_isa_dmat;
307 	    }
308 #elif defined(ALGOR_P6032)
309 	    {
310 		struct p6032_config *acp = &p6032_configuration;
311 
312 		iba.iba_iot = &acp->ac_iot;
313 		iba.iba_memt = &acp->ac_memt;
314 		iba.iba_dmat = &acp->ac_isa_dmat;
315 	    }
316 #endif
317 
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;
321 
322 	(void) config_found_ia(&sc->sc_dev, "isabus", &iba, isabusprint);
323 }
324 
325 void
326 pcib_isa_attach_hook(struct device *parent, struct device *self,
327     struct isabus_attach_args *iba)
328 {
329 
330 	/* Nothing to do. */
331 }
332 
333 void
334 pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self)
335 {
336 
337 	/* Nothing to do. */
338 }
339 
340 void
341 pcib_set_icus(struct pcib_softc *sc)
342 {
343 
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);
349 
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);
354 
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);
359 }
360 
361 int
362 pcib_intr(void *v)
363 {
364 	struct pcib_softc *sc = v;
365 	struct algor_intrhand *ih;
366 	int irq;
367 
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);
374 
375 		irq = OCW3_POLL_IRQ(irq);
376 
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;
386 		}
387 
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);
392 		}
393 
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;
400 		}
401 
402 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
403 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
404 	}
405 }
406 
407 const struct evcnt *
408 pcib_isa_intr_evcnt(void *v, int irq)
409 {
410 	struct pcib_softc *sc = v;
411 
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
416 
417 	return (&sc->sc_intrtab[irq].intr_count);
418 }
419 
420 void *
421 pcib_isa_intr_establish(void *v, int irq, int type, int level,
422     int (*func)(void *), void *arg)
423 {
424 	struct pcib_softc *sc = v;
425 	struct algor_intrhand *ih;
426 	int s;
427 
428 	if (irq > 15 || irq == 2 || type == IST_NONE)
429 		panic("pcib_isa_intr_establish: bad irq or type");
430 
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
436 
437 	switch (sc->sc_intrtab[irq].intr_type) {
438 	case IST_NONE:
439 		sc->sc_intrtab[irq].intr_type = type;
440 		break;
441 
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:
448 		/*
449 		 * We can't share interrupts in this case.
450 		 */
451 		return (NULL);
452 	}
453 
454 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
455 	if (ih == NULL)
456 		return (NULL);
457 
458 	ih->ih_func = func;
459 	ih->ih_arg = arg;
460 	ih->ih_irq = irq;
461 	ih->ih_irqmap = NULL;
462 
463 	s = splhigh();
464 
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;
468 
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);
475 
476 	pcib_set_icus(sc);
477 
478 	splx(s);
479 
480 	return (ih);
481 }
482 
483 void
484 pcib_isa_intr_disestablish(void *v, void *arg)
485 {
486 	struct pcib_softc *sc = v;
487 	struct algor_intrhand *ih = arg;
488 	int s;
489 
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;
494 	}
495 #endif
496 
497 	s = splhigh();
498 
499 	LIST_REMOVE(ih, ih_q);
500 
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);
505 	}
506 
507 	splx(s);
508 
509 	free(ih, M_DEVBUF);
510 }
511 
512 int
513 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
514 {
515 	struct pcib_softc *sc = v;
516 	int i, tmp, bestirq, count;
517 	struct algor_intrhand *ih;
518 
519 	if (type == IST_NONE)
520 		panic("pcib_intr_alloc: bogus type");
521 
522 	bestirq = -1;
523 	count = -1;
524 
525 	mask &= ~sc->sc_reserved;
526 
527 #if 0
528 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
529 #endif
530 
531 	for (i = 0; i < 16; i++) {
532 		if ((mask & (1 << i)) == 0)
533 			continue;
534 
535 		switch (sc->sc_intrtab[i].intr_type) {
536 		case IST_NONE:
537 			/*
538 			 * If nothing's using the IRQ, just return it.
539 			 */
540 			*irq = i;
541 			return (0);
542 
543 		case IST_EDGE:
544 		case IST_LEVEL:
545 			if (type != sc->sc_intrtab[i].intr_type)
546 				continue;
547 			/*
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.
551 			 */
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;
559 			}
560 			break;
561 
562 		case IST_PULSE:
563 			/* This just isn't sharable. */
564 			continue;
565 		}
566 	}
567 
568 	if (bestirq == -1)
569 		return (1);
570 
571 	*irq = bestirq;
572 	return (0);
573 }
574