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