1*d974db0aSgarbled /*	$NetBSD: pic_discovery.c,v 1.2 2007/10/17 19:56:42 garbled Exp $	*/
2*d974db0aSgarbled 
3*d974db0aSgarbled /*
4*d974db0aSgarbled  * Copyright (c) 2002 Allegro Networks, Inc., Wasabi Systems, Inc.
5*d974db0aSgarbled  * All rights reserved.
6*d974db0aSgarbled  *
7*d974db0aSgarbled  * Redistribution and use in source and binary forms, with or without
8*d974db0aSgarbled  * modification, are permitted provided that the following conditions
9*d974db0aSgarbled  * are met:
10*d974db0aSgarbled  * 1. Redistributions of source code must retain the above copyright
11*d974db0aSgarbled  *    notice, this list of conditions and the following disclaimer.
12*d974db0aSgarbled  * 2. Redistributions in binary form must reproduce the above copyright
13*d974db0aSgarbled  *    notice, this list of conditions and the following disclaimer in the
14*d974db0aSgarbled  *    documentation and/or other materials provided with the distribution.
15*d974db0aSgarbled  * 3. All advertising materials mentioning features or use of this software
16*d974db0aSgarbled  *    must display the following acknowledgement:
17*d974db0aSgarbled  *      This product includes software developed for the NetBSD Project by
18*d974db0aSgarbled  *      Allegro Networks, Inc., and Wasabi Systems, Inc.
19*d974db0aSgarbled  * 4. The name of Allegro Networks, Inc. may not be used to endorse
20*d974db0aSgarbled  *    or promote products derived from this software without specific prior
21*d974db0aSgarbled  *    written permission.
22*d974db0aSgarbled  * 5. The name of Wasabi Systems, Inc. may not be used to endorse
23*d974db0aSgarbled  *    or promote products derived from this software without specific prior
24*d974db0aSgarbled  *    written permission.
25*d974db0aSgarbled  *
26*d974db0aSgarbled  * THIS SOFTWARE IS PROVIDED BY ALLEGRO NETWORKS, INC. AND
27*d974db0aSgarbled  * WASABI SYSTEMS, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28*d974db0aSgarbled  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
29*d974db0aSgarbled  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30*d974db0aSgarbled  * IN NO EVENT SHALL EITHER ALLEGRO NETWORKS, INC. OR WASABI SYSTEMS, INC.
31*d974db0aSgarbled  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32*d974db0aSgarbled  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33*d974db0aSgarbled  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34*d974db0aSgarbled  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35*d974db0aSgarbled  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36*d974db0aSgarbled  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37*d974db0aSgarbled  * POSSIBILITY OF SUCH DAMAGE.
38*d974db0aSgarbled  */
39*d974db0aSgarbled 
40*d974db0aSgarbled /*
41*d974db0aSgarbled  * extintr.c - external interrupt management for discovery
42*d974db0aSgarbled  *
43*d974db0aSgarbled  *	Interrupts are software-prioritized and preempting,
44*d974db0aSgarbled  *	they are only actually masked when pending.
45*d974db0aSgarbled  *	this allows avoiding slow, off-CPU mask reprogramming for spl/splx.
46*d974db0aSgarbled  *	When a lower priority interrupt preempts a high one,
47*d974db0aSgarbled  *	it is pended and masked.  Masks are re-enabled after service.
48*d974db0aSgarbled  *
49*d974db0aSgarbled  *	`ci->ci_cpl'   is a "priority level" not a bitmask.
50*d974db0aSgarbled  *	`irq'   is a bit number in the 128 bit imask_t which reflects
51*d974db0aSgarbled  *		the GT-64260 Main Cause register pair (64 bits), and
52*d974db0aSgarbled  *		GPP Cause register (32 bits) interrupts.
53*d974db0aSgarbled  *
54*d974db0aSgarbled  *	Intra IPL dispatch order is defined in cause_irq()
55*d974db0aSgarbled  *
56*d974db0aSgarbled  *	Summary bits in cause registers are not valid IRQs
57*d974db0aSgarbled  *
58*d974db0aSgarbled  * 	Within a cause register bit vector ISRs are called in
59*d974db0aSgarbled  *	order of IRQ (descending).
60*d974db0aSgarbled  *
61*d974db0aSgarbled  *	When IRQs are shared, ISRs are called in order on the queue
62*d974db0aSgarbled  *	(which is arbitrarily first-established-first-served).
63*d974db0aSgarbled  *
64*d974db0aSgarbled  *	GT64260 GPP setup is for edge-triggered interrupts.
65*d974db0aSgarbled  *	We maintain a mask of level-triggered type IRQs
66*d974db0aSgarbled  *	and gather unlatched level from the GPP Value register.
67*d974db0aSgarbled  *
68*d974db0aSgarbled  *	Software interrupts are just like regular IRQs,
69*d974db0aSgarbled  *	they are established, pended, and dispatched exactly the
70*d974db0aSgarbled  *	same as HW interrupts.
71*d974db0aSgarbled  *
72*d974db0aSgarbled  *	128 bit imask_t operations could be implemented with Altivec
73*d974db0aSgarbled  *	("vand", "vor", etc however no "vcntlzw" or "vffs"....)
74*d974db0aSgarbled  *
75*d974db0aSgarbled  * creation	Tue Feb  6 17:27:18 PST 2001	cliff
76*d974db0aSgarbled  */
77*d974db0aSgarbled 
78*d974db0aSgarbled #include <sys/cdefs.h>
79*d974db0aSgarbled __KERNEL_RCSID(0, "$NetBSD: pic_discovery.c,v 1.2 2007/10/17 19:56:42 garbled Exp $");
80*d974db0aSgarbled 
81*d974db0aSgarbled #include "opt_marvell.h"
82*d974db0aSgarbled #include "opt_kgdb.h"
83*d974db0aSgarbled 
84*d974db0aSgarbled #include <sys/param.h>
85*d974db0aSgarbled #include <sys/systm.h>
86*d974db0aSgarbled #include <sys/types.h>
87*d974db0aSgarbled #include <sys/malloc.h>
88*d974db0aSgarbled #include <sys/kernel.h>
89*d974db0aSgarbled 
90*d974db0aSgarbled #include <machine/psl.h>
91*d974db0aSgarbled #include <machine/bus.h>
92*d974db0aSgarbled #include <machine/cpu.h>
93*d974db0aSgarbled #include <machine/intr.h>
94*d974db0aSgarbled #include <powerpc/pic/picvar.h>
95*d974db0aSgarbled #ifdef KGDB
96*d974db0aSgarbled #include <machine/db_machdep.h>
97*d974db0aSgarbled #endif
98*d974db0aSgarbled #include <dev/marvell/gtreg.h>
99*d974db0aSgarbled #include <dev/marvell/gtvar.h>
100*d974db0aSgarbled #include <dev/marvell/gtintrreg.h>
101*d974db0aSgarbled 
102*d974db0aSgarbled #include <uvm/uvm_extern.h>
103*d974db0aSgarbled 
104*d974db0aSgarbled #if defined(DEBUG) && defined(DDB)
105*d974db0aSgarbled #endif
106*d974db0aSgarbled 
107*d974db0aSgarbled #ifdef DEBUG
108*d974db0aSgarbled # define STATIC
109*d974db0aSgarbled int intrdebug = 0;
110*d974db0aSgarbled # define DPRINTF(x)		do { if (intrdebug) printf x ; } while (0)
111*d974db0aSgarbled # define DPRINTFN(n, x)		do { if (intrdebug > (n)) printf x ; } while (0)
112*d974db0aSgarbled #else
113*d974db0aSgarbled # define STATIC static
114*d974db0aSgarbled # define DPRINTF(x)
115*d974db0aSgarbled # define DPRINTFN(n, x)
116*d974db0aSgarbled #endif
117*d974db0aSgarbled 
118*d974db0aSgarbled #ifdef DIAGNOSTIC
119*d974db0aSgarbled # define DIAGPRF(x)		printf x
120*d974db0aSgarbled #else
121*d974db0aSgarbled # define DIAGPRF(x)
122*d974db0aSgarbled #endif
123*d974db0aSgarbled 
124*d974db0aSgarbled #define ILLEGAL_IRQ(x) (((x) < 0) || ((x) >= NIRQ) || \
125*d974db0aSgarbled 		 ((1<<((x)&IMASK_BITMASK)) & imres.bits[(x)>>IMASK_WORDSHIFT]))
126*d974db0aSgarbled 
127*d974db0aSgarbled extern struct powerpc_bus_space gt_mem_bs_tag;
128*d974db0aSgarbled extern bus_space_handle_t gt_memh;
129*d974db0aSgarbled 
130*d974db0aSgarbled static const char intr_source_strings[NIRQ][16] = {
131*d974db0aSgarbled 	"unknown 0",	"dev",		"dma",		"cpu",
132*d974db0aSgarbled 	"idma 01",	"idma 23",	"idma 45",	"idma 67",
133*d974db0aSgarbled 	"timer 01",	"timer 23",	"timer 45",	"timer 67",
134*d974db0aSgarbled 	"pci0-0",	"pci0-1",	"pci0-2",	"pci0-3",
135*d974db0aSgarbled /*16*/	"pci1-0",	"ecc",		"pci1-1",	"pci1-2",
136*d974db0aSgarbled 	"pci1-3",	"pci0-outl",	"pci0-outh",	"pci1-outl",
137*d974db0aSgarbled 	"pci1-outh",	"unknown 25",	"pci0-inl",	"pci0-inh",
138*d974db0aSgarbled 	"pci1-inl",	"pci1-inh",	"unknown 30",	"unknown 31",
139*d974db0aSgarbled /*32*/	"ether 0",	"ether 1",	"ether 2",	"unknown 35",
140*d974db0aSgarbled 	"sdma",		"iic",		"unknown 38",	"brg",
141*d974db0aSgarbled 	"mpsc 0",	"unknown 41",	"mpsc 1",	"comm",
142*d974db0aSgarbled 	"unknown 44",	"unknown 45",	"unknown 46",	"unknown 47",
143*d974db0aSgarbled /*48*/	"unknown 48",	"unknown 49",	"unknown 50",	"unknown 51",
144*d974db0aSgarbled 	"unknown 52",	"unknown 53",	"unknown 54",	"unknown 55",
145*d974db0aSgarbled 	"gppsum 0",	"gppsum 1",	"gppsum 2",	"gppsum 3",
146*d974db0aSgarbled 	"unknown 60",	"unknown 61",	"unknown 62",	"unknown 63",
147*d974db0aSgarbled };
148*d974db0aSgarbled 
149*d974db0aSgarbled struct discovery_pic_ops {
150*d974db0aSgarbled 	struct pic_ops dsc_pic;
151*d974db0aSgarbled 	bus_space_tag_t dsc_memt;
152*d974db0aSgarbled 	bus_space_tag_t dsc_memh;
153*d974db0aSgarbled 	uint32_t dsc_interrupt_mask[2];
154*d974db0aSgarbled 	uint8_t dsc_priority[64];
155*d974db0aSgarbled 	uint8_t dsc_maxpriority[64];
156*d974db0aSgarbled };
157*d974db0aSgarbled 
158*d974db0aSgarbled struct gpp_pic_ops {
159*d974db0aSgarbled 	struct pic_ops gpp_pic;
160*d974db0aSgarbled 	bus_space_tag_t gpp_memt;
161*d974db0aSgarbled 	bus_space_handle_t gpp_memh;
162*d974db0aSgarbled 	uint32_t gpp_interrupt_mask;
163*d974db0aSgarbled 	uint8_t gpp_priority[32];
164*d974db0aSgarbled 	uint8_t gpp_maxpriority[32];
165*d974db0aSgarbled };
166*d974db0aSgarbled 
167*d974db0aSgarbled static void
168*d974db0aSgarbled gpp_source_name(struct pic_ops *pic, int irq, char *name, size_t len)
169*d974db0aSgarbled {
170*d974db0aSgarbled 	snprintf(name, len, "gpp %d", irq);
171*d974db0aSgarbled }
172*d974db0aSgarbled 
173*d974db0aSgarbled #define GPP_RES ~GT_MPP_INTERRUPTS	/* from config */
174*d974db0aSgarbled 
175*d974db0aSgarbled static int
176*d974db0aSgarbled gpp_get_irq(struct pic_ops *pic)
177*d974db0aSgarbled {
178*d974db0aSgarbled 	struct gpppic_ops * const gpp = (void *)pic;
179*d974db0aSgarbled 	uint32_t mask;
180*d974db0aSgarbled 	int maybe_irq = -1;
181*d974db0aSgarbled 	int maybe_priority = IPL_NONE;
182*d974db0aSgarbled 
183*d974db0aSgarbled #ifdef GPP_EDGE
184*d974db0aSgarbled 	mask = bus_space_read_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Cause);
185*d974db0aSgarbled #else
186*d974db0aSgarbled 	mask = bus_space_read_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Value);
187*d974db0aSgarbled #endif
188*d974db0aSgarbled 	mask &= gpp->gpp_interrupt_mask;
189*d974db0aSgarbled 	if (mask == 0)
190*d974db0aSgarbled 		return NO_IRQ;
191*d974db0aSgarbled 
192*d974db0aSgarbled 	while (mask != 0) {
193*d974db0aSgarbled 		int irq = 32 - __builtin_clz(mask);
194*d974db0aSgarbled 		if (gpp->gpp_priority[irq] > maybe_irq) {
195*d974db0aSgarbled 			maybe_irq = irq;
196*d974db0aSgarbled 			maybe_priority = gpp->gpp_priority[irq];
197*d974db0aSgarbled 			if (maybe_priority > gpp->gpp_maxpriority[irq])
198*d974db0aSgarbled 				break;
199*d974db0aSgarbled 		}
200*d974db0aSgarbled 		mask &= ~(1 << irq);
201*d974db0aSgarbled 	}
202*d974db0aSgarbled 	/*
203*d974db0aSgarbled 	 * We now have the highest priority IRQ.
204*d974db0aSgarbled 	 */
205*d974db0aSgarbled 	KASSERT(maybe_irq >= 0);
206*d974db0aSgarbled #ifdef GPP_EDGE
207*d974db0aSgarbled 	mask = 1 << maybe_irq;
208*d974db0aSgarbled 	bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Cause, mask);
209*d974db0aSgarbled #endif
210*d974db0aSgarbled 
211*d974db0aSgarbled 	return maybe_irq;
212*d974db0aSgarbled }
213*d974db0aSgarbled 
214*d974db0aSgarbled static void
215*d974db0aSgarbled gpp_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
216*d974db0aSgarbled {
217*d974db0aSgarbled 	struct gpppic_ops * const gpp = (void *)pic;
218*d974db0aSgarbled 	const uint32_t mask = 1 << irq;
219*d974db0aSgarbled 
220*d974db0aSgarbled 	KASSERT((unsigned) irq < 32);
221*d974db0aSgarbled #ifdef GPP_EDGE
222*d974db0aSgarbled 	KASSERT(type == IST_EDGE);
223*d974db0aSgarbled #else
224*d974db0aSgarbled 	KASSERT(type == IST_LEVEL);
225*d974db0aSgarbled #endif
226*d974db0aSgarbled 
227*d974db0aSgarbled 	/*
228*d974db0aSgarbled 	 * Set pin to input and active low.
229*d974db0aSgarbled 	 */
230*d974db0aSgarbled 	val = bus_space_read_4(gpp->gpp_memt, gpp->gpp_memh, GT_GPP_IO_Control);
231*d974db0aSgarbled 	val &= ~mask;
232*d974db0aSgarbled 	bus_space_write_4(gpp->gpp_memt, gpp->gpp_memh, GT_GPP_IO_Control, val);
233*d974db0aSgarbled 
234*d974db0aSgarbled 	val = bus_space_read_4(gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Level_Control);
235*d974db0aSgarbled 	val |= mask;
236*d974db0aSgarbled 	bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Level_Control, val);
237*d974db0aSgarbled 
238*d974db0aSgarbled 	gpp->gpp_priority[irq] = pri;
239*d974db0aSgarbled 
240*d974db0aSgarbled 	/*
241*d974db0aSgarbled 	 * recalculate the maxpriority of an interrupt.  This is highest
242*d974db0aSgarbled 	 * priority interrupt from itself to gpp0.
243*d974db0aSgarbled 	 */
244*d974db0aSgarbled 	pri = IPL_NONE;
245*d974db0aSgarbled 	for (i = 0; i < __arraycount(gpp->gpp_priority); i++) {
246*d974db0aSgarbled 		if (gpp->gpp_priority[i] > pri)
247*d974db0aSgarbled 			pri = gpp->gpp_priority[i];
248*d974db0aSgarbled 		gpp->gpp_maxpriority[i] = pri;
249*d974db0aSgarbled 	}
250*d974db0aSgarbled }
251*d974db0aSgarbled 
252*d974db0aSgarbled static void
253*d974db0aSgarbled gpp_enable_irq(struct pic_ops *pic, int irq, int type)
254*d974db0aSgarbled {
255*d974db0aSgarbled 	struct gpppic_ops * const gpp = (void *)pic;
256*d974db0aSgarbled 	const uint32_t mask = 1 << irq;
257*d974db0aSgarbled 
258*d974db0aSgarbled 	KASSERT(type == IST_LEVEL);
259*d974db0aSgarbled 	KASSERT(gpp->gpp_priority[irq] != IPL_NONE);
260*d974db0aSgarbled 	gpp->gpp_interrupt_mask |= mask;
261*d974db0aSgarbled 	bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Mask,
262*d974db0aSgarbled 	    gpp->gpp_interrupt_mask);
263*d974db0aSgarbled }
264*d974db0aSgarbled 
265*d974db0aSgarbled static void
266*d974db0aSgarbled gpp_disable_irq(struct pic_ops *pic, int irq)
267*d974db0aSgarbled {
268*d974db0aSgarbled 	struct gpppic_ops * const gpp = (void *)pic;
269*d974db0aSgarbled 	const uint32_t mask = 1 << irq;
270*d974db0aSgarbled 
271*d974db0aSgarbled 	gpp->gpp_interrupt_mask &= ~mask;
272*d974db0aSgarbled 	bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, GT_GPP_Interrupt_Mask,
273*d974db0aSgarbled 	    gpp->gpp_interrupt_mask);
274*d974db0aSgarbled }
275*d974db0aSgarbled 
276*d974db0aSgarbled static void
277*d974db0aSgarbled gpp_ack_irq(struct pic_ops *pic, int irq)
278*d974db0aSgarbled {
279*d974db0aSgarbled }
280*d974db0aSgarbled 
281*d974db0aSgarbled static struct pic_ops *
282*d974db0aSgarbled gpp_pic_setup(bus_space_tag_t memt, bus_space_handle_t memh)
283*d974db0aSgarbled {
284*d974db0aSgarbled 	struct gpppic_ops * gpp;
285*d974db0aSgarbled 	uint32_t val;
286*d974db0aSgarbled 
287*d974db0aSgarbled 	gpp = malloc(sizeof(*gpp), M_DEVBUF, M_NOWAIT|M_ZERO);
288*d974db0aSgarbled 	if (!gpp)
289*d974db0aSgarbled 		panic("gpp_pic_setup: malloc(%zu) failed", sizeof(*gpp));
290*d974db0aSgarbled 
291*d974db0aSgarbled 	gpp->gpp_memt = memt;
292*d974db0aSgarbled 	gpp->gpp_memh = memh;
293*d974db0aSgarbled 	gpp->gpp_pic.pic_get_irq = gpp_get_irq;
294*d974db0aSgarbled 	gpp->gpp_pic.pic_enable_irq = gpp_enable_irq;
295*d974db0aSgarbled 	gpp->gpp_pic.pic_reenable_irq = gpp_enable_irq;
296*d974db0aSgarbled 	gpp->gpp_pic.pic_disable_irq = gpp_disable_irq;
297*d974db0aSgarbled 	gpp->gpp_pic.pic_ack_irq = gpp_ack_irq;
298*d974db0aSgarbled 	gpp->gpp_pic.pic_establish_irq = gpp_establish_irq;
299*d974db0aSgarbled 	gpp->gpp_pic.pic_source_name = gpp_source_name;
300*d974db0aSgarbled 
301*d974db0aSgarbled 	/*
302*d974db0aSgarbled 	 * Force GPP interrupts to be level sensitive.
303*d974db0aSgarbled 	 */
304*d974db0aSgarbled 	val = bus_space_read_4(&gpp->gpp_memt, gpp->gpp_memh, 0xf300);
305*d974db0aSgarbled 	bus_space_write_4(&gpp->gpp_memt, gpp->gpp_memh, 0xf300, val | 0x400);
306*d974db0aSgarbled 
307*d974db0aSgarbled 	pic_add(&gpp->gpp_pic);
308*d974db0aSgarbled 
309*d974db0aSgarbled 	return &gpp->gpp_pic;
310*d974db0aSgarbled }
311*d974db0aSgarbled 
312*d974db0aSgarbled static void
313*d974db0aSgarbled discovery_source_name(struct pic_ops *pic, int irq, char *name, size_t len)
314*d974db0aSgarbled {
315*d974db0aSgarbled 	strlcpy(name, discovery_intr_source_strings[irq], len);
316*d974db0aSgarbled }
317*d974db0aSgarbled 
318*d974db0aSgarbled static int
319*d974db0aSgarbled discovery_get_irq(struct pic_ops *pic)
320*d974db0aSgarbled {
321*d974db0aSgarbled 	struct discoverypic_ops * const dsc = (void *)pic;
322*d974db0aSgarbled 	uint32_t mask;
323*d974db0aSgarbled 	int irq_base = 0;
324*d974db0aSgarbled 	int maybe_irq = -1;
325*d974db0aSgarbled 	int maybe_priority = IPL_NONE;
326*d974db0aSgarbled 
327*d974db0aSgarbled 	mask = bus_space_read_4(&dsc->dsc_memt, dsc->dsc_memh, ICR_CSC);
328*d974db0aSgarbled 	if (!(mask & CSC_STAT))
329*d974db0aSgarbled 		return NO_IRQ;
330*d974db0aSgarbled 	irq_base = (mask & CSC_SEL) ? 32 : 0;
331*d974db0aSgarbled 	mask &= dsc->dsc_interrupt_mask[(mask & CSC_SEL) ? 1 : 0];
332*d974db0aSgarbled 	while (mask != 0) {
333*d974db0aSgarbled 		int irq = 32 - __builtin_clz(mask);
334*d974db0aSgarbled 		if (dsc->dsc_priority[irq_base + irq] > maybe_irq) {
335*d974db0aSgarbled 			maybe_irq = irq_base + irq;
336*d974db0aSgarbled 			maybe_priority = dsc->dsc_priority[irq_base + irq];
337*d974db0aSgarbled 			if (maybe_priority > dsc->dsc_maxpriority[irq_base + irq])
338*d974db0aSgarbled 				break;
339*d974db0aSgarbled 		}
340*d974db0aSgarbled 		mask &= ~(1 << irq);
341*d974db0aSgarbled 	}
342*d974db0aSgarbled 	/*
343*d974db0aSgarbled 	 * We now have the highest priority IRQ (except it's cascaded).
344*d974db0aSgarbled 	 */
345*d974db0aSgarbled 	KASSERT(maybe_irq >= 0);
346*d974db0aSgarbled 	return maybe_irq;
347*d974db0aSgarbled }
348*d974db0aSgarbled 
349*d974db0aSgarbled static void
350*d974db0aSgarbled discovery_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
351*d974db0aSgarbled {
352*d974db0aSgarbled 	struct discoverypic_ops * const dsc = (void *)pic;
353*d974db0aSgarbled 
354*d974db0aSgarbled 	KASSERT((unsigned) irq < 32);
355*d974db0aSgarbled #ifdef GPP_EDGE
356*d974db0aSgarbled 	KASSERT(type == IST_EDGE);
357*d974db0aSgarbled #else
358*d974db0aSgarbled 	KASSERT(type == IST_LEVEL);
359*d974db0aSgarbled #endif
360*d974db0aSgarbled 
361*d974db0aSgarbled 	dsc->dsc_priority[irq] = pri;
362*d974db0aSgarbled 
363*d974db0aSgarbled 	/*
364*d974db0aSgarbled 	 * recalculate the maxpriority of an interrupt.  This is highest
365*d974db0aSgarbled 	 * priority interrupt from itself to irq 0.
366*d974db0aSgarbled 	 */
367*d974db0aSgarbled 	pri = IPL_NONE;
368*d974db0aSgarbled 	for (i = 0; i < __arraycount(dsc->dsc_priority); i++) {
369*d974db0aSgarbled 		if (dsc->dsc_priority[i] > pri)
370*d974db0aSgarbled 			pri = dsc->dsc_priority[i];
371*d974db0aSgarbled 		dsc->dsc_maxpriority[i] = pri;
372*d974db0aSgarbled 	}
373*d974db0aSgarbled }
374*d974db0aSgarbled 
375*d974db0aSgarbled static void
376*d974db0aSgarbled discovery_enable_irq(struct pic_ops *pic, int irq, int type)
377*d974db0aSgarbled {
378*d974db0aSgarbled 	struct discoverypic_ops * const dsc = (void *)pic;
379*d974db0aSgarbled 	const uint32_t mask = 1 << (irq & 31);
380*d974db0aSgarbled 
381*d974db0aSgarbled 	KASSERT(type == IST_LEVEL);
382*d974db0aSgarbled 	KASSERT(dsc->dsc_priority[irq] != IPL_NONE);
383*d974db0aSgarbled 	if (irq < 32) {
384*d974db0aSgarbled 		dsc->dsc_interrupt_mask[0] |= mask;
385*d974db0aSgarbled 		bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
386*d974db0aSgarbled 		    ICR_MIC_LO, dsc->dsc_interrupt_mask[0]);
387*d974db0aSgarbled 	} else {
388*d974db0aSgarbled 		dsc->dsc_interrupt_mask[1] |= mask;
389*d974db0aSgarbled 		bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
390*d974db0aSgarbled 		    ICR_MIC_HI, dsc->dsc_interrupt_mask[1]);
391*d974db0aSgarbled 	}
392*d974db0aSgarbled }
393*d974db0aSgarbled 
394*d974db0aSgarbled static void
395*d974db0aSgarbled discovery_disable_irq(struct pic_ops *pic, int irq)
396*d974db0aSgarbled {
397*d974db0aSgarbled 	struct discoverypic_ops * const dsc = (void *)pic;
398*d974db0aSgarbled 	const uint32_t mask = 1 << (irq & 31);
399*d974db0aSgarbled 
400*d974db0aSgarbled 	if (irq < 32) {
401*d974db0aSgarbled 		dsc->dsc_interrupt_mask[0] &= ~mask;
402*d974db0aSgarbled 		bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
403*d974db0aSgarbled 		    ICR_MIC_LO, dsc->dsc_interrupt_mask[0]);
404*d974db0aSgarbled 	} else {
405*d974db0aSgarbled 		dsc->dsc_interrupt_mask[1] &= ~mask;
406*d974db0aSgarbled 		bus_space_write_4(&dsc->dsc_memt, dsc->dsc_memh,
407*d974db0aSgarbled 		    ICR_MIC_HI, dsc->dsc_interrupt_mask[1]);
408*d974db0aSgarbled 	}
409*d974db0aSgarbled }
410*d974db0aSgarbled 
411*d974db0aSgarbled static void
412*d974db0aSgarbled discovery_ack_irq(struct pic_ops *pic, int irq)
413*d974db0aSgarbled {
414*d974db0aSgarbled }
415*d974db0aSgarbled 
416*d974db0aSgarbled void
417*d974db0aSgarbled discoverypic_setup(bus_space_tag_t memt, bus_space_handle_t memh)
418*d974db0aSgarbled {
419*d974db0aSgarbled 	struct discoverypic_ops *dsc;
420*d974db0aSgarbled 	uint32_t val;
421*d974db0aSgarbled 
422*d974db0aSgarbled 	dsc = malloc(sizeof(*dsc), M_DEVBUF, M_NOWAIT|M_ZERO);
423*d974db0aSgarbled 	if (!dsc)
424*d974db0aSgarbled 		panic("dsc_pic_setup: malloc(%zu) failed", sizeof(*dsc));
425*d974db0aSgarbled 
426*d974db0aSgarbled 	dsc->dsc_memt = memt;
427*d974db0aSgarbled 	dsc->dsc_memh = memh;
428*d974db0aSgarbled 	dsc->dsc_pic.pic_get_irq = dsc_get_irq;
429*d974db0aSgarbled 	dsc->dsc_pic.pic_enable_irq = dsc_enable_irq;
430*d974db0aSgarbled 	dsc->dsc_pic.pic_reenable_irq = dsc_enable_irq;
431*d974db0aSgarbled 	dsc->dsc_pic.pic_disable_irq = dsc_disable_irq;
432*d974db0aSgarbled 	dsc->dsc_pic.pic_ack_irq = dsc_ack_irq;
433*d974db0aSgarbled 	dsc->dsc_pic.pic_establish_irq = dsc_establish_irq;
434*d974db0aSgarbled 	dsc->dsc_pic.pic_source_name = dsc_source_name;
435*d974db0aSgarbled 
436*d974db0aSgarbled 	pic_add(&dsc->dsc_pic);
437*d974db0aSgarbled 	KASSERT(dsc->dsc_pic.pic_intrbase == 0);
438*d974db0aSgarbled 
439*d974db0aSgarbled 	pic = dscpic_setup(memt, memh);
440*d974db0aSgarbled 	intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP7_0,
441*d974db0aSgarbled 	    IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
442*d974db0aSgarbled 	intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP15_8,
443*d974db0aSgarbled 	    IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
444*d974db0aSgarbled 	intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP23_16,
445*d974db0aSgarbled 	    IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
446*d974db0aSgarbled 	intr_establish(dsc->dsc_pic.pic_intrbase + IRQ_GPP31_24,
447*d974db0aSgarbled 	    IST_LEVEL, IPL_NONE, pic_handle_intr, pic);
448*d974db0aSgarbled }
449