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>
Thu, 10 Oct 2019 04:38:42 +0000 (13:38 +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>
drivers/serial/serial_bcm283x_mu.c

index 2030952..4b73762 100644 (file)
@@ -46,8 +46,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);
@@ -81,22 +87,61 @@ 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;
 }
 
+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)
@@ -124,6 +169,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;