1 /*	$NetBSD: tr2a_intr.c,v 1.15 2011/03/10 17:05:41 tsutsui Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
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 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: tr2a_intr.c,v 1.15 2011/03/10 17:05:41 tsutsui Exp $");
34 
35 #define __INTR_PRIVATE
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/evcnt.h>
40 #include <sys/lwp.h>
41 #include <sys/cpu.h>
42 #include <sys/intr.h>
43 
44 #include <machine/locore.h>	/* mips3_cp0* */
45 #include <machine/sbdvar.h>
46 #define	_SBD_TR2A_PRIVATE
47 #include <machine/sbd_tr2a.h>
48 
49 SBD_DECL(tr2a);
50 
51 const struct ipl_sr_map tr2a_ipl_sr_map = {
52     .sr_bits = {
53 	[IPL_NONE] = 0,
54 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
55 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK,
56 	[IPL_VM] =		MIPS_INT_MASK & ~MIPS_INT_MASK_5,
57 	[IPL_SCHED] =		MIPS_INT_MASK,
58 	[IPL_DDB] =		MIPS_INT_MASK,
59 	[IPL_HIGH] =		MIPS_INT_MASK,
60     },
61 };
62 
63 #define	NIRQ		16
64 enum bustype {
65 	ASOBUS,
66 	APBUS,
67 };
68 
69 /* ASO + APbus interrupt */
70 struct tr2a_intr_handler {
71 	int (*func)(void *);
72 	void *arg;
73 	enum bustype bustype;
74 	uint32_t cpu_int;
75 	uint32_t aso_mask;
76 	struct evcnt evcnt;
77 	char evname[32];
78 } tr2a_intr_handler[NIRQ] = {
79 	[0]  = { NULL, NULL, ASOBUS, 2, 0x00000001 },	/* AM79C90 */
80 	[4]  = { NULL, NULL, ASOBUS, 4, 0x00300010 },	/* Z85230 (SIO) */
81 	[6]  = { NULL, NULL, ASOBUS, 2, 0x00000200 },	/* 53C710 SCSI-A */
82 	[9]  = { NULL, NULL, ASOBUS, 4, 0x00000040 },	/* Z85230 (KBMS) */
83 	[10] = { NULL, NULL, ASOBUS, 2, 0x00000100 },	/* 53C710 SCSI-B */
84 };
85 
86 /* CPU interrupt */
87 struct tr2a_intc_handler {
88 	int ref_cnt;
89 	uint32_t mask;
90 } tr2a_intc_handler[6] = {
91 	[0] = { 0, 0x00000020 },
92 	[1] = { 0, 0x00000800 },
93 	[2] = { 0, 0x00010000 },
94 	[3] = { 0, 0x00200000 },
95 	[4] = { 0, 0x04000000 },
96 	[5] = { 0, 0x80000000 }
97 };
98 
99 struct evcnt timer_tr2a_ev =
100     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "intc", "timer");
101 
102 void
tr2a_intr_init(void)103 tr2a_intr_init(void)
104 {
105 
106 	/* Disable all ASObus interrupt */
107 #if 1
108 	*ASO_INT_MASK_REG &= ~TR2A_ASO_INTMASK_ALL;
109 #else
110 	/* open all interrupt for development. */
111 	*ASO_INT_MASK_REG |= TR2A_ASO_INTMASK_ALL;
112 #endif
113 	tr2a_wbflush();
114 
115 	/* set up interval timer clock */
116 	*INTC_MASK_REG = 0;
117 	*CLOCK_REG = 0x80;
118 	tr2a_wbflush();
119 	if ((*CLOCK_REG & 0x80) != 0)
120 		*ASO_INT_MASK_REG |= 0x8000;	/* NMI (what UX does.) -uch */
121 	tr2a_wbflush();
122 
123 	evcnt_attach_static(&timer_tr2a_ev);
124 }
125 
126 void *
tr2a_intr_establish(int irq,int (* func)(void *),void * arg)127 tr2a_intr_establish(int irq, int (*func)(void *), void *arg)
128 {
129 	struct tr2a_intr_handler *ih = &tr2a_intr_handler[irq];
130 	struct tr2a_intc_handler *ic = &tr2a_intc_handler[ih->cpu_int];
131 	int s;
132 
133 	s = splhigh();
134 	ih->func = func;
135 	ih->arg  = arg;
136 	snprintf(ih->evname, sizeof(ih->evname), "irq %d", irq);
137 	evcnt_attach_dynamic(&ih->evcnt, EVCNT_TYPE_INTR,
138 	    NULL, "intc", ih->evname);
139 
140 	if (ih->bustype == ASOBUS)
141 		*ASO_INT_MASK_REG |= ih->aso_mask;
142 
143 	if (ic->ref_cnt++ == 0)
144 		*INTC_MASK_REG |= ic->mask;
145 
146 	tr2a_wbflush();
147 	splx(s);
148 
149 	return (void *)irq;
150 }
151 
152 void
tr2a_intr_disestablish(void * arg)153 tr2a_intr_disestablish(void *arg)
154 {
155 	int s, irq = (int)arg;
156 	struct tr2a_intr_handler *ih = &tr2a_intr_handler[irq];
157 	struct tr2a_intc_handler *ic = &tr2a_intc_handler[ih->cpu_int];
158 
159 	s = splhigh();
160 	if (ih->bustype == ASOBUS)
161 		*ASO_INT_MASK_REG &= ~ih->aso_mask;
162 
163 	if (--ic->ref_cnt == 0)
164 		*INTC_MASK_REG &= ~ic->mask;
165 
166 	ih->func = NULL;
167 	ih->arg = NULL;
168 	evcnt_detach(&ih->evcnt);
169 	splx(s);
170 }
171 
172 void
tr2a_intr(int ppl,vaddr_t pc,uint32_t status)173 tr2a_intr(int ppl, vaddr_t pc, uint32_t status)
174 {
175 	struct tr2a_intr_handler *ih;
176 	struct clockframe cf;
177 	uint32_t r, intc_cause, ipending;
178 	int ipl;
179 
180 	intc_cause = *INTC_STATUS_REG & *INTC_MASK_REG;
181 
182 	while (ppl < (ipl = splintr(&ipending))) {
183 		if ((ipending & MIPS_INT_MASK_5) && (intc_cause & INTC_INT5)) {
184 			cf.pc = pc;
185 			cf.sr = status;
186 			cf.intr = (curcpu()->ci_idepth > 1);
187 			tr2a_wbflush();
188 			*INTC_CLEAR_REG = 0x7c;
189 			*INTC_STATUS_REG;
190 
191 			hardclock(&cf);
192 			timer_tr2a_ev.ev_count++;
193 		}
194 
195 		if ((ipending & MIPS_INT_MASK_4) && (intc_cause & INTC_INT4)) {
196 			/* KBD, MOUSE, SERIAL */
197 			r = *ASO_INT_STATUS_REG;
198 			if (r & 0x300010) {
199 				ih = &tr2a_intr_handler[4];
200 				if (ih->func) {
201 					ih->func(ih->arg);
202 					ih->evcnt.ev_count++;
203 				}
204 			} else if (r & 0x40) {
205 				/* kbms */
206 				ih = &tr2a_intr_handler[9];
207 				if (ih->func) {
208 					ih->func(ih->arg);
209 					ih->evcnt.ev_count++;
210 				}
211 			} else if (r & 0x20) {
212 				printf("INT4 (1)\n");
213 			} else if (r & 0x00800000) {
214 				printf("INT4 (2)\n");
215 			} else if (r & 0x00400000) {
216 				printf("INT4 (3)\n");
217 			} else if (r != 0) {
218 				printf("not for INT4 %x\n", r);
219 			}
220 
221 			tr2a_wbflush();
222 			*INTC_CLEAR_REG = 0x68;
223 			*INTC_STATUS_REG;
224 		}
225 
226 		if ((ipending & MIPS_INT_MASK_3) && (intc_cause & INTC_INT3)) {
227 			/* APbus HI */
228 			printf("APbus HI\n");
229 			tr2a_wbflush();
230 			*INTC_CLEAR_REG = 0x54;
231 			*INTC_STATUS_REG;
232 		}
233 
234 		if ((ipending & MIPS_INT_MASK_2) && (intc_cause & INTC_INT2)) {
235 			/* SCSI, ETHER */
236 			r = *ASO_INT_STATUS_REG;
237 			if (r & 0x100) {	/* SCSI-A */
238 				ih = &tr2a_intr_handler[6];
239 				if (ih->func) {
240 					ih->func(ih->arg);
241 					ih->evcnt.ev_count++;
242 				}
243 			} else if (r & 0x200) {	/* SCSI-B */
244 				ih = &tr2a_intr_handler[10];
245 				if (ih->func) {
246 					ih->func(ih->arg);
247 					ih->evcnt.ev_count++;
248 				}
249 			} else if (r & 0x1) {	/* LANCE */
250 				ih = &tr2a_intr_handler[0];
251 				if (ih->func) {
252 					ih->func(ih->arg);
253 					ih->evcnt.ev_count++;
254 				}
255 			} else if (r != 0) {
256 				printf("not for INT2 %x %x\n", r,
257 				    *ASO_DMAINT_STATUS_REG);
258 			}
259 
260 			tr2a_wbflush();
261 			*INTC_CLEAR_REG = 0x40;
262 			*INTC_STATUS_REG;
263 		}
264 
265 		if ((ipending & MIPS_INT_MASK_1) && (intc_cause & INTC_INT1)) {
266 			/* APbus LO */
267 			printf("APbus LO\n");
268 			tr2a_wbflush();
269 			*INTC_CLEAR_REG = 0x2c;
270 			*INTC_STATUS_REG;
271 		}
272 
273 		if ((ipending & MIPS_INT_MASK_0) && (intc_cause & INTC_INT0)) {
274 			/* NMI etc. */
275 			r = *ASO_INT_STATUS_REG;
276 			printf("INT0 %08x\n", r);
277 			if (r & 0x8000) {
278 				printf("INT0(1) NMI\n");
279 			} else if (r & 0x8) {
280 				printf("INT0(2)\n");
281 			} else if (r & 0x4) {
282 				printf("INT0(3)\n");
283 			} else if (r != 0) {
284 				printf("not for INT0 %x\n", r);
285 			}
286 			tr2a_wbflush();
287 			*INTC_CLEAR_REG = 0x14;
288 			*INTC_STATUS_REG;
289 		}
290 		intc_cause = *INTC_STATUS_REG & *INTC_MASK_REG;
291 	}
292 }
293 
294 void
tr2a_initclocks(void)295 tr2a_initclocks(void)
296 {
297 
298 	/* Enable INT5 */
299 	*INTC_MASK_REG |= INTC_INT5;
300 	tr2a_wbflush();
301 }
302