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