summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorscw <scw@NetBSD.org>2002-02-12 20:38:43 +0000
committerscw <scw@NetBSD.org>2002-02-12 20:38:43 +0000
commit08bde987bb7ce6a5fa7f4c155a4e3718b5877c20 (patch)
treeeb3b3f86030960c01c86a78f8cd66ccacf3ef185 /sys/dev
parentacb4381e275e6a3bafb36c6803893fbe78f25e6e (diff)
Separate out devices common to many Motorola mvme boards (68k, 88k and ppc)
in preparation for future mvmeppc and mvme88k ports. This needs a bit if tidying up to make it trully shareable, which will happen as the new mvme ports are added.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/mvme/if_ie_mvme.c352
-rw-r--r--sys/dev/mvme/if_iereg.h64
-rw-r--r--sys/dev/mvme/lpt_mvme.c396
-rw-r--r--sys/dev/mvme/lpt_pcctwo.c294
-rw-r--r--sys/dev/mvme/lptvar.h95
-rw-r--r--sys/dev/mvme/memc.c640
-rw-r--r--sys/dev/mvme/memcreg.h177
-rw-r--r--sys/dev/mvme/memcvar.h69
-rw-r--r--sys/dev/mvme/mvmebus.c961
-rw-r--r--sys/dev/mvme/mvmebus.h161
-rw-r--r--sys/dev/mvme/osiop_pcctwo.c191
-rw-r--r--sys/dev/mvme/pcctwo.c204
-rw-r--r--sys/dev/mvme/pcctworeg.h316
-rw-r--r--sys/dev/mvme/pcctwovar.h103
-rw-r--r--sys/dev/mvme/vme_two.c353
-rw-r--r--sys/dev/mvme/vme_two_isr.c429
-rw-r--r--sys/dev/mvme/vme_tworeg.h526
-rw-r--r--sys/dev/mvme/vme_twovar.h79
18 files changed, 5410 insertions, 0 deletions
diff --git a/sys/dev/mvme/if_ie_mvme.c b/sys/dev/mvme/if_ie_mvme.c
new file mode 100644
index 00000000000..45e8d6e7884
--- /dev/null
+++ b/sys/dev/mvme/if_ie_mvme.c
@@ -0,0 +1,352 @@
+/* $NetBSD: if_ie_mvme.c,v 1.1 2002/02/12 20:38:43 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/ic/i82586reg.h>
+#include <dev/ic/i82586var.h>
+
+#include <dev/mvme/if_iereg.h>
+#include <dev/mvme/pcctwovar.h>
+#include <dev/mvme/pcctworeg.h>
+
+
+int ie_pcctwo_match __P((struct device *, struct cfdata *, void *));
+void ie_pcctwo_attach __P((struct device *, struct device *, void *));
+
+struct ie_pcctwo_softc {
+ struct ie_softc ps_ie;
+ bus_space_tag_t ps_bust;
+ bus_space_handle_t ps_bush;
+ struct evcnt ps_evcnt;
+};
+
+struct cfattach ie_pcctwo_ca = {
+ sizeof(struct ie_pcctwo_softc), ie_pcctwo_match, ie_pcctwo_attach
+};
+
+extern struct cfdriver ie_cd;
+
+
+/* Functions required by the i82586 MI driver */
+static void ie_reset __P((struct ie_softc *, int));
+static int ie_intrhook __P((struct ie_softc *, int));
+static void ie_hwinit __P((struct ie_softc *));
+static void ie_atten __P((struct ie_softc *, int));
+
+static void ie_copyin __P((struct ie_softc *, void *, int, size_t));
+static void ie_copyout __P((struct ie_softc *, const void *, int, size_t));
+
+static u_int16_t ie_read_16 __P((struct ie_softc *, int));
+static void ie_write_16 __P((struct ie_softc *, int, u_int16_t));
+static void ie_write_24 __P((struct ie_softc *, int, int));
+
+/*
+ * i82596 Support Routines for MVME1[67][27] and MVME187 Boards
+ */
+static void
+ie_reset(sc, why)
+ struct ie_softc *sc;
+ int why;
+{
+ struct ie_pcctwo_softc *ps;
+ u_int32_t scp_addr;
+
+ ps = (struct ie_pcctwo_softc *) sc;
+
+ switch (why) {
+ case CHIP_PROBE:
+ case CARD_RESET:
+ bus_space_write_2(ps->ps_bust, ps->ps_bush, IE_MPUREG_UPPER,
+ IE_PORT_RESET);
+ bus_space_write_2(ps->ps_bust, ps->ps_bush, IE_MPUREG_LOWER, 0);
+ delay(1000);
+
+ /*
+ * Set the BUSY and BUS_USE bytes here, since the MI code
+ * incorrectly assumes it can use byte addressing to set it.
+ * (due to wrong-endianess of the chip)
+ */
+ ie_write_16(sc, IE_ISCP_BUSY(sc->iscp), 1);
+ ie_write_16(sc, IE_SCP_BUS_USE(sc->scp), IE_BUS_USE);
+
+ scp_addr = sc->scp + (u_int) sc->sc_iobase;
+ scp_addr |= IE_PORT_ALT_SCP;
+
+ bus_space_write_2(ps->ps_bust, ps->ps_bush, IE_MPUREG_UPPER,
+ scp_addr & 0xffff);
+ bus_space_write_2(ps->ps_bust, ps->ps_bush, IE_MPUREG_LOWER,
+ (scp_addr >> 16) & 0xffff);
+ delay(1000);
+ break;
+ }
+}
+
+/* ARGSUSED */
+static int
+ie_intrhook(sc, when)
+ struct ie_softc *sc;
+ int when;
+{
+ struct ie_pcctwo_softc *ps;
+ u_int8_t reg;
+
+ ps = (struct ie_pcctwo_softc *) sc;
+
+ if (when == INTR_EXIT) {
+ reg = pcc2_reg_read(sys_pcctwo, PCC2REG_ETH_ICSR);
+ reg |= PCCTWO_ICR_ICLR;
+ pcc2_reg_write(sys_pcctwo, PCC2REG_ETH_ICSR, reg);
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+static void
+ie_hwinit(sc)
+ struct ie_softc *sc;
+{
+ u_int8_t reg;
+
+ reg = pcc2_reg_read(sys_pcctwo, PCC2REG_ETH_ICSR);
+ reg |= PCCTWO_ICR_IEN | PCCTWO_ICR_ICLR;
+ pcc2_reg_write(sys_pcctwo, PCC2REG_ETH_ICSR, reg);
+}
+
+/* ARGSUSED */
+static void
+ie_atten(sc, reason)
+ struct ie_softc *sc;
+ int reason;
+{
+ struct ie_pcctwo_softc *ps;
+
+ ps = (struct ie_pcctwo_softc *) sc;
+ bus_space_write_4(ps->ps_bust, ps->ps_bush, IE_MPUREG_CA, 0);
+}
+
+static void
+ie_copyin(sc, dst, offset, size)
+ struct ie_softc *sc;
+ void *dst;
+ int offset;
+ size_t size;
+{
+ if (size == 0) /* This *can* happen! */
+ return;
+
+#if 0
+ bus_space_read_region_1(sc->bt, sc->bh, offset, dst, size);
+#else
+ /* A minor optimisation ;-) */
+ memcpy(dst, (void *) ((u_long) sc->bh + (u_long) offset), size);
+#endif
+}
+
+static void
+ie_copyout(sc, src, offset, size)
+ struct ie_softc *sc;
+ const void *src;
+ int offset;
+ size_t size;
+{
+ if (size == 0) /* This *can* happen! */
+ return;
+
+#if 0
+ bus_space_write_region_1(sc->bt, sc->bh, offset, src, size);
+#else
+ /* A minor optimisation ;-) */
+ memcpy((void *) ((u_long) sc->bh + (u_long) offset), src, size);
+#endif
+}
+
+static u_int16_t
+ie_read_16(sc, offset)
+ struct ie_softc *sc;
+ int offset;
+{
+
+ return (bus_space_read_2(sc->bt, sc->bh, offset));
+}
+
+static void
+ie_write_16(sc, offset, value)
+ struct ie_softc *sc;
+ int offset;
+ u_int16_t value;
+{
+
+ bus_space_write_2(sc->bt, sc->bh, offset, value);
+}
+
+static void
+ie_write_24(sc, offset, addr)
+ struct ie_softc *sc;
+ int offset;
+ int addr;
+{
+
+ addr += (int) sc->sc_iobase;
+
+ bus_space_write_2(sc->bt, sc->bh, offset, addr & 0xffff);
+ bus_space_write_2(sc->bt, sc->bh, offset + 2, (addr >> 16) & 0x00ff);
+}
+
+/* ARGSUSED */
+int
+ie_pcctwo_match(parent, cf, args)
+ struct device *parent;
+ struct cfdata *cf;
+ void *args;
+{
+ struct pcctwo_attach_args *pa;
+
+ pa = args;
+
+ if (strcmp(pa->pa_name, ie_cd.cd_name))
+ return (0);
+
+ pa->pa_ipl = cf->pcctwocf_ipl;
+
+ return (1);
+}
+
+/* ARGSUSED */
+void
+ie_pcctwo_attach(parent, self, args)
+ struct device *parent;
+ struct device *self;
+ void *args;
+{
+ struct pcctwo_attach_args *pa;
+ struct ie_pcctwo_softc *ps;
+ struct ie_softc *sc;
+ bus_dma_segment_t seg;
+ int rseg;
+
+ pa = (struct pcctwo_attach_args *) args;
+ ps = (struct ie_pcctwo_softc *) self;
+ sc = (struct ie_softc *) self;
+
+ /* Map the MPU controller registers in PCCTWO space */
+ ps->ps_bust = pa->pa_bust;
+ bus_space_map(pa->pa_bust, pa->pa_offset, IE_MPUREG_SIZE,
+ 0, &ps->ps_bush);
+
+ /* Get contiguous DMA-able memory for the IE chip */
+ if (bus_dmamem_alloc(pa->pa_dmat, ether_data_buff_size, NBPG, 0,
+ &seg, 1, &rseg,
+ BUS_DMA_NOWAIT | BUS_DMA_ONBOARD_RAM | BUS_DMA_24BIT) != 0) {
+ printf("%s: Failed to allocate ether buffer\n", self->dv_xname);
+ return;
+ }
+ if (bus_dmamem_map(pa->pa_dmat, &seg, rseg, ether_data_buff_size,
+ (caddr_t *) & sc->sc_maddr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
+ printf("%s: Failed to map ether buffer\n", self->dv_xname);
+ bus_dmamem_free(pa->pa_dmat, &seg, rseg);
+ return;
+ }
+ sc->bt = pa->pa_bust;
+ sc->bh = (bus_space_handle_t) sc->sc_maddr; /* XXXSCW Better way? */
+ sc->sc_iobase = (void *) seg.ds_addr;
+ sc->sc_msize = ether_data_buff_size;
+ memset(sc->sc_maddr, 0, ether_data_buff_size);
+
+ sc->hwreset = ie_reset;
+ sc->hwinit = ie_hwinit;
+ sc->chan_attn = ie_atten;
+ sc->intrhook = ie_intrhook;
+ sc->memcopyin = ie_copyin;
+ sc->memcopyout = ie_copyout;
+ sc->ie_bus_barrier = NULL;
+ sc->ie_bus_read16 = ie_read_16;
+ sc->ie_bus_write16 = ie_write_16;
+ sc->ie_bus_write24 = ie_write_24;
+ sc->sc_mediachange = NULL;
+ sc->sc_mediastatus = NULL;
+
+ sc->scp = 0;
+ sc->iscp = sc->scp + ((IE_SCP_SZ + 15) & ~15);
+ sc->scb = sc->iscp + IE_ISCP_SZ;
+ sc->buf_area = sc->scb + IE_SCB_SZ;
+ sc->buf_area_sz = sc->sc_msize - (sc->buf_area - sc->scp);
+
+ /*
+ * BUS_USE -> Interrupt Active High (edge-triggered),
+ * Lock function enabled,
+ * Internal bus throttle timer triggering,
+ * 82586 operating mode.
+ */
+ ie_write_16(sc, IE_SCP_BUS_USE(sc->scp), IE_BUS_USE);
+ ie_write_24(sc, IE_SCP_ISCP(sc->scp), sc->iscp);
+ ie_write_16(sc, IE_ISCP_SCB(sc->iscp), sc->scb);
+ ie_write_24(sc, IE_ISCP_BASE(sc->iscp), sc->scp);
+
+ /* This has the side-effect of resetting the chip */
+ i82586_proberam(sc);
+
+ /* Attach the MI back-end */
+ i82586_attach(sc, "onboard", mvme_ea, NULL, 0, 0);
+
+ /* Register the event counter */
+ evcnt_attach_dynamic(&ps->ps_evcnt, EVCNT_TYPE_INTR,
+ pcctwointr_evcnt(pa->pa_ipl), "ether", sc->sc_dev.dv_xname);
+
+ /* Finally, hook the hardware interrupt */
+ pcctwointr_establish(PCCTWOV_LANC_IRQ, i82586_intr, pa->pa_ipl, sc,
+ &ps->ps_evcnt);
+}
diff --git a/sys/dev/mvme/if_iereg.h b/sys/dev/mvme/if_iereg.h
new file mode 100644
index 00000000000..5a1354cc2fd
--- /dev/null
+++ b/sys/dev/mvme/if_iereg.h
@@ -0,0 +1,64 @@
+/* $NetBSD: if_iereg.h,v 1.1 2002/02/12 20:38:43 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Definitions for the MPU Port and Channel Attention registers
+ * of the onboard i82596 Ethernet controller on MVME68K and MVME88K boards.
+ */
+#ifndef __mvme_if_iereg_h
+#define __mvme_if_iereg_h
+
+#define IE_MPUREG_UPPER 0x00 /* Upper Command Word */
+#define IE_MPUREG_LOWER 0x02 /* Lower Command Word */
+#define IE_MPUREG_CA 0x04 /* Channel Attention. Dummy Rd or Wr */
+
+#define IE_MPUREG_SIZE 0x08
+
+/*
+ * BUS_USE -> Interrupt Active High (edge-triggered),
+ * Lock function enabled,
+ * Internal bus throttle timer triggering,
+ * 82586 operating mode.
+ */
+#define IE_BUS_USE (IE_SYSBUS_596_INTHIGH | \
+ IE_SYSBUS_596_LOCK | \
+ IE_SYSBUS_596_TRGINT | \
+ IE_SYSBUS_596_82586 | \
+ IE_SYSBUS_596_RSVD_SET)
+
+#endif /* __mvme_if_iereg_h */
diff --git a/sys/dev/mvme/lpt_mvme.c b/sys/dev/mvme/lpt_mvme.c
new file mode 100644
index 00000000000..ccaaba7cec7
--- /dev/null
+++ b/sys/dev/mvme/lpt_mvme.c
@@ -0,0 +1,396 @@
+/* $NetBSD: lpt_mvme.c,v 1.1 2002/02/12 20:38:44 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1993, 1994 Charles M. Hannum.
+ * Copyright (c) 1990 William F. Jolitz, TeleMuse
+ * 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 software is a component of "386BSD" developed by
+ * William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE OF THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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.
+ */
+
+/*
+ * Device Driver for an MVME68K/MVME88K board's parallel printer port
+ * This driver attaches above the board-specific back-end.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/mvme/lptvar.h>
+
+
+#define TIMEOUT hz*16 /* wait up to 16 seconds for a ready */
+#define STEP hz/4
+
+#define LPTPRI (PZERO+8)
+#define LPT_BSIZE 1024
+
+#if !defined(DEBUG) || !defined(notdef)
+#define LPRINTF(a)
+#else
+#define LPRINTF if (lptdebug) printf a
+int lptdebug = 1;
+#endif
+
+/* {b,c}devsw[] function prototypes */
+dev_type_open(lptopen);
+dev_type_close(lptclose);
+dev_type_write(lptwrite);
+dev_type_ioctl(lptioctl);
+
+
+#define LPTUNIT(s) (minor(s) & 0x0f)
+#define LPTFLAGS(s) (minor(s) & 0xf0)
+
+static void lpt_wakeup __P((void *arg));
+static int pushbytes __P((struct lpt_softc *));
+
+extern struct cfdriver lpt_cd;
+
+
+void
+lpt_attach_subr(sc)
+ struct lpt_softc *sc;
+{
+
+ sc->sc_state = 0;
+ callout_init(&sc->sc_wakeup_ch);
+}
+
+/*
+ * Reset the printer, then wait until it's selected and not busy.
+ */
+int
+lptopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit;
+ u_char flags;
+ struct lpt_softc *sc;
+ int error;
+ int spin;
+
+ unit = LPTUNIT(dev);
+ flags = LPTFLAGS(dev);
+
+ if (unit >= lpt_cd.cd_ndevs)
+ return (ENXIO);
+ sc = lpt_cd.cd_devs[unit];
+ if (!sc)
+ return (ENXIO);
+
+#ifdef DIAGNOSTIC
+ if (sc->sc_state)
+ printf("%s: stat=0x%x not zero\n", sc->sc_dev.dv_xname,
+ sc->sc_state);
+#endif
+
+ if (sc->sc_state)
+ return (EBUSY);
+
+ sc->sc_state = LPT_INIT;
+ sc->sc_flags = flags;
+ LPRINTF(("%s: open: flags=0x%x\n", sc->sc_dev.dv_xname, flags));
+
+ if ((flags & LPT_NOPRIME) == 0) {
+ /* assert Input Prime for 100 usec to start up printer */
+ (sc->sc_funcs->lf_iprime) (sc);
+ }
+
+ /* select fast or slow strobe depending on minor device number */
+ if (flags & LPT_FAST_STROBE)
+ (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_FAST);
+ else
+ (sc->sc_funcs->lf_speed) (sc, LPT_STROBE_SLOW);
+
+ /* wait till ready (printer running diagnostics) */
+ for (spin = 0; (sc->sc_funcs->lf_notrdy) (sc, 1); spin += STEP) {
+ if (spin >= TIMEOUT) {
+ sc->sc_state = 0;
+ return (EBUSY);
+ }
+ /* wait 1/4 second, give up if we get a signal */
+ error = tsleep((caddr_t) sc, LPTPRI | PCATCH, "lptopen", STEP);
+ if (error != EWOULDBLOCK) {
+ sc->sc_state = 0;
+ return (error);
+ }
+ }
+
+ sc->sc_inbuf = geteblk(LPT_BSIZE);
+ sc->sc_count = 0;
+ sc->sc_state = LPT_OPEN;
+
+ if ((sc->sc_flags & LPT_NOINTR) == 0)
+ lpt_wakeup(sc);
+
+ (sc->sc_funcs->lf_open) (sc, sc->sc_flags & LPT_NOINTR);
+
+ LPRINTF(("%s: opened\n", sc->sc_dev.dv_xname));
+ return (0);
+}
+
+void
+lpt_wakeup(arg)
+ void *arg;
+{
+ struct lpt_softc *sc;
+ int s;
+
+ sc = arg;
+
+ s = spltty();
+ lpt_intr(sc);
+ splx(s);
+
+ callout_reset(&sc->sc_wakeup_ch, STEP, lpt_wakeup, sc);
+}
+
+/*
+ * Close the device, and free the local line buffer.
+ */
+int
+lptclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct lpt_softc *sc;
+ int unit;
+
+ unit = LPTUNIT(dev);
+ sc = lpt_cd.cd_devs[unit];
+
+ if (sc->sc_count)
+ (void) pushbytes(sc);
+
+ if ((sc->sc_flags & LPT_NOINTR) == 0)
+ callout_stop(&sc->sc_wakeup_ch);
+
+ (sc->sc_funcs->lf_close) (sc);
+
+ sc->sc_state = 0;
+ brelse(sc->sc_inbuf);
+
+ LPRINTF(("%s: closed\n", sc->sc_dev.dv_xname));
+ return (0);
+}
+
+int
+pushbytes(sc)
+ struct lpt_softc *sc;
+{
+ int s, error, spin, tic;
+
+ if (sc->sc_flags & LPT_NOINTR) {
+ while (sc->sc_count > 0) {
+ spin = 0;
+ while ((sc->sc_funcs->lf_notrdy) (sc, 0)) {
+ if (++spin < sc->sc_spinmax)
+ continue;
+ tic = 0;
+ /* adapt busy-wait algorithm */
+ sc->sc_spinmax++;
+ while ((sc->sc_funcs->lf_notrdy) (sc, 1)) {
+ /* exponential backoff */
+ tic = tic + tic + 1;
+ if (tic > TIMEOUT)
+ tic = TIMEOUT;
+ error = tsleep((caddr_t) sc,
+ LPTPRI | PCATCH, "lptpsh", tic);
+ if (error != EWOULDBLOCK)
+ return (error);
+ }
+ break;
+ }
+
+ (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++);
+ sc->sc_count--;
+
+ /* adapt busy-wait algorithm */
+ if (spin * 2 + 16 < sc->sc_spinmax)
+ sc->sc_spinmax--;
+ }
+ } else {
+ while (sc->sc_count > 0) {
+ /* if the printer is ready for a char, give it one */
+ if ((sc->sc_state & LPT_OBUSY) == 0) {
+ LPRINTF(("%s: write %d\n", sc->sc_dev.dv_xname,
+ sc->sc_count));
+ s = spltty();
+ (void) lpt_intr(sc);
+ splx(s);
+ }
+ error = tsleep((caddr_t) sc, LPTPRI | PCATCH,
+ "lptwrite2", 0);
+ if (error)
+ return (error);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Copy a line from user space to a local buffer, then call putc to get the
+ * chars moved to the output queue.
+ */
+int
+lptwrite(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct lpt_softc *sc;
+ size_t n;
+ int error;
+
+ sc = lpt_cd.cd_devs[LPTUNIT(dev)];
+ error = 0;
+
+ while ((n = min(LPT_BSIZE, uio->uio_resid)) != 0) {
+ uiomove(sc->sc_cp = sc->sc_inbuf->b_data, n, uio);
+ sc->sc_count = n;
+ error = pushbytes(sc);
+ if (error) {
+ /*
+ * Return accurate residual if interrupted or timed
+ * out.
+ */
+ uio->uio_resid += sc->sc_count;
+ sc->sc_count = 0;
+ return (error);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Handle printer interrupts which occur when the printer is ready to accept
+ * another char.
+ */
+int
+lpt_intr(sc)
+ struct lpt_softc *sc;
+{
+
+ if (sc->sc_count) {
+ /* send char */
+ (sc->sc_funcs->lf_wrdata) (sc, *sc->sc_cp++);
+ sc->sc_count--;
+ sc->sc_state |= LPT_OBUSY;
+ } else
+ sc->sc_state &= ~LPT_OBUSY;
+
+ if (sc->sc_count == 0) {
+ /* none, wake up the top half to get more */
+ wakeup((caddr_t) sc);
+ }
+
+ return (1);
+}
+
+/* ARGSUSED */
+int
+lptioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+
+ return (ENODEV);
+}
diff --git a/sys/dev/mvme/lpt_pcctwo.c b/sys/dev/mvme/lpt_pcctwo.c
new file mode 100644
index 00000000000..9aa13c7e736
--- /dev/null
+++ b/sys/dev/mvme/lpt_pcctwo.c
@@ -0,0 +1,294 @@
+/* $NetBSD: lpt_pcctwo.c,v 1.1 2002/02/12 20:38:44 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Device Driver back-end for the PCCChip2's parallel printer port
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/syslog.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/mvme/lptvar.h>
+#include <dev/mvme/pcctworeg.h>
+#include <dev/mvme/pcctwovar.h>
+
+/*
+ * Autoconfig stuff
+ */
+int lpt_pcctwo_match __P((struct device *, struct cfdata *, void *));
+void lpt_pcctwo_attach __P((struct device *, struct device *, void *));
+
+struct cfattach lpt_pcctwo_ca = {
+ sizeof(struct lpt_softc), lpt_pcctwo_match, lpt_pcctwo_attach
+};
+
+extern struct cfdriver lpt_cd;
+
+
+int lpt_pcctwo_intr __P((void *));
+void lpt_pcctwo_open __P((struct lpt_softc *, int));
+void lpt_pcctwo_close __P((struct lpt_softc *));
+void lpt_pcctwo_iprime __P((struct lpt_softc *));
+void lpt_pcctwo_speed __P((struct lpt_softc *, int));
+int lpt_pcctwo_notrdy __P((struct lpt_softc *, int));
+void lpt_pcctwo_wr_data __P((struct lpt_softc *, u_char));
+
+struct lpt_funcs lpt_pcctwo_funcs = {
+ lpt_pcctwo_open,
+ lpt_pcctwo_close,
+ lpt_pcctwo_iprime,
+ lpt_pcctwo_speed,
+ lpt_pcctwo_notrdy,
+ lpt_pcctwo_wr_data
+};
+
+/* ARGSUSED */
+int
+lpt_pcctwo_match(parent, cf, args)
+ struct device *parent;
+ struct cfdata *cf;
+ void *args;
+{
+ struct pcctwo_attach_args *pa;
+
+ pa = args;
+
+ if (strcmp(pa->pa_name, lpt_cd.cd_name))
+ return (0);
+
+#ifdef MVME68K
+ if (machineid != MVME_167 && machineid != MVME_177)
+ return (0);
+#endif
+
+#ifdef MVME88K
+ if (machineid != MVME_187)
+ return (0);
+#endif
+
+ pa->pa_ipl = cf->pcctwocf_ipl;
+
+ return (1);
+}
+
+/* ARGSUSED */
+void
+lpt_pcctwo_attach(parent, self, args)
+ struct device *parent;
+ struct device *self;
+ void *args;
+{
+ struct pcctwo_attach_args *pa;
+ struct lpt_softc *sc;
+
+ pa = (struct pcctwo_attach_args *) args;
+ sc = (struct lpt_softc *) self;
+
+ /* The printer registers are part of the PCCChip2's own registers. */
+ sc->sc_bust = pa->pa_bust;
+ bus_space_map(pa->pa_bust, pa->pa_offset, PCC2REG_SIZE, 0,
+ &sc->sc_bush);
+
+ sc->sc_ipl = pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK;
+ sc->sc_laststatus = 0;
+ sc->sc_funcs = &lpt_pcctwo_funcs;
+
+ printf(": PCCchip2 Parallel Printer\n");
+
+ /*
+ * Disable interrupts until device is opened
+ */
+ pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 0);
+ pcc2_reg_write(sc, PCC2REG_PRT_FAULT_ICSR, 0);
+ pcc2_reg_write(sc, PCC2REG_PRT_SEL_ICSR, 0);
+ pcc2_reg_write(sc, PCC2REG_PRT_PE_ICSR, 0);
+ pcc2_reg_write(sc, PCC2REG_PRT_BUSY_ICSR, 0);
+ pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
+
+ /*
+ * Main attachment code
+ */
+ lpt_attach_subr(sc);
+
+ /* Register the event counter */
+ evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
+ pcctwointr_evcnt(sc->sc_ipl), "printer", sc->sc_dev.dv_xname);
+
+ /*
+ * Hook into the printer interrupt
+ */
+ pcctwointr_establish(PCCTWOV_PRT_ACK, lpt_pcctwo_intr, sc->sc_ipl, sc,
+ &sc->sc_evcnt);
+}
+
+/*
+ * Handle printer interrupts
+ */
+int
+lpt_pcctwo_intr(arg)
+ void *arg;
+{
+ struct lpt_softc *sc;
+ int i;
+
+ sc = (struct lpt_softc *) arg;
+
+ /* is printer online and ready for output */
+ if (lpt_pcctwo_notrdy(sc, 0) || lpt_pcctwo_notrdy(sc, 1))
+ return (0);
+
+ i = lpt_intr(sc);
+
+ if (pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) & PCCTWO_PRT_IN_SR_PINT)
+ pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
+ sc->sc_icr | PCCTWO_ICR_ICLR);
+
+ return (i);
+}
+
+void
+lpt_pcctwo_open(sc, int_ena)
+ struct lpt_softc *sc;
+ int int_ena;
+{
+ int sps;
+
+ pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
+ PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
+
+ pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
+ pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_DOEN);
+
+ if (int_ena == 0) {
+ sps = splhigh();
+ sc->sc_icr = sc->sc_ipl | PCCTWO_ICR_EDGE;
+ pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, sc->sc_icr);
+ splx(sps);
+ }
+}
+
+void
+lpt_pcctwo_close(sc)
+ struct lpt_softc *sc;
+{
+
+ pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
+ PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
+ pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
+}
+
+void
+lpt_pcctwo_iprime(sc)
+ struct lpt_softc *sc;
+{
+
+ pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
+ pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_INP);
+
+ delay(100);
+
+ pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
+ pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) & ~PCCTWO_PRT_CTRL_INP);
+
+ delay(100);
+}
+
+void
+lpt_pcctwo_speed(sc, speed)
+ struct lpt_softc *sc;
+ int speed;
+{
+ u_int8_t reg;
+
+ reg = pcc2_reg_read(sc, PCC2REG_PRT_CONTROL);
+
+ if (speed == LPT_STROBE_FAST)
+ reg |= PCCTWO_PRT_CTRL_FAST;
+ else
+ reg &= ~PCCTWO_PRT_CTRL_FAST;
+
+ pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, reg);
+}
+
+int
+lpt_pcctwo_notrdy(sc, err)
+ struct lpt_softc *sc;
+ int err;
+{
+ u_int8_t status;
+ u_int8_t new;
+
+#define LPS_INVERT (PCCTWO_PRT_IN_SR_SEL)
+#define LPS_MASK (PCCTWO_PRT_IN_SR_SEL | PCCTWO_PRT_IN_SR_FLT | \
+ PCCTWO_PRT_IN_SR_BSY | PCCTWO_PRT_IN_SR_PE)
+
+ status = pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) ^ LPS_INVERT;
+ status &= LPS_MASK;
+
+ if (err) {
+ new = status & ~sc->sc_laststatus;
+ sc->sc_laststatus = status;
+
+ if (new & PCCTWO_PRT_IN_SR_SEL)
+ log(LOG_NOTICE, "%s: offline\n",
+ sc->sc_dev.dv_xname);
+ else if (new & PCCTWO_PRT_IN_SR_PE)
+ log(LOG_NOTICE, "%s: out of paper\n",
+ sc->sc_dev.dv_xname);
+ else if (new & PCCTWO_PRT_IN_SR_FLT)
+ log(LOG_NOTICE, "%s: output error\n",
+ sc->sc_dev.dv_xname);
+ }
+
+ return (status);
+}
+
+void
+lpt_pcctwo_wr_data(sc, data)
+ struct lpt_softc *sc;
+ u_char data;
+{
+
+ pcc2_reg_write16(sc, PCC2REG_PRT_DATA, (u_int16_t) data);
+}
diff --git a/sys/dev/mvme/lptvar.h b/sys/dev/mvme/lptvar.h
new file mode 100644
index 00000000000..5b461396545
--- /dev/null
+++ b/sys/dev/mvme/lptvar.h
@@ -0,0 +1,95 @@
+/* $NetBSD: lptvar.h,v 1.1 2002/02/12 20:38:45 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Common front-end for mvme68k/mvme88k parallel printer ports
+ */
+
+#ifndef __mvme_lptvar_h
+#define __mvme_lptvar_h
+
+#include <sys/callout.h>
+
+struct lpt_funcs;
+
+
+struct lpt_softc {
+ struct device sc_dev;
+ struct callout sc_wakeup_ch;
+ struct lpt_funcs *sc_funcs;
+ void *sc_arg;
+ size_t sc_count;
+ struct buf *sc_inbuf;
+ u_char *sc_cp;
+ int sc_spinmax;
+ u_char sc_state;
+#define LPT_OPEN 0x01 /* device is open */
+#define LPT_OBUSY 0x02 /* printer is busy doing output */
+#define LPT_INIT 0x04 /* waiting to initialize for open */
+ u_char sc_flags;
+#define LPT_FAST_STROBE 0x10 /* Select 1.6uS strobe pulse */
+#define LPT_AUTOLF 0x20 /* automatic LF on CR */
+#define LPT_NOPRIME 0x40 /* don't prime on open */
+#define LPT_NOINTR 0x80 /* do not use interrupt */
+
+ /* Back-end specific stuff */
+ bus_space_tag_t sc_bust;
+ bus_space_handle_t sc_bush;
+ int sc_ipl;
+ u_char sc_icr;
+ u_char sc_laststatus;
+ struct evcnt sc_evcnt;
+};
+
+
+struct lpt_funcs {
+ void (*lf_open) __P((struct lpt_softc *, int));
+ void (*lf_close) __P((struct lpt_softc *));
+ void (*lf_iprime) __P((struct lpt_softc *));
+ void (*lf_speed) __P((struct lpt_softc *, int));
+ int (*lf_notrdy) __P((struct lpt_softc *, int));
+ void (*lf_wrdata) __P((struct lpt_softc *, u_char));
+};
+
+#define LPT_STROBE_FAST 0
+#define LPT_STROBE_SLOW 1
+
+extern void lpt_attach_subr __P((struct lpt_softc *));
+extern int lpt_intr __P((struct lpt_softc *));
+
+#endif /* __mvme_lptvar_h */
diff --git a/sys/dev/mvme/memc.c b/sys/dev/mvme/memc.c
new file mode 100644
index 00000000000..49c9825b081
--- /dev/null
+++ b/sys/dev/mvme/memc.c
@@ -0,0 +1,640 @@
+/* $NetBSD: memc.c,v 1.1 2002/02/12 20:38:46 scw Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Support for the MEMECC and MEMC40 memory controllers on MVME68K
+ * and MVME88K boards.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/mvme/memcvar.h>
+#include <dev/mvme/memcreg.h>
+#include <dev/mvme/pcctwovar.h>
+#include <dev/mvme/pcctworeg.h>
+
+#include <dev/vme/vmevar.h>
+#include <dev/mvme/mvmebus.h>
+#include <dev/mvme/vme_twovar.h>
+#include <dev/mvme/vme_tworeg.h>
+
+
+static struct memc_softc *memc_softcs[MEMC_NDEVS];
+static int memc_softc_count;
+
+static void memc040_attach(struct memc_softc *);
+static void memecc_attach(struct memc_softc *);
+static void memc_hook_error_intr(struct memc_softc *, int (*)(void *));
+
+static int memecc_err_intr(void *);
+static void memecc_log_error(struct memc_softc *, u_int8_t, int, int);
+
+#define MEMECC_SCRUBBER_PERIOD 86400 /* ~24 hours */
+
+/*
+ * The following stuff is used to decode the ECC syndrome code so
+ * that we can figure out exactly which address/bit needed to be
+ * corrected.
+ */
+#define MEMECC_SYN_BIT_MASK 0x0fu
+#define MEMECC_SYN_BANK_A (0x00u << 4)
+#define MEMECC_SYN_BANK_B (0x01u << 4)
+#define MEMECC_SYN_BANK_C (0x02u << 4)
+#define MEMECC_SYN_BANK_D (0x03u << 4)
+#define MEMECC_SYN_BANK_SHIFT 4
+#define MEMECC_SYN_BANK_MASK 0x03u
+#define MEMECC_SYN_CHECKBIT_ERR 0x80u
+#define MEMECC_SYN_INVALID 0xffu
+
+static u_int8_t memc_syn_decode[256] = {
+ MEMECC_SYN_INVALID, /* 0x00 */
+ MEMECC_SYN_CHECKBIT_ERR | 0, /* 0x01: Checkbit 0 */
+ MEMECC_SYN_CHECKBIT_ERR | 1, /* 0x02: Checkbit 1 */
+ MEMECC_SYN_INVALID, /* 0x03 */
+ MEMECC_SYN_CHECKBIT_ERR | 2, /* 0x04: Checkbit 2 */
+ MEMECC_SYN_INVALID, /* 0x05 */
+ MEMECC_SYN_INVALID, /* 0x06 */
+ MEMECC_SYN_BANK_C | 10, /* 0x07: Bank C 10/26 */
+ MEMECC_SYN_CHECKBIT_ERR | 3, /* 0x08: Checkbit 3 */
+ MEMECC_SYN_INVALID, /* 0x09 */
+ MEMECC_SYN_INVALID, /* 0x0a */
+ MEMECC_SYN_BANK_C | 13, /* 0x0b: Bank C 13/29 */
+ MEMECC_SYN_INVALID, /* 0x0c */
+ MEMECC_SYN_BANK_D | 1, /* 0x0d: Bank D 1/17 */
+ MEMECC_SYN_BANK_D | 2, /* 0x0e: Bank D 2/18 */
+ MEMECC_SYN_INVALID, /* 0x0f */
+ MEMECC_SYN_CHECKBIT_ERR | 4, /* 0x10: Checkbit 4 */
+ MEMECC_SYN_INVALID, /* 0x11 */
+ MEMECC_SYN_INVALID, /* 0x12 */
+ MEMECC_SYN_BANK_C | 14, /* 0x13: Bank C 14/30 */
+ MEMECC_SYN_INVALID, /* 0x14 */
+ MEMECC_SYN_BANK_D | 4, /* 0x15: Bank D 4/20 */
+ MEMECC_SYN_BANK_D | 5, /* 0x16: Bank D 5/21 */
+ MEMECC_SYN_INVALID, /* 0x17 */
+ MEMECC_SYN_INVALID, /* 0x18 */
+ MEMECC_SYN_BANK_D | 8, /* 0x19: Bank D 8/24 */
+ MEMECC_SYN_BANK_D | 9, /* 0x1a: Bank D 9/25 */
+ MEMECC_SYN_INVALID, /* 0x1b */
+ MEMECC_SYN_BANK_D | 10, /* 0x1c: Bank D 10/26 */
+ MEMECC_SYN_INVALID, /* 0x1d */
+ MEMECC_SYN_INVALID, /* 0x1e */
+ MEMECC_SYN_INVALID, /* 0x1f */
+ MEMECC_SYN_CHECKBIT_ERR | 5, /* 0x20: Checkbit 5 */
+ MEMECC_SYN_INVALID, /* 0x21 */
+ MEMECC_SYN_INVALID, /* 0x22 */
+ MEMECC_SYN_BANK_C | 0, /* 0x23: Bank C 0/16 */
+ MEMECC_SYN_INVALID, /* 0x24 */
+ MEMECC_SYN_BANK_D | 7, /* 0x25: Bank D 7/23 */
+ MEMECC_SYN_BANK_D | 6, /* 0x26: Bank D 6/22 */
+ MEMECC_SYN_INVALID, /* 0x27 */
+ MEMECC_SYN_INVALID, /* 0x28 */
+ MEMECC_SYN_BANK_A | 15, /* 0x29: Bank A 15/31 */
+ MEMECC_SYN_BANK_D | 12, /* 0x2a: Bank D 12/28 */
+ MEMECC_SYN_INVALID, /* 0x2b */
+ MEMECC_SYN_BANK_D | 13, /* 0x2c: Bank D 13/29 */
+ MEMECC_SYN_INVALID, /* 0x2d */
+ MEMECC_SYN_INVALID, /* 0x2e */
+ MEMECC_SYN_INVALID, /* 0x2f */
+ MEMECC_SYN_INVALID, /* 0x30 */
+ MEMECC_SYN_BANK_A | 14, /* 0x31: Bank A 14/30 */
+ MEMECC_SYN_BANK_A | 0, /* 0x32: Bank A 0/16 */
+ MEMECC_SYN_INVALID, /* 0x33 */
+ MEMECC_SYN_BANK_A | 1, /* 0x34: Bank A 1/17 */
+ MEMECC_SYN_INVALID, /* 0x35 */
+ MEMECC_SYN_INVALID, /* 0x36 */
+ MEMECC_SYN_INVALID, /* 0x37 */
+ MEMECC_SYN_BANK_A | 2, /* 0x38: Bank A 2/18 */
+ MEMECC_SYN_INVALID, /* 0x39 */
+ MEMECC_SYN_INVALID, /* 0x3a */
+ MEMECC_SYN_INVALID, /* 0x3b */
+ MEMECC_SYN_INVALID, /* 0x3c */
+ MEMECC_SYN_BANK_C | 3, /* 0x3d: Bank C 3/19 */
+ MEMECC_SYN_INVALID, /* 0x3e */
+ MEMECC_SYN_INVALID, /* 0x3f */
+ MEMECC_SYN_CHECKBIT_ERR | 6, /* 0x40: Checkbit 6 */
+ MEMECC_SYN_INVALID, /* 0x41 */
+ MEMECC_SYN_INVALID, /* 0x42 */
+ MEMECC_SYN_BANK_C | 1, /* 0x43: Bank C 1/17 */
+ MEMECC_SYN_INVALID, /* 0x44 */
+ MEMECC_SYN_BANK_C | 4, /* 0x45: Bank C 4/20 */
+ MEMECC_SYN_BANK_C | 8, /* 0x46: Bank C 8/24 */
+ MEMECC_SYN_INVALID, /* 0x47 */
+ MEMECC_SYN_INVALID, /* 0x48 */
+ MEMECC_SYN_BANK_C | 7, /* 0x49: Bank C 7/23 */
+ MEMECC_SYN_BANK_D | 15, /* 0x4a: Bank D 15/31 */
+ MEMECC_SYN_INVALID, /* 0x4b */
+ MEMECC_SYN_BANK_D | 14, /* 0x4c: Bank D 14/30 */
+ MEMECC_SYN_INVALID, /* 0x4d */
+ MEMECC_SYN_INVALID, /* 0x4e */
+ MEMECC_SYN_BANK_B | 3, /* 0x4f: Bank B 3/19 */
+ MEMECC_SYN_INVALID, /* 0x50 */
+ MEMECC_SYN_BANK_B | 4, /* 0x51: Bank B 4/20 */
+ MEMECC_SYN_BANK_B | 7, /* 0x52: Bank B 7/23 */
+ MEMECC_SYN_INVALID, /* 0x53 */
+ MEMECC_SYN_BANK_A | 4, /* 0x54: Bank A 4/20 */
+ MEMECC_SYN_INVALID, /* 0x55 */
+ MEMECC_SYN_INVALID, /* 0x56 */
+ MEMECC_SYN_INVALID, /* 0x57 */
+ MEMECC_SYN_BANK_A | 5, /* 0x58: Bank A 5/21 */
+ MEMECC_SYN_INVALID, /* 0x59 */
+ MEMECC_SYN_INVALID, /* 0x5a */
+ MEMECC_SYN_INVALID, /* 0x5b */
+ MEMECC_SYN_INVALID, /* 0x5c */
+ MEMECC_SYN_INVALID, /* 0x5d */
+ MEMECC_SYN_INVALID, /* 0x5e */
+ MEMECC_SYN_INVALID, /* 0x5f */
+ MEMECC_SYN_INVALID, /* 0x60 */
+ MEMECC_SYN_BANK_B | 5, /* 0x61: Bank B 5/21 */
+ MEMECC_SYN_BANK_B | 6, /* 0x62: Bank B 6/22 */
+ MEMECC_SYN_INVALID, /* 0x63 */
+ MEMECC_SYN_BANK_A | 8, /* 0x64: Bank A 8/24 */
+ MEMECC_SYN_INVALID, /* 0x65 */
+ MEMECC_SYN_INVALID, /* 0x66 */
+ MEMECC_SYN_INVALID, /* 0x67 */
+ MEMECC_SYN_BANK_A | 9, /* 0x68: Bank A 9/25 */
+ MEMECC_SYN_INVALID, /* 0x69 */
+ MEMECC_SYN_INVALID, /* 0x6a */
+ MEMECC_SYN_INVALID, /* 0x6b */
+ MEMECC_SYN_INVALID, /* 0x6c */
+ MEMECC_SYN_INVALID, /* 0x6d */
+ MEMECC_SYN_INVALID, /* 0x6e */
+ MEMECC_SYN_INVALID, /* 0x6f */
+ MEMECC_SYN_BANK_A | 10, /* 0x70: Bank A 10/26 */
+ MEMECC_SYN_INVALID, /* 0x71 */
+ MEMECC_SYN_INVALID, /* 0x72 */
+ MEMECC_SYN_INVALID, /* 0x73 */
+ MEMECC_SYN_INVALID, /* 0x74 */
+ MEMECC_SYN_INVALID, /* 0x75 */
+ MEMECC_SYN_INVALID, /* 0x76 */
+ MEMECC_SYN_INVALID, /* 0x77 */
+ MEMECC_SYN_INVALID, /* 0x78 */
+ MEMECC_SYN_INVALID, /* 0x79 */
+ MEMECC_SYN_BANK_C | 11, /* 0x7a: Bank C 11/27 */
+ MEMECC_SYN_INVALID, /* 0x7b */
+ MEMECC_SYN_INVALID, /* 0x7c */
+ MEMECC_SYN_INVALID, /* 0x7d */
+ MEMECC_SYN_INVALID, /* 0x7e */
+ MEMECC_SYN_INVALID, /* 0x7f */
+ MEMECC_SYN_CHECKBIT_ERR | 7, /* 0x80: Checkbit 7 */
+ MEMECC_SYN_INVALID, /* 0x81 */
+ MEMECC_SYN_INVALID, /* 0x82 */
+ MEMECC_SYN_BANK_C | 2, /* 0x83: Bank C 2/18 */
+ MEMECC_SYN_INVALID, /* 0x84 */
+ MEMECC_SYN_BANK_C | 5, /* 0x85: Bank C 5/21 */
+ MEMECC_SYN_BANK_C | 9, /* 0x86: Bank C 9/25 */
+ MEMECC_SYN_INVALID, /* 0x87 */
+ MEMECC_SYN_INVALID, /* 0x88 */
+ MEMECC_SYN_BANK_C | 6, /* 0x89: Bank C 6/22 */
+ MEMECC_SYN_BANK_C | 12, /* 0x8a: Bank C 12/28 */
+ MEMECC_SYN_INVALID, /* 0x8b */
+ MEMECC_SYN_BANK_D | 0, /* 0x8c: Bank D 0/16 */
+ MEMECC_SYN_INVALID, /* 0x8d */
+ MEMECC_SYN_INVALID, /* 0x8e */
+ MEMECC_SYN_INVALID, /* 0x8f */
+ MEMECC_SYN_INVALID, /* 0x90 */
+ MEMECC_SYN_BANK_B | 8, /* 0x91: Bank B 8/24 */
+ MEMECC_SYN_BANK_C | 15, /* 0x92: Bank C 15/31 */
+ MEMECC_SYN_INVALID, /* 0x93 */
+ MEMECC_SYN_BANK_A | 7, /* 0x94: Bank A 7/23 */
+ MEMECC_SYN_INVALID, /* 0x95 */
+ MEMECC_SYN_INVALID, /* 0x96 */
+ MEMECC_SYN_INVALID, /* 0x97 */
+ MEMECC_SYN_BANK_A | 6, /* 0x98: Bank A 6/22 */
+ MEMECC_SYN_INVALID, /* 0x99 */
+ MEMECC_SYN_INVALID, /* 0x9a */
+ MEMECC_SYN_INVALID, /* 0x9b */
+ MEMECC_SYN_INVALID, /* 0x9c */
+ MEMECC_SYN_INVALID, /* 0x9d */
+ MEMECC_SYN_BANK_B | 11, /* 0x9e: Bank B 11/27 */
+ MEMECC_SYN_INVALID, /* 0x9f */
+ MEMECC_SYN_INVALID, /* 0xa0 */
+ MEMECC_SYN_BANK_B | 9, /* 0xa1: Bank B 9/25 */
+ MEMECC_SYN_BANK_B | 12, /* 0xa2: Bank B 12/28 */
+ MEMECC_SYN_INVALID, /* 0xa3 */
+ MEMECC_SYN_BANK_B | 15, /* 0xa4: Bank B 15/31 */
+ MEMECC_SYN_INVALID, /* 0xa5 */
+ MEMECC_SYN_INVALID, /* 0xa6 */
+ MEMECC_SYN_BANK_A | 11, /* 0xa7: Bank A 11/27 */
+ MEMECC_SYN_BANK_A | 12, /* 0xa8: Bank A 12/28 */
+ MEMECC_SYN_INVALID, /* 0xa9 */
+ MEMECC_SYN_INVALID, /* 0xaa */
+ MEMECC_SYN_INVALID, /* 0xab */
+ MEMECC_SYN_INVALID, /* 0xac */
+ MEMECC_SYN_INVALID, /* 0xad */
+ MEMECC_SYN_INVALID, /* 0xae */
+ MEMECC_SYN_INVALID, /* 0xaf */
+ MEMECC_SYN_BANK_A | 13, /* 0xb0: Bank A 13/29 */
+ MEMECC_SYN_INVALID, /* 0xb1 */
+ MEMECC_SYN_INVALID, /* 0xb2 */
+ MEMECC_SYN_INVALID, /* 0xb3 */
+ MEMECC_SYN_INVALID, /* 0xb4 */
+ MEMECC_SYN_INVALID, /* 0xb5 */
+ MEMECC_SYN_INVALID, /* 0xb6 */
+ MEMECC_SYN_INVALID, /* 0xb7 */
+ MEMECC_SYN_INVALID, /* 0xb8 */
+ MEMECC_SYN_INVALID, /* 0xb9 */
+ MEMECC_SYN_INVALID, /* 0xba */
+ MEMECC_SYN_INVALID, /* 0xbb */
+ MEMECC_SYN_INVALID, /* 0xbc */
+ MEMECC_SYN_INVALID, /* 0xbd */
+ MEMECC_SYN_INVALID, /* 0xbe */
+ MEMECC_SYN_INVALID, /* 0xbf */
+ MEMECC_SYN_INVALID, /* 0xc0 */
+ MEMECC_SYN_BANK_B | 10, /* 0xc1: Bank B 10/26 */
+ MEMECC_SYN_BANK_B | 13, /* 0xc2: Bank B 13/29 */
+ MEMECC_SYN_INVALID, /* 0xc3 */
+ MEMECC_SYN_BANK_B | 14, /* 0xc4: Bank B 14/30 */
+ MEMECC_SYN_INVALID, /* 0xc5 */
+ MEMECC_SYN_INVALID, /* 0xc6 */
+ MEMECC_SYN_INVALID, /* 0xc7 */
+ MEMECC_SYN_BANK_B | 0, /* 0xc8: Bank B 0/16 */
+ MEMECC_SYN_INVALID, /* 0xc9 */
+ MEMECC_SYN_INVALID, /* 0xca */
+ MEMECC_SYN_INVALID, /* 0xcb */
+ MEMECC_SYN_INVALID, /* 0xcc */
+ MEMECC_SYN_INVALID, /* 0xcd */
+ MEMECC_SYN_INVALID, /* 0xce */
+ MEMECC_SYN_INVALID, /* 0xcf */
+ MEMECC_SYN_BANK_B | 1, /* 0xd0: Bank B 1/17 */
+ MEMECC_SYN_INVALID, /* 0xd1 */
+ MEMECC_SYN_INVALID, /* 0xd2 */
+ MEMECC_SYN_BANK_A | 3, /* 0xd3: Bank A 3/19 */
+ MEMECC_SYN_INVALID, /* 0xd4 */
+ MEMECC_SYN_INVALID, /* 0xd5 */
+ MEMECC_SYN_INVALID, /* 0xd6 */
+ MEMECC_SYN_INVALID, /* 0xd7 */
+ MEMECC_SYN_INVALID, /* 0xd8 */
+ MEMECC_SYN_INVALID, /* 0xd9 */
+ MEMECC_SYN_INVALID, /* 0xda */
+ MEMECC_SYN_INVALID, /* 0xdb */
+ MEMECC_SYN_INVALID, /* 0xdc */
+ MEMECC_SYN_INVALID, /* 0xdd */
+ MEMECC_SYN_INVALID, /* 0xde */
+ MEMECC_SYN_INVALID, /* 0xdf */
+ MEMECC_SYN_BANK_B | 2, /* 0xe0: Bank B 2/18 */
+ MEMECC_SYN_INVALID, /* 0xe1 */
+ MEMECC_SYN_INVALID, /* 0xe2 */
+ MEMECC_SYN_INVALID, /* 0xe3 */
+ MEMECC_SYN_INVALID, /* 0xe4 */
+ MEMECC_SYN_INVALID, /* 0xe5 */
+ MEMECC_SYN_INVALID, /* 0xe6 */
+ MEMECC_SYN_INVALID, /* 0xe7 */
+ MEMECC_SYN_INVALID, /* 0xe8 */
+ MEMECC_SYN_BANK_D | 11, /* 0xe9: Bank D 11/27 */
+ MEMECC_SYN_INVALID, /* 0xea */
+ MEMECC_SYN_INVALID, /* 0xeb */
+ MEMECC_SYN_INVALID, /* 0xec */
+ MEMECC_SYN_INVALID, /* 0xed */
+ MEMECC_SYN_INVALID, /* 0xee */
+ MEMECC_SYN_INVALID, /* 0xef */
+ MEMECC_SYN_INVALID, /* 0xf0 */
+ MEMECC_SYN_INVALID, /* 0xf1 */
+ MEMECC_SYN_INVALID, /* 0xf2 */
+ MEMECC_SYN_INVALID, /* 0xf3 */
+ MEMECC_SYN_BANK_D | 3, /* 0xf4: Bank D 3/19 */
+ MEMECC_SYN_INVALID, /* 0xf5 */
+ MEMECC_SYN_INVALID, /* 0xf6 */
+ MEMECC_SYN_INVALID, /* 0xf7 */
+ MEMECC_SYN_INVALID, /* 0xf8 */
+ MEMECC_SYN_INVALID, /* 0xf9 */
+ MEMECC_SYN_INVALID, /* 0xfa */
+ MEMECC_SYN_INVALID, /* 0xfb */
+ MEMECC_SYN_INVALID, /* 0xfc */
+ MEMECC_SYN_INVALID, /* 0xfd */
+ MEMECC_SYN_INVALID, /* 0xfe */
+ MEMECC_SYN_INVALID /* 0xff */
+};
+
+
+/* ARGSUSED */
+void
+memc_init(sc)
+ struct memc_softc *sc;
+{
+ u_int8_t chipid;
+ u_int8_t memcfg;
+
+ if (memc_softc_count == MEMC_NDEVS)
+ panic("memc_attach: too many memc devices!");
+
+ memc_softcs[memc_softc_count++] = sc;
+
+ chipid = memc_reg_read(sc, MEMC_REG_CHIP_ID);
+ memcfg = memc_reg_read(sc, MEMC_REG_MEMORY_CONFIG);
+
+ printf(": %dMB %s Memory Controller Chip (Rev %d)\n",
+ MEMC_MEMORY_CONFIG_2_MB(memcfg),
+ (chipid == MEMC_CHIP_ID_MEMC040) ? "Parity" : "ECC",
+ memc_reg_read(sc, MEMC_REG_CHIP_REVISION));
+
+ printf("%s: Base Address: 0x%x, ", sc->sc_dev.dv_xname,
+ MEMC_BASE_ADDRESS(memc_reg_read(sc, MEMC_REG_BASE_ADDRESS_HI),
+ memc_reg_read(sc, MEMC_REG_BASE_ADDRESS_LO)));
+
+ printf("Fast RAM Read %sabled\n", (memc_reg_read(sc,
+ MEMC_REG_MEMORY_CONFIG) & MEMC_MEMORY_CONFIG_FSTRD) ?
+ "En" : "Dis");
+
+ switch (chipid) {
+ case MEMC_CHIP_ID_MEMC040:
+ memc040_attach(sc);
+ break;
+ case MEMC_CHIP_ID_MEMECC:
+ memecc_attach(sc);
+ break;
+ }
+}
+
+static void
+memc040_attach(struct memc_softc *sc)
+{
+
+ /* XXX: TBD */
+}
+
+static void
+memecc_attach(struct memc_softc *sc)
+{
+ u_int8_t rv;
+
+ /*
+ * First, disable bus-error and interrupts on ECC errors.
+ * Also switch off SWAIT to enhance performance.
+ */
+ rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL);
+ rv &= ~(MEMECC_DRAM_CONTROL_NCEBEN |
+ MEMECC_DRAM_CONTROL_NCEIEN |
+ MEMECC_DRAM_CONTROL_SWAIT);
+ rv |= MEMECC_DRAM_CONTROL_RAMEN;
+ memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL, rv);
+ rv = memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL);
+ rv &= ~(MEMECC_SCRUB_CONTROL_SCRBEN | MEMECC_SCRUB_CONTROL_SBEIEN);
+ memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL, rv);
+
+ /*
+ * Ensure error correction is enabled
+ */
+ rv = memc_reg_read(sc, MEMECC_REG_DATA_CONTROL);
+ rv &= ~MEMECC_DATA_CONTROL_DERC;
+ memc_reg_write(sc, MEMECC_REG_DATA_CONTROL, rv);
+
+ /*
+ * Clear any error currently in the logs
+ */
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER);
+#ifdef DIAGNOSTIC
+ if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0)
+ memecc_log_error(sc, rv, 0, 0);
+#endif
+ memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER,
+ MEMECC_ERROR_LOGGER_ERRLOG);
+
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER + 2);
+#ifdef DIAGNOSTIC
+ if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0)
+ memecc_log_error(sc, rv, 2, 0);
+#endif
+ memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER + 2,
+ MEMECC_ERROR_LOGGER_ERRLOG);
+
+ /*
+ * Now hook the ECC error interrupt
+ */
+ if (memc_softc_count == 1)
+ memc_hook_error_intr(sc, memecc_err_intr);
+
+ /*
+ * Enable bus-error and interrupt on uncorrectable ECC
+ */
+ rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL);
+ rv |= MEMECC_DRAM_CONTROL_NCEBEN | MEMECC_DRAM_CONTROL_NCEIEN;
+ memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL, rv);
+
+ /*
+ * Set up the scrubber to run roughly once every 24 hours
+ * with minimal impact on the local bus. With these on/off
+ * time settings, a scrub of a 32MB DRAM board will take
+ * roughly half a minute.
+ */
+ memc_reg_write(sc, MEMECC_REG_SCRUB_PERIOD_HI,
+ MEMECC_SCRUB_PERIOD_HI(MEMECC_SCRUBBER_PERIOD));
+ memc_reg_write(sc, MEMECC_REG_SCRUB_PERIOD_LO,
+ MEMECC_SCRUB_PERIOD_LO(MEMECC_SCRUBBER_PERIOD));
+ memc_reg_write(sc, MEMECC_REG_SCRUB_TIME_ONOFF,
+ MEMECC_SCRUB_TIME_ON_1 | MEMECC_SCRUB_TIME_OFF_16);
+
+ /*
+ * Start the scrubber, and enable interrupts on Correctable errors
+ */
+ memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL,
+ memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL) |
+ MEMECC_SCRUB_CONTROL_SCRBEN | MEMECC_SCRUB_CONTROL_SBEIEN);
+
+ printf("%s: Logging ECC errors at ipl %d\n", sc->sc_dev.dv_xname,
+ MEMC_IRQ_LEVEL);
+}
+
+static void
+memc_hook_error_intr(struct memc_softc *sc, int (*func)(void *))
+{
+
+#if 0
+ evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
+ (*sc->sc_isrevcnt)(sc->sc_isrcookie, MEMC_IRQ_LEVEL),
+ "memory", "ecc errors");
+#endif
+
+ /*
+ * On boards without a VMEChip2, the interrupt is routed
+ * via the MCChip (mvme162/mvme172).
+ */
+ if (vmetwo_not_present)
+ pcctwointr_establish(MCCHIPV_PARITY_ERR, func, MEMC_IRQ_LEVEL,
+ sc, &sc->sc_evcnt);
+ else
+ vmetwo_local_intr_establish(MEMC_IRQ_LEVEL,
+ VME2_VEC_PARITY_ERROR, func, sc, &sc->sc_evcnt);
+}
+
+/* ARGSUSED */
+static int
+memecc_err_intr(void *arg)
+{
+ struct memc_softc *sc;
+ u_int8_t rv;
+ int i, j, cnt = 0;
+
+ /*
+ * For each memory controller we found ...
+ */
+ for (i = 0; i < memc_softc_count; i++) {
+ sc = memc_softcs[i];
+
+ /*
+ * There are two error loggers per controller, the registers of
+ * the 2nd are offset from the 1st by 2 bytes.
+ */
+ for (j = 0; j <= 2; j += 2) {
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_LOGGER + j);
+ if ((rv & MEMECC_ERROR_LOGGER_MASK) != 0) {
+ memecc_log_error(sc, rv, j, 1);
+ memc_reg_write(sc, MEMECC_REG_ERROR_LOGGER + j,
+ MEMECC_ERROR_LOGGER_ERRLOG);
+ cnt++;
+ }
+ }
+ }
+
+ return (cnt);
+}
+
+/*
+ * Log an ECC error to the console.
+ * Note: Since this usually runs at an elevated ipl (above clock), we
+ * should probably schedule a soft interrupt to log the error details.
+ * (But only for errors where we would not normally panic.)
+ */
+static void
+memecc_log_error(struct memc_softc *sc, u_int8_t errlog, int off, int mbepanic)
+{
+ u_int32_t addr;
+ u_int8_t rv, syndrome;
+ const char *bm = "CPU";
+ const char *rdwr;
+ const char *etype;
+ char syntext[32];
+
+ /*
+ * Get the address associated with the error.
+ */
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_HIHI + off);
+ addr = (u_int32_t)rv;
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_HI + off);
+ addr = (addr << 8) | (u_int32_t)rv;
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_MID + off);
+ addr = (addr << 8) | (u_int32_t)rv;
+ rv = memc_reg_read(sc, MEMECC_REG_ERROR_ADDRESS_LO + off);
+ addr = (addr << 8) | (u_int32_t)rv;
+
+ /*
+ * And the Syndrome bits
+ */
+ syndrome = memc_reg_read(sc, MEMECC_REG_ERROR_SYNDROME + off);
+
+ rdwr = ((errlog & MEMECC_ERROR_LOGGER_ERD) != 0) ? " read" : " write";
+
+ if ((errlog & MEMECC_ERROR_LOGGER_EALT) != 0)
+ bm = "Peripheral Device";
+ else
+ if ((errlog & MEMECC_ERROR_LOGGER_ESCRB) != 0) {
+ bm = "Scrubber";
+ rdwr = "";
+ }
+
+ if ((errlog & MEMECC_ERROR_LOGGER_SBE) != 0) {
+ int syncode, bank, bitnum;
+
+ etype = "Correctable";
+ syncode = memc_syn_decode[syndrome];
+ bitnum = (syncode & MEMECC_SYN_BIT_MASK) + (off ? 16 : 0);
+ bank = (syncode >> MEMECC_SYN_BANK_SHIFT) &MEMECC_SYN_BANK_MASK;
+
+ if (syncode == MEMECC_SYN_INVALID)
+ strcpy(syntext, "Invalid!");
+ else
+ if ((syncode & MEMECC_SYN_CHECKBIT_ERR) != 0)
+ sprintf(syntext, "Checkbit#%d", bitnum);
+ else {
+ addr |= (u_int32_t) (bank << 2);
+ sprintf(syntext, "DRAM Bank %c, Bit#%d",
+ 'A' + bank, bitnum);
+ }
+ } else if ((errlog & MEMECC_ERROR_LOGGER_MBE) != 0)
+ etype = "Uncorrectable";
+ else
+ etype = "Spurious";
+
+ printf("%s: %s error on %s%s access to 0x%08x.\n",
+ sc->sc_dev.dv_xname, etype, bm, rdwr, addr);
+
+ if ((errlog & MEMECC_ERROR_LOGGER_SBE) != 0)
+ printf("%s: ECC Syndrome 0x%02x (%s)\n", sc->sc_dev.dv_xname,
+ syndrome, syntext);
+
+ /*
+ * If an uncorrectable error was detected by an alternate
+ * bus master or the scrubber, panic immediately.
+ * We can't rely on the contents of memory at this point.
+ *
+ * Uncorrectable errors detected when the CPU was accessing
+ * DRAM will cause the CPU to take a bus error trap. Depending
+ * on whether the error was in kernel or user mode, the system
+ * with either panic or kill the affected process. Basically,
+ * we don't have to deal with it here.
+ *
+ * XXX: I'm not sure whether it's our responsibility to
+ * perform some dummy writes to the offending address in this
+ * case to re-generate a good ECC. Note that we'd have to write
+ * an entire block of 4 words since we can only narrow down the
+ * faulty address for correctable errors...
+ */
+ if (mbepanic && (errlog & MEMECC_ERROR_LOGGER_MBE) &&
+ (errlog & (MEMECC_ERROR_LOGGER_ESCRB|MEMECC_ERROR_LOGGER_EALT))) {
+ /*
+ * Ensure we don't get a Bus Error while panicing...
+ */
+ rv = memc_reg_read(sc, MEMECC_REG_DRAM_CONTROL + off);
+ rv &= ~(MEMECC_DRAM_CONTROL_NCEBEN |
+ MEMECC_DRAM_CONTROL_NCEIEN);
+ memc_reg_write(sc, MEMECC_REG_DRAM_CONTROL + off, rv);
+ rv = memc_reg_read(sc, MEMECC_REG_SCRUB_CONTROL + off);
+ rv &= ~(MEMECC_SCRUB_CONTROL_SBEIEN |
+ MEMECC_SCRUB_CONTROL_SCRBEN);
+ memc_reg_write(sc, MEMECC_REG_SCRUB_CONTROL + off, rv);
+
+ panic("%s: Halting system to preserve data integrity.",
+ sc->sc_dev.dv_xname);
+ }
+}
diff --git a/sys/dev/mvme/memcreg.h b/sys/dev/mvme/memcreg.h
new file mode 100644
index 00000000000..e75bb013f91
--- /dev/null
+++ b/sys/dev/mvme/memcreg.h
@@ -0,0 +1,177 @@
+/* $NetBSD: memcreg.h,v 1.1 2002/02/12 20:38:46 scw Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 MEMECC and MEMC040 devices.
+ */
+#ifndef _MVME_MEMCREG_H
+#define _MVME_MEMCREG_H
+
+/*
+ * Size, in bytes, of the memory controller's register set
+ * (Actually, the MEMC040's register set is only 0x20 bytes in size, but
+ * we go with the larger of the two).
+ */
+#define MEMC_REGSIZE 0x80
+
+/* Both memory controllers share some registers in common */
+#define MEMC_REG_CHIP_ID 0x00
+#define MEMC_CHIP_ID_MEMC040 0x80 /* It's a MEMC040 */
+#define MEMC_CHIP_ID_MEMECC 0x81 /* It's a MEMECC */
+
+/* Revision of the ASIC */
+#define MEMC_REG_CHIP_REVISION 0x04
+
+/* Configuration of the memory block controlled by this ASIC */
+#define MEMC_REG_MEMORY_CONFIG 0x08
+#define MEMC_MEMORY_CONFIG_2_BYTES(x) (0x400000 << ((x) & 0x07))
+#define MEMC_MEMORY_CONFIG_2_MB(x) (4 << ((x) & 0x07))
+#define MEMC040_MEMORY_CONFIG_EXTPEN (1u << 3) /* External parity enabled */
+#define MEMC040_MEMORY_CONFIG_WPB (1u << 4) /* Write Per Bit mode */
+#define MEMC_MEMORY_CONFIG_FSTRD (1u << 5) /* Fast RAM Read enabled */
+
+/* Where, in the cpu's address space, does this memory appear? */
+#define MEMC_REG_BASE_ADDRESS_HI 0x14
+#define MEMC_REG_BASE_ADDRESS_LO 0x18
+#define MEMC_BASE_ADDRESS(hi,lo) (((hi) << 24) | (((lo) & 0xc0) << 22))
+
+/* Tells the memory controller what the board's Bus Clock frequency is */
+#define MEMC_REG_BUS_CLOCK 0x1c
+
+
+/* Register offsets and definitions for the Parity Memory Controller */
+#define MEMC040_REG_ALT_STATUS 0x0c /* Not used */
+#define MEMC040_REG_ALT_CONTROL 0x10 /* Not used */
+
+/* Memory Control Register */
+#define MEMC040_REG_RAM_CONTROL 0x18
+#define MEMC040_RAM_CONTROL_RAMEN (1u << 0)
+#define MEMC040_RAM_CONTROL_PAREN (1u << 1)
+#define MEMC040_RAM_CONTROL_PARINT (1u << 2)
+#define MEMC040_RAM_CONTROL_WWP (1u << 3)
+#define MEMC040_RAM_CONTROL_SWAIT (1u << 4)
+#define MEMC040_RAM_CONTROL_DMCTL (1u << 5)
+
+
+/* Register offsets and definitions for the ECC Memory Controller */
+#define MEMECC_REG_DRAM_CONTROL 0x18
+#define MEMECC_DRAM_CONTROL_RAMEN (1u << 0)
+#define MEMECC_DRAM_CONTROL_NCEBEN (1u << 1)
+#define MEMECC_DRAM_CONTROL_NCEIEN (1u << 2)
+#define MEMECC_DRAM_CONTROL_RWB3 (1u << 3)
+#define MEMECC_DRAM_CONTROL_SWAIT (1u << 4)
+#define MEMECC_DRAM_CONTROL_RWB5 (1u << 5)
+#define MEMECC_DRAM_CONTROL_BAD22 (1u << 6)
+#define MEMECC_DRAM_CONTROL_BAD23 (1u << 7)
+
+#define MEMECC_REG_DATA_CONTROL 0x20
+#define MEMECC_DATA_CONTROL_RWCKB (1u << 3)
+#define MEMECC_DATA_CONTROL_ZFILL (1u << 4)
+#define MEMECC_DATA_CONTROL_DERC (1u << 5)
+
+#define MEMECC_REG_SCRUB_CONTROL 0x24
+#define MEMECC_SCRUB_CONTROL_IDIS (1u << 0)
+#define MEMECC_SCRUB_CONTROL_SBEIEN (1u << 1)
+#define MEMECC_SCRUB_CONTROL_SCRBEN (1u << 3)
+#define MEMECC_SCRUB_CONTROL_SCRB (1u << 4)
+#define MEMECC_SCRUB_CONTROL_HITDIS (1u << 5)
+#define MEMECC_SCRUB_CONTROL_RADATA (1u << 6)
+#define MEMECC_SCRUB_CONTROL_RACODE (1u << 7)
+
+#define MEMECC_REG_SCRUB_PERIOD_HI 0x28
+#define MEMECC_SCRUB_PERIOD_HI(secs) (((secs) / 2) >> 8)
+#define MEMECC_REG_SCRUB_PERIOD_LO 0x2c
+#define MEMECC_SCRUB_PERIOD_LO(secs) (((secs) / 2) & 0xffu)
+
+#define MEMECC_REG_CHIP_PRESCALE 0x30
+
+#define MEMECC_REG_SCRUB_TIME_ONOFF 0x34
+#define MEMECC_SCRUB_TIME_ONOFF_MASK 0x07u
+#define MEMECC_SCRUB_TIME_OFF_0 0u
+#define MEMECC_SCRUB_TIME_OFF_16 1u
+#define MEMECC_SCRUB_TIME_OFF_32 2u
+#define MEMECC_SCRUB_TIME_OFF_64 3u
+#define MEMECC_SCRUB_TIME_OFF_128 4u
+#define MEMECC_SCRUB_TIME_OFF_256 5u
+#define MEMECC_SCRUB_TIME_OFF_512 6u
+#define MEMECC_SCRUB_TIME_OFF_NEVER 7u
+#define MEMECC_SCRUB_TIME_ON_1 (0u << 3)
+#define MEMECC_SCRUB_TIME_ON_16 (1u << 3)
+#define MEMECC_SCRUB_TIME_ON_32 (2u << 3)
+#define MEMECC_SCRUB_TIME_ON_64 (3u << 3)
+#define MEMECC_SCRUB_TIME_ON_128 (4u << 3)
+#define MEMECC_SCRUB_TIME_ON_256 (5u << 3)
+#define MEMECC_SCRUB_TIME_ON_512 (6u << 3)
+#define MEMECC_SCRUB_TIME_ON_ALWAYS (7u << 3)
+#define MEMECC_SCRUB_TIME_SRDIS (1u << 7)
+
+#define MEMECC_REG_SCRUB_PRESCALE_HI 0x38
+#define MEMECC_REG_SCRUB_PRESCALE_MID 0x3c
+#define MEMECC_REG_SCRUB_PRESCALE_LO 0x40
+
+#define MEMECC_REG_SCRUB_TIMER_HI 0x44
+#define MEMECC_REG_SCRUB_TIMER_LO 0x48
+
+#define MEMECC_REG_SCRUB_ADDR_CNTR_HIHI 0x4c
+#define MEMECC_REG_SCRUB_ADDR_CNTR_HI 0x50
+#define MEMECC_REG_SCRUB_ADDR_CNTR_MID 0x54
+#define MEMECC_REG_SCRUB_ADDR_CNTR_LO 0x58
+
+#define MEMECC_REG_ERROR_LOGGER 0x5c
+#define MEMECC_ERROR_LOGGER_MASK 0x7fu
+#define MEMECC_ERROR_LOGGER_SBE (1u << 0)
+#define MEMECC_ERROR_LOGGER_MBE (1u << 1)
+#define MEMECC_ERROR_LOGGER_EALT (1u << 3)
+#define MEMECC_ERROR_LOGGER_ERA (1u << 4)
+#define MEMECC_ERROR_LOGGER_ESCRB (1u << 5)
+#define MEMECC_ERROR_LOGGER_ERD (1u << 6)
+#define MEMECC_ERROR_LOGGER_ERRLOG (1u << 7)
+
+#define MEMECC_REG_ERROR_ADDRESS_HIHI 0x60
+#define MEMECC_REG_ERROR_ADDRESS_HI 0x64
+#define MEMECC_REG_ERROR_ADDRESS_MID 0x68
+#define MEMECC_REG_ERROR_ADDRESS_LO 0x6c
+
+#define MEMECC_REG_ERROR_SYNDROME 0x70
+
+#define MEMECC_REG_DEFAULTS1 0x74
+#define MEMECC_REG_DEFAULTS2 0x78
+
+#define MEMECC_REG_SDRAM_CONFIG 0x7c
+
+#endif /* _MVME_MEMCREG_H */
diff --git a/sys/dev/mvme/memcvar.h b/sys/dev/mvme/memcvar.h
new file mode 100644
index 00000000000..c38f596d016
--- /dev/null
+++ b/sys/dev/mvme/memcvar.h
@@ -0,0 +1,69 @@
+/* $NetBSD: memcvar.h,v 1.1 2002/02/12 20:38:46 scw Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _MVME_MEMCVAR_H
+#define _MVME_MEMCVAR_H
+
+struct memc_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_bust;
+ bus_space_handle_t sc_bush;
+ struct evcnt sc_evcnt;
+};
+
+#define MEMC_NDEVS 2
+
+#define memc_reg_read(sc, off) \
+ bus_space_read_1((sc)->sc_bust, (sc)->sc_bush, (off))
+#define memc_reg_write(sc, off, v) \
+ bus_space_write_1((sc)->sc_bust, (sc)->sc_bush, (off), (v))
+
+/*
+ * Some tweakable parameters. Mind you, I don't recommend changing
+ * the ipl...
+ * XXX: This should probably be ipl 7
+ */
+#ifdef MVME68K
+#define MEMC_IRQ_LEVEL 6
+#else
+#error Define irq level for memory contoller
+#endif
+
+extern void memc_init(struct memc_softc *);
+
+#endif /* _MVME_MEMCREG_H */
diff --git a/sys/dev/mvme/mvmebus.c b/sys/dev/mvme/mvmebus.c
new file mode 100644
index 00000000000..c71f54bf389
--- /dev/null
+++ b/sys/dev/mvme/mvmebus.c
@@ -0,0 +1,961 @@
+/* $NetBSD: mvmebus.c,v 1.1 2002/02/12 20:38:47 scw Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/kcore.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/vme/vmereg.h>
+#include <dev/vme/vmevar.h>
+
+#include <dev/mvme/mvmebus.h>
+
+#ifdef DIAGNOSTIC
+int mvmebus_dummy_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t,
+ bus_size_t, int, bus_dmamap_t *);
+void mvmebus_dummy_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
+int mvmebus_dummy_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int);
+void mvmebus_dummy_dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int);
+#endif
+
+#ifdef DEBUG
+static const char *mvmebus_mod_string(vme_addr_t, vme_size_t,
+ vme_am_t, vme_datasize_t);
+#endif
+
+static void mvmebus_offboard_ram(struct mvmebus_softc *);
+static int mvmebus_dmamap_load_common(struct mvmebus_softc *, bus_dmamap_t);
+
+vme_am_t _mvmebus_am_cap[] = {
+ MVMEBUS_AM_CAP_BLKD64 | MVMEBUS_AM_CAP_USER,
+ MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_USER,
+ MVMEBUS_AM_CAP_PROG | MVMEBUS_AM_CAP_USER,
+ MVMEBUS_AM_CAP_BLK | MVMEBUS_AM_CAP_USER,
+ MVMEBUS_AM_CAP_BLKD64 | MVMEBUS_AM_CAP_SUPER,
+ MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_SUPER,
+ MVMEBUS_AM_CAP_PROG | MVMEBUS_AM_CAP_SUPER,
+ MVMEBUS_AM_CAP_BLK | MVMEBUS_AM_CAP_SUPER
+};
+
+const char *mvmebus_irq_name[] = {
+ "vmeirq0", "vmeirq1", "vmeirq2", "vmeirq3",
+ "vmeirq4", "vmeirq5", "vmeirq6", "vmeirq7"
+};
+
+extern phys_ram_seg_t mem_clusters[0];
+extern int mem_cluster_cnt;
+
+
+static void
+mvmebus_offboard_ram(sc)
+ struct mvmebus_softc *sc;
+{
+ struct mvmebus_range *svr, *mvr;
+ vme_addr_t start, end, size;
+ int i;
+
+ /*
+ * If we have any offboard RAM (i.e. a VMEbus RAM board) then
+ * we need to record its details since it's effectively another
+ * VMEbus slave image as far as we're concerned.
+ * The chip-specific backend will have reserved sc->sc_slaves[0]
+ * for exactly this purpose.
+ */
+ svr = sc->sc_slaves;
+ if (mem_cluster_cnt < 2) {
+ svr->vr_am = MVMEBUS_AM_DISABLED;
+ return;
+ }
+
+ start = mem_clusters[1].start;
+ size = mem_clusters[1].size - 1;
+ end = start + size;
+
+ /*
+ * Figure out which VMEbus master image the RAM is
+ * visible through. This will tell us the address
+ * modifier and datasizes it uses, as well as allowing
+ * us to calculate its `real' VMEbus address.
+ *
+ * XXX FIXME: This is broken if the RAM is mapped through
+ * a translated address space. For example, on mvme167 it's
+ * perfectly legal to set up the following A32 mapping:
+ *
+ * vr_locaddr == 0x80000000
+ * vr_vmestart == 0x10000000
+ * vr_vmeend == 0x10ffffff
+ *
+ * In this case, RAM at VMEbus address 0x10800000 will appear at local
+ * address 0x80800000, but we need to set the slave vr_vmestart to
+ * 0x10800000.
+ */
+ for (i = 0, mvr = sc->sc_masters; i < sc->sc_nmasters; i++, mvr++) {
+ vme_addr_t vstart = mvr->vr_locstart + mvr->vr_vmestart;
+
+ if (start >= vstart &&
+ end <= vstart + (mvr->vr_vmeend - mvr->vr_vmestart))
+ break;
+ }
+ if (i == sc->sc_nmasters) {
+ svr->vr_am = MVMEBUS_AM_DISABLED;
+#ifdef DEBUG
+ printf("%s: No VMEbus master mapping for offboard RAM!\n",
+ sc->sc_dev.dv_xname);
+#endif
+ return;
+ }
+
+ svr->vr_locstart = start;
+ svr->vr_vmestart = start & mvr->vr_mask;
+ svr->vr_vmeend = svr->vr_vmestart + size;
+ svr->vr_datasize = mvr->vr_datasize;
+ svr->vr_mask = mvr->vr_mask;
+ svr->vr_am = mvr->vr_am & VME_AM_ADRSIZEMASK;
+ svr->vr_am |= MVMEBUS_AM_CAP_DATA | MVMEBUS_AM_CAP_PROG |
+ MVMEBUS_AM_CAP_SUPER | MVMEBUS_AM_CAP_USER;
+}
+
+void
+mvmebus_attach(sc)
+ struct mvmebus_softc *sc;
+{
+ struct vmebus_attach_args vaa;
+ int i;
+
+ /* Zap the IRQ reference counts */
+ for (i = 0; i < 8; i++)
+ sc->sc_irqref[i] = 0;
+
+ /* If there's offboard RAM, get its VMEbus slave attributes */
+ mvmebus_offboard_ram(sc);
+
+#ifdef DEBUG
+ for (i = 0; i < sc->sc_nmasters; i++) {
+ struct mvmebus_range *vr = &sc->sc_masters[i];
+ if (vr->vr_am == MVMEBUS_AM_DISABLED) {
+ printf("%s: Master#%d: disabled\n",
+ sc->sc_dev.dv_xname, i);
+ continue;
+ }
+ printf("%s: Master#%d: 0x%08lx -> %s\n",
+ sc->sc_dev.dv_xname, i,
+ vr->vr_locstart + (vr->vr_vmestart & vr->vr_mask),
+ mvmebus_mod_string(vr->vr_vmestart,
+ (vr->vr_vmeend - vr->vr_vmestart) + 1,
+ vr->vr_am, vr->vr_datasize));
+ }
+
+ for (i = 0; i < sc->sc_nslaves; i++) {
+ struct mvmebus_range *vr = &sc->sc_slaves[i];
+ if (vr->vr_am == MVMEBUS_AM_DISABLED) {
+ printf("%s: Slave#%d: disabled\n",
+ sc->sc_dev.dv_xname, i);
+ continue;
+ }
+ printf("%s: Slave#%d: 0x%08lx -> %s\n",
+ sc->sc_dev.dv_xname, i, vr->vr_locstart,
+ mvmebus_mod_string(vr->vr_vmestart,
+ (vr->vr_vmeend - vr->vr_vmestart) + 1,
+ vr->vr_am, vr->vr_datasize));
+ }
+#endif
+
+ sc->sc_vct.cookie = sc;
+ sc->sc_vct.vct_probe = mvmebus_probe;
+ sc->sc_vct.vct_map = mvmebus_map;
+ sc->sc_vct.vct_unmap = mvmebus_unmap;
+ sc->sc_vct.vct_int_map = mvmebus_intmap;
+ sc->sc_vct.vct_int_evcnt = mvmebus_intr_evcnt;
+ sc->sc_vct.vct_int_establish = mvmebus_intr_establish;
+ sc->sc_vct.vct_int_disestablish = mvmebus_intr_disestablish;
+ sc->sc_vct.vct_dmamap_create = mvmebus_dmamap_create;
+ sc->sc_vct.vct_dmamap_destroy = mvmebus_dmamap_destroy;
+ sc->sc_vct.vct_dmamem_alloc = mvmebus_dmamem_alloc;
+ sc->sc_vct.vct_dmamem_free = mvmebus_dmamem_free;
+
+ sc->sc_mvmedmat._cookie = sc;
+ sc->sc_mvmedmat._dmamap_load = mvmebus_dmamap_load;
+ sc->sc_mvmedmat._dmamap_load_mbuf = mvmebus_dmamap_load_mbuf;
+ sc->sc_mvmedmat._dmamap_load_uio = mvmebus_dmamap_load_uio;
+ sc->sc_mvmedmat._dmamap_load_raw = mvmebus_dmamap_load_raw;
+ sc->sc_mvmedmat._dmamap_unload = mvmebus_dmamap_unload;
+ sc->sc_mvmedmat._dmamap_sync = mvmebus_dmamap_sync;
+ sc->sc_mvmedmat._dmamem_map = mvmebus_dmamem_map;
+ sc->sc_mvmedmat._dmamem_unmap = mvmebus_dmamem_unmap;
+ sc->sc_mvmedmat._dmamem_mmap = mvmebus_dmamem_mmap;
+
+#ifdef DIAGNOSTIC
+ sc->sc_mvmedmat._dmamap_create = mvmebus_dummy_dmamap_create;
+ sc->sc_mvmedmat._dmamap_destroy = mvmebus_dummy_dmamap_destroy;
+ sc->sc_mvmedmat._dmamem_alloc = mvmebus_dummy_dmamem_alloc;
+ sc->sc_mvmedmat._dmamem_free = mvmebus_dummy_dmamem_free;
+#else
+ sc->sc_mvmedmat._dmamap_create = NULL;
+ sc->sc_mvmedmat._dmamap_destroy = NULL;
+ sc->sc_mvmedmat._dmamem_alloc = NULL;
+ sc->sc_mvmedmat._dmamem_free = NULL;
+#endif
+
+ vaa.va_vct = &sc->sc_vct;
+ vaa.va_bdt = &sc->sc_mvmedmat;
+ vaa.va_slaveconfig = NULL;
+
+ config_found(&sc->sc_dev, &vaa, 0);
+}
+
+int
+mvmebus_map(vsc, vmeaddr, len, am, datasize, swap, tag, handle, resc)
+ void *vsc;
+ vme_addr_t vmeaddr;
+ vme_size_t len;
+ vme_am_t am;
+ vme_datasize_t datasize;
+ vme_swap_t swap;
+ bus_space_tag_t *tag;
+ bus_space_handle_t *handle;
+ vme_mapresc_t *resc;
+{
+ struct mvmebus_softc *sc;
+ struct mvmebus_mapresc *mr;
+ struct mvmebus_range *vr;
+ vme_addr_t end;
+ vme_am_t cap, as;
+ paddr_t paddr;
+ int rv, i;
+
+ sc = vsc;
+ end = (vmeaddr + len) - 1;
+ paddr = 0;
+ vr = sc->sc_masters;
+ cap = MVMEBUS_AM2CAP(am);
+ as = am & VME_AM_ADRSIZEMASK;
+
+ for (i = 0; i < sc->sc_nmasters && paddr == 0; i++, vr++) {
+ if (vr->vr_am == MVMEBUS_AM_DISABLED)
+ continue;
+
+ if (cap == (vr->vr_am & cap) &&
+ as == (vr->vr_am & VME_AM_ADRSIZEMASK) &&
+ datasize <= vr->vr_datasize &&
+ vmeaddr >= vr->vr_vmestart && end < vr->vr_vmeend)
+ paddr = vr->vr_locstart + (vmeaddr & vr->vr_mask);
+ }
+ if (paddr == 0)
+ return (ENOMEM);
+
+ rv = bus_space_map(sc->sc_bust, paddr, len, 0, handle);
+ if (rv != 0)
+ return (rv);
+
+ /* Allocate space for the resource tag */
+ if ((mr = malloc(sizeof(*mr), M_DEVBUF, M_NOWAIT)) == NULL) {
+ bus_space_unmap(sc->sc_bust, *handle, len);
+ return (ENOMEM);
+ }
+
+ /* Record the range's details */
+ mr->mr_am = am;
+ mr->mr_datasize = datasize;
+ mr->mr_addr = vmeaddr;
+ mr->mr_size = len;
+ mr->mr_handle = *handle;
+ mr->mr_range = i;
+
+ *tag = sc->sc_bust;
+ *resc = (vme_mapresc_t *) mr;
+
+ return (0);
+}
+
+/* ARGSUSED */
+void
+mvmebus_unmap(vsc, resc)
+ void *vsc;
+ vme_mapresc_t resc;
+{
+ struct mvmebus_softc *sc = vsc;
+ struct mvmebus_mapresc *mr = (struct mvmebus_mapresc *) resc;
+
+ bus_space_unmap(sc->sc_bust, mr->mr_handle, mr->mr_size);
+
+ free(mr, M_DEVBUF);
+}
+
+int
+mvmebus_probe(vsc, vmeaddr, len, am, datasize, callback, arg)
+ void *vsc;
+ vme_addr_t vmeaddr;
+ vme_size_t len;
+ vme_am_t am;
+ vme_datasize_t datasize;
+ int (*callback)(void *, bus_space_tag_t, bus_space_handle_t);
+ void *arg;
+{
+ bus_space_tag_t tag;
+ bus_space_handle_t handle;
+ vme_mapresc_t resc;
+ vme_size_t offs;
+ int rv;
+
+ /* Get a temporary mapping to the VMEbus range */
+ rv = mvmebus_map(vsc, vmeaddr, len, am, datasize, 0,
+ &tag, &handle, &resc);
+ if (rv)
+ return (rv);
+
+ if (callback)
+ rv = (*callback) (arg, tag, handle);
+ else
+ for (offs = 0; offs < len && rv == 0;) {
+ switch (datasize) {
+ case VME_D8:
+ rv = bus_space_peek_1(tag, handle, offs, NULL);
+ offs += 1;
+ break;
+
+ case VME_D16:
+ rv = bus_space_peek_2(tag, handle, offs, NULL);
+ offs += 2;
+ break;
+
+ case VME_D32:
+ rv = bus_space_peek_4(tag, handle, offs, NULL);
+ offs += 4;
+ break;
+ }
+ }
+
+ mvmebus_unmap(vsc, resc);
+
+ return (rv);
+}
+
+/* ARGSUSED */
+int
+mvmebus_intmap(vsc, level, vector, handlep)
+ void *vsc;
+ int level, vector;
+ vme_intr_handle_t *handlep;
+{
+
+ if (level < 1 || level > 7 || vector < 0x80 || vector > 0xff)
+ return (EINVAL);
+
+ /* This is rather gross */
+ *handlep = (void *) (int) ((level << 8) | vector);
+ return (0);
+}
+
+/* ARGSUSED */
+const struct evcnt *
+mvmebus_intr_evcnt(vsc, handle)
+ void *vsc;
+ vme_intr_handle_t handle;
+{
+ struct mvmebus_softc *sc = vsc;
+
+ return (&sc->sc_evcnt[(((int) handle) >> 8) - 1]);
+}
+
+void *
+mvmebus_intr_establish(vsc, handle, prior, func, arg)
+ void *vsc;
+ vme_intr_handle_t handle;
+ int prior;
+ int (*func)(void *);
+ void *arg;
+{
+ struct mvmebus_softc *sc;
+ int level, vector, first;
+
+ sc = vsc;
+
+ /* Extract the interrupt's level and vector */
+ level = ((int) handle) >> 8;
+ vector = ((int) handle) & 0xff;
+
+#ifdef DIAGNOSTIC
+ if (vector < 0 || vector > 0xff) {
+ printf("%s: Illegal vector offset: 0x%x\n",
+ sc->sc_dev.dv_xname, vector);
+ panic("mvmebus_intr_establish");
+ }
+ if (level < 1 || level > 7) {
+ printf("%s: Illegal interrupt level: %d\n",
+ sc->sc_dev.dv_xname, level);
+ panic("mvmebus_intr_establish");
+ }
+#endif
+
+ first = (sc->sc_irqref[level]++ == 0);
+
+ (*sc->sc_intr_establish)(sc->sc_chip, prior, level, vector, first,
+ func, arg, &sc->sc_evcnt[level - 1]);
+
+ return ((void *) handle);
+}
+
+void
+mvmebus_intr_disestablish(vsc, handle)
+ void *vsc;
+ vme_intr_handle_t handle;
+{
+ struct mvmebus_softc *sc;
+ int level, vector, last;
+
+ sc = vsc;
+
+ /* Extract the interrupt's level and vector */
+ level = ((int) handle) >> 8;
+ vector = ((int) handle) & 0xff;
+
+#ifdef DIAGNOSTIC
+ if (vector < 0 || vector > 0xff) {
+ printf("%s: Illegal vector offset: 0x%x\n",
+ sc->sc_dev.dv_xname, vector);
+ panic("mvmebus_intr_disestablish");
+ }
+ if (level < 1 || level > 7) {
+ printf("%s: Illegal interrupt level: %d\n",
+ sc->sc_dev.dv_xname, level);
+ panic("mvmebus_intr_disestablish");
+ }
+ if (sc->sc_irqref[level] == 0) {
+ printf("%s: VMEirq#%d: Reference count already zero!\n",
+ sc->sc_dev.dv_xname, level);
+ panic("mvmebus_intr_disestablish");
+ }
+#endif
+
+ last = (--(sc->sc_irqref[level]) == 0);
+
+ (*sc->sc_intr_disestablish)(sc->sc_chip, level, vector, last,
+ &sc->sc_evcnt[level - 1]);
+}
+
+#ifdef DIAGNOSTIC
+/* ARGSUSED */
+int
+mvmebus_dummy_dmamap_create(t, size, nsegs, maxsegsz, boundary, flags, dmamp)
+ bus_dma_tag_t t;
+ bus_size_t size;
+ int nsegs;
+ bus_size_t maxsegsz;
+ bus_size_t boundary;
+ int flags;
+ bus_dmamap_t *dmamp;
+{
+
+ panic("Must use vme_dmamap_create() in place of bus_dmamap_create()");
+ return (0); /* Shutup the compiler */
+}
+
+/* ARGSUSED */
+void
+mvmebus_dummy_dmamap_destroy(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+
+ panic("Must use vme_dmamap_destroy() in place of bus_dmamap_destroy()");
+}
+#endif
+
+/* ARGSUSED */
+int
+mvmebus_dmamap_create(vsc, len, am, datasize, swap, nsegs,
+ segsz, bound, flags, mapp)
+ void *vsc;
+ vme_size_t len;
+ vme_am_t am;
+ vme_datasize_t datasize;
+ vme_swap_t swap;
+ int nsegs;
+ vme_size_t segsz;
+ vme_addr_t bound;
+ int flags;
+ bus_dmamap_t *mapp;
+{
+ struct mvmebus_softc *sc = vsc;
+ struct mvmebus_dmamap *vmap;
+ struct mvmebus_range *vr;
+ vme_am_t cap, as;
+ int i, rv;
+
+ cap = MVMEBUS_AM2CAP(am);
+ as = am & VME_AM_ADRSIZEMASK;
+
+ /*
+ * Verify that we even stand a chance of satisfying
+ * the VMEbus address space and datasize requested.
+ */
+ for (i = 0, vr = sc->sc_slaves; i < sc->sc_nslaves; i++, vr++) {
+ if (vr->vr_am == MVMEBUS_AM_DISABLED)
+ continue;
+
+ if (as == (vr->vr_am & VME_AM_ADRSIZEMASK) &&
+ cap == (vr->vr_am & cap) && datasize <= vr->vr_datasize &&
+ len <= (vr->vr_vmeend - vr->vr_vmestart))
+ break;
+ }
+
+ if (i == sc->sc_nslaves)
+ return (EINVAL);
+
+ if ((vmap = malloc(sizeof(*vmap), M_DMAMAP,
+ (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL)
+ return (ENOMEM);
+
+
+ rv = bus_dmamap_create(sc->sc_dmat, len, nsegs, segsz,
+ bound, flags, mapp);
+ if (rv != 0) {
+ free(vmap, M_DMAMAP);
+ return (rv);
+ }
+
+ vmap->vm_am = am;
+ vmap->vm_datasize = datasize;
+ vmap->vm_swap = swap;
+ vmap->vm_slave = vr;
+
+ (*mapp)->_dm_cookie = vmap;
+
+ return (0);
+}
+
+void
+mvmebus_dmamap_destroy(vsc, map)
+ void *vsc;
+ bus_dmamap_t map;
+{
+ struct mvmebus_softc *sc = vsc;
+
+ free(map->_dm_cookie, M_DMAMAP);
+ bus_dmamap_destroy(sc->sc_dmat, map);
+}
+
+static int
+mvmebus_dmamap_load_common(sc, map)
+ struct mvmebus_softc *sc;
+ bus_dmamap_t map;
+{
+ struct mvmebus_dmamap *vmap = map->_dm_cookie;
+ struct mvmebus_range *vr = vmap->vm_slave;
+ bus_dma_segment_t *ds;
+ vme_am_t cap, am;
+ int i;
+
+ cap = MVMEBUS_AM2CAP(vmap->vm_am);
+ am = vmap->vm_am & VME_AM_ADRSIZEMASK;
+
+ /*
+ * Traverse the list of segments which make up this map, and
+ * convert the cpu-relative addresses therein to VMEbus addresses.
+ */
+ for (ds = &map->dm_segs[0]; ds < &map->dm_segs[map->dm_nsegs]; ds++) {
+ /*
+ * First, see if this map's slave image can access the
+ * segment, otherwise we have to waste time scanning all
+ * the slave images.
+ */
+ vr = vmap->vm_slave;
+ if (am == (vr->vr_am & VME_AM_ADRSIZEMASK) &&
+ cap == (vr->vr_am & cap) &&
+ vmap->vm_datasize <= vr->vr_datasize &&
+ ds->_ds_cpuaddr >= vr->vr_locstart &&
+ ds->ds_len <= (vr->vr_vmeend - vr->vr_vmestart))
+ goto found;
+
+ for (i = 0, vr = sc->sc_slaves; i < sc->sc_nslaves; i++, vr++) {
+ if (vr->vr_am == MVMEBUS_AM_DISABLED)
+ continue;
+
+ /*
+ * Filter out any slave images which don't have the
+ * same VMEbus address modifier and datasize as
+ * this DMA map, and those which don't cover the
+ * physical address region containing the segment.
+ */
+ if (vr != vmap->vm_slave &&
+ am == (vr->vr_am & VME_AM_ADRSIZEMASK) &&
+ cap == (vr->vr_am & cap) &&
+ vmap->vm_datasize <= vr->vr_datasize &&
+ ds->_ds_cpuaddr >= vr->vr_locstart &&
+ ds->ds_len <= (vr->vr_vmeend - vr->vr_vmestart))
+ break;
+ }
+
+ /*
+ * Did we find an applicable slave image which covers this
+ * segment?
+ */
+ if (i == sc->sc_nslaves) {
+ /*
+ * XXX TODO:
+ *
+ * Bounce this segment via a bounce buffer allocated
+ * from this DMA map.
+ */
+ printf("mvmebus_dmamap_load_common: bounce needed!\n");
+ return (EINVAL);
+ }
+
+found:
+ /*
+ * Generate the VMEbus address of this segment
+ */
+ ds->ds_addr = (ds->_ds_cpuaddr - vr->vr_locstart) +
+ vr->vr_vmestart;
+ }
+
+ return (0);
+}
+
+int
+mvmebus_dmamap_load(t, map, buf, buflen, p, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ void *buf;
+ bus_size_t buflen;
+ struct proc *p;
+ int flags;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+ int rv;
+
+ rv = bus_dmamap_load(sc->sc_dmat, map, buf, buflen, p, flags);
+ if (rv != 0)
+ return rv;
+
+ return mvmebus_dmamap_load_common(sc, map);
+}
+
+int
+mvmebus_dmamap_load_mbuf(t, map, chain, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ struct mbuf *chain;
+ int flags;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+ int rv;
+
+ rv = bus_dmamap_load_mbuf(sc->sc_dmat, map, chain, flags);
+ if (rv != 0)
+ return rv;
+
+ return mvmebus_dmamap_load_common(sc, map);
+}
+
+int
+mvmebus_dmamap_load_uio(t, map, uio, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ struct uio *uio;
+ int flags;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+ int rv;
+
+ rv = bus_dmamap_load_uio(sc->sc_dmat, map, uio, flags);
+ if (rv != 0)
+ return rv;
+
+ return mvmebus_dmamap_load_common(sc, map);
+}
+
+int
+mvmebus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ bus_size_t size;
+ int flags;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+ int rv;
+
+ /*
+ * mvmebus_dmamem_alloc() will ensure that the physical memory
+ * backing these segments is 100% accessible in at least one
+ * of the board's VMEbus slave images.
+ */
+ rv = bus_dmamap_load_raw(sc->sc_dmat, map, segs, nsegs, size, flags);
+ if (rv != 0)
+ return rv;
+
+ return mvmebus_dmamap_load_common(sc, map);
+}
+
+void
+mvmebus_dmamap_unload(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+
+ /* XXX Deal with bounce buffers */
+
+ bus_dmamap_unload(sc->sc_dmat, map);
+}
+
+void
+mvmebus_dmamap_sync(t, map, offset, len, ops)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_addr_t offset;
+ bus_size_t len;
+ int ops;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+
+ /* XXX Bounce buffers */
+
+ bus_dmamap_sync(sc->sc_dmat, map, offset, len, ops);
+}
+
+#ifdef DIAGNOSTIC
+/* ARGSUSED */
+int
+mvmebus_dummy_dmamem_alloc(t, size, align, boundary, segs, nsegs, rsegs, flags)
+ bus_dma_tag_t t;
+ bus_size_t size;
+ bus_size_t align;
+ bus_size_t boundary;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ int *rsegs;
+ int flags;
+{
+
+ panic("Must use vme_dmamem_alloc() in place of bus_dmamem_alloc()\n");
+}
+
+/* ARGSUSED */
+void
+mvmebus_dummy_dmamem_free(t, segs, nsegs)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+{
+
+ panic("Must use vme_dmamem_free() in place of bus_dmamem_free()");
+}
+#endif
+
+/* ARGSUSED */
+int
+mvmebus_dmamem_alloc(vsc, len, am, datasize, swap, segs, nsegs, rsegs, flags)
+ void *vsc;
+ vme_size_t len;
+ vme_am_t am;
+ vme_datasize_t datasize;
+ vme_swap_t swap;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ int *rsegs;
+ int flags;
+{
+ extern paddr_t avail_start;
+ struct mvmebus_softc *sc = vsc;
+ struct mvmebus_range *vr;
+ bus_addr_t low, high;
+ bus_size_t bound;
+ vme_am_t cap;
+ int i;
+
+ cap = MVMEBUS_AM2CAP(am);
+ am &= VME_AM_ADRSIZEMASK;
+
+ /*
+ * Find a slave mapping in the requested VMEbus address space.
+ */
+ for (i = 0, vr = sc->sc_slaves; i < sc->sc_nslaves; i++, vr++) {
+ if (vr->vr_am == MVMEBUS_AM_DISABLED)
+ continue;
+
+ if (i == 0 && (flags & BUS_DMA_ONBOARD_RAM) != 0)
+ continue;
+
+ if (am == (vr->vr_am & VME_AM_ADRSIZEMASK) &&
+ cap == (vr->vr_am & cap) && datasize <= vr->vr_datasize &&
+ len <= (vr->vr_vmeend - vr->vr_vmestart))
+ break;
+ }
+ if (i == sc->sc_nslaves)
+ return (EINVAL);
+
+ /*
+ * Set up the constraints so we can allocate physical memory which
+ * is visible in the requested address space
+ */
+ low = max(vr->vr_locstart, avail_start);
+ high = vr->vr_locstart + (vr->vr_vmeend - vr->vr_vmestart) + 1;
+ bound = (bus_size_t) vr->vr_mask + 1;
+
+ /*
+ * Allocate physical memory.
+ *
+ * Note: This fills in the segments with cpu-relative physical
+ * addresses. A further call to bus_dmamap_load_raw() (with a
+ * dma map which specifies the same VMEbus address space and
+ * constraints as the call to here) must be made. The segments
+ * of the dma map will then contain VMEbus-relative physical
+ * addresses of the memory allocated here.
+ */
+ return _bus_dmamem_alloc_common(sc->sc_dmat, low, high,
+ len, 0, bound, segs, nsegs, rsegs, flags);
+}
+
+void
+mvmebus_dmamem_free(vsc, segs, nsegs)
+ void *vsc;
+ bus_dma_segment_t *segs;
+ int nsegs;
+{
+ struct mvmebus_softc *sc = vsc;
+
+ bus_dmamem_free(sc->sc_dmat, segs, nsegs);
+}
+
+int
+mvmebus_dmamem_map(t, segs, nsegs, size, kvap, flags)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ size_t size;
+ caddr_t *kvap;
+ int flags;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+
+ return bus_dmamem_map(sc->sc_dmat, segs, nsegs, size, kvap, flags);
+}
+
+void
+mvmebus_dmamem_unmap(t, kva, size)
+ bus_dma_tag_t t;
+ caddr_t kva;
+ size_t size;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+
+ bus_dmamem_unmap(sc->sc_dmat, kva, size);
+}
+
+paddr_t
+mvmebus_dmamem_mmap(t, segs, nsegs, offset, prot, flags)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ off_t offset;
+ int prot;
+ int flags;
+{
+ struct mvmebus_softc *sc = t->_cookie;
+
+ return bus_dmamem_mmap(sc->sc_dmat, segs, nsegs, offset, prot, flags);
+}
+
+#ifdef DEBUG
+static const char *
+mvmebus_mod_string(addr, len, am, ds)
+ vme_addr_t addr;
+ vme_size_t len;
+ vme_am_t am;
+ vme_datasize_t ds;
+{
+ static const char *mode[] = {"BLT64)", "DATA)", "PROG)", "BLT32)"};
+ static const char *dsiz[] = {"(", "(D8,", "(D16,", "(D16-D8,",
+ "(D32,", "(D32,D8,", "(D32-D16,", "(D32-D8,"};
+ static char mstring[40];
+ char *fmt;
+
+ switch (am & VME_AM_ADRSIZEMASK) {
+ case VME_AM_A32:
+ fmt = "A32:%08x-%08x ";
+ break;
+
+ case VME_AM_A24:
+ fmt = "A24:%06x-%06x ";
+ break;
+
+ case VME_AM_A16:
+ fmt = "A16:%04x-%04x ";
+ break;
+
+ case VME_AM_USERDEF:
+ fmt = "USR:%08x-%08x ";
+ break;
+ }
+
+ sprintf(mstring, fmt, addr, addr + len - 1);
+ strcat(mstring, dsiz[ds & 0x7]);
+
+ if (MVMEBUS_AM_HAS_CAP(am)) {
+ if (am & MVMEBUS_AM_CAP_DATA)
+ strcat(mstring, "D");
+ if (am & MVMEBUS_AM_CAP_PROG)
+ strcat(mstring, "P");
+ if (am & MVMEBUS_AM_CAP_USER)
+ strcat(mstring, "U");
+ if (am & MVMEBUS_AM_CAP_SUPER)
+ strcat(mstring, "S");
+ if (am & MVMEBUS_AM_CAP_BLK)
+ strcat(mstring, "B");
+ if (am & MVMEBUS_AM_CAP_BLKD64)
+ strcat(mstring, "6");
+ strcat(mstring, ")");
+ } else {
+ strcat(mstring, ((am & VME_AM_PRIVMASK) == VME_AM_USER) ?
+ "USER," : "SUPER,");
+ strcat(mstring, mode[am & VME_AM_MODEMASK]);
+ }
+
+ return (mstring);
+}
+#endif
diff --git a/sys/dev/mvme/mvmebus.h b/sys/dev/mvme/mvmebus.h
new file mode 100644
index 00000000000..e2c0c5e6e72
--- /dev/null
+++ b/sys/dev/mvme/mvmebus.h
@@ -0,0 +1,161 @@
+/* $NetBSD: mvmebus.h,v 1.1 2002/02/12 20:38:48 scw Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _MVME_MVMEBUS_H
+#define _MVME_MVMEBUS_H
+
+/*
+ * VMEbus master and slave windows are described using
+ * instances of this structure.
+ *
+ * The chip-specific code records the details of the available mappings
+ * for the MVME board.
+ */
+struct mvmebus_range {
+ vme_am_t vr_am; /* Address modifier (A16, A24, A32) */
+ vme_datasize_t vr_datasize; /* Datasize: logical OR of D8,D16,D32 */
+ paddr_t vr_locstart; /* CPU-relative address of mapping */
+ paddr_t vr_mask; /* Mask to apply to this mapping */
+ vme_addr_t vr_vmestart; /* VMEbus start address */
+ vme_addr_t vr_vmeend; /* VMEbus end address */
+};
+
+/* Assigned to vr_am to specify the mapping is not valid */
+#define MVMEBUS_AM_DISABLED ((vme_am_t)-1)
+
+/* For slave mappings, these specify the slave's capabilities */
+#define MVMEBUS_AM_CAP_DATA 0x0100
+#define MVMEBUS_AM_CAP_PROG 0x0200
+#define MVMEBUS_AM_CAP_BLK 0x0400
+#define MVMEBUS_AM_CAP_BLKD64 0x0800
+#define MVMEBUS_AM_CAP_USER 0x1000
+#define MVMEBUS_AM_CAP_SUPER 0x2000
+#define MVMEBUS_AM_HAS_CAP(x) (((x) & 0x3f00) != 0)
+
+#define MVMEBUS_AM2CAP(am) (_mvmebus_am_cap[((am) & \
+ (VME_AM_MODEMASK | VME_AM_PRIVMASK))])
+
+
+/*
+ * This records VMEbus-specific details of a region of bus_space_map'd
+ * VMEbus address space.
+ */
+struct mvmebus_mapresc {
+ bus_space_handle_t mr_handle;
+ bus_addr_t mr_addr;
+ bus_size_t mr_size;
+ vme_am_t mr_am;
+ vme_datasize_t mr_datasize;
+ int mr_range;
+};
+
+
+/*
+ * This records the VMEbus-specific details of a region of phyisical
+ * memory accessible through a VMEbus slave map.
+ */
+struct mvmebus_dmamap {
+ vme_am_t vm_am;
+ vme_datasize_t vm_datasize;
+ vme_swap_t vm_swap;
+ struct mvmebus_range *vm_slave;
+};
+
+
+struct mvmebus_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_bust;
+ bus_dma_tag_t sc_dmat;
+ short sc_irqref[8];
+ void *sc_chip;
+ int sc_nmasters;
+ struct mvmebus_range *sc_masters;
+ int sc_nslaves;
+ struct mvmebus_range *sc_slaves;
+ struct evcnt sc_evcnt[7];
+ void (*sc_intr_establish)(void *, int, int, int, int,
+ int (*)(void *), void *, struct evcnt *);
+ void (*sc_intr_disestablish)(void *, int, int, int,
+ struct evcnt *);
+ struct vme_chipset_tag sc_vct;
+ struct mvme68k_bus_dma_tag sc_mvmedmat;
+};
+
+
+void mvmebus_attach(struct mvmebus_softc *);
+int mvmebus_map(void *, vme_addr_t, vme_size_t, vme_am_t,
+ vme_datasize_t, vme_swap_t, bus_space_tag_t *,
+ bus_space_handle_t *, vme_mapresc_t *);
+void mvmebus_unmap(void *, vme_mapresc_t);
+int mvmebus_probe(void *, vme_addr_t, vme_size_t,
+ vme_am_t, vme_datasize_t,
+ int (*) (void *, bus_space_tag_t, bus_space_handle_t), void *arg);
+int mvmebus_intmap(void *, int, int, vme_intr_handle_t *);
+const struct evcnt *mvmebus_intr_evcnt(void *, vme_intr_handle_t);
+void * mvmebus_intr_establish(void *, vme_intr_handle_t, int,
+ int (*) (void *), void *);
+void mvmebus_intr_disestablish(void *, vme_intr_handle_t);
+
+int mvmebus_dmamap_create(void *, vme_size_t, vme_am_t, vme_datasize_t,
+ vme_swap_t, int, vme_size_t, vme_addr_t, int, bus_dmamap_t *);
+void mvmebus_dmamap_destroy(void *, bus_dmamap_t);
+int mvmebus_dmamap_load(bus_dma_tag_t, bus_dmamap_t,
+ void *, bus_size_t, struct proc *, int);
+int mvmebus_dmamap_load_mbuf(bus_dma_tag_t,
+ bus_dmamap_t, struct mbuf *, int);
+int mvmebus_dmamap_load_uio(bus_dma_tag_t,
+ bus_dmamap_t, struct uio *, int);
+int mvmebus_dmamap_load_raw(bus_dma_tag_t,
+ bus_dmamap_t, bus_dma_segment_t *, int, bus_size_t, int);
+void mvmebus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
+void mvmebus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+ bus_size_t, int);
+
+int mvmebus_dmamem_alloc(void *, vme_size_t, vme_am_t, vme_datasize_t,
+ vme_swap_t, bus_dma_segment_t *, int, int *, int);
+void mvmebus_dmamem_free(void *, bus_dma_segment_t *, int);
+int mvmebus_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, int,
+ size_t, caddr_t *, int);
+void mvmebus_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t);
+paddr_t mvmebus_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, int,
+ off_t, int, int);
+
+extern vme_am_t _mvmebus_am_cap[];
+extern const char *mvmebus_irq_name[];
+
+#endif /* _MVME_MVMEBUS_H */
diff --git a/sys/dev/mvme/osiop_pcctwo.c b/sys/dev/mvme/osiop_pcctwo.c
new file mode 100644
index 00000000000..f959f35faf9
--- /dev/null
+++ b/sys/dev/mvme/osiop_pcctwo.c
@@ -0,0 +1,191 @@
+/* $NetBSD: osiop_pcctwo.c,v 1.1 2002/02/12 20:38:48 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Front-end attachment code for the ncr53c710 SCSI controller
+ * on mvme68k/mvme88k boards.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <dev/scsipi/scsi_all.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsiconf.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/autoconf.h>
+
+#include <dev/ic/osiopreg.h>
+#include <dev/ic/osiopvar.h>
+
+#include <dev/mvme/pcctworeg.h>
+#include <dev/mvme/pcctwovar.h>
+
+
+int osiop_pcctwo_match __P((struct device *, struct cfdata *, void *));
+void osiop_pcctwo_attach __P((struct device *, struct device *, void *));
+
+struct osiop_pcctwo_softc {
+ struct osiop_softc sc_osiop;
+ struct evcnt sc_evcnt;
+};
+
+struct cfattach osiop_pcctwo_ca = {
+ sizeof(struct osiop_pcctwo_softc), osiop_pcctwo_match,
+ osiop_pcctwo_attach
+};
+
+static int osiop_pcctwo_intr __P((void *));
+
+extern struct cfdriver osiop_cd;
+
+/* ARGSUSED */
+int
+osiop_pcctwo_match(parent, cf, args)
+ struct device *parent;
+ struct cfdata *cf;
+ void *args;
+{
+ struct pcctwo_attach_args *pa;
+
+ pa = args;
+
+ if (strcmp(pa->pa_name, osiop_cd.cd_name))
+ return (0);
+
+ pa->pa_ipl = cf->pcctwocf_ipl;
+
+ return (1);
+}
+
+/* ARGSUSED */
+void
+osiop_pcctwo_attach(parent, self, args)
+ struct device *parent;
+ struct device *self;
+ void *args;
+{
+ struct pcctwo_attach_args *pa;
+ struct osiop_pcctwo_softc *sc;
+ int clk, ctest7;
+
+ pa = (struct pcctwo_attach_args *) args;
+ sc = (struct osiop_pcctwo_softc *) self;
+
+ /*
+ * On the '17x the siop's clock is the same as the cpu clock.
+ * On the other boards, the siop runs at twice the cpu clock.
+ * Also, the 17x cannot do proper bus-snooping (the 68060 is
+ * lame in this repspect) so don't enable it on that board.
+ */
+#ifdef MVME68K
+ if (machineid == MVME_172 || machineid == MVME_177) {
+ clk = cpuspeed;
+ ctest7 = 0;
+ } else {
+ clk = cpuspeed * 2;
+ ctest7 = OSIOP_CTEST7_SC0;
+ }
+#else
+#error Set up siop clock speed for mvme187
+#endif
+
+ sc->sc_osiop.sc_bst = pa->pa_bust;
+ sc->sc_osiop.sc_dmat = pa->pa_dmat;
+ (void) bus_space_map(sc->sc_osiop.sc_bst, pa->pa_offset, OSIOP_NREGS,
+ 0, &sc->sc_osiop.sc_reg);
+
+ sc->sc_osiop.sc_clock_freq = clk;
+ sc->sc_osiop.sc_ctest7 = ctest7 | OSIOP_CTEST7_TT1;
+ sc->sc_osiop.sc_dcntl = OSIOP_DCNTL_EA;
+ sc->sc_osiop.sc_id = 7; /* XXX: Could use NVRAM setting */
+
+ /* Attach main MI driver */
+ osiop_attach(&sc->sc_osiop);
+
+ /* Register the event counter */
+ evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
+ pcctwointr_evcnt(pa->pa_ipl), "disk", sc->sc_osiop.sc_dev.dv_xname);
+
+ /* Hook the chip's interrupt */
+ pcctwointr_establish(PCCTWOV_SCSI, osiop_pcctwo_intr, pa->pa_ipl, sc,
+ &sc->sc_evcnt);
+}
+
+static int
+osiop_pcctwo_intr(arg)
+ void *arg;
+{
+ struct osiop_pcctwo_softc *sc = (struct osiop_pcctwo_softc *) arg;
+ u_char istat;
+
+ /*
+ * Catch any errors which can happen when the SIOP is
+ * local bus master...
+ */
+ istat = pcc2_reg_read(sys_pcctwo, PCC2REG_SCSI_ERR_STATUS);
+ if ((istat & PCCTWO_ERR_SR_MASK) != 0) {
+ printf("%s: Local bus error: 0x%02x\n",
+ sc->sc_osiop.sc_dev.dv_xname, istat);
+ istat |= PCCTWO_ERR_SR_SCLR;
+ pcc2_reg_write(sys_pcctwo, PCC2REG_SCSI_ERR_STATUS, istat);
+ }
+
+ /* This is potentially nasty, since the IRQ is level triggered... */
+ if (sc->sc_osiop.sc_flags & OSIOP_INTSOFF)
+ return (0);
+
+ istat = osiop_read_1(&sc->sc_osiop, OSIOP_ISTAT);
+
+ if ((istat & (OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP)) == 0)
+ return (0);
+
+ /* Save interrupt details for the back-end interrupt handler */
+ sc->sc_osiop.sc_sstat0 = osiop_read_1(&sc->sc_osiop, OSIOP_SSTAT0);
+ sc->sc_osiop.sc_istat = istat;
+ sc->sc_osiop.sc_dstat = osiop_read_1(&sc->sc_osiop, OSIOP_DSTAT);
+
+ /* Deal with the interrupt */
+ osiop_intr(&sc->sc_osiop);
+
+ return (1);
+}
diff --git a/sys/dev/mvme/pcctwo.c b/sys/dev/mvme/pcctwo.c
new file mode 100644
index 00000000000..13c1fe9a2ab
--- /dev/null
+++ b/sys/dev/mvme/pcctwo.c
@@ -0,0 +1,204 @@
+/* $NetBSD: pcctwo.c,v 1.1 2002/02/12 20:38:49 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * PCCchip2 and MCchip Driver
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/mvme/pcctworeg.h>
+#include <dev/mvme/pcctwovar.h>
+
+/*
+ * Global Pointer to the PCCChip2/MCchip soft state, and chip ID
+ */
+struct pcctwo_softc *sys_pcctwo;
+
+int pcctwoprint(void *, const char *);
+
+
+/* ARGSUSED */
+void
+pcctwo_init(sc, pd, devoff)
+ struct pcctwo_softc *sc;
+ struct pcctwo_device *pd;
+ int devoff;
+{
+ struct pcctwo_attach_args npa;
+ u_int8_t cid;
+
+ /*
+ * Fix up the vector base for PCCChip2 Interrupts
+ */
+ pcc2_reg_write(sc, PCC2REG_VECTOR_BASE, sc->sc_vecbase);
+
+ /*
+ * Enable PCCChip2 Interrupts
+ */
+ pcc2_reg_write(sc, PCC2REG_GENERAL_CONTROL,
+ pcc2_reg_read(sc, PCC2REG_GENERAL_CONTROL) | PCCTWO_GEN_CTRL_MIEN);
+
+ /* What are we? */
+ cid = pcc2_reg_read(sc, PCC2REG_CHIP_ID);
+
+ /*
+ * Announce ourselves to the world in general
+ */
+ if (cid == PCCTWO_CHIP_ID_PCC2)
+ printf(": Peripheral Channel Controller (PCCchip2), Rev %d\n",
+ pcc2_reg_read(sc, PCC2REG_CHIP_REVISION));
+ else
+ if (cid == PCCTWO_CHIP_ID_MCCHIP)
+ printf(": Memory Controller ASIC (MCchip), Rev %d\n",
+ pcc2_reg_read(sc, PCC2REG_CHIP_REVISION));
+
+ /*
+ * Attach configured children.
+ */
+ npa._pa_base = devoff;
+ while (pd->pcc_name != NULL) {
+ /*
+ * Note that IPL is filled in by match function.
+ */
+ npa.pa_name = pd->pcc_name;
+ npa.pa_ipl = -1;
+ npa.pa_dmat = sc->sc_dmat;
+ npa.pa_bust = sc->sc_bust;
+ npa.pa_offset = pd->pcc_offset + devoff;
+ pd++;
+
+ /* Attach the device if configured. */
+ (void) config_found(&sc->sc_dev, &npa, pcctwoprint);
+ }
+}
+
+int
+pcctwoprint(aux, cp)
+ void *aux;
+ const char *cp;
+{
+ struct pcctwo_attach_args *pa;
+
+ pa = aux;
+
+ if (cp)
+ printf("%s at %s", pa->pa_name, cp);
+
+ printf(" offset 0x%lx", pa->pa_offset - pa->_pa_base);
+ if (pa->pa_ipl != -1)
+ printf(" ipl %d", pa->pa_ipl);
+
+ return (UNCONF);
+}
+
+/*
+ * pcctwointr_establish: Establish PCCChip2 Interrupt
+ */
+void
+pcctwointr_establish(vec, hand, lvl, arg, evcnt)
+ int vec;
+ int (*hand) __P((void *)), lvl;
+ void *arg;
+ struct evcnt *evcnt;
+{
+ int vec2icsr;
+
+#ifdef DEBUG
+ if (vec < 0 || vec >= PCCTWOV_MAX) {
+ printf("pcctwo: illegal vector offset: 0x%x\n", vec);
+ panic("pcctwointr_establish");
+ }
+ if (lvl < 1 || lvl > 7) {
+ printf("pcctwo: illegal interrupt level: %d\n", lvl);
+ panic("pcctwointr_establish");
+ }
+ if (sys_pcctwo->sc_vec2icsr[vec] == -1) {
+ printf("pcctwo: unsupported vector: %d\n", vec);
+ panic("pcctwointr_establish");
+ }
+#endif
+
+ vec2icsr = sys_pcctwo->sc_vec2icsr[vec];
+ pcc2_reg_write(sys_pcctwo, VEC2ICSR_REG(vec2icsr), 0);
+
+ /* Hook the interrupt */
+ (*sys_pcctwo->sc_isrlink)(sys_pcctwo->sc_isrcookie, hand, arg,
+ lvl, vec + sys_pcctwo->sc_vecbase, evcnt);
+
+ /* Enable it in hardware */
+ pcc2_reg_write(sys_pcctwo, VEC2ICSR_REG(vec2icsr),
+ VEC2ICSR_INIT(vec2icsr) | lvl);
+}
+
+void
+pcctwointr_disestablish(vec)
+ int vec;
+{
+
+#ifdef DEBUG
+ if (vec < 0 || vec >= PCCTWOV_MAX) {
+ printf("pcctwo: illegal vector offset: 0x%x\n", vec);
+ panic("pcctwointr_disestablish");
+ }
+ if (sys_pcctwo->sc_vec2icsr[vec] == -1) {
+ printf("pcctwo: unsupported vector: %d\n", vec);
+ panic("pcctwointr_establish");
+ }
+#endif
+
+ /* Disable it in hardware */
+ pcc2_reg_write(sys_pcctwo, sys_pcctwo->sc_vec2icsr[vec], 0);
+
+ (*sys_pcctwo->sc_isrunlink)(sys_pcctwo->sc_isrcookie,
+ vec + sys_pcctwo->sc_vecbase);
+}
+
+struct evcnt *
+pcctwointr_evcnt(lev)
+ int lev;
+{
+
+ return ((*sys_pcctwo->sc_isrevcnt)(sys_pcctwo->sc_isrcookie, lev));
+}
diff --git a/sys/dev/mvme/pcctworeg.h b/sys/dev/mvme/pcctworeg.h
new file mode 100644
index 00000000000..d644ca583e1
--- /dev/null
+++ b/sys/dev/mvme/pcctworeg.h
@@ -0,0 +1,316 @@
+/* $NetBSD: pcctworeg.h,v 1.1 2002/02/12 20:38:49 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 PCCchip2 device, and offset to the
+ * various subordinate devices which hang off it.
+ */
+#ifndef _MVME_PCCTWOREG_H
+#define _MVME_PCCTWOREG_H
+
+/*
+ * Offsets to the various devices which hang off the PCCChip2.
+ * Note that these are offsets from the base of the PCCChip2's
+ * own registers.
+ */
+#define PCCTWO_REG_OFF 0x00000 /* Offset of PCCChip2's own registers */
+#define PCCTWO_LPT_OFF 0x00000 /* Offset of parallel port registers */
+#define PCCTWO_SCC_OFF 0x03000 /* Offset of CD2401 Serial Comms chip */
+#define PCCTWO_IE_OFF 0x04000 /* Offset of 82596 LAN controller */
+#define PCCTWO_NCRSC_OFF 0x05000 /* Offset of NCR53C710 SCSI chip */
+
+/*
+ * The two devices on mvme1[67]2's MCchip
+ */
+#define MCCHIP_ZS0_OFF 0x03000
+#define MCCHIP_ZS1_OFF 0x03800
+
+/*
+ * This is needed to figure out the boot device.
+ * (The physical address of the boot device's registers are passed in
+ * from the Boot ROM)
+ */
+#define PCCTWO_PADDR(off) ((void *)(0xfff42000u + (off)))
+
+
+/*
+ * The layout of the PCCchip2's Registers.
+ * Each one is 8-bits wide, unless otherwise indicated.
+ */
+#define PCC2REG_CHIP_ID 0x00 /* Chip ID */
+#define PCC2REG_CHIP_REVISION 0x01 /* Chip Revision */
+#define PCC2REG_GENERAL_CONTROL 0x02 /* General Control */
+#define PCC2REG_VECTOR_BASE 0x03 /* Vector Base */
+#define PCC2REG_TIMER1_COMPARE 0x04 /* Tick Timer 1 Compare (32-bit) */
+#define PCC2REG_TIMER1_COUNTER 0x08 /* Tick Timer 1 Counter (32-bit) */
+#define PCC2REG_TIMER2_COMPARE 0x0c /* Tick Timer 2 Compare (32-bit) */
+#define PCC2REG_TIMER2_COUNTER 0x10 /* Tick Timer 2 Counter (32-bit) */
+#define PCC2REG_PRESCALE_COUNT 0x14 /* Prescaler Count */
+#define PCC2REG_PRESCALE_ADJUST 0x15 /* Prescaler Clock Adjust */
+#define PCC2REG_TIMER2_CONTROL 0x16 /* Tick Timer 2 Control */
+#define PCC2REG_TIMER1_CONTROL 0x17 /* Tick Timer 1 Control */
+#define PCC2REG_GPIO_ICSR 0x18 /* GP Input Interrupt Control */
+#define PCC2REG_GPIO_CONTROL 0x19 /* GP Input/Output Control */
+#define PCC2REG_TIMER2_ICSR 0x1a /* Tick Timer 2 Interrupt Control */
+#define PCC2REG_TIMER1_ICSR 0x1b /* Tick Timer 1 Interrupt Control */
+#define PCC2REG_SCC_ERR_STATUS 0x1c /* SCC Error Status */
+#define PCC2REG_SCC_MODEM_ICSR 0x1d /* SCC Modem Interrupt Control */
+#define PCC2REG_SCC_TX_ICSR 0x1e /* SCC Transmit Interrupt Control */
+#define PCC2REG_SCC_RX_ICSR 0x1f /* SCC Receive Interrupt Control */
+#define PCC2REG_SCC_MODEM_PIACK 0x23 /* SCC Modem PIACK */
+#define PCC2REG_SCC_TX_PIACK 0x25 /* SCC Transmit PIACK */
+#define PCC2REG_SCC_RX_PIACK 0x27 /* SCC Receive PIACK */
+#define PCC2REG_ETH_ERR_STATUS 0x28 /* LANC Error Status */
+#define PCC2REG_ETH_ICSR 0x2a /* LANC Interrupt Control */
+#define PCC2REG_ETH_BERR_STATUS 0x2b /* LANC Bus Error Interrupt Ctrl */
+#define PCC2REG_SCSI_ERR_STATUS 0x2c /* SCSI Error Status */
+#define PCC2REG_SCSI_ICSR 0x2f /* SCSI Interrupt Control */
+#define PCC2REG_PRT_ACK_ICSR 0x30 /* Printer ACK Interrupt Control */
+#define PCC2REG_PRT_FAULT_ICSR 0x31 /* Printer FAULT Interrupt Ctrl */
+#define PCC2REG_PRT_SEL_ICSR 0x32 /* Printer SEL Interrupt Control */
+#define PCC2REG_PRT_PE_ICSR 0x33 /* Printer PE Interrupt Control */
+#define PCC2REG_PRT_BUSY_ICSR 0x34 /* Printer BUSY Interrupt Control */
+#define PCC2REG_PRT_INPUT_STATUS 0x36 /* Printer Input Status */
+#define PCC2REG_PRT_CONTROL 0x37 /* Printer Port Control */
+#define PCC2REG_CHIP_SPEED 0x38 /* Chip Speed (16-bit) */
+#define PCC2REG_PRT_DATA 0x3a /* Printer Data (16-bit) */
+#define PCC2REG_IRQ_LEVEL 0x3e /* Interrupt Priority Level */
+#define PCC2REG_IRQ_MASK 0x3f /* Interrupt Mask */
+
+/*
+ * Additions to the registers for the MCChip. Some of these overlap with
+ * the PCCchip2's registers, but only where hardware is not present, eg.
+ * the printer registers.
+ */
+#define MCCHIPREG_TIMER4_ICSR 0x18 /* Tick timer 4 interrupt control */
+#define MCCHIPREG_TIMER3_ICSR 0x19 /* Tick timer 4 interrupt control */
+#define MCCHIPREG_PARERR_ICSR 0x1c /* Parity error interrupt control */
+#define MCCHIPREG_SCC_ICSR 0x1d /* ZS-85230 interrupt control */
+#define MCCHIPREG_TIMER4_CTRL 0x1e /* Tick timer 4 control */
+#define MCCHIPREG_TIMER3_CTRL 0x1f /* Tick timer 3 control */
+#define MCCHIPREG_DRAM_BAR 0x20 /* DRAM Base Address (16-bits) */
+#define MCCHIPREG_SRAM_BAR 0x22 /* SRAM Base Address (16-bits) */
+#define MCCHIPREG_DRAM_SIZE 0x24 /* DRAM Size */
+#define MCCHIPREG_RAM_OPTIONS 0x25 /* DRAM/SRAM Options */
+#define MCCHIPREG_SRAM_SIZE 0x26 /* SRAM Size */
+#define MCCHIPREG_GP_INPUTS 0x2d /* General Purpose Inputs */
+#define MCCHIPREG_162_VERSION 0x2e /* MVME162-LX Series Version */
+#define MCCHIPREG_TIMER3_COMP 0x30 /* Tick Timer 3 Compare (32-bit) */
+#define MCCHIPREG_TIMER3_CNTR 0x34 /* Tick Timer 3 Counter (32-bit) */
+#define MCCHIPREG_TIMER4_COMP 0x38 /* Tick Timer 4 Compare (32-bit) */
+#define MCCHIPREG_TIMER4_CNTR 0x3c /* Tick Timer 4 Counter (32-bit) */
+#define MCCHIPREG_BUS_CLOCK 0x40 /* Bus Clock */
+#define MCCHIPREG_EPROM_TIMING 0x41 /* EPROM Access Time Control */
+#define MCCHIPREG_FLASH_TIMING 0x42 /* FLASH Access Time Control */
+#define MCCHIPREG_ABORT_ICSR 0x43 /* ABORT Switch Interrupt Control */
+#define MCCHIPREG_RESET_CONTROL 0x44 /* Reset Switch Control */
+#define MCCHIPREG_WDOG_CONTROL 0x45 /* Watchdog Timer Control */
+#define MCCHIPREG_TIMEBASE_SEL 0x46 /* Access & Watchdog Timebase Select */
+#define MCCHIPREG_DRAM_CONTROL 0x48 /* Parity DRAM Control */
+#define MCCHIPREG_MPU_STATUS 0x4a /* MPU Status */
+#define MCCHIPREG_PRESCALER 0x4c /* Prescaler Count Register (32-bits) */
+
+/*
+ * PCCchip2's register size is 0x40. MCchip's is 0x50. Plump for the latter.
+ */
+#define PCC2REG_SIZE 0x50
+
+/*
+ * Convenience macroes for accessing the PCCChip2's registers
+ * through bus_space.
+ */
+#define pcc2_reg_read(sc,r) \
+ bus_space_read_1((sc)->sc_bust, (sc)->sc_bush, (r))
+#define pcc2_reg_read16(sc,r) \
+ bus_space_read_2((sc)->sc_bust, (sc)->sc_bush, (r))
+#define pcc2_reg_read32(sc,r) \
+ bus_space_read_4((sc)->sc_bust, (sc)->sc_bush, (r))
+#define pcc2_reg_write(sc,r,v) \
+ bus_space_write_1((sc)->sc_bust, (sc)->sc_bush, (r), (v))
+#define pcc2_reg_write16(sc,r,v) \
+ bus_space_write_2((sc)->sc_bust, (sc)->sc_bush, (r), (v))
+#define pcc2_reg_write32(sc,r,v) \
+ bus_space_write_4((sc)->sc_bust, (sc)->sc_bush, (r), (v))
+
+/*
+ * We use the interrupt vector bases suggested in the Motorola Docs...
+ * The first is written to the PCCChip2 for interrupt sources under
+ * its control. The second is written to the CD2401's Local Interrupt
+ * Vector Register. Thus, we don't use the Auto-Vector facilities
+ * for the CD2401, as recommended in the PCCChip2 Programmer's Guide.
+ * The third is used as a base for the ZS85230 serial chips on mvme162.
+ */
+#define PCCTWO_VECBASE 0x50
+#define PCCTWO_SCC_VECBASE 0x5c
+#define MCCHIP_ZS_VECBASE 0x5c
+
+/*
+ * PCCchip2 Vector Encoding (Offsets from PCCTWO_VECBASE)
+ * The order 0x0 -> 0xf also indicates priority, with 0x0 lowest.
+ */
+#define PCCTWOV_PRT_BUSY 0x0 /* Printer Port 'BSY' */
+#define PCCTWOV_PRT_PE 0x1 /* Printer Port 'PE' (Paper Empty) */
+#define PCCTWOV_PRT_SELECT 0x2 /* Printer Port 'SELECT' */
+#define PCCTWOV_PRT_FAULT 0x3 /* Printer Port 'FAULT' */
+#define PCCTWOV_PRT_ACK 0x4 /* Printer Port 'ACK' */
+#define PCCTWOV_SCSI 0x5 /* SCSI Interrupt */
+#define PCCTWOV_LANC_ERR 0x6 /* LAN Controller Error */
+#define PCCTWOV_LANC_IRQ 0x7 /* LAN Controller Interrupt */
+#define PCCTWOV_TIMER2 0x8 /* Tick Timer 2 Interrupt */
+#define PCCTWOV_TIMER1 0x9 /* Tick Timer 1 Interrupt */
+#define PCCTWOV_GPIO 0xa /* General Purpose Input Interrupt */
+#define PCCTWOV_SCC_RX_EXCEP 0xc /* SCC Receive Exception */
+#define PCCTWOV_SCC_MODEM 0xd /* SCC Modem (Non-Auto-vector mode) */
+#define PCCTWOV_SCC_TX 0xe /* SCC Tx (Non-Auto-vector mode) */
+#define PCCTWOV_SCC_RX 0xf /* SCC Rx (Non-Auto-vector mode) */
+#define PCCTWOV_MAX 16
+
+/*
+ * MCchip-specific Vector Encoding (Offsets from PCCTWO_VECBASE)
+ */
+#define MCCHIPV_TIMER4 0x3 /* Tick Timer 4 Interrupt */
+#define MCCHIPV_TIMER3 0x4 /* Tick Timer 3 Interrupt */
+#define MCCHIPV_PARITY_ERR 0xb /* Parity DRAM Error Exception */
+#define MCCHIPV_ZS0 0xc /* First ZS85230 Interrupt Vector */
+#define MCCHIPV_ZS1 0xc /* Second ZS85230 Interrupt Vector */
+#define MCCHIPV_ABORT 0xe /* Abort Switch */
+
+/*
+ * How to identify the PCCchip2 from an MCchip
+ */
+#define PCCTWO_CHIP_ID_PCC2 0x20
+#define PCCTWO_CHIP_ID_MCCHIP 0x84
+
+
+/*
+ * Bit Values for the General Control Register (PCC2REG_GENERAL_CONTROL)
+ */
+#define PCCTWO_GEN_CTRL_FAST (1u<<0) /* BBRAM Speed Control */
+#define PCCTWO_GEN_CTRL_MIEN (1u<<1) /* Master Interrupt Enable */
+#define PCCTWO_GEN_CTRL_C040 (1u<<2) /* Set when CPU is mc68k family */
+#define PCCTWO_GEN_CTRL_DR0 (1u<<3) /* Download ROM at 0 (mvme166 only) */
+
+
+/*
+ * Calculate the Prescaler Adjust value for a given
+ * value of BCLK in MHz. (PCC2REG_PRESCALE_ADJUST)
+ */
+#define PCCTWO_PRES_ADJ(mhz) (256 - (mhz))
+
+
+/*
+ * Calculate the Tick Timer Compare register value for
+ * a given number of micro-seconds. With the PCCChip2,
+ * this is simple since the Tick Counters already have
+ * a 1uS period. (PCC2REG_TIMER[12]_COMPARE)
+ */
+#define PCCTWO_US2LIM(us) (us)
+#define PCCTWO_LIM2US(lim) (lim)
+
+/*
+ * The Tick Timer Control Registers (PCC2REG_TIMER[12]_CONTROL)
+ */
+#define PCCTWO_TT_CTRL_CEN (1u<<0) /* Counter Enable */
+#define PCCTWO_TT_CTRL_COC (1u<<1) /* Clear On Compare */
+#define PCCTWO_TT_CTRL_COVF (1u<<2) /* Clear Overflow Counter */
+#define PCCTWO_TT_CTRL_OVF(r) ((r)>>4)/* Value of the Overflow Counter */
+
+
+/*
+ * All the Interrupt Control Registers (PCC2REG_*_ICSR) on the PCCChip2
+ * mostly share the same basic layout. These are defined as follows:
+ */
+#define PCCTWO_ICR_LEVEL_MASK 0x7 /* Mask for the interrupt level */
+#define PCCTWO_ICR_ICLR (1u<<3) /* Clear Int. (edge-sensitive mode) */
+#define PCCTWO_ICR_AVEC (1u<<3) /* Enable Auto-Vector Mode */
+#define PCCTWO_ICR_IEN (1u<<4) /* Interrupt Enable */
+#define PCCTWO_ICR_INT (1u<<5) /* Interrupt Active */
+#define PCCTWO_ICR_LEVEL (0u<<6) /* Level Triggered */
+#define PCCTWO_ICR_EDGE (1u<<6) /* Edge Triggered */
+#define PCCTWO_ICR_RISE_HIGH (0u<<7) /* Polarity: Rising Edge or Hi Level */
+#define PCCTWO_ICR_FALL_LOW (1u<<7) /* Polarity: Falling Edge or Lo Level */
+#define PCCTWO_ICR_SC_RD(r) ((r)>>6)/* Get Snoop Control Bits */
+#define PCCTWO_ICR_SC_WR(r) ((r)<<6)/* Write Snoop Control Bits */
+
+
+
+/*
+ * Most of the Error Status Registers (PCC2REG_*_ERR_STATUS) mostly
+ * follow the same layout. These error registers are used when a
+ * device (eg. SCC, LANC) is mastering the PCCChip2's local bus (for
+ * example, performing a DMA) and some error occurs. The bits are
+ * defined as follows:
+ */
+#define PCCTWO_ERR_SR_SCLR (1u<<0) /* Clear Error Status */
+#define PCCTWO_ERR_SR_LTO (1u<<1) /* Local Bus Timeout */
+#define PCCTWO_ERR_SR_EXT (1u<<2) /* External (VMEbus) Error */
+#define PCCTWO_ERR_SR_PRTY (1u<<3) /* DRAM Parity Error */
+#define PCCTWO_ERR_SR_RTRY (1u<<4) /* Retry Required */
+#define PCCTWO_ERR_SR_MASK 0x0Eu
+
+
+/*
+ * General Purpose Input/Output Pin Control Register
+ * (PCC2REG_GPIO_CONTROL)
+ */
+#define PCCTWO_GPIO_CTRL_GPO (1u<<0) /* Controls the GP Output Pin */
+#define PCCTWO_GPIO_CTRL_GPOE (1u<<1) /* General Purpose Output Enable */
+#define PCCTWO_GPIO_CTRL_GPI (1u<<3) /* The current state of the GP Input */
+
+
+/*
+ * Printer Input Status Register (PCC2REG_PRT_INPUT_STATUS)
+ */
+#define PCCTWO_PRT_IN_SR_BSY (1u<<0) /* State of printer's BSY Input */
+#define PCCTWO_PRT_IN_SR_PE (1u<<1) /* State of printer's PE Input */
+#define PCCTWO_PRT_IN_SR_SEL (1u<<2) /* State of printer's SELECT Input */
+#define PCCTWO_PRT_IN_SR_FLT (1u<<3) /* State of printer's FAULT Input */
+#define PCCTWO_PRT_IN_SR_ACK (1u<<4) /* State of printer's ACK Input */
+#define PCCTWO_PRT_IN_SR_PINT (1u<<7) /* Printer Interrupt Status */
+
+
+/*
+ * Printer Port Control Register (PCC2REG_PRT_CONTROL)
+ */
+#define PCCTWO_PRT_CTRL_MAN (1u<<0) /* Manual Strobe Control */
+#define PCCTWO_PRT_CTRL_FAST (1u<<1) /* Fast Auto Strobe */
+#define PCCTWO_PRT_CTRL_STB (1u<<2) /* Strobe Pin, in manual control mode */
+#define PCCTWO_PRT_CTRL_INP (1u<<3) /* Printer Input Prime */
+#define PCCTWO_PRT_CTRL_DOEN (1u<<4) /* Printer Data Output Enable */
+
+#endif /* _MVME_PCCTWOREG_H */
diff --git a/sys/dev/mvme/pcctwovar.h b/sys/dev/mvme/pcctwovar.h
new file mode 100644
index 00000000000..2b5c394cd40
--- /dev/null
+++ b/sys/dev/mvme/pcctwovar.h
@@ -0,0 +1,103 @@
+/* $NetBSD: pcctwovar.h,v 1.1 2002/02/12 20:38:50 scw Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _MVME_PCCTWOVAR_H
+#define _MVME_PCCTWOVAR_H
+
+/*
+ * Structure used to attach PCC devices.
+ */
+struct pcctwo_attach_args {
+ const char *pa_name; /* name of device */
+ int pa_ipl; /* interrupt level */
+ bus_dma_tag_t pa_dmat; /* DMA tag */
+ bus_space_tag_t pa_bust; /* Bus tag */
+ bus_addr_t pa_offset; /* Offset with 'Bus tag' bus space */
+
+ bus_addr_t _pa_base;
+};
+
+/*
+ * Structure used to describe a device for autoconfiguration purposes.
+ */
+struct pcctwo_device {
+ char *pcc_name; /* name of device (e.g. "clock") */
+ bus_addr_t pcc_offset; /* offset from PCC2 base */
+};
+
+/*
+ * Macroes to make life easy when converting vector offset to interrupt
+ * control register, and how to initialise the ICSR.
+ */
+#define VEC2ICSR(r,v) ((r) | (((v) | PCCTWO_ICR_IEN) << 8))
+#define VEC2ICSR_REG(x) ((x) & 0xff)
+#define VEC2ICSR_INIT(x) ((x) >> 8)
+
+/* Shorthand for locators. */
+#include "locators.h"
+#define pcctwocf_ipl cf_loc[PCCTWOCF_IPL]
+
+/*
+ * PCCChip2 driver's soft state structure
+ */
+struct pcctwo_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_bust; /* PCCChip2's register tag */
+ bus_space_handle_t sc_bush; /* PCCChip2's register handle */
+ bus_dma_tag_t sc_dmat; /* PCCChip2's dma tag (unused)*/
+ int *sc_vec2icsr; /* Translate vector to ICSR */
+ int sc_vecbase;
+ void *sc_isrcookie;
+ void (*sc_isrlink)(void *, int (*)(void *), void *,
+ int, int, struct evcnt *);
+ void (*sc_isrunlink)(void *, int);
+ struct evcnt * (*sc_isrevcnt)(void *, int);
+#if defined(MVME162) || defined(MVME172)
+ struct evcnt sc_evcnt;
+#endif
+};
+
+extern struct pcctwo_softc *sys_pcctwo;
+
+extern void pcctwo_init(struct pcctwo_softc *, struct pcctwo_device *, int);
+extern struct evcnt *pcctwointr_evcnt(int);
+extern void pcctwointr_establish(int, int (*)(void *), int, void *,
+ struct evcnt *);
+extern void pcctwointr_disestablish(int);
+
+#endif /* _MVME_PCCTWOVAR_H */
diff --git a/sys/dev/mvme/vme_two.c b/sys/dev/mvme/vme_two.c
new file mode 100644
index 00000000000..8eb7f191e0e
--- /dev/null
+++ b/sys/dev/mvme/vme_two.c
@@ -0,0 +1,353 @@
+/* $NetBSD: vme_two.c,v 1.1 2002/02/12 20:38:50 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * VME support specific to the VMEchip2 found on all high-end MVME boards
+ */
+
+#include "vmetwo.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/vme/vmereg.h>
+#include <dev/vme/vmevar.h>
+
+#include <dev/mvme/mvmebus.h>
+#include <dev/mvme/vme_tworeg.h>
+#include <dev/mvme/vme_twovar.h>
+
+void vmetwo_master_range(struct vmetwo_softc *, int, struct mvmebus_range *);
+void vmetwo_slave_range(struct vmetwo_softc *, int, vme_am_t,
+ struct mvmebus_range *);
+
+/* ARGSUSED */
+void
+vmetwo_init(sc)
+ struct vmetwo_softc *sc;
+{
+ u_int32_t reg;
+ int i;
+
+ /* Initialise stuff for the common mvmebus front-end */
+ sc->sc_mvmebus.sc_chip = sc;
+ sc->sc_mvmebus.sc_nmasters = VME2_NMASTERS;
+ sc->sc_mvmebus.sc_masters = &sc->sc_master[0];
+ sc->sc_mvmebus.sc_nslaves = VME2_NSLAVES;
+ sc->sc_mvmebus.sc_slaves = &sc->sc_slave[0];
+ sc->sc_mvmebus.sc_intr_establish = vmetwo_intr_establish;
+ sc->sc_mvmebus.sc_intr_disestablish = vmetwo_intr_disestablish;
+
+ /* Initialise interrupts */
+ vmetwo_intr_init(sc);
+
+ reg = vme2_lcsr_read(sc, VME2LCSR_BOARD_CONTROL);
+ printf(": Type 2 VMEchip, scon jumper %s\n",
+ (reg & VME2_BOARD_CONTROL_SCON) ? "enabled" : "disabled");
+
+ /*
+ * Figure out what bits of the VMEbus we can access.
+ * First record the `fixed' maps (if they're enabled)
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_IO_CONTROL);
+ if (reg & VME2_IO_CONTROL_I1EN) {
+ /* This range is fixed to A16, DATA */
+ sc->sc_master[0].vr_am = VME_AM_A16 | MVMEBUS_AM_CAP_DATA;
+
+ /* However, SUPER/USER is selectable... */
+ if (reg & VME2_IO_CONTROL_I1SU)
+ sc->sc_master[0].vr_am |= MVMEBUS_AM_CAP_SUPER;
+ else
+ sc->sc_master[0].vr_am |= MVMEBUS_AM_CAP_USER;
+
+ /* As is the datasize */
+ sc->sc_master[0].vr_datasize = VME_D32 | VME_D16 | VME_D8;
+ if (reg & VME2_IO_CONTROL_I1D16)
+ sc->sc_master[0].vr_datasize &= ~VME_D32;
+
+ sc->sc_master[0].vr_locstart = VME2_IO0_LOCAL_START;
+ sc->sc_master[0].vr_mask = VME2_IO0_MASK;
+ sc->sc_master[0].vr_vmestart = VME2_IO0_VME_START;
+ sc->sc_master[0].vr_vmeend = VME2_IO0_VME_END;
+ } else
+ sc->sc_master[0].vr_am = MVMEBUS_AM_DISABLED;
+
+ if (reg & VME2_IO_CONTROL_I2EN) {
+ /* These two ranges are fixed to A24D16 and A32D16 */
+ sc->sc_master[1].vr_am = VME_AM_A24;
+ sc->sc_master[1].vr_datasize = VME_D16 | VME_D8;
+ sc->sc_master[2].vr_am = VME_AM_A32;
+ sc->sc_master[2].vr_datasize = VME_D16 | VME_D8;
+
+ /* However, SUPER/USER is selectable */
+ if (reg & VME2_IO_CONTROL_I2SU) {
+ sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_SUPER;
+ sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_SUPER;
+ } else {
+ sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_USER;
+ sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_USER;
+ }
+
+ /* As is PROGRAM/DATA */
+ if (reg & VME2_IO_CONTROL_I2PD) {
+ sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_PROG;
+ sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_PROG;
+ } else {
+ sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_DATA;
+ sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_DATA;
+ }
+
+ sc->sc_master[1].vr_locstart = VME2_IO1_LOCAL_START;
+ sc->sc_master[1].vr_mask = VME2_IO1_MASK;
+ sc->sc_master[1].vr_vmestart = VME2_IO1_VME_START;
+ sc->sc_master[1].vr_vmeend = VME2_IO1_VME_END;
+
+ sc->sc_master[2].vr_locstart = VME2_IO2_LOCAL_START;
+ sc->sc_master[2].vr_mask = VME2_IO2_MASK;
+ sc->sc_master[2].vr_vmestart = VME2_IO2_VME_START;
+ sc->sc_master[2].vr_vmeend = VME2_IO2_VME_END;
+ } else {
+ sc->sc_master[1].vr_am = MVMEBUS_AM_DISABLED;
+ sc->sc_master[2].vr_am = MVMEBUS_AM_DISABLED;
+ }
+
+ /*
+ * Now read the progammable maps
+ */
+ for (i = 0; i < VME2_MASTER_WINDOWS; i++)
+ vmetwo_master_range(sc, i,
+ &(sc->sc_master[i + VME2_MASTER_PROG_START]));
+
+ /* XXX: No A16 slave yet :XXX */
+ sc->sc_slave[VME2_SLAVE_A16].vr_am = MVMEBUS_AM_DISABLED;
+
+ for (i = 0; i < VME2_SLAVE_WINDOWS; i++) {
+ vmetwo_slave_range(sc, i, VME_AM_A32,
+ &sc->sc_slave[i + VME2_SLAVE_PROG_START]);
+ vmetwo_slave_range(sc, i, VME_AM_A24,
+ &sc->sc_slave[i + VME2_SLAVE_PROG_START + 2]);
+ }
+
+ mvmebus_attach(&sc->sc_mvmebus);
+}
+
+void
+vmetwo_master_range(sc, range, vr)
+ struct vmetwo_softc *sc;
+ int range;
+ struct mvmebus_range *vr;
+{
+ u_int32_t start, end, attr;
+ u_int32_t reg;
+
+ /*
+ * First, check if the range is actually enabled...
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_MASTER_ENABLE);
+ if ((reg & VME2_MASTER_ENABLE(range)) == 0) {
+ vr->vr_am = MVMEBUS_AM_DISABLED;
+ return;
+ }
+
+ /*
+ * Fetch and record the range's attributes
+ */
+ attr = vme2_lcsr_read(sc, VME2LCSR_MASTER_ATTR);
+ attr >>= VME2_MASTER_ATTR_AM_SHIFT(range);
+
+ /*
+ * Fix up the datasizes available through this range
+ */
+ vr->vr_datasize = VME_D32 | VME_D16 | VME_D8;
+ if (attr & VME2_MASTER_ATTR_D16)
+ vr->vr_datasize &= ~VME_D32;
+ attr &= VME2_MASTER_ATTR_AM_MASK;
+
+ vr->vr_am = (attr & VME_AM_ADRSIZEMASK) | MVMEBUS_AM2CAP(attr);
+ switch (vr->vr_am & VME_AM_ADRSIZEMASK) {
+ case VME_AM_A32:
+ default:
+ vr->vr_mask = 0xffffffffu;
+ break;
+
+ case VME_AM_A24:
+ vr->vr_mask = 0x00ffffffu;
+ break;
+
+ case VME_AM_A16:
+ vr->vr_mask = 0x0000ffffu;
+ break;
+ }
+
+ /*
+ * XXX
+ * It would be nice if users of the MI VMEbus code could pass down
+ * whether they can tolerate Write-Posting to their device(s).
+ * XXX
+ */
+
+ /*
+ * Fetch the local-bus start and end addresses for the range
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_MASTER_ADDRESS(range));
+ start = (reg & VME2_MAST_ADDRESS_START_MASK);
+ start <<= VME2_MAST_ADDRESS_START_SHIFT;
+ end = (reg & VME2_MAST_ADDRESS_END_MASK);
+ end <<= VME2_MAST_ADDRESS_END_SHIFT;
+
+ /*
+ * Local->VMEbus map '4' has optional translation bits, so
+ * the VMEbus start and end addresses may need to be adjusted.
+ */
+ if (range == 3 && (reg = vme2_lcsr_read(sc, VME2LCSR_MAST4_TRANS))!=0) {
+ uint32_t addr, sel, len = end - start;
+
+ vr->vr_locstart = start;
+
+ reg = vme2_lcsr_read(sc, VME2LCSR_MAST4_TRANS);
+ reg &= VME2_MAST4_TRANS_SELECT_MASK;
+ sel = reg << VME2_MAST4_TRANS_SELECT_SHIFT;
+
+ reg = vme2_lcsr_read(sc, VME2LCSR_MAST4_TRANS);
+ reg &= VME2_MAST4_TRANS_ADDRESS_MASK;
+ addr = reg << VME2_MAST4_TRANS_ADDRESS_SHIFT;
+
+ start = (addr & sel) | (start & (~sel));
+ end = start + len;
+ vr->vr_mask &= len - 1;
+ } else
+ vr->vr_locstart = 0;
+
+ /* XXX Deal with overlap of onboard RAM address space */
+ /* XXX Then again, 167-Bug warns about this at setup time ... */
+
+ /*
+ * Fixup the addresses this range corresponds to
+ */
+ vr->vr_vmestart = start;
+ vr->vr_vmeend = end - 1;
+}
+
+void
+vmetwo_slave_range(sc, range, am, vr)
+ struct vmetwo_softc *sc;
+ int range;
+ vme_am_t am;
+ struct mvmebus_range *vr;
+{
+ u_int32_t reg;
+
+ /*
+ * First, check if the range is actually enabled.
+ * Note that bit 1 of `range' is used to indicte if we're
+ * looking for an A24 range (set) or an A32 range (clear).
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_CTRL);
+
+ if (am == VME_AM_A32 && (reg & VME2_SLAVE_AMSEL_A32(range))) {
+ vr->vr_am = VME_AM_A32;
+ vr->vr_mask = 0xffffffffu;
+ } else
+ if (am == VME_AM_A24 && (reg & VME2_SLAVE_AMSEL_A24(range))) {
+ vr->vr_am = VME_AM_A24;
+ vr->vr_mask = 0x00ffffffu;
+ } else {
+ /* The range is not enabled */
+ vr->vr_am = MVMEBUS_AM_DISABLED;
+ return;
+ }
+
+ if ((reg & VME2_SLAVE_AMSEL_DAT(range)) != 0)
+ vr->vr_am |= MVMEBUS_AM_CAP_DATA;
+
+ if ((reg & VME2_SLAVE_AMSEL_PGM(range)) != 0)
+ vr->vr_am |= MVMEBUS_AM_CAP_PROG;
+
+ if ((reg & VME2_SLAVE_AMSEL_USR(range)) != 0)
+ vr->vr_am |= MVMEBUS_AM_CAP_USER;
+
+ if ((reg & VME2_SLAVE_AMSEL_SUP(range)) != 0)
+ vr->vr_am |= MVMEBUS_AM_CAP_SUPER;
+
+ if ((reg & VME2_SLAVE_AMSEL_BLK(range)) != 0)
+ vr->vr_am |= MVMEBUS_AM_CAP_BLK;
+
+ if ((reg & VME2_SLAVE_AMSEL_BLKD64(range)) != 0)
+ vr->vr_am |= MVMEBUS_AM_CAP_BLKD64;
+
+ vr->vr_datasize = VME_D32 | VME_D16 | VME_D8;
+
+ /*
+ * Record the VMEbus start and end addresses of the slave image
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_ADDRESS(range));
+ vr->vr_vmestart = reg & VME2_SLAVE_ADDRESS_START_MASK;
+ vr->vr_vmestart <<= VME2_SLAVE_ADDRESS_START_SHIFT;
+ vr->vr_vmestart &= vr->vr_mask;
+ vr->vr_vmeend = reg & VME2_SLAVE_ADDRESS_END_MASK;
+ vr->vr_vmeend <<= VME2_SLAVE_ADDRESS_END_SHIFT;
+ vr->vr_vmeend &= vr->vr_mask;
+ vr->vr_vmeend |= 0xffffu;
+
+ /*
+ * Now figure out the local-bus address
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_CTRL);
+ if ((reg & VME2_SLAVE_CTRL_ADDER(range)) != 0) {
+ reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_TRANS(range));
+ reg &= VME2_SLAVE_TRANS_ADDRESS_MASK;
+ reg <<= VME2_SLAVE_TRANS_ADDRESS_SHIFT;
+ vr->vr_locstart = vr->vr_vmestart + reg;
+ } else {
+ u_int32_t sel, addr;
+
+ reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_TRANS(range));
+ sel = reg & VME2_SLAVE_TRANS_SELECT_MASK;
+ sel <<= VME2_SLAVE_TRANS_SELECT_SHIFT;
+ addr = reg & VME2_SLAVE_TRANS_ADDRESS_MASK;
+ addr <<= VME2_SLAVE_TRANS_ADDRESS_SHIFT;
+
+ vr->vr_locstart = addr & sel;
+ vr->vr_locstart |= vr->vr_vmestart & (~sel);
+ }
+}
diff --git a/sys/dev/mvme/vme_two_isr.c b/sys/dev/mvme/vme_two_isr.c
new file mode 100644
index 00000000000..d065bfabc9e
--- /dev/null
+++ b/sys/dev/mvme/vme_two_isr.c
@@ -0,0 +1,429 @@
+/* $NetBSD: vme_two_isr.c,v 1.1 2002/02/12 20:38:51 scw Exp $ */
+
+/*-
+ * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Split off from vme_two.c specifically to deal with hardware assisted
+ * soft interrupts when the user hasn't specified `vmetwo0' in the
+ * kernel config file (mvme1[67]2 only).
+ */
+
+#include "vmetwo.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <dev/vme/vmereg.h>
+#include <dev/vme/vmevar.h>
+
+#include <dev/mvme/mvmebus.h>
+#include <dev/mvme/vme_tworeg.h>
+#include <dev/mvme/vme_twovar.h>
+
+/*
+ * Non-zero if there is no VMEChip2 on this board.
+ */
+int vmetwo_not_present;
+
+/*
+ * Array of interrupt handlers registered with us for the non-VMEbus
+ * vectored interrupts. Eg. ABORT Switch, SYSFAIL etc.
+ *
+ * We can't just install a caller's handler directly, since these
+ * interrupts have to be manually cleared, so we have a trampoline
+ * which does the clearing automatically.
+ */
+static struct vme_two_handler {
+ int (*isr_hand) __P((void *));
+ void *isr_arg;
+} vme_two_handlers[(VME2_VECTOR_LOCAL_MAX - VME2_VECTOR_LOCAL_MIN) + 1];
+
+#define VMETWO_HANDLERS_SZ (sizeof(vme_two_handlers) / \
+ sizeof(struct vme_two_handler))
+
+static int vmetwo_local_isr_trampoline(void *);
+static void vmetwo_softintr_assert(void);
+
+static struct vmetwo_softc *vmetwo_sc;
+
+int
+vmetwo_probe(bus_space_tag_t bt, bus_addr_t offset)
+{
+ bus_space_handle_t bh;
+
+ bus_space_map(bt, offset + VME2REG_LCSR_OFFSET, VME2LCSR_SIZE, 0, &bh);
+
+ if (bus_space_peek_4(bt, bh, VME2LCSR_MISC_STATUS, NULL) != 0) {
+#if defined(MVME162) || defined(MVME172)
+#if defined(MVME167) || defined(MVME177)
+ if (machineid == MVME_162 || machineid == MVME_172)
+#endif
+ {
+ /*
+ * No VMEChip2 on mvme162/172 is not too big a
+ * deal; we can fall back on timer4 in the
+ * mcchip for h/w assisted soft interrupts...
+ */
+ extern void pcctwosoftintrinit(void);
+ bus_space_unmap(bt, bh, VME2LCSR_SIZE);
+ vmetwo_not_present = 1;
+ pcctwosoftintrinit();
+ return (0);
+ }
+#endif
+#if defined(MVME167) || defined(MVME177) || defined(MVME88K)
+ /*
+ * No VMEChip2 on mvme167/177, however, is a Big Deal.
+ * In fact, it means the hardware's shot since the
+ * VMEChip2 is not a `build-option' on those boards.
+ */
+ panic("VMEChip2 not responding! Faulty board?");
+ /* NOTREACHED */
+#endif
+#if defined(MVMEPPC)
+ /*
+ * No VMEChip2 on mvmeppc is no big deal.
+ */
+ bus_space_unmap(bt, bh, VME2LCSR_SIZE);
+ vmetwo_not_present = 1;
+ return (0);
+#endif
+ }
+#if NVMETWO == 0
+ else {
+ /*
+ * The kernel config file has no `vmetwo0' device, but
+ * there is a VMEChip2 on the board. Fix up things
+ * just enough to hook VMEChip2 local interrupts.
+ */
+ struct vmetwo_softc *sc;
+
+ /* XXX Should check sc != NULL here... */
+ MALLOC(sc, struct vmetwo_softc *, sizeof(*sc), M_DEVBUF,
+ M_NOWAIT);
+
+ sc->sc_mvmebus.sc_bust = bt;
+ sc->sc_lcrh = bh;
+ vmetwo_intr_init(sc);
+ return 0;
+ }
+#else
+ bus_space_unmap(bt, bh, VME2LCSR_SIZE);
+ return (1);
+#endif
+}
+
+void
+vmetwo_intr_init(struct vmetwo_softc *sc)
+{
+ u_int32_t reg;
+ int i;
+
+ vmetwo_sc = sc;
+
+ /* Clear out the ISR handler array */
+ for (i = 0; i < VMETWO_HANDLERS_SZ; i++)
+ vme_two_handlers[i].isr_hand = NULL;
+
+ /*
+ * Initialize the chip.
+ * Firstly, disable all VMEChip2 Interrupts
+ */
+ reg = vme2_lcsr_read(sc, VME2LCSR_MISC_STATUS) & ~VME2_MISC_STATUS_MIEN;
+ vme2_lcsr_write(sc, VME2LCSR_MISC_STATUS, reg);
+ vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, 0);
+ vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
+ VME2_LOCAL_INTERRUPT_CLEAR_ALL);
+
+ /* Zap all the IRQ level registers */
+ for (i = 0; i < VME2_NUM_IL_REGS; i++)
+ vme2_lcsr_write(sc, VME2LCSR_INTERRUPT_LEVEL_BASE + (i * 4), 0);
+
+ /* Disable the tick timers */
+ reg = vme2_lcsr_read(sc, VME2LCSR_TIMER_CONTROL);
+ reg &= ~VME2_TIMER_CONTROL_EN(0);
+ reg &= ~VME2_TIMER_CONTROL_EN(1);
+ vme2_lcsr_write(sc, VME2LCSR_TIMER_CONTROL, reg);
+
+ /* Set the VMEChip2's vector base register to the required value */
+ reg = vme2_lcsr_read(sc, VME2LCSR_VECTOR_BASE);
+ reg &= ~VME2_VECTOR_BASE_MASK;
+ reg |= VME2_VECTOR_BASE_REG_VALUE;
+ vme2_lcsr_write(sc, VME2LCSR_VECTOR_BASE, reg);
+
+ /* Set the Master Interrupt Enable bit now */
+ reg = vme2_lcsr_read(sc, VME2LCSR_MISC_STATUS) | VME2_MISC_STATUS_MIEN;
+ vme2_lcsr_write(sc, VME2LCSR_MISC_STATUS, reg);
+
+#if defined(MVME167) || defined(MVME177)
+#if defined(MVME162) || defined(MVME172)
+ if (machineid != MVME_162 && machineid != MVME_172)
+#endif
+ {
+ /*
+ * Let the NMI handler deal with level 7 ABORT switch
+ * interrupts
+ */
+ vmetwo_intr_establish(sc, 7, 7, VME2_VEC_ABORT, 1,
+ nmihand, NULL, NULL);
+ }
+#endif
+
+ /* Setup hardware assisted soft interrupts */
+ vmetwo_intr_establish(sc, 1, 1, VME2_VEC_SOFT0, 1,
+ (int (*)(void *))softintr_dispatch, NULL, NULL);
+ _softintr_chipset_assert = vmetwo_softintr_assert;
+}
+
+static int
+vmetwo_local_isr_trampoline(arg)
+ void *arg;
+{
+ struct vme_two_handler *isr;
+ int vec;
+
+ vec = (int) arg; /* 0x08 <= vec <= 0x1f */
+
+ /* Clear the interrupt source */
+ vme2_lcsr_write(vmetwo_sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
+ VME2_LOCAL_INTERRUPT(vec));
+
+ isr = &vme_two_handlers[vec - VME2_VECTOR_LOCAL_OFFSET];
+ if (isr->isr_hand)
+ (void) (*isr->isr_hand) (isr->isr_arg);
+ else
+ printf("vmetwo: Spurious local interrupt, vector 0x%x\n", vec);
+
+ return (1);
+}
+
+void
+vmetwo_local_intr_establish(pri, vec, hand, arg, evcnt)
+ int pri, vec;
+ int (*hand)(void *);
+ void *arg;
+ struct evcnt *evcnt;
+{
+
+ vmetwo_intr_establish(vmetwo_sc, pri, pri, vec, 1, hand, arg, evcnt);
+}
+
+/* ARGSUSED */
+void
+vmetwo_intr_establish(csc, prior, lvl, vec, first, hand, arg, evcnt)
+ void *csc;
+ int prior, lvl, vec, first;
+ int (*hand)(void *);
+ void *arg;
+ struct evcnt *evcnt;
+{
+ struct vmetwo_softc *sc = csc;
+ u_int32_t reg;
+ int bitoff;
+ int iloffset, ilshift;
+ int s;
+
+ s = splhigh();
+
+#if NVMETWO > 0
+ /*
+ * Sort out interrupts generated locally by the VMEChip2 from
+ * those generated by VMEbus devices...
+ */
+ if (vec >= VME2_VECTOR_LOCAL_MIN && vec <= VME2_VECTOR_LOCAL_MAX) {
+#endif
+ /*
+ * Local interrupts need to be bounced through some
+ * trampoline code which acknowledges/clears them.
+ */
+ vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_hand = hand;
+ vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_arg = arg;
+ hand = vmetwo_local_isr_trampoline;
+ arg = (void *) (vec - VME2_VECTOR_BASE);
+
+ /*
+ * Interrupt enable/clear bit offset is 0x08 - 0x1f
+ */
+ bitoff = vec - VME2_VECTOR_BASE;
+#if NVMETWO > 0
+ first = 1; /* Force the interrupt to be enabled */
+ } else {
+ /*
+ * Interrupts originating from the VMEbus are
+ * controlled by an offset of 0x00 - 0x07
+ */
+ bitoff = lvl - 1;
+ }
+#endif
+
+ /* Hook the interrupt */
+ (*sc->sc_isrlink)(sc->sc_isrcookie, hand, arg, prior, vec, evcnt);
+
+ /*
+ * Do we need to tell the VMEChip2 to let the interrupt through?
+ * (This is always true for locally-generated interrupts, but only
+ * needs doing once for each VMEbus interrupt level which is hooked)
+ */
+#if NVMETWO > 0
+ if (first) {
+ if (evcnt)
+ evcnt_attach_dynamic(evcnt, EVCNT_TYPE_INTR,
+ (*sc->sc_isrevcnt)(sc->sc_isrcookie, prior),
+ sc->sc_mvmebus.sc_dev.dv_xname,
+ mvmebus_irq_name[lvl]);
+#endif
+ iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
+ VME2LCSR_INTERRUPT_LEVEL_BASE;
+ ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
+
+ /* Program the specified interrupt to signal at 'prior' */
+ reg = vme2_lcsr_read(sc, iloffset);
+ reg &= ~(VME2_INTERRUPT_LEVEL_MASK << ilshift);
+ reg |= (prior << ilshift);
+ vme2_lcsr_write(sc, iloffset, reg);
+
+ /* Clear it */
+ vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
+ VME2_LOCAL_INTERRUPT(bitoff));
+
+ /* Enable it. */
+ reg = vme2_lcsr_read(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE);
+ reg |= VME2_LOCAL_INTERRUPT(bitoff);
+ vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, reg);
+#if NVMETWO > 0
+ }
+#ifdef DIAGNOSTIC
+ else {
+ /* Verify the interrupt priority is the same */
+ iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
+ VME2LCSR_INTERRUPT_LEVEL_BASE;
+ ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
+
+ reg = vme2_lcsr_read(sc, iloffset);
+ reg &= (VME2_INTERRUPT_LEVEL_MASK << ilshift);
+
+ if ((prior << ilshift) != reg)
+ panic("vmetwo_intr_establish: priority mismatch!");
+ }
+#endif
+#endif
+ splx(s);
+}
+
+void
+vmetwo_intr_disestablish(csc, lvl, vec, last, evcnt)
+ void *csc;
+ int lvl, vec, last;
+ struct evcnt *evcnt;
+{
+ struct vmetwo_softc *sc = csc;
+ u_int32_t reg;
+ int iloffset, ilshift;
+ int bitoff;
+ int s;
+
+ s = splhigh();
+
+#if NVMETWO > 0
+ /*
+ * Sort out interrupts generated locally by the VMEChip2 from
+ * those generated by VMEbus devices...
+ */
+ if (vec >= VME2_VECTOR_LOCAL_MIN && vec <= VME2_VECTOR_LOCAL_MAX) {
+#endif
+ /*
+ * Interrupt enable/clear bit offset is 0x08 - 0x1f
+ */
+ bitoff = vec - VME2_VECTOR_BASE;
+ vme_two_handlers[vec - VME2_VECTOR_LOCAL_MIN].isr_hand = NULL;
+ last = 1; /* Force the interrupt to be cleared */
+#if NVMETWO > 0
+ } else {
+ /*
+ * Interrupts originating from the VMEbus are
+ * controlled by an offset of 0x00 - 0x07
+ */
+ bitoff = lvl - 1;
+ }
+#endif
+
+ /*
+ * Do we need to tell the VMEChip2 to block the interrupt?
+ * (This is always true for locally-generated interrupts, but only
+ * needs doing once when the last VMEbus handler for any given level
+ * has been unhooked.)
+ */
+ if (last) {
+ iloffset = VME2_ILOFFSET_FROM_VECTOR(bitoff) +
+ VME2LCSR_INTERRUPT_LEVEL_BASE;
+ ilshift = VME2_ILSHIFT_FROM_VECTOR(bitoff);
+
+ /* Disable it. */
+ reg = vme2_lcsr_read(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE);
+ reg &= ~VME2_LOCAL_INTERRUPT(bitoff);
+ vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_ENABLE, reg);
+
+ /* Set the interrupt's level to zero */
+ reg = vme2_lcsr_read(sc, iloffset);
+ reg &= ~(VME2_INTERRUPT_LEVEL_MASK << ilshift);
+ vme2_lcsr_write(sc, iloffset, reg);
+
+ /* Clear it */
+ vme2_lcsr_write(sc, VME2LCSR_LOCAL_INTERRUPT_CLEAR,
+ VME2_LOCAL_INTERRUPT(vec));
+
+ if (evcnt)
+ evcnt_detach(evcnt);
+ }
+ /* Un-hook it */
+ (*sc->sc_isrunlink)(sc->sc_isrcookie, vec);
+
+ splx(s);
+}
+
+static void
+vmetwo_softintr_assert(void)
+{
+
+ vme2_lcsr_write(vmetwo_sc, VME2LCSR_SOFTINT_SET, VME2_SOFTINT_SET(0));
+}
diff --git a/sys/dev/mvme/vme_tworeg.h b/sys/dev/mvme/vme_tworeg.h
new file mode 100644
index 00000000000..80d8609a28a
--- /dev/null
+++ b/sys/dev/mvme/vme_tworeg.h
@@ -0,0 +1,526 @@
+/* $NetBSD: vme_tworeg.h,v 1.1 2002/02/12 20:38:51 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _MVME_VME_TWOREG_H
+#define _MVME_VME_TWOREG_H
+
+/*
+ * Where the VMEchip2's registers live relative to the start
+ * of the VMEChip2's register space.
+ */
+#define VME2REG_LCSR_OFFSET 0x0000
+#define VME2REG_GCSR_OFFSET 0x0100
+
+
+/*
+ * Register map of the Type 2 VMEchip found on many MVME boards.
+ * Note: Only responds to D32 accesses.
+ */
+
+ /*
+ * Slave window configuration registers
+ */
+#define VME2_SLAVE_WINDOWS 2
+#define VME2LCSR_SLAVE_ADDRESS(x) (0x00 + ((x) * 4))
+#define VME2_SLAVE_ADDRESS_START_SHIFT 16
+#define VME2_SLAVE_ADDRESS_START_MASK (0x0000ffffu)
+#define VME2_SLAVE_ADDRESS_END_SHIFT 0
+#define VME2_SLAVE_ADDRESS_END_MASK (0xffff0000u)
+
+#define VME2LCSR_SLAVE_TRANS(x) (0x08 + ((x) * 4))
+#define VME2_SLAVE_TRANS_SELECT_SHIFT 16
+#define VME2_SLAVE_TRANS_SELECT_MASK (0x0000ffffu)
+#define VME2_SLAVE_TRANS_ADDRESS_SHIFT 0
+#define VME2_SLAVE_TRANS_ADDRESS_MASK (0xffff0000u)
+
+#define VME2LCSR_SLAVE_CTRL 0x10
+#define VME2_SLAVE_AMSEL_DAT(x) (1u << (0 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_PGM(x) (1u << (1 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_BLK(x) (1u << (2 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_BLKD64(x) (1u << (3 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_A24(x) (1u << (4 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_A32(x) (1u << (5 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_USR(x) (1u << (6 + ((x) * 16)))
+#define VME2_SLAVE_AMSEL_SUP(x) (1u << (7 + ((x) * 16)))
+#define VME2_SLAVE_CTRL_WP(x) (1u << (8 + ((x) * 16)))
+#define VME2_SLAVE_CTRL_SNOOP_INHIBIT(x) (0u << (9 + ((x) * 16)))
+#define VME2_SLAVE_CTRL_SNOOP_WRSINK(x) (1u << (9 + ((x) * 16)))
+#define VME2_SLAVE_CTRL_SNOOP_WRINVAL(x) (2u << (9 + ((x) * 16)))
+#define VME2_SLAVE_CTRL_ADDER(x) (1u << (11 + ((x) * 16)))
+
+ /*
+ * Master window address control registers
+ */
+#define VME2_MASTER_WINDOWS 4
+#define VME2LCSR_MASTER_ADDRESS(x) (0x14 + ((x) * 4))
+#define VME2_MAST_ADDRESS_START_SHIFT 16
+#define VME2_MAST_ADDRESS_START_MASK (0x0000ffffu)
+#define VME2_MAST_ADDRESS_END_SHIFT 0
+#define VME2_MAST_ADDRESS_END_MASK (0xffff0000u)
+
+#define VME2LCSR_MAST4_TRANS 0x24
+#define VME2_MAST4_TRANS_SELECT_SHIFT 16
+#define VME2_MAST4_TRANS_SELECT_MASK (0x0000ffffu)
+#define VME2_MAST4_TRANS_ADDRESS_SHIFT 0
+#define VME2_MAST4_TRANS_ADDRESS_MASK (0xffff0000u)
+
+ /*
+ * VMEbus master attribute control register
+ */
+#define VME2LCSR_MASTER_ATTR 0x28
+#define VME2_MASTER_ATTR_AM_SHIFT(x) ((x) * 8)
+#define VME2_MASTER_ATTR_AM_MASK (0x0000003fu)
+#define VME2_MASTER_ATTR_WP (1u << 6)
+#define VME2_MASTER_ATTR_D16 (1u << 7)
+
+ /*
+ * GCSR Group/Board addresses, and
+ * VMEbus Master Enable Control register, and
+ * Local to VMEbus I/O Control register, and
+ * ROM Control register (unused).
+ */
+#define VME2LCSR_GCSR_ADDRESS 0x2c
+#define VME2_GCSR_ADDRESS_SHIFT 16
+#define VME2_GCSR_ADDRESS_MASK (0xfff00000u)
+
+#define VME2LCSR_MASTER_ENABLE 0x2c
+#define VME2_MASTER_ENABLE_MASK (0x000f0000u)
+#define VME2_MASTER_ENABLE(x) (1u << ((x) + 16))
+
+#define VME2LCSR_IO_CONTROL 0x2c
+#define VME2_IO_CONTROL_SHIFT 8
+#define VME2_IO_CONTROL_MASK (0x0000ff00u)
+#define VME2_IO_CONTROL_I1SU (1u << 8)
+#define VME2_IO_CONTROL_I1WP (1u << 9)
+#define VME2_IO_CONTROL_I1D16 (1u << 10)
+#define VME2_IO_CONTROL_I1EN (1u << 11)
+#define VME2_IO_CONTROL_I2PD (1u << 12)
+#define VME2_IO_CONTROL_I2SU (1u << 13)
+#define VME2_IO_CONTROL_I2WP (1u << 14)
+#define VME2_IO_CONTROL_I2EN (1u << 15)
+
+ /*
+ * VMEChip2 PROM Decoder, SRAM and DMA Control register
+ */
+#define VME2LCSR_PROM_SRAM_DMA_CTRL 0x30
+#define VME2_PSD_SRAMS_MASK (0x00ff0000u)
+#define VME2_PSD_SRAMS_CLKS6 (0u << 16)
+#define VME2_PSD_SRAMS_CLKS5 (1u << 16)
+#define VME2_PSD_SRAMS_CLKS4 (2u << 16)
+#define VME2_PSD_SRAMS_CLKS3 (3u << 16)
+#define VME2_PSD_TBLSC_INHIB (0u << 18)
+#define VME2_PSD_TBLSC_WRSINK (1u << 18)
+#define VME2_PSD_TBLSC_WRINV (2u << 18)
+#define VME2_PSD_ROM0 (1u << 20)
+#define VME2_PSD_WAITRMW (1u << 21)
+
+ /*
+ * VMEbus requester control register
+ */
+#define VME2LCSR_VME_REQUESTER_CONTROL 0x30
+#define VME2_VMEREQ_CTRL_MASK (0x0000ff00u)
+#define VME2_VMEREQ_CTRL_LVREQL_MASK (0x00000300u)
+#define VME2_VMEREQ_CTRL_LVREQL(x) ((u_int)(x) << 8)
+#define VME2_VMEREQ_CTRL_LVRWD (1u << 10)
+#define VME2_VMEREQ_CTRL_LVFAIR (1u << 11)
+#define VME2_VMEREQ_CTRL_DWB (1u << 13)
+#define VME2_VMEREQ_CTRL_DHB (1u << 14)
+#define VME2_VMEREQ_CTRL_ROBN (1u << 15)
+
+ /*
+ * DMAC control register
+ */
+#define VME2LCSR_DMAC_CONTROL1 0x30
+#define VME2_DMAC_CTRL1_MASK (0x000000ffu)
+#define VME2_DMAC_CTRL1_DREQL_MASK (0x00000003u)
+#define VME2_DMAC_CTRL1_DREQL(x) ((u_int)(x) << 0)
+#define VME2_DMAC_CTRL1_DRELM_MASK (0x0000000cu)
+#define VME2_DMAC_CTRL1_DRELM(x) ((u_int)(x) << 2)
+#define VME2_DMAC_CTRL1_DFAIR (1u << 4)
+#define VME2_DMAC_CTRL1_DTBL (1u << 5)
+#define VME2_DMAC_CTRL1_DEN (1u << 6)
+#define VME2_DMAC_CTRL1_DHALT (1u << 7)
+
+ /*
+ * DMA Control register #2
+ */
+#define VME2LCSR_DMAC_CONTROL2 0x34
+#define VME2_DMAC_CTRL2_MASK (0x0000ffffu)
+#define VME2_DMAC_CTRL2_SHIFT 0
+#define VME2_DMAC_CTRL2_AM_MASK (0x0000003fu)
+#define VME2_DMAC_CTRL2_BLK_D32 (1u << 6)
+#define VME2_DMAC_CTRL2_BLK_D64 (3u << 6)
+#define VME2_DMAC_CTRL2_D16 (1u << 8)
+#define VME2_DMAC_CTRL2_TVME (1u << 9)
+#define VME2_DMAC_CTRL2_LINC (1u << 10)
+#define VME2_DMAC_CTRL2_VINC (1u << 11)
+#define VME2_DMAC_CTRL2_SNOOP_INHIB (0u << 13)
+#define VME2_DMAC_CTRL2_SNOOP_WRSNK (1u << 13)
+#define VME2_DMAC_CTRL2_SNOOP_WRINV (2u << 13)
+#define VME2_DMAC_CTRL2_INTE (1u << 15)
+
+ /*
+ * DMA Controller Local Bus and VMEbus Addresses, Byte
+ * Counter and Table Address Counter registers
+ */
+#define VME2LCSR_DMAC_LOCAL_ADDRESS 0x38
+#define VME2LCSR_DMAC_VME_ADDRESS 0x3c
+#define VME2LCSR_DMAC_BYTE_COUNTER 0x40
+#define VME2LCSR_DMAC_TABLE_ADDRESS 0x44
+
+ /*
+ * VMEbus Interrupter Control register
+ */
+#define VME2LCSR_INTERRUPT_CONTROL 0x48
+#define VME2_INT_CTRL_MASK (0xff000000u)
+#define VME2_INT_CTRL_SHIFT 24
+#define VME2_INT_CTRL_IRQL_MASK (0x07000000u)
+#define VME2_INT_CTRL_IRQS (1u << 27)
+#define VME2_INT_CTRL_IRQC (1u << 28)
+#define VME2_INT_CTRL_IRQ1S_INT (0u << 29)
+#define VME2_INT_CTRL_IRQ1S_TICK1 (1u << 29)
+#define VME2_INT_CTRL_IRQ1S_TICK2 (3u << 29)
+
+ /*
+ * VMEbus Interrupt Vector register
+ */
+#define VME2LCSR_INTERRUPT_VECTOR 0x48
+#define VME2_INTERRUPT_VECTOR_MASK (0x00ff0000u)
+#define VME2_INTERRUPT_VECTOR_SHIFT 16
+
+ /*
+ * MPU Status register
+ */
+#define VME2LCSR_MPU_STATUS 0x48
+#define VME2_MPU_STATUS_MLOB (1u << 0)
+#define VME2_MPU_STATUS_MLPE (1u << 1)
+#define VME2_MPU_STATUS_MLBE (1u << 2)
+#define VME2_MPU_STATUS_MCLR (1u << 3)
+
+ /*
+ * DMA Interrupt Count register
+ */
+#define VME2LCSR_DMAC_INTERRUPT_CONTROL 0x48
+#define VME2_DMAC_INT_COUNT_MASK (0x0000f000u)
+#define VME2_DMAC_INT_COUNT_SHIFT 12
+
+ /*
+ * DMA Controller Status register
+ */
+#define VME2LCSR_DMAC_STATUS 0x48
+#define VME2_DMAC_STATUS_DONE (1u << 0)
+#define VME2_DMAC_STATUS_VME (1u << 1)
+#define VME2_DMAC_STATUS_TBL (1u << 2)
+#define VME2_DMAC_STATUS_DLTO (1u << 3)
+#define VME2_DMAC_STATUS_DLOB (1u << 4)
+#define VME2_DMAC_STATUS_DLPE (1u << 5)
+#define VME2_DMAC_STATUS_DLBE (1u << 6)
+#define VME2_DMAC_STATUS_MLTO (1u << 7)
+
+
+ /*
+ * VMEbus Arbiter Time-out register
+ */
+#define VME2LCSR_VME_ARB_TIMEOUT 0x4c
+#define VME2_VME_ARB_TIMEOUT_ENAB (1u << 24)
+
+ /*
+ * DMA Controller Timers and VMEbus Global Time-out Control registers
+ */
+#define VME2LCSR_DMAC_TIME_ONOFF 0x4c
+#define VME2_DMAC_TIME_ON_MASK (0x001c0000u)
+#define VME2_DMAC_TIME_ON_16US (0u << 18)
+#define VME2_DMAC_TIME_ON_32US (1u << 18)
+#define VME2_DMAC_TIME_ON_64US (2u << 18)
+#define VME2_DMAC_TIME_ON_128US (3u << 18)
+#define VME2_DMAC_TIME_ON_256US (4u << 18)
+#define VME2_DMAC_TIME_ON_512US (5u << 18)
+#define VME2_DMAC_TIME_ON_1024US (6u << 18)
+#define VME2_DMAC_TIME_ON_DONE (7u << 18)
+#define VME2_DMAC_TIME_OFF_MASK (0x00e00000u)
+#define VME2_DMAC_TIME_OFF_0US (0u << 21)
+#define VME2_DMAC_TIME_OFF_16US (1u << 21)
+#define VME2_DMAC_TIME_OFF_32US (2u << 21)
+#define VME2_DMAC_TIME_OFF_64US (3u << 21)
+#define VME2_DMAC_TIME_OFF_128US (4u << 21)
+#define VME2_DMAC_TIME_OFF_256US (5u << 21)
+#define VME2_DMAC_TIME_OFF_512US (6u << 21)
+#define VME2_DMAC_TIME_OFF_1024US (7u << 21)
+#define VME2_VME_GLOBAL_TO_MASK (0x00030000u)
+#define VME2_VME_GLOBAL_TO_8US (0u << 16)
+#define VME2_VME_GLOBAL_TO_16US (1u << 16)
+#define VME2_VME_GLOBAL_TO_256US (2u << 16)
+#define VME2_VME_GLOBAL_TO_DISABLE (3u << 16)
+
+ /*
+ * VME Access, Local Bus and Watchdog Time-out Control register
+ */
+#define VME2LCSR_VME_ACCESS_TIMEOUT 0x4c
+#define VME2_VME_ACCESS_TIMEOUT_MASK (0x0000c000u)
+#define VME2_VME_ACCESS_TIMEOUT_64US (0u << 14)
+#define VME2_VME_ACCESS_TIMEOUT_1MS (1u << 14)
+#define VME2_VME_ACCESS_TIMEOUT_32MS (2u << 14)
+#define VME2_VME_ACCESS_TIMEOUT_DISABLE (3u << 14)
+
+#define VME2LCSR_LOCAL_BUS_TIMEOUT 0x4c
+#define VME2_LOCAL_BUS_TIMEOUT_MASK (0x00003000u)
+#define VME2_LOCAL_BUS_TIMEOUT_64US (0u << 12)
+#define VME2_LOCAL_BUS_TIMEOUT_1MS (1u << 12)
+#define VME2_LOCAL_BUS_TIMEOUT_32MS (2u << 12)
+#define VME2_LOCAL_BUS_TIMEOUT_DISABLE (3u << 12)
+
+#define VME2LCSR_WATCHDOG_TIMEOUT 0x4c
+#define VME2_WATCHDOG_TIMEOUT_MASK (0x00000f00u)
+#define VME2_WATCHDOG_TIMEOUT_512US (0u << 8)
+#define VME2_WATCHDOG_TIMEOUT_1MS (1u << 8)
+#define VME2_WATCHDOG_TIMEOUT_2MS (2u << 8)
+#define VME2_WATCHDOG_TIMEOUT_4MS (3u << 8)
+#define VME2_WATCHDOG_TIMEOUT_8MS (4u << 8)
+#define VME2_WATCHDOG_TIMEOUT_16MS (5u << 8)
+#define VME2_WATCHDOG_TIMEOUT_32MS (6u << 8)
+#define VME2_WATCHDOG_TIMEOUT_64MS (7u << 8)
+#define VME2_WATCHDOG_TIMEOUT_128MS (8u << 8)
+#define VME2_WATCHDOG_TIMEOUT_256MS (9u << 8)
+#define VME2_WATCHDOG_TIMEOUT_512MS (10u << 8)
+#define VME2_WATCHDOG_TIMEOUT_1S (11u << 8)
+#define VME2_WATCHDOG_TIMEOUT_4S (12u << 8)
+#define VME2_WATCHDOG_TIMEOUT_16S (13u << 8)
+#define VME2_WATCHDOG_TIMEOUT_32S (14u << 8)
+#define VME2_WATCHDOG_TIMEOUT_64S (15u << 8)
+
+ /*
+ * Prescaler Control register
+ */
+#define VME2LCSR_PRESCALER_CONTROL 0x4c
+#define VME2_PRESCALER_MASK (0x000000ffu)
+#define VME2_PRESCALER_SHIFT 0
+#define VME2_PRESCALER_CTRL(c) (256 - (c))
+
+ /*
+ * Tick Timer registers
+ */
+#define VME2LCSR_TIMER_COMPARE(x) (0x50 + ((x) * 8))
+#define VME2LCSR_TIMER_COUNTER(x) (0x54 + ((x) * 8))
+
+
+ /*
+ * Board Control register
+ */
+#define VME2LCSR_BOARD_CONTROL 0x60
+#define VME2_BOARD_CONTROL_RSWE (1u << 24)
+#define VME2_BOARD_CONTROL_BDFLO (1u << 25)
+#define VME2_BOARD_CONTROL_CPURS (1u << 26)
+#define VME2_BOARD_CONTROL_PURS (1u << 27)
+#define VME2_BOARD_CONTROL_BRFLI (1u << 28)
+#define VME2_BOARD_CONTROL_SFFL (1u << 29)
+#define VME2_BOARD_CONTROL_SCON (1u << 30)
+
+ /*
+ * Watchdog Timer Control register
+ */
+#define VME2LCSR_WATCHDOG_TIMER_CONTROL 0x60
+#define VME2_WATCHDOG_TCONTROL_WDEN (1u << 16)
+#define VME2_WATCHDOG_TCONTTRL_WDRSE (1u << 17)
+#define VME2_WATCHDOG_TCONTTRL_WDSL (1u << 18)
+#define VME2_WATCHDOG_TCONTTRL_WDBFE (1u << 19)
+#define VME2_WATCHDOG_TCONTTRL_WDTO (1u << 20)
+#define VME2_WATCHDOG_TCONTTRL_WDCC (1u << 21)
+#define VME2_WATCHDOG_TCONTTRL_WDCS (1u << 22)
+#define VME2_WATCHDOG_TCONTTRL_SRST (1u << 23)
+
+ /*
+ * Tick Timer Control registers
+ */
+#define VME2LCSR_TIMER_CONTROL 0x60
+#define VME2_TIMER_CONTROL_EN(x) (1u << (0 + ((x) * 8)))
+#define VME2_TIMER_CONTROL_COC(x) (1u << (1 + ((x) * 8)))
+#define VME2_TIMER_CONTROL_COF(x) (1u << (2 + ((x) * 8)))
+#define VME2_TIMER_CONTROL_OVF_SHIFT(x) (4 + ((x) * 8))
+#define VME2_TIMER_CONTROL_OVF_MASK(x) (0x000000f0u << (4 + ((x) * 8)))
+
+ /*
+ * Prescaler Counter register
+ */
+#define VME2LCSR_PRESCALER_COUNTER 0x64
+
+ /*
+ * Local Bus Interrupter Status/Enable/Clear registers
+ */
+#define VME2LCSR_LOCAL_INTERRUPT_STATUS 0x68
+#define VME2LCSR_LOCAL_INTERRUPT_ENABLE 0x6c
+#define VME2LCSR_LOCAL_INTERRUPT_CLEAR 0x74
+#define VME2_LOCAL_INTERRUPT(x) (1u << (x))
+#define VME2_LOCAL_INTERRUPT_VME(x) (1u << ((x) - 1))
+#define VME2_LOCAL_INTERRUPT_SWINT(x) (1u << ((x) + 8))
+#define VME2_LOCAL_INTERRUPT_LM(x) (1u << ((x) + 16))
+#define VME2_LOCAL_INTERRUPT_SIG(x) (1u << ((x) + 18))
+#define VME2_LOCAL_INTERRUPT_DMAC (1u << 22)
+#define VME2_LOCAL_INTERRUPT_VIA (1u << 23)
+#define VME2_LOCAL_INTERRUPT_TIC(x) (1u << ((x) + 24))
+#define VME2_LOCAL_INTERRUPT_VI1E (1u << 26)
+#define VME2_LOCAL_INTERRUPT_PE (1u << 27)
+#define VME2_LOCAL_INTERRUPT_MWP (1u << 28)
+#define VME2_LOCAL_INTERRUPT_SYSF (1u << 29)
+#define VME2_LOCAL_INTERRUPT_ABORT (1u << 30)
+#define VME2_LOCAL_INTERRUPT_ACFAIL (1u << 31)
+#define VME2_LOCAL_INTERRUPT_CLEAR_ALL (0xffffff00u)
+
+ /*
+ * Software Interrupt Set register
+ */
+#define VME2LCSR_SOFTINT_SET 0x70
+#define VME2_SOFTINT_SET(x) (1u << ((x) + 8))
+
+ /*
+ * Interrupt Level registers
+ */
+#define VME2LCSR_INTERRUPT_LEVEL_BASE 0x78
+#define VME2_NUM_IL_REGS 4
+#define VME2_ILOFFSET_FROM_VECTOR(v) (((((VME2_NUM_IL_REGS*8)-1)-(v))/8)<<2)
+#define VME2_ILSHIFT_FROM_VECTOR(v) (((v) & 7) * 4)
+#define VME2_INTERRUPT_LEVEL_MASK (0x0fu)
+
+ /*
+ * Vector Base register
+ */
+#define VME2LCSR_VECTOR_BASE 0x88
+#define VME2_VECTOR_BASE_MASK (0xff000000u)
+#define VME2_VECTOR_BASE_REG_VALUE (0x76000000u)
+#define VME2_VECTOR_BASE (0x60u)
+#define VME2_VECTOR_LOCAL_OFFSET (0x08u)
+#define VME2_VECTOR_LOCAL_MIN (VME2_VECTOR_BASE + 0x08u)
+#define VME2_VECTOR_LOCAL_MAX (VME2_VECTOR_BASE + 0x1fu)
+#define VME2_VEC_SOFT0 (VME2_VECTOR_BASE + 0x08u)
+#define VME2_VEC_SOFT1 (VME2_VECTOR_BASE + 0x09u)
+#define VME2_VEC_SOFT2 (VME2_VECTOR_BASE + 0x0au)
+#define VME2_VEC_SOFT3 (VME2_VECTOR_BASE + 0x0bu)
+#define VME2_VEC_SOFT4 (VME2_VECTOR_BASE + 0x0cu)
+#define VME2_VEC_SOFT5 (VME2_VECTOR_BASE + 0x0du)
+#define VME2_VEC_SOFT6 (VME2_VECTOR_BASE + 0x0eu)
+#define VME2_VEC_SOFT7 (VME2_VECTOR_BASE + 0x0fu)
+#define VME2_VEC_GCSRLM0 (VME2_VECTOR_BASE + 0x10u)
+#define VME2_VEC_GCSRLM1 (VME2_VECTOR_BASE + 0x11u)
+#define VME2_VEC_GCSRSIG0 (VME2_VECTOR_BASE + 0x12u)
+#define VME2_VEC_GCSRSIG1 (VME2_VECTOR_BASE + 0x13u)
+#define VME2_VEC_GCSRSIG2 (VME2_VECTOR_BASE + 0x14u)
+#define VME2_VEC_GCSRSIG3 (VME2_VECTOR_BASE + 0x15u)
+#define VME2_VEC_DMAC (VME2_VECTOR_BASE + 0x16u)
+#define VME2_VEC_VIA (VME2_VECTOR_BASE + 0x17u)
+#define VME2_VEC_TT1 (VME2_VECTOR_BASE + 0x18u)
+#define VME2_VEC_TT2 (VME2_VECTOR_BASE + 0x19u)
+#define VME2_VEC_IRQ1 (VME2_VECTOR_BASE + 0x1au)
+#define VME2_VEC_PARITY_ERROR (VME2_VECTOR_BASE + 0x1bu)
+#define VME2_VEC_MWP_ERROR (VME2_VECTOR_BASE + 0x1cu)
+#define VME2_VEC_SYSFAIL (VME2_VECTOR_BASE + 0x1du)
+#define VME2_VEC_ABORT (VME2_VECTOR_BASE + 0x1eu)
+#define VME2_VEC_ACFAIL (VME2_VECTOR_BASE + 0x1fu)
+
+ /*
+ * I/O Control register #1
+ */
+#define VME2LCSR_GPIO_DIRECTION 0x88
+#define VME2_GPIO_DIRECTION_OUT(x) (1u << ((x) + 16))
+
+ /*
+ * Misc. Status register
+ */
+#define VME2LCSR_MISC_STATUS 0x88
+#define VME2_MISC_STATUS_ABRTL (1u << 20)
+#define VME2_MISC_STATUS_ACFL (1u << 21)
+#define VME2_MISC_STATUS_SYSFL (1u << 22)
+#define VME2_MISC_STATUS_MIEN (1u << 23)
+
+ /*
+ * GPIO Status register
+ */
+#define VME2LCSR_GPIO_STATUS 0x88
+#define VME2_GPIO_STATUS(x) (1u << ((x) + 8))
+
+ /*
+ * GPIO Control register #2
+ */
+#define VME2LCSR_GPIO_CONTROL 0x88
+#define VME2_GPIO_CONTROL_SET(x) (1u << ((x) + 12))
+
+ /*
+ * General purpose input registers
+ */
+#define VME2LCSR_GP_INPUTS 0x88
+#define VME2_GP_INPUT(x) (1u << (x))
+
+ /*
+ * Miscellaneous Control register
+ */
+#define VME2LCSR_MISC_CONTROL 0x8c
+#define VME2_MISC_CONTROL_DISBGN (1u << 0)
+#define VME2_MISC_CONTROL_ENINT (1u << 1)
+#define VME2_MISC_CONTROL_DISBSYT (1u << 2)
+#define VME2_MISC_CONTROL_NOELBBSY (1u << 3)
+#define VME2_MISC_CONTROL_DISMST (1u << 4)
+#define VME2_MISC_CONTROL_DISSRAM (1u << 5)
+#define VME2_MISC_CONTROL_REVEROM (1u << 6)
+#define VME2_MISC_CONTROL_MPIRQEN (1u << 7)
+
+#define VME2LCSR_SIZE 0x90
+
+
+#define vme2_lcsr_read(s,r) \
+ bus_space_read_4((s)->sc_mvmebus.sc_bust, (s)->sc_lcrh, (r))
+#define vme2_lcsr_write(s,r,v) \
+ bus_space_write_4((s)->sc_mvmebus.sc_bust, (s)->sc_lcrh, (r), (v))
+
+
+/*
+ * Locations of the three fixed VMEbus I/O ranges
+ */
+#define VME2_IO0_LOCAL_START (0xffff0000u)
+#define VME2_IO0_MASK (0x0000ffffu)
+#define VME2_IO0_VME_START (0x00000000u)
+#define VME2_IO0_VME_END (0x0000ffffu)
+
+#define VME2_IO1_LOCAL_START (0xf0000000u)
+#define VME2_IO1_MASK (0x00ffffffu)
+#define VME2_IO1_VME_START (0x00000000u)
+#define VME2_IO1_VME_END (0x00ffffffu)
+
+#define VME2_IO2_LOCAL_START (0x00000000u)
+#define VME2_IO2_MASK (0xffffffffu)
+#define VME2_IO2_VME_START (0xf1000000u) /* Maybe starts@ 0x0? */
+#define VME2_IO2_VME_END (0xff7fffffu)
+
+#endif /* _MVME_VME_TWOREG_H */
diff --git a/sys/dev/mvme/vme_twovar.h b/sys/dev/mvme/vme_twovar.h
new file mode 100644
index 00000000000..10b3e50cb1e
--- /dev/null
+++ b/sys/dev/mvme/vme_twovar.h
@@ -0,0 +1,79 @@
+/* $NetBSD: vme_twovar.h,v 1.1 2002/02/12 20:38:52 scw Exp $ */
+
+/*-
+ * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Steve C. Woodford.
+ *
+ * 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 NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _MVME_VME_TWOVAR_H
+#define _MVME_VME_TWOVAR_H
+
+#define VME2_MASTER_FIXED_A16 0
+#define VME2_MASTER_FIXED_A24 1
+#define VME2_MASTER_FIXED_A32 2
+#define VME2_MASTER_PROG_START 3
+#define VME2_SLAVE_OFFBOARD_RAM 0
+#define VME2_SLAVE_PROG_START 1
+#define VME2_SLAVE_A16 (VME2_SLAVE_PROG_START+(VME2_SLAVE_WINDOWS*2))
+
+#define VME2_NMASTERS (VME2_MASTER_PROG_START + VME2_MASTER_WINDOWS)
+#define VME2_NSLAVES (VME2_SLAVE_A16 + 1)
+
+struct vmetwo_softc {
+ struct mvmebus_softc sc_mvmebus;
+ bus_space_handle_t sc_lcrh;
+ bus_space_handle_t sc_gcrh;
+ void *sc_isrcookie;
+ void (*sc_isrlink)(void *, int (*)(void *),
+ void *, int, int, struct evcnt *);
+ void (*sc_isrunlink)(void *, int);
+ struct evcnt * (*sc_isrevcnt)(void *, int);
+#if NVMETWO > 0
+ struct mvmebus_range sc_master[VME2_NMASTERS];
+ struct mvmebus_range sc_slave[VME2_NSLAVES];
+#endif
+};
+
+extern int vmetwo_not_present;
+
+void vmetwo_init(struct vmetwo_softc *);
+int vmetwo_probe(bus_space_tag_t, bus_addr_t);
+void vmetwo_intr_init(struct vmetwo_softc *);
+void vmetwo_intr_establish(void *, int, int, int, int,
+ int (*)(void *), void *, struct evcnt *);
+void vmetwo_intr_disestablish(void *, int, int, int, struct evcnt *);
+void vmetwo_local_intr_establish(int, int,
+ int (*)(void *), void *, struct evcnt *);
+
+#endif /* _MVME_VME_TWOVAR_H */