1/*	$NetBSD: algor_p5064_intr.c,v 1.30 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-5064.
34 *
35 * The Algorithmics P-5064 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_p5064_intr.c,v 1.30 2020/11/14 02:23:04 thorpej 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/kmem.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_p5064reg.h>
63#include <algor/algor/algor_p5064var.h>
64
65#include <dev/pci/pcireg.h>
66#include <dev/pci/pcivar.h>
67#include <dev/pci/pciidereg.h>
68#include <dev/pci/pciidevar.h>
69
70#include <dev/isa/isavar.h>
71
72#define	REGVAL(x)	*((volatile uint32_t *)(MIPS_PHYS_TO_KSEG1((x))))
73
74struct p5064_irqreg {
75	bus_addr_t	addr;
76	uint32_t	val;
77};
78
79#define	IRQREG_LOCINT		0
80#define	IRQREG_PANIC		1
81#define	IRQREG_PCIINT		2
82#define	IRQREG_ISAINT		3
83#define	IRQREG_KBDINT		4
84#define	NIRQREG			5
85
86struct p5064_irqreg p5064_irqregs[NIRQREG] = {
87	{ P5064_LOCINT,		0 },
88	{ P5064_PANIC,		0 },
89	{ P5064_PCIINT,		0 },
90	{ P5064_ISAINT,		0 },
91	{ P5064_KBDINT,		0 },
92};
93
94#define	NSTEERREG		5
95
96struct p5064_irqreg p5064_irqsteer[NSTEERREG] = {
97	{ P5064_XBAR0,		0 },
98	{ P5064_XBAR1,		0 },
99	{ P5064_XBAR2,		0 },
100	{ P5064_XBAR3,		0 },
101	{ P5064_XBAR4,		0 },
102};
103
104#define	NPCIIRQS		7
105
106#define	NLOCIRQS		6
107
108#define	NISAIRQS		3
109
110#define	IRQMAP_PCIBASE		0
111#define	IRQMAP_LOCBASE		NPCIIRQS
112#define	IRQMAP_ISABASE		(IRQMAP_LOCBASE + NLOCIRQS)
113#define	NIRQMAPS		(IRQMAP_ISABASE + NISAIRQS)
114
115const char * const p5064_intrnames[NIRQMAPS] = {
116	/*
117	 * PCI INTERRUPTS
118	 */
119	"PCIIRQ 0",
120	"PCIIRQ 1",
121	"PCIIRQ 2",
122	"PCIIRQ 3",
123	"Ethernet IRQ",
124	"SCSI IRQ",
125	"USB IRQ",
126
127	/*
128	 * LOCAL INTERRUPTS
129	 */
130	"mkbd",
131	"com 1",
132	"com 2",
133	"floppy",
134	"centronics",
135	"mcclock",
136
137	/*
138	 * ISA interrupts.
139	 */
140	"bridge",
141	"IDE primary",
142	"IDE secondary",
143};
144
145struct p5064_irqmap {
146	int	irqidx;
147	int	cpuintr;
148	int	irqreg;
149	int	irqbit;
150	int	xbarreg;
151	int	xbarshift;
152};
153
154const struct p5064_irqmap p5064_irqmap[NIRQMAPS] = {
155	/*
156	 * PCI INTERRUPTS
157	 */
158	/* PCIIRQ 0 */
159	{ 0,			1,
160	  IRQREG_PCIINT,	PCIINT_PCI0,
161	  2,			0 },
162
163	/* PCIIRQ 1 */
164	{ 1,			1,
165	  IRQREG_PCIINT,	PCIINT_PCI1,
166	  2,			2 },
167
168	/* PCIIRQ 2 */
169	{ 2,			1,
170	  IRQREG_PCIINT,	PCIINT_PCI2,
171	  2,			4 },
172
173	/* PCIIRQ 3 */
174	{ 3,			1,
175	  IRQREG_PCIINT,	PCIINT_PCI3,
176	  2,			6 },
177
178	/* Ethernet */
179	{ P5064_IRQ_ETHERNET,	1,
180	  IRQREG_PCIINT,	PCIINT_ETH,
181	  4,			2 },
182
183	/* SCSI */
184	{ P5064_IRQ_SCSI,	1,
185	  IRQREG_PCIINT,	PCIINT_SCSI,
186	  4,			4 },
187
188	/* USB */
189	{ P5064_IRQ_USB,	1,
190	  IRQREG_PCIINT,	PCIINT_USB,
191	  4,			6 },
192
193	/*
194	 * LOCAL INTERRUPTS
195	 */
196	/* keyboard */
197	{ P5064_IRQ_MKBD,	2,
198	  IRQREG_LOCINT,	LOCINT_MKBD,
199	  0,			4 },
200
201	/* COM1 */
202	{ P5064_IRQ_COM1,	2,
203	  IRQREG_LOCINT,	LOCINT_COM1,
204	  0,			6 },
205
206	/* COM2 */
207	{ P5064_IRQ_COM2,	2,
208	  IRQREG_LOCINT,	LOCINT_COM2,
209	  1,			0 },
210
211	/* floppy controller */
212	{ P5064_IRQ_FLOPPY,	2,
213	  IRQREG_LOCINT,	LOCINT_FLP,
214	  0,			2 },
215
216	/* parallel port */
217	{ P5064_IRQ_CENTRONICS,	2,
218	  IRQREG_LOCINT,	LOCINT_CENT,
219	  1,			2 },
220
221	/* RTC */
222	{ P5064_IRQ_RTC,	2,
223	  IRQREG_LOCINT,	LOCINT_RTC,
224	  1,			6 },
225
226	/*
227	 * ISA INTERRUPTS
228	 */
229	/* ISA bridge */
230	{ P5064_IRQ_ISABRIDGE,	0,
231	  IRQREG_ISAINT,	ISAINT_ISABR,
232	  3,			0 },
233
234	/* IDE 0 */
235	{ P5064_IRQ_IDE0,	0,
236	  IRQREG_ISAINT,	ISAINT_IDE0,
237	  3,			2 },
238
239	/* IDE 1 */
240	{ P5064_IRQ_IDE1,	0,
241	  IRQREG_ISAINT,	ISAINT_IDE1,
242	  3,			4 },
243};
244
245const int p5064_isa_to_irqmap[16] = {
246	-1,			/* 0 */
247	P5064_IRQ_MKBD,		/* 1 */
248	-1,			/* 2 */
249	P5064_IRQ_COM2,		/* 3 */
250	P5064_IRQ_COM1,		/* 4 */
251	-1,			/* 5 */
252	P5064_IRQ_FLOPPY,	/* 6 */
253	P5064_IRQ_CENTRONICS,	/* 7 */
254	P5064_IRQ_RTC,		/* 8 */
255	-1,			/* 9 */
256	-1,			/* 10 */
257	-1,			/* 11 */
258	P5064_IRQ_MKBD,		/* 12 */
259	-1,			/* 13 */
260	P5064_IRQ_IDE0,		/* 14 */
261	P5064_IRQ_IDE1,		/* 15 */
262};
263
264struct p5064_intrhead {
265	struct evcnt intr_count;
266	int intr_refcnt;
267};
268struct p5064_intrhead p5064_intrtab[NIRQMAPS];
269
270#define	NINTRS			3	/* MIPS INT0 - INT2 */
271
272struct p5064_cpuintr {
273	LIST_HEAD(, evbmips_intrhand) cintr_list;
274	struct evcnt cintr_count;
275};
276
277struct p5064_cpuintr p5064_cpuintrs[NINTRS];
278const char * const p5064_cpuintrnames[NINTRS] = {
279	"int 0 (isa)",
280	"int 1 (pci)",
281	"int 2 (local)",
282};
283
284const char * const p5064_intrgroups[NINTRS] = {
285	"isa",
286	"pci",
287	"local",
288};
289
290void	*algor_p5064_intr_establish(int, int (*)(void *), void *);
291void	algor_p5064_intr_disestablish(void *);
292
293int	algor_p5064_pci_intr_map(const struct pci_attach_args *,
294	    pci_intr_handle_t *);
295const char *algor_p5064_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
296const struct evcnt *algor_p5064_pci_intr_evcnt(void *, pci_intr_handle_t);
297void	*algor_p5064_pci_intr_establish(void *, pci_intr_handle_t, int,
298	    int (*)(void *), void *);
299void	algor_p5064_pci_intr_disestablish(void *, void *);
300void	*algor_p5064_pciide_compat_intr_establish(void *, device_t,
301	    const struct pci_attach_args *, int, int (*)(void *), void *);
302void	algor_p5064_pci_conf_interrupt(void *, int, int, int, int, int *);
303
304const struct evcnt *algor_p5064_isa_intr_evcnt(void *, int);
305void	*algor_p5064_isa_intr_establish(void *, int, int, int,
306	    int (*)(void *), void *);
307void	algor_p5064_isa_intr_disestablish(void *, void *);
308int	algor_p5064_isa_intr_alloc(void *, int, int, int *);
309
310void	algor_p5064_iointr(int, vaddr_t, uint32_t);
311
312void
313algor_p5064_intr_init(struct p5064_config *acp)
314{
315	const struct p5064_irqmap *irqmap;
316	int i;
317
318	for (i = 0; i < NIRQREG; i++)
319		REGVAL(p5064_irqregs[i].addr) = p5064_irqregs[i].val;
320
321	for (i = 0; i < NINTRS; i++) {
322		LIST_INIT(&p5064_cpuintrs[i].cintr_list);
323		evcnt_attach_dynamic(&p5064_cpuintrs[i].cintr_count,
324		    EVCNT_TYPE_INTR, NULL, "mips", p5064_cpuintrnames[i]);
325	}
326
327	for (i = 0; i < NIRQMAPS; i++) {
328		irqmap = &p5064_irqmap[i];
329
330		p5064_irqsteer[irqmap->xbarreg].val |=
331		    irqmap->cpuintr << irqmap->xbarshift;
332
333		evcnt_attach_dynamic(&p5064_intrtab[i].intr_count,
334		    EVCNT_TYPE_INTR, NULL, p5064_intrgroups[irqmap->cpuintr],
335		    p5064_intrnames[i]);
336	}
337
338	for (i = 0; i < NSTEERREG; i++)
339		REGVAL(p5064_irqsteer[i].addr) = p5064_irqsteer[i].val;
340
341	acp->ac_pc.pc_intr_v = NULL;
342	acp->ac_pc.pc_intr_map = algor_p5064_pci_intr_map;
343	acp->ac_pc.pc_intr_string = algor_p5064_pci_intr_string;
344	acp->ac_pc.pc_intr_evcnt = algor_p5064_pci_intr_evcnt;
345	acp->ac_pc.pc_intr_establish = algor_p5064_pci_intr_establish;
346	acp->ac_pc.pc_intr_disestablish = algor_p5064_pci_intr_disestablish;
347	acp->ac_pc.pc_conf_interrupt = algor_p5064_pci_conf_interrupt;
348	acp->ac_pc.pc_pciide_compat_intr_establish =
349	    algor_p5064_pciide_compat_intr_establish;
350
351	acp->ac_ic.ic_v = NULL;
352	acp->ac_ic.ic_intr_evcnt = algor_p5064_isa_intr_evcnt;
353	acp->ac_ic.ic_intr_establish = algor_p5064_isa_intr_establish;
354	acp->ac_ic.ic_intr_disestablish = algor_p5064_isa_intr_disestablish;
355	acp->ac_ic.ic_intr_alloc = algor_p5064_isa_intr_alloc;
356
357	algor_intr_establish = algor_p5064_intr_establish;
358	algor_intr_disestablish = algor_p5064_intr_disestablish;
359	algor_iointr = algor_p5064_iointr;
360}
361
362void
363algor_p5064_cal_timer(bus_space_tag_t st, bus_space_handle_t sh)
364{
365	u_long ctrdiff[4], startctr, endctr, cps;
366	uint32_t irr;
367	int i;
368
369	/* Disable interrupts first. */
370	bus_space_write_1(st, sh, 0, MC_REGB);
371	bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
372	    MC_REGB_24HR);
373
374	/* Initialize for 16Hz. */
375	bus_space_write_1(st, sh, 0, MC_REGA);
376	bus_space_write_1(st, sh, 1, MC_BASE_32_KHz | MC_RATE_16_Hz);
377
378	REGVAL(P5064_LOCINT) = LOCINT_RTC;
379
380	/* Run the loop an extra time to prime the cache. */
381	for (i = 0; i < 4; i++) {
382		led_display('h', 'z', '0' + i, ' ');
383
384		/* Enable the interrupt. */
385		bus_space_write_1(st, sh, 0, MC_REGB);
386		bus_space_write_1(st, sh, 1, MC_REGB_PIE | MC_REGB_SQWE |
387		    MC_REGB_BINARY | MC_REGB_24HR);
388
389		/* Wait for it to happen. */
390		startctr = mips3_cp0_count_read();
391		do {
392			irr = REGVAL(P5064_LOCINT);
393			endctr = mips3_cp0_count_read();
394		} while ((irr & LOCINT_RTC) == 0);
395
396		/* ACK. */
397		bus_space_write_1(st, sh, 0, MC_REGC);
398		(void) bus_space_read_1(st, sh, 1);
399
400		/* Disable. */
401		bus_space_write_1(st, sh, 0, MC_REGB);
402		bus_space_write_1(st, sh, 1, MC_REGB_SQWE | MC_REGB_BINARY |
403		    MC_REGB_24HR);
404
405		ctrdiff[i] = endctr - startctr;
406	}
407
408	REGVAL(P5064_LOCINT) = 0;
409
410	/* Update CPU frequency values */
411	cps = ((ctrdiff[2] + ctrdiff[3]) / 2) * 16;
412#if 1
413	/* XXX for unaccurate emulators */
414	if (cps < 10 * 1000 * 1000) {
415		/* unlikely, use a reasonable value */
416		cps = 75 * 1000 * 1000;
417	}
418#endif
419	/* XXX mips_cpu_flags isn't set here; assume CPU_MIPS_DOUBLE_COUNT */
420	curcpu()->ci_cpu_freq = cps * 2;
421	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
422	curcpu()->ci_divisor_delay =
423	    ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000);
424	/* XXX assume CPU_MIPS_DOUBLE_COUNT */
425	curcpu()->ci_cycles_per_hz /= 2;
426	curcpu()->ci_divisor_delay /= 2;
427
428	printf("Timer calibration: %lu cycles/sec [(%lu, %lu) * 16]\n",
429	    cps, ctrdiff[2], ctrdiff[3]);
430	printf("CPU clock speed = %lu.%02luMHz "
431	    "(hz cycles = %lu, delay divisor = %lu)\n",
432	    curcpu()->ci_cpu_freq / 1000000,
433	    (curcpu()->ci_cpu_freq % 1000000) / 10000,
434	    curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay);
435}
436
437void *
438algor_p5064_intr_establish(int irq, int (*func)(void *), void *arg)
439{
440	const struct p5064_irqmap *irqmap;
441	struct evbmips_intrhand *ih;
442	int s;
443
444	irqmap = &p5064_irqmap[irq];
445
446	KASSERT(irq == irqmap->irqidx);
447
448	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
449	ih->ih_func = func;
450	ih->ih_arg = arg;
451	ih->ih_irq = 0;
452	ih->ih_irqmap = irqmap;
453
454	s = splhigh();
455
456	/*
457	 * First, link it into the tables.
458	 */
459	LIST_INSERT_HEAD(&p5064_cpuintrs[irqmap->cpuintr].cintr_list,
460	    ih, ih_q);
461
462	/*
463	 * Now enable it.
464	 */
465	if (p5064_intrtab[irqmap->irqidx].intr_refcnt++ == 0) {
466		p5064_irqregs[irqmap->irqreg].val |= irqmap->irqbit;
467		REGVAL(p5064_irqregs[irqmap->irqreg].addr) =
468		    p5064_irqregs[irqmap->irqreg].val;
469	}
470
471	splx(s);
472
473	return (ih);
474}
475
476void
477algor_p5064_intr_disestablish(void *cookie)
478{
479	const struct p5064_irqmap *irqmap;
480	struct evbmips_intrhand *ih = cookie;
481	int s;
482
483	irqmap = ih->ih_irqmap;
484
485	s = splhigh();
486
487	/*
488	 * First, remove it from the table.
489	 */
490	LIST_REMOVE(ih, ih_q);
491
492	/*
493	 * Now, disable it, if there is nothing remaining on the
494	 * list.
495	 */
496	if (p5064_intrtab[irqmap->irqidx].intr_refcnt-- == 1) {
497		p5064_irqregs[irqmap->irqreg].val &= ~irqmap->irqbit;
498		REGVAL(p5064_irqregs[irqmap->irqreg].addr) =
499		    p5064_irqregs[irqmap->irqreg].val;
500	}
501
502	splx(s);
503
504	kmem_free(ih, sizeof(*ih));
505}
506
507void
508algor_p5064_iointr(int ipl, vaddr_t pc, uint32_t ipending)
509{
510	const struct p5064_irqmap *irqmap;
511	struct evbmips_intrhand *ih;
512	int level, i;
513	uint32_t irr[NIRQREG];
514
515	/* Check for PANIC interrupts. */
516	if (ipending & MIPS_INT_MASK_4) {
517		irr[IRQREG_PANIC] = REGVAL(p5064_irqregs[IRQREG_PANIC].addr);
518		if (irr[IRQREG_PANIC] & PANIC_IOPERR)
519			printf("WARNING: I/O parity error\n");
520		if (irr[IRQREG_PANIC] & PANIC_ISANMI)
521			printf("WARNING: ISA NMI\n");
522		if (irr[IRQREG_PANIC] & PANIC_BERR)
523			printf("WARNING: Bus error\n");
524		if (irr[IRQREG_PANIC] & PANIC_PFAIL)
525			printf("WARNING: Power failure\n");
526		if (irr[IRQREG_PANIC] & PANIC_DEBUG) {
527#ifdef DDB
528			printf("Debug switch -- entering debugger\n");
529			led_display('D','D','B',' ');
530			Debugger();
531			led_display('N','B','S','D');
532#else
533			printf("Debug switch ignored -- "
534			    "no debugger configured\n");
535#endif
536		}
537
538		/* Clear them. */
539		REGVAL(p5064_irqregs[IRQREG_PANIC].addr) = irr[IRQREG_PANIC];
540	}
541
542	/*
543	 * Read the interrupt pending registers, mask them with the
544	 * ones we have enabled, and service them in order of decreasing
545	 * priority.
546	 */
547	for (i = 0; i < NIRQREG; i++) {
548		if (i == IRQREG_PANIC)
549			continue;
550		irr[i] = REGVAL(p5064_irqregs[i].addr) & p5064_irqregs[i].val;
551	}
552
553	for (level = (NINTRS - 1); level >= 0; level--) {
554		if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
555			continue;
556		p5064_cpuintrs[level].cintr_count.ev_count++;
557		for (ih = LIST_FIRST(&p5064_cpuintrs[level].cintr_list);
558		     ih != NULL; ih = LIST_NEXT(ih, ih_q)) {
559			irqmap = ih->ih_irqmap;
560			if (irr[irqmap->irqreg] & irqmap->irqbit) {
561				p5064_intrtab[
562				    irqmap->irqidx].intr_count.ev_count++;
563				(*ih->ih_func)(ih->ih_arg);
564			}
565		}
566	}
567}
568
569/*****************************************************************************
570 * PCI interrupt support
571 *****************************************************************************/
572
573int
574algor_p5064_pci_intr_map(const struct pci_attach_args *pa,
575    pci_intr_handle_t *ihp)
576{
577	static const int pciirqmap[6/*device*/][4/*pin*/] = {
578		{ P5064_IRQ_ETHERNET, -1, -1, -1 },	/* 0: Ethernet */
579		{ P5064_IRQ_SCSI, -1, -1, -1 },		/* 1: SCSI */
580		{ -1, -1, -1, P5064_IRQ_USB },		/* 2: PCI-ISA bridge */
581		{ 0, 1, 2, 3 },				/* 3: PCI slot 3 */
582		{ 3, 0, 1, 2 },				/* 4: PCI slot 2 */
583		{ 2, 3, 0, 1 },				/* 5: PCI slot 1 */
584	};
585	pcitag_t bustag = pa->pa_intrtag;
586	int buspin = pa->pa_intrpin;
587	pci_chipset_tag_t pc = pa->pa_pc;
588	int device, irq;
589
590	if (buspin == 0) {
591		/* No IRQ used. */
592		return (1);
593	}
594
595	if (buspin > 4) {
596		printf("algor_p5064_pci_intr_map: bad interrupt pin %d\n",
597		    buspin);
598		return (1);
599	}
600
601	pci_decompose_tag(pc, bustag, NULL, &device, NULL);
602	if (device > 5) {
603		printf("algor_p5064_pci_intr_map: bad device %d\n",
604		    device);
605		return (1);
606	}
607
608	irq = pciirqmap[device][buspin - 1];
609	if (irq == -1) {
610		printf("algor_p5064_pci_intr_map: no mapping for "
611		    "device %d pin %d\n", device, buspin);
612		return (1);
613	}
614
615	*ihp = irq;
616	return (0);
617}
618
619const char *
620algor_p5064_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
621{
622
623	if (ih >= NPCIIRQS)
624		panic("algor_p5064_intr_string: bogus IRQ %ld", ih);
625
626	strlcpy(buf, p5064_intrnames[ih], len);
627	return buf;
628}
629
630const struct evcnt *
631algor_p5064_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
632{
633
634	return (&p5064_intrtab[ih].intr_count);
635}
636
637void *
638algor_p5064_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
639    int (*func)(void *), void *arg)
640{
641
642	if (ih >= NPCIIRQS)
643		panic("algor_p5064_intr_establish: bogus IRQ %ld", ih);
644
645	return (algor_p5064_intr_establish(ih, func, arg));
646}
647
648void
649algor_p5064_pci_intr_disestablish(void *v, void *cookie)
650{
651
652	return (algor_p5064_intr_disestablish(cookie));
653}
654
655void
656algor_p5064_pci_conf_interrupt(void *v, int bus, int dev, int pin, int swiz,
657    int *iline)
658{
659
660	/*
661	 * We actually don't need to do anything; everything is handled
662	 * in pci_intr_map().
663	 */
664	*iline = 0;
665}
666
667void *
668algor_p5064_pciide_compat_intr_establish(void *v, device_t dev,
669    const struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
670{
671	pci_chipset_tag_t pc = pa->pa_pc;
672	void *cookie;
673	int bus;
674
675	pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
676
677	/*
678	 * If this isn't PCI bus #0, all bets are off.
679	 */
680	if (bus != 0)
681		return (NULL);
682
683	cookie = algor_p5064_intr_establish(P5064_IRQ_IDE0 + chan, func, arg);
684	if (cookie == NULL)
685		return (NULL);
686	aprint_normal_dev(dev, "%s channel interrupting at on-board %s IRQ\n",
687	    PCIIDE_CHANNEL_NAME(chan), p5064_intrnames[P5064_IRQ_IDE0 + chan]);
688	return (cookie);
689}
690
691/*****************************************************************************
692 * ISA interrupt support
693 *****************************************************************************/
694
695const struct evcnt *
696algor_p5064_isa_intr_evcnt(void *v, int iirq)
697{
698
699	/* XXX */
700	return (NULL);
701}
702
703void *
704algor_p5064_isa_intr_establish(void *v, int iirq, int type, int level,
705    int (*func)(void *), void *arg)
706{
707	struct evbmips_intrhand *ih;
708	int irqidx;
709
710	if (iirq > 15 || type == IST_NONE)
711		panic("algor_p5064_isa_intr_establish: bad irq or type");
712
713	if ((irqidx = p5064_isa_to_irqmap[iirq]) == -1)
714		return (NULL);
715
716	ih = algor_p5064_intr_establish(irqidx, func, arg);
717	if (ih != NULL) {
718		/* Translate it to an ISA IRQ. */
719		ih->ih_irq = iirq;
720	}
721	return (ih);
722}
723
724void
725algor_p5064_isa_intr_disestablish(void *v, void *cookie)
726{
727	struct evbmips_intrhand *ih = cookie;
728
729	/* Translate the IRQ back to our domain. */
730	ih->ih_irq = p5064_isa_to_irqmap[ih->ih_irq];
731
732	algor_p5064_intr_disestablish(ih);
733}
734
735int
736algor_p5064_isa_intr_alloc(void *v, int mask, int type, int *iirq)
737{
738
739	/* XXX */
740	return (1);
741}
742