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