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, 17 Oct 2023 04:19:19 +0000 (13:19 +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 7585f79..93f3657 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;
+
+               bcm283x_mu_rx_buffer_put(priv, readl(&regs->io));
+       }
 
-       data = 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)
@@ -186,6 +228,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