xref: /netbsd-src/sys/arch/algor/pci/pcib.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: pcib.c,v 1.24 2011/07/09 16:03:01 matt 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.24 2011/07/09 16:03:01 matt Exp $");
35 
36 #include "opt_algor_p5064.h"
37 #include "opt_algor_p6032.h"
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/device.h>
42 #include <sys/intr.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/systm.h>
46 
47 #include <algor/autoconf.h>
48 
49 #include <dev/isa/isareg.h>
50 #include <dev/isa/isavar.h>
51 
52 #include <dev/pci/pcireg.h>
53 #include <dev/pci/pcivar.h>
54 #include <dev/pci/pcidevs.h>
55 
56 #include <dev/ic/i8259reg.h>
57 
58 #ifdef ALGOR_P5064
59 #include <algor/algor/algor_p5064var.h>
60 #endif
61 
62 #ifdef ALGOR_P6032
63 #include <algor/algor/algor_p6032var.h>
64 #endif
65 
66 const char * const pcib_intrnames[16] = {
67 	"irq 0",
68 	"irq 1",
69 	"irq 2",
70 	"irq 3",
71 	"irq 4",
72 	"irq 5",
73 	"irq 6",
74 	"irq 7",
75 	"irq 8",
76 	"irq 9",
77 	"irq 10",
78 	"irq 11",
79 	"irq 12",
80 	"irq 13",
81 	"irq 14",
82 	"irq 15",
83 };
84 
85 struct pcib_intrhead {
86 	LIST_HEAD(, evbmips_intrhand) intr_q;
87 	struct evcnt intr_count;
88 	int intr_type;
89 };
90 
91 struct pcib_softc {
92 	device_t	sc_dev;
93 
94 	bus_space_tag_t	sc_iot;
95 	bus_space_handle_t sc_ioh_icu1;
96 	bus_space_handle_t sc_ioh_icu2;
97 	bus_space_handle_t sc_ioh_elcr;
98 
99 	struct mips_isa_chipset sc_ic;
100 
101 	struct pcib_intrhead sc_intrtab[16];
102 
103 	u_int16_t	sc_imask;
104 	u_int16_t	sc_elcr;
105 
106 #if defined(ALGOR_P5064)
107 	isa_chipset_tag_t sc_parent_ic;
108 #endif
109 
110 	u_int16_t	sc_reserved;
111 
112 	void		*sc_ih;
113 };
114 
115 int	pcib_match(device_t, cfdata_t, void *);
116 void	pcib_attach(device_t, device_t, void *);
117 
118 CFATTACH_DECL_NEW(pcib, sizeof(struct pcib_softc),
119     pcib_match, pcib_attach, NULL, NULL);
120 
121 void	pcib_isa_attach_hook(device_t, device_t, 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(device_t);
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(device_t parent, cfdata_t 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(device_t parent, device_t self, void *aux)
150 {
151 	struct pcib_softc *sc = device_private(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 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
158 	    PCI_REVISION(pa->pa_class));
159 
160 	sc->sc_dev = self;
161 	sc->sc_iot = pa->pa_iot;
162 
163 	/*
164 	 * Map the PIC/ELCR registers.
165 	 */
166 	if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
167 		aprint_error_dev(self, "unable to map ELCR registers\n");
168 	if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
169 		aprint_error_dev(self, "unable to map ICU1 registers\n");
170 	if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
171 		aprint_error_dev(self, "unable to map ICU2 registers\n");
172 
173 	/* All interrupts default to "masked off". */
174 	sc->sc_imask = 0xffff;
175 
176 	/* All interrupts default to edge-triggered. */
177 	sc->sc_elcr = 0;
178 
179 	/*
180 	 * Initialize the 8259s.
181 	 */
182 
183 	/* reset, program device, 4 bytes */
184 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1,
185 	    ICW1_SELECT | ICW1_IC4);
186 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2,
187 	    ICW2_VECTOR(0)/*XXX*/);
188 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3,
189 	    ICW3_CASCADE(2));
190 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4,
191 	    ICW4_8086);
192 
193 	/* mask all interrupts */
194 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
195 	    sc->sc_imask & 0xff);
196 
197 	/* enable special mask mode */
198 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
199 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
200 
201 	/* read IRR by default */
202 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
203 	    OCW3_SELECT | OCW3_RR);
204 
205 	/* reset; program device, 4 bytes */
206 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1,
207 	    ICW1_SELECT | ICW1_IC4);
208 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2,
209 	    ICW2_VECTOR(0)/*XXX*/);
210 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3,
211 	    ICW3_SIC(2));
212 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4,
213 	    ICW4_8086);
214 
215 	/* mask all interrupts */
216 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
217 	    (sc->sc_imask >> 8) & 0xff);
218 
219 	/* enable special mask mode */
220 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
221 	    OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
222 
223 	/* read IRR by default */
224 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3,
225 	    OCW3_SELECT | OCW3_RR);
226 
227 	/*
228 	 * Default all interrupts to edge-triggered.
229 	 */
230 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
231 	    sc->sc_elcr & 0xff);
232 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
233 	    (sc->sc_elcr >> 8) & 0xff);
234 
235 	/*
236 	 * Some ISA interrupts are reserved for devices that
237 	 * we know are hard-wired to certain IRQs.
238 	 */
239 	sc->sc_reserved =
240 		(1U << 0) |	/* timer */
241 		(1U << 1) |	/* keyboard controller */
242 		(1U << 2) |	/* PIC cascade */
243 		(1U << 3) |	/* COM 2 */
244 		(1U << 4) |	/* COM 1 */
245 		(1U << 6) |	/* floppy */
246 		(1U << 7) |	/* centronics */
247 		(1U << 8) |	/* RTC */
248 		(1U << 12) |	/* keyboard controller */
249 		(1U << 14) |	/* IDE 0 */
250 		(1U << 15);	/* IDE 1 */
251 
252 #if defined(ALGOR_P5064)
253 	/*
254 	 * Some "ISA" interrupts are a little wacky, wired up directly
255 	 * to the P-5064 interrupt controller.
256 	 */
257 	sc->sc_parent_ic = &p5064_configuration.ac_ic;
258 #endif /* ALGOR_P5064 */
259 
260 	/* Set up our ISA chipset. */
261 	sc->sc_ic.ic_v = sc;
262 	sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt;
263 	sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish;
264 	sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish;
265 	sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc;
266 
267 	/* Initialize our interrupt table. */
268 	for (i = 0; i < 16; i++) {
269 		LIST_INIT(&sc->sc_intrtab[i].intr_q);
270 		evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count,
271 		    EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]);
272 		sc->sc_intrtab[i].intr_type = IST_NONE;
273 	}
274 
275 	/* Hook up our interrupt handler. */
276 #if defined(ALGOR_P5064)
277 	sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE,
278 	    pcib_intr, sc);
279 #elif defined(ALGOR_P6032)
280 	sc->sc_ih = (*algor_intr_establish)(P6032_IRQ_ISABRIDGE,
281 	    pcib_intr, sc);
282 #endif
283 	if (sc->sc_ih == NULL)
284 		printf("%s: WARNING: unable to register interrupt handler\n",
285 		    device_xname(sc->sc_dev));
286 
287 	config_defer(self, pcib_bridge_callback);
288 }
289 
290 void
291 pcib_bridge_callback(device_t self)
292 {
293 	struct pcib_softc *sc = device_private(self);
294 	struct isabus_attach_args iba;
295 
296 	memset(&iba, 0, sizeof(iba));
297 
298 #if defined(ALGOR_P5064)
299 	    {
300 		struct p5064_config *acp = &p5064_configuration;
301 
302 		iba.iba_iot = &acp->ac_iot;
303 		iba.iba_memt = &acp->ac_memt;
304 		iba.iba_dmat = &acp->ac_isa_dmat;
305 	    }
306 #elif defined(ALGOR_P6032)
307 	    {
308 		struct p6032_config *acp = &p6032_configuration;
309 
310 		iba.iba_iot = &acp->ac_iot;
311 		iba.iba_memt = &acp->ac_memt;
312 		iba.iba_dmat = &acp->ac_isa_dmat;
313 	    }
314 #endif
315 
316 	iba.iba_ic = &sc->sc_ic;
317 	iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook;
318 	iba.iba_ic->ic_detach_hook = pcib_isa_detach_hook;
319 
320 	(void) config_found_ia(sc->sc_dev, "isabus", &iba, isabusprint);
321 }
322 
323 void
324 pcib_isa_attach_hook(device_t parent, device_t self,
325     struct isabus_attach_args *iba)
326 {
327 
328 	/* Nothing to do. */
329 }
330 
331 void
332 pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self)
333 {
334 
335 	/* Nothing to do. */
336 }
337 
338 void
339 pcib_set_icus(struct pcib_softc *sc)
340 {
341 
342 	/* Enable the cascade IRQ (2) if 8-15 is enabled. */
343 	if ((sc->sc_imask & 0xff00) != 0xff00)
344 		sc->sc_imask &= ~(1U << 2);
345 	else
346 		sc->sc_imask |= (1U << 2);
347 
348 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1,
349 	    sc->sc_imask & 0xff);
350 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1,
351 	    (sc->sc_imask >> 8) & 0xff);
352 
353 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0,
354 	    sc->sc_elcr & 0xff);
355 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1,
356 	    (sc->sc_elcr >> 8) & 0xff);
357 }
358 
359 int
360 pcib_intr(void *v)
361 {
362 	struct pcib_softc *sc = v;
363 	struct evbmips_intrhand *ih;
364 	int irq;
365 
366 	for (;;) {
367 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3,
368 		    OCW3_SELECT | OCW3_POLL);
369 		irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3);
370 		if ((irq & OCW3_POLL_PENDING) == 0)
371 			return (1);
372 
373 		irq = OCW3_POLL_IRQ(irq);
374 
375 		if (irq == 2) {
376 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
377 			    PIC_OCW3, OCW3_SELECT | OCW3_POLL);
378 			irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2,
379 			    PIC_OCW3);
380 			if (irq & OCW3_POLL_PENDING)
381 				irq = OCW3_POLL_IRQ(irq) + 8;
382 			else
383 				irq = 2;
384 		}
385 
386 		sc->sc_intrtab[irq].intr_count.ev_count++;
387 		for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q);
388 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
389 			(*ih->ih_func)(ih->ih_arg);
390 		}
391 
392 		/* Send a specific EOI to the 8259. */
393 		if (irq > 7) {
394 			bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2,
395 			    PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
396 			    OCW2_ILS(irq & 7));
397 			irq = 2;
398 		}
399 
400 		bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2,
401 		    OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
402 	}
403 }
404 
405 const struct evcnt *
406 pcib_isa_intr_evcnt(void *v, int irq)
407 {
408 	struct pcib_softc *sc = v;
409 
410 #if defined(ALGOR_P5064)
411 	if (p5064_isa_to_irqmap[irq] != -1)
412 		return (isa_intr_evcnt(sc->sc_parent_ic, irq));
413 #endif
414 
415 	return (&sc->sc_intrtab[irq].intr_count);
416 }
417 
418 void *
419 pcib_isa_intr_establish(void *v, int irq, int type, int level,
420     int (*func)(void *), void *arg)
421 {
422 	struct pcib_softc *sc = v;
423 	struct evbmips_intrhand *ih;
424 	int s;
425 
426 	if (irq > 15 || irq == 2 || type == IST_NONE)
427 		panic("pcib_isa_intr_establish: bad irq or type");
428 
429 #if defined(ALGOR_P5064)
430 	if (p5064_isa_to_irqmap[irq] != -1)
431 		return (isa_intr_establish(sc->sc_parent_ic, irq, type,
432 		    level, func, arg));
433 #endif
434 
435 	switch (sc->sc_intrtab[irq].intr_type) {
436 	case IST_NONE:
437 		sc->sc_intrtab[irq].intr_type = type;
438 		break;
439 
440 	case IST_EDGE:
441 	case IST_LEVEL:
442 		if (type == sc->sc_intrtab[irq].intr_type)
443 			break;
444 		/* FALLTHROUGH */
445 	case IST_PULSE:
446 		/*
447 		 * We can't share interrupts in this case.
448 		 */
449 		return (NULL);
450 	}
451 
452 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
453 	if (ih == NULL)
454 		return (NULL);
455 
456 	ih->ih_func = func;
457 	ih->ih_arg = arg;
458 	ih->ih_irq = irq;
459 	ih->ih_irqmap = NULL;
460 
461 	s = splhigh();
462 
463 	/* Insert the handler into the table. */
464 	LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
465 	sc->sc_intrtab[irq].intr_type = type;
466 
467 	/* Enable it, set trigger mode. */
468 	sc->sc_imask &= ~(1 << irq);
469 	if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
470 		sc->sc_elcr |= (1 << irq);
471 	else
472 		sc->sc_elcr &= ~(1 << irq);
473 
474 	pcib_set_icus(sc);
475 
476 	splx(s);
477 
478 	return (ih);
479 }
480 
481 void
482 pcib_isa_intr_disestablish(void *v, void *arg)
483 {
484 	struct pcib_softc *sc = v;
485 	struct evbmips_intrhand *ih = arg;
486 	int s;
487 
488 #if defined(ALGOR_P5064)
489 	if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
490 		isa_intr_disestablish(sc->sc_parent_ic, ih);
491 		return;
492 	}
493 #endif
494 
495 	s = splhigh();
496 
497 	LIST_REMOVE(ih, ih_q);
498 
499 	/* If there are no more handlers on this IRQ, disable it. */
500 	if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
501 		sc->sc_imask |= (1 << ih->ih_irq);
502 		pcib_set_icus(sc);
503 	}
504 
505 	splx(s);
506 
507 	free(ih, M_DEVBUF);
508 }
509 
510 int
511 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
512 {
513 	struct pcib_softc *sc = v;
514 	int i, tmp, bestirq, count;
515 	struct evbmips_intrhand *ih;
516 
517 	if (type == IST_NONE)
518 		panic("pcib_intr_alloc: bogus type");
519 
520 	bestirq = -1;
521 	count = -1;
522 
523 	mask &= ~sc->sc_reserved;
524 
525 #if 0
526 	printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
527 #endif
528 
529 	for (i = 0; i < 16; i++) {
530 		if ((mask & (1 << i)) == 0)
531 			continue;
532 
533 		switch (sc->sc_intrtab[i].intr_type) {
534 		case IST_NONE:
535 			/*
536 			 * If nothing's using the IRQ, just return it.
537 			 */
538 			*irq = i;
539 			return (0);
540 
541 		case IST_EDGE:
542 		case IST_LEVEL:
543 			if (type != sc->sc_intrtab[i].intr_type)
544 				continue;
545 			/*
546 			 * If the IRQ is sharable, count the number of
547 			 * other handlers, and if it's smaller than the
548 			 * last IRQ like this, remember it.
549 			 */
550 			tmp = 0;
551 			for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
552 			     ih != NULL; ih = LIST_NEXT(ih, ih_q))
553 				tmp++;
554 			if (bestirq == -1 || count > tmp) {
555 				bestirq = i;
556 				count = tmp;
557 			}
558 			break;
559 
560 		case IST_PULSE:
561 			/* This just isn't sharable. */
562 			continue;
563 		}
564 	}
565 
566 	if (bestirq == -1)
567 		return (1);
568 
569 	*irq = bestirq;
570 	return (0);
571 }
572