Enable PL011 UART FIF0 support in pluart(4). The FIFO depth depends on
authoranton <anton@openbsd.org>
Fri, 11 Mar 2022 06:45:22 +0000 (06:45 +0000)
committeranton <anton@openbsd.org>
Fri, 11 Mar 2022 06:45:22 +0000 (06:45 +0000)
the revision and ranges from 16 to 32 bytes.

Special treatment of Server Base System Architecture (SBSA) generic UART
devices is required as presence of the interrupt trigger level register
is not guaranteed. Therefore treat such devices of having a 1-byte FIFO.

With help from kettenis@ and ok visa@

sys/dev/acpi/pluart_acpi.c
sys/dev/fdt/pluart_fdt.c
sys/dev/ic/pluart.c
sys/dev/ic/pluartvar.h

index dc8ea5e..a9d8b6c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pluart_acpi.c,v 1.5 2021/12/21 20:53:46 kettenis Exp $        */
+/*     $OpenBSD: pluart_acpi.c,v 1.6 2022/03/11 06:45:22 anton Exp $   */
 /*
  * Copyright (c) 2018 Mark Kettenis
  *
@@ -91,6 +91,8 @@ pluart_acpi_attach(struct device *parent, struct device *self, void *aux)
                return;
        }
 
+       sc->sc.sc_hwflags |= COM_HW_SBSA;
+
        pluart_attach_common(&sc->sc, pluart_acpi_is_console(sc));
 }
 
index 7f17365..2633f05 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pluart_fdt.c,v 1.4 2021/10/24 17:52:26 mpi Exp $      */
+/*     $OpenBSD: pluart_fdt.c,v 1.5 2022/03/11 06:45:22 anton Exp $    */
 /*
  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
  * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
@@ -69,6 +69,9 @@ pluart_fdt_attach(struct device *parent, struct device *self, void *aux)
                return;
        }
 
+       if (OF_is_compatible(faa->fa_node, "arm,sbsa-uart"))
+               sc->sc_hwflags |= COM_HW_SBSA;
+
        sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY, pluart_intr,
            sc, sc->sc_dev.dv_xname);
 
index eaa11b6..31da89e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pluart.c,v 1.7 2021/09/01 09:29:31 jan Exp $  */
+/*     $OpenBSD: pluart.c,v 1.8 2022/03/11 06:45:22 anton Exp $        */
 /*
  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
  * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
 #define UART_CR_CTSE           (1 << 14)       /* CTS hardware flow control enable */
 #define UART_CR_RTSE           (1 << 15)       /* RTS hardware flow control enable */
 #define UART_IFLS              0x34            /* Interrupt FIFO level select register */
+#define UART_IFLS_RX_SHIFT     3               /* RX level in bits [5:3] */
+#define UART_IFLS_TX_SHIFT     0               /* TX level in bits [2:0] */
+#define UART_IFLS_1_8          0               /* FIFO 1/8 full */
+#define UART_IFLS_1_4          1               /* FIFO 1/4 full */
+#define UART_IFLS_1_2          2               /* FIFO 1/2 full */
+#define UART_IFLS_3_4          3               /* FIFO 3/4 full */
+#define UART_IFLS_7_8          4               /* FIFO 7/8 full */
 #define UART_IMSC              0x38            /* Interrupt mask set/clear register */
 #define UART_IMSC_RIMIM                (1 << 0)
 #define UART_IMSC_CTSMIM       (1 << 1)
 #define UART_MIS               0x40            /* Masked interrupt status register */
 #define UART_ICR               0x44            /* Interrupt clear register */
 #define UART_DMACR             0x48            /* DMA control register */
+#define UART_PID0              0xfe0           /* Peripheral identification register 0 */
+#define UART_PID1              0xfe4           /* Peripheral identification register 1 */
+#define UART_PID2              0xfe8           /* Peripheral identification register 2 */
+#define UART_PID2_REV(x)       (((x) & 0xf0) >> 4)
+#define UART_PID3              0xfec           /* Peripheral identification register 3 */
 #define UART_SPACE             0x100
 
+#define UART_FIFO_SIZE         16
+#define UART_FIFO_SIZE_R3      32
+
 void pluartcnprobe(struct consdev *cp);
 void pluartcninit(struct consdev *cp);
 int pluartcngetc(dev_t dev);
