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