xref: /netbsd-src/sys/arch/arc/isa/isabus.c (revision bcc8ec9959e7b01e313d813067bfb43a3ad70551)
1 /*	$NetBSD: isabus.c,v 1.14 2000/12/24 09:25:27 ur 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@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/jazz/pica.h>
110 #include <arc/jazz/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