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