summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
authorTom Warren <twarren.nvidia@gmail.com>2011-04-28 07:55:13 -0700
committerSimon Glass <sjg@chromium.org>2011-08-24 09:56:21 -0700
commitd1b282db26a73650b51c680a693e707579ea8035 (patch)
treec985d8a611a2d549edd30902b0b4fd048686c455 /drivers/serial
parenta14a954f1ed38a92f83a7b2861e438f21d728027 (diff)
Fix Seaboard UART corruption on SPI activity
On Seaboard the UART and SPI interfere with each other. This causes the UART to receive spurious zero bytes after SPI transactions and also means that SPI can corrupt a few output characters when it starts up if they are still in the UART buffer. This hack corrects this by making SPI record that it may have corrupted the UART, and making the UART take evasive action. BUG=chromium-os:13228 TEST=Try developer U-Boot on Seaboard, make sure it auto-boots OK now Review URL: http://codereview.chromium.org/6715017 Change-Id: If2281357f177eeb3a19a170ddea22adbcf5942e9 Reviewed-on: http://gerrit.chromium.org/gerrit/191 Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/ns16550.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index ed3428d7d8..71c523dfeb 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <config.h>
+#include <common.h>
#include <ns16550.h>
#include <watchdog.h>
#include <linux/types.h>
@@ -31,6 +32,16 @@ DECLARE_GLOBAL_DATA_PTR;
#define CONFIG_SYS_NS16550_IER 0x00
#endif /* CONFIG_SYS_NS16550_IER */
+/*
+ * Signal that we are about to use the UART. This unfortunate hack is
+ * required by Seaboard, which cannot use its console and SPI at the same
+ * time. If the board file provides this, the board config will declare it.
+ * Let this be a lesson for others.
+ */
+#ifndef CONFIG_SPI_CORRUPTS_UART
+inline void uart_enable(void) {}
+#endif
+
void NS16550_init (NS16550_t com_port, int baud_divisor)
{
serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
@@ -71,10 +82,12 @@ void NS16550_reinit (NS16550_t com_port, int baud_divisor)
serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
serial_out(UART_LCRVAL, &com_port->lcr);
}
+
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */
void NS16550_putc (NS16550_t com_port, char c)
{
+ uart_enable();
while ((serial_in(&com_port->lsr) & UART_LSR_THRE) == 0);
serial_out(c, &com_port->thr);
@@ -92,6 +105,7 @@ void NS16550_putc (NS16550_t com_port, char c)
static char NS16550_raw_getc(NS16550_t regs)
{
+ uart_enable();
while ((serial_in(&regs->lsr) & UART_LSR_DR) == 0) {
#ifdef CONFIG_USB_TTY
extern void usbtty_poll(void);
@@ -107,7 +121,6 @@ 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
@@ -185,8 +198,37 @@ char NS16550_getc(NS16550_t regs, unsigned int port)
int NS16550_tstc(NS16550_t regs, unsigned int port)
{
+ uart_enable();
return NS16550_raw_tstc(regs);
}
#endif /* CONFIG_NS16550_BUFFER_READS */
+
+/* Clear the UART's RX FIFO */
+
+void NS16550_clear(NS16550_t regs, unsigned port)
+{
+ /* Reset RX fifo */
+ serial_out(UART_FCR_FIFO_EN | UART_FCR_RXSR, &regs->fcr);
+
+ /* Remove any pending characters */
+ while (NS16550_raw_tstc(regs))
+ NS16550_raw_getc(regs);
+}
+
+/* Wait for the UART's output buffer and holding register to drain */
+
+void NS16550_drain(NS16550_t regs, unsigned port)
+{
+ u32 mask = UART_LSR_TEMT | UART_LSR_THRE;
+
+ /* Wait for the UART to finish sending */
+ while ((serial_in(&regs->lsr) & mask) != mask)
+ udelay(100);
+#ifdef CONFIG_NS16550_BUFFER_READS
+ /* Quickly grab any incoming data while we can */
+ fill_rx_buf(regs, port);
+#endif
+}
+
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */