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