diff options
Diffstat (limited to 'sys/arch/arc/isa')
-rw-r--r-- | sys/arch/arc/isa/isa_machdep.h | 72 | ||||
-rw-r--r-- | sys/arch/arc/isa/isabus.c | 490 | ||||
-rw-r--r-- | sys/arch/arc/isa/isadma.c | 317 | ||||
-rw-r--r-- | sys/arch/arc/isa/isadmareg.h | 22 | ||||
-rw-r--r-- | sys/arch/arc/isa/spkrreg.h | 11 | ||||
-rw-r--r-- | sys/arch/arc/isa/timerreg.h | 100 |
6 files changed, 1012 insertions, 0 deletions
diff --git a/sys/arch/arc/isa/isa_machdep.h b/sys/arch/arc/isa/isa_machdep.h new file mode 100644 index 00000000000..24c104c3deb --- /dev/null +++ b/sys/arch/arc/isa/isa_machdep.h @@ -0,0 +1,72 @@ +/* $OpenBSD: isa_machdep.h,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ + +/* + * Copyright (c) 1996 Per Fogelstrom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Per Fogelstrom + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ISA_MACHDEP_H_ +#define _ISA_MACHDEP_H_ + +typedef struct arc_isa_bus *isa_chipset_tag_t; + +struct arc_isa_bus { + void *ic_data; + + void (*ic_attach_hook) __P((struct device *, struct device *, + struct isabus_attach_args *)); + void *(*ic_intr_establish) __P((isa_chipset_tag_t, int, int, int, + int (*)(void *), void *, char *)); + void (*ic_intr_disestablish) __P((isa_chipset_tag_t, void *)); +}; + + +/* + * Functions provided to machine-independent ISA code. + */ +#define isa_attach_hook(p, s, a) /* \ + (*(a)->iba_ic->ic_attach_hook)((p), (s), (a)) */ +#define isa_intr_establish(c, i, t, l, f, a, w) \ + (*(c)->ic_intr_establish)((c)->ic_data, (i), (t), (l), (f), (a), (w)) +#define isa_intr_disestablish(c, h) \ + (*(c)->ic_intr_disestablish)((c)->ic_data, (h)) + +/* + * Interrupt control struct used to control the ICU setup. + */ + +struct intrhand { + struct intrhand *ih_next; + int (*ih_fun) __P((void *)); + void *ih_arg; + u_long ih_count; + int ih_level; + int ih_irq; + char *ih_what; +}; + +#endif /* _ISA_MACHDEP_H_ */ diff --git a/sys/arch/arc/isa/isabus.c b/sys/arch/arc/isa/isabus.c new file mode 100644 index 00000000000..75f69270954 --- /dev/null +++ b/sys/arch/arc/isa/isabus.c @@ -0,0 +1,490 @@ +/* $OpenBSD: isabus.c,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp $ */ + +/*- + * Copyright (c) 1995 Per Fogelstrom + * Copyright (c) 1993, 1994 Charles Hannum. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)isa.c 7.2 (Berkeley) 5/12/91 + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/pio.h> +#include <machine/autoconf.h> +#include <machine/intr.h> + +#include <arc/arc/arctype.h> +#include <arc/pica/pica.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <arc/isa/timerreg.h> +#include <arc/isa/spkrreg.h> +#include <arc/isa/isa_machdep.h> + +extern int isa_io_base; /* Base address for ISA I/O space */ +extern int isa_mem_base; /* Base address for ISA MEM space */ + +static int beeping; + +/* + * I/O macros to access isa bus ports/memory. + * At the first glance theese macros may seem inefficient. + * However, the cpu executes an instruction every 7.5ns + * so the bus is much slower so it doesn't matter, really. + */ +#define isa_outb(x,y) outb(isa_io_base + (x), y) +#define isa_inb(x) inb(isa_io_base + (x)) + +#define IRQ_SLAVE 2 +#define ICU_LEN 16 + +struct isabr_softc { + struct device sc_dv; + struct arc_isa_bus arc_isa_cs; + struct arc_isa_busmap arc_isa_map; + struct abus sc_bus; +}; + +/* Definition of the driver for autoconfig. */ +int isabrmatch(struct device *, void *, void *); +void isabrattach(struct device *, struct device *, void *); +int isabrprint(void *, char *); + +struct cfattach isabr_ca = { + sizeof(struct isabr_softc), isabrmatch, isabrattach +}; +struct cfdriver isabr_cd = { + NULL, "isabr", DV_DULL, NULL, 0 +}; + +void *isabr_intr_establish __P((isa_chipset_tag_t, int, int, int, + int (*)(void *), void *, char *)); +void isabr_intr_disestablish __P((isa_chipset_tag_t, void*)); +int isabr_iointr __P((void *)); +void isabr_initicu(); + +extern int cputype; + + +int +isabrmatch(parent, cfdata, aux) + struct device *parent; + void *cfdata; + void *aux; +{ + struct cfdata *cf = cfdata; + struct confargs *ca = aux; + + /* Make sure that we're looking for a ISABR. */ + if (strcmp(ca->ca_name, isabr_cd.cd_name) != 0) + return (0); + + return (1); +} + +void +isabrattach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct isabr_softc *sc = (struct isabr_softc *)self; + struct isabus_attach_args iba; + + printf("\n"); + + /* Initialize interrupt controller */ + isabr_initicu(); + + /* set up interrupt handlers */ + switch(cputype) { + case ACER_PICA_61: + set_intr(INT_MASK_2, isabr_iointr, 3); + break; + default: + panic("isabrattach: unkown cputype!"); + } + +/*XXX we may remove the abus part of the softc struct... */ + sc->sc_bus.ab_dv = (struct device *)sc; + sc->sc_bus.ab_type = BUS_ISABR; + + sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish; + sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish; + sc->arc_isa_map.isa_io_base = (void *)isa_io_base; + sc->arc_isa_map.isa_mem_base = (void *)isa_mem_base; + + iba.iba_busname = "isa"; + iba.iba_bc = &sc->arc_isa_map; + iba.iba_ic = &sc->arc_isa_cs; + config_found(self, &iba, isabrprint); +} + +int +isabrprint(aux, pnp) + void *aux; + char *pnp; +{ + struct confargs *ca = aux; + + if (pnp) + printf("%s at %s", ca->ca_name, pnp); + printf(" I/O base 0x%lx Mem base 0x%lx", isa_io_base, isa_mem_base); + return (UNCONF); +} + + +/* + * Interrupt system driver code + * ============================ + */ +#define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2) + +int imen; +int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN]; +struct intrhand *intrhand[ICU_LEN]; + +int fakeintr(void *arg) {return 0;} + +/* + * Recalculate the interrupt masks from scratch. + * We could code special registry and deregistry versions of this function that + * would be faster, but the code would be nastier, and we don't expect this to + * happen very much anyway. + */ +void +intr_calculatemasks() +{ + int irq, level; + struct intrhand *q; + + /* First, figure out which levels each IRQ uses. */ + for (irq = 0; irq < ICU_LEN; irq++) { + register int levels = 0; + for (q = intrhand[irq]; q; q = q->ih_next) + levels |= 1 << q->ih_level; + intrlevel[irq] = levels; + } + + /* Then figure out which IRQs use each level. */ + for (level = 0; level < 5; level++) { + register int irqs = 0; + for (irq = 0; irq < ICU_LEN; irq++) + if (intrlevel[irq] & (1 << level)) + irqs |= 1 << irq; + imask[level] = irqs | SIR_ALLMASK; + } + + /* + * There are tty, network and disk drivers that use free() at interrupt + * time, so imp > (tty | net | bio). + */ + imask[IPL_IMP] |= imask[IPL_TTY] | imask[IPL_NET] | imask[IPL_BIO]; + + /* + * Enforce a hierarchy that gives slow devices a better chance at not + * dropping data. + */ + imask[IPL_TTY] |= imask[IPL_NET] | imask[IPL_BIO]; + imask[IPL_NET] |= imask[IPL_BIO]; + + /* + * These are pseudo-levels. + */ + imask[IPL_NONE] = 0x00000000; + imask[IPL_HIGH] = 0xffffffff; + + /* And eventually calculate the complete masks. */ + for (irq = 0; irq < ICU_LEN; irq++) { + register int irqs = 1 << irq; + for (q = intrhand[irq]; q; q = q->ih_next) + irqs |= imask[q->ih_level]; + intrmask[irq] = irqs | SIR_ALLMASK; + } + + /* Lastly, determine which IRQs are actually in use. */ + { + register int irqs = 0; + for (irq = 0; irq < ICU_LEN; irq++) + if (intrhand[irq]) + irqs |= 1 << irq; + if (irqs >= 0x100) /* any IRQs >= 8 in use */ + irqs |= 1 << IRQ_SLAVE; + imen = ~irqs; + isa_outb(IO_ICU1 + 1, imen); + isa_outb(IO_ICU2 + 1, imen >> 8); + } +} + +/* + * Establish a ISA bus interrupt. + */ +void * +isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what) + isa_chipset_tag_t ic; + int irq; + int type; + int level; + int (*ih_fun) __P((void *)); + void *ih_arg; + char *ih_what; +{ + struct intrhand **p, *q, *ih; + static struct intrhand fakehand = {NULL, fakeintr}; + extern int cold; + + /* no point in sleeping unless someone can free memory. */ + ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) + panic("isa_intr_establish: can't malloc handler info"); + + if (!LEGAL_IRQ(irq) || type == IST_NONE) + panic("intr_establish: bogus irq or type"); + + switch (intrtype[irq]) { + case IST_EDGE: + case IST_LEVEL: + if (type == intrtype[irq]) + break; + case IST_PULSE: + if (type != IST_NONE) + panic("intr_establish: can't share %s with %s", + isa_intr_typename(intrtype[irq]), + isa_intr_typename(type)); + break; + } + + /* + * Figure out where to put the handler. + * This is O(N^2), but we want to preserve the order, and N is + * generally small. + */ + for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + ; + + /* + * Actually install a fake handler momentarily, since we might be doing + * this with interrupts enabled and don't want the real routine called + * until masking is set up. + */ + fakehand.ih_level = level; + *p = &fakehand; + + intr_calculatemasks(); + + /* + * Poke the real handler in now. + */ + ih->ih_fun = ih_fun; + ih->ih_arg = ih_arg; + ih->ih_count = 0; + ih->ih_next = NULL; + ih->ih_level = level; + ih->ih_irq = irq; + ih->ih_what = ih_what; + *p = ih; + + return (ih); +} + +void +isabr_intr_disestablish(ic, arg) + isa_chipset_tag_t ic; + void *arg; +{ + +} + +/* + * Process an interrupt from the ISA bus ACER PICA style. + */ +int +isabr_iointr(ca) + void *ca; /* XXX */ +{ + struct intrhand *ih; + int isa_vector; + int o_imen; + + isa_vector = in32(PICA_SYS_ISA_VECTOR) & (ICU_LEN - 1); + + o_imen = imen; + imen |= 1 << (isa_vector & (ICU_LEN - 1)); + if(isa_vector & 0x08) { + isa_inb(IO_ICU2 + 1); + isa_outb(IO_ICU2 + 1, imen >> 8); + isa_outb(IO_ICU2, 0x60 + (isa_vector & 7)); + isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE); + } + else { + isa_inb(IO_ICU1 + 1); + isa_outb(IO_ICU1 + 1, imen); + isa_outb(IO_ICU1, 0x60 + isa_vector); + } + ih = intrhand[isa_vector]; + while(ih) { + (*ih->ih_fun)(ih->ih_arg); + ih = ih->ih_next; + } + imen = o_imen; + isa_inb(IO_ICU1 + 1); + isa_inb(IO_ICU2 + 1); + isa_outb(IO_ICU1 + 1, imen); + isa_outb(IO_ICU2 + 1, imen >> 8); + + return(~0); /* Dont reenable */ +} + + +/* + * Initialize the Interrupt controller logic. + */ +void +isabr_initicu() +{ + + isa_outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ + isa_outb(IO_ICU1+1, 0); /* starting at this vector index */ + isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */ + isa_outb(IO_ICU1+1, 1); /* 8086 mode */ + isa_outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ + isa_outb(IO_ICU1, 0x68); /* special mask mode (if available) */ + isa_outb(IO_ICU1, 0x0a); /* Read IRR by default. */ +#ifdef REORDER_IRQ + isa_outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ +#endif + + isa_outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ + isa_outb(IO_ICU2+1, 8); /* staring at this vector index */ + isa_outb(IO_ICU2+1, IRQ_SLAVE); + isa_outb(IO_ICU2+1, 1); /* 8086 mode */ + isa_outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ + isa_outb(IO_ICU2, 0x68); /* special mask mode (if available) */ + isa_outb(IO_ICU2, 0x0a); /* Read IRR by default. */ +} + + +/* + * SPEAKER BEEPER... + */ +void +sysbeepstop(arg) + void *arg; +{ + int s; + + /* disable counter 2 */ + s = splhigh(); + isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR); + splx(s); + beeping = 0; +} + +void +sysbeep(pitch, period) + int pitch, period; +{ + static int last_pitch, last_period; + int s; + + if (beeping) + untimeout(sysbeepstop, 0); + if (!beeping || last_pitch != pitch) { + s = splhigh(); + isa_outb(TIMER_MODE, TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); + isa_outb(TIMER_CNTR2, TIMER_DIV(pitch) % 256); + isa_outb(TIMER_CNTR2, TIMER_DIV(pitch) / 256); + isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR); + splx(s); + } + last_pitch = pitch; + beeping = last_period = period; + timeout(sysbeepstop, 0, period); +} diff --git a/sys/arch/arc/isa/isadma.c b/sys/arch/arc/isa/isadma.c new file mode 100644 index 00000000000..95cdfbe475f --- /dev/null +++ b/sys/arch/arc/isa/isadma.c @@ -0,0 +1,317 @@ +/* $OpenBSD: isadma.c,v 1.1 1996/06/24 09:07:18 pefo Exp $ */ +/* $NetBSD: isadma.c,v 1.19 1996/04/29 20:03:26 christos Exp $ */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/file.h> +#include <sys/buf.h> +#include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/uio.h> + +#include <vm/vm.h> + +#include <machine/pio.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/isa/isadmavar.h> +#include <arch/arc/isa/isadmareg.h> /*XXX*/ + +struct dma_info { + int flags; + int active; + caddr_t addr; + vm_size_t nbytes; + struct isadma_seg phys[1]; +}; + +static struct isadma_softc *isadma_sc; /*XXX ugly */ +static struct dma_info dma_info[8]; +static u_int8_t dma_finished; + +/* high byte of address is stored in this port for i-th dma channel */ +static int dmapageport[2][4] = { + {0x87, 0x83, 0x81, 0x82}, + {0x8f, 0x8b, 0x89, 0x8a} +}; + +static u_int8_t dmamode[4] = { + DMA37MD_READ | DMA37MD_SINGLE, + DMA37MD_WRITE | DMA37MD_SINGLE, + DMA37MD_READ | DMA37MD_LOOP, + DMA37MD_WRITE | DMA37MD_LOOP +}; + +int isadmamatch __P((struct device *, void *, void *)); +void isadmaattach __P((struct device *, struct device *, void *)); +int isadmaprint __P((void *, char *)); + +struct isadma_softc { + struct device sc_dev; + bus_chipset_tag_t sc_bc; + bus_io_handle_t sc_ioh1; + bus_io_handle_t sc_ioh2; +} + +struct cfattach isadma_ca = { + sizeof(struct isadma_softc), isadmamatch, isadmaattach +}; + +struct cfdriver isadma_cd = { + NULL, "isadma", DV_DULL, 1 +}; + +isadmamatch(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct isa_attach_args *ia = aux; + + /* Sure we exist */ + ia->ia_iosize = 0; + return (1); +} + +void +isadmaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isadma_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + bus_chipset_tag_t bc; + bus_io_handle_t ioh; + + printf("\n"); + + bc = sc->sc_bc = ia->ia_bc; + if (bus_io_map(bc, IO_DMA1, DMA_NREGS, &ioh)) + panic("isadmaattach: couldn't map I/O ports"); + sc->sc_ioh1 = ioh; + if (bus_io_map(bc, IO_DMA2, DMA_NREGS*2, &ioh)) + panic("isadmaattach: couldn't map I/O ports"); + sc->sc_ioh2 = ioh; + isadma_sc = sc; +} + +/* + * isadma_cascade(): program 8237 DMA controller channel to accept + * external dma control by a board. + */ +void +isadma_cascade(chan) + int chan; +{ + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7) + panic("isadma_cascade: impossible request"); +#endif + + /* set dma channel mode, and set dma channel mode */ + if ((chan & 4) == 0) { + bus_io_write_1(bc, sc->sc_ioh1, DMA1_MODE, chan | DMA37MD_CASCADE); + bus_io_write_1(bc, sc->sc_ioh1, DMA1_SMSK, chan); + } else { + chan &= 3; + + bus_io_write_1(bc, sc->sc_ioh2, DMA2_MODE, chan | DMA37MD_CASCADE); + bus_io_write_1(bc, sc->sc_ioh2, DMA2_SMSK, chan); + } +} + +/* + * isadma_start(): program 8237 DMA controller channel, avoid page alignment + * problems by using a bounce buffer. + */ +void +isadma_start(addr, nbytes, chan, flags) + caddr_t addr; + vm_size_t nbytes; + int chan; + int flags; +{ + struct dma_info *di; + int waport; + int mflags; + vm_size_t size; + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + bus_io_handle_t ioh; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7 || + (((flags & DMAMODE_READ) != 0) + ((flags & DMAMODE_WRITE) != 0) + + ((flags & DMAMODE_LOOP) != 0) != 1) || + ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) : + (nbytes >= (1<<16)))) + panic("isadma_start: impossible request"); +#endif + + di = dma_info+chan; + if (di->active) { + log(LOG_ERR,"isadma_start: old request active on %d\n",chan); + isadma_abort(chan); + } + + di->flags = flags; + di->active = 1; + di->addr = addr; + di->nbytes = nbytes; + + mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_BOUNCE | ISADMA_MAP_CONTIG; + mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT; + + if (isadma_map(addr, nbytes, di->phys, mflags) != 1) + panic("isadma_start: cannot map"); + + /* XXX Will this do what we want with DMAMODE_LOOP? */ + if ((flags & DMAMODE_READ) == 0) + isadma_copytobuf(addr, nbytes, 1, di->phys); + + dma_finished &= ~(1 << chan); + + if ((chan & 4) == 0) { + ioh = sc->sc_ioh1; + /* + * Program one of DMA channels 0..3. These are + * byte mode channels. + */ + /* set dma channel mode, and reset address ff */ + bus_io_write_1(bc, ioh, DMA1_MODE, chan | dmamode[flags]); + bus_io_write_1(bc, ioh, DMA1_FFC, 0); + + /* send start address */ + waport = DMA1_CHN(chan); + outb(dmapageport[0][chan], di->phys[0].addr>>16); + outb(waport, di->phys[0].addr); + outb(waport, di->phys[0].addr>>8); + + /* send count */ + outb(waport + 1, --nbytes); + outb(waport + 1, nbytes>>8); + + /* unmask channel */ + bus_io_write_1(bc, ioh, DMA1_SMSK, chan | DMA37SM_CLEAR); + } else { + ioh = sc->sc_ioh2; + /* + * Program one of DMA channels 4..7. These are + * word mode channels. + */ + /* set dma channel mode, and reset address ff */ + bus_io_write_1(bc, ioh, DMA2_MODE, (chan & 3) | dmamode[flags]); + bus_io_write_1(bc, ioh, DMA2_FFC, 0); + + /* send start address */ + waport = DMA2_CHN(chan & 3); + outb(dmapageport[1][chan], di->phys[0].addr>>16); + outb(waport, di->phys[0].addr>>1); + outb(waport, di->phys[0].addr>>9); + + /* send count */ + nbytes >>= 1; + outb(waport + 2, --nbytes); + outb(waport + 2, nbytes>>8); + + /* unmask channel */ + bus_io_write_1(bc, ioh, DMA2_SMSK, (chan & 3) | DMA37SM_CLEAR); + } +} + +void +isadma_abort(chan) + int chan; +{ + struct dma_info *di; + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7) + panic("isadma_abort: impossible request"); +#endif + + di = dma_info+chan; + if (! di->active) { + log(LOG_ERR,"isadma_abort: no request active on %d\n",chan); + return; + } + + /* mask channel */ + if ((chan & 4) == 0) + bus_io_write_1(bc, sc->sc_ioh1, DMA1_SMSK, DMA37SM_SET | chan); + else + bus_io_write_1(bc, sc->sc_ioh2, DMA2_SMSK, DMA37SM_SET | (chan & 3)); + + isadma_unmap(di->addr, di->nbytes, 1, di->phys); + di->active = 0; +} + +int +isadma_finished(chan) + int chan; +{ + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef ISADMA_DEBUG + if (chan < 0 || chan > 7) + panic("isadma_finished: impossible request"); +#endif + + /* check that the terminal count was reached */ + if ((chan & 4) == 0) + dma_finished |= bus_io_read_1(bc, sc->sc_ioh1, DMA1_SR) & 0x0f; + else + dma_finished |= (bus_io_read_1(bc, sc->sc_ioh2, DMA2_SR) & 0x0f) << 4; + + return ((dma_finished & (1 << chan)) != 0); +} + +void +isadma_done(chan) + int chan; +{ + struct dma_info *di; + u_char tc; + struct isadma_softc *sc = isadma_sc; + bus_chipset_tag_t bc = sc->sc_bc; + +#ifdef DIAGNOSTIC + if (chan < 0 || chan > 7) + panic("isadma_done: impossible request"); +#endif + + di = dma_info+chan; + if (! di->active) { + log(LOG_ERR,"isadma_done: no request active on %d\n",chan); + return; + } + + /* check that the terminal count was reached */ + if ((chan & 4) == 0) + tc = bus_io_read_1(bc, sc->sc_ioh1, DMA1_SR) & (1 << chan); + else + tc = bus_io_read_1(bc, sc->sc_ioh2, DMA2_SR) & (1 << (chan & 3)); + if (tc == 0) + /* XXX probably should panic or something */ + log(LOG_ERR, "dma channel %d not finished\n", chan); + + /* mask channel */ + if ((chan & 4) == 0) + bus_io_write_1(bc, sc->sc_ioh1, DMA1_SMSK, DMA37SM_SET | chan); + else + bus_io_write_1(bc, sc->sc_ioh2, DMA2_SMSK, DMA37SM_SET | (chan & 3)); + + /* XXX Will this do what we want with DMAMODE_LOOP? */ + if (di->flags & DMAMODE_READ) + isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys); + + isadma_unmap(di->addr, di->nbytes, 1, di->phys); + di->active = 0; +} diff --git a/sys/arch/arc/isa/isadmareg.h b/sys/arch/arc/isa/isadmareg.h new file mode 100644 index 00000000000..185016060f2 --- /dev/null +++ b/sys/arch/arc/isa/isadmareg.h @@ -0,0 +1,22 @@ +/* $NetBSD: isadmareg.h,v 1.4 1995/06/28 04:31:48 cgd Exp $ */ + +#include <dev/ic/i8237reg.h> + +#define DMA_NREG 16 +/* + * Register definitions for DMA controller 1 (channels 0..3): + */ +#define DMA1_CHN(c) (1*(2*(c))) /* addr reg for channel c */ +#define DMA1_SR (1*8) /* status register */ +#define DMA1_SMSK (1*10) /* single mask register */ +#define DMA1_MODE (1*11) /* mode register */ +#define DMA1_FFC (1*12) /* clear first/last FF */ + +/* + * Register definitions for DMA controller 2 (channels 4..7): + */ +#define DMA2_CHN(c) (2*(2*(c))) /* addr reg for channel c */ +#define DMA2_SR (2*8) /* status register */ +#define DMA2_SMSK (2*10) /* single mask register */ +#define DMA2_MODE (2*11) /* mode register */ +#define DMA2_FFC (2*12) /* clear first/last FF */ diff --git a/sys/arch/arc/isa/spkrreg.h b/sys/arch/arc/isa/spkrreg.h new file mode 100644 index 00000000000..af1df50e2ad --- /dev/null +++ b/sys/arch/arc/isa/spkrreg.h @@ -0,0 +1,11 @@ +/* $NetBSD: spkrreg.h,v 1.2 1994/10/27 04:18:16 cgd Exp $ */ + +/* + * PIT port addresses and speaker control values + */ + +#define PITAUX_PORT 0x61 /* port of Programmable Peripheral Interface */ +#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */ +#define PIT_SPKRDATA 0x02 /* Direct to speaker */ + +#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA) diff --git a/sys/arch/arc/isa/timerreg.h b/sys/arch/arc/isa/timerreg.h new file mode 100644 index 00000000000..996834cadca --- /dev/null +++ b/sys/arch/arc/isa/timerreg.h @@ -0,0 +1,100 @@ +/* $NetBSD: timerreg.h,v 1.4 1994/10/27 04:18:17 cgd Exp $ */ + +/*- + * Copyright (c) 1993 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Register definitions for the Intel 8253 Programmable Interval Timer. + * + * This chip has three independent 16-bit down counters that can be + * read on the fly. There are three mode registers and three countdown + * registers. The countdown registers are addressed directly, via the + * first three I/O ports. The three mode registers are accessed via + * the fourth I/O port, with two bits in the mode byte indicating the + * register. (Why are hardware interfaces always so braindead?). + * + * To write a value into the countdown register, the mode register + * is first programmed with a command indicating the which byte of + * the two byte register is to be modified. The three possibilities + * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then + * msb (TMR_MR_BOTH). + * + * To read the current value ("on the fly") from the countdown register, + * you write a "latch" command into the mode register, then read the stable + * value from the corresponding I/O port. For example, you write + * TMR_MR_LATCH into the corresponding mode register. Presumably, + * after doing this, a write operation to the I/O port would result + * in undefined behavior (but hopefully not fry the chip). + * Reading in this manner has no side effects. + * + * The outputs of the three timers are connected as follows: + * + * timer 0 -> irq 0 + * timer 1 -> dma chan 0 (for dram refresh) + * timer 2 -> speaker (via keyboard controller) + * + * Timer 0 is used to call hardclock. + * Timer 2 is used to generate console beeps. + */ + +/* + * Frequency of all three count-down timers; (TIMER_FREQ/freq) is the + * appropriate count to generate a frequency of freq hz. + */ +#ifndef TIMER_FREQ +#define TIMER_FREQ 1193182 +#endif +#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) + +/* + * Macros for specifying values to be written into a mode register. + */ +#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */ +#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */ +#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */ +#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */ +#define TIMER_SEL0 0x00 /* select counter 0 */ +#define TIMER_SEL1 0x40 /* select counter 1 */ +#define TIMER_SEL2 0x80 /* select counter 2 */ +#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */ +#define TIMER_ONESHOT 0x02 /* mode 1, one shot */ +#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */ +#define TIMER_SQWAVE 0x06 /* mode 3, square wave */ +#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */ +#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */ +#define TIMER_LATCH 0x00 /* latch counter for reading */ +#define TIMER_LSB 0x10 /* r/w counter LSB */ +#define TIMER_MSB 0x20 /* r/w counter MSB */ +#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */ +#define TIMER_BCD 0x01 /* count in BCD */ + |