summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongwoo Lee <dwoo08.lee@samsung.com>2019-05-08 21:03:47 +0900
committerDongwoo Lee <dwoo08.lee@samsung.com>2019-05-08 21:16:32 +0900
commite748adf178fcd378f87b8d6116e6a3c516100aa4 (patch)
tree676f13460f617753082db9c5acc659335f84442c
parent118b456bf17ac870afdb3ca3ee6e8ed94592935a (diff)
downloadu-boot-e748adf178fcd378f87b8d6116e6a3c516100aa4.tar.gz
u-boot-e748adf178fcd378f87b8d6116e6a3c516100aa4.tar.bz2
u-boot-e748adf178fcd378f87b8d6116e6a3c516100aa4.zip
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>
-rw-r--r--drivers/serial/serial_bcm283x_mu.c60
1 files changed, 54 insertions, 6 deletions
diff --git a/drivers/serial/serial_bcm283x_mu.c b/drivers/serial/serial_bcm283x_mu.c
index 606e233be7..5b88deb17d 100644
--- a/drivers/serial/serial_bcm283x_mu.c
+++ b/drivers/serial/serial_bcm283x_mu.c
@@ -48,8 +48,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_setbrg(struct udevice *dev, int baudrate)
@@ -80,26 +86,65 @@ 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_serial_platdata *plat = dev_get_platdata(dev);
struct bcm283x_mu_priv *priv = dev_get_priv(dev);
struct bcm283x_mu_regs *regs = priv->regs;
- u32 data;
+ int max_count = 256;
if (plat->disabled)
return -EAGAIN;
- /* 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)
@@ -135,6 +180,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;