xref: /netbsd-src/sys/arch/playstation2/ee/intc.c (revision aad6ef8bb53467e46ac6eaf569f9972623d96e56)
1*aad6ef8bSmartin /*	$NetBSD: intc.c,v 1.8 2014/03/31 11:25:49 martin Exp $	*/
2*aad6ef8bSmartin 
3*aad6ef8bSmartin /*-
4*aad6ef8bSmartin  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5*aad6ef8bSmartin  * All rights reserved.
6*aad6ef8bSmartin  *
7*aad6ef8bSmartin  * This code is derived from software contributed to The NetBSD Foundation
8*aad6ef8bSmartin  * by UCHIYAMA Yasushi.
9*aad6ef8bSmartin  *
10*aad6ef8bSmartin  * Redistribution and use in source and binary forms, with or without
11*aad6ef8bSmartin  * modification, are permitted provided that the following conditions
12*aad6ef8bSmartin  * are met:
13*aad6ef8bSmartin  * 1. Redistributions of source code must retain the above copyright
14*aad6ef8bSmartin  *    notice, this list of conditions and the following disclaimer.
15*aad6ef8bSmartin  * 2. Redistributions in binary form must reproduce the above copyright
16*aad6ef8bSmartin  *    notice, this list of conditions and the following disclaimer in the
17*aad6ef8bSmartin  *    documentation and/or other materials provided with the distribution.
18*aad6ef8bSmartin  *
19*aad6ef8bSmartin  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*aad6ef8bSmartin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*aad6ef8bSmartin  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*aad6ef8bSmartin  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*aad6ef8bSmartin  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*aad6ef8bSmartin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*aad6ef8bSmartin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*aad6ef8bSmartin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*aad6ef8bSmartin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*aad6ef8bSmartin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*aad6ef8bSmartin  * POSSIBILITY OF SUCH DAMAGE.
30*aad6ef8bSmartin  */
31*aad6ef8bSmartin 
32*aad6ef8bSmartin #include <sys/cdefs.h>
33*aad6ef8bSmartin __KERNEL_RCSID(0, "$NetBSD: intc.c,v 1.8 2014/03/31 11:25:49 martin Exp $");
34*aad6ef8bSmartin 
35*aad6ef8bSmartin #include "debug_playstation2.h"
36*aad6ef8bSmartin 
37*aad6ef8bSmartin #include <sys/param.h>
38*aad6ef8bSmartin #include <sys/systm.h>
39*aad6ef8bSmartin 
40*aad6ef8bSmartin #include <playstation2/ee/eevar.h>
41*aad6ef8bSmartin #include <playstation2/ee/intcvar.h>
42*aad6ef8bSmartin #include <playstation2/ee/intcreg.h>
43*aad6ef8bSmartin #include <playstation2/ee/gsvar.h>	/* debug monitor */
44*aad6ef8bSmartin 
45*aad6ef8bSmartin #include <playstation2/playstation2/interrupt.h>
46*aad6ef8bSmartin 
47*aad6ef8bSmartin #ifdef DEBUG
48*aad6ef8bSmartin #define LEGAL_CHANNEL(x)	((x) >= 0 && (x) <= 15)
49*aad6ef8bSmartin #define STATIC
50*aad6ef8bSmartin #else
51*aad6ef8bSmartin #define STATIC	static
52*aad6ef8bSmartin #endif
53*aad6ef8bSmartin 
54*aad6ef8bSmartin #define _INTC_NINTR	16
55*aad6ef8bSmartin 
56*aad6ef8bSmartin u_int32_t __intc_enabled_channel;
57*aad6ef8bSmartin 
58*aad6ef8bSmartin STATIC int __intc_initialized;
59*aad6ef8bSmartin STATIC struct _ipl_dispatcher __intc_dispatcher[_INTC_NINTR];
60*aad6ef8bSmartin STATIC struct _ipl_holder __intc_ipl_holder[_IPL_N];
61*aad6ef8bSmartin 
62*aad6ef8bSmartin STATIC SLIST_HEAD(, _ipl_dispatcher) __intc_dispatcher_head =
63*aad6ef8bSmartin  SLIST_HEAD_INITIALIZER(__intc_dispatcher_head);
64*aad6ef8bSmartin 
65*aad6ef8bSmartin void
intc_init(void)66*aad6ef8bSmartin intc_init(void)
67*aad6ef8bSmartin {
68*aad6ef8bSmartin 	int i;
69*aad6ef8bSmartin 
70*aad6ef8bSmartin 	if (__intc_initialized++)
71*aad6ef8bSmartin 		return;
72*aad6ef8bSmartin 
73*aad6ef8bSmartin 	/* disable all channel */
74*aad6ef8bSmartin 	for (i = 0; i < _INTC_NINTR; i++)
75*aad6ef8bSmartin 		intc_intr_disable(i);
76*aad6ef8bSmartin 
77*aad6ef8bSmartin 	/* clear interrupts */
78*aad6ef8bSmartin 	_reg_write_4(I_STAT_REG, _reg_read_4(I_STAT_REG));
79*aad6ef8bSmartin 
80*aad6ef8bSmartin 	for (i = 0; i < _IPL_N; i++)
81*aad6ef8bSmartin 		__intc_ipl_holder[i].mask = 0xffffffff;
82*aad6ef8bSmartin }
83*aad6ef8bSmartin 
84*aad6ef8bSmartin int
intc_intr(u_int32_t mask)85*aad6ef8bSmartin intc_intr(u_int32_t mask)
86*aad6ef8bSmartin {
87*aad6ef8bSmartin 	struct _ipl_dispatcher *dispatcher;
88*aad6ef8bSmartin 	u_int32_t r, dispatch, pending;
89*aad6ef8bSmartin 
90*aad6ef8bSmartin 	r = _reg_read_4(I_STAT_REG);
91*aad6ef8bSmartin 	dispatch = r & ~mask & __intc_enabled_channel;
92*aad6ef8bSmartin 	pending = r & mask & __intc_enabled_channel;
93*aad6ef8bSmartin 
94*aad6ef8bSmartin #if 0
95*aad6ef8bSmartin 	__gsfb_print(1,
96*aad6ef8bSmartin 	    "INTC stat=%08x, mask=%08x, pend=%08x, disp=%08x enable=%08x\n",
97*aad6ef8bSmartin 	    r, mask, pending, dispatch, __intc_enabled_channel);
98*aad6ef8bSmartin #endif
99*aad6ef8bSmartin 	if (dispatch == 0)
100*aad6ef8bSmartin 		return (pending == 0 ? 1 : 0);
101*aad6ef8bSmartin 
102*aad6ef8bSmartin 	/* clear interrupt */
103*aad6ef8bSmartin 	_reg_write_4(I_STAT_REG, dispatch);
104*aad6ef8bSmartin 
105*aad6ef8bSmartin 	/* dispatch interrupt handler */
106*aad6ef8bSmartin 	SLIST_FOREACH(dispatcher, &__intc_dispatcher_head, link) {
107*aad6ef8bSmartin 		if (dispatcher->bit & dispatch) {
108*aad6ef8bSmartin 			KDASSERT(dispatcher->func);
109*aad6ef8bSmartin 			(*dispatcher->func)(dispatcher->arg);
110*aad6ef8bSmartin 			dispatch &= ~dispatcher->bit;
111*aad6ef8bSmartin 		}
112*aad6ef8bSmartin 	}
113*aad6ef8bSmartin 
114*aad6ef8bSmartin 	/* disable spurious interrupt source */
115*aad6ef8bSmartin 	if (dispatch) {
116*aad6ef8bSmartin 		int i, bit;
117*aad6ef8bSmartin 		for (i = 0, bit = 1; i < _INTC_NINTR; i++, bit <<= 1) {
118*aad6ef8bSmartin 			if (bit & dispatch) {
119*aad6ef8bSmartin 				intc_intr_disable(i);
120*aad6ef8bSmartin 				printf("%s: spurious interrupt %d disabled.\n",
121*aad6ef8bSmartin 				    __func__, i);
122*aad6ef8bSmartin 			}
123*aad6ef8bSmartin 		}
124*aad6ef8bSmartin 	}
125*aad6ef8bSmartin 
126*aad6ef8bSmartin 	return (pending == 0 ? 1 : 0);
127*aad6ef8bSmartin }
128*aad6ef8bSmartin 
129*aad6ef8bSmartin void
intc_intr_enable(enum intc_channel ch)130*aad6ef8bSmartin intc_intr_enable(enum intc_channel ch)
131*aad6ef8bSmartin {
132*aad6ef8bSmartin 	u_int32_t mask;
133*aad6ef8bSmartin 
134*aad6ef8bSmartin 	KDASSERT(LEGAL_CHANNEL(ch));
135*aad6ef8bSmartin 	mask = 1 << ch;
136*aad6ef8bSmartin 	_reg_write_4(I_MASK_REG, (_reg_read_4(I_MASK_REG) & mask) ^ mask);
137*aad6ef8bSmartin }
138*aad6ef8bSmartin 
139*aad6ef8bSmartin void
intc_intr_disable(enum intc_channel ch)140*aad6ef8bSmartin intc_intr_disable(enum intc_channel ch)
141*aad6ef8bSmartin {
142*aad6ef8bSmartin 
143*aad6ef8bSmartin 	KDASSERT(LEGAL_CHANNEL(ch));
144*aad6ef8bSmartin 	_reg_write_4(I_MASK_REG, _reg_read_4(I_MASK_REG) & (1 << ch));
145*aad6ef8bSmartin }
146*aad6ef8bSmartin 
147*aad6ef8bSmartin void
intc_update_mask(u_int32_t mask)148*aad6ef8bSmartin intc_update_mask(u_int32_t mask)
149*aad6ef8bSmartin {
150*aad6ef8bSmartin 	u_int32_t cur_mask;
151*aad6ef8bSmartin 
152*aad6ef8bSmartin 	cur_mask = _reg_read_4(I_MASK_REG);
153*aad6ef8bSmartin 
154*aad6ef8bSmartin 	_reg_write_4(I_MASK_REG, ((cur_mask ^ ~mask) | (cur_mask & mask)) &
155*aad6ef8bSmartin 	    __intc_enabled_channel);
156*aad6ef8bSmartin }
157*aad6ef8bSmartin 
158*aad6ef8bSmartin void *
intc_intr_establish(enum intc_channel ch,int ipl,int (* func)(void *),void * arg)159*aad6ef8bSmartin intc_intr_establish(enum intc_channel ch, int ipl, int (*func)(void *),
160*aad6ef8bSmartin     void *arg)
161*aad6ef8bSmartin {
162*aad6ef8bSmartin 	struct _ipl_dispatcher *dispatcher = &__intc_dispatcher[ch];
163*aad6ef8bSmartin 	struct _ipl_dispatcher *d;
164*aad6ef8bSmartin 	u_int32_t bit;
165*aad6ef8bSmartin 	int i, s;
166*aad6ef8bSmartin 
167*aad6ef8bSmartin 	KDASSERT(dispatcher->func == NULL);
168*aad6ef8bSmartin 
169*aad6ef8bSmartin 	s = _intr_suspend();
170*aad6ef8bSmartin 	dispatcher->func = func;
171*aad6ef8bSmartin 	dispatcher->arg = arg;
172*aad6ef8bSmartin 	dispatcher->ipl = ipl;
173*aad6ef8bSmartin 	dispatcher->channel = ch;
174*aad6ef8bSmartin 	dispatcher->bit = bit = (1 << ch);
175*aad6ef8bSmartin 
176*aad6ef8bSmartin 	for (i = 0; i < _IPL_N; i++)
177*aad6ef8bSmartin 		if (i < ipl)
178*aad6ef8bSmartin 			__intc_ipl_holder[i].mask &= ~bit;
179*aad6ef8bSmartin 		else
180*aad6ef8bSmartin 			__intc_ipl_holder[i].mask |= bit;
181*aad6ef8bSmartin 
182*aad6ef8bSmartin 	/* insert queue IPL order */
183*aad6ef8bSmartin 	if (SLIST_EMPTY(&__intc_dispatcher_head)) {
184*aad6ef8bSmartin 		SLIST_INSERT_HEAD(&__intc_dispatcher_head, dispatcher, link);
185*aad6ef8bSmartin 	} else {
186*aad6ef8bSmartin 		SLIST_FOREACH(d, &__intc_dispatcher_head, link) {
187*aad6ef8bSmartin 			if (SLIST_NEXT(d, link) == 0 ||
188*aad6ef8bSmartin 			    SLIST_NEXT(d, link)->ipl < ipl) {
189*aad6ef8bSmartin 				SLIST_INSERT_AFTER(d, dispatcher, link);
190*aad6ef8bSmartin 				break;
191*aad6ef8bSmartin 			}
192*aad6ef8bSmartin 		}
193*aad6ef8bSmartin 	}
194*aad6ef8bSmartin 
195*aad6ef8bSmartin 	md_ipl_register(IPL_INTC, __intc_ipl_holder);
196*aad6ef8bSmartin 
197*aad6ef8bSmartin 	intc_intr_enable(ch);
198*aad6ef8bSmartin 	__intc_enabled_channel |= bit;
199*aad6ef8bSmartin 
200*aad6ef8bSmartin 	_intr_resume(s);
201*aad6ef8bSmartin 
202*aad6ef8bSmartin 	return ((void *)ch);
203*aad6ef8bSmartin }
204*aad6ef8bSmartin 
205*aad6ef8bSmartin void
intc_intr_disestablish(void * handle)206*aad6ef8bSmartin intc_intr_disestablish(void *handle)
207*aad6ef8bSmartin {
208*aad6ef8bSmartin 	int ch = (int)(handle);
209*aad6ef8bSmartin 	struct _ipl_dispatcher *dispatcher = &__intc_dispatcher[ch];
210*aad6ef8bSmartin 	u_int32_t bit;
211*aad6ef8bSmartin 	int i, s;
212*aad6ef8bSmartin 
213*aad6ef8bSmartin 	s = _intr_suspend();
214*aad6ef8bSmartin 
215*aad6ef8bSmartin 	intc_intr_disable(ch);
216*aad6ef8bSmartin 	dispatcher->func = NULL;
217*aad6ef8bSmartin 
218*aad6ef8bSmartin 	SLIST_REMOVE(&__intc_dispatcher_head, dispatcher,
219*aad6ef8bSmartin 	    _ipl_dispatcher, link);
220*aad6ef8bSmartin 
221*aad6ef8bSmartin 	bit = dispatcher->bit;
222*aad6ef8bSmartin 	for (i = 0; i < _IPL_N; i++)
223*aad6ef8bSmartin 		__intc_ipl_holder[i].mask |= bit;
224*aad6ef8bSmartin 
225*aad6ef8bSmartin 	md_ipl_register(IPL_INTC, __intc_ipl_holder);
226*aad6ef8bSmartin 	__intc_enabled_channel &= ~bit;
227*aad6ef8bSmartin 
228*aad6ef8bSmartin 	_intr_resume(s);
229*aad6ef8bSmartin }
230*aad6ef8bSmartin 
231