diff options
author | Dale S. Rahn <rahnds@cvs.openbsd.org> | 1997-03-03 20:23:07 +0000 |
---|---|---|
committer | Dale S. Rahn <rahnds@cvs.openbsd.org> | 1997-03-03 20:23:07 +0000 |
commit | b810033e0fa5b5b7163cee7059c523aaf907c6a5 (patch) | |
tree | fcde3ace3c188a7d797a313c9173a233532d44ca /sys/arch/mvme88k/dev | |
parent | 90ff5a441368313fa226376473fea6908c2c3539 (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.c | 502 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/clock.c | 371 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/pcc2.c | 253 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/pcctwo.c | 210 |
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); +} |