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 <sr@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Cc: Bin Meng <bmeng.cn@gmail.com>
Cc: Tom Rini <trini@konsulko.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
master
Stefan Roese 7 years ago committed by Bin Meng
parent 7fded0ce0f
commit 3ca7a06afb
  1. 15
      drivers/serial/Kconfig
  2. 48
      drivers/serial/serial-uclass.c
  3. 10
      include/serial.h

@ -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

@ -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;

@ -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 */

Loading…
Cancel
Save