diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/sbus/files.sbus | 10 | ||||
-rw-r--r-- | sys/dev/sbus/spif.c | 1149 | ||||
-rw-r--r-- | sys/dev/sbus/spifreg.h | 380 | ||||
-rw-r--r-- | sys/dev/sbus/spifvar.h | 87 |
4 files changed, 1625 insertions, 1 deletions
diff --git a/sys/dev/sbus/files.sbus b/sys/dev/sbus/files.sbus index 10b90ecc57a..861257f4418 100644 --- a/sys/dev/sbus/files.sbus +++ b/sys/dev/sbus/files.sbus @@ -1,4 +1,4 @@ -# $OpenBSD: files.sbus,v 1.11 2002/01/12 20:19:40 jason Exp $ +# $OpenBSD: files.sbus,v 1.12 2002/01/13 02:06:45 jason Exp $ # $NetBSD: files.sbus,v 1.16 2000/12/08 17:29:12 martin Exp $ # # Config file and device description for machine-independent SBUS code. @@ -67,3 +67,11 @@ attach mtty at magma device mbpp attach mbpp at magma file dev/sbus/magma.c magma | mtty | mbpp needs-flag + +device spif {} +attach spif at sbus +device stty +attach stty at spif +device sbpp +attach sbpp at spif +file dev/sbus/spif.c spif | stty | sbpp needs-flag diff --git a/sys/dev/sbus/spif.c b/sys/dev/sbus/spif.c new file mode 100644 index 00000000000..4c8496ba528 --- /dev/null +++ b/sys/dev/sbus/spif.c @@ -0,0 +1,1149 @@ +/* $OpenBSD: spif.c,v 1.1 2002/01/13 02:06:45 jason Exp $ */ + +/* + * Copyright (c) 1999-2002 Jason L. Wright (jason@thought.net) + * 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 Jason L. Wright + * 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. + */ + +/* + * Driver for the SUNW,spif: 8 serial, 1 parallel sbus board + * based heavily on Iain Hibbert's driver for the MAGMA cards + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/malloc.h> +#include <sys/tty.h> +#include <sys/conf.h> + +#include <machine/autoconf.h> +#include <dev/sbus/sbusvar.h> +#include <dev/sbus/spifreg.h> +#include <dev/sbus/spifvar.h> + +/* + * useful macros + */ +#define SET(t, f) ((t) |= (f)) +#define CLR(t, f) ((t) &= ~(f)) +#define ISSET(t, f) ((t) & (f)) + +int spifmatch __P((struct device *, void *, void *)); +void spifattach __P((struct device *, struct device *, void *)); + +int sttymatch __P((struct device *, void *, void *)); +void sttyattach __P((struct device *, struct device *, void *)); +int sttyopen __P((dev_t, int, int, struct proc *)); +int sttyclose __P((dev_t, int, int, struct proc *)); +int sttyread __P((dev_t, struct uio *, int)); +int sttywrite __P((dev_t, struct uio *, int)); +int sttyioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +int sttystop __P((struct tty *, int)); + +int spifstcintr __P((void *)); +int spifstcintr_mx __P((struct spif_softc *, int *)); +int spifstcintr_tx __P((struct spif_softc *, int *)); +int spifstcintr_rx __P((struct spif_softc *, int *)); +int spifstcintr_rxexception __P((struct spif_softc *, int *)); +void spifsoftintr __P((void *)); + +int stty_param __P((struct tty *, struct termios *)); +struct tty *sttytty __P((dev_t)); +int stty_modem_control __P((struct stty_port *, int, int)); +void stty_write_ccr __P((struct spif_softc *, u_int8_t)); +int stty_compute_baud __P((speed_t, int, u_int8_t *, u_int8_t *)); +void stty_start __P((struct tty *)); + +int sbppmatch __P((struct device *, void *, void *)); +void sbppattach __P((struct device *, struct device *, void *)); +int sbppopen __P((dev_t, int, int, struct proc *)); +int sbppclose __P((dev_t, int, int, struct proc *)); +int sbppread __P((dev_t, struct uio *, int)); +int sbppwrite __P((dev_t, struct uio *, int)); +int sbpp_rw __P((dev_t, struct uio *)); +int spifppcintr __P((void *)); +int sbppselect __P((dev_t, int, struct proc *)); +int sbppioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); + +struct cfattach spif_ca = { + sizeof (struct spif_softc), spifmatch, spifattach +}; + +struct cfdriver spif_cd = { + NULL, "spif", DV_DULL +}; + +struct cfattach stty_ca = { + sizeof(struct stty_softc), sttymatch, sttyattach +}; + +struct cfdriver stty_cd = { + NULL, "stty", DV_TTY +}; + +struct cfattach sbpp_ca = { + sizeof(struct sbpp_softc), sbppmatch, sbppattach +}; + +struct cfdriver sbpp_cd = { + NULL, "sbpp", DV_DULL +}; + +/* normal STC access */ +#define STC_WRITE(sc,r,v) \ + bus_space_write_1((sc)->sc_bustag, (sc)->sc_stch, (r), (v)) +#define STC_READ(sc,r) \ + bus_space_read_1((sc)->sc_bustag, (sc)->sc_stch, (r)) + +/* IACK STC access */ +#define ISTC_WRITE(sc,r,v) \ + bus_space_write_1((sc)->sc_bustag, (sc)->sc_istch, (r), (v)) +#define ISTC_READ(sc,r) \ + bus_space_read_1((sc)->sc_bustag, (sc)->sc_istch, (r)) + +/* PPC access */ +#define PPC_WRITE(sc,r,v) \ + bus_space_write_1((sc)->sc_bustag, (sc)->sc_ppch, (r), (v)) +#define PPC_READ(sc,r) \ + bus_space_read_1((sc)->sc_bustag, (sc)->sc_ppch, (r)) + +#define DTR_WRITE(sc,port,v) \ + do { \ + sc->sc_ttys->sc_port[(port)].sp_dtr = v; \ + bus_space_write_1((sc)->sc_bustag, \ + sc->sc_dtrh, port, (v == 0) ? 1 : 0); \ + } while (0) + +#define DTR_READ(sc,port) ((sc)->sc_ttys->sc_port[(port)].sp_dtr) + +int +spifmatch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct cfdata *cf = vcf; + struct sbus_attach_args *sa = aux; + + if (strcmp(cf->cf_driver->cd_name, sa->sa_name) && + strcmp("SUNW,spif", sa->sa_name)) + return (0); + return (1); +} + +void +spifattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct spif_softc *sc = (struct spif_softc *)self; + struct sbus_attach_args *sa = aux; + + if (sa->sa_nintr != 2) { + printf(": expected 2 interrupts, got %d\n", + sa->sa_nintr); + return; + } + + if (sa->sa_nreg != 1) { + printf(": expected %d registers, got %d\n", + 1, sa->sa_nreg); + return; + } + + sc->sc_bustag = sa->sa_bustag; + if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, + sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size, + BUS_SPACE_MAP_LINEAR, 0, &sc->sc_regh) != 0) { + printf(": can't map registers\n"); + return; + } + + if (bus_space_subregion(sc->sc_bustag, sc->sc_regh, + DTR_REG_OFFSET, DTR_REG_LEN, &sc->sc_dtrh) != 0) { + printf(": can't map dtr regs\n"); + return; + } + + if (bus_space_subregion(sc->sc_bustag, sc->sc_regh, + STC_REG_OFFSET, STC_REG_LEN, &sc->sc_stch) != 0) { + printf(": can't map dtr regs\n"); + return; + } + + if (bus_space_subregion(sc->sc_bustag, sc->sc_regh, + ISTC_REG_OFFSET, ISTC_REG_LEN, &sc->sc_istch) != 0) { + printf(": can't map dtr regs\n"); + return; + } + + if (bus_space_subregion(sc->sc_bustag, sc->sc_regh, + PPC_REG_OFFSET, PPC_REG_LEN, &sc->sc_ppch) != 0) { + printf(": can't map dtr regs\n"); + return; + } + + sc->sc_ppcih = bus_intr_establish(sa->sa_bustag, + sa->sa_intr[PARALLEL_INTR].sbi_pri, IPL_TTY, 0, spifppcintr, sc); + if (sc->sc_ppcih == NULL) { + printf(": failed to establish ppc interrupt\n"); + return; + } + + sc->sc_stcih = bus_intr_establish(sa->sa_bustag, + sa->sa_intr[SERIAL_INTR].sbi_pri, IPL_TTY, 0, spifstcintr, sc); + if (sc->sc_stcih == NULL) { + printf(": failed to establish stc interrupt\n"); + return; + } + + sc->sc_softih = softintr_establish(IPL_TTY, spifsoftintr, sc); + if (sc->sc_softih == NULL) { + printf(": can't get soft intr\n"); + return; + } + + sc->sc_node = sa->sa_node; + + sc->sc_rev = getpropint(sc->sc_node, "revlev", 0); + + sc->sc_osc = getpropint(sc->sc_node, "verosc", 0); + switch (sc->sc_osc) { + case SPIF_OSC10: + sc->sc_osc = 10000000; + break; + case SPIF_OSC9: + default: + sc->sc_osc = 9830400; + break; + } + + sc->sc_nser = 8; + sc->sc_npar = 1; + + sc->sc_rev2 = STC_READ(sc, STC_GFRCR); + STC_WRITE(sc, STC_GSVR, 0); + + stty_write_ccr(sc, CD180_CCR_CMD_RESET | CD180_CCR_RESETALL); + while (STC_READ(sc, STC_GSVR) != 0xff); + while (STC_READ(sc, STC_GFRCR) != sc->sc_rev2); + + STC_WRITE(sc, STC_PPRH, CD180_PPRH); + STC_WRITE(sc, STC_PPRL, CD180_PPRL); + STC_WRITE(sc, STC_MSMR, SPIF_MSMR); + STC_WRITE(sc, STC_TSMR, SPIF_TSMR); + STC_WRITE(sc, STC_RSMR, SPIF_RSMR); + STC_WRITE(sc, STC_GSVR, 0); + STC_WRITE(sc, STC_GSCR1, 0); + STC_WRITE(sc, STC_GSCR2, 0); + STC_WRITE(sc, STC_GSCR3, 0); + + printf(": rev %x chiprev %x osc %sMhz\n", + sc->sc_rev, sc->sc_rev2, clockfreq(sc->sc_osc)); + + (void)config_found(self, sttymatch, NULL); + (void)config_found(self, sbppmatch, NULL); +} + +int +sttymatch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct spif_softc *sc = (struct spif_softc *)parent; + + return (aux == sttymatch && sc->sc_ttys == NULL); +} + +void +sttyattach(parent, dev, aux) + struct device *parent, *dev; + void *aux; +{ + struct spif_softc *sc = (struct spif_softc *)parent; + struct stty_softc *ssc = (struct stty_softc *)dev; + int port; + + sc->sc_ttys = ssc; + + for (port = 0; port < sc->sc_nser; port++) { + struct stty_port *sp = &ssc->sc_port[port]; + struct tty *tp; + + DTR_WRITE(sc, port, 0); + + tp = ttymalloc(); + if (tp == NULL) + break; + tty_attach(tp); + + tp->t_oproc = stty_start; + tp->t_param = stty_param; + + sp->sp_tty = tp; + sp->sp_sc = sc; + sp->sp_channel = port; + + sp->sp_rbuf = malloc(STTY_RBUF_SIZE, M_DEVBUF, M_NOWAIT); + if(sp->sp_rbuf == NULL) + break; + + sp->sp_rend = sp->sp_rbuf + STTY_RBUF_SIZE; + } + + ssc->sc_nports = port; + + printf(": %d tty%s\n", port, port == 1 ? "" : "s"); +} + +int +sttyopen(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + struct spif_softc *csc; + struct stty_softc *sc; + struct stty_port *sp; + struct tty *tp; + int card = SPIF_CARD(dev); + int port = SPIF_PORT(dev); + int s; + + if (card >= stty_cd.cd_ndevs || card >= spif_cd.cd_ndevs) + return (ENXIO); + + sc = stty_cd.cd_devs[card]; + csc = spif_cd.cd_devs[card]; + if (sc == NULL) + return (ENXIO); + + if (port >= sc->sc_nports) + return (ENXIO); + + sp = &sc->sc_port[port]; + tp = sp->sp_tty; + tp->t_dev = dev; + + if (!ISSET(tp->t_state, TS_ISOPEN)) { + SET(tp->t_state, TS_WOPEN); + + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + if (ISSET(sp->sp_openflags, TIOCFLAG_CLOCAL)) + SET(tp->t_cflag, CLOCAL); + if (ISSET(sp->sp_openflags, TIOCFLAG_CRTSCTS)) + SET(tp->t_cflag, CRTSCTS); + if (ISSET(sp->sp_openflags, TIOCFLAG_MDMBUF)) + SET(tp->t_cflag, MDMBUF); + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + + sp->sp_rput = sp->sp_rget = sp->sp_rbuf; + + s = spltty(); + + STC_WRITE(csc, STC_CAR, sp->sp_channel); + stty_write_ccr(csc, CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN); + STC_WRITE(csc, STC_CAR, sp->sp_channel); + + stty_param(tp, &tp->t_termios); + + ttsetwater(tp); + + STC_WRITE(csc, STC_SRER, CD180_SRER_CD | CD180_SRER_RXD); + + if (ISSET(sp->sp_openflags, TIOCFLAG_SOFTCAR) || sp->sp_carrier) + SET(tp->t_state, TS_CARR_ON); + else + CLR(tp->t_state, TS_CARR_ON); + } + else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) { + return (EBUSY); + } else { + s = spltty(); + } + + if (!ISSET(flags, O_NONBLOCK)) { + while (!ISSET(tp->t_cflag, CLOCAL) && + !ISSET(tp->t_state, TS_CARR_ON)) { + int error; + + SET(tp->t_state, TS_WOPEN); + error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, + "sttycd", 0); + if (error != 0) { + splx(s); + CLR(tp->t_state, TS_WOPEN); + return (error); + } + } + } + + splx(s); + + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +int +sttyclose(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)]; + struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)]; + struct spif_softc *csc = sp->sp_sc; + struct tty *tp = sp->sp_tty; + int port = SPIF_PORT(dev); + int s; + + (*linesw[tp->t_line].l_close)(tp, flags); + s = spltty(); + + if (ISSET(tp->t_cflag, HUPCL) || !ISSET(tp->t_state, TS_ISOPEN)) { + stty_modem_control(sp, 0, DMSET); + STC_WRITE(csc, STC_CAR, port); + STC_WRITE(csc, STC_CCR, + CD180_CCR_CMD_RESET|CD180_CCR_RESETCHAN); + } + + splx(s); + ttyclose(tp); + return (0); +} + +int +sttyioctl(dev, cmd, data, flags, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(dev)]; + struct stty_port *sp = &stc->sc_port[SPIF_PORT(dev)]; + struct spif_softc *sc = sp->sp_sc; + struct tty *tp = sp->sp_tty; + int error; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p); + if (error >= 0) + return (error); + + error = ttioctl(tp, cmd, data, flags, p); + if (error >= 0) + return (error); + + error = 0; + + switch (cmd) { + case TIOCSBRK: + SET(sp->sp_flags, STTYF_SET_BREAK); + STC_WRITE(sc, STC_CAR, sp->sp_channel); + STC_WRITE(sc, STC_SRER, + STC_READ(sc, STC_SRER) | CD180_SRER_TXD); + break; + case TIOCCBRK: + SET(sp->sp_flags, STTYF_CLR_BREAK); + STC_WRITE(sc, STC_CAR, sp->sp_channel); + STC_WRITE(sc, STC_SRER, + STC_READ(sc, STC_SRER) | CD180_SRER_TXD); + break; + case TIOCSDTR: + stty_modem_control(sp, TIOCM_DTR, DMBIS); + break; + case TIOCCDTR: + stty_modem_control(sp, TIOCM_DTR, DMBIC); + break; + case TIOCMBIS: + stty_modem_control(sp, *((int *)data), DMBIS); + break; + case TIOCMBIC: + stty_modem_control(sp, *((int *)data), DMBIC); + break; + case TIOCMGET: + *((int *)data) = stty_modem_control(sp, 0, DMGET); + break; + case TIOCMSET: + stty_modem_control(sp, *((int *)data), DMSET); + break; + case TIOCGFLAGS: + *((int *)data) = sp->sp_openflags; + break; + case TIOCSFLAGS: + if (suser(p->p_ucred, &p->p_acflag)) + error = EPERM; + else + sp->sp_openflags = *((int *)data) & + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | + TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF); + break; + default: + error = ENOTTY; + } + + return (error); +} + +int +stty_modem_control(sp, bits, how) + struct stty_port *sp; + int bits, how; +{ + struct spif_softc *csc = sp->sp_sc; + struct tty *tp = sp->sp_tty; + int s, msvr; + + s = spltty(); + STC_WRITE(csc, STC_CAR, sp->sp_channel); + + switch (how) { + case DMGET: + bits = TIOCM_LE; + if (DTR_READ(csc, sp->sp_channel)) + bits |= TIOCM_DTR; + msvr = STC_READ(csc, STC_MSVR); + if (ISSET(msvr, CD180_MSVR_DSR)) + bits |= TIOCM_DSR; + if (ISSET(msvr, CD180_MSVR_CD)) + bits |= TIOCM_CD; + if (ISSET(msvr, CD180_MSVR_CTS)) + bits |= TIOCM_CTS; + if (ISSET(msvr, CD180_MSVR_RTS)) + bits |= TIOCM_RTS; + break; + case DMSET: + DTR_WRITE(csc, sp->sp_channel, ISSET(bits, TIOCM_DTR) ? 1 : 0); + if (ISSET(bits, TIOCM_RTS)) + STC_WRITE(csc, STC_MSVR, + STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS)); + else + STC_WRITE(csc, STC_MSVR, + STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS); + break; + case DMBIS: + if (ISSET(bits, TIOCM_DTR)) + DTR_WRITE(csc, sp->sp_channel, 1); + if (ISSET(bits, TIOCM_RTS) && !ISSET(tp->t_cflag, CRTSCTS)) + STC_WRITE(csc, STC_MSVR, + STC_READ(csc, STC_MSVR) & (~CD180_MSVR_RTS)); + break; + case DMBIC: + if (ISSET(bits, TIOCM_DTR)) + DTR_WRITE(csc, sp->sp_channel, 0); + if (ISSET(bits, TIOCM_RTS)) + STC_WRITE(csc, STC_MSVR, + STC_READ(csc, STC_MSVR) | CD180_MSVR_RTS); + break; + } + + splx(s); + return (bits); +} + +int +stty_param(tp, t) + struct tty *tp; + struct termios *t; +{ + struct stty_softc *st = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)]; + struct stty_port *sp = &st->sc_port[SPIF_PORT(tp->t_dev)]; + struct spif_softc *sc = sp->sp_sc; + u_int8_t rbprl, rbprh, tbprl, tbprh; + int s, opt; + + if (t->c_ospeed && + stty_compute_baud(t->c_ospeed, sc->sc_osc, &tbprl, &tbprh)) + return (EINVAL); + + if (t->c_ispeed && + stty_compute_baud(t->c_ispeed, sc->sc_osc, &rbprl, &rbprh)) + return (EINVAL); + + s = spltty(); + + /* hang up line if ospeed is zero, otherwise raise DTR */ + stty_modem_control(sp, TIOCM_DTR, + (t->c_ospeed == 0 ? DMBIC : DMBIS)); + + STC_WRITE(sc, STC_CAR, sp->sp_channel); + + opt = 0; + if (ISSET(t->c_cflag, PARENB)) { + opt |= CD180_COR1_PARMODE_NORMAL; + opt |= (ISSET(t->c_cflag, PARODD) ? + CD180_COR1_ODDPAR : + CD180_COR1_EVENPAR); + } + else + opt |= CD180_COR1_PARMODE_NO; + + if (!ISSET(t->c_iflag, INPCK)) + opt |= CD180_COR1_IGNPAR; + + if (ISSET(t->c_cflag, CSTOPB)) + opt |= CD180_COR1_STOP2; + + switch (t->c_cflag & CSIZE) { + case CS5: + opt |= CD180_COR1_CS5; + break; + case CS6: + opt |= CD180_COR1_CS6; + break; + case CS7: + opt |= CD180_COR1_CS7; + break; + default: + opt |= CD180_COR1_CS8; + break; + } + STC_WRITE(sc, STC_COR1, opt); + stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG1); + + opt = CD180_COR2_ETC; + if (ISSET(t->c_cflag, CRTSCTS)) + opt |= CD180_COR2_CTSAE; + STC_WRITE(sc, STC_COR2, opt); + stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG2); + + STC_WRITE(sc, STC_COR3, STTY_RX_FIFO_THRESHOLD); + stty_write_ccr(sc, CD180_CCR_CMD_COR|CD180_CCR_CORCHG3); + + STC_WRITE(sc, STC_SCHR1, 0x11); + STC_WRITE(sc, STC_SCHR2, 0x13); + STC_WRITE(sc, STC_SCHR3, 0x11); + STC_WRITE(sc, STC_SCHR4, 0x13); + STC_WRITE(sc, STC_RTPR, 0x12); + + STC_WRITE(sc, STC_MCOR1, CD180_MCOR1_CDZD | STTY_RX_DTR_THRESHOLD); + STC_WRITE(sc, STC_MCOR2, CD180_MCOR2_CDOD); + STC_WRITE(sc, STC_MCR, 0); + + if (t->c_ospeed) { + STC_WRITE(sc, STC_TBPRH, tbprh); + STC_WRITE(sc, STC_TBPRL, tbprl); + } + + if (t->c_ispeed) { + STC_WRITE(sc, STC_RBPRH, rbprh); + STC_WRITE(sc, STC_RBPRL, rbprl); + } + + stty_write_ccr(sc, CD180_CCR_CMD_CHAN | + CD180_CCR_CHAN_TXEN | CD180_CCR_CHAN_RXEN); + + sp->sp_carrier = STC_READ(sc, STC_MSVR) & CD180_MSVR_CD; + + splx(s); + return (0); +} + +int +sttyread(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)]; + struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)]; + struct tty *tp = sp->sp_tty; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flags)); +} + +int +sttywrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)]; + struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)]; + struct tty *tp = sp->sp_tty; + + return ((*linesw[tp->t_line].l_write)(tp, uio, flags)); +} + +struct tty * +sttytty(dev) + dev_t dev; +{ + struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(dev)]; + struct stty_port *sp = &sc->sc_port[SPIF_PORT(dev)]; + + return (sp->sp_tty); +} + +int +sttystop(tp, flags) + struct tty *tp; + int flags; +{ + struct stty_softc *sc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)]; + struct stty_port *sp = &sc->sc_port[SPIF_PORT(tp->t_dev)]; + int s; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY)) { + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + SET(sp->sp_flags, STTYF_STOP); + } + splx(s); + return (0); +} + +void +stty_start(tp) + struct tty *tp; +{ + struct stty_softc *stc = stty_cd.cd_devs[SPIF_CARD(tp->t_dev)]; + struct stty_port *sp = &stc->sc_port[SPIF_PORT(tp->t_dev)]; + struct spif_softc *sc = sp->sp_sc; + int s; + + s = spltty(); + + if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) { + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup(&tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + if (tp->t_outq.c_cc) { + sp->sp_txc = ndqb(&tp->t_outq, 0); + sp->sp_txp = tp->t_outq.c_cf; + SET(tp->t_state, TS_BUSY); + STC_WRITE(sc, STC_CAR, sp->sp_channel); + STC_WRITE(sc, STC_SRER, + STC_READ(sc, STC_SRER) | CD180_SRER_TXD); + } + } + + splx(s); +} + +int +spifstcintr_rxexception(sc, needsoftp) + struct spif_softc *sc; + int *needsoftp; +{ + struct stty_port *sp; + u_int8_t channel, *ptr; + int cnt; + + channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1)); + sp = &sc->sc_ttys->sc_port[channel]; + ptr = sp->sp_rput; + *ptr++ = STC_READ(sc, STC_RCSR); + *ptr++ = STC_READ(sc, STC_RDR); + if (ptr == sp->sp_rend) + ptr = sp->sp_rbuf; + if (ptr == sp->sp_rget) { + if (ptr == sp->sp_rbuf) + ptr = sp->sp_rend; + ptr -= 2; + SET(sp->sp_flags, STTYF_RING_OVERFLOW); + } + STC_WRITE(sc, STC_EOSRR, 0); + if (cnt) { + *needsoftp = 1; + sp->sp_rput = ptr; + } + return (1); +} + +int +spifstcintr_rx(sc, needsoftp) + struct spif_softc *sc; + int *needsoftp; +{ + struct stty_port *sp; + u_int8_t channel, *ptr, cnt, rcsr; + int i; + + channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1)); + sp = &sc->sc_ttys->sc_port[channel]; + ptr = sp->sp_rput; + cnt = STC_READ(sc, STC_RDCR); + for (i = 0; i < cnt; i++) { + *ptr++ = 0; + rcsr = STC_READ(sc, STC_RCSR); + *ptr++ = STC_READ(sc, STC_RDR); + if (ptr == sp->sp_rend) + ptr = sp->sp_rbuf; + if (ptr == sp->sp_rget) { + if (ptr == sp->sp_rbuf) + ptr = sp->sp_rend; + ptr -= 2; + SET(sp->sp_flags, STTYF_RING_OVERFLOW); + break; + } + } + STC_WRITE(sc, STC_EOSRR, 0); + if (cnt) { + *needsoftp = 1; + sp->sp_rput = ptr; + } + return (1); +} + +int +spifstcintr_tx(sc, needsoftp) + struct spif_softc *sc; + int *needsoftp; +{ + struct stty_port *sp; + u_int8_t channel, ch; + int cnt = 0; + + channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1)); + sp = &sc->sc_ttys->sc_port[channel]; + if (!ISSET(sp->sp_flags, STTYF_STOP)) { + if (ISSET(sp->sp_flags, STTYF_SET_BREAK)) { + STC_WRITE(sc, STC_TDR, 0); + STC_WRITE(sc, STC_TDR, 0x81); + CLR(sp->sp_flags, STTYF_SET_BREAK); + cnt += 2; + } + if (ISSET(sp->sp_flags, STTYF_CLR_BREAK)) { + STC_WRITE(sc, STC_TDR, 0); + STC_WRITE(sc, STC_TDR, 0x83); + CLR(sp->sp_flags, STTYF_CLR_BREAK); + cnt += 2; + } + + while (sp->sp_txc > 0 && cnt < (CD180_TX_FIFO_SIZE-1)) { + ch = *sp->sp_txp; + sp->sp_txc--; + sp->sp_txp++; + + if (ch == 0) { + STC_WRITE(sc, STC_TDR, ch); + cnt++; + } + STC_WRITE(sc, STC_TDR, ch); + cnt++; + } + } + + if (sp->sp_txc == 0 || + ISSET(sp->sp_flags, STTYF_STOP)) { + STC_WRITE(sc, STC_SRER, STC_READ(sc, STC_SRER) & + (~CD180_SRER_TXD)); + CLR(sp->sp_flags, STTYF_STOP); + SET(sp->sp_flags, STTYF_DONE); + *needsoftp = 1; + } + + STC_WRITE(sc, STC_EOSRR, 0); + + return (1); +} + +int +spifstcintr_mx(sc, needsoftp) + struct spif_softc *sc; + int *needsoftp; +{ + struct stty_port *sp; + u_int8_t channel, mcr; + + channel = CD180_GSCR_CHANNEL(STC_READ(sc, STC_GSCR1)); + sp = &sc->sc_ttys->sc_port[channel]; + mcr = STC_READ(sc, STC_MCR); + if (mcr & CD180_MCR_CD) { + SET(sp->sp_flags, STTYF_CDCHG); + *needsoftp = 1; + } + STC_WRITE(sc, STC_MCR, 0); + STC_WRITE(sc, STC_EOSRR, 0); + return (1); +} + +int +spifstcintr(vsc) + void *vsc; +{ + struct spif_softc *sc = (struct spif_softc *)vsc; + int needsoft = 0, r = 0, i; + u_int8_t ar; + + for (i = 0; i < 8; i++) { + ar = ISTC_READ(sc, STC_RRAR) & CD180_GSVR_IMASK; + if (ar == CD180_GSVR_RXGOOD) + r |= spifstcintr_rx(sc, &needsoft); + else if (ar == CD180_GSVR_RXEXCEPTION) + r |= spifstcintr_rxexception(sc, &needsoft); + } + + for (i = 0; i < 8; i++) { + ar = ISTC_READ(sc, STC_TRAR) & CD180_GSVR_IMASK; + if (ar == CD180_GSVR_TXDATA) + r |= spifstcintr_tx(sc, &needsoft); + } + + for (i = 0; i < 8; i++) { + ar = ISTC_READ(sc, STC_MRAR) & CD180_GSVR_IMASK; + if (ar == CD180_GSVR_STATCHG) + r |= spifstcintr_mx(sc, &needsoft); + } + + if (needsoft) + softintr_schedule(sc->sc_softih); + return (r); +} + +void +spifsoftintr(vsc) + void *vsc; +{ + struct spif_softc *sc = (struct spif_softc *)vsc; + struct stty_softc *stc = sc->sc_ttys; + int r = 0, i, data, s, flags; + u_int8_t stat, msvr; + struct stty_port *sp; + struct tty *tp; + + if (stc != NULL) { + for (i = 0; i < stc->sc_nports; i++) { + sp = &stc->sc_port[i]; + tp = sp->sp_tty; + + if (!ISSET(tp->t_state, TS_ISOPEN)) + continue; + + while (sp->sp_rget != sp->sp_rput) { + stat = sp->sp_rget[0]; + data = sp->sp_rget[1]; + sp->sp_rget += 2; + if (sp->sp_rget == sp->sp_rend) + sp->sp_rget = sp->sp_rbuf; + + if (stat & (CD180_RCSR_BE | CD180_RCSR_FE)) + data |= TTY_FE; + + if (stat & CD180_RCSR_PE) + data |= TTY_PE; + + (*linesw[tp->t_line].l_rint)(data, tp); + r = 1; + } + + s = splhigh(); + flags = sp->sp_flags; + CLR(sp->sp_flags, STTYF_DONE | STTYF_CDCHG | + STTYF_RING_OVERFLOW); + splx(s); + + if (ISSET(flags, STTYF_CDCHG)) { + s = spltty(); + STC_WRITE(sc, STC_CAR, i); + msvr = STC_READ(sc, STC_MSVR); + splx(s); + + sp->sp_carrier = msvr & CD180_MSVR_CD; + (*linesw[tp->t_line].l_modem)(tp, + sp->sp_carrier); + r = 1; + } + + if (ISSET(flags, STTYF_RING_OVERFLOW)) { + log(LOG_WARNING, "%s-%x: ring overflow\n", + stc->sc_dev.dv_xname, i); + r = 1; + } + + if (ISSET(flags, STTYF_DONE)) { + ndflush(&tp->t_outq, + sp->sp_txp - tp->t_outq.c_cf); + CLR(tp->t_state, TS_BUSY); + (*linesw[tp->t_line].l_start)(tp); + r = 1; + } + } + } +} + +void +stty_write_ccr(sc, val) + struct spif_softc *sc; + u_int8_t val; +{ + int tries = 100000; + + while (STC_READ(sc, STC_CCR) && tries--) + /*EMPTY*/; + if (tries == 0) + printf("%s: ccr timeout\n", sc->sc_dev.dv_xname); + STC_WRITE(sc, STC_CCR, val); +} + +int +stty_compute_baud(speed, clock, bprlp, bprhp) + speed_t speed; + int clock; + u_int8_t *bprlp, *bprhp; +{ + u_int32_t rate; + + rate = (2 * clock) / (16 * speed); + if (rate & 1) + rate = (rate >> 1) + 1; + else + rate = rate >> 1; + + if (rate > 0xffff || rate == 0) + return (1); + + *bprlp = rate & 0xff; + *bprhp = (rate >> 8) & 0xff; + return (0); +} + +int +sbppmatch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct spif_softc *sc = (struct spif_softc *)parent; + + return (aux == sbppmatch && sc->sc_bpps == NULL); +} + +void +sbppattach(parent, dev, aux) + struct device *parent, *dev; + void *aux; +{ + struct spif_softc *sc = (struct spif_softc *)parent; + struct sbpp_softc *psc = (struct sbpp_softc *)dev; + int port; + + sc->sc_bpps = psc; + + for (port = 0; port < sc->sc_npar; port++) { + } + + psc->sc_nports = port; + printf(": %d port%s\n", port, port == 1 ? "" : "s"); +} + +int +sbppopen(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + return (ENXIO); +} + +int +sbppclose(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + return (ENXIO); +} + +int +spifppcintr(v) + void *v; +{ + return (0); +} + +int +sbppread(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + return (sbpp_rw(dev, uio)); +} + +int +sbppwrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + return (sbpp_rw(dev, uio)); +} + +int +sbpp_rw(dev, uio) + dev_t dev; + struct uio *uio; +{ + return (ENXIO); +} + +int +sbppselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; +{ + return (ENODEV); +} + +int +sbppioctl(dev, cmd, data, flags, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + int error; + + error = ENOTTY; + + return (error); +} diff --git a/sys/dev/sbus/spifreg.h b/sys/dev/sbus/spifreg.h new file mode 100644 index 00000000000..1bf5d44b7fe --- /dev/null +++ b/sys/dev/sbus/spifreg.h @@ -0,0 +1,380 @@ +/* $OpenBSD: spifreg.h,v 1.1 2002/01/13 02:06:46 jason Exp $ */ + +/* + * Copyright (c) 1999-2002 Jason L. Wright (jason@thought.net) + * 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 Jason L. Wright + * 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. + */ + +#define PPC_IN_PDATA 0x000 /* input data */ +#define PPC_IN_PSTAT 0x001 /* input status */ +#define PPC_IN_CTRL 0x002 /* input control */ +#define PPC_IN_PWEIRD 0x003 /* input weird */ +#define PPC_OUT_PDATA 0x000 /* output data */ +#define PPC_OUT_PSTAT 0x001 /* output status */ +#define PPC_OUT_PCTRL 0x002 /* output control */ +#define PPC_OUT_PWEIRD 0x003 /* output weird */ +#define PPC_IACK_PDATA 0x1fc /* iack data */ +#define PPC_IACK_PSTAT 0x1fd /* iack status */ +#define PPC_IACK_PCTRL 0x1fe /* iack control */ +#define PPC_IACK_PWEIRD 0x1ff /* iack weird */ + +/* Parallel Status: read only */ +#define PPC_PSTAT_ERROR 0x08 /* error */ +#define PPC_PSTAT_SELECT 0x10 /* select */ +#define PPC_PSTAT_PAPER 0x20 /* paper out */ +#define PPC_PSTAT_ACK 0x40 /* ack */ +#define PPC_PSTAT_BUSY 0x80 /* busy */ + +/* Parallel Control: read/write */ +#define PPC_CTRL_STROBE 0x01 /* strobe, 1=drop strobe */ +#define PPC_CTRL_AFX 0x02 /* auto form-feed */ +#define PPC_CTRL_INIT 0x04 /* init, 1=enable printer */ +#define PPC_CTRL_SLCT 0x08 /* SLC, 1=select printer */ +#define PPC_CTRL_IRQE 0x10 /* IRQ, 1=enable intrs */ +#define PPC_CTRL_OUTPUT 0x20 /* direction: 1=ppc out */ + +/* + * The 'stc' is a Cirrus Logic CL-CD180 (either revision B or revision C) + */ +#define STC_CCR 0x01 /* channel command */ +#define STC_SRER 0x02 /* service request enable */ +#define STC_COR1 0x03 /* channel option 1 */ +#define STC_COR2 0x04 /* channel option 2 */ +#define STC_COR3 0x05 /* channel option 3 */ +#define STC_CCSR 0x06 /* channel control status */ +#define STC_RDCR 0x07 /* rx data count */ +#define STC_SCHR1 0x09 /* special character 1 */ +#define STC_SCHR2 0x0a /* special character 2 */ +#define STC_SCHR3 0x0b /* special character 3 */ +#define STC_SCHR4 0x0c /* special character 4 */ +#define STC_MCOR1 0x10 /* modem change option 1 */ +#define STC_MCOR2 0x11 /* modem change option 2 */ +#define STC_MCR 0x12 /* modem change */ +#define STC_RTPR 0x18 /* rx timeout period */ +#define STC_MSVR 0x28 /* modem signal value */ +#define STC_MSVRTS 0x29 /* modem signal value rts */ +#define STC_MSVDTR 0x2a /* modem signal value dtr */ +#define STC_RBPRH 0x31 /* rx bit rate period high */ +#define STC_RBPRL 0x32 /* rx bit rate period low */ +#define STC_RBR 0x33 /* rx bit */ +#define STC_TBPRH 0x39 /* tx bit rate period high */ +#define STC_TBPRL 0x3a /* tx bit rate period low */ +#define STC_GSVR 0x40 /* global service vector */ +#define STC_GSCR1 0x41 /* global service channel 1 */ +#define STC_GSCR2 0x42 /* global service channel 2 */ +#define STC_GSCR3 0x43 /* global service channel 3 */ +#define STC_MSMR 0x61 /* modem service match */ +#define STC_TSMR 0x62 /* tx service match */ +#define STC_RSMR 0x63 /* rx service match */ +#define STC_CAR 0x64 /* channel access */ +#define STC_SRSR 0x65 /* service request status */ +#define STC_SRCR 0x66 /* service request config */ +#define STC_GFRCR 0x6b /* global firmware rev code */ +#define STC_PPRH 0x70 /* prescalar period high */ +#define STC_PPRL 0x71 /* prescalar period low */ +#define STC_MRAR 0x75 /* modem request ack */ +#define STC_TRAR 0x76 /* tx request ack */ +#define STC_RRAR 0x77 /* rx request ack */ +#define STC_RDR 0x78 /* rx data */ +#define STC_RCSR 0x7a /* rx character status */ +#define STC_TDR 0x7b /* tx data */ +#define STC_EOSRR 0x7f /* end of service */ + +#define STC_REGMAPSIZE 0x80 + +/* Global Firmware Revision Code Register (rw) */ +#define CD180_GFRCR_REV_B 0x81 /* CL-CD180B */ +#define CD180_GFRCR_REV_C 0x82 /* CL-CD180C */ + +/* Service Request Configuration Register (rw) (CD180C or higher) */ +#define CD180_SRCR_PKGTYP 0x80 /* pkg type,0=PLCC,1=PQFP */ +#define CD180_SRCR_REGACKEN 0x40 /* register ack enable */ +#define CD180_SRCR_DAISYEN 0x20 /* daisy chain enable */ +#define CD180_SRCR_GLOBPRI 0x10 /* global priority */ +#define CD180_SRCR_UNFAIR 0x08 /* use unfair interrupts */ +#define CD180_SRCR_AUTOPRI 0x02 /* automatic priority */ +#define CD180_SRCR_PRISEL 0x01 /* select rx/tx as high pri */ + +/* Prescalar Period Register High (rw) */ +#define CD180_PPRH 0xf0 /* high byte */ +#define CD180_PPRL 0x00 /* low byte */ + +/* Global Service Vector Register (rw) */ +/* Modem Request Acknowledgement Register (ro) (and IACK equivalent) */ +/* Receive Request Acknowledgement Register (ro) (and IACK equivalent) */ +/* Transmit Request Acknowledgement Register (ro) (and IACK equivalent) */ +#define CD180_GSVR_USERMASK 0xf8 /* user defined bits */ +#define CD180_GSVR_IMASK 0x07 /* interrupt type mask */ +#define CD180_GSVR_NOREQUEST 0x00 /* no request pending */ +#define CD180_GSVR_STATCHG 0x01 /* modem signal change */ +#define CD180_GSVR_TXDATA 0x02 /* tx service request */ +#define CD180_GSVR_RXGOOD 0x03 /* rx service request */ +#define CD180_GSVR_reserved1 0x04 /* reserved */ +#define CD180_GSVR_reserved2 0x05 /* reserved */ +#define CD180_GSVR_reserved3 0x06 /* reserved */ +#define CD180_GSVR_RXEXCEPTION 0x07 /* rx exception request */ + +/* Service Request Status Register (ro) (CD180C and higher) */ +#define CD180_SRSR_MREQINT 0x01 /* modem request internal */ +#define CD180_SRSR_MREQEXT 0x02 /* modem request external */ +#define CD180_SRSR_TREQINT 0x04 /* tx request internal */ +#define CD180_SRSR_TREQEXT 0x08 /* tx request external */ +#define CD180_SRSR_RREQINT 0x10 /* rx request internal */ +#define CD180_SRSR_RREQEXT 0x20 /* rx request external */ +#define CD180_SRSR_ILV_MASK 0xc0 /* internal service context */ +#define CD180_SRSR_ILV_NONE 0x00 /* not in service context */ +#define CD180_SRSR_ILV_RX 0xc0 /* in rx service context */ +#define CD180_SRSR_ILV_TX 0x80 /* in tx service context */ +#define CD180_SRSR_ILV_MODEM 0x40 /* in modem service context */ + +/* Global Service Channel Register 1,2,3 (rw) */ +#define CD180_GSCR_CHANNEL(gscr) (((gscr) >> 2) & 7) + +/* Receive Data Count Register (ro) */ +#define CD180_RDCR_MASK 0x0f /* mask for fifo length */ + +/* Receive Character Status Register (ro) */ +#define CD180_RCSR_TO 0x80 /* time out */ +#define CD180_RCSR_SCD2 0x40 /* special char detect 2 */ +#define CD180_RCSR_SCD1 0x20 /* special char detect 1 */ +#define CD180_RCSR_SCD0 0x10 /* special char detect 0 */ +#define CD180_RCSR_BE 0x08 /* break exception */ +#define CD180_RCSR_PE 0x04 /* parity exception */ +#define CD180_RCSR_FE 0x02 /* framing exception */ +#define CD180_RCSR_OE 0x01 /* overrun exception */ + +/* Service Request Enable Register (rw) */ +#define CD180_SRER_DSR 0x80 /* DSR service request */ +#define CD180_SRER_CD 0x40 /* CD service request */ +#define CD180_SRER_CTS 0x20 /* CTS service request */ +#define CD180_SRER_RXD 0x10 /* RXD service request */ +#define CD180_SRER_RXSCD 0x08 /* RX special char request */ +#define CD180_SRER_TXD 0x04 /* TX ready service request */ +#define CD180_SRER_TXE 0x02 /* TX empty service request */ +#define CD180_SRER_NNDT 0x01 /* No new data timeout req */ + +/* Channel Command Register (rw) */ +/* Reset Channel Command */ +#define CD180_CCR_CMD_RESET 0x80 /* chip/channel reset */ +#define CD180_CCR_RESETALL 0x01 /* global reset */ +#define CD180_CCR_RESETCHAN 0x00 /* current channel reset */ +/* Channel Option Register Command */ +#define CD180_CCR_CMD_COR 0x40 /* channel opt reg changed */ +#define CD180_CCR_CORCHG1 0x02 /* cor1 has changed */ +#define CD180_CCR_CORCHG2 0x04 /* cor2 has changed */ +#define CD180_CCR_CORCHG3 0x08 /* cor3 has changed */ +/* Send Special Character Command */ +#define CD180_CCR_CMD_SPC 0x20 /* send special chars changed */ +#define CD180_CCR_SSPC0 0x01 /* send special char 0 change */ +#define CD180_CCR_SSPC1 0x02 /* send special char 1 change */ +#define CD180_CCR_SSPC2 0x04 /* send special char 2 change */ +/* Channel Control Command */ +#define CD180_CCR_CMD_CHAN 0x10 /* channel control command */ +#define CD180_CCR_CHAN_TXEN 0x08 /* enable channel tx */ +#define CD180_CCR_CHAN_TXDIS 0x04 /* disable channel tx */ +#define CD180_CCR_CHAN_RXEN 0x02 /* enable channel rx */ +#define CD180_CCR_CHAN_RXDIS 0x01 /* disable channel rx */ + +/* Channel Option Register 1 (rw) */ +#define CD180_COR1_EVENPAR 0x00 /* even parity */ +#define CD180_COR1_ODDPAR 0x80 /* odd parity */ +#define CD180_COR1_PARMODE_NO 0x00 /* no parity */ +#define CD180_COR1_PARMODE_FORCE 0x20 /* force (odd=1, even=0) */ +#define CD180_COR1_PARMODE_NORMAL 0x40 /* normal parity mode */ +#define CD180_COR1_PARMODE_NA 0x60 /* notused */ +#define CD180_COR1_IGNPAR 0x10 /* ignore parity */ +#define CD180_COR1_STOP1 0x00 /* 1 stop bit */ +#define CD180_COR1_STOP15 0x04 /* 1.5 stop bits */ +#define CD180_COR1_STOP2 0x08 /* 2 stop bits */ +#define CD180_COR1_STOP25 0x0c /* 2.5 stop bits */ +#define CD180_COR1_CS5 0x00 /* 5 bit characters */ +#define CD180_COR1_CS6 0x01 /* 6 bit characters */ +#define CD180_COR1_CS7 0x02 /* 7 bit characters */ +#define CD180_COR1_CS8 0x03 /* 8 bit characters */ + +/* Channel Option Register 2 (rw) */ +#define CD180_COR2_IXM 0x80 /* implied xon mode */ +#define CD180_COR2_TXIBE 0x40 /* tx in-band flow control */ +#define CD180_COR2_ETC 0x20 /* embedded tx command enbl */ +#define CD180_COR2_LLM 0x10 /* local loopback mode */ +#define CD180_COR2_RLM 0x08 /* remote loopback mode */ +#define CD180_COR2_RTSAO 0x04 /* RTS automatic output enbl */ +#define CD180_COR2_CTSAE 0x02 /* CTS automatic enable */ +#define CD180_COR2_DSRAE 0x01 /* DSR automatic enable */ + +/* Channel Option Register 3 (rw) */ +#define CD180_COR3_XON2 0x80 /* XON char in spc1&3 */ +#define CD180_COR3_XON1 0x00 /* XON char in spc1 */ +#define CD180_COR3_XOFF2 0x40 /* XOFF char in spc2&4 */ +#define CD180_COR3_XOFF1 0x00 /* XOFF char in spc2 */ +#define CD180_COR3_FCT 0x20 /* flow control transparency */ +#define CD180_COR3_SCDE 0x10 /* special char recognition */ +#define CD180_COR3_RXFIFO_MASK 0x0f /* rx fifo threshold */ + +/* Channel Control Status Register (ro) */ +#define CD180_CCSR_RXEN 0x80 /* rx is enabled */ +#define CD180_CCSR_RXFLOFF 0x40 /* rx flow-off */ +#define CD180_CCSR_RXFLON 0x20 /* rx flow-on */ +#define CD180_CCSR_TXEN 0x08 /* tx is enabled */ +#define CD180_CCSR_TXFLOFF 0x04 /* tx flow-off */ +#define CD180_CCSR_TXFLON 0x02 /* tx flow-on */ + +/* Receiver Bit Register (ro) */ +#define CD180_RBR_RXD 0x40 /* state of RxD pin */ +#define CD180_RBR_STARTHUNT 0x20 /* looking for start bit */ + +/* Modem Change Register (rw) */ +#define CD180_MCR_DSR 0x80 /* DSR changed */ +#define CD180_MCR_CD 0x40 /* CD changed */ +#define CD180_MCR_CTS 0x20 /* CTS changed */ + +/* Modem Change Option Register 1 (rw) */ +#define CD180_MCOR1_DSRZD 0x80 /* catch 0->1 DSR changes */ +#define CD180_MCOR1_CDZD 0x40 /* catch 0->1 CD changes */ +#define CD180_MCOR1_CTSZD 0x40 /* catch 0->1 CTS changes */ +#define CD180_MCOR1_DTRTHRESH 0x0f /* DTR threshold mask */ + +/* Modem Change Option Register 2 (rw) */ +#define CD180_MCOR2_DSROD 0x80 /* catch 1->0 DSR changes */ +#define CD180_MCOR2_CDOD 0x40 /* catch 1->0 CD changes */ +#define CD180_MCOR2_CTSOD 0x20 /* catch 1->0 CTS changes */ + +/* Modem Signal Value Register (rw) */ +#define CD180_MSVR_DSR 0x80 /* DSR input state */ +#define CD180_MSVR_CD 0x40 /* CD input state */ +#define CD180_MSVR_CTS 0x20 /* CTS input state */ +#define CD180_MSVR_DTR 0x02 /* DTR output state */ +#define CD180_MSVR_RTS 0x01 /* RTS output state */ + +/* Modem Signal Value Register - Request To Send (w) (CD180C and higher) */ +#define CD180_MSVRTS_RTS 0x01 /* RTS signal value */ + +/* Modem Signal Value Register - Data Terminal Ready (w) (CD180C and higher) */ +#define CD180_MSVDTR_DTR 0x02 /* DTR signal value */ + +/* + * The register map for the SUNW,spif looks something like: + * Offset: Function: + * 0000 - 03ff Boot ROM + * 0400 - 0407 dtr latches (one per port) + * 0409 - 07ff unused + * 0800 - 087f CD180 registers (normal mapping) + * 0880 - 0bff unused + * 0c00 - 0c7f CD180 registers (*iack mapping) + * 0c80 - 0dff unused + * 0e00 - 1fff PPC registers + * + * One note about the DTR latches: The values stored there are reversed. + * By writing a 1 to the latch, DTR is lowered, and by writing a 0, DTR + * is raised. The latches cannot be read, and no other value can be written + * there or the system will crash due to "excessive bus loading (see + * SBus loading and capacitance spec)" + * + * The *iack registers are read/written with the IACK bit set. When + * the interrupt routine starts, it reads the MRAR, TRAR, and RRAR registers + * from this mapping. This signals an interrupt acknowlegement cycle. + * (NOTE: these are not really the MRAR, TRAR, and RRAR... They are copies + * of the GSVR, I just mapped them to the same location as the mrar, trar, + * and rrar because it seemed appropriate). + */ +#define DTR_REG_OFFSET 0x400 /* DTR latches */ +#define DTR_REG_LEN 0x8 +#define STC_REG_OFFSET 0x800 /* normal cd180 access */ +#define STC_REG_LEN 0x80 +#define ISTC_REG_OFFSET 0xc00 /* IACK cd180 access */ +#define ISTC_REG_LEN STC_REG_LEN +#define PPC_REG_OFFSET 0xe00 /* PPC registers */ +#define PPC_REG_LEN 0x200 + +/* + * The mapping of minor device number -> card and port is done as + * follows by default: + * + * +---+---+---+---+---+---+---+---+ + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +---+---+---+---+---+---+---+---+ + * | | | | | | | | + * | | | | | +---+---+---> port number + * | | | | | + * | | | | +---------------> unused + * | | | | + * | | | +-------------------> dialout (on tty ports) + * | | | + * | | +-----------------------> unused + * | | + * +---+---------------------------> card number + * + */ +#define SPIF_MAX_CARDS 4 +#define SPIF_MAX_TTY 8 +#define SPIF_MAX_BPP 1 + +/* + * device selectors + */ +#define SPIF_CARD(x) ((minor(x) >> 6) & 0x03) +#define SPIF_PORT(x) (minor(x) & 0x07) +#define STTY_DIALOUT(x) (minor(x) & 0x10) + +#define STTY_RX_FIFO_THRESHOLD 4 +#define STTY_RX_DTR_THRESHOLD 7 +#define CD180_TX_FIFO_SIZE 8 /* 8 chars of fifo */ + +/* + * These are the offsets of the MRAR, TRAR, and RRAR in *IACK space. + * The high bit must be set as per specs for the MSMR, TSMR, and RSMR. + */ +#define SPIF_MSMR (0x80 | STC_MRAR) /* offset of MRAR | 0x80 */ +#define SPIF_TSMR (0x80 | STC_TRAR) /* offset of TRAR | 0x80 */ +#define SPIF_RSMR (0x80 | STC_RRAR) /* offset of RRAR | 0x80 */ + +/* + * "verosc" node tells which oscillator we have. + */ +#define SPIF_OSC9 1 /* 9.8304 Mhz */ +#define SPIF_OSC10 2 /* 10Mhz */ + +/* + * There are two interrupts, serial gets interrupt[0], and parallel + * gets interrupt[1] + */ +#define SERIAL_INTR 0 +#define PARALLEL_INTR 1 + +/* + * spif tty flags + */ +#define STTYF_CDCHG 0x01 /* carrier changed */ +#define STTYF_RING_OVERFLOW 0x02 /* ring buffer overflowed */ +#define STTYF_DONE 0x04 /* done... flush buffers */ +#define STTYF_SET_BREAK 0x08 /* set break signal */ +#define STTYF_CLR_BREAK 0x10 /* clear break signal */ +#define STTYF_STOP 0x20 /* stopped */ + +#define STTY_RBUF_SIZE (2 * 512) diff --git a/sys/dev/sbus/spifvar.h b/sys/dev/sbus/spifvar.h new file mode 100644 index 00000000000..54fe9ae6d1b --- /dev/null +++ b/sys/dev/sbus/spifvar.h @@ -0,0 +1,87 @@ +/* $OpenBSD: spifvar.h,v 1.1 2002/01/13 02:06:46 jason Exp $ */ + +/* + * Copyright (c) 1999-2002 Jason L. Wright (jason@thought.net) + * 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 Jason L. Wright + * 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. + */ + +#define SPIF_MAX_SERIAL 8 +#define SPIF_MAX_PARALLEL 1 + +struct stty_port { + struct tty *sp_tty; /* tty device */ + struct spif_softc *sp_sc; /* pointer back to registers */ + int sp_channel; /* channel number */ + u_char *sp_rbuf; /* ring buffer start */ + u_char *sp_rend; /* ring buffer end */ + u_char *sp_rget; /* ring buffer read pointer */ + u_char *sp_rput; /* ring buffer write pointer */ + u_char *sp_txp; /* transmit character pointer */ + int sp_txc; /* transmit character counter */ + + int sp_openflags; /* open flags */ + int sp_carrier; /* software carrier status */ + int sp_flags; /* software state */ + char sp_dtr; /* software dtr status */ +}; + +struct stty_softc { + struct device sc_dev; /* base device */ + int sc_nports; /* number of serial ports */ + struct stty_port sc_port[SPIF_MAX_SERIAL]; +}; + +struct sbpp_softc { + struct device sc_dev; /* base device */ + int sc_nports; /* number of parallel ports */ +}; + +struct spif_softc { + struct device sc_dev; /* base device */ + struct sbusdev sc_sd; /* sbus device */ + void *sc_stcih; /* stc interrupt vector */ + void *sc_ppcih; /* ppc interrut vector */ + void *sc_softih; /* soft interrupt vector */ + int sc_rev; /* revision level */ + int sc_osc; /* oscillator speed (hz) */ + int sc_node; /* which sbus node */ + int sc_nser; /* number of serial ports */ + int sc_npar; /* number of parallel ports */ + int sc_rev2; /* cd180 chip revision */ + bus_space_tag_t sc_bustag; /* our bus tag */ + bus_space_handle_t sc_regh; /* whole register map */ + bus_space_handle_t sc_stch; /* STC registers */ + bus_space_handle_t sc_istch; /* IACK STC registers */ + bus_space_handle_t sc_dtrh; /* DTR registers */ + bus_space_handle_t sc_ppch; /* PPC registers */ + struct spifregs *sc_regs; /* registers */ + struct stty_softc *sc_ttys; /* our ttys */ + struct sbpp_softc *sc_bpps; /* our ttys */ +}; + |