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