Add cduart(4), a driver for the Cadence UART found on Xilinx Zynq SoCs.
authorvisa <visa@openbsd.org>
Sat, 24 Apr 2021 07:49:11 +0000 (07:49 +0000)
committervisa <visa@openbsd.org>
Sat, 24 Apr 2021 07:49:11 +0000 (07:49 +0000)
Tested on Xilinx Zynq-7000.

Input and OK kettenis@

share/man/man4/Makefile
share/man/man4/cduart.4 [new file with mode: 0644]
sys/arch/armv7/armv7/platform.c
sys/arch/armv7/conf/GENERIC
sys/arch/armv7/conf/RAMDISK
sys/dev/fdt/cduart.c [new file with mode: 0644]
sys/dev/fdt/files.fdt

index 0edb314..734737c 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.795 2021/04/24 05:16:27 jsg Exp $
+#      $OpenBSD: Makefile,v 1.796 2021/04/24 07:49:11 visa Exp $
 
 MAN=   aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 acrtc.4 \
        acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \
@@ -23,7 +23,8 @@ MAN=  aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 acrtc.4 \
        bcmtmon.4 bdpmic.4 \
        berkwdt.4 bge.4 bgw.4 bio.4 bpe.4 bktr.4 bmtphy.4 bnx.4 bnxt.4 \
        boca.4 bpf.4 brgphy.4 bridge.4 brswphy.4 bse.4 bwfm.4 bwi.4 bytgpio.4 \
-       cac.4 cas.4 cardbus.4 carp.4 ccp.4 ccpmic.4 cd.4 cdce.4 cfxga.4 \
+       cac.4 cas.4 cardbus.4 carp.4 ccp.4 ccpmic.4 cd.4 cdce.4 \
+       cduart.4 cfxga.4 \
        ch.4 chvgpio.4 ciphy.4 ciss.4 clcs.4 clct.4 cmpci.4 \
        com.4 cue.4 cwfg.4 cy.4 cz.4 \
        dc.4 dcphy.4 ddb.4 de.4 diskmap.4 divert.4 drm.4 dsxrtc.4 dt.4 \
