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