isabus.c revision 1.10 1 /* $NetBSD: isabus.c,v 1.10 2000/06/09 05:42:01 soda Exp $ */
2 /* $OpenBSD: isabus.c,v 1.15 1998/03/16 09:38:46 pefo Exp $ */
3 /* NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp */
4
5 /*-
6 * Copyright (c) 1995 Per Fogelstrom
7 * Copyright (c) 1993, 1994 Charles M. Hannum.
8 * Copyright (c) 1990 The Regents of the University of California.
9 * All rights reserved.
10 *
11 * This code is derived from software contributed to Berkeley by
12 * William Jolitz and Don Ahn.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the University of
25 * California, Berkeley and its contributors.
26 * 4. Neither the name of the University nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 * @(#)isa.c 7.2 (Berkeley) 5/12/91
43 */
44 /*
45 * Mach Operating System
46 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
47 * All Rights Reserved.
48 *
49 * Permission to use, copy, modify and distribute this software and its
50 * documentation is hereby granted, provided that both the copyright
51 * notice and this permission notice appear in all copies of the
52 * software, derivative works or modified versions, and any portions
53 * thereof, and that both notices appear in supporting documentation.
54 *
55 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
56 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
57 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
58 *
59 * Carnegie Mellon requests users of this software to return to
60 *
61 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
62 * School of Computer Science
63 * Carnegie Mellon University
64 * Pittsburgh PA 15213-3890
65 *
66 * any improvements or extensions that they make and grant Carnegie Mellon
67 * the rights to redistribute these changes.
68 */
69 /*
70 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
71
72 All Rights Reserved
73
74 Permission to use, copy, modify, and distribute this software and
75 its documentation for any purpose and without fee is hereby
76 granted, provided that the above copyright notice appears in all
77 copies and that both the copyright notice and this permission notice
78 appear in supporting documentation, and that the name of Intel
79 not be used in advertising or publicity pertaining to distribution
80 of the software without specific, written prior permission.
81
82 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
83 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
84 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
85 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
86 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
87 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
88 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
89 */
90
91 #include <sys/param.h>
92 #include <sys/proc.h>
93 #include <sys/user.h>
94 #include <sys/systm.h>
95 #include <sys/callout.h>
96 #include <sys/time.h>
97 #include <sys/kernel.h>
98 #include <sys/device.h>
99 #include <sys/malloc.h>
100 #include <vm/vm.h>
101
102 #include <machine/cpu.h>
103 #include <machine/pio.h>
104 #include <machine/autoconf.h>
105 #include <machine/intr.h>
106
107 #include <arc/arc/arctype.h>
108 #include <arc/pica/pica.h>
109 #include <arc/pica/rd94.h>
110
111 #include <dev/isa/isareg.h>
112 #include <dev/isa/isavar.h>
113 #include <arc/isa/timerreg.h>
114 #include <arc/isa/spkrreg.h>
115 #include <machine/isa_machdep.h>
116
117 static int beeping;
118 static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
119
120 #define IRQ_SLAVE 2
121 #define ICU_LEN 16
122
123 struct isabr_softc {
124 struct device sc_dv;
125 struct arc_isa_bus arc_isa_cs;
126 struct abus sc_bus;
127 };
128
129 /* Definition of the driver for autoconfig. */
130 int isabrmatch(struct device *, struct cfdata *, void *);
131 void isabrattach(struct device *, struct device *, void *);
132 int isabrprint(void *, const char *);
133
134 struct cfattach isabr_ca = {
135 sizeof(struct isabr_softc), isabrmatch, isabrattach
136 };
137 extern struct cfdriver isabr_cd;
138
139 extern struct arc_bus_space arc_bus_io, arc_bus_mem;
140
141 const struct evcnt *isabr_intr_evcnt __P((isa_chipset_tag_t, int));
142 void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int,
143 int (*)(void *), void *));
144 void isabr_intr_disestablish __P((isa_chipset_tag_t, void*));
145 int isabr_iointr __P((unsigned int, struct clockframe *));
146 void isabr_initicu __P((void));
147 void intr_calculatemasks __P((void));
148 int fakeintr __P((void *a));
149
150 int
151 isabrmatch(parent, match, aux)
152 struct device *parent;
153 struct cfdata *match;
154 void *aux;
155 {
156 struct confargs *ca = aux;
157
158 /* Make sure that we're looking for a ISABR. */
159 if (strcmp(ca->ca_name, isabr_cd.cd_name) != 0)
160 return (0);
161
162 return (1);
163 }
164
165 void
166 isabrattach(parent, self, aux)
167 struct device *parent;
168 struct device *self;
169 void *aux;
170 {
171 struct isabr_softc *sc = (struct isabr_softc *)self;
172 struct isabus_attach_args iba;
173
174 printf("\n");
175
176 /* Initialize interrupt controller */
177 isabr_initicu();
178
179 /* set up interrupt handlers */
180 switch(cputype) {
181 case ACER_PICA_61:
182 case MAGNUM:
183 case NEC_R94:
184 case NEC_R96:
185 set_intr(MIPS_INT_MASK_2, isabr_iointr, 3);
186 break;
187 case DESKSTATION_TYNE:
188 set_intr(MIPS_INT_MASK_2, isabr_iointr, 2);
189 break;
190 case DESKSTATION_RPC44:
191 set_intr(MIPS_INT_MASK_2, isabr_iointr, 2);
192 break;
193 default:
194 panic("isabrattach: unkown cputype!");
195 }
196
197 /*XXX we may remove the abus part of the softc struct... */
198 sc->sc_bus.ab_dv = (struct device *)sc;
199 sc->sc_bus.ab_type = BUS_ISABR;
200
201 sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
202 sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
203 sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
204
205 iba.iba_busname = "isa";
206 iba.iba_iot = (bus_space_tag_t)&arc_bus_io;
207 iba.iba_memt = (bus_space_tag_t)&arc_bus_mem;
208 iba.iba_ic = &sc->arc_isa_cs;
209 config_found(self, &iba, isabrprint);
210 }
211
212 int
213 isabrprint(aux, pnp)
214 void *aux;
215 const char *pnp;
216 {
217 struct confargs *ca = aux;
218
219 if (pnp)
220 printf("%s at %s", ca->ca_name, pnp);
221 printf(" isa_io_base 0x%lx isa_mem_base 0x%lx",
222 arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
223 return (UNCONF);
224 }
225
226
227 /*
228 * Interrupt system driver code
229 * ============================
230 */
231 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
232
233 int imen;
234 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
235 struct intrhand *intrhand[ICU_LEN];
236
237 int fakeintr(a)
238 void *a;
239 {
240 return 0;
241 }
242
243 /*
244 * Recalculate the interrupt masks from scratch.
245 * We could code special registry and deregistry versions of this function that
246 * would be faster, but the code would be nastier, and we don't expect this to
247 * happen very much anyway.
248 */
249 void
250 intr_calculatemasks()
251 {
252 int irq, level;
253 struct intrhand *q;
254
255 /* First, figure out which levels each IRQ uses. */
256 for (irq = 0; irq < ICU_LEN; irq++) {
257 register int levels = 0;
258 for (q = intrhand[irq]; q; q = q->ih_next)
259 levels |= 1 << q->ih_level;
260 intrlevel[irq] = levels;
261 }
262
263 /* Then figure out which IRQs use each level. */
264 for (level = 0; level < 5; level++) {
265 register int irqs = 0;
266 for (irq = 0; irq < ICU_LEN; irq++)
267 if (intrlevel[irq] & (1 << level))
268 irqs |= 1 << irq;
269 imask[level] = irqs | SIR_ALLMASK;
270 }
271
272 /*
273 * There are tty, network and disk drivers that use free() at interrupt
274 * time, so imp > (tty | net | bio).
275 */
276 imask[IPL_IMP] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO];
277
278 /*
279 * Enforce a hierarchy that gives slow devices a better chance at not
280 * dropping data.
281 */
282 imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO];
283 imask[IPL_NET] |= imask[IPL_BIO];
284
285 /*
286 * These are pseudo-levels.
287 */
288 imask[IPL_NONE] = 0x00000000;
289 imask[IPL_HIGH] = 0xffffffff;
290
291 /* And eventually calculate the complete masks. */
292 for (irq = 0; irq < ICU_LEN; irq++) {
293 register int irqs = 1 << irq;
294 for (q = intrhand[irq]; q; q = q->ih_next)
295 irqs |= imask[q->ih_level];
296 intrmask[irq] = irqs | SIR_ALLMASK;
297 }
298
299 /* Lastly, determine which IRQs are actually in use. */
300 {
301 register int irqs = 0;
302 for (irq = 0; irq < ICU_LEN; irq++)
303 if (intrhand[irq])
304 irqs |= 1 << irq;
305 if (irqs >= 0x100) /* any IRQs >= 8 in use */
306 irqs |= 1 << IRQ_SLAVE;
307 imen = ~irqs;
308 isa_outb(IO_ICU1 + 1, imen);
309 isa_outb(IO_ICU2 + 1, imen >> 8);
310 }
311 }
312
313 const struct evcnt *
314 isabr_intr_evcnt(ic, irq)
315 isa_chipset_tag_t ic;
316 int irq;
317 {
318
319 /* XXX for now, no evcnt parent reported */
320 return NULL;
321 }
322
323 /*
324 * Establish a ISA bus interrupt.
325 */
326 void *
327 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
328 isa_chipset_tag_t ic;
329 int irq;
330 int type;
331 int level;
332 int (*ih_fun) __P((void *));
333 void *ih_arg;
334 {
335 struct intrhand **p, *q, *ih;
336 static struct intrhand fakehand = {NULL, fakeintr};
337 extern int cold;
338
339 /* no point in sleeping unless someone can free memory. */
340 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
341 if (ih == NULL)
342 panic("isa_intr_establish: can't malloc handler info");
343
344 if (!LEGAL_IRQ(irq) || type == IST_NONE)
345 panic("intr_establish: bogus irq or type");
346
347 switch (intrtype[irq]) {
348 case IST_EDGE:
349 case IST_LEVEL:
350 if (type == intrtype[irq])
351 break;
352 case IST_PULSE:
353 if (type != IST_NONE)
354 panic("intr_establish: can't share %s with %s",
355 isa_intr_typename(intrtype[irq]),
356 isa_intr_typename(type));
357 break;
358 }
359
360 /*
361 * Figure out where to put the handler.
362 * This is O(N^2), but we want to preserve the order, and N is
363 * generally small.
364 */
365 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
366 ;
367
368 /*
369 * Actually install a fake handler momentarily, since we might be doing
370 * this with interrupts enabled and don't want the real routine called
371 * until masking is set up.
372 */
373 fakehand.ih_level = level;
374 *p = &fakehand;
375
376 intr_calculatemasks();
377
378 /*
379 * Poke the real handler in now.
380 */
381 ih->ih_fun = ih_fun;
382 ih->ih_arg = ih_arg;
383 ih->ih_count = 0;
384 ih->ih_next = NULL;
385 ih->ih_level = level;
386 ih->ih_irq = irq;
387 ih->ih_what = ""; /* XXX - should be eliminated */
388 *p = ih;
389
390 return (ih);
391 }
392
393 void
394 isabr_intr_disestablish(ic, arg)
395 isa_chipset_tag_t ic;
396 void *arg;
397 {
398
399 }
400
401 /*
402 * Process an interrupt from the ISA bus.
403 */
404 int
405 isabr_iointr(mask, cf)
406 unsigned mask;
407 struct clockframe *cf;
408 {
409 struct intrhand *ih;
410 int isa_vector;
411 int o_imen;
412 char vector;
413
414 (void) &isa_vector; /* shut off gcc unused-variable warnings */
415
416 switch(cputype) {
417 case ACER_PICA_61:
418 case MAGNUM:
419 isa_vector = in32(R4030_SYS_ISA_VECTOR) & (ICU_LEN - 1);
420 break;
421
422 case NEC_R94:
423 case NEC_R96:
424 isa_vector = in32(RD94_SYS_INTSTAT2) & (ICU_LEN - 1);
425 break;
426
427 case DESKSTATION_TYNE:
428 isa_outb(IO_ICU1, 0x0f); /* Poll */
429 vector = isa_inb(IO_ICU1);
430 if(vector > 0 || (isa_vector = vector & 7) == 2) {
431 isa_outb(IO_ICU2, 0x0f);
432 vector = isa_inb(IO_ICU2);
433 if(vector > 0) {
434 printf("isa: spurious interrupt.\n");
435 return(~0);
436 }
437 isa_vector = (vector & 7) | 8;
438 }
439 break;
440
441 case DESKSTATION_RPC44:
442 isa_outb(IO_ICU1, 0x0f); /* Poll */
443 vector = isa_inb(IO_ICU1);
444 if(vector > 0 || (isa_vector = vector & 7) == 2) {
445 isa_outb(IO_ICU2, 0x0f);
446 vector = isa_inb(IO_ICU2);
447 if(vector > 0) {
448 printf("isa: spurious interrupt.\n");
449 return(~0);
450 }
451 isa_vector = (vector & 7) | 8;
452 }
453 break;
454 }
455
456 o_imen = imen;
457 imen |= 1 << (isa_vector & (ICU_LEN - 1));
458 if(isa_vector & 0x08) {
459 isa_inb(IO_ICU2 + 1);
460 isa_outb(IO_ICU2 + 1, imen >> 8);
461 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
462 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
463 }
464 else {
465 isa_inb(IO_ICU1 + 1);
466 isa_outb(IO_ICU1 + 1, imen);
467 isa_outb(IO_ICU1, 0x60 + isa_vector);
468 }
469 ih = intrhand[isa_vector];
470 if(isa_vector == 0) { /* Clock */ /*XXX*/
471 (*ih->ih_fun)(cf);
472 ih = ih->ih_next;
473 }
474 while(ih) {
475 (*ih->ih_fun)(ih->ih_arg);
476 ih = ih->ih_next;
477 }
478 imen = o_imen;
479 isa_inb(IO_ICU1 + 1);
480 isa_inb(IO_ICU2 + 1);
481 isa_outb(IO_ICU1 + 1, imen);
482 isa_outb(IO_ICU2 + 1, imen >> 8);
483
484 return(~0); /* Dont reenable */
485 }
486
487
488 /*
489 * Initialize the Interrupt controller logic.
490 */
491 void
492 isabr_initicu()
493 {
494
495 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
496 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */
497 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
498 isa_outb(IO_ICU1+1, 1); /* 8086 mode */
499 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
500 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */
501 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */
502 #ifdef REORDER_IRQ
503 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
504 #endif
505
506 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
507 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */
508 isa_outb(IO_ICU2+1, IRQ_SLAVE);
509 isa_outb(IO_ICU2+1, 1); /* 8086 mode */
510 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
511 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */
512 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */
513 }
514
515
516 /*
517 * SPEAKER BEEPER...
518 */
519 void
520 sysbeepstop(arg)
521 void *arg;
522 {
523 int s;
524
525 /* disable counter 2 */
526 s = splhigh();
527 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
528 splx(s);
529 beeping = 0;
530 }
531
532 void
533 sysbeep(pitch, period)
534 int pitch, period;
535 {
536 static int last_pitch, last_period;
537 int s;
538 extern int cold;
539
540 if (cold)
541 return; /* Can't beep yet. */
542
543 if (beeping)
544 callout_stop(&sysbeep_ch);
545 if (!beeping || last_pitch != pitch) {
546 s = splhigh();
547 isa_outb(IO_TIMER1 + TIMER_MODE,
548 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
549 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
550 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
551 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
552 splx(s);
553 }
554 last_pitch = pitch;
555 beeping = last_period = period;
556 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
557 }
558