isabus.c revision 1.8 1 /* $NetBSD: isabus.c,v 1.8 2000/03/23 06:34:25 thorpej 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 void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int,
140 int (*)(void *), void *));
141 void isabr_intr_disestablish __P((isa_chipset_tag_t, void*));
142 int isabr_iointr __P((unsigned int, struct clockframe *));
143 void isabr_initicu __P((void));
144 void intr_calculatemasks __P((void));
145 int fakeintr __P((void *a));
146
147 int
148 isabrmatch(parent, match, aux)
149 struct device *parent;
150 struct cfdata *match;
151 void *aux;
152 {
153 struct confargs *ca = aux;
154
155 /* Make sure that we're looking for a ISABR. */
156 if (strcmp(ca->ca_name, isabr_cd.cd_name) != 0)
157 return (0);
158
159 return (1);
160 }
161
162 void
163 isabrattach(parent, self, aux)
164 struct device *parent;
165 struct device *self;
166 void *aux;
167 {
168 struct isabr_softc *sc = (struct isabr_softc *)self;
169 struct isabus_attach_args iba;
170
171 printf("\n");
172
173 /* Initialize interrupt controller */
174 isabr_initicu();
175
176 /* set up interrupt handlers */
177 switch(cputype) {
178 case ACER_PICA_61:
179 case MAGNUM:
180 case NEC_RD94:
181 set_intr(MIPS_INT_MASK_2, isabr_iointr, 3);
182 break;
183 case DESKSTATION_TYNE:
184 set_intr(MIPS_INT_MASK_2, isabr_iointr, 2);
185 break;
186 case DESKSTATION_RPC44:
187 set_intr(MIPS_INT_MASK_2, isabr_iointr, 2);
188 break;
189 default:
190 panic("isabrattach: unkown cputype!");
191 }
192
193 /*XXX we may remove the abus part of the softc struct... */
194 sc->sc_bus.ab_dv = (struct device *)sc;
195 sc->sc_bus.ab_type = BUS_ISABR;
196
197 sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
198 sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
199
200 iba.iba_busname = "isa";
201 iba.iba_iot = (bus_space_tag_t)&arc_bus_io;
202 iba.iba_memt = (bus_space_tag_t)&arc_bus_mem;
203 iba.iba_ic = &sc->arc_isa_cs;
204 config_found(self, &iba, isabrprint);
205 }
206
207 int
208 isabrprint(aux, pnp)
209 void *aux;
210 const char *pnp;
211 {
212 struct confargs *ca = aux;
213
214 if (pnp)
215 printf("%s at %s", ca->ca_name, pnp);
216 printf(" isa_io_base 0x%x isa_mem_base 0x%x",
217 arc_bus_io.bus_base, arc_bus_mem.bus_base);
218 return (UNCONF);
219 }
220
221
222 /*
223 * Interrupt system driver code
224 * ============================
225 */
226 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
227
228 int imen;
229 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
230 struct intrhand *intrhand[ICU_LEN];
231
232 int fakeintr(a)
233 void *a;
234 {
235 return 0;
236 }
237
238 /*
239 * Recalculate the interrupt masks from scratch.
240 * We could code special registry and deregistry versions of this function that
241 * would be faster, but the code would be nastier, and we don't expect this to
242 * happen very much anyway.
243 */
244 void
245 intr_calculatemasks()
246 {
247 int irq, level;
248 struct intrhand *q;
249
250 /* First, figure out which levels each IRQ uses. */
251 for (irq = 0; irq < ICU_LEN; irq++) {
252 register int levels = 0;
253 for (q = intrhand[irq]; q; q = q->ih_next)
254 levels |= 1 << q->ih_level;
255 intrlevel[irq] = levels;
256 }
257
258 /* Then figure out which IRQs use each level. */
259 for (level = 0; level < 5; level++) {
260 register int irqs = 0;
261 for (irq = 0; irq < ICU_LEN; irq++)
262 if (intrlevel[irq] & (1 << level))
263 irqs |= 1 << irq;
264 imask[level] = irqs | SIR_ALLMASK;
265 }
266
267 /*
268 * There are tty, network and disk drivers that use free() at interrupt
269 * time, so imp > (tty | net | bio).
270 */
271 imask[IPL_IMP] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO];
272
273 /*
274 * Enforce a hierarchy that gives slow devices a better chance at not
275 * dropping data.
276 */
277 imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO];
278 imask[IPL_NET] |= imask[IPL_BIO];
279
280 /*
281 * These are pseudo-levels.
282 */
283 imask[IPL_NONE] = 0x00000000;
284 imask[IPL_HIGH] = 0xffffffff;
285
286 /* And eventually calculate the complete masks. */
287 for (irq = 0; irq < ICU_LEN; irq++) {
288 register int irqs = 1 << irq;
289 for (q = intrhand[irq]; q; q = q->ih_next)
290 irqs |= imask[q->ih_level];
291 intrmask[irq] = irqs | SIR_ALLMASK;
292 }
293
294 /* Lastly, determine which IRQs are actually in use. */
295 {
296 register int irqs = 0;
297 for (irq = 0; irq < ICU_LEN; irq++)
298 if (intrhand[irq])
299 irqs |= 1 << irq;
300 if (irqs >= 0x100) /* any IRQs >= 8 in use */
301 irqs |= 1 << IRQ_SLAVE;
302 imen = ~irqs;
303 isa_outb(IO_ICU1 + 1, imen);
304 isa_outb(IO_ICU2 + 1, imen >> 8);
305 }
306 }
307
308 /*
309 * Establish a ISA bus interrupt.
310 */
311 void *
312 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
313 isa_chipset_tag_t ic;
314 int irq;
315 int type;
316 int level;
317 int (*ih_fun) __P((void *));
318 void *ih_arg;
319 {
320 struct intrhand **p, *q, *ih;
321 static struct intrhand fakehand = {NULL, fakeintr};
322 extern int cold;
323
324 /* no point in sleeping unless someone can free memory. */
325 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
326 if (ih == NULL)
327 panic("isa_intr_establish: can't malloc handler info");
328
329 if (!LEGAL_IRQ(irq) || type == IST_NONE)
330 panic("intr_establish: bogus irq or type");
331
332 switch (intrtype[irq]) {
333 case IST_EDGE:
334 case IST_LEVEL:
335 if (type == intrtype[irq])
336 break;
337 case IST_PULSE:
338 if (type != IST_NONE)
339 panic("intr_establish: can't share %s with %s",
340 isa_intr_typename(intrtype[irq]),
341 isa_intr_typename(type));
342 break;
343 }
344
345 /*
346 * Figure out where to put the handler.
347 * This is O(N^2), but we want to preserve the order, and N is
348 * generally small.
349 */
350 for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
351 ;
352
353 /*
354 * Actually install a fake handler momentarily, since we might be doing
355 * this with interrupts enabled and don't want the real routine called
356 * until masking is set up.
357 */
358 fakehand.ih_level = level;
359 *p = &fakehand;
360
361 intr_calculatemasks();
362
363 /*
364 * Poke the real handler in now.
365 */
366 ih->ih_fun = ih_fun;
367 ih->ih_arg = ih_arg;
368 ih->ih_count = 0;
369 ih->ih_next = NULL;
370 ih->ih_level = level;
371 ih->ih_irq = irq;
372 ih->ih_what = ""; /* XXX - should be eliminated */
373 *p = ih;
374
375 return (ih);
376 }
377
378 void
379 isabr_intr_disestablish(ic, arg)
380 isa_chipset_tag_t ic;
381 void *arg;
382 {
383
384 }
385
386 /*
387 * Process an interrupt from the ISA bus.
388 */
389 int
390 isabr_iointr(mask, cf)
391 unsigned mask;
392 struct clockframe *cf;
393 {
394 struct intrhand *ih;
395 int isa_vector;
396 int o_imen;
397 char vector;
398
399 (void) &isa_vector; /* shut off gcc unused-variable warnings */
400
401 switch(cputype) {
402 case ACER_PICA_61:
403 case MAGNUM:
404 isa_vector = in32(R4030_SYS_ISA_VECTOR) & (ICU_LEN - 1);
405 break;
406
407 case NEC_RD94:
408 isa_vector = in32(RD94_SYS_INTSTAT2) & (ICU_LEN - 1);
409 break;
410
411 case DESKSTATION_TYNE:
412 isa_outb(IO_ICU1, 0x0f); /* Poll */
413 vector = isa_inb(IO_ICU1);
414 if(vector > 0 || (isa_vector = vector & 7) == 2) {
415 isa_outb(IO_ICU2, 0x0f);
416 vector = isa_inb(IO_ICU2);
417 if(vector > 0) {
418 printf("isa: spurious interrupt.\n");
419 return(~0);
420 }
421 isa_vector = (vector & 7) | 8;
422 }
423 break;
424
425 case DESKSTATION_RPC44:
426 isa_outb(IO_ICU1, 0x0f); /* Poll */
427 vector = isa_inb(IO_ICU1);
428 if(vector > 0 || (isa_vector = vector & 7) == 2) {
429 isa_outb(IO_ICU2, 0x0f);
430 vector = isa_inb(IO_ICU2);
431 if(vector > 0) {
432 printf("isa: spurious interrupt.\n");
433 return(~0);
434 }
435 isa_vector = (vector & 7) | 8;
436 }
437 break;
438 }
439
440 o_imen = imen;
441 imen |= 1 << (isa_vector & (ICU_LEN - 1));
442 if(isa_vector & 0x08) {
443 isa_inb(IO_ICU2 + 1);
444 isa_outb(IO_ICU2 + 1, imen >> 8);
445 isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
446 isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
447 }
448 else {
449 isa_inb(IO_ICU1 + 1);
450 isa_outb(IO_ICU1 + 1, imen);
451 isa_outb(IO_ICU1, 0x60 + isa_vector);
452 }
453 ih = intrhand[isa_vector];
454 if(isa_vector == 0) { /* Clock */ /*XXX*/
455 (*ih->ih_fun)(cf);
456 ih = ih->ih_next;
457 }
458 while(ih) {
459 (*ih->ih_fun)(ih->ih_arg);
460 ih = ih->ih_next;
461 }
462 imen = o_imen;
463 isa_inb(IO_ICU1 + 1);
464 isa_inb(IO_ICU2 + 1);
465 isa_outb(IO_ICU1 + 1, imen);
466 isa_outb(IO_ICU2 + 1, imen >> 8);
467
468 return(~0); /* Dont reenable */
469 }
470
471
472 /*
473 * Initialize the Interrupt controller logic.
474 */
475 void
476 isabr_initicu()
477 {
478
479 isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
480 isa_outb(IO_ICU1+1, 0); /* starting at this vector index */
481 isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
482 isa_outb(IO_ICU1+1, 1); /* 8086 mode */
483 isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
484 isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */
485 isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */
486 #ifdef REORDER_IRQ
487 isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
488 #endif
489
490 isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
491 isa_outb(IO_ICU2+1, 8); /* staring at this vector index */
492 isa_outb(IO_ICU2+1, IRQ_SLAVE);
493 isa_outb(IO_ICU2+1, 1); /* 8086 mode */
494 isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
495 isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */
496 isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */
497 }
498
499
500 /*
501 * SPEAKER BEEPER...
502 */
503 void
504 sysbeepstop(arg)
505 void *arg;
506 {
507 int s;
508
509 /* disable counter 2 */
510 s = splhigh();
511 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
512 splx(s);
513 beeping = 0;
514 }
515
516 void
517 sysbeep(pitch, period)
518 int pitch, period;
519 {
520 static int last_pitch, last_period;
521 int s;
522 extern int cold;
523
524 if (cold)
525 return; /* Can't beep yet. */
526
527 if (beeping)
528 callout_stop(&sysbeep_ch);
529 if (!beeping || last_pitch != pitch) {
530 s = splhigh();
531 isa_outb(IO_TIMER1 + TIMER_MODE,
532 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
533 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
534 isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
535 isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
536 splx(s);
537 }
538 last_pitch = pitch;
539 beeping = last_period = period;
540 callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
541 }
542