xref: /netbsd-src/sys/arch/arc/isa/isabus.c (revision 5e4c038a45edbc7d63b7c2daa76e29f88b64a4e3)
1 /*	$NetBSD: isabus.c,v 1.16 2002/03/04 02:19:07 simonb 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 
303 	/* no point in sleeping unless someone can free memory. */
304 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
305 	if (ih == NULL)
306 		panic("isa_intr_establish: can't malloc handler info");
307 
308 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
309 		panic("intr_establish: bogus irq or type");
310 
311 	switch (intrtype[irq]) {
312 	case IST_EDGE:
313 	case IST_LEVEL:
314 		if (type == intrtype[irq])
315 			break;
316 	case IST_PULSE:
317 		if (type != IST_NONE)
318 			panic("intr_establish: can't share %s with %s",
319 			    isa_intr_typename(intrtype[irq]),
320 			    isa_intr_typename(type));
321 		break;
322 	}
323 
324 	/*
325 	 * Figure out where to put the handler.
326 	 * This is O(N^2), but we want to preserve the order, and N is
327 	 * generally small.
328 	 */
329 	for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
330 		;
331 
332 	/*
333 	 * Actually install a fake handler momentarily, since we might be doing
334 	 * this with interrupts enabled and don't want the real routine called
335 	 * until masking is set up.
336 	 */
337 	fakehand.ih_level = level;
338 	*p = &fakehand;
339 
340 	intr_calculatemasks();
341 
342 	/*
343 	 * Poke the real handler in now.
344 	 */
345 	ih->ih_fun = ih_fun;
346 	ih->ih_arg = ih_arg;
347 	ih->ih_count = 0;
348 	ih->ih_next = NULL;
349 	ih->ih_level = level;
350 	ih->ih_irq = irq;
351 	ih->ih_what = ""; /* XXX - should be eliminated */
352 	*p = ih;
353 
354 	return (ih);
355 }
356 
357 void
358 isabr_intr_disestablish(ic, arg)
359         isa_chipset_tag_t ic;
360         void *arg;
361 {
362 
363 }
364 
365 /*
366  *	Process an interrupt from the ISA bus.
367  */
368 int
369 isabr_iointr(mask, cf)
370         unsigned mask;
371         struct clockframe *cf;
372 {
373 	struct intrhand *ih;
374 	int isa_vector;
375 	int o_imen;
376 
377 	isa_vector = (*isabr_conf->ic_intr_status)();
378 	if (isa_vector < 0)
379 		return (~0);
380 
381 	o_imen = imen;
382 	imen |= 1 << (isa_vector & (ICU_LEN - 1));
383 	if(isa_vector & 0x08) {
384 		isa_inb(IO_ICU2 + 1);
385 		isa_outb(IO_ICU2 + 1, imen >> 8);
386 		isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
387 		isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
388 	}
389 	else {
390 		isa_inb(IO_ICU1 + 1);
391 		isa_outb(IO_ICU1 + 1, imen);
392 		isa_outb(IO_ICU1, 0x60 + isa_vector);
393 	}
394 	ih = intrhand[isa_vector];
395 	if(isa_vector == 0) {	/* Clock */	/*XXX*/
396 		(*ih->ih_fun)(cf);
397 		ih = ih->ih_next;
398 	}
399 	while(ih) {
400 		(*ih->ih_fun)(ih->ih_arg);
401 		ih = ih->ih_next;
402 	}
403 	imen = o_imen;
404 	isa_inb(IO_ICU1 + 1);
405 	isa_inb(IO_ICU2 + 1);
406 	isa_outb(IO_ICU1 + 1, imen);
407 	isa_outb(IO_ICU2 + 1, imen >> 8);
408 
409 	return(~0);  /* Dont reenable */
410 }
411 
412 
413 /*
414  * Initialize the Interrupt controller logic.
415  */
416 void
417 isabr_initicu()
418 {
419 
420 	isa_outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
421 	isa_outb(IO_ICU1+1, 0);			/* starting at this vector index */
422 	isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE);	/* slave on line 2 */
423 	isa_outb(IO_ICU1+1, 1);			/* 8086 mode */
424 	isa_outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
425 	isa_outb(IO_ICU1, 0x68);		/* special mask mode (if available) */
426 	isa_outb(IO_ICU1, 0x0a);		/* Read IRR by default. */
427 #ifdef REORDER_IRQ
428 	isa_outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
429 #endif
430 
431 	isa_outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
432 	isa_outb(IO_ICU2+1, 8);			/* staring at this vector index */
433 	isa_outb(IO_ICU2+1, IRQ_SLAVE);
434 	isa_outb(IO_ICU2+1, 1);			/* 8086 mode */
435 	isa_outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
436 	isa_outb(IO_ICU2, 0x68);		/* special mask mode (if available) */
437 	isa_outb(IO_ICU2, 0x0a);		/* Read IRR by default. */
438 }
439 
440 
441 /*
442  *	SPEAKER BEEPER...
443  */
444 void
445 sysbeepstop(arg)
446 	void *arg;
447 {
448 	int s;
449 
450 	/* disable counter 2 */
451 	s = splhigh();
452 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
453 	splx(s);
454 	beeping = 0;
455 }
456 
457 void
458 sysbeep(pitch, period)
459 	int pitch, period;
460 {
461 	static int last_pitch, last_period;
462 	int s;
463 
464 	if (cold)
465 		return;		/* Can't beep yet. */
466 
467 	if (beeping)
468 		callout_stop(&sysbeep_ch);
469 	if (!beeping || last_pitch != pitch) {
470 		s = splhigh();
471 		isa_outb(IO_TIMER1 + TIMER_MODE,
472 		    TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
473 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
474 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
475 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
476 		splx(s);
477 	}
478 	last_pitch = pitch;
479 	beeping = last_period = period;
480 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
481 }
482