xref: /netbsd-src/sys/arch/algor/algor/algor_p6032_intr.c (revision ae873cf0ebcc8e109bf9c6aa08ee836eebb343be)
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