diff options
Diffstat (limited to 'sys/arch/sparc/dev/obio.c')
-rw-r--r-- | sys/arch/sparc/dev/obio.c | 266 |
1 files changed, 194 insertions, 72 deletions
diff --git a/sys/arch/sparc/dev/obio.c b/sys/arch/sparc/dev/obio.c index 2787aa91c01..845d97dddd3 100644 --- a/sys/arch/sparc/dev/obio.c +++ b/sys/arch/sparc/dev/obio.c @@ -1,8 +1,9 @@ -/* $NetBSD: obio.c,v 1.24 1996/05/18 12:22:49 mrg Exp $ */ +/* $OpenBSD: obio.c,v 1.7 1997/08/08 08:25:20 downsj Exp $ */ +/* $NetBSD: obio.c,v 1.37 1997/07/29 09:58:11 fair Exp $ */ /* * Copyright (c) 1993, 1994 Theo de Raadt - * Copyright (c) 1995 Paul Kranenburg + * Copyright (c) 1995, 1997 Paul Kranenburg * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,28 +51,42 @@ #include <machine/ctlreg.h> #include <sparc/sparc/asm.h> #include <sparc/sparc/vaddrs.h> +#include <sparc/sparc/cpuvar.h> #include <sparc/dev/sbusvar.h> +#include <sparc/dev/vmereg.h> + +struct vmebus_softc { + struct device sc_dev; /* base device */ + struct vmebusreg *sc_reg; /* VME control registers */ + struct vmebusvec *sc_vec; /* VME interrupt vector */ + struct rom_range *sc_range; /* ROM range property */ + int sc_nrange; +}; +struct vmebus_softc *vmebus_sc;/*XXX*/ struct bus_softc { union { struct device scu_dev; /* base device */ struct sbus_softc scu_sbus; /* obio is another sbus slot */ + struct vmebus_softc scu_vme; } bu; -#define sc_dev bu.scu_dev }; + /* autoconfiguration driver */ static int busmatch __P((struct device *, void *, void *)); static void obioattach __P((struct device *, struct device *, void *)); static void vmesattach __P((struct device *, struct device *, void *)); static void vmelattach __P((struct device *, struct device *, void *)); +static void vmeattach __P((struct device *, struct device *, void *)); int busprint __P((void *, const char *)); +int vmeprint __P((void *, const char *)); static int busattach __P((struct device *, void *, void *, int)); -void * bus_map __P((struct rom_reg *, int, int)); int obio_scan __P((struct device *, void *, void *)); int vmes_scan __P((struct device *, void *, void *)); int vmel_scan __P((struct device *, void *, void *)); +void vmebus_translate __P((struct device *, struct confargs *, int)); int vmeintr __P((void *)); struct cfattach obio_ca = { @@ -98,6 +113,14 @@ struct cfdriver vmes_cd = { NULL, "vmes", DV_DULL }; +struct cfattach vme_ca = { + sizeof(struct bus_softc), busmatch, vmeattach +}; + +struct cfdriver vme_cd = { + NULL, "vme", DV_DULL +}; + struct intrhand **vmeints; @@ -106,7 +129,7 @@ busmatch(parent, vcf, aux) struct device *parent; void *vcf, *aux; { - struct cfdata *cf = vcf; + register struct cfdata *cf = vcf; register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; @@ -140,6 +163,17 @@ busprint(args, obio) return (UNCONF); } +int +vmeprint(args, name) + void *args; + const char *name; +{ + register struct confargs *ca = args; + + if (name) + printf("%s at %s", ca->ca_ra.ra_name, name); + return (UNCONF); +} void obioattach(parent, self, args) @@ -154,13 +188,16 @@ obioattach(parent, self, args) register char *name; register const char *sp; const char *const *ssp; + int rlen; extern int autoconf_nzs; static const char *const special4m[] = { /* find these first */ "eeprom", "counter", +#if 0 /* Not all sun4m's have an `auxio' */ "auxio", +#endif "", /* place device to ignore here */ "interrupt", @@ -187,7 +224,7 @@ obioattach(parent, self, args) * There is only one obio bus (it is in fact one of the Sbus slots) * How about VME? */ - if (sc->sc_dev.dv_unit > 0) { + if (self->dv_unit > 0) { printf(" unsupported\n"); return; } @@ -199,8 +236,16 @@ obioattach(parent, self, args) else oca.ca_ra.ra_bp = NULL; - sc->bu.scu_sbus.sc_range = ra->ra_range; - sc->bu.scu_sbus.sc_nrange = ra->ra_nrange; + node = ra->ra_node; + rlen = getproplen(node, "ranges"); + if (rlen > 0) { + sc->bu.scu_sbus.sc_nrange = rlen / sizeof(struct rom_range); + sc->bu.scu_sbus.sc_range = + (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); + if (sc->bu.scu_sbus.sc_range == 0) + panic("obio: PROM ranges too large: %d", rlen); + (void)getprop(node, "ranges", sc->bu.scu_sbus.sc_range, rlen); + } /* * Loop through ROM children, fixing any relative addresses @@ -218,7 +263,7 @@ obioattach(parent, self, args) sbus_translate(self, &oca); oca.ca_bustype = BUS_OBIO; - (void) config_found(&sc->sc_dev, (void *)&oca, busprint); + (void) config_found(self, (void *)&oca, busprint); } for (node = node0; node; node = nextsibling(node)) { @@ -237,7 +282,7 @@ obioattach(parent, self, args) /* Translate into parent address spaces */ sbus_translate(self, &oca); oca.ca_bustype = BUS_OBIO; - (void) config_found(&sc->sc_dev, (void *)&oca, busprint); + (void) config_found(self, (void *)&oca, busprint); } #endif } @@ -247,7 +292,8 @@ vmesattach(parent, self, args) struct device *parent, *self; void *args; { - if (CPU_ISSUN4M || self->dv_unit > 0) { + if (self->dv_unit > 0 || + (CPU_ISSUN4M && strncmp(parent->dv_xname, "vme", 3) != 0)) { printf(" unsupported\n"); return; } @@ -267,7 +313,8 @@ vmelattach(parent, self, args) struct device *parent, *self; void *args; { - if (CPU_ISSUN4M || self->dv_unit > 0) { + if (self->dv_unit > 0 || + (CPU_ISSUN4M && strncmp(parent->dv_xname, "vme", 3) != 0)) { printf(" unsupported\n"); return; } @@ -282,14 +329,116 @@ vmelattach(parent, self, args) bus_untmp(); } +void +vmeattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct vmebus_softc *sc = (struct vmebus_softc *)self; + struct confargs *ca = aux; + register struct romaux *ra = &ca->ca_ra; + int node, rlen; + struct confargs oca; + + if (!CPU_ISSUN4M || self->dv_unit > 0) { + printf(" unsupported\n"); + return; + } + + node = ra->ra_node; + + sc->sc_reg = (struct vmebusreg *) + mapdev(&ra->ra_reg[0], 0, 0, ra->ra_reg[0].rr_len); + sc->sc_vec = (struct vmebusvec *) + mapdev(&ra->ra_reg[1], 0, 0, ra->ra_reg[1].rr_len); + + /* + * Get "range" property, though we don't do anything with it yet. + */ + rlen = getproplen(node, "ranges"); + if (rlen > 0) { + sc->sc_nrange = rlen / sizeof(struct rom_range); + sc->sc_range = + (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT); + if (sc->sc_range == 0) + panic("vme: PROM ranges too large: %d", rlen); + (void)getprop(node, "ranges", sc->sc_range, rlen); + } + + vmebus_sc = sc; + printf(": version 0x%x\n", + sc->sc_reg->vmebus_cr & VMEBUS_CR_IMPL); + + if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "vme") == 0) + oca.ca_ra.ra_bp = ra->ra_bp + 1; + else + oca.ca_ra.ra_bp = NULL; + + oca.ca_ra.ra_name = "vmes"; + oca.ca_bustype = BUS_MAIN; + (void)config_found(self, (void *)&oca, vmeprint); + + oca.ca_ra.ra_name = "vmel"; + oca.ca_bustype = BUS_MAIN; + (void)config_found(self, (void *)&oca, vmeprint); +} + +void +vmebus_translate(dev, ca, bustype) + struct device *dev; + struct confargs *ca; + int bustype; +{ + struct vmebus_softc *sc = (struct vmebus_softc *)dev; + register int j; + int cspace; + + if (sc->sc_nrange == 0) + panic("vmebus: no ranges"); + + /* + * Find VMEbus modifier based on address space. + * XXX - should not be encoded in `ra_paddr' + */ + if (((u_long)ca->ca_ra.ra_paddr & 0xffff0000) == 0xffff0000) + cspace = VMEMOD_A16_D_S; + else if (((u_long)ca->ca_ra.ra_paddr & 0xff000000) == 0xff000000) + cspace = VMEMOD_A24_D_S; + else + cspace = VMEMOD_A32_D_S; + + cspace |= (bustype == BUS_VME32) ? VMEMOD_D32 : 0; + + /* Translate into parent address spaces */ + for (j = 0; j < sc->sc_nrange; j++) { + if (sc->sc_range[j].cspace == cspace) { +#if notyet + (int)ca->ca_ra.ra_paddr += + sc->sc_range[j].poffset; +#endif + (int)ca->ca_ra.ra_iospace = + sc->sc_range[j].pspace; + break; + } + } +} + +int bt2pmt[] = { + PMAP_OBIO, + PMAP_OBIO, + PMAP_VME16, + PMAP_VME32, + PMAP_OBIO +}; + int -busattach(parent, child, args, bustype) +busattach(parent, vcf, args, bustype) struct device *parent; - void *args, *child; + void *vcf, *args; int bustype; { -#if defined(SUN4) - struct cfdata *cf = child; +#if defined(SUN4) || defined(SUN4M) + register struct cfdata *cf = vcf; register struct confargs *ca = args; struct confargs oca; caddr_t tmp; @@ -309,24 +458,24 @@ busattach(parent, child, args, bustype) * XXX: We also assume that 4/[23]00 obio addresses * must be 0xZYYYYYYY, where (Z != 0) */ - if (cpumod == SUN4_100 && (cf->cf_loc[0] & 0xf0000000)) + if (cpuinfo.cpu_type == CPUTYP_4_100 && + (cf->cf_loc[0] & 0xf0000000)) return 0; - if (cpumod != SUN4_100 && !(cf->cf_loc[0] & 0xf0000000)) + if (cpuinfo.cpu_type != CPUTYP_4_100 && + !(cf->cf_loc[0] & 0xf0000000)) return 0; } - if (parent->dv_cfdata->cf_driver->cd_indirect) { - printf(" indirect devices not supported\n"); - return 0; - } - - oca.ca_ra.ra_iospace = -1; oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0]; oca.ca_ra.ra_len = 0; oca.ca_ra.ra_nreg = 1; + if (CPU_ISSUN4M) + vmebus_translate(parent->dv_parent, &oca, bustype); + else + oca.ca_ra.ra_iospace = bt2pmt[bustype]; + if (oca.ca_ra.ra_paddr) - tmp = (caddr_t)bus_tmp(oca.ca_ra.ra_paddr, - bustype); + tmp = (caddr_t)mapdev(oca.ca_ra.ra_reg, TMPMAP_VA, 0, NBPG); else tmp = NULL; oca.ca_ra.ra_vaddr = tmp; @@ -364,8 +513,7 @@ busattach(parent, child, args, bustype) */ if (oca.ca_ra.ra_len) oca.ca_ra.ra_vaddr = - bus_map(oca.ca_ra.ra_reg, - oca.ca_ra.ra_len, oca.ca_bustype); + bus_map(oca.ca_ra.ra_reg, oca.ca_ra.ra_len); config_attach(parent, cf, &oca, busprint); return 1; @@ -421,18 +569,19 @@ int vmeintr(arg) void *arg; { - int level = (int)arg, vec; + int pil = (int)arg, level, vec; struct intrhand *ih; int i = 0; -#ifdef DIAGNOSTIC - if (!CPU_ISSUN4) { + level = (pil_to_vme[pil] << 1) | 1; + + if (CPU_ISSUN4) { + vec = ldcontrolb((caddr_t)(AC_VMEINTVEC | level)); + } else if (CPU_ISSUN4M) { + vec = vmebus_sc->sc_vec->vmebusvec[level]; + } else panic("vme: spurious interrupt"); - } -#endif - vec = ldcontrolb((caddr_t) - (AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1)); if (vec == -1) { printf("vme: spurious interrupt\n"); return 0; @@ -451,13 +600,11 @@ vmeintr_establish(vec, level, ih) { struct intrhand *ihs; - if (!CPU_ISSUN4) { - panic("vmeintr_establish: not supported on cpu-type %d", - cputyp); - } + if (vmeints == NULL) + panic("vmeintr_establish: interrupt vector not allocated"); if (vec == -1) - panic("vmeintr_establish: uninitialized vec\n"); + panic("vmeintr_establish: uninitialized vec"); if (vmeints[vec] == NULL) vmeints[vec] = ih; @@ -489,28 +636,16 @@ vmeintr_establish(vec, level, ih) * Else, create a new mapping. */ void * -bus_map(pa, len, bustype) +bus_map(pa, len) struct rom_reg *pa; int len; - int bustype; { - u_long pf = (u_long)(pa->rr_paddr) >> PGSHIFT; - u_long va, pte; - int pgtype = -1; - - switch (bt2pmt[bustype]) { - case PMAP_OBIO: - pgtype = PG_OBIO; - break; - case PMAP_VME32: - pgtype = PG_VME32; - break; - case PMAP_VME16: - pgtype = PG_VME16; - break; - } - if (len <= NBPG) { + if (CPU_ISSUN4 && len <= NBPG) { + u_long pf = (u_long)(pa->rr_paddr) >> PGSHIFT; + int pgtype = PMAP_T2PTE_4(pa->rr_iospace); + u_long va, pte; + for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) { pte = getpte(va); if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype && @@ -520,21 +655,8 @@ bus_map(pa, len, bustype) /* note: preserve page offset */ } } - return mapiodev(pa, 0, len, bustype); -} - -void * -bus_tmp(pa, bustype) - void *pa; - int bustype; -{ - vm_offset_t addr = (vm_offset_t)pa & ~PGOFSET; - int pmtype = bt2pmt[bustype]; - pmap_enter(pmap_kernel(), TMPMAP_VA, - addr | pmtype | PMAP_NC, - VM_PROT_READ | VM_PROT_WRITE, 1); - return ((void *)(TMPMAP_VA | ((u_long) pa & PGOFSET)) ); + return mapiodev(pa, 0, len); } void |