xref: /netbsd-src/sys/arch/ews4800mips/ews4800mips/tr2_intr.c (revision 8e8cc5afced64f769fdd4f2f1268c24d02d74e04)
1 /*	$NetBSD: tr2_intr.c,v 1.12 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: tr2_intr.c,v 1.12 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/cpu.h>
41 #include <sys/lwp.h>
42 #include <sys/intr.h>
43 
44 #include <machine/locore.h>	/* mips3_cp0* */
45 #include <machine/sbdvar.h>
46 #define	_SBD_TR2_PRIVATE
47 #include <machine/sbd_tr2.h>
48 
49 #include <mips/cpuregs.h>
50 
51 SBD_DECL(tr2);
52 
53 const struct ipl_sr_map tr2_ipl_sr_map = {
54     {
55 	[IPL_NONE] =		0,
56 	[IPL_SOFTCLOCK] =	MIPS_SOFT_INT_MASK_0,
57 	[IPL_SOFTNET] =		MIPS_SOFT_INT_MASK,
58 	[IPL_VM] =		MIPS_SOFT_INT_MASK
59 				| MIPS_INT_MASK_0
60 				| MIPS_INT_MASK_2
61 				| MIPS_INT_MASK_4,
62 	[IPL_SCHED] =		MIPS_SOFT_INT_MASK
63 				| MIPS_INT_MASK_0
64 				| MIPS_INT_MASK_2
65 				| MIPS_INT_MASK_4
66 				| MIPS_INT_MASK_5,
67 	[IPL_DDB] =		MIPS_INT_MASK,
68 	[IPL_HIGH] =		MIPS_INT_MASK,
69 	/* !!! TEST !!! VME INTERRUPT IS NOT MASKED */
70     },
71 };
72 
73 #define	NIRQ		8
74 struct tr2_intr_handler {
75 	int (*func)(void *);
76 	void *arg;
77 	volatile uint8_t *picnic_reg;
78 	uint8_t picnic_mask;
79 	struct evcnt evcnt;
80 	char evname[32];
81 } tr2_intr_handler[NIRQ] = {
82 	[0] = { NULL, NULL, PICNIC_INT4_MASK_REG, PICNIC_INT_KBMS },
83 	[2] = { NULL, NULL, PICNIC_INT4_MASK_REG, PICNIC_INT_SERIAL },
84 	[5] = { NULL, NULL, PICNIC_INT2_MASK_REG, PICNIC_INT_SCSI },
85 	[6] = { NULL, NULL, PICNIC_INT2_MASK_REG, PICNIC_INT_ETHER },
86 	[7] = { NULL, NULL, PICNIC_INT0_MASK_REG, PICNIC_INT_FDDLPT },
87 };
88 
89 struct evcnt timer_tr2_ev =
90     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "picnic", "timer");
91 
92 void
tr2_intr_init(void)93 tr2_intr_init(void)
94 {
95 	uint32_t a = (uint32_t)ews4800mips_nmi_vec;
96 
97 	/* Install dump button handler address to NVSRAM (jumped from ROM) */
98 	*(NVSRAM_CDUMP_ADDR + 0) = (a >> 24) & 0xff;
99 	*(NVSRAM_CDUMP_ADDR + 4) = (a >> 16) & 0xff;
100 	*(NVSRAM_CDUMP_ADDR + 8) = (a >> 8) & 0xff;
101 	*(NVSRAM_CDUMP_ADDR +12) = a & 0xff;
102 
103 	/* Disable external interrupts */
104 	*PICNIC_INT0_MASK_REG = 0;
105 	*PICNIC_INT2_MASK_REG = 0;
106 	*PICNIC_INT4_MASK_REG = 0;
107 	*PICNIC_INT5_MASK_REG = 0;
108 
109 	evcnt_attach_static(&timer_tr2_ev);
110 }
111 
112 void *
tr2_intr_establish(int irq,int (* func)(void *),void * arg)113 tr2_intr_establish(int irq, int (*func)(void *), void *arg)
114 {
115 	struct tr2_intr_handler *ih = &tr2_intr_handler[irq];
116 	int s;
117 
118 	s = splhigh();
119 	ih->func = func;
120 	ih->arg = arg;
121 	snprintf(ih->evname, sizeof(ih->evname), "irq %d", irq);
122 	evcnt_attach_dynamic(&ih->evcnt, EVCNT_TYPE_INTR, NULL,
123 	    "picnic", ih->evname);
124 
125 	*ih->picnic_reg |= ih->picnic_mask;
126 	splx(s);
127 
128 	return (void *)irq;
129 }
130 
131 void
tr2_intr_disestablish(void * arg)132 tr2_intr_disestablish(void *arg)
133 {
134 	int s, irq = (int)arg;
135 	struct tr2_intr_handler *ih = &tr2_intr_handler[irq];
136 
137 	s = splhigh();
138 	*ih->picnic_reg &= ~ih->picnic_mask;
139 	ih->func = NULL;
140 	ih->arg = NULL;
141 	evcnt_detach(&ih->evcnt);
142 	splx(s);
143 }
144 
145 void
tr2_intr(int ppl,vaddr_t pc,uint32_t status)146 tr2_intr(int ppl, vaddr_t pc, uint32_t status)
147 {
148 	struct tr2_intr_handler *ih;
149 	struct clockframe cf;
150 	uint32_t r, ipending;
151 	int ipl;
152 
153 	while (ppl < (ipl = splintr(&ipending))) {
154 		if (ipending & MIPS_INT_MASK_5) {	/* CLOCK */
155 			cf.pc = pc;
156 			cf.sr = status;
157 			cf.intr = (curcpu()->ci_idepth > 1);
158 
159 			*PICNIC_INT5_STATUS_REG = 0;
160 			r = *PICNIC_INT5_STATUS_REG;
161 
162 			hardclock(&cf);
163 			timer_tr2_ev.ev_count++;
164 		}
165 
166 		if (ipending & MIPS_INT_MASK_4) {	/* KBD, MOUSE, SERIAL */
167 			r = *PICNIC_INT4_STATUS_REG;
168 
169 			if (r & PICNIC_INT_KBMS) {
170 				ih = &tr2_intr_handler[0];
171 				if (ih->func) {
172 					ih->func(ih->arg);
173 					ih->evcnt.ev_count++;
174 				}
175 				r &= ~PICNIC_INT_KBMS;
176 			}
177 
178 			if (r & PICNIC_INT_SERIAL) {
179 #if 0
180 				printf("SIO interrupt\n");
181 #endif
182 				ih = &tr2_intr_handler[2];
183 				if (ih->func) {
184 					ih->func(ih->arg);
185 					ih->evcnt.ev_count++;
186 				}
187 				r &= ~PICNIC_INT_SERIAL;
188 			}
189 		}
190 
191 		if (ipending & MIPS_INT_MASK_3) {	/* VME */
192 			printf("VME interrupt\n");
193 
194 			r = *(volatile uint32_t *)0xbfb00018; /* NABI? */
195 			if ((r & 0x10) != 0) {
196 				/* vme high interrupt */
197 			} else if ((r & 0x4) != 0) {
198 				/* vme lo interrupt */
199 			} else {
200 				/* error */
201 			}
202 		}
203 
204 		if (ipending & MIPS_INT_MASK_2) {	/* ETHER, SCSI */
205 			r = *PICNIC_INT2_STATUS_REG;
206 
207 			if (r & PICNIC_INT_ETHER) {
208 				ih = &tr2_intr_handler[6];
209 				if (ih->func) {
210 					ih->func(ih->arg);
211 					ih->evcnt.ev_count++;
212 				}
213 				r &= ~PICNIC_INT_ETHER;
214 			}
215 
216 			if (r & PICNIC_INT_SCSI) {
217 				ih = &tr2_intr_handler[5];
218 				if (ih->func) {
219 					ih->func(ih->arg);
220 					ih->evcnt.ev_count++;
221 				}
222 				r &= ~PICNIC_INT_SCSI;
223 			}
224 
225 			if ((r & PICNIC_INT_FDDLPT) &&
226 			    (ipending & MIPS_INT_MASK_5)) {
227 #ifdef DEBUG
228 				printf("FDD LPT interrupt\n");
229 #endif
230 				ih = &tr2_intr_handler[7];
231 				if (ih->func) {
232 					ih->func(ih->arg);
233 					ih->evcnt.ev_count++;
234 				}
235 				r &= ~PICNIC_INT_FDDLPT;
236 			}
237 		}
238 
239 		if (ipending & MIPS_INT_MASK_1)
240 			panic("unknown interrupt INT1\n");
241 
242 		if (ipending & MIPS_INT_MASK_0) {	/* FDD, PRINTER */
243 #ifdef DEBUG
244 			printf("printer, printer interrupt\n");
245 #endif
246 			r = *PICNIC_INT0_STATUS_REG;
247 			if (r & PICNIC_INT_FDDLPT) {
248 #ifdef DEBUG
249 				printf("FDD, Printer interrupt.\n");
250 #endif
251 			} else {
252 				printf("unknown interrupt INT0\n");
253 			}
254 		}
255 	}
256 }
257 
258 void
tr2_initclocks(void)259 tr2_initclocks(void)
260 {
261 
262 	/* Enable clock interrupt */
263 	*PICNIC_INT5_MASK_REG |= PICNIC_INT_CLOCK;
264 }
265