1 /*        $NetBSD: algor_p4032_intr.c,v 1.27 2020/11/14 02:23:04 thorpej Exp $  */
2 
3 /*-
4  * Copyright (c) 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 /*
33  * Platform-specific interrupt support for the Algorithmics P-4032.
34  *
35  * The Algorithmics P-4032 has an interrupt controller that is pretty
36  * flexible -- it can take an interrupt source and route it to an
37  * arbitrary MIPS CPU hardware interrupt pin.
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: algor_p4032_intr.c,v 1.27 2020/11/14 02:23:04 thorpej Exp $");
42 
43 #include "opt_ddb.h"
44 #define   __INTR_PRIVATE
45 
46 #include <sys/param.h>
47 #include <sys/bus.h>
48 #include <sys/cpu.h>
49 #include <sys/device.h>
50 #include <sys/intr.h>
51 #include <sys/kernel.h>
52 #include <sys/kmem.h>
53 #include <sys/queue.h>
54 #include <sys/systm.h>
55 
56 #include <algor/autoconf.h>
57 
58 #include <mips/locore.h>
59 
60 #include <dev/ic/mc146818reg.h>
61 
62 #include <algor/algor/algor_p4032reg.h>
63 #include <algor/algor/algor_p4032var.h>
64 
65 #include <dev/pci/pcireg.h>
66 #include <dev/pci/pcivar.h>
67 
68 #define   REGVAL(x) *((volatile u_int32_t *)(MIPS_PHYS_TO_KSEG1((x))))
69 
70 struct p4032_irqreg {
71           bus_addr_t          addr;
72           u_int32_t val;
73 };
74 
75 #define   IRQREG_8BIT                   0
76 #define   IRQREG_ERROR                  1
77 #define   IRQREG_PCI                    2
78 #define   NIRQREG                       3
79 
80 struct p4032_irqreg p4032_irqregs[NIRQREG] = {
81           { P4032_IRR0,                 0 },
82           { P4032_IRR1,                 0 },
83           { P4032_IRR2,                 0 },
84 };
85 
86 #define   NSTEERREG           3
87 
88 struct p4032_irqreg p4032_irqsteer[NSTEERREG] = {
89           { P4032_XBAR0,                0 },
90           { P4032_XBAR1,                0 },
91           { P4032_XBAR2,                0 },
92 };
93 
94 #define   NPCIIRQS            4
95 
96 /* See algor_p4032var.h */
97 #define   N8BITIRQS           8
98 
99 #define   IRQMAP_PCIBASE                0
100 #define   IRQMAP_8BITBASE               NPCIIRQS
101 #define   NIRQMAPS            (IRQMAP_8BITBASE + N8BITIRQS)
102 
103 const char * const p4032_intrnames[NIRQMAPS] = {
104           /*
105            * PCI INTERRUPTS
106            */
107           "PCIIRQ 0",
108           "PCIIRQ 1",
109           "PCIIRQ 2",
110           "PCIIRQ 3",
111 
112           /*
113            * 8-BIT DEVICE INTERRUPTS
114            */
115           "PCI ctlr",
116           "floppy",
117           "pckbc",
118           "com 1",
119           "com 2",
120           "centronics",
121           "gpio",
122           "mcclock",
123 };
124 
125 struct p4032_irqmap {
126           int       irqidx;
127           int       cpuintr;
128           int       irqreg;
129           int       irqbit;
130           int       xbarreg;
131           int       xbarshift;
132 };
133 
134 const struct p4032_irqmap p4032_irqmap[NIRQMAPS] = {
135           /*
136            * PCI INTERRUPTS
137            */
138           /* PCIIRQ 0 */
139           { 0,                          0,
140             IRQREG_PCI,                 IRR2_PCIIRQ0,
141             2,                          0 },
142 
143           /* PCIIRQ 1 */
144           { 1,                          0,
145             IRQREG_PCI,                 IRR2_PCIIRQ1,
146             2,                          2 },
147 
148           /* PCIIRQ 2 */
149           { 2,                          0,
150             IRQREG_PCI,                 IRR2_PCIIRQ2,
151             2,                          4 },
152 
153           /* PCIIRQ 3 */
154           { 3,                          0,
155             IRQREG_PCI,                 IRR2_PCIIRQ3,
156             2,                          6 },
157 
158           /*
159            * 8-BIT DEVICE INTERRUPTS
160            */
161           { P4032_IRQ_PCICTLR,          1,
162             IRQREG_8BIT,                IRR0_PCICTLR,
163             0,                          0 },
164 
165           { P4032_IRQ_FLOPPY, 1,
166             IRQREG_8BIT,                IRR0_FLOPPY,
167             0,                          2 },
168 
169           { P4032_IRQ_PCKBC,  1,
170             IRQREG_8BIT,                IRR0_PCKBC,
171             0,                          4 },
172 
173           { P4032_IRQ_COM1,   1,
174             IRQREG_8BIT,                IRR0_COM1,
175             0,                          6 },
176 
177           { P4032_IRQ_COM2,   1,
178             IRQREG_8BIT,                IRR0_COM2,
179             1,                          0 },
180 
181           { P4032_IRQ_LPT,    1,
182             IRQREG_8BIT,                IRR0_LPT,
183             1,                          2 },
184 
185           { P4032_IRQ_GPIO,   1,
186             IRQREG_8BIT,                IRR0_GPIO,
187             1,                          4 },
188 
189           { P4032_IRQ_RTC,    1,
190             IRQREG_8BIT,                IRR0_RTC,
191             1,                          6 },
192 };
193 
194 struct p4032_intrhead {
195           struct evcnt intr_count;
196           int intr_refcnt;
197 };
198 struct p4032_intrhead p4032_intrtab[NIRQMAPS];
199 
200 #define   NINTRS                        2         /* MIPS INT0 - INT1 */
201 
202 
203 struct p4032_cpuintr {
204           LIST_HEAD(, evbmips_intrhand) cintr_list;
205           struct evcnt cintr_count;
206 };
207 
208 struct p4032_cpuintr p4032_cpuintrs[NINTRS];
209 const char * const p4032_cpuintrnames[NINTRS] = {
210           "int 0 (pci)",
211           "int 1 (8-bit)",
212 };
213 
214 const char * const p4032_intrgroups[NINTRS] = {
215           "pci",
216           "8-bit",
217 };
218 
219 void      *algor_p4032_intr_establish(int, int (*)(void *), void *);
220 void      algor_p4032_intr_disestablish(void *);
221 
222 int       algor_p4032_pci_intr_map(const struct pci_attach_args *,
223               pci_intr_handle_t *);
224 const char *algor_p4032_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
225 const struct evcnt *algor_p4032_pci_intr_evcnt(void *, pci_intr_handle_t);
226 void      *algor_p4032_pci_intr_establish(void *, pci_intr_handle_t, int,
227               int (*)(void *), void *);
228 void      algor_p4032_pci_intr_disestablish(void *, void *);
229 void      algor_p4032_pci_conf_interrupt(void *, int, int, int, int, int *);
230 
231 void      algor_p4032_iointr(int, vaddr_t, uint32_t);
232 
233 void
algor_p4032_intr_init(struct p4032_config * acp)234 algor_p4032_intr_init(struct p4032_config *acp)
235 {
236           const struct p4032_irqmap *irqmap;
237           int i;
238 
239           for (i = 0; i < NIRQREG; i++)
240                     REGVAL(p4032_irqregs[i].addr) = p4032_irqregs[i].val;
241 
242           for (i = 0; i < NINTRS; i++) {
243                     LIST_INIT(&p4032_cpuintrs[i].cintr_list);
244                     evcnt_attach_dynamic(&p4032_cpuintrs[i].cintr_count,
245                         EVCNT_TYPE_INTR, NULL, "mips", p4032_cpuintrnames[i]);
246           }
247 
248           for (i = 0; i < NIRQMAPS; i++) {
249                     irqmap = &p4032_irqmap[i];
250 
251                     p4032_irqsteer[irqmap->xbarreg].val |=
252                         irqmap->cpuintr << irqmap->xbarshift;
253 
254                     evcnt_attach_dynamic(&p4032_intrtab[i].intr_count,
255                         EVCNT_TYPE_INTR, NULL, p4032_intrgroups[irqmap->cpuintr],
256                         p4032_intrnames[i]);
257           }
258 
259           for (i = 0; i < NSTEERREG; i++)
260                     REGVAL(p4032_irqsteer[i].addr) = p4032_irqsteer[i].val;
261 
262           acp->ac_pc.pc_intr_v = NULL;
263           acp->ac_pc.pc_intr_map = algor_p4032_pci_intr_map;
264           acp->ac_pc.pc_intr_string = algor_p4032_pci_intr_string;
265           acp->ac_pc.pc_intr_evcnt = algor_p4032_pci_intr_evcnt;
266           acp->ac_pc.pc_intr_establish = algor_p4032_pci_intr_establish;
267           acp->ac_pc.pc_intr_disestablish = algor_p4032_pci_intr_disestablish;
268           acp->ac_pc.pc_conf_interrupt = algor_p4032_pci_conf_interrupt;
269           acp->ac_pc.pc_pciide_compat_intr_establish = NULL;
270 
271           algor_intr_establish = algor_p4032_intr_establish;
272           algor_intr_disestablish = algor_p4032_intr_disestablish;
273           algor_iointr = algor_p4032_iointr;
274 }
275 
276 void
algor_p4032_cal_timer(bus_space_tag_t st,bus_space_handle_t sh)277 algor_p4032_cal_timer(bus_space_tag_t st, bus_space_handle_t sh)
278 {
279           u_long ctrdiff[4], startctr, endctr, cps;
280           u_int32_t irr;
281           int i;
282 
283           /* Disable interrupts first. */
284           bus_space_write_1(st, sh, 0, MC_REGB);
285           bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
286               MC_REGB_24HR);
287 
288           /* Initialize for 16Hz. */
289           bus_space_write_1(st, sh, 0, MC_REGA);
290           bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz);
291 
292           REGVAL(P4032_IRR0) = IRR0_RTC;
293 
294           /* Run the loop an extra time to prime the cache. */
295           for (i = 0; i < 4; i++) {
296                     led_display('h', 'z', '0' + i, ' ');
297 
298                     /* Enable the interrupt. */
299                     bus_space_write_1(st, sh, 0, MC_REGB);
300                     bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE |
301                         MC_REGB_BINARY | MC_REGB_24HR);
302 
303                     /* Wait for it to happen. */
304                     startctr = mips3_cp0_count_read();
305                     do {
306                               irr = REGVAL(P4032_IRR0);
307                               endctr = mips3_cp0_count_read();
308                     } while ((irr & IRR0_RTC) == 0);
309 
310                     /* ACK. */
311                     bus_space_write_1(st, sh, 0, MC_REGC);
312                     (void) bus_space_read_1(st, sh, 1);
313 
314                     /* Disable. */
315                     bus_space_write_1(st, sh, 0, MC_REGB);
316                     bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
317                         MC_REGB_24HR);
318 
319                     ctrdiff[i] = endctr - startctr;
320           }
321 
322           REGVAL(P4032_IRR0) = 0;
323 
324           /* Update CPU frequency values */
325           cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
326           /* XXX mips_cpu_flags isn't set here; assume CPU_MIPS_DOUBLE_COUNT */
327           curcpu()->ci_cpu_freq = cps * 2;
328           curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
329           curcpu()->ci_divisor_delay =
330               ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000);
331           /* XXX assume CPU_MIPS_DOUBLE_COUNT */
332           curcpu()->ci_cycles_per_hz /= 2;
333           curcpu()->ci_divisor_delay /= 2;
334 
335           printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n",
336               cps, ctrdiff[2], ctrdiff[3]);
337           printf("CPU clock speed = %lu.%02luMHz "
338               "(hz cycles = %lu, delay divisor = %lu)\n",
339               curcpu()->ci_cpu_freq / 1000000,
340               (curcpu()->ci_cpu_freq % 1000000) / 10000,
341               curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay);
342 }
343 
344 void *
algor_p4032_intr_establish(int irq,int (* func)(void *),void * arg)345 algor_p4032_intr_establish(int irq, int (*func)(void *), void *arg)
346 {
347           const struct p4032_irqmap *irqmap;
348           struct evbmips_intrhand *ih;
349           int s;
350 
351           irqmap = &p4032_irqmap[irq];
352 
353           KASSERT(irq == irqmap->irqidx);
354 
355           ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
356           ih->ih_func = func;
357           ih->ih_arg = arg;
358           ih->ih_irq = 0;
359           ih->ih_irqmap = irqmap;
360 
361           s = splhigh();
362 
363           /*
364            * First, link it into the tables.
365            */
366           LIST_INSERT_HEAD(&p4032_cpuintrs[irqmap->cpuintr].cintr_list,
367               ih, ih_q);
368 
369           /*
370            * Now enable it.
371            */
372           if (p4032_intrtab[irqmap->irqidx].intr_refcnt++ == 0) {
373                     p4032_irqregs[irqmap->irqreg].val |= irqmap->irqbit;
374                     REGVAL(p4032_irqregs[irqmap->irqreg].addr) =
375                         p4032_irqregs[irqmap->irqreg].val;
376           }
377 
378           splx(s);
379 
380           return (ih);
381 }
382 
383 void
algor_p4032_intr_disestablish(void * cookie)384 algor_p4032_intr_disestablish(void *cookie)
385 {
386           const struct p4032_irqmap *irqmap;
387           struct evbmips_intrhand *ih = cookie;
388           int s;
389 
390           irqmap = ih->ih_irqmap;
391 
392           s = splhigh();
393 
394           /*
395            * First, remove it from the table.
396            */
397           LIST_REMOVE(ih, ih_q);
398 
399           /*
400            * Now, disable it, if there is nothing remaining on the
401            * list.
402            */
403           if (p4032_intrtab[irqmap->irqidx].intr_refcnt-- == 1) {
404                     p4032_irqregs[irqmap->irqreg].val &= ~irqmap->irqbit;
405                     REGVAL(p4032_irqregs[irqmap->irqreg].addr) =
406                         p4032_irqregs[irqmap->irqreg].val;
407           }
408 
409           splx(s);
410 
411           kmem_free(ih, sizeof(*ih));
412 }
413 
414 void
algor_p4032_iointr(int ipl,vaddr_t pc,u_int32_t ipending)415 algor_p4032_iointr(int ipl, vaddr_t pc, u_int32_t ipending)
416 {
417           const struct p4032_irqmap *irqmap;
418           struct evbmips_intrhand *ih;
419           int level, i;
420           u_int32_t irr[NIRQREG];
421 
422           /* Check for ERROR interrupts. */
423           if (ipending & MIPS_INT_MASK_4) {
424                     irr[IRQREG_ERROR] = REGVAL(p4032_irqregs[IRQREG_ERROR].addr);
425                     if (irr[IRQREG_ERROR] & IRR1_BUSERR)
426                               printf("WARNING: Bus error\n");
427                     if (irr[IRQREG_ERROR] & IRR1_POWERFAIL)
428                               printf("WARNING: Power failure\n");
429                     if (irr[IRQREG_ERROR] & IRR1_DEBUG) {
430 #ifdef DDB
431                               printf("Debug switch -- entering debugger\n");
432                               led_display('D','D','B',' ');
433                               Debugger();
434                               led_display('N','B','S','D');
435 #else
436                               printf("Debug switch ignored -- "
437                                   "no debugger configured\n");
438 #endif
439                     }
440 
441                     /* Clear them. */
442                     REGVAL(p4032_irqregs[IRQREG_ERROR].addr) = irr[IRQREG_ERROR];
443           }
444 
445           /* Do floppy DMA request interrupts. */
446           if (ipending & MIPS_INT_MASK_3) {
447                     /*
448                      * XXX Hi, um, yah, we need to deal with
449                      * XXX the floppy interrupt here.
450                      */
451 
452           }
453 
454           /*
455            * Read the interrupt pending registers, mask them with the
456            * ones we have enabled, and service them in order of decreasing
457            * priority.
458            */
459           for (i = 0; i < NIRQREG; i++) {
460                     if (i == IRQREG_ERROR)
461                               continue;
462                     irr[i] = REGVAL(p4032_irqregs[i].addr) & p4032_irqregs[i].val;
463           }
464 
465           for (level = (NINTRS - 1); level >= 0; level--) {
466                     if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
467                               continue;
468                     p4032_cpuintrs[level].cintr_count.ev_count++;
469                     for (ih = LIST_FIRST(&p4032_cpuintrs[level].cintr_list);
470                          ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
471                               irqmap = ih->ih_irqmap;
472                               if (irr[irqmap->irqreg] & irqmap->irqbit) {
473                                         p4032_intrtab[
474                                             irqmap->irqidx].intr_count.ev_count++;
475                                         (*ih->ih_func)(ih->ih_arg);
476                               }
477                     }
478           }
479 }
480 
481 /*****************************************************************************
482  * PCI interrupt support
483  *****************************************************************************/
484 
485 int
algor_p4032_pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)486 algor_p4032_pci_intr_map(const struct pci_attach_args *pa,
487     pci_intr_handle_t *ihp)
488 {
489           static const int pciirqmap[6/*device*/][4/*pin*/] = {
490                     { 1, -1, -1, -1 },            /* 5: Ethernet */
491                     { 2, 3, 0, 1 },                         /* 6: PCI slot 1 */
492                     { 3, 0, 1, 2 },                         /* 7: PCI slot 2 */
493                     { 0, -1, -1, -1 },            /* 8: SCSI */
494                     { -1, -1, -1, -1 },           /* 9: not used */
495                     { 0, 1, 2, 3 },                         /* 10: custom connector */
496           };
497           pcitag_t bustag = pa->pa_intrtag;
498           int buspin = pa->pa_intrpin;
499           pci_chipset_tag_t pc = pa->pa_pc;
500           int device, irq;
501 
502           if (buspin == 0) {
503                     /* No IRQ used. */
504                     return (1);
505           }
506 
507           if (buspin > 4) {
508                     printf("algor_p4032_pci_intr_map: bad interrupt pin %d\n",
509                         buspin);
510                     return (1);
511           }
512 
513           pci_decompose_tag(pc, bustag, NULL, &device, NULL);
514           if (device < 5 || device > 10) {
515                     printf("algor_p4032_pci_intr_map: bad device %d\n",
516                         device);
517                     return (1);
518           }
519 
520           irq = pciirqmap[device - 5][buspin - 1];
521           if (irq == -1) {
522                     printf("algor_p4032_pci_intr_map: no mapping for "
523                         "device %d pin %d\n", device, buspin);
524                     return (1);
525           }
526 
527           *ihp = irq;
528           return (0);
529 }
530 
531 const char *
algor_p4032_pci_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)532 algor_p4032_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
533 {
534 
535           if (ih >= NPCIIRQS)
536                     panic("algor_p4032_intr_string: bogus IRQ %ld", ih);
537 
538           strlcpy(buf, p4032_intrnames[ih], len);
539           return buf;
540 }
541 
542 const struct evcnt *
algor_p4032_pci_intr_evcnt(void * v,pci_intr_handle_t ih)543 algor_p4032_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
544 {
545 
546           return (&p4032_intrtab[ih].intr_count);
547 }
548 
549 void *
algor_p4032_pci_intr_establish(void * v,pci_intr_handle_t ih,int level,int (* func)(void *),void * arg)550 algor_p4032_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
551     int (*func)(void *), void *arg)
552 {
553 
554           if (ih >= NPCIIRQS)
555                     panic("algor_p4032_intr_establish: bogus IRQ %ld", ih);
556 
557           return (algor_p4032_intr_establish(ih, func, arg));
558 }
559 
560 void
algor_p4032_pci_intr_disestablish(void * v,void * cookie)561 algor_p4032_pci_intr_disestablish(void *v, void *cookie)
562 {
563 
564           return (algor_p4032_intr_disestablish(cookie));
565 }
566 
567 void
algor_p4032_pci_conf_interrupt(void * v,int bus,int dev,int pin,int swiz,int * iline)568 algor_p4032_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
569     int *iline)
570 {
571 
572           /*
573            * We actually don't need to do anything; everything is handled
574            * in pci_intr_map().
575            */
576           *iline = 0;
577 }
578