1 /* $NetBSD: pcib.c,v 1.29 2024/02/08 20:11:55 andvar 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.29 2024/02/08 20:11:55 andvar 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/kmem.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
pcib_match(device_t parent,cfdata_t match,void * aux)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
pcib_attach(device_t parent,device_t self,void * aux)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
pcib_bridge_callback(device_t self)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 config_found(sc->sc_dev, &iba, isabusprint, CFARGS_NONE);
321 }
322
323 void
pcib_isa_attach_hook(device_t parent,device_t self,struct isabus_attach_args * iba)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
pcib_isa_detach_hook(isa_chipset_tag_t ic,device_t self)332 pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self)
333 {
334
335 /* Nothing to do. */
336 }
337
338 void
pcib_set_icus(struct pcib_softc * sc)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
pcib_intr(void * v)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 *
pcib_isa_intr_evcnt(void * v,int irq)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 *
pcib_isa_intr_establish(void * v,int irq,int type,int level,int (* func)(void *),void * arg)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 = kmem_alloc(sizeof(*ih), KM_SLEEP);
453 ih->ih_func = func;
454 ih->ih_arg = arg;
455 ih->ih_irq = irq;
456 ih->ih_irqmap = NULL;
457
458 s = splhigh();
459
460 /* Insert the handler into the table. */
461 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q);
462 sc->sc_intrtab[irq].intr_type = type;
463
464 /* Enable it, set trigger mode. */
465 sc->sc_imask &= ~(1 << irq);
466 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL)
467 sc->sc_elcr |= (1 << irq);
468 else
469 sc->sc_elcr &= ~(1 << irq);
470
471 pcib_set_icus(sc);
472
473 splx(s);
474
475 return (ih);
476 }
477
478 void
pcib_isa_intr_disestablish(void * v,void * arg)479 pcib_isa_intr_disestablish(void *v, void *arg)
480 {
481 struct pcib_softc *sc = v;
482 struct evbmips_intrhand *ih = arg;
483 int s;
484
485 #if defined(ALGOR_P5064)
486 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) {
487 isa_intr_disestablish(sc->sc_parent_ic, ih);
488 return;
489 }
490 #endif
491
492 s = splhigh();
493
494 LIST_REMOVE(ih, ih_q);
495
496 /* If there are no more handlers on this IRQ, disable it. */
497 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) {
498 sc->sc_imask |= (1 << ih->ih_irq);
499 pcib_set_icus(sc);
500 }
501
502 splx(s);
503
504 kmem_free(ih, sizeof(*ih));
505 }
506
507 int
pcib_isa_intr_alloc(void * v,int mask,int type,int * irq)508 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq)
509 {
510 struct pcib_softc *sc = v;
511 int i, tmp, bestirq, count;
512 struct evbmips_intrhand *ih;
513
514 if (type == IST_NONE)
515 panic("pcib_intr_alloc: bogus type");
516
517 bestirq = -1;
518 count = -1;
519
520 mask &= ~sc->sc_reserved;
521
522 #if 0
523 printf("pcib_intr_alloc: mask = 0x%04x\n", mask);
524 #endif
525
526 for (i = 0; i < 16; i++) {
527 if ((mask & (1 << i)) == 0)
528 continue;
529
530 switch (sc->sc_intrtab[i].intr_type) {
531 case IST_NONE:
532 /*
533 * If nothing's using the IRQ, just return it.
534 */
535 *irq = i;
536 return (0);
537
538 case IST_EDGE:
539 case IST_LEVEL:
540 if (type != sc->sc_intrtab[i].intr_type)
541 continue;
542 /*
543 * If the IRQ is shareable, count the number of
544 * other handlers, and if it's smaller than the
545 * last IRQ like this, remember it.
546 */
547 tmp = 0;
548 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q);
549 ih != NULL; ih = LIST_NEXT(ih, ih_q))
550 tmp++;
551 if (bestirq == -1 || count > tmp) {
552 bestirq = i;
553 count = tmp;
554 }
555 break;
556
557 case IST_PULSE:
558 /* This just isn't shareable. */
559 continue;
560 }
561 }
562
563 if (bestirq == -1)
564 return (1);
565
566 *irq = bestirq;
567 return (0);
568 }
569