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