diff options
author | Jason Wright <jason@cvs.openbsd.org> | 1999-07-23 19:11:29 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 1999-07-23 19:11:29 +0000 |
commit | 212dedf9ce2e0a21513256af0a7ba3a55cd34af0 (patch) | |
tree | 8e7f0565da8bfc7b6c609b6436770c7f94b58e79 /sys/arch/sparc/dev/fga.c | |
parent | 59c9a82da9a132f80f7cc45e30892651795fdfe9 (diff) |
Drivers for the FORCE CPU-5V:
o fga5000 vme-sbus bridge
o system config registers
o flash memory
and daadio VME board driver
Diffstat (limited to 'sys/arch/sparc/dev/fga.c')
-rw-r--r-- | sys/arch/sparc/dev/fga.c | 815 |
1 files changed, 815 insertions, 0 deletions
diff --git a/sys/arch/sparc/dev/fga.c b/sys/arch/sparc/dev/fga.c new file mode 100644 index 00000000000..b6d88026ce5 --- /dev/null +++ b/sys/arch/sparc/dev/fga.c @@ -0,0 +1,815 @@ +/* $OpenBSD: fga.c,v 1.1 1999/07/23 19:11:25 jason Exp $ */ + +/* + * Copyright (c) 1999 Jason L. Wright (jason@thought.net) + * All rights reserved. + * + * This software was developed by Jason L. Wright under contract with + * RTMX Incorporated (http://www.rtmx.com). + * + * 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 Jason L. Wright for + * RTMX Incorporated. + * 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. + */ + +/* + * Driver for the Force Gate Array 5000 (VME/SBus bridge) found + * on FORCE CPU-5V boards. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <vm/vm.h> +#include <machine/pmap.h> + +#include <machine/autoconf.h> +#include <sparc/cpu.h> +#include <sparc/sparc/cpuvar.h> +#include <sparc/dev/sbusvar.h> +#include <sparc/dev/dmareg.h> /* for SBUS_BURST_* */ + +#include <sparc/dev/fgareg.h> +#include <sparc/dev/fgavar.h> +#include <sparc/dev/fgaio.h> +#include <sparc/dev/daadioreg.h> + +int fgamatch __P((struct device *, void *, void *)); +void fgaattach __P((struct device *, struct device *, void *)); +int fvmematch __P((struct device *, void *, void *)); +void fvmeattach __P((struct device *, struct device *, void *)); +int fgaprint __P((void *, const char *)); +int fvmeprint __P((void *, const char *)); +int fvmescan __P((struct device *parent, void *, void *)); + +struct fga_softc { + struct device sc_dev; /* base device */ + int sc_node; /* prom node */ + struct fga_regs *sc_regs; /* registers */ + struct intrhand sc_ih1; /* level 1 handler */ + struct intrhand sc_ih2; /* level 2 handler */ + struct intrhand sc_ih3; /* level 3 handler */ + struct intrhand sc_ih4; /* level 4 handler */ + struct intrhand sc_ih5; /* level 5 handler */ + struct intrhand sc_ih6; /* level 6 handler */ + struct intrhand sc_ih7; /* level 7 handler */ + struct intrhand **sc_vmevec; /* vectored handlers */ +#ifdef DDB + int sc_abort; /* abort switch enabled? */ +#endif + int sc_nrange; /* number of sbus ranges */ + struct rom_range *sc_range; /* sbus range data */ + u_int8_t sc_established; /* which hw intrs installed */ +}; + +int fgaopen __P((dev_t, int, int, struct proc *)); +int fgaclose __P((dev_t, int, int, struct proc *)); +int fgaioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); + +int fga_vmerangemap __P((struct fga_softc *, u_int32_t, u_int32_t, + int, int, u_int32_t, struct confargs *)); +int fga_intr_establish __P((struct fga_softc *, int, int, + struct intrhand *)); +int fga_hwintr_establish __P((struct fga_softc *, u_int8_t)); + +int fga_hwintr1 __P((void *)); +int fga_hwintr2 __P((void *)); +int fga_hwintr3 __P((void *)); +int fga_hwintr4 __P((void *)); +int fga_hwintr5 __P((void *)); +int fga_hwintr6 __P((void *)); +int fga_hwintr7 __P((void *)); +int fga_intrvec __P((struct fga_softc *, int)); + +struct cfattach fga_ca = { + sizeof (struct fga_softc), fgamatch, fgaattach +}; + +struct cfdriver fga_cd = { + NULL, "fga", DV_DULL +}; + +struct fvme_softc { + struct device sc_dv; + u_int32_t sc_vmeoffset; /* vme range offset */ + u_int32_t sc_len; /* length of range */ + u_int32_t sc_sbusoffset; /* sbus phys address */ + u_int32_t sc_type; /* amcode type */ +}; + +struct cfattach fvme_ca = { + sizeof (struct fvme_softc), fvmematch, fvmeattach +}; + +struct cfdriver fvme_cd = { + NULL, "fvme", DV_DULL +}; + +int +fgamatch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + + if (strcmp("VME", ra->ra_name)) + return (0); + return (1); +} + +void +fgaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct confargs *ca = aux, oca[FVME_MAX_RANGES]; + struct fga_softc *sc = (struct fga_softc *)self; + char *s; + int i, rlen; + + if (sc->sc_dev.dv_unit > 0) { + printf(" unsupported\n"); + return; + } + + /* map registers */ + if (ca->ca_ra.ra_nreg != 1) { + printf(": expected 1 register, got %d\n", ca->ca_ra.ra_nreg); + return; + } + sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0, + ca->ca_ra.ra_reg[0].rr_len); + + sc->sc_node = ca->ca_ra.ra_node; + + i = opennode("/iommu/sbus"); + if (i == 0) { + printf(": no iommu or sbus found, unconfigured\n"); + return; + } + rlen = getproplen(i, "ranges"); + sc->sc_range = + (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); + if (sc->sc_range == NULL) { + printf(": PROM ranges too large: %d\n", rlen); + return; + } + sc->sc_nrange = rlen / sizeof(struct rom_range); + (void)getprop(i, "ranges", sc->sc_range, rlen); + + s = getpropstring(sc->sc_node, "model"); + printf(": model %s id %c%c%c\n", s, + sc->sc_regs->id[0], sc->sc_regs->id[1], sc->sc_regs->id[2]); + + /* + * The prom leaves at least one of the ranges "on", so make sure + * they are all off. + */ + for (i = 0; i < 16; i++) + sc->sc_regs->vme_range[i] |= VME_RANGE_DECEN; + + sc->sc_regs->sbus_ssel[0] &= ~(SBUS_SSEL_Y); + sc->sc_regs->sbus_ssel[0] |= SBUS_SSEL_Y_SLOT4; + sc->sc_regs->sbus_ssel[1] &= ~(SBUS_SSEL_X | SBUS_SSEL_Y); + sc->sc_regs->sbus_ssel[1] |= SBUS_SSEL_X_SLOT5 | SBUS_SSEL_Y_SLOT5; + sc->sc_regs->sbus_ssel[2] &= ~(SBUS_SSEL_X | SBUS_SSEL_Y); + sc->sc_regs->sbus_ssel[2] |= SBUS_SSEL_X_SLOT5 | SBUS_SSEL_Y_SLOT1; + sc->sc_regs->sbus_ssel[3] &= ~(SBUS_SSEL_X | SBUS_SSEL_Y); + sc->sc_regs->sbus_ssel[3] |= SBUS_SSEL_X_SLOT1 | SBUS_SSEL_Y_SLOT1; + + /* + * Map and attach vme<->sbus master ranges + */ + fga_vmerangemap(sc, 0xf0000000, 0x10000000, + VME_MASTER_CAP_D32 | VME_MASTER_CAP_A32, 1, 0, oca); + fga_vmerangemap(sc, 0xf0000000, 0x10000000, + VME_MASTER_CAP_D16 | VME_MASTER_CAP_A32, 4, 0, oca); + fga_vmerangemap(sc, 0x00000000, 0x01000000, + VME_MASTER_CAP_D16 | VME_MASTER_CAP_A24, 5, 0xe000000, oca); + fga_vmerangemap(sc, 0x00000000, 0x00010000, + VME_MASTER_CAP_D8 | VME_MASTER_CAP_A16, 5, 0x0ffc0000, oca); + fga_vmerangemap(sc, 0x00000000, 0x00010000, + VME_MASTER_CAP_D16 | VME_MASTER_CAP_A16, 5, 0x0ffd0000, oca); + fga_vmerangemap(sc, 0x00000000, 0x00010000, + VME_MASTER_CAP_D32 | VME_MASTER_CAP_A16, 5, 0x0ffe0000, oca); + +#ifdef DDB + s = getpropstring(optionsnode, "abort-ena?"); + if (s && strcmp(s, "true") == 0) { + sc->sc_abort = 1; + fga_hwintr_establish(sc, IRQ_MAP_SINT7); + sc->sc_regs->abort_irq_map &= ~IRQ_MAP_INT_MASK; + sc->sc_regs->abort_irq_map |= IRQ_MAP_SINT7; + sc->sc_regs->abort_irq_map &= ~IRQ_MAP_ENABLE; + } +#endif +} + +int +fgaprint(args, name) + void *args; + const char *name; +{ + struct confargs *ca = args; + + if (name) + printf("%s at %s", ca->ca_ra.ra_name, name); + printf(" slot %d addr 0x%x", ca->ca_slot, ca->ca_offset); + return (UNCONF); +} + +/* + * Map a region of VME space to a sbus slot/offset. + */ +int +fga_vmerangemap(sc, vmebase, vmelen, vmecap, sbusslot, sbusoffset, oca) + struct fga_softc *sc; + u_int32_t vmebase, vmelen; + int vmecap; + int sbusslot; + u_int32_t sbusoffset; + struct confargs *oca; +{ + struct fga_regs *regs = sc->sc_regs; + u_int32_t rval; + u_int8_t sval; + int range, i, srange; + + for (i = 0; i < FVME_MAX_RANGES; i++) { + if (regs->vme_range[i] & VME_RANGE_DECEN) + break; + } + if (i == FVME_MAX_RANGES) + return (-1); + range = i; + + for (srange = 0; srange < sc->sc_nrange; srange++) { + if (sbusslot == sc->sc_range[srange].cspace) + break; + } + if (srange == sc->sc_nrange) + return (-1); + + oca[range].ca_bustype = BUS_FGA; + oca[range].ca_slot = sbusslot; + oca[range].ca_offset = sc->sc_range[srange].poffset | sbusoffset; + oca[range].ca_ra.ra_name = "fvme"; + oca[range].ca_ra.ra_nreg = 2; + oca[range].ca_ra.ra_reg[0].rr_len = vmelen; + oca[range].ca_ra.ra_reg[0].rr_paddr = + (void *)(sc->sc_range[srange].poffset | sbusoffset); + oca[range].ca_ra.ra_reg[0].rr_iospace = sbusslot; + oca[range].ca_ra.ra_reg[1].rr_iospace = vmecap; + oca[range].ca_ra.ra_reg[1].rr_paddr = (void*)vmebase; + oca[range].ca_ra.ra_reg[1].rr_len = vmelen; + + /* 1. Setup slot select register for this range. */ + switch (sbusslot) { + case 1: + sval = SBUS_SSEL_Y_SLOT1; + break; + case 2: + sval = SBUS_SSEL_Y_SLOT2; + break; + case 3: + sval = SBUS_SSEL_Y_SLOT3; + break; + case 4: + sval = SBUS_SSEL_Y_SLOT4; + break; + case 5: + sval = SBUS_SSEL_Y_SLOT5; + break; + default: + return (-1); + } + + if (range & 1) { + regs->sbus_ssel[range >> 1] &= ~SBUS_SSEL_Y; + regs->sbus_ssel[range >> 1] |= sval; + } + else { + regs->sbus_ssel[range >> 1] &= ~SBUS_SSEL_X; + regs->sbus_ssel[range >> 1] |= sval << 4; + } + + /* 2. Setup and enable the VME master range. */ + rval = regs->vme_range[range]; + rval &= ~(VME_RANGE_VMAE | VME_RANGE_VMAT); + rval |= (vmebase >> 13) & (VME_RANGE_VMAE | VME_RANGE_VMAT); + rval &= ~VME_RANGE_VMRCC; + rval |= ((sbusoffset << 4) | (vmelen << 3)) & VME_RANGE_VMRCC; + rval &= ~VME_RANGE_DECEN; + regs->vme_range[range] = rval; + + /* 3. Setup addr/data capabilities for the range. */ + regs->vme_master_cap[range] &= + ~(VME_MASTER_CAP_DATA | VME_MASTER_CAP_ADDR); + regs->vme_master_cap[range] |= vmecap; + + (void)config_found(&sc->sc_dev, (void *)&oca[range], fgaprint); + + return (0); +} + +int +fga_hwintr1(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + u_int32_t bits = 0, stat; + int r = 0, s; + + s = splhigh(); + stat = regs->intr_stat; + splx(s); + + if ((stat & INTR_STAT_VMEIRQ1) == 0) { + bits |= INTR_STAT_VMEIRQ1; + r |= fga_intrvec(sc, regs->viack_emu1); + } + + s = splhigh(); + regs->intr_stat &= ~bits; + splx(s); + + return (r); +} + +int +fga_hwintr2(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + int r = 0; + + if ((regs->intr_stat & INTR_STAT_VMEIRQ2) == 0) + r |= fga_intrvec(sc, regs->viack_emu2); + + return (r); +} + +int +fga_hwintr3(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + int r = 0; + + /* vme irq 3 */ + if ((regs->intr_stat & INTR_STAT_VMEIRQ3) == 0) + r |= fga_intrvec(sc, regs->viack_emu3); + + return (r); +} + +int +fga_hwintr4(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + int r = 0; + + if ((regs->intr_stat & INTR_STAT_VMEIRQ4) == 0) + r |= fga_intrvec(sc, regs->viack_emu4); + + return (r); +} + +int +fga_hwintr5(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + int r = 0; + + if ((regs->intr_stat & INTR_STAT_VMEIRQ5) == 0) + r |= fga_intrvec(sc, regs->viack_emu5); + + return (r); +} + +int +fga_hwintr6(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + int r = 0; + + if ((regs->intr_stat & INTR_STAT_VMEIRQ6) == 0) + r |= fga_intrvec(sc, regs->viack_emu6); + + return (r); +} + +int +fga_hwintr7(v) + void *v; +{ + struct fga_softc *sc = v; + struct fga_regs *regs = sc->sc_regs; + int r = 0, s; + u_int32_t bits = 0, stat; + + s = splhigh(); + stat = regs->intr_stat; + splx(s); + +#ifdef DDB + if (sc->sc_abort && (stat & INTR_STAT_ABORT) == 0) { + bits |= INTR_STAT_ABORT; + r |= 1; + Debugger(); + } +#endif + + if ((regs->intr_stat & INTR_STAT_VMEIRQ7) == 0) { + bits |= INTR_STAT_VMEIRQ7; + r |= fga_intrvec(sc, regs->viack_emu7); + } + + s = splhigh(); + regs->intr_stat &= ~bits; + splx(s); + + return (r); +} + +/* + * Handle a VME vectored interrupt. + */ +int +fga_intrvec(sc, vec) + struct fga_softc *sc; + u_int8_t vec; +{ + struct intrhand *ih; + int r, s = 0; + + if (sc->sc_vmevec == NULL) + return (0); + + for (ih = sc->sc_vmevec[vec]; ih; ih = ih->ih_next) { + r = (*ih->ih_fun)(ih->ih_arg); + if (r > 0) + return (r); + s |= r; + } + + return (s); +} + +/* + * Establish a VME level/vector interrupt. + */ +int +fga_intr_establish(sc, vec, level, ih) + struct fga_softc *sc; + int vec, level; + struct intrhand *ih; +{ + struct intrhand *ihs; + u_int8_t level_to_sint[] = { + IRQ_MAP_INT, + IRQ_MAP_SINT1, + IRQ_MAP_SINT2, + IRQ_MAP_SINT3, + IRQ_MAP_SINT4, + IRQ_MAP_SINT5, + IRQ_MAP_SINT6, + IRQ_MAP_SINT7 + }; + u_int8_t level_to_irqmap[] = {0xff, 6, 5, 4, 3, 2, 1, 0}; + + if (level < 1 || level > 7) + panic("fga_level"); + + /* setup vector handler */ + if (sc->sc_vmevec == NULL) { + sc->sc_vmevec = (struct intrhand **)malloc(256 * + sizeof(struct intrhand *), M_DEVBUF, M_NOWAIT); + if (sc->sc_vmevec == NULL) + panic("fga_addirq"); + bzero(sc->sc_vmevec, 256 * sizeof(struct intrhand)); + } + if (sc->sc_vmevec[vec] == NULL) + sc->sc_vmevec[vec] = ih; + else { + ihs = sc->sc_vmevec[vec]; + while (ihs->ih_next) + ihs = ihs->ih_next; + ih->ih_next = ih; + } + + /* setup hardware handler */ + fga_hwintr_establish(sc, level_to_sint[level]); + + /* setup/enable vme -> sbus irq mapping */ + sc->sc_regs->virq_map[level_to_irqmap[level]] &= ~IRQ_MAP_INT_MASK; + sc->sc_regs->virq_map[level_to_irqmap[level]] |= level_to_sint[level]; + sc->sc_regs->virq_map[level_to_irqmap[level]] &= ~IRQ_MAP_ENABLE; + + return (0); +} + +/* + * Establish a hardware interrupt, making sure we're not there already. + */ +int +fga_hwintr_establish(sc, sint) + struct fga_softc *sc; + u_int8_t sint; +{ + int sint_to_pri[] = {0, 2, 3, 5, 6, 7, 8, 9}; + + if (sc->sc_established & (1 << sint)) + return (0); + + switch (sint) { + case 1: + sc->sc_ih1.ih_fun = fga_hwintr1; + sc->sc_ih1.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih1); + break; + case 2: + sc->sc_ih2.ih_fun = fga_hwintr2; + sc->sc_ih2.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih2); + break; + case 3: + sc->sc_ih3.ih_fun = fga_hwintr3; + sc->sc_ih3.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih3); + break; + case 4: + sc->sc_ih4.ih_fun = fga_hwintr4; + sc->sc_ih4.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih4); + break; + case 5: + sc->sc_ih5.ih_fun = fga_hwintr5; + sc->sc_ih5.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih5); + break; + case 6: + sc->sc_ih6.ih_fun = fga_hwintr6; + sc->sc_ih6.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih6); + break; + case 7: + sc->sc_ih7.ih_fun = fga_hwintr7; + sc->sc_ih7.ih_arg = sc; + intr_establish(sint_to_pri[sint], &sc->sc_ih7); + break; + default: + panic("fga_sint"); + } + + sc->sc_established |= 1 << sint; + return (0); +} + +int +fgaopen(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + if (fga_cd.cd_ndevs == 0 || fga_cd.cd_ndevs != 0) + return (ENXIO); + return (0); +} + +int +fgaclose(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + return (0); +} + +int +fgaioctl(dev, cmd, data, flags, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + struct fga_softc *sc = fga_cd.cd_devs[0]; + struct fga_sem *fsem = (struct fga_sem *)data; + int error = 0; + + switch (cmd) { + case FGAIOCSEM: + if (fsem->fgasem_num >= 48) { + error = ENOENT; + break; + } + sc->sc_regs->sem[fsem->fgasem_num] = 0xff; + break; + case FGAIOGSEM: + if (fsem->fgasem_num >= 48) { + error = ENOENT; + break; + } + fsem->fgasem_val = + (sc->sc_regs->sem[fsem->fgasem_num] & MBOX_SEM) ? 0 : 1; + break; + case FGAIOCMBX: + if (fsem->fgasem_num >= 16) { + error = ENOENT; + break; + } + sc->sc_regs->mbox[fsem->fgasem_num] = 0xff; + break; + case FGAIOGMBX: + if (fsem->fgasem_num >= 16) { + error = ENOENT; + break; + } + fsem->fgasem_val = + sc->sc_regs->mbox[fsem->fgasem_num] ? 0 : 1; + break; + default: + error = EINVAL; + } + + return (error); +} + +int +fvmematch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + + if (strcmp("fvme", ra->ra_name) || ca->ca_bustype != BUS_FGA) + return (0); + + return (1); +} + +struct fvme_types { + int data_cap; + int addr_cap; + char *name; + int bustype; +} fvme_types[] = { + {0, 0, "a16d8", BUS_FGA_A16D8}, + {0, 1, "a24d8", BUS_FGA_A24D8}, + {0, 2, "a32d8", BUS_FGA_A32D8}, + {1, 0, "a16d16", BUS_FGA_A16D16}, + {1, 1, "a24d16", BUS_FGA_A24D16}, + {1, 2, "a32d16", BUS_FGA_A32D16}, + {2, 0, "a16d32", BUS_FGA_A16D32}, + {2, 1, "a24d32", BUS_FGA_A24D32}, + {2, 2, "a32d32", BUS_FGA_A32D32}, + {3, 0, "a16blt", -1}, + {3, 1, "a24blt", -1}, + {3, 2, "a32blt", -1}, + {4, 0, "a16mblt", -1}, + {4, 1, "a24mblt", -1}, + {4, 2, "a32mblt", -1}, + {-1, -1, "", -1}, +}; + +void +fvmeattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct confargs *ca = aux; + struct fvme_types *p; + int dtype, atype; + + atype = (ca->ca_ra.ra_reg[1].rr_iospace & VME_MASTER_CAP_ADDR) >> 2; + dtype = (ca->ca_ra.ra_reg[1].rr_iospace & VME_MASTER_CAP_DATA) >> 5; + for (p = fvme_types; p->data_cap != -1; p++) { + if (p->data_cap == dtype && p->addr_cap == atype) + break; + } + if (p->data_cap == -1) { + printf(" unknown addr/data capability\n"); + return; + } + printf(": %s", p->name); + if (p->bustype == -1) { + printf(" unsupported\n"); + return; + } + ca->ca_ra.ra_reg[1].rr_iospace = p->bustype; + + printf(" offset 0x%x len 0x%x\n", ca->ca_ra.ra_reg[1].rr_paddr, + ca->ca_ra.ra_reg[1].rr_len); + + (void)config_search(fvmescan, self, aux); +} + +int +fvmescan(parent, child, aux) + struct device *parent; + void *child, *aux; +{ + struct cfdata *cf = child; + struct confargs *ca = aux, oca; + int plen, paddr; + + if (cf->cf_loc[0] == -1) + return (0); + + if ((unsigned)cf->cf_loc[0] < (unsigned)ca->ca_ra.ra_reg[1].rr_paddr) + return (0); + + paddr = cf->cf_loc[0] - (int)ca->ca_ra.ra_reg[1].rr_paddr; + paddr = (int)ca->ca_ra.ra_reg[0].rr_paddr + paddr; + plen = cf->cf_loc[0] - (int)ca->ca_ra.ra_reg[1].rr_paddr; + plen = ca->ca_ra.ra_reg[1].rr_len - plen; + + oca.ca_bustype = ca->ca_ra.ra_reg[1].rr_iospace; + oca.ca_offset = cf->cf_loc[0]; + + oca.ca_ra.ra_nintr = 1; + oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1]; + oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2]; + oca.ca_ra.ra_name = cf->cf_driver->cd_name; + + oca.ca_ra.ra_nreg = 1; + oca.ca_ra.ra_reg[0].rr_paddr = (void *)paddr; + oca.ca_ra.ra_reg[0].rr_iospace = ca->ca_ra.ra_reg[0].rr_iospace; + oca.ca_ra.ra_reg[0].rr_len = plen; + oca.ca_ra.ra_reg[0].rr_paddr = + mapdev(&oca.ca_ra.ra_reg[0], TMPMAP_VA, 0, NBPG); + + if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) { + pmap_remove(pmap_kernel(), TMPMAP_VA, TMPMAP_VA + NBPG); + return (0); + } + pmap_remove(pmap_kernel(), TMPMAP_VA, TMPMAP_VA + NBPG); + + oca.ca_ra.ra_reg[0].rr_paddr = (void *)paddr; + config_attach(parent, cf, &oca, fvmeprint); + return (1); +} + +int +fvmeprint(args, name) + void *args; + const char *name; +{ + struct confargs *ca = args; + + if (name) + printf("%s at %s", ca->ca_ra.ra_name, name); + printf(" addr 0x%x", ca->ca_offset); + return (UNCONF); +} + +int +fvmeintrestablish(dsc, vec, level, ih) + struct device *dsc; + int vec, level; + struct intrhand *ih; +{ + struct fga_softc *fsc = (struct fga_softc *)dsc->dv_parent; + + return (fga_intr_establish(fsc, vec, level, ih)); +} |