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