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