xref: /netbsd-src/sys/arch/sgimips/dev/int.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: int.c,v 1.9 2004/07/08 10:10:49 sekiya Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 Christopher SEKIYA
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * INT/INT2/INT3 interrupt controller (used in Indy's, Indigo's, etc..)
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: int.c,v 1.9 2004/07/08 10:10:49 sekiya Exp $");
36 
37 #include "opt_cputype.h"
38 
39 #include <sys/param.h>
40 #include <sys/proc.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/device.h>
44 #include <sys/malloc.h>
45 
46 #include <dev/ic/i8253reg.h>
47 #include <machine/sysconf.h>
48 #include <machine/machtype.h>
49 #include <machine/bus.h>
50 #include <mips/locore.h>
51 
52 #include <mips/cache.h>
53 
54 #include <sgimips/dev/int2reg.h>
55 #include <sgimips/dev/int2var.h>
56 
57 static bus_space_handle_t ioh;
58 static bus_space_tag_t iot;
59 
60 struct int_softc {
61 	struct device sc_dev;
62 };
63 
64 
65 static int	int_match(struct device *, struct cfdata *, void *);
66 static void	int_attach(struct device *, struct device *, void *);
67 void 		int_local0_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
68 void		int_local1_intr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
69 int 		int_mappable_intr(void *);
70 void		*int_intr_establish(int, int, int (*)(void *), void *);
71 unsigned long	int_cal_timer(void);
72 void		int_8254_cal(void);
73 
74 CFATTACH_DECL(int, sizeof(struct int_softc),
75 	int_match, int_attach, NULL, NULL);
76 
77 static int
78 int_match(struct device *parent, struct cfdata *match, void *aux)
79 {
80 
81 	if ((mach_type == MACH_SGI_IP12) || (mach_type == MACH_SGI_IP20) ||
82 	    (mach_type == MACH_SGI_IP22) )
83 		return 1;
84 
85 	return 0;
86 }
87 
88 static void
89 int_attach(struct device *parent, struct device *self, void *aux)
90 {
91 	u_int32_t address;
92 
93 	if (mach_type == MACH_SGI_IP12)
94 		address = INT_IP12;
95 	else if (mach_type == MACH_SGI_IP20)
96 		address = INT_IP20;
97 	else if (mach_type == MACH_SGI_IP22) {
98 		if (mach_subtype == MACH_SGI_IP22_FULLHOUSE)
99 			address = INT_IP22;
100 		else
101 			address = INT_IP24;
102 	} else
103 		panic("\nint0: passed match, but failed attach?");
104 
105 	printf(" addr 0x%x", address);
106 
107 	bus_space_map(iot, address, 0, 0, &ioh);
108 	iot = SGIMIPS_BUS_SPACE_NORMAL;
109 
110 	/* Clean out interrupt masks */
111 	bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, 0);
112 	bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, 0);
113 	bus_space_write_4(iot, ioh, INT2_MAP_MASK0, 0);
114 	bus_space_write_4(iot, ioh, INT2_MAP_MASK1, 0);
115 
116 	/* Reset timer interrupts */
117 	bus_space_write_4(iot, ioh, INT2_TIMER_CLEAR, 0x03);
118 
119 	switch (mach_type) {
120 		case MACH_SGI_IP12:
121 			platform.intr1 = int_local0_intr;
122 			platform.intr2 = int_local1_intr;
123 			int_8254_cal();
124 			break;
125 #ifdef MIPS3
126 		case MACH_SGI_IP20:
127 		case MACH_SGI_IP22:
128 		{
129 			int i;
130 			unsigned long cps;
131 			unsigned long ctrdiff[3];
132 
133 			platform.intr0 = int_local0_intr;
134 			platform.intr1 = int_local1_intr;
135 
136 			/* calibrate timer */
137 			int_cal_timer();
138 
139 			cps = 0;
140 			for (i = 0;
141 			    i < sizeof(ctrdiff) / sizeof(ctrdiff[0]); i++) {
142 				do {
143 					ctrdiff[i] = int_cal_timer();
144 				} while (ctrdiff[i] == 0);
145 
146 				cps += ctrdiff[i];
147 			}
148 
149 			cps = cps / (sizeof(ctrdiff) / sizeof(ctrdiff[0]));
150 
151 			printf(": bus %luMHz, CPU %luMHz",
152 			    cps / 10000, cps / 5000);
153 
154 			/* R4k/R4400/R4600/R5k count at half CPU frequency */
155 			curcpu()->ci_cpu_freq = 2 * cps * hz;
156 		}
157 #endif /* MIPS3 */
158 
159 			break;
160 		default:
161 			panic("int0: unsupported machine type %i\n", mach_type);
162 			break;
163 	}
164 
165 	printf("\n");
166 
167 	curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz);
168 	curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000);
169 	MIPS_SET_CI_RECIPRICAL(curcpu());
170 
171 	if (mach_type == MACH_SGI_IP22) {
172 		/* Wire interrupts 7, 11 to mappable interrupt 0,1 handlers */
173 		intrtab[7].ih_fun = int_mappable_intr;
174 		intrtab[7].ih_arg = (void*) 0;
175 
176 		intrtab[11].ih_fun = int_mappable_intr;
177 		intrtab[11].ih_arg = (void*) 1;
178 	}
179 
180 	platform.intr_establish = int_intr_establish;
181 }
182 
183 int
184 int_mappable_intr(void *arg)
185 {
186 	int i;
187 	int ret;
188 	int intnum;
189 	u_int32_t mstat;
190 	u_int32_t mmask;
191 	int which = (int)arg;
192 	struct sgimips_intrhand *ih;
193 
194 	ret = 0;
195 	mstat = bus_space_read_4(iot, ioh, INT2_MAP_STATUS);
196 	mmask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0 + (which << 2));
197 
198 	mstat &= mmask;
199 
200 	for (i = 0; i < 8; i++) {
201 		intnum = i + 16 + (which << 3);
202 		if (mstat & (1 << i)) {
203 			for (ih = &intrtab[intnum]; ih != NULL;
204 							ih = ih->ih_next) {
205 				if (ih->ih_fun != NULL)
206 					ret |= (ih->ih_fun)(ih->ih_arg);
207 				else
208 					printf("int0: unexpected mapped "
209 					       "interrupt %d\n", intnum);
210 			}
211 		}
212 	}
213 
214 	return ret;
215 }
216 
217 void
218 int_local0_intr(u_int32_t status, u_int32_t cause, u_int32_t pc,
219 		u_int32_t ipending)
220 {
221 	int i;
222 	u_int32_t l0stat;
223 	u_int32_t l0mask;
224 	struct sgimips_intrhand *ih;
225 
226 	l0stat = bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS);
227 	l0mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK);
228 
229 	/* The "FIFO full" bit is apparently not latched in the ISR, which
230 	   means that it won't be present in l0stat unless we're very lucky.
231 	   If no interrupts are pending, assume that it was caused by a full
232 	   FIFO and dispatch.
233 	 */
234 	bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, l0mask & (0xfe));
235 	if ( (l0mask & 0x01) && ((l0stat & l0mask) == 0) )
236 	  l0stat = 0x01;
237 
238 	for (i = 0; i < 8; i++) {
239 		if ( (l0stat & l0mask) & (1 << i)) {
240 			for (ih = &intrtab[i]; ih != NULL; ih = ih->ih_next) {
241 				if (ih->ih_fun != NULL)
242 					(ih->ih_fun)(ih->ih_arg);
243 				else
244 					printf("int0: unexpected local0 "
245 					       "interrupt %d\n", i);
246 			}
247 		}
248 	}
249 
250 	/* Unmask FIFO */
251 	bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, l0mask | 0x01);
252 }
253 
254 void
255 int_local1_intr(u_int32_t status, u_int32_t cause, u_int32_t pc,
256 		u_int32_t ipending)
257 {
258 	int i;
259 	u_int32_t l1stat;
260 	u_int32_t l1mask;
261 	struct sgimips_intrhand *ih;
262 
263 	l1stat = bus_space_read_4(iot, ioh, INT2_LOCAL1_STATUS);
264 	l1mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK);
265 
266 	l1stat &= l1mask;
267 
268 	for (i = 0; i < 8; i++) {
269 		if (l1stat & (1 << i)) {
270 			for (ih = &intrtab[8+i]; ih != NULL; ih = ih->ih_next) {
271 				if (ih->ih_fun != NULL)
272 					(ih->ih_fun)(ih->ih_arg);
273 				else
274 					printf("int0: unexpected local1 "
275 					       " interrupt %x\n", 8 + i);
276 			}
277 		}
278 	}
279 }
280 
281 void *
282 int_intr_establish(int level, int ipl, int (*handler) (void *), void *arg)
283 {
284 	u_int32_t mask;
285 
286 	if (level < 0 || level >= NINTR)
287 		panic("invalid interrupt level");
288 
289 	if (intrtab[level].ih_fun == NULL) {
290 		intrtab[level].ih_fun = handler;
291 		intrtab[level].ih_arg = arg;
292 		intrtab[level].ih_next = NULL;
293 	} else {
294 		struct sgimips_intrhand *n, *ih = malloc(sizeof *ih,
295 							 M_DEVBUF, M_NOWAIT);
296 
297 		if (ih == NULL) {
298 			printf("int_intr_establish: can't allocate handler\n");
299 			return (void *)NULL;
300 		}
301 
302 		ih->ih_fun = handler;
303 		ih->ih_arg = arg;
304 		ih->ih_next = NULL;
305 
306 		for (n = &intrtab[level]; n->ih_next != NULL; n = n->ih_next)
307 			;
308 
309 		n->ih_next = ih;
310 
311 		return (void *)NULL;	/* vector already set */
312 	}
313 
314 
315 	if (level < 8) {
316 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK);
317 		mask |= (1 << level);
318 		bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask);
319 	} else if (level < 16) {
320 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK);
321 		mask |= (1 << (level - 8));
322 		bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask);
323 	} else if (level < 24) {
324 		/* Map0 interrupt maps to l0 bit 7, so turn that on too */
325 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL0_MASK);
326 		mask |= (1 << 7);
327 		bus_space_write_4(iot, ioh, INT2_LOCAL0_MASK, mask);
328 
329 		mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK0);
330 		mask |= (1 << (level - 16));
331 		bus_space_write_4(iot, ioh, INT2_MAP_MASK0, mask);
332 	} else {
333 		/* Map1 interrupt maps to l1 bit 3, so turn that on too */
334 		mask = bus_space_read_4(iot, ioh, INT2_LOCAL1_MASK);
335 		mask |= (1 << 3);
336 		bus_space_write_4(iot, ioh, INT2_LOCAL1_MASK, mask);
337 
338 		mask = bus_space_read_4(iot, ioh, INT2_MAP_MASK1);
339 		mask |= (1 << (level - 24));
340 		bus_space_write_4(iot, ioh, INT2_MAP_MASK1, mask);
341 	}
342 
343 	return (void *)NULL;
344 }
345 
346 #ifdef MIPS3
347 unsigned long
348 int_cal_timer(void)
349 {
350 	int s;
351 	int roundtime;
352 	int sampletime;
353 	int startmsb, lsb, msb;
354 	unsigned long startctr, endctr;
355 
356 	/*
357 	 * NOTE: HZ must be greater than 15 for this to work, as otherwise
358 	 * we'll overflow the counter.  We round the answer to hearest 1
359 	 * MHz of the master (2x) clock.
360 	 */
361 	roundtime = (1000000 / hz) / 2;
362 	sampletime = (1000000 / hz) + 0xff;
363 	startmsb = (sampletime >> 8);
364 
365 	s = splhigh();
366 
367 	bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL,
368 		( TIMER_SEL2 | TIMER_16BIT | TIMER_RATEGEN) );
369 	bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime & 0xff));
370 	bus_space_write_4(iot, ioh, INT2_TIMER_2, (sampletime >> 8));
371 
372 	startctr = mips3_cp0_count_read();
373 
374 	/* Wait for the MSB to count down to zero */
375 	do {
376 		bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL, TIMER_SEL2 );
377 		lsb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff;
378 		msb = bus_space_read_4(iot, ioh, INT2_TIMER_2) & 0xff;
379 
380 		endctr = mips3_cp0_count_read();
381 	} while (msb);
382 
383 	/* Turn off timer */
384 	bus_space_write_4(iot, ioh, INT2_TIMER_CONTROL,
385 		( TIMER_SEL2 | TIMER_16BIT | TIMER_SWSTROBE) );
386 
387 	splx(s);
388 
389 	return (endctr - startctr) / roundtime * roundtime;
390 }
391 #endif /* MIPS3 */
392 
393 void
394 int_8254_cal(void)
395 {
396 	int s;
397 
398 	s = splhigh();
399 
400 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15,
401                                 TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
402 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) % 256);
403 	wbflush();
404 	delay(4);
405 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 3, (20000 / hz) / 256);
406 
407 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 15,
408                                 TIMER_SEL2|TIMER_RATEGEN|TIMER_16BIT);
409 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 50);
410 	wbflush();
411 	delay(4);
412 	bus_space_write_1(iot, ioh, INT2_TIMER_0 + 11, 0);
413 	splx(s);
414 }
415 
416 void
417 int2_wait_fifo(u_int32_t flag)
418 {
419 	if (ioh == 0)
420 		delay(5000);
421 	else
422 		while (bus_space_read_4(iot, ioh, INT2_LOCAL0_STATUS) & flag)
423 			;
424 }
425