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