diff options
-rw-r--r-- | drivers/serial/serial_bcm283x_mu.c | 60 |
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(®s->lsr) & BCM283X_MU_LSR_RX_READY)) - return -EAGAIN; + while (readl(®s->lsr) & BCM283X_MU_LSR_RX_READY) { + if (bcm283x_mu_rx_buffer_full(priv) || --max_count == 0) + break; + + bcm283x_mu_rx_buffer_put(priv, readl(®s->io)); + } - data = readl(®s->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; |