xref: /netbsd-src/sys/arch/algor/algor/algor_p4032_intr.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: algor_p4032_intr.c,v 1.25 2014/03/29 19:28:25 christos 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.25 2014/03/29 19:28:25 christos 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/malloc.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
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
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 *
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 = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
356 	if (ih == NULL)
357 		return (NULL);
358 
359 	ih->ih_func = func;
360 	ih->ih_arg = arg;
361 	ih->ih_irq = 0;
362 	ih->ih_irqmap = irqmap;
363 
364 	s = splhigh();
365 
366 	/*
367 	 * First, link it into the tables.
368 	 */
369 	LIST_INSERT_HEAD(&p4032_cpuintrs[irqmap->cpuintr].cintr_list,
370 	    ih, ih_q);
371 
372 	/*
373 	 * Now enable it.
374 	 */
375 	if (p4032_intrtab[irqmap->irqidx].intr_refcnt++ == 0) {
376 		p4032_irqregs[irqmap->irqreg].val |= irqmap->irqbit;
377 		REGVAL(p4032_irqregs[irqmap->irqreg].addr) =
378 		    p4032_irqregs[irqmap->irqreg].val;
379 	}
380 
381 	splx(s);
382 
383 	return (ih);
384 }
385 
386 void
387 algor_p4032_intr_disestablish(void *cookie)
388 {
389 	const struct p4032_irqmap *irqmap;
390 	struct evbmips_intrhand *ih = cookie;
391 	int s;
392 
393 	irqmap = ih->ih_irqmap;
394 
395 	s = splhigh();
396 
397 	/*
398 	 * First, remove it from the table.
399 	 */
400 	LIST_REMOVE(ih, ih_q);
401 
402 	/*
403 	 * Now, disable it, if there is nothing remaining on the
404 	 * list.
405 	 */
406 	if (p4032_intrtab[irqmap->irqidx].intr_refcnt-- == 1) {
407 		p4032_irqregs[irqmap->irqreg].val &= ~irqmap->irqbit;
408 		REGVAL(p4032_irqregs[irqmap->irqreg].addr) =
409 		    p4032_irqregs[irqmap->irqreg].val;
410 	}
411 
412 	splx(s);
413 
414 	free(ih, M_DEVBUF);
415 }
416 
417 void
418 algor_p4032_iointr(int ipl, vaddr_t pc, u_int32_t ipending)
419 {
420 	const struct p4032_irqmap *irqmap;
421 	struct evbmips_intrhand *ih;
422 	int level, i;
423 	u_int32_t irr[NIRQREG];
424 
425 	/* Check for ERROR interrupts. */
426 	if (ipending & MIPS_INT_MASK_4) {
427 		irr[IRQREG_ERROR] = REGVAL(p4032_irqregs[IRQREG_ERROR].addr);
428 		if (irr[IRQREG_ERROR] & IRR1_BUSERR)
429 			printf("WARNING: Bus error\n");
430 		if (irr[IRQREG_ERROR] & IRR1_POWERFAIL)
431 			printf("WARNING: Power failure\n");
432 		if (irr[IRQREG_ERROR] & IRR1_DEBUG) {
433 #ifdef DDB
434 			printf("Debug switch -- entering debugger\n");
435 			led_display('D','D','B',' ');
436 			Debugger();
437 			led_display('N','B','S','D');
438 #else
439 			printf("Debug switch ignored -- "
440 			    "no debugger configured\n");
441 #endif
442 		}
443 
444 		/* Clear them. */
445 		REGVAL(p4032_irqregs[IRQREG_ERROR].addr) = irr[IRQREG_ERROR];
446 	}
447 
448 	/* Do floppy DMA request interrupts. */
449 	if (ipending & MIPS_INT_MASK_3) {
450 		/*
451 		 * XXX Hi, um, yah, we need to deal with
452 		 * XXX the floppy interrupt here.
453 		 */
454 
455 	}
456 
457 	/*
458 	 * Read the interrupt pending registers, mask them with the
459 	 * ones we have enabled, and service them in order of decreasing
460 	 * priority.
461 	 */
462 	for (i = 0; i < NIRQREG; i++) {
463 		if (i == IRQREG_ERROR)
464 			continue;
465 		irr[i] = REGVAL(p4032_irqregs[i].addr) & p4032_irqregs[i].val;
466 	}
467 
468 	for (level = (NINTRS - 1); level >= 0; level--) {
469 		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
470 			continue;
471 		p4032_cpuintrs[level].cintr_count.ev_count++;
472 		for (ih = LIST_FIRST(&p4032_cpuintrs[level].cintr_list);
473 		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
474 			irqmap = ih->ih_irqmap;
475 			if (irr[irqmap->irqreg] & irqmap->irqbit) {
476 				p4032_intrtab[
477 				    irqmap->irqidx].intr_count.ev_count++;
478 				(*ih->ih_func)(ih->ih_arg);
479 			}
480 		}
481 	}
482 }
483 
484 /*****************************************************************************
485  * PCI interrupt support
486  *****************************************************************************/
487 
488 int
489 algor_p4032_pci_intr_map(const struct pci_attach_args *pa,
490     pci_intr_handle_t *ihp)
491 {
492 	static const int pciirqmap[6/*device*/][4/*pin*/] = {
493 		{ 1, -1, -1, -1 },		/* 5: Ethernet */
494 		{ 2, 3, 0, 1 },			/* 6: PCI slot 1 */
495 		{ 3, 0, 1, 2 },			/* 7: PCI slot 2 */
496 		{ 0, -1, -1, -1 },		/* 8: SCSI */
497 		{ -1, -1, -1, -1 },		/* 9: not used */
498 		{ 0, 1, 2, 3 },			/* 10: custom connector */
499 	};
500 	pcitag_t bustag = pa->pa_intrtag;
501 	int buspin = pa->pa_intrpin;
502 	pci_chipset_tag_t pc = pa->pa_pc;
503 	int device, irq;
504 
505 	if (buspin == 0) {
506 		/* No IRQ used. */
507 		return (1);
508 	}
509 
510 	if (buspin > 4) {
511 		printf("algor_p4032_pci_intr_map: bad interrupt pin %d\n",
512 		    buspin);
513 		return (1);
514 	}
515 
516 	pci_decompose_tag(pc, bustag, NULL, &device, NULL);
517 	if (device < 5 || device > 10) {
518 		printf("algor_p4032_pci_intr_map: bad device %d\n",
519 		    device);
520 		return (1);
521 	}
522 
523 	irq = pciirqmap[device - 5][buspin - 1];
524 	if (irq == -1) {
525 		printf("algor_p4032_pci_intr_map: no mapping for "
526 		    "device %d pin %d\n", device, buspin);
527 		return (1);
528 	}
529 
530 	*ihp = irq;
531 	return (0);
532 }
533 
534 const char *
535 algor_p4032_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
536 {
537 
538 	if (ih >= NPCIIRQS)
539 		panic("algor_p4032_intr_string: bogus IRQ %ld", ih);
540 
541 	strlcpy(buf, p4032_intrnames[ih], len);
542 	return buf;
543 }
544 
545 const struct evcnt *
546 algor_p4032_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
547 {
548 
549 	return (&p4032_intrtab[ih].intr_count);
550 }
551 
552 void *
553 algor_p4032_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
554     int (*func)(void *), void *arg)
555 {
556 
557 	if (ih >= NPCIIRQS)
558 		panic("algor_p4032_intr_establish: bogus IRQ %ld", ih);
559 
560 	return (algor_p4032_intr_establish(ih, func, arg));
561 }
562 
563 void
564 algor_p4032_pci_intr_disestablish(void *v, void *cookie)
565 {
566 
567 	return (algor_p4032_intr_disestablish(cookie));
568 }
569 
570 void
571 algor_p4032_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
572     int *iline)
573 {
574 
575 	/*
576 	 * We actually don't need to do anything; everything is handled
577 	 * in pci_intr_map().
578 	 */
579 	*iline = 0;
580 }
581