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