serial: bcm283x_mu: Support RX buffer
authorDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 8 May 2019 12:03:47 +0000 (21:03 +0900)
committerJaehoon Chung <jh80.chung@samsung.com>
Tue, 20 Oct 2020 06:13:47 +0000 (15:13 +0900)
 Since mini uart has very small rx fifo, writing long string can
 cause overrun. To prevent this, this patch appiles buffer for rx
 process.

Change-Id: Ic5bd37875567fe51eb5491b8867f39c1a78de6b9
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
drivers/serial/serial_bcm283x_mu.c

index 1be41ff..e3abb1e 100644 (file)
@@ -47,8 +47,14 @@ struct bcm283x_mu_regs {
 #define BCM283X_MU_LSR_TX_EMPTY                BIT(5)
 #define BCM283X_MU_LSR_RX_READY                BIT(0)
 
+#define BCM283X_MU_RX_BUFFER_LEN       1024
+#define BCM283X_MU_RX_BUFFER_INIT_POS  -1
+
 struct bcm283x_mu_priv {
        struct bcm283x_mu_regs *regs;
+       int rx_buffer[BCM283X_MU_RX_BUFFER_LEN];
+       int rx_buffer_in_pos;
+       int rx_buffer_out_pos;
 };
 
 static int bcm283x_mu_serial_getc(struct udevice *dev);
@@ -75,19 +81,55 @@ out:
        return 0;
 }
 
+static inline int bcm283x_mu_rx_buffer_full(struct bcm283x_mu_priv *priv)
+{
+       return !!(priv->rx_buffer_in_pos == BCM283X_MU_RX_BUFFER_LEN - 1);
+}
+
+static inline int bcm283x_mu_rx_buffer_empty(struct bcm283x_mu_priv *priv)
+{
+       return !!(priv->rx_buffer_out_pos == BCM283X_MU_RX_BUFFER_INIT_POS);
+}
+
+static void bcm283x_mu_rx_buffer_put(struct bcm283x_mu_priv *priv, int data)
+{
+       if (bcm283x_mu_rx_buffer_empty(priv))
+               priv->rx_buffer_out_pos++;
+
+       priv->rx_buffer[++priv->rx_buffer_in_pos] = data;
+}
+
+static int bcm283x_mu_rx_buffer_get(struct bcm283x_mu_priv *priv)
+{
+       int data = priv->rx_buffer[priv->rx_buffer_out_pos];
+
+       if (priv->rx_buffer_in_pos == priv->rx_buffer_out_pos) {
+               priv->rx_buffer_in_pos = BCM283X_MU_RX_BUFFER_INIT_POS;
+               priv->rx_buffer_out_pos = BCM283X_MU_RX_BUFFER_INIT_POS;
+       } else {
+               priv->rx_buffer_out_pos++;
+       }
+
+       return data;
+}
+
 static int bcm283x_mu_serial_getc(struct udevice *dev)
 {
        struct bcm283x_mu_priv *priv = dev_get_priv(dev);
        struct bcm283x_mu_regs *regs = priv->regs;
-       u32 data;
+       int max_count = 256;
 
-       /* Wait until there is data in the FIFO */
-       if (!(readl(&regs->lsr) & BCM283X_MU_LSR_RX_READY))
-               return -EAGAIN;
+       while (readl(&regs->lsr) & BCM283X_MU_LSR_RX_READY) {
+               if (bcm283x_mu_rx_buffer_full(priv) || --max_count == 0)
+                       break;
 
-       data = readl(&regs->io);
+               bcm283x_mu_rx_buffer_put(priv, readl(&regs->io));
+       }
+
+       if (bcm283x_mu_rx_buffer_empty(priv))
+               return -EAGAIN;
 
-       return (int)data;
+       return (int)bcm283x_mu_rx_buffer_get(priv);
 }
 
 static int bcm283x_mu_serial_putc(struct udevice *dev, const char data)
@@ -115,6 +157,9 @@ static int bcm283x_mu_serial_pending(struct udevice *dev, bool input)
 
        if (input) {
                WATCHDOG_RESET();
+               if (!bcm283x_mu_rx_buffer_empty(priv))
+                       return 1;
+
                return (lsr & BCM283X_MU_LSR_RX_READY) ? 1 : 0;
        } else {
                return (lsr & BCM283X_MU_LSR_TX_IDLE) ? 0 : 1;
@@ -186,6 +231,10 @@ static int bcm283x_mu_serial_probe(struct udevice *dev)
 
        priv->regs = (struct bcm283x_mu_regs *)plat->base;
 
+       priv->rx_buffer_in_pos = BCM283X_MU_RX_BUFFER_INIT_POS;
+       priv->rx_buffer_out_pos = BCM283X_MU_RX_BUFFER_INIT_POS;
+
+
        return 0;
 }
 #endif