diff --git a/share/man/man4/cduart.4 b/share/man/man4/cduart.4
new file mode 100644 (file)
index 0000000..9d330d2
--- /dev/null
@@ -0,0 +1,36 @@
+.\"    $OpenBSD: cduart.4,v 1.1 2021/04/24 07:49:11 visa Exp $
+.\"
+.\" Copyright (c) 2021 Visa Hankala
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: April 24 2021 $
+.Dt CDUART 4
+.Os
+.Sh NAME
+.Nm cduart
+.Nd Cadence Universal Asynchronous Receiver/Transmitter
+.Sh SYNOPSIS
+.Cd "cduart* at fdt?"
+.Sh DESCRIPTION
+The
+.Nm
+driver supports the Cadence Universal Asynchronous
+Receiver/Transmitter (UART).
+.Sh SEE ALSO
+.Xr tty 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 7.0 .
index 650886e..1916673 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: platform.c,v 1.25 2021/03/25 04:12:01 jsg Exp $       */
+/*     $OpenBSD: platform.c,v 1.26 2021/04/24 07:49:11 visa Exp $      */
 /*
  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
  *
@@ -30,6 +30,7 @@ static struct armv7_platform *platform;
 
 void   agtimer_init(void);
 
+extern void    cduart_init_cons(void);
 extern void    exuart_init_cons(void);
 extern void    imxuart_init_cons(void);
 extern void    com_fdt_init_cons(void);
@@ -87,6 +88,7 @@ platform_init_cons(void)
                platform->init_cons();
                return;
        }
+       cduart_init_cons();
        exuart_init_cons();
        imxuart_init_cons();
        com_fdt_init_cons();
index 3bf925a..b0a969a 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.134 2021/02/04 16:25:39 anton Exp $
+#      $OpenBSD: GENERIC,v 1.135 2021/04/24 07:49:11 visa Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -211,6 +211,9 @@ iic*                at rkiic?
 rktemp*                at fdt?
 dwdog*         at fdt?
 
+# Xilinx Zynq-7000
+cduart*                at fdt?
+
 # I2C devices
 abcrtc*                at iic?                 # Abracon x80x RTC
 axppmic*       at iic?                 # axp209 pmic
index eedd98a..5fd7918 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: RAMDISK,v 1.120 2021/03/11 07:57:18 deraadt Exp $
+#      $OpenBSD: RAMDISK,v 1.121 2021/04/24 07:49:11 visa Exp $
 
 machine                armv7 arm
 
@@ -196,6 +196,9 @@ rkiic*              at fdt?
 iic*           at rkiic?
 dwdog*         at fdt?
 
+# Xilinx Zynq-7000
+cduart*                at fdt?
+
 axppmic*       at iic?                 # axp209 pmic
 crosec*                at iic?
 wskbd*         at crosec? mux 1
diff --git a/sys/dev/fdt/cduart.c b/sys/dev/fdt/cduart.c
new file mode 100644 (file)
index 0000000..8e28d60
--- /dev/null
@@ -0,0 +1,703 @@
+/*     $OpenBSD: cduart.c,v 1.1 2021/04/24 07:49:11 visa Exp $ */
+
+/*
+ * Copyright (c) 2021 Visa Hankala
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Driver for Cadence UART.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/fcntl.h>
+#include <sys/tty.h>
+#include <sys/syslog.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/cons.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
+#define CDUART_CR                      0x0000
+#define  CDUART_CR_STOPBRK                     (1 << 8)
+#define  CDUART_CR_STARTBRK                    (1 << 7)
+#define  CDUART_CR_TORST                       (1 << 6)
+#define  CDUART_CR_TXDIS                       (1 << 5)
+#define  CDUART_CR_TXEN                                (1 << 4)
+#define  CDUART_CR_RXDIS                       (1 << 3)
+#define  CDUART_CR_RXEN                                (1 << 2)
+#define  CDUART_CR_TXRST                       (1 << 1)
+#define  CDUART_CR_RXRST                       (1 << 0)
+#define CDUART_MR                      0x0004
+#define  CDUART_MR_CHMODE_MASK                 (0x3 << 8)
+#define  CDUART_MR_NBSTOP_MASK                 (0x3 << 6)
+#define  CDUART_MR_PAR_MASK                    (0x7 << 3)
+#define  CDUART_MR_PAR_NO                      (0x4 << 3)
+#define  CDUART_MR_PAR_FORCED1                 (0x3 << 3)
+#define  CDUART_MR_PAR_FORCED0                 (0x2 << 3)
+#define  CDUART_MR_PAR_ODD                     (0x1 << 3)
+#define  CDUART_MR_PAR_EVEN                    (0x0 << 3)
+#define  CDUART_MR_CHRL_MASK                   (0x3 << 1)
+#define  CDUART_MR_CHRL_C6                     (0x3 << 1)
+#define  CDUART_MR_CHRL_C7                     (0x2 << 1)
+#define  CDUART_MR_CHRL_C8                     (0x0 << 1)
+#define  CDUART_MR_CLKSEL                      (1 << 0)
+#define CDUART_IER                     0x0008
+#define CDUART_IDR                     0x000c
+#define CDUART_IMR                     0x0010
+#define CDUART_ISR                     0x0014
+#define  CDUART_ISR_TXOVR                      (1 << 12)
+#define  CDUART_ISR_TNFUL                      (1 << 11)
+#define  CDUART_ISR_TTRIG                      (1 << 10)
+#define  CDUART_IXR_DMS                                (1 << 9)
+#define  CDUART_IXR_TOUT                       (1 << 8)
+#define  CDUART_IXR_PARITY                     (1 << 7)
+#define  CDUART_IXR_FRAMING                    (1 << 6)
+#define  CDUART_IXR_RXOVR                      (1 << 5)
+#define  CDUART_IXR_TXFULL                     (1 << 4)
+#define  CDUART_IXR_TXEMPTY                    (1 << 3)
+#define  CDUART_IXR_RXFULL                     (1 << 2)
+#define  CDUART_IXR_RXEMPTY                    (1 << 1)
+#define  CDUART_IXR_RTRIG                      (1 << 0)
+#define CDUART_RXTOUT                  0x001c
+#define CDUART_RXWM                    0x0020
+#define CDUART_SR                      0x002c
+#define  CDUART_SR_TNFUL                       (1 << 14)
+#define  CDUART_SR_TTRIG                       (1 << 13)
+#define  CDUART_SR_FLOWDEL                     (1 << 12)
+#define  CDUART_SR_TACTIVE                     (1 << 11)
+#define  CDUART_SR_RACTIVE                     (1 << 10)
+#define  CDUART_SR_TXFULL                      (1 << 4)
+#define  CDUART_SR_TXEMPTY                     (1 << 3)
+#define  CDUART_SR_RXFULL                      (1 << 2)
+#define  CDUART_SR_RXEMPTY                     (1 << 1)
+#define  CDUART_SR_RXOVR                       (1 << 0)
+#define CDUART_FIFO                    0x0030
+
+#define CDUART_SPACE_SIZE              0x0048
+
+#define CDUART_FIFOSIZE                64
+#define CDUART_IBUFSIZE                128
+
+struct cduart_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+       void                    *sc_ih;
+       void                    *sc_si;
+
+       struct tty              *sc_tty;
+       uint8_t                 sc_cua;
+
+       struct timeout          sc_diag_tmo;
+       int                     sc_overflows;
+       int                     sc_floods;
+       int                     sc_errors;
+
+       int                     sc_ibufs[2][CDUART_IBUFSIZE];
+       int                     *sc_ibuf;
+       int                     *sc_ibufend;
+       int                     *sc_ibufp;
+};
+
+int    cduart_match(struct device *, void *, void *);
+void   cduart_attach(struct device *, struct device *, void *);
+void   cduart_diag(void *);
+int    cduart_intr(void *);
+void   cduart_softintr(void *);
+
+struct tty *cduarttty(dev_t);
+struct cduart_softc *cduart_sc(dev_t);
+
+int    cduartparam(struct tty *, struct termios *);
+void   cduartstart(struct tty *);
+
+int    cduartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t);
+void   cduartcnprobe(struct consdev *);
+void   cduartcninit(struct consdev *);
+int    cduartcngetc(dev_t);
+void   cduartcnputc(dev_t, int);
+void   cduartcnpollc(dev_t, int);
+
+cdev_decl(com);
+cdev_decl(cduart);
+
+const struct cfattach cduart_ca = {
+       sizeof(struct cduart_softc), cduart_match, cduart_attach
+};
+
+struct cfdriver cduart_cd = {
+       NULL, "cduart", DV_DULL
+};
+
+bus_space_tag_t        cduartconsiot;
+bus_space_handle_t cduartconsioh;
+int            cduartconsrate;
+tcflag_t       cduartconscflag;
+struct cdevsw  cduartdev = cdev_tty_init(3, cduart);
+
+#define DEVUNIT(x)     (minor(x) & 0x7f)
+#define DEVCUA(x)      (minor(x) & 0x80)
+
+static inline uint32_t
+cduart_read(struct cduart_softc *sc, uint32_t reg)
+{
+       return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
+}
+
+static inline void
+cduart_write(struct cduart_softc *sc, uint32_t reg, uint32_t val)
+{
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
+}
+
+void
+cduart_init_cons(void)
+{
+       struct fdt_reg reg;
+       void *node;
+
+       if ((node = fdt_find_cons("cdns,uart-r1p8")) == NULL &&
+           (node = fdt_find_cons("cdns,uart-r1p12")) == NULL)
+               return;
+       if (fdt_get_reg(node, 0, &reg) != 0)
+               return;
+
+       cduartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
+}
+
+int
+cduart_match(struct device *parent, void *match, void *aux)
+{
+       struct fdt_attach_args *faa = aux;
+
+       return OF_is_compatible(faa->fa_node, "cdns,uart-r1p8") ||
+           OF_is_compatible(faa->fa_node, "cdns,uart-r1p12");
+}
+
+void
+cduart_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct fdt_attach_args *faa = aux;
+       struct cduart_softc *sc = (struct cduart_softc *)self;
+       uint32_t cr, isr;
+       int maj;
+
+       if (faa->fa_nreg < 1) {
+               printf(": no registers\n");
+               return;
+       }
+
+       sc->sc_iot = faa->fa_iot;
+       if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+           faa->fa_reg[0].size, 0, &sc->sc_ioh) != 0) {
+               printf(": can't map registers\n");
+               return;
+       }
+
+       /* Disable all interrupts. */
+       cduart_write(sc, CDUART_IDR, ~0U);
+
+       /* Clear any pending interrupts. */
+       isr = cduart_read(sc, CDUART_ISR);
+       cduart_write(sc, CDUART_ISR, isr);
+
+       sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
+           cduart_intr, sc, sc->sc_dev.dv_xname);
+       if (sc->sc_ih == NULL) {
+               printf(": can't establish interrupt\n");
+               goto fail;
+       }
+
+       timeout_set(&sc->sc_diag_tmo, cduart_diag, sc);
+       sc->sc_si = softintr_establish(IPL_TTY, cduart_softintr, sc);
+       if (sc->sc_si == NULL) {
+               printf(": can't establish soft interrupt\n");
+               goto fail;
+       }
+
+       if (faa->fa_node == stdout_node) {
+               /* Locate the major number. */
+               for (maj = 0; maj < nchrdev; maj++) {
+                       if (cdevsw[maj].d_open == cduartopen)
+                               break;
+               }
+               KASSERT(maj < nchrdev);
+               cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
+               printf(": console");
+       }
+
+       /* Enable transmitter and receiver. */
+       cr = cduart_read(sc, CDUART_CR);
+       cr &= ~(CDUART_CR_TXDIS | CDUART_CR_RXDIS);
+       cr |= CDUART_CR_TXEN | CDUART_CR_RXEN;
+       cduart_write(sc, CDUART_CR, cr);
+
+       printf("\n");
+
+       return;
+
+fail:
+       if (sc->sc_si != NULL)
+               softintr_disestablish(sc->sc_si);
+       if (sc->sc_ih != NULL)
+               fdt_intr_disestablish(sc->sc_ih);
+       if (sc->sc_ioh != 0)
+               bus_space_unmap(sc->sc_iot, sc->sc_ioh, CDUART_SPACE_SIZE);
+}
+
+int
+cduart_intr(void *arg)
+{
+       struct cduart_softc *sc = arg;
+       struct tty *tp = sc->sc_tty;
+       int *ibufp;
+       uint32_t isr, sr;
+       int c, handled = 0;
+
+       if (tp == NULL)
+               return 0;
+
+       isr = cduart_read(sc, CDUART_ISR);
+       cduart_write(sc, CDUART_ISR, isr);
+
+       if ((isr & CDUART_IXR_TXEMPTY) && (tp->t_state & TS_BUSY)) {
+               tp->t_state &= ~TS_BUSY;
+               (*linesw[tp->t_line].l_start)(tp);
+               handled = 1;
+       }
+
+       if (isr & (CDUART_IXR_TOUT | CDUART_IXR_RTRIG)) {
+               ibufp = sc->sc_ibufp;
+               for (;;) {
+                       sr = cduart_read(sc, CDUART_SR);
+                       if (sr & CDUART_SR_RXEMPTY)
+                               break;
+                       c = cduart_read(sc, CDUART_FIFO) & 0xff;
+
+                       if (ibufp < sc->sc_ibufend) {
+                               *ibufp++ = c;
+                       } else {
+                               sc->sc_floods++;
+                               if (sc->sc_errors++ == 0)
+                                       timeout_add_sec(&sc->sc_diag_tmo, 60);
+                       }
+               }
+               if (sc->sc_ibufp != ibufp) {
+                       sc->sc_ibufp = ibufp;
+                       softintr_schedule(sc->sc_si);
+               }
+               handled = 1;
+       }
+
+       if (isr & CDUART_IXR_RXOVR) {
+               sc->sc_overflows++;
+               if (sc->sc_errors++ == 0)
+                       timeout_add_sec(&sc->sc_diag_tmo, 60);
+               handled = 1;
+       }
+
+       return handled;
+}
+
+void
+cduart_softintr(void *arg)
+{
+       struct cduart_softc *sc = arg;
+       struct tty *tp = sc->sc_tty;
+       int *ibufend, *ibufp;
+       int s;
+
+       s = spltty();
+
+       ibufp = sc->sc_ibuf;
+       ibufend = sc->sc_ibufp;
+
+       if (ibufp == ibufend) {
+               splx(s);
+               return;
+       }
+
+       sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+           sc->sc_ibufs[1] : sc->sc_ibufs[0];
+       sc->sc_ibufend = sc->sc_ibuf + CDUART_IBUFSIZE;
+
+       if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
+               splx(s);
+               return;
+       }
+
+       splx(s);
+
+       while (ibufp < ibufend)
+               (*linesw[tp->t_line].l_rint)(*ibufp++, tp);
+}
+
+void
+cduart_diag(void *arg)
+{
+       struct cduart_softc *sc = arg;
+       int overflows, floods;
+       int s;
+
+       s = spltty();
+       sc->sc_errors = 0;
+       overflows = sc->sc_overflows;
+       sc->sc_overflows = 0;
+       floods = sc->sc_floods;
+       sc->sc_floods = 0;
+       splx(s);
+       log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+           sc->sc_dev.dv_xname,
+           overflows, overflows == 1 ? "" : "s",
+           floods, floods == 1 ? "" : "s");
+}
+
+int
+cduartopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+       struct cduart_softc *sc;
+       struct tty *tp;
+       uint32_t sr;
+       int error, s;
+
+       sc = cduart_sc(dev);
+       if (sc == NULL)
+               return ENXIO;
+
+       s = spltty();
+
+       if (sc->sc_tty == NULL)
+               sc->sc_tty = ttymalloc(0);
+
+       tp = sc->sc_tty;
+       tp->t_oproc = cduartstart;
+       tp->t_param = cduartparam;
+       tp->t_dev = dev;
+       if ((tp->t_state & TS_ISOPEN) == 0) {
+               tp->t_state |= TS_WOPEN | TS_CARR_ON;
+               ttychars(tp);
+               tp->t_iflag = TTYDEF_IFLAG;
+               tp->t_oflag = TTYDEF_OFLAG;
+               tp->t_cflag = TTYDEF_CFLAG;
+               tp->t_lflag = TTYDEF_LFLAG;
+               tp->t_ispeed = B115200; /* XXX */
+               tp->t_ospeed = tp->t_ispeed;
+               ttsetwater(tp);
+
+               sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+               sc->sc_ibufend = sc->sc_ibuf + CDUART_IBUFSIZE;
+
+               cduart_write(sc, CDUART_RXTOUT, 10);
+               cduart_write(sc, CDUART_RXWM, CDUART_FIFOSIZE / 2);
+
+               /* Clear any pending I/O. */
+               for (;;) {
+                       sr = cduart_read(sc, CDUART_SR);
+                       if (sr & CDUART_SR_RXEMPTY)
+                               break;
+                       (void)cduart_read(sc, CDUART_FIFO);
+               }
+
+               cduart_write(sc, CDUART_IER,
+                   CDUART_IXR_TOUT | CDUART_IXR_RXOVR | CDUART_IXR_RTRIG);
+       } else if ((tp->t_state & TS_XCLUDE) && suser(p) != 0) {
+               splx(s);
+               return EBUSY;
+       }
+
+       if (DEVCUA(dev)) {
+               if (tp->t_state & TS_ISOPEN) {
+                       splx(s);
+                       return EBUSY;
+               }
+               sc->sc_cua = 1;
+       } else {
+               if ((flag & O_NONBLOCK) && sc->sc_cua) {
+                       splx(s);
+                       return EBUSY;
+               } else {
+                       while (sc->sc_cua) {
+                               tp->t_state |= TS_WOPEN;
+                               error = ttysleep(tp, &tp->t_rawq,
+                                   TTIPRI | PCATCH, ttopen);
+                               if (error != 0 && (tp->t_state & TS_WOPEN)) {
+                                       tp->t_state &= ~TS_WOPEN;
+                                       splx(s);
+                                       return error;
+                               }
+                       }
+               }
+       }
+
+       splx(s);
+
+       return (*linesw[tp->t_line].l_open)(dev, tp, p);
+}
+
+int
+cduartclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+       struct cduart_softc *sc;
+       struct tty *tp;
+       int s;
+
+       sc = cduart_sc(dev);
+       tp = sc->sc_tty;
+
+       if ((tp->t_state & TS_ISOPEN) == 0)
+               return 0;
+
+       (*linesw[tp->t_line].l_close)(tp, flag, p);
+       s = spltty();
+       /* Disable interrupts. */
+       cduart_write(sc, CDUART_IDR, ~0U);
+       sc->sc_cua = 0;
+       splx(s);
+       ttyclose(tp);
+
+       return 0;
+}
+
+int
+cduartread(dev_t dev, struct uio *uio, int flag)
+{
+       struct tty *tp;
+
+       tp = cduarttty(dev);
+       if (tp == NULL)
+               return ENODEV;
+
+       return (*linesw[tp->t_line].l_read)(tp, uio, flag);
+}
+
+int
+cduartwrite(dev_t dev, struct uio *uio, int flag)
+{
+       struct tty *tp;
+
+       tp = cduarttty(dev);
+       if (tp == NULL)
+               return ENODEV;
+
+       return (*linesw[tp->t_line].l_write)(tp, uio, flag);
+}
+
+int
+cduartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       struct cduart_softc *sc;
+       struct tty *tp;
+       int error;
+
+       sc = cduart_sc(dev);
+       if (sc == NULL)
+               return ENODEV;
+
+       tp = sc->sc_tty;
+       if (tp == NULL)
+               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;
+
+       /* XXX */
+       switch (cmd) {
+       case TIOCSBRK:
+       case TIOCCBRK:
+       case TIOCSDTR:
+       case TIOCCDTR:
+       case TIOCMSET:
+       case TIOCMBIC:
+       case TIOCMGET:
+       case TIOCGFLAGS:
+               break;
+       case TIOCSFLAGS:
+               error = suser(p);
+               if (error != 0)
+                       return EPERM;
+               break;
+       default:
+               return ENOTTY;
+       }
+
+       return 0;
+}
+
+int
+cduartparam(struct tty *tp, struct termios *t)
+{
+       return 0;
+}
+
+void
+cduartstart(struct tty *tp)
+{
+       struct cduart_softc *sc;
+       uint32_t sr;
+       int s;
+
+       sc = cduart_sc(tp->t_dev);
+
+       s = spltty();
+       if (tp->t_state & TS_BUSY)
+               goto out;
+       if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+               goto stopped;
+       ttwakeupwr(tp);
+       if (tp->t_outq.c_cc == 0)
+               goto stopped;
+       tp->t_state |= TS_BUSY;
+
+       cduart_write(sc, CDUART_ISR, CDUART_IXR_TXEMPTY);
+
+       sr = cduart_read(sc, CDUART_SR);
+       while ((sr & CDUART_SR_TXFULL) == 0 && tp->t_outq.c_cc != 0) {
+               cduart_write(sc, CDUART_FIFO, getc(&tp->t_outq));
+               sr = cduart_read(sc, CDUART_SR);
+       }
+
+       cduart_write(sc, CDUART_IER, CDUART_IXR_TXEMPTY);
+out:
+       splx(s);
+       return;
+stopped:
+       cduart_write(sc, CDUART_IDR, CDUART_IXR_TXEMPTY);
+       splx(s);
+}
+
+int
+cduartstop(struct tty *tp, int flag)
+{
+       return 0;
+}
+
+struct tty *
+cduarttty(dev_t dev)
+{
+       struct cduart_softc *sc;
+
+       sc = cduart_sc(dev);
+       if (sc == NULL)
+               return NULL;
+
+       return sc->sc_tty;
+}
+
+struct cduart_softc *
+cduart_sc(dev_t dev)
+{
+       int unit = DEVUNIT(dev);
+
+       if (unit >= cduart_cd.cd_ndevs)
+               return NULL;
+       return (struct cduart_softc *)cduart_cd.cd_devs[unit];
+}
+
+struct consdev cduartcons = {
+       .cn_probe       = NULL,
+       .cn_init        = NULL,
+       .cn_getc        = cduartcngetc,
+       .cn_putc        = cduartcnputc,
+       .cn_pollc       = cduartcnpollc,
+       .cn_bell        = NULL,
+       .cn_dev         = NODEV,
+       .cn_pri         = CN_MIDPRI,
+};
+
+int
+cduartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
+    tcflag_t cflag)
+{
+       bus_space_handle_t ioh;
+       int maj;
+
+       /* Look for major of com(4) to replace. */
+       for (maj = 0; maj < nchrdev; maj++) {
+               if (cdevsw[maj].d_open == comopen)
+                       break;
+       }
+       if (maj == nchrdev)
+               return ENXIO;
+
+       if (bus_space_map(iot, iobase, CDUART_SPACE_SIZE, 0, &ioh) != 0)
+               return ENOMEM;
+
+       cn_tab = &cduartcons;
+       cn_tab->cn_dev = makedev(maj, 0);
+       cdevsw[maj] = cduartdev;
+
+       cduartconsiot = iot;
+       cduartconsioh = ioh;
+       cduartconsrate = rate;
+       cduartconscflag = cflag;
+
+       return 0;
+}
+
+void
+cduartcnprobe(struct consdev *cp)
+{
+}
+
+void
+cduartcninit(struct consdev *cp)
+{
+}
+
+int
+cduartcngetc(dev_t dev)
+{
+       int s;
+       uint8_t c;
+
+       s = splhigh();
+       while (bus_space_read_4(cduartconsiot, cduartconsioh,
+           CDUART_SR) & CDUART_SR_RXEMPTY)
+               CPU_BUSY_CYCLE();
+       c = bus_space_read_4(cduartconsiot, cduartconsioh, CDUART_FIFO);
+       splx(s);
+
+       return c;
+}
+
+void
+cduartcnputc(dev_t dev, int c)
+{
+       int s;
+
+       s = splhigh();
+       while (bus_space_read_4(cduartconsiot, cduartconsioh,
+           CDUART_SR) & CDUART_SR_TXFULL)
+               CPU_BUSY_CYCLE();
+       bus_space_write_4(cduartconsiot, cduartconsioh, CDUART_FIFO, c);
+       splx(s);
+}
+
+void
+cduartcnpollc(dev_t dev, int on)
+{
+}
index 88d3b34..9a84a2b 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.fdt,v 1.148 2021/04/24 05:14:45 jsg Exp $
+#      $OpenBSD: files.fdt,v 1.149 2021/04/24 07:49:11 visa Exp $
 #
 # Config file and device description for machine-independent FDT code.
 # Included by ports that need it.
@@ -276,6 +276,10 @@ device     amlusbphy
 attach amlusbphy at fdt
 file   dev/fdt/amlusbphy.c             amlusbphy
 
+device cduart
+attach cduart at fdt
+file   dev/fdt/cduart.c                cduart
+
 device hiclock
 attach hiclock at fdt
 file   dev/fdt/hiclock.c               hiclock