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