diff options
author | Scott Wood <scottwood@freescale.com> | 2011-04-06 15:30:12 -0500 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-08-24 09:54:53 -0700 |
commit | a39ef1e73b8a8e9dd808ed7b7661ff0ba1ff8db7 (patch) | |
tree | ac83db85a401e6bbd15bccb03cae08c3dd8a1fcb /drivers | |
parent | 84d99e6f30b19c4b9006bb199bad2fab078ce222 (diff) |
NS16550: buffer reads
This improves the performance of U-Boot when accepting rapid input,
such as pasting a sequence of commands.
Without this patch, on P4080DS I see a maximum of around 5 mw.l lines can
be pasted. With this patch, it handles around 70 lines before lossage,
long enough for most things you'd paste.
Change-Id: Ic17bce2fe04a3526c2605ad6d58a0d1f172e728f
Signed-off-by: Scott Wood <scottwood@freescale.com>
Tested-by: Simon Glass <sjg@chromium.org>
Reviewed-on: http://gerrit.chromium.org/gerrit/404
Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/ns16550.c | 96 | ||||
-rw-r--r-- | drivers/serial/serial.c | 5 |
2 files changed, 94 insertions, 7 deletions
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 8eeb48fb2a9..ed3428d7d84 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -4,12 +4,15 @@ * modified to use CONFIG_SYS_ISA_MEM and new defines */ +#include <common.h> #include <config.h> #include <ns16550.h> #include <watchdog.h> #include <linux/types.h> #include <asm/io.h> +DECLARE_GLOBAL_DATA_PTR; + #define UART_LCRVAL UART_LCR_8N1 /* 8 data, 1 stop, no parity */ #define UART_MCRVAL (UART_MCR_DTR | \ UART_MCR_RTS) /* RTS/DTR */ @@ -86,21 +89,104 @@ void NS16550_putc (NS16550_t com_port, char c) } #ifndef CONFIG_NS16550_MIN_FUNCTIONS -char NS16550_getc (NS16550_t com_port) + +static char NS16550_raw_getc(NS16550_t regs) { - while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) { + while ((serial_in(®s->lsr) & UART_LSR_DR) == 0) { #ifdef CONFIG_USB_TTY extern void usbtty_poll(void); usbtty_poll(); #endif WATCHDOG_RESET(); } - return serial_in(&com_port->rbr); + return serial_in(®s->rbr); +} + +static int NS16550_raw_tstc(NS16550_t regs) +{ + return ((serial_in(®s->lsr) & UART_LSR_DR) != 0); +} + + +#ifdef CONFIG_NS16550_BUFFER_READS + +#define BUF_SIZE 256 +#define NUM_PORTS 4 + +struct ns16550_priv { + char buf[BUF_SIZE]; + unsigned int head, tail; +}; + +static struct ns16550_priv rxstate[NUM_PORTS]; + +static void enqueue(unsigned int port, char ch) +{ + /* If queue is full, drop the character. */ + if ((rxstate[port].head - rxstate[port].tail - 1) % BUF_SIZE == 0) + return; + + rxstate[port].buf[rxstate[port].tail] = ch; + rxstate[port].tail = (rxstate[port].tail + 1) % BUF_SIZE; +} + +static int dequeue(unsigned int port, char *ch) +{ + /* Empty queue? */ + if (rxstate[port].head == rxstate[port].tail) + return 0; + + *ch = rxstate[port].buf[rxstate[port].head]; + rxstate[port].head = (rxstate[port].head + 1) % BUF_SIZE; + return 1; +} + +static void fill_rx_buf(NS16550_t regs, unsigned int port) +{ + while ((serial_in(®s->lsr) & UART_LSR_DR) != 0) + enqueue(port, serial_in(®s->rbr)); +} + +char NS16550_getc(NS16550_t regs, unsigned int port) +{ + char ch; + + if (port >= NUM_PORTS || !(gd->flags & GD_FLG_RELOC)) + return NS16550_raw_getc(regs); + + do { +#ifdef CONFIG_USB_TTY + extern void usbtty_poll(void); + usbtty_poll(); +#endif + fill_rx_buf(regs, port); + WATCHDOG_RESET(); + } while (!dequeue(port, &ch)); + + return ch; +} + +int NS16550_tstc(NS16550_t regs, unsigned int port) +{ + if (port >= NUM_PORTS || !(gd->flags & GD_FLG_RELOC)) + return NS16550_raw_tstc(regs); + + fill_rx_buf(regs, port); + + return rxstate[port].head != rxstate[port].tail; +} + +#else /* CONFIG_NS16550_BUFFER_READS */ + +char NS16550_getc(NS16550_t regs, unsigned int port) +{ + return NS16550_raw_getc(regs); } -int NS16550_tstc (NS16550_t com_port) +int NS16550_tstc(NS16550_t regs, unsigned int port) { - return ((serial_in(&com_port->lsr) & UART_LSR_DR) != 0); + return NS16550_raw_tstc(regs); } +#endif /* CONFIG_NS16550_BUFFER_READS */ #endif /* CONFIG_NS16550_MIN_FUNCTIONS */ diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 4032dfde748..49b2591dbc5 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -92,6 +92,7 @@ static NS16550_t serial_ports[4] = { }; #define PORT serial_ports[port-1] +#define PORTNR (port-1) #if defined(CONFIG_CONS_INDEX) #define CONSOLE (serial_ports[CONFIG_CONS_INDEX-1]) #endif @@ -219,13 +220,13 @@ _serial_puts (const char *s,const int port) int _serial_getc(const int port) { - return NS16550_getc(PORT); + return NS16550_getc(PORT, PORTNR); } int _serial_tstc(const int port) { - return NS16550_tstc(PORT); + return NS16550_tstc(PORT, PORTNR); } void |