xref: /netbsd-src/sys/arch/ews4800mips/ews4800mips/tr2_intr.c (revision c8da0e5fefd3800856b306200a18b2315c7fbb9f)
1 /*	$NetBSD: tr2_intr.c,v 1.10 2008/04/28 20:23:18 martin 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.10 2008/04/28 20:23:18 martin Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/intr.h>
40 
41 #include <machine/locore.h>	/* mips3_cp0* */
42 #include <machine/sbdvar.h>
43 #define	_SBD_TR2_PRIVATE
44 #include <machine/sbd_tr2.h>
45 
46 #include <mips/cpuregs.h>
47 
48 SBD_DECL(tr2);
49 
50 const uint32_t tr2_sr_bits[_IPL_N] = {
51 	[IPL_NONE] = 0,
52 	[IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
53 	[IPL_SOFTNET] =
54 	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1,
55 	[IPL_VM] =
56 	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
57 	    MIPS_INT_MASK_0 |
58 	    MIPS_INT_MASK_2 |
59 	    MIPS_INT_MASK_4,
60 	[IPL_SCHED] =
61 	    MIPS_SOFT_INT_MASK_0 | MIPS_SOFT_INT_MASK_1 |
62 	    MIPS_INT_MASK_0 |
63 	    MIPS_INT_MASK_2 |
64 	    MIPS_INT_MASK_4 |
65 	    MIPS_INT_MASK_5,
66 	/* !!! TEST !!! VME INTERRUPT IS NOT MASKED */
67 };
68 
69 #define	NIRQ		8
70 struct tr2_intr_handler {
71 	int (*func)(void *);
72 	void *arg;
73 	volatile uint8_t *picnic_reg;
74 	uint8_t picnic_mask;
75 	struct evcnt evcnt;
76 	char evname[32];
77 } tr2_intr_handler[NIRQ] = {
78 	[0] = { NULL, NULL, PICNIC_INT4_MASK_REG, PICNIC_INT_KBMS },
79 	[2] = { NULL, NULL, PICNIC_INT4_MASK_REG, PICNIC_INT_SERIAL },
80 	[5] = { NULL, NULL, PICNIC_INT2_MASK_REG, PICNIC_INT_SCSI },
81 	[6] = { NULL, NULL, PICNIC_INT2_MASK_REG, PICNIC_INT_ETHER },
82 	[7] = { NULL, NULL, PICNIC_INT0_MASK_REG, PICNIC_INT_FDDLPT },
83 };
84 
85 struct evcnt timer_tr2_ev =
86     EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "picnic", "timer");
87 
88 void
89 tr2_intr_init(void)
90 {
91 	uint32_t a = (uint32_t)ews4800mips_nmi_vec;
92 
93 	/* Install dump button handler address to NVSRAM (jumped from ROM) */
94 	*(NVSRAM_CDUMP_ADDR + 0) = (a >> 24) & 0xff;
95 	*(NVSRAM_CDUMP_ADDR + 4) = (a >> 16) & 0xff;
96 	*(NVSRAM_CDUMP_ADDR + 8) = (a >> 8) & 0xff;
97 	*(NVSRAM_CDUMP_ADDR +12) = a & 0xff;
98 
99 	/* Disable external interrupts */
100 	*PICNIC_INT0_MASK_REG = 0;
101 	*PICNIC_INT2_MASK_REG = 0;
102 	*PICNIC_INT4_MASK_REG = 0;
103 	*PICNIC_INT5_MASK_REG = 0;
104 
105 	evcnt_attach_static(&timer_tr2_ev);
106 }
107 
108 void *
109 tr2_intr_establish(int irq, int (*func)(void *), void *arg)
110 {
111 	struct tr2_intr_handler *ih = &tr2_intr_handler[irq];
112 	int s;
113 
114 	s = splhigh();
115 	ih->func = func;
116 	ih->arg = arg;
117 	snprintf(ih->evname, sizeof(ih->evname), "irq %d", irq);
118 	evcnt_attach_dynamic(&ih->evcnt, EVCNT_TYPE_INTR, NULL,
119 	    "picnic", ih->evname);
120 
121 	*ih->picnic_reg |= ih->picnic_mask;
122 	splx(s);
123 
124 	return (void *)irq;
125 }
126 
127 void
128 tr2_intr_disestablish(void *arg)
129 {
130 	int s, irq = (int)arg;
131 	struct tr2_intr_handler *ih = &tr2_intr_handler[irq];
132 
133 	s = splhigh();
134 	*ih->picnic_reg &= ~ih->picnic_mask;
135 	ih->func = NULL;
136 	ih->arg = NULL;
137 	evcnt_detach(&ih->evcnt);
138 	splx(s);
139 }
140 
141 void
142 tr2_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
143 {
144 	struct tr2_intr_handler *ih;
145 	struct clockframe cf;
146 	uint32_t r, handled;
147 
148 	handled = 0;
149 
150 	if (ipending & MIPS_INT_MASK_5) {	/* CLOCK */
151 		cf.pc = pc;
152 		cf.sr = status;
153 
154 		*PICNIC_INT5_STATUS_REG = 0;
155 		r = *PICNIC_INT5_STATUS_REG;
156 
157 		hardclock(&cf);
158 		timer_tr2_ev.ev_count++;
159 		handled |= MIPS_INT_MASK_5;
160 	}
161 	_splset((status & handled) | MIPS_SR_INT_IE);
162 
163 	if (ipending & MIPS_INT_MASK_4) {	/* KBD, MOUSE, SERIAL */
164 		r = *PICNIC_INT4_STATUS_REG;
165 
166 		if (r & PICNIC_INT_KBMS) {
167 			ih = &tr2_intr_handler[0];
168 			if (ih->func) {
169 				ih->func(ih->arg);
170 				ih->evcnt.ev_count++;
171 			}
172 			r &= ~PICNIC_INT_KBMS;
173 		}
174 
175 		if (r & PICNIC_INT_SERIAL) {
176 #if 0
177 			printf("SIO interrupt\n");
178 #endif
179 			ih = &tr2_intr_handler[2];
180 			if (ih->func) {
181 				ih->func(ih->arg);
182 				ih->evcnt.ev_count++;
183 			}
184 			r &= ~PICNIC_INT_SERIAL;
185 		}
186 
187 		handled |= MIPS_INT_MASK_4;
188 	}
189 	_splset((status & handled) | MIPS_SR_INT_IE);
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 		    ((cause & status) & 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 		handled |= MIPS_INT_MASK_2;
239 	}
240 	_splset((status & handled) | MIPS_SR_INT_IE);
241 
242 	if (ipending & MIPS_INT_MASK_1)
243 		panic("unknown interrupt INT1\n");
244 
245 	if (ipending & MIPS_INT_MASK_0) {	/* FDD, PRINTER */
246 		printf("printer, printer interrupt\n");
247 		r = *PICNIC_INT0_STATUS_REG;
248 		if (r & PICNIC_INT_FDDLPT) {
249 			printf("FDD, Printer interrupt.\n");
250 		} else {
251 			printf("unknown interrupt INT0\n");
252 		}
253 		handled |= MIPS_INT_MASK_0;
254 	}
255 	cause &= ~handled;
256 	_splset(((status & ~cause) & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
257 }
258 
259 void
260 tr2_initclocks(void)
261 {
262 
263 	/* Enable clock interrupt */
264 	*PICNIC_INT5_MASK_REG |= PICNIC_INT_CLOCK;
265 }
266