int.c revision 1.10 1 /* $NetBSD: int.c,v 1.10 2005/10/18 11:31:12 tsutsui 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.10 2005/10/18 11:31:12 tsutsui 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