summaryrefslogtreecommitdiff
path: root/sys/arch/mvme88k/dev
diff options
context:
space:
mode:
authorDale S. Rahn <rahnds@cvs.openbsd.org>1997-03-03 20:23:07 +0000
committerDale S. Rahn <rahnds@cvs.openbsd.org>1997-03-03 20:23:07 +0000
commitb810033e0fa5b5b7163cee7059c523aaf907c6a5 (patch)
treefcde3ace3c188a7d797a313c9173a233532d44ca /sys/arch/mvme88k/dev
parent90ff5a441368313fa226376473fea6908c2c3539 (diff)
Cleanup after import. This also seems to bring up the current version.
Diffstat (limited to 'sys/arch/mvme88k/dev')
-rw-r--r--sys/arch/mvme88k/dev/bugtty.c502
-rw-r--r--sys/arch/mvme88k/dev/clock.c371
-rw-r--r--sys/arch/mvme88k/dev/pcc2.c253
-rw-r--r--sys/arch/mvme88k/dev/pcctwo.c210
4 files changed, 1336 insertions, 0 deletions
diff --git a/sys/arch/mvme88k/dev/bugtty.c b/sys/arch/mvme88k/dev/bugtty.c
new file mode 100644
index 00000000000..0eeafd308c7
--- /dev/null
+++ b/sys/arch/mvme88k/dev/bugtty.c
@@ -0,0 +1,502 @@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1995 Dale Rahn.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Dale Rahn.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+#include <dev/cons.h>
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+#include "bugtty.h"
+
+int bugttymatch __P((struct device *parent, void *self, void *aux));
+void bugttyattach __P((struct device *parent, struct device *self, void *aux));
+
+struct cfattach bugtty_ca = {
+ sizeof(struct device), bugttymatch, bugttyattach
+};
+
+struct cfdriver bugtty_cd = {
+ NULL, "bugtty", DV_TTY, 0
+};
+
+/* prototypes */
+int bugttycnprobe __P((struct consdev *cp));
+int bugttycninit __P((struct consdev *cp));
+int bugttycngetc __P((dev_t dev));
+int bugttycnputc __P((dev_t dev, char c));
+
+int bugttyopen __P((dev_t dev, int flag, int mode, struct proc *p));
+int bugttyclose __P((dev_t dev, int flag, int mode, struct proc *p));
+int bugttyread __P((dev_t dev, struct uio *uio, int flag));
+int bugttywrite __P((dev_t dev, struct uio *uio, int flag));
+int bugttyioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p));
+int bugttystop __P((struct tty *tp, int flag));
+
+#define DIALOUT(x) ((x) & 0x80)
+#define SWFLAGS(dev) (bugttyswflags | (DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0))
+
+#define BUGBUF 80
+char bugtty_ibuffer[BUGBUF+1];
+volatile char *pinchar = bugtty_ibuffer;
+char bug_obuffer[BUGBUF+1];
+
+#define bugtty_tty bugttytty
+struct tty *bugtty_tty[NBUGTTY];
+int needprom = 1;
+
+int
+bugttymatch(parent, self, aux)
+ struct device *parent;
+ void *self;
+ void *aux;
+{
+ extern int needprom;
+ struct confargs *ca = aux;
+
+ if (needprom == 0)
+ return (0);
+ /*
+ * tell our parent our requirements
+ */
+ ca->ca_paddr = (caddr_t)0xfff45000;
+ ca->ca_size = 0x200;
+ ca->ca_ipl = IPL_TTY;
+ return (1);
+}
+
+void
+bugttyattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ printf("\n");
+}
+
+#define BUGTTYUNIT(x) ((x) & (0x7f))
+void bugttyoutput __P((struct tty *tp));
+
+int bugttydefaultrate = TTYDEF_SPEED;
+int bugttyswflags;
+
+int
+bugttymctl(dev, bits, how)
+ dev_t dev;
+ int bits, how;
+{
+ static int settings = TIOCM_DTR | TIOCM_RTS |
+ TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
+ int s;
+
+ /*printf("mctl: dev %x, bits %x, how %x,",dev, bits, how);*/
+
+ /* settings are currently ignored */
+ s = spltty();
+ switch (how) {
+ case DMSET:
+ break;
+ case DMBIC:
+ break;
+ case DMBIS:
+ break;
+ case DMGET:
+ break;
+ }
+ (void)splx(s);
+
+ bits = 0;
+ /* proper defaults? */
+ bits |= TIOCM_DTR;
+ bits |= TIOCM_RTS;
+ bits |= TIOCM_CTS;
+ bits |= TIOCM_CD;
+ /* bits |= TIOCM_RI; */
+ bits |= TIOCM_DSR;
+
+ /* printf("retbits %x\n", bits); */
+ return (bits);
+}
+
+int
+bugttyopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int s, unit = BUGTTYUNIT(dev);
+ struct tty *tp;
+ extern int needprom;
+
+ if (needprom == 0)
+ return (ENODEV);
+
+ s = spltty();
+ if (bugtty_tty[unit]) {
+ tp = bugtty_tty[unit];
+ } else {
+ tp = bugtty_tty[unit] = ttymalloc();
+ }
+ tp->t_oproc = bugttyoutput;
+ tp->t_param = NULL;
+ tp->t_dev = dev;
+
+ if ((tp->t_state & TS_ISOPEN) == 0) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * only when cleared do we reset to defaults.
+ */
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = bugttydefaultrate;
+ }
+ /* bugtty does not have carrier */
+ tp->t_cflag |= CLOCAL;
+ /*
+ * do these all the time
+ */
+ if (bugttyswflags & TIOCFLAG_CLOCAL)
+ tp->t_cflag |= CLOCAL;
+ if (bugttyswflags & TIOCFLAG_CRTSCTS)
+ tp->t_cflag |= CRTSCTS;
+ if (bugttyswflags & TIOCFLAG_MDMBUF)
+ tp->t_cflag |= MDMBUF;
+ bugttyparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+
+ (void)bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET);
+ /*
+ if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) ||
+ (bugttymctl(dev, 0, DMGET) & TIOCM_CD))
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+ */
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+
+ /*
+ * if NONBLOCK requested, ignore carrier
+ */
+/*
+ if (flag & O_NONBLOCK)
+ goto done;
+*/
+
+ splx(s);
+ /*
+ * Reset the tty pointer, as there could have been a dialout
+ * use of the tty with a dialin open waiting.
+ */
+ tp->t_dev = dev;
+ return ((*linesw[tp->t_line].l_open)(dev, tp));
+}
+
+int
+bugttyparam()
+{
+ return (0);
+}
+
+void
+bugttyoutput(tp)
+ struct tty *tp;
+{
+ int cc, s, unit, cnt ;
+
+ /* only supports one unit */
+
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ return;
+
+ s = spltty();
+ cc = tp->t_outq.c_cc;
+ while (cc > 0) {
+ cnt = min(BUGBUF, cc);
+ cnt = q_to_b(&tp->t_outq, bug_obuffer, cnt);
+ bugoutstr(bug_obuffer, &bug_obuffer[cnt]);
+ cc -= cnt;
+ }
+ splx(s);
+}
+
+int
+bugttyclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ int unit = BUGTTYUNIT(dev);
+ struct tty *tp = bugtty_tty[unit];
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+
+ ttyclose(tp);
+#if 0
+ bugtty_tty[unit] = NULL;
+#endif
+ return (0);
+}
+
+int
+bugttyread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp;
+
+ if ((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+#if 1
+/* only to be called at splclk() */
+bugtty_chkinput()
+{
+ struct tty *tp;
+
+ tp = bugtty_tty[0]; /* Kinda ugly hack */
+ if (tp == NULL )
+ return;
+
+ if (buginstat()) {
+ while (buginstat()) {
+ u_char c = buginchr() & 0xff;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+ /*
+ wakeup(tp);
+ */
+ }
+}
+#endif
+
+int
+bugttywrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+#if 0
+ /* bypass tty output routines. */
+ int i, cnt, s;
+ int oldoff;
+
+ s = spltty();
+ oldoff = uio->uio_offset;
+ do {
+ uiomove(bug_obuffer, BUGBUF, uio);
+ bugoutstr(bug_obuffer, &bug_obuffer[uio->uio_offset - oldoff]);
+ oldoff = uio->uio_offset;
+ } while (uio->uio_resid != 0);
+ splx(s);
+
+ return (0);
+#else
+ struct tty *tp;
+ if((tp = bugtty_tty[BUGTTYUNIT(dev)]) == NULL)
+ return (ENXIO);
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+#endif
+}
+
+int
+bugttyioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int unit = BUGTTYUNIT(dev);
+ struct tty *tp = bugtty_tty[unit];
+ int error;
+
+ if (!tp)
+ return (ENXIO);
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ switch (cmd) {
+ case TIOCSBRK:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+ (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+ break;
+
+ case TIOCCDTR:
+ (void) bugttymctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+ break;
+
+ case TIOCMSET:
+ (void) bugttymctl(dev, *(int *) data, DMSET);
+ break;
+
+ case TIOCMBIS:
+ (void) bugttymctl(dev, *(int *) data, DMBIS);
+ break;
+
+ case TIOCMBIC:
+ (void) bugttymctl(dev, *(int *) data, DMBIC);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = bugttymctl(dev, 0, DMGET);
+ break;
+ case TIOCGFLAGS:
+ *(int *)data = SWFLAGS(dev);
+ break;
+ case TIOCSFLAGS:
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0)
+ return (EPERM);
+
+ bugttyswflags = *(int *)data;
+ bugttyswflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+int
+bugttystop(tp, flag)
+ struct tty *tp;
+ int flag;
+{
+ int s;
+
+ s = spltty();
+ if (tp->t_state & TS_BUSY) {
+ if ((tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+ }
+ splx(s);
+ return (0);
+}
+
+/*
+ * bugtty is the last possible choice for a console device.
+ */
+int
+bugttycnprobe(cp)
+ struct consdev *cp;
+{
+ int maj;
+ extern int needprom;
+
+ if (needprom == 0) {
+ cp->cn_pri = CN_DEAD;
+ return (0);
+ }
+
+#if 0
+ switch (cputyp) {
+ case CPU_147:
+ case CPU_162:
+ cp->cn_pri = CN_NORMAL;
+ return (0);
+ default:
+ break;
+ }
+#else
+ cp->cn_pri = CN_NORMAL;
+ return (0);
+#endif /* 0 */
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == bugttyopen)
+ break;
+
+ cp->cn_dev = makedev(maj, 0);
+ cp->cn_pri = CN_NORMAL;
+
+ return (1);
+}
+
+int
+bugttycninit(cp)
+ struct consdev *cp;
+{
+}
+
+int
+bugttycngetc(dev)
+ dev_t dev;
+{
+ return (buginchr());
+}
+
+int
+bugttycnputc(dev, c)
+ dev_t dev;
+ char c;
+{
+ int s;
+
+ if (c == '\n')
+ bugoutchr('\r');
+ bugoutchr(c);
+}
diff --git a/sys/arch/mvme88k/dev/clock.c b/sys/arch/mvme88k/dev/clock.c
new file mode 100644
index 00000000000..352bc426dfc
--- /dev/null
+++ b/sys/arch/mvme88k/dev/clock.c
@@ -0,0 +1,371 @@
+/* $NetBSD: clock.c,v 1.22 1995/05/29 23:57:15 pk Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1995 Nivas Madhur
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1993 Adam Glass
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * Clock driver. Has both interval timer as well as statistics timer.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#ifdef GPROF
+#include <sys/gmon.h>
+#endif
+
+#include <machine/autoconf.h>
+#include <machine/cpu.h>
+
+#include <mvme88k/dev/pcctworeg.h>
+
+/*
+ * Statistics clock interval and variance, in usec. Variance must be a
+ * power of two. Since this gives us an even number, not an odd number,
+ * we discard one case and compensate. That is, a variance of 4096 would
+ * give us offsets in [0..4095]. Instead, we take offsets in [1..4095].
+ * This is symmetric about the point 2048, or statvar/2, and thus averages
+ * to that value (assuming uniform random numbers).
+ */
+int statvar = 8192;
+int statmin; /* statclock interval - 1/2*variance */
+int timerok;
+
+u_long delay_factor = 1;
+
+static int clockmatch __P((struct device *, void *, void *));
+static void clockattach __P((struct device *, struct device *, void *));
+int clockintr __P((void *, void *));
+int statintr __P((void *, void *));
+
+struct clocksoftc {
+ struct device sc_dev;
+ volatile struct pcc2reg *sc_pcc2reg;
+};
+
+struct cfattach clock_ca = {
+ sizeof(struct clocksoftc), clockmatch, clockattach
+};
+
+struct cfdriver clock_cd = {
+ NULL, "clock", DV_DULL, 0
+};
+
+struct intrhand clockintrhand, statintrhand;
+
+static int
+clockmatch(struct device *parent, void *self, void *aux)
+{
+ register struct confargs *ca = aux;
+ register struct cfdata *cf = self;
+
+ if (ca->ca_bustype != BUS_PCCTWO ||
+ strcmp(cf->cf_driver->cd_name, "clock")) {
+ return (0);
+ }
+
+ /*
+ * clock has to be at ipl 5
+ * We return the ipl here so that the parent can print
+ * a message if it is different from what ioconf.c says.
+ */
+ ca->ca_ipl = IPL_CLOCK;
+ /* set size to 0 - see pcctwo.c:match for details */
+ ca->ca_size = 0;
+
+ return 1;
+}
+
+/* ARGSUSED */
+static void
+clockattach(struct device *parent, struct device *self, void *aux)
+{
+ struct confargs *ca = aux;
+ struct clocksoftc *sc = (struct clocksoftc *)self;
+ u_long elapsedtime;
+
+ extern void delay(u_long);
+ extern int cpuspeed;
+
+ /*
+ * save virtual address of the pcc2 block since our
+ * registers are in that block.
+ */
+ sc->sc_pcc2reg = (struct pcc2reg *)ca->ca_vaddr;
+
+ /*
+ * calibrate for delay() calls.
+ * We do this by using tick timer1 in free running mode before
+ * cpu_initclocks() is called so turn on clock interrupts etc.
+ *
+ * the approach is:
+ * set count in timer to 0
+ * call delay(1000) for a 1000 us delay
+ * after return, stop count and figure out
+ * how many us went by (call it x)
+ * now the factor to multiply the arg. passed to
+ * delay would be (x/1000) rounded up to an int.
+ */
+ printf("\n");
+ sc->sc_pcc2reg->pcc2_t1ctl &= ~PCC2_TICTL_CEN;
+ sc->sc_pcc2reg->pcc2_psclkadj = 256 - cpuspeed;
+ sc->sc_pcc2reg->pcc2_t1irq &= ~PCC2_TTIRQ_IEN;
+ sc->sc_pcc2reg->pcc2_t1cntr = 0;
+ sc->sc_pcc2reg->pcc2_t1ctl |= PCC2_TICTL_CEN;
+ delay(1000); /* delay for 1 ms */
+ sc->sc_pcc2reg->pcc2_t1ctl &= ~PCC2_TICTL_CEN;
+ elapsedtime = sc->sc_pcc2reg->pcc2_t1cntr;
+
+ delay_factor = (u_long)(elapsedtime / 1000 + 1);
+
+ /*
+ * program clock to interrupt at IPL_CLOCK. Set everything
+ * except compare registers, interrupt enable and counter
+ * enable registers.
+ */
+ sc->sc_pcc2reg->pcc2_t1ctl &= ~(PCC2_TICTL_CEN);
+ sc->sc_pcc2reg->pcc2_t1cntr= 0;
+ sc->sc_pcc2reg->pcc2_t1ctl |= (PCC2_TICTL_COC|PCC2_TICTL_COVF);
+ sc->sc_pcc2reg->pcc2_t1irq = (PCC2_TTIRQ_ICLR|IPL_CLOCK);
+
+ sc->sc_pcc2reg->pcc2_t2ctl &= ~(PCC2_TICTL_CEN);
+ sc->sc_pcc2reg->pcc2_t2cntr= 0;
+ sc->sc_pcc2reg->pcc2_t2ctl |= (PCC2_TICTL_COC|PCC2_TICTL_COVF);
+ sc->sc_pcc2reg->pcc2_t2irq = (PCC2_TTIRQ_ICLR|IPL_CLOCK);
+
+ /*
+ * Establish inerrupt handlers.
+ */
+ clockintrhand.ih_fn = clockintr;
+ clockintrhand.ih_arg = 0; /* don't want anything */
+ clockintrhand.ih_ipl = IPL_CLOCK;
+ clockintrhand.ih_wantframe = 1;
+ intr_establish(PCC2_VECT+9, &clockintrhand);
+
+ statintrhand.ih_fn = statintr;
+ statintrhand.ih_arg = 0; /* don't want anything */
+ statintrhand.ih_ipl = IPL_CLOCK;
+ statintrhand.ih_wantframe = 1;
+ intr_establish(PCC2_VECT+8, &statintrhand);
+
+ timerok = 1;
+}
+
+/*
+ * Set up the real-time and statistics clocks. Leave stathz 0 only if
+ * no alternative timer is available. mvme167/mvme187 has 2 tick timers
+ * in pcc2 - we are using timer 1 for clock interrupt and timer 2 for
+ * statistics.
+ *
+ * The frequencies of these clocks must be an even number of microseconds.
+ */
+cpu_initclocks()
+{
+ register int statint, minint;
+ volatile struct pcc2reg *pcc2reg;
+
+ pcc2reg = ((struct clocksoftc *)clock_cd.cd_devs[0])->sc_pcc2reg;
+
+ if (1000000 % hz) {
+ printf("cannot get %d Hz clock; using 100 Hz\n", hz);
+ hz = 100;
+ tick = 1000000 / hz;
+ }
+ if (stathz == 0)
+ stathz = hz;
+ if (1000000 % stathz) {
+ printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
+ stathz = 100;
+ }
+ profhz = stathz; /* always */
+
+ statint = 1000000 / stathz;
+ minint = statint / 2 + 100;
+ while (statvar > minint)
+ statvar >>= 1;
+ /*
+ * hz value 100 means we want the clock to interrupt 100
+ * times a sec or 100 times in 1000000 us ie, 1 interrupt
+ * every 10000 us. Program the tick timer compare register
+ * to this value.
+ */
+ pcc2reg->pcc2_t1cmp = tick;
+ pcc2reg->pcc2_t2cmp = statint;
+ statmin = statint - (statvar >> 1);
+
+ /* start the clocks ticking */
+ pcc2reg->pcc2_t1ctl = (PCC2_TICTL_CEN|PCC2_TICTL_COC|PCC2_TICTL_COVF);
+ pcc2reg->pcc2_t2ctl = (PCC2_TICTL_CEN|PCC2_TICTL_COC|PCC2_TICTL_COVF);
+ /* and enable those interrupts */
+ pcc2reg->pcc2_t1irq |= (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR);
+ pcc2reg->pcc2_t2irq |= (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR);
+}
+
+/*
+ * Dummy setstatclockrate(), since we know profhz==hz.
+ */
+/* ARGSUSED */
+void
+setstatclockrate(int newhz)
+{
+ /* nothing */
+}
+
+/*
+ * Delay: wait for `about' n microseconds to pass.
+ */
+void
+delay(volatile u_long n)
+{
+ volatile u_long cnt = n * delay_factor;
+
+ while (cnt-- > 0) {
+ asm volatile("");
+ }
+}
+
+/*
+ * Clock interrupt handler. Calls hardclock() after setting up a
+ * clockframe.
+ */
+int
+clockintr(void *cap, void *frame)
+{
+ volatile struct pcc2reg *reg;
+
+ reg = ((struct clocksoftc *)clock_cd.cd_devs[0])->sc_pcc2reg;
+
+ /* Clear the interrupt */
+ reg->pcc2_t1irq = (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR|IPL_CLOCK);
+#if 0
+ reg->pcc2_t1irq |= PCC2_TTIRQ_ICLR;
+#endif /* 0 */
+
+ hardclock((struct clockframe *)frame);
+#include "bugtty.h"
+#if NBUGTTY > 0
+ bugtty_chkinput();
+#endif /* NBUGTTY */
+
+ return (1);
+}
+
+/*
+ * Stat clock interrupt handler.
+ */
+int
+statintr(void *cap, void *frame)
+{
+ volatile struct pcc2reg *reg;
+ register u_long newint, r, var;
+
+ reg = ((struct clocksoftc *)clock_cd.cd_devs[0])->sc_pcc2reg;
+
+ /* Clear the interrupt */
+#if 0
+ reg->pcc2_t2irq |= PCC2_TTIRQ_ICLR;
+#endif /* 0 */
+ reg->pcc2_t2irq = (PCC2_TTIRQ_IEN|PCC2_TTIRQ_ICLR|IPL_CLOCK);
+
+ statclock((struct clockframe *)frame);
+
+ /*
+ * Compute new randomized interval. The intervals are uniformly
+ * distributed on [statint - statvar / 2, statint + statvar / 2],
+ * and therefore have mean statint, giving a stathz frequency clock.
+ */
+ var = statvar;
+ do {
+ r = random() & (var - 1);
+ } while (r == 0);
+ newint = statmin + r;
+
+ /*
+ * reprogram statistics timer to interrupt at
+ * newint us intervals.
+ */
+ reg->pcc2_t2ctl = ~(PCC2_TICTL_CEN);
+ reg->pcc2_t2cntr = 0;
+ reg->pcc2_t2cmp = newint;
+ reg->pcc2_t2ctl = (PCC2_TICTL_CEN|PCC2_TICTL_COC|PCC2_TICTL_COVF);
+ reg->pcc2_t2irq |= (PCC2_TTIRQ_ICLR|PCC2_TTIRQ_IEN);
+
+ return (1);
+}
+
+/*
+ * Return the best possible estimate of the time in the timeval
+ * to which tvp points. We do this by returning the current time
+ * plus the amount of time since the last clock interrupt.
+ *
+ * Check that this time is no less than any previously-reported time,
+ * which could happen around the time of a clock adjustment. Just for
+ * fun, we guarantee that the time will be greater than the value
+ * obtained by a previous call.
+ */
+void
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s;
+ static struct timeval lasttime;
+
+ s = splhigh();
+ *tvp = time;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ if (tvp->tv_sec == lasttime.tv_sec &&
+ tvp->tv_usec <= lasttime.tv_usec &&
+ (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ lasttime = *tvp;
+ splx(s);
+}
diff --git a/sys/arch/mvme88k/dev/pcc2.c b/sys/arch/mvme88k/dev/pcc2.c
new file mode 100644
index 00000000000..c78cbb24a81
--- /dev/null
+++ b/sys/arch/mvme88k/dev/pcc2.c
@@ -0,0 +1,253 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/pcc2.h>
+
+int m1x7pccprobe(struct device *parent, struct cfdata *self, void *aux);
+void m1x7pccattach(struct device *parent, struct device *self, void *aux);
+
+int abort_handler();
+extern void abort_intrv();
+extern void pcc_intrv();
+extern int intrh_debug;
+extern int machineid;
+extern void badtrap();
+extern int submatch( struct device *parent, struct cfdata *self, void *aux);
+/* static */ u_int *pcc_io_base;
+static u_int *pcc_vector_base;
+
+static void abort_setup();
+void timer2_intr();
+
+struct pcctwosoftc {
+ struct device sc_dev;
+ caddr_t sc_vaddr;
+ caddr_t sc_paddr;
+ struct pcctworeg *sc_pcc2;
+};
+
+void pcctwoattach __P((struct device *, struct device *, void *));
+int pcctwoprobe __P((struct device *, void *, void *));
+int pcctwoabort __P((struct frame *));
+
+struct cfdriver pcctwocd = {
+ NULL, "pcctwo", pcctwomatch, pcctwoattach,
+ DV_DULL, sizeof(struct pcctwosoftc), 0
+};
+
+struct pcctworeg *sys_pcc2 = NULL;
+
+int
+pcctwomatch(struct device *parent, struct cfdata *self, void *aux)
+{
+#if defined(__m88k__)
+ if (machineid == 0x187) {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+void
+pcctwoattach(struct device *parent, struct device *self, void *aux)
+{
+ struct cfdata *cf;
+ volatile char *ibvr; /* Interrupt Base Vector Register */
+ u_int ibv; /* Interrupt Base Vector, offset from vbr */
+ u_int *iv; /* interupt vector */
+ int i;
+ u_int vector_base;
+
+ /* attach memory mapped io space */
+ /* map 0xfffe1000 - 0xfffe102f, 0xfffe2800 */
+ /* ppc_io_base = mmio(0xfffe1000, 1800, PG_RW|PG_CI); */
+ pcc_io_base = 0xfffe1000; /* should really be return of virtmem alloc */
+ /* set PCC vector base */
+ ibv = PCC_IBVR(pcc_io_base) & 0xf0;
+ ibvr = &PCC_IBVR(pcc_io_base);
+ printf("pcc:ibvr %x *ibvr %x ibv %x\n",ibvr,*ibvr, ibv);
+ pcc_vector_base = (u_int *)ibv;
+ asm volatile ("movec vbr,%0": "=d" (vector_base));
+ printf("pcc:vector_base %x\n",vector_base);
+ /* register "standard interupt handlers */
+
+ abort_setup();
+ iv = (u_int *)(vector_base + (ibv * 4));
+printf("iv %x\n",iv);
+ for (i = 0; i <= SOFT2_VECTOR; i++) {
+ iv[i] = (u_int)pcc_intrv;
+ }
+ /*
+ timer2_setup();
+ */
+ iv = (u_int *)(vector_base + (ibv + TICK2_VECTOR) * 4);
+ *iv = (u_int)&pcc_intrv;
+
+#ifdef DEBUG
+ if (intrh_debug)
+ pr_intrh();
+#endif
+ if ((cf = config_search(submatch, self, aux)) != NULL) {
+ return;
+ }
+ return ;
+}
+asm (" .text");
+asm (" .global _pcc_intrv");
+asm ("_pcc_intrv:");
+asm (" link a6,#0");
+asm (" movml a0/a1/d0/d1,sp@-");
+asm (" movel a6,a0");
+asm (" addql #4,a0");
+asm (" movel a0,sp@-");
+asm (" jbsr _pcc_handler");
+asm (" addql #4,sp");
+asm (" movml sp@+,a0/a1/d0/d1");
+asm (" unlk a6");
+asm (" jra rei");
+
+asm (" .global _abort_intrv");
+asm ("_abort_intrv:");
+asm (" movml a0/a1/d0/d1,sp@-");
+asm (" jbsr _abort_handler");
+asm (" movml sp@+,a0/a1/d0/d1");
+asm (" jra rei");
+/* asm (" .previous"); */
+
+void *m147le_arg;
+void
+pcc_handler(struct exception_frame *except)
+{
+ u_int vector;
+ int handled = 0;
+
+#if 0
+ printf("except %x\n",except);
+ printf("sr %x\n",except->sr);
+ printf("pc %x\n",except->pc);
+ printf("type %x\n",except->type);
+#endif
+ vector = except->vo;
+/* printf("vector %x\n",vector); */
+ vector = (vector/4 - (u_int)pcc_vector_base);
+/* printf("vector %x\n",vector); */
+
+ switch (vector) {
+ case AC_FAIL_VECTOR:
+ printf("ac_fail vector\n");
+ break;
+ case BERR_VECTOR:
+ printf("berr vector\n");
+ printf("pcc_handler:invalid vector %x\n",vector);
+ break;
+ case ABORT_VECTOR:
+ printf("abort vector\n");
+ abort_handler();
+ handled = 1;
+ break;
+ case SERIAL_VECTOR:
+ printf("serial vector\n");
+ PCC_SERIAL_ICR(0xfffe1000) = 0;
+ break;
+ case LANCE_VECTOR:
+ leintr(m147le_arg);
+ handled = 1;
+ break;
+ case SCSIPORT_VECTOR:
+ printf("scsiport vector\n");
+ m147sc_scintr();
+ break;
+ case SCSIDMA_VECTOR:
+ printf("scsidma vector\n");
+ m147sc_dmaintr();
+ break;
+ case PRINTER_VECTOR:
+ printf("printer vector\n");
+ break;
+ case TICK1_VECTOR:
+ printf("tick1 vector\n");
+ printf("pcc_handler:invalid vector %x\n",vector);
+ break;
+ case TICK2_VECTOR:
+ timer2_intr(except);
+ handled = 1;
+ break;
+ case SOFT1_VECTOR:
+ printf("soft1 vector\n");
+ break;
+ case SOFT2_VECTOR:
+ printf("soft2 vector\n");
+ break;
+ default:
+ printf("pcc_handler:invalid vector %x\n",vector);
+ }
+
+ if (handled == 0) {
+ printf("except %x\n",except);
+ printf("sr %x\n",except->sr);
+ printf("pc %x\n",except->pc);
+ printf("type %x\n",except->type);
+ }
+}
+
+
+int
+abort_handler()
+{
+ printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base));
+ PCC_ABRT_ICR(pcc_io_base) = 0x88;
+ printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base));
+ Debugger();
+ return 0;
+}
+static void abort_setup()
+{
+ printf("PCC_ABRT_ICR %x\n",&PCC_ABRT_ICR(pcc_io_base));
+ printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base));
+ PCC_ABRT_ICR(pcc_io_base) = 0x88;
+ printf("aicr = 0x%x\n",PCC_ABRT_ICR(pcc_io_base));
+}
+
+/* timer2 (clock) driver */
+
+/*const u_int timer_reload = 0; /* .4096 sec ? */
+/* const u_int timer_reload = 62870; 1/60 sec ? */
+const u_int timer_reload = 63936; /* 1/100 sec ? */
+
+#if 0
+void
+timer2_setup()
+{
+ u_int *io_base;
+ pcc_io_base = 0xfffe1000; /* should really be return of virtmem alloc */
+ io_base = pcc_io_base;
+ printf("pcc_io_base %x io_base %x\n",pcc_io_base, io_base);
+ printf("PCC_TIMER2_PRE %x\n",&PCC_TIMER2_PRE(io_base));
+ printf("PCC_TIMER2_CTR %x\n",&PCC_TIMER2_CTR(io_base));
+ printf("PCC_TIMER2_ICR %x\n",&PCC_TIMER2_ICR(io_base));
+ PCC_TIMER2_PRE(io_base) = timer_reload;
+ PCC_TIMER2_CTR(io_base) = 0x7;
+ PCC_TIMER2_ICR(io_base) = 0x8e;
+}
+#endif
+void
+timer2_intr(struct exception_frame *except)
+{
+ u_int *io_base;
+ pcc_io_base = 0xfffe1000; /* should really be return of virtmem alloc */
+ io_base = pcc_io_base;
+
+ if (0x80 && PCC_TIMER2_ICR(io_base)) {
+ PCC_TIMER2_ICR(io_base) = 0x8e;
+ /* hardclock(); */
+ hardclock(except);
+
+ } else {
+ printf("timer2_intr: vector called without interrupt\n");
+ }
+ /* REALLY UGLY HACK */
+ bugtty_chkinput();
+
+ return;
+}
diff --git a/sys/arch/mvme88k/dev/pcctwo.c b/sys/arch/mvme88k/dev/pcctwo.c
new file mode 100644
index 00000000000..7ad4c3abee1
--- /dev/null
+++ b/sys/arch/mvme88k/dev/pcctwo.c
@@ -0,0 +1,210 @@
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <machine/cpu.h>
+#include <machine/autoconf.h>
+
+#include <mvme88k/dev/pcctworeg.h>
+
+struct pcctwosoftc {
+ struct device sc_dev;
+ volatile struct pcc2reg *sc_pcc2reg;
+};
+
+int pcctwomatch __P((struct device *, void *, void *));
+int pcctwoscan __P((struct device *, void *, void *));
+void pcctwoattach __P((struct device *, struct device *, void *));
+
+#ifdef MVME187
+void setupiackvectors __P((void));
+#endif /* MVME187 */
+
+struct cfattach pcctwo_ca = {
+ sizeof(struct pcctwosoftc), pcctwomatch, pcctwoattach
+};
+
+struct cfdriver pcctwo_cd = {
+ NULL, "pcctwo", DV_DULL, 0
+};
+
+/*ARGSUSED*/
+int
+pcctwomatch(struct device *parent, void *self, void *aux)
+{
+ int ret;
+ u_char id, rev;
+ caddr_t base;
+ struct confargs *ca = aux;
+ struct cfdata *cf = self;
+
+#if 0
+ if (cputyp != CPU_167 && cputyp != CPU_166
+#ifdef MVME187
+ && cputyp != CPU_187
+#endif
+ )
+ {
+ return 0;
+ }
+#endif /* 0 */
+ if (cputyp != CPU_187) {
+ return 0;
+ }
+
+ /*
+ * If bus or name do not match, fail.
+ */
+ if (ca->ca_bustype != BUS_MAIN ||
+ strcmp(cf->cf_driver->cd_name, "pcctwo")) {
+ return 0;
+ }
+
+ if ((base = (caddr_t)cf->cf_loc[0]) == (caddr_t)-1) {
+ return 0;
+ }
+
+ id = badpaddr(base, 1);
+ rev = badpaddr(base + 1, 1);
+
+ if (id != PCC2_CHIP_ID || rev != PCC2_CHIP_REV) {
+ return 0;
+ }
+
+ ca->ca_size = PCC2_SIZE;
+ ca->ca_paddr = base;
+
+ return 1;
+}
+
+int
+pcctwoprint(void *aux, char *parent)
+{
+ struct confargs *ca = aux;
+
+ /*
+ * We call pcctwoprint() via config_attach(). Parent
+ * will always be null and config_attach() would have already
+ * printed "nvram0 at pcctwo0".
+ */
+ printf(" addr %x size %x", ca->ca_paddr, ca->ca_size);
+ if (ca->ca_ipl != -1) {
+ printf(" ipl %x", ca->ca_ipl);
+ }
+
+ return (UNCONF);
+}
+
+/*ARGSUSED*/
+int
+pcctwoscan(struct device *parent, void *self, void *aux)
+{
+ struct confargs ca;
+ struct cfdata *cf = self;
+ struct pcctwosoftc *sc = (struct pcctwosoftc *)parent;
+
+ /*
+ * Pcctwoscan gets called by config_search() for each
+ * child of parent (pcctwo) specified in ioconf.c.
+ * Fill in the bus type to be PCCTWO and call the child's
+ * match routine. If the child's match returns 1, then
+ * we need to allocate device memory, set it in confargs
+ * and call config_attach(). This, in turn, will call the
+ * child's attach.
+ */
+
+ ca.ca_bustype = BUS_PCCTWO;
+
+ if ((*cf->cf_attach->ca_match)(parent, cf, &ca) == 0)
+ return 0;
+
+ /*
+ * The child would have fixed up ca to reflect what its
+ * requirements are.
+ */
+
+ if (cf->cf_loc[2] != ca.ca_ipl) {
+ printf("Changing ipl %x specified in ioconf.c to %x for %s\n",
+ cf->cf_loc[2], ca.ca_ipl, cf->cf_driver->cd_name);
+ }
+
+ /*
+ * If the size specified by the child is 0, don't map
+ * any IO space, but pass in the address of pcc2reg as vaddr.
+ * This is for clock and parallel port which don't have a
+ * separate address space by themselves but use pcc2's register
+ * block.
+ */
+ if (ca.ca_size == 0) {
+ /*
+ * pcc2regs addr
+ */
+#if 0
+ ca.ca_vaddr = ((struct confargs *)aux)->ca_vaddr;
+#endif /* 0 */
+ ca.ca_vaddr = (caddr_t)sc->sc_pcc2reg;
+
+ } else {
+ ca.ca_vaddr = ca.ca_paddr;
+ }
+
+#if 0
+ ca.ca_parent = ((struct confargs *)aux)->ca_vaddr;
+#endif /* 0 */
+ ca.ca_parent = (caddr_t)sc->sc_pcc2reg;
+
+ /*
+ * Call child's attach using config_attach().
+ */
+ config_attach(parent, cf, &ca, pcctwoprint);
+ return 1;
+}
+
+/*
+ * This function calls the match routine of the configured children
+ * in turn. For each configured child, map the device address into
+ * iomap space and then call config_attach() to attach the child.
+ */
+
+/* ARGSUSED */
+void
+pcctwoattach(struct device *parent, struct device *self, void *aux)
+{
+ struct pcctwosoftc *sc = (struct pcctwosoftc *)self;
+ struct confargs *ca = aux;
+ caddr_t base;
+
+ if (self->dv_unit > 0) {
+ printf(" unsupported\n");
+ return;
+ }
+
+ base = ca->ca_vaddr;
+
+ printf(": PCCTWO id 0x%2x rev 0x%2x\n",
+ *(u_char *)base, *((u_char *)base + 1));
+
+ /*
+ * mainbus driver would have mapped Pcc2 at base. Save
+ * the address in pcctwosoftc.
+ */
+ sc->sc_pcc2reg = (struct pcc2reg *)base;
+
+ /*
+ * Set pcc2intr_mask and pcc2intr_ipl.
+ */
+ pcc2intr_ipl = (u_char *)&(sc->sc_pcc2reg->pcc2_ipl);
+ pcc2intr_mask = (u_char *)&(sc->sc_pcc2reg->pcc2_imask);
+
+#ifdef MVME187
+ /*
+ * Get mappings for iack vectors. This doesn't belong here
+ * but is more closely related to pcc than anything I can
+ * think of. (could probably do it in locore.s).
+ */
+
+ setupiackvectors();
+#endif /* MVME187 */
+
+ (void)config_search(pcctwoscan, self, aux);
+}