summaryrefslogtreecommitdiff
path: root/sys/arch/sparc/dev/obio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sparc/dev/obio.c')
-rw-r--r--sys/arch/sparc/dev/obio.c266
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