@@ -150,7 +165,31 @@ struct cdevsw pluartdev =
 void
 pluart_attach_common(struct pluart_softc *sc, int console)
 {
-       int maj;
+       int fifolen, maj;
+       int lcr;
+
+       if ((sc->sc_hwflags & COM_HW_SBSA) == 0) {
+               int rev;
+
+               rev = UART_PID2_REV(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                   UART_PID2));
+               if (rev < 3)
+                       fifolen = UART_FIFO_SIZE;
+               else
+                       fifolen = UART_FIFO_SIZE_R3;
+               printf(": rev %d, %d byte fifo\n", rev, fifolen);
+       } else {
+               /*
+                * The SBSA UART is PL011 r1p5 compliant which implies revision
+                * 3 with a 32 byte FIFO. However, we cannot expect to configure
+                * RX/TX interrupt levels using the UARTIFLS register making it
+                * impossible to make assumptions about the number of available
+                * bytes in the FIFO. Therefore disable FIFO support for such
+                * devices.
+                */
+               fifolen = 0;
+               printf("\n");
+       }
 
        if (console) {
                /* Locate the major number. */
@@ -159,7 +198,7 @@ pluart_attach_common(struct pluart_softc *sc, int console)
                                break;
                cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
 
-               printf(": console");
+               printf("%s: console\n", sc->sc_dev.dv_xname);
                SET(sc->sc_hwflags, COM_HW_CONSOLE);
        }
 
@@ -171,13 +210,20 @@ pluart_attach_common(struct pluart_softc *sc, int console)
                panic("%s: can't establish soft interrupt.",
                    sc->sc_dev.dv_xname);
 
-       bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM));
+       if (fifolen > 0) {
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS,
+                   (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) |
+                   (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT));
+       }
+       sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM | UART_IMSC_TXIM;
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc);
        bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
-       bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H,
-           bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) &
-           ~UART_LCR_H_FEN);
-
-       printf("\n");
+       lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
+       if (fifolen > 0)
+               lcr |= UART_LCR_H_FEN;
+       else
+               lcr &= ~UART_LCR_H_FEN;
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
 }
 
 int
@@ -197,19 +243,26 @@ pluart_intr(void *arg)
        if (sc->sc_tty == NULL)
                return 0;
 
-       if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM))
+       if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) &&
+           !ISSET(is, UART_IMSC_TXIM))
                return 0;
 
-       if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) {
-               CLR(tp->t_state, TS_BUSY | TS_FLUSH);
-               if (sc->sc_halt > 0)
-                       wakeup(&tp->t_outq);
-               (*linesw[tp->t_line].l_start)(tp);
+       if (ISSET(is, UART_IMSC_TXIM)) {
+               /* Disable transmit interrupt. */
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
+                   sc->sc_imsc & ~UART_IMSC_TXIM);
+
+               if (ISSET(tp->t_state, TS_BUSY)) {
+                       CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+                       if (sc->sc_halt > 0)
+                               wakeup(&tp->t_outq);
+                       (*linesw[tp->t_line].l_start)(tp);
+               }
        }
 
        p = sc->sc_ibufp;
 
-       while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) {
+       while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) {
                c = bus_space_read_2(iot, ioh, UART_DR);
                if (c & UART_DR_BE) {
 #ifdef DDB
@@ -325,7 +378,6 @@ pluart_start(struct tty *tp)
        struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
        bus_space_tag_t iot = sc->sc_iot;
        bus_space_handle_t ioh = sc->sc_ioh;
-       u_int16_t fr;
        int s;
 
        s = spltty();
@@ -336,11 +388,19 @@ pluart_start(struct tty *tp)
                goto out;
        SET(tp->t_state, TS_BUSY);
 
-       fr = bus_space_read_4(iot, ioh, UART_FR);
-       while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) {
-               bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
+       /* Enable transmit interrupt. */
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc);
+
+       while (tp->t_outq.c_cc > 0) {
+               uint16_t fr;
+
                fr = bus_space_read_4(iot, ioh, UART_FR);
+               if (ISSET(fr, UART_FR_TXFF))
+                       break;
+
+               bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
        }
+
 out:
        splx(s);
 }
index 8fcbed1..847cf94 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pluartvar.h,v 1.1 2018/07/02 12:46:20 kettenis Exp $  */
+/*     $OpenBSD: pluartvar.h,v 1.2 2022/03/11 06:45:22 anton Exp $     */
 /*
  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
  * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
@@ -38,6 +38,7 @@ struct pluart_softc {
 #define COM_HW_FIFO     0x02
 #define COM_HW_SIR      0x20
 #define COM_HW_CONSOLE  0x40
+#define COM_HW_SBSA    0x80
        u_int8_t        sc_swflags;
 #define COM_SW_SOFTCAR  0x01
 #define COM_SW_CLOCAL   0x02
@@ -45,6 +46,7 @@ struct pluart_softc {
 #define COM_SW_MDMBUF   0x08
 #define COM_SW_PPS      0x10
        int             sc_fifolen;
+       int             sc_imsc;
 
        u_int8_t        sc_initialize;
        u_int8_t        sc_cua;