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