summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2011-04-06 15:30:12 -0500
committerSimon Glass <sjg@chromium.org>2011-08-24 09:54:53 -0700
commita39ef1e73b8a8e9dd808ed7b7661ff0ba1ff8db7 (patch)
treeac83db85a401e6bbd15bccb03cae08c3dd8a1fcb /drivers/serial
parent84d99e6f30b19c4b9006bb199bad2fab078ce222 (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/serial')
-rw-r--r--drivers/serial/ns16550.c96
-rw-r--r--drivers/serial/serial.c5
2 files changed, 94 insertions, 7 deletions
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 8eeb48fb2a..ed3428d7d8 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(&regs->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(&regs->rbr);
+}
+
+static int NS16550_raw_tstc(NS16550_t regs)
+{
+ return ((serial_in(&regs->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(&regs->lsr) & UART_LSR_DR) != 0)
+ enqueue(port, serial_in(&regs->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 4032dfde74..49b2591dbc 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