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