From: Stefan Roese Date: Wed, 16 Aug 2017 15:37:16 +0000 (+0200) Subject: serial: serial-uclass: Add generic serial RX buffer support X-Git-Tag: v2017.09-rc3~24^2~6 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=3ca7a06afb7cbc867b7861a8b9aada74e5bbb559;p=u-boot serial: serial-uclass: Add generic serial RX buffer support Pasting longer lines into the U-Boot console prompt sometimes leads to characters missing. One problem here is the small 16-byte FIFO of the legacy NS16550 UART, e.g. on x86 platforms. This patch now introduces a Kconfig option to enable RX buffer support for all DM based serial drivers. With this option enabled, I was able paste really long lines into the U-Boot console, without any characters missing. Signed-off-by: Stefan Roese Cc: Simon Glass Cc: Bin Meng Cc: Tom Rini Reviewed-by: Bin Meng Tested-by: Bin Meng --- diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1c2c5d66e1..aeed538fa4 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -64,6 +64,21 @@ config DM_SERIAL implements serial_putc() etc. The uclass interface is defined in include/serial.h. +config SERIAL_RX_BUFFER + bool "Enable RX buffer for serial input" + depends on DM_SERIAL + help + Enable RX buffer support for the serial driver. This enables + pasting longer strings, even when the RX FIFO of the UART is + not big enough (e.g. 16 bytes on the normal NS16550). + +config SERIAL_RX_BUFFER_SIZE + int "RX buffer size" + depends on SERIAL_RX_BUFFER + default 256 + help + The size of the RX buffer (needs to be power of 2) + config SPL_DM_SERIAL bool "Enable Driver Model for serial drivers in SPL" depends on DM_SERIAL diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 998d372da6..2e5116f7ce 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -160,7 +160,7 @@ static void _serial_puts(struct udevice *dev, const char *str) _serial_putc(dev, *str++); } -static int _serial_getc(struct udevice *dev) +static int __serial_getc(struct udevice *dev) { struct dm_serial_ops *ops = serial_get_ops(dev); int err; @@ -174,7 +174,7 @@ static int _serial_getc(struct udevice *dev) return err >= 0 ? err : 0; } -static int _serial_tstc(struct udevice *dev) +static int __serial_tstc(struct udevice *dev) { struct dm_serial_ops *ops = serial_get_ops(dev); @@ -184,6 +184,44 @@ static int _serial_tstc(struct udevice *dev) return 1; } +#if CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) +static int _serial_tstc(struct udevice *dev) +{ + struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); + + /* Read all available chars into the RX buffer */ + while (__serial_tstc(dev)) { + upriv->buf[upriv->wr_ptr++] = __serial_getc(dev); + upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; + } + + return upriv->rd_ptr != upriv->wr_ptr ? 1 : 0; +} + +static int _serial_getc(struct udevice *dev) +{ + struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); + char val; + + val = upriv->buf[upriv->rd_ptr++]; + upriv->rd_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; + + return val; +} + +#else /* CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) */ + +static int _serial_getc(struct udevice *dev) +{ + return __serial_getc(dev); +} + +static int _serial_tstc(struct udevice *dev) +{ + return __serial_tstc(dev); +} +#endif /* CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) */ + void serial_putc(char ch) { if (gd->cur_serial_dev) @@ -359,6 +397,12 @@ static int serial_post_probe(struct udevice *dev) sdev.puts = serial_stub_puts; sdev.getc = serial_stub_getc; sdev.tstc = serial_stub_tstc; + +#if CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) + /* Allocate the RX buffer */ + upriv->buf = malloc(CONFIG_SERIAL_RX_BUFFER_SIZE); +#endif + stdio_register_dev(&sdev, &upriv->sdev); #endif return 0; diff --git a/include/serial.h b/include/serial.h index f4171964ae..d87f01082a 100644 --- a/include/serial.h +++ b/include/serial.h @@ -148,10 +148,18 @@ struct dm_serial_ops { /** * struct serial_dev_priv - information about a device used by the uclass * - * @sdev: stdio device attached to this uart + * @sdev: stdio device attached to this uart + * + * @buf: Pointer to the RX buffer + * @rd_ptr: Read pointer in the RX buffer + * @wr_ptr: Write pointer in the RX buffer */ struct serial_dev_priv { struct stdio_dev *sdev; + + char *buf; + int rd_ptr; + int wr_ptr; }; /* Access the serial operations for a device */