1 /* $NetBSD: algor_p6032_intr.c,v 1.24 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-6032.
34 *
35 * The Algorithmics P-6032's interrupts are wired to GPIO pins
36 * on the BONITO system controller.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: algor_p6032_intr.c,v 1.24 2020/11/14 02:23:04 thorpej Exp $");
41
42 #include "opt_ddb.h"
43 #define __INTR_PRIVATE
44
45 #include <sys/param.h>
46 #include <sys/bus.h>
47 #include <sys/cpu.h>
48 #include <sys/device.h>
49 #include <sys/intr.h>
50 #include <sys/kernel.h>
51 #include <sys/kmem.h>
52 #include <sys/queue.h>
53 #include <sys/systm.h>
54
55 #include <algor/autoconf.h>
56
57 #include <mips/locore.h>
58
59 #include <dev/ic/mc146818reg.h>
60
61 #include <algor/algor/algor_p6032reg.h>
62 #include <algor/algor/algor_p6032var.h>
63
64 #include <dev/pci/pcireg.h>
65 #include <dev/pci/pcivar.h>
66
67 #include <dev/isa/isavar.h>
68
69 /*
70 * The P-6032 interrupts are wired up in the following way:
71 *
72 * GPIN0 ISA_NMI (in)
73 * GPIN1 ISA_INTR (in)
74 * GPIN2 ETH_INT~ (in)
75 * GPIN3 BONIDE_INT (in)
76 *
77 * GPIN4 ISA IRQ3 (in, also on piix4)
78 * GPIN5 ISA IRQ4 (in, also on piix4)
79 *
80 * GPIO0 PIRQ A~ (in)
81 * GPIO1 PIRQ B~ (in)
82 * GPIO2 PIRQ C~ (in)
83 * GPIO3 PIRQ D~ (in)
84 */
85
86 #define NIRQMAPS 10
87
88 const char * const p6032_intrnames[NIRQMAPS] = {
89 "gpin 0",
90 "gpin 1",
91 "gpin 2",
92 "gpin 3",
93
94 "gpin 4",
95 "gpin 5",
96
97 "gpio 0",
98 "gpio 1",
99 "gpio 2",
100 "gpio 3",
101 };
102
103 struct p6032_irqmap {
104 int irqidx;
105 uint32_t intbit;
106 uint32_t gpioiebit;
107 int flags;
108 };
109
110 #define IRQ_F_INVERT 0x01 /* invert polarity */
111 #define IRQ_F_EDGE 0x02 /* edge trigger */
112 #define IRQ_F_INT1 0x04 /* INT1, else INT0 */
113
114 const struct p6032_irqmap p6032_irqmap[NIRQMAPS] = {
115 /* ISA NMI */
116 { P6032_IRQ_GPIN0, BONITO_ICU_GPIN(0),
117 BONITO_GPIO_INR(0), IRQ_F_INT1 },
118
119 /* ISA bridge */
120 { P6032_IRQ_GPIN1, BONITO_ICU_GPIN(1),
121 BONITO_GPIO_INR(1), IRQ_F_INT1 },
122
123 /* Ethernet */
124 { P6032_IRQ_GPIN2, BONITO_ICU_GPIN(2),
125 BONITO_GPIO_INR(2), IRQ_F_INVERT },
126
127 /* BONITO IDE */
128 { P6032_IRQ_GPIN3, BONITO_ICU_GPIN(3),
129 BONITO_GPIO_INR(3), 0 },
130
131 /* ISA IRQ3 */
132 { P6032_IRQ_GPIN4, BONITO_ICU_GPIN(4),
133 BONITO_GPIO_INR(4), IRQ_F_INT1 },
134
135 /* ISA IRQ4 */
136 { P6032_IRQ_GPIN5, BONITO_ICU_GPIN(5),
137 BONITO_GPIO_INR(5), IRQ_F_INT1 },
138
139 /* PIRQ A */
140 { P6032_IRQ_GPIO0, BONITO_ICU_GPIO(0),
141 BONITO_GPIO_IOW(0), IRQ_F_INVERT },
142
143 /* PIRQ B */
144 { P6032_IRQ_GPIO1, BONITO_ICU_GPIO(1),
145 BONITO_GPIO_IOW(1), IRQ_F_INVERT },
146
147 /* PIRQ C */
148 { P6032_IRQ_GPIO2, BONITO_ICU_GPIO(2),
149 BONITO_GPIO_IOW(2), IRQ_F_INVERT },
150
151 /* PIRQ D */
152 { P6032_IRQ_GPIO3, BONITO_ICU_GPIO(3),
153 BONITO_GPIO_IOW(3), IRQ_F_INVERT },
154 };
155
156 struct p6032_intrhead {
157 struct evcnt intr_count;
158 int intr_refcnt;
159 };
160 struct p6032_intrhead p6032_intrtab[NIRQMAPS];
161
162 #define NINTRS 2 /* MIPS INT0 - INT1 */
163
164 struct p6032_cpuintr {
165 LIST_HEAD(, evbmips_intrhand) cintr_list;
166 struct evcnt cintr_count;
167 };
168
169 struct p6032_cpuintr p6032_cpuintrs[NINTRS];
170 const char * const p6032_cpuintrnames[NINTRS] = {
171 "int 0 (pci)",
172 "int 1 (isa)",
173 };
174
175 void *algor_p6032_intr_establish(int, int (*)(void *), void *);
176 void algor_p6032_intr_disestablish(void *);
177
178 int algor_p6032_pci_intr_map(const struct pci_attach_args *,
179 pci_intr_handle_t *);
180 const char *algor_p6032_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
181 const struct evcnt *algor_p6032_pci_intr_evcnt(void *, pci_intr_handle_t);
182 void *algor_p6032_pci_intr_establish(void *, pci_intr_handle_t, int,
183 int (*)(void *), void *);
184 void algor_p6032_pci_intr_disestablish(void *, void *);
185 void algor_p6032_pci_conf_interrupt(void *, int, int, int, int, int *);
186
187 void algor_p6032_iointr(int, vaddr_t, uint32_t);
188
189 void
algor_p6032_intr_init(struct p6032_config * acp)190 algor_p6032_intr_init(struct p6032_config *acp)
191 {
192 struct bonito_config *bc = &acp->ac_bonito;
193 const struct p6032_irqmap *irqmap;
194 int i;
195
196 for (i = 0; i < NINTRS; i++) {
197 LIST_INIT(&p6032_cpuintrs[i].cintr_list);
198 evcnt_attach_dynamic(&p6032_cpuintrs[i].cintr_count,
199 EVCNT_TYPE_INTR, NULL, "mips", p6032_cpuintrnames[i]);
200 }
201
202 for (i = 0; i < __arraycount(p6032_irqmap); i++) {
203 irqmap = &p6032_irqmap[i];
204
205 evcnt_attach_dynamic(&p6032_intrtab[i].intr_count,
206 EVCNT_TYPE_INTR, NULL, "bonito", p6032_intrnames[i]);
207
208 bc->bc_gpioIE |= irqmap->gpioiebit;
209 if (irqmap->flags & IRQ_F_INVERT)
210 bc->bc_intPol |= irqmap->intbit;
211 if (irqmap->flags & IRQ_F_EDGE)
212 bc->bc_intEdge |= irqmap->intbit;
213 if (irqmap->flags & IRQ_F_INT1)
214 bc->bc_intSteer |= irqmap->intbit;
215
216 REGVAL(BONITO_INTENCLR) = irqmap->intbit;
217 }
218
219 REGVAL(BONITO_GPIOIE) = bc->bc_gpioIE;
220 REGVAL(BONITO_INTEDGE) = bc->bc_intEdge;
221 REGVAL(BONITO_INTSTEER) = bc->bc_intSteer;
222 REGVAL(BONITO_INTPOL) = bc->bc_intPol;
223
224 acp->ac_pc.pc_intr_v = NULL;
225 acp->ac_pc.pc_intr_map = algor_p6032_pci_intr_map;
226 acp->ac_pc.pc_intr_string = algor_p6032_pci_intr_string;
227 acp->ac_pc.pc_intr_evcnt = algor_p6032_pci_intr_evcnt;
228 acp->ac_pc.pc_intr_establish = algor_p6032_pci_intr_establish;
229 acp->ac_pc.pc_intr_disestablish = algor_p6032_pci_intr_disestablish;
230 acp->ac_pc.pc_conf_interrupt = algor_p6032_pci_conf_interrupt;
231
232 /* We let the PCI-ISA bridge code handle this. */
233 acp->ac_pc.pc_pciide_compat_intr_establish = NULL;
234
235 algor_intr_establish = algor_p6032_intr_establish;
236 algor_intr_disestablish = algor_p6032_intr_disestablish;
237 algor_iointr = algor_p6032_iointr;
238 }
239
240 void
algor_p6032_cal_timer(bus_space_tag_t st,bus_space_handle_t sh)241 algor_p6032_cal_timer(bus_space_tag_t st, bus_space_handle_t sh)
242 {
243 u_long ctrdiff[4], startctr, endctr, cps;
244 uint8_t regc;
245 int i;
246
247 /* Disable interrupts first. */
248 bus_space_write_1(st, sh, 0, MC_REGB);
249 bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
250 MC_REGB_24HR);
251
252 /* Initialize for 16Hz. */
253 bus_space_write_1(st, sh, 0, MC_REGA);
254 bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz);
255
256 /* Run the loop an extra time to prime the cache. */
257 for (i = 0; i < 4; i++) {
258 led_display('h', 'z', '0' + i, ' ');
259
260 /* Enable the interrupt. */
261 bus_space_write_1(st, sh, 0, MC_REGB);
262 bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE |
263 MC_REGB_BINARY | MC_REGB_24HR);
264
265 /* Go to REGC. */
266 bus_space_write_1(st, sh, 0, MC_REGC);
267
268 /* Wait for it to happen. */
269 startctr = mips3_cp0_count_read();
270 do {
271 regc = bus_space_read_1(st, sh, 1);
272 endctr = mips3_cp0_count_read();
273 } while ((regc & MC_REGC_IRQF) == 0);
274
275 /* Already ACK'd. */
276
277 /* Disable. */
278 bus_space_write_1(st, sh, 0, MC_REGB);
279 bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
280 MC_REGB_24HR);
281
282 ctrdiff[i] = endctr - startctr;
283 }
284
285 /* Update CPU frequency values */
286 cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
287 /* XXX mips_cpu_flags isn't set here; assume CPU_MIPS_DOUBLE_COUNT */
288 curcpu()->ci_cpu_freq = cps * 2;
289 curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
290 curcpu()->ci_divisor_delay =
291 ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000);
292 /* XXX assume CPU_MIPS_DOUBLE_COUNT */
293 curcpu()->ci_cycles_per_hz /= 2;
294 curcpu()->ci_divisor_delay /= 2;
295
296 printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n",
297 cps, ctrdiff[2], ctrdiff[3]);
298 printf("CPU clock speed = %lu.%02luMHz "
299 "(hz cycles = %lu, delay divisor = %lu)\n",
300 curcpu()->ci_cpu_freq / 1000000,
301 (curcpu()->ci_cpu_freq % 1000000) / 10000,
302 curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay);
303 }
304
305 void *
algor_p6032_intr_establish(int irq,int (* func)(void *),void * arg)306 algor_p6032_intr_establish(int irq, int (*func)(void *), void *arg)
307 {
308 const struct p6032_irqmap *irqmap;
309 struct evbmips_intrhand *ih;
310 int s;
311
312 irqmap = &p6032_irqmap[irq];
313
314 KASSERT(irq == irqmap->irqidx);
315
316 ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
317 ih->ih_func = func;
318 ih->ih_arg = arg;
319 ih->ih_irq = 0;
320 ih->ih_irqmap = irqmap;
321
322 s = splhigh();
323
324 /*
325 * First, link it into the tables.
326 */
327 if (irqmap->flags & IRQ_F_INT1)
328 LIST_INSERT_HEAD(&p6032_cpuintrs[1].cintr_list, ih, ih_q);
329 else
330 LIST_INSERT_HEAD(&p6032_cpuintrs[0].cintr_list, ih, ih_q);
331
332 /*
333 * Now enable it.
334 */
335 if (p6032_intrtab[irqmap->irqidx].intr_refcnt++ == 0)
336 REGVAL(BONITO_INTENSET) = irqmap->intbit;
337
338 splx(s);
339
340 return (ih);
341 }
342
343 void
algor_p6032_intr_disestablish(void * cookie)344 algor_p6032_intr_disestablish(void *cookie)
345 {
346 const struct p6032_irqmap *irqmap;
347 struct evbmips_intrhand *ih = cookie;
348 int s;
349
350 irqmap = ih->ih_irqmap;
351
352 s = splhigh();
353
354 /*
355 * First, remove it from the table.
356 */
357 LIST_REMOVE(ih, ih_q);
358
359 /*
360 * Now, disable it, if there is nothing remaining on the
361 * list.
362 */
363 if (p6032_intrtab[irqmap->irqidx].intr_refcnt-- == 1)
364 REGVAL(BONITO_INTENCLR) = irqmap->intbit;
365
366 splx(s);
367
368 kmem_free(ih, sizeof(*ih));
369 }
370
371 void
algor_p6032_iointr(int ipl,vaddr_t pc,uint32_t ipending)372 algor_p6032_iointr(int ipl, vaddr_t pc, uint32_t ipending)
373 {
374 const struct p6032_irqmap *irqmap;
375 struct evbmips_intrhand *ih;
376 int level;
377 uint32_t isr;
378
379 /* Check for DEBUG interrupts. */
380 if (ipending & MIPS_INT_MASK_3) {
381 #ifdef DDB
382 printf("Debug switch -- entering debugger\n");
383 led_display('D','D','B',' ');
384 Debugger();
385 led_display('N','B','S','D');
386 #else
387 printf("Debug switch ignored -- "
388 "no debugger configured\n");
389 #endif
390 }
391
392 /*
393 * Read the interrupt pending registers, mask them with the
394 * ones we have enabled, and service them in order of decreasing
395 * priority.
396 */
397 isr = REGVAL(BONITO_INTISR) & REGVAL(BONITO_INTEN);
398
399 for (level = 1; level >= 0; level--) {
400 if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
401 continue;
402 p6032_cpuintrs[level].cintr_count.ev_count++;
403 for (ih = LIST_FIRST(&p6032_cpuintrs[level].cintr_list);
404 ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
405 irqmap = ih->ih_irqmap;
406 if (isr & irqmap->intbit) {
407 p6032_intrtab[
408 irqmap->irqidx].intr_count.ev_count++;
409 (*ih->ih_func)(ih->ih_arg);
410 }
411 }
412 }
413 }
414
415 /*****************************************************************************
416 * PCI interrupt support
417 *****************************************************************************/
418
419 int
algor_p6032_pci_intr_map(const struct pci_attach_args * pa,pci_intr_handle_t * ihp)420 algor_p6032_pci_intr_map(const struct pci_attach_args *pa,
421 pci_intr_handle_t *ihp)
422 {
423 static const int pciirqmap[6/*device*/][4/*pin*/] = {
424 { P6032_IRQ_GPIO0, P6032_IRQ_GPIO1,
425 P6032_IRQ_GPIO2, P6032_IRQ_GPIO3 }, /* 13: slot 2 (p9) */
426
427 { P6032_IRQ_GPIO1, P6032_IRQ_GPIO2,
428 P6032_IRQ_GPIO3, P6032_IRQ_GPIO0 }, /* 14: slot 3 (p10) */
429
430 { P6032_IRQ_GPIO2, P6032_IRQ_GPIO3,
431 P6032_IRQ_GPIO0, P6032_IRQ_GPIO1 }, /* 15: slot 4 (p11) */
432
433 { P6032_IRQ_GPIN2, -1,
434 -1, -1 }, /* 16: Ethernet */
435
436 { P6032_IRQ_GPIO0, P6032_IRQ_GPIO1,
437 P6032_IRQ_GPIO2, P6032_IRQ_GPIO3 }, /* 17: southbridge */
438
439 { P6032_IRQ_GPIO3, P6032_IRQ_GPIO0,
440 P6032_IRQ_GPIO1, P6032_IRQ_GPIO2 }, /* 18: slot 1 (p8) */
441 };
442 pcitag_t bustag = pa->pa_intrtag;
443 int buspin = pa->pa_intrpin;
444 pci_chipset_tag_t pc = pa->pa_pc;
445 int device, irq;
446
447 if (buspin == 0) {
448 /* No IRQ used. */
449 return (1);
450 }
451
452 if (buspin > 4) {
453 printf("algor_p6032_pci_intr_map: bad interrupt pin %d\n",
454 buspin);
455 return (1);
456 }
457
458 pci_decompose_tag(pc, bustag, NULL, &device, NULL);
459 if (device < 13 || device > 18) {
460 printf("algor_p6032_pci_intr_map: bad device %d\n",
461 device);
462 return (1);
463 }
464
465 irq = pciirqmap[device - 13][buspin - 1];
466 if (irq == -1) {
467 printf("algor_p6032_pci_intr_map: no mapping for "
468 "device %d pin %d\n", device, buspin);
469 return (1);
470 }
471
472 *ihp = irq;
473 return (0);
474 }
475
476 const char *
algor_p6032_pci_intr_string(void * v,pci_intr_handle_t ih,char * buf,size_t len)477 algor_p6032_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
478 {
479
480 if (ih >= NIRQMAPS)
481 panic("algor_p6032_intr_string: bogus IRQ %ld", ih);
482
483 strlcpy(buf, p6032_intrnames[ih], len);
484 return buf;
485 }
486
487 const struct evcnt *
algor_p6032_pci_intr_evcnt(void * v,pci_intr_handle_t ih)488 algor_p6032_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
489 {
490
491 return (&p6032_intrtab[ih].intr_count);
492 }
493
494 void *
algor_p6032_pci_intr_establish(void * v,pci_intr_handle_t ih,int level,int (* func)(void *),void * arg)495 algor_p6032_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
496 int (*func)(void *), void *arg)
497 {
498
499 if (ih >= NIRQMAPS)
500 panic("algor_p6032_intr_establish: bogus IRQ %ld", ih);
501
502 return (algor_p6032_intr_establish(ih, func, arg));
503 }
504
505 void
algor_p6032_pci_intr_disestablish(void * v,void * cookie)506 algor_p6032_pci_intr_disestablish(void *v, void *cookie)
507 {
508
509 return (algor_p6032_intr_disestablish(cookie));
510 }
511
512 void
algor_p6032_pci_conf_interrupt(void * v,int bus,int dev,int pin,int swiz,int * iline)513 algor_p6032_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
514 int *iline)
515 {
516
517 /*
518 * We actually don't need to do anything; everything is handled
519 * in pci_intr_map().
520 */
521 *iline = 0;
522 }
523