aboutsummaryrefslogtreecommitdiff
path: root/drivers/serial/ns16550.c
diff options
context:
space:
mode:
authorSimon Goldschmidt <simon.k.r.goldschmidt@gmail.com>2019-01-09 20:35:31 +0100
committerTom Rini <trini@konsulko.com>2019-01-15 15:28:52 -0500
commitc4448bdc4fb398478bc8499cfcf85fca3c36ad08 (patch)
tree267e9f9c0b75d575fe6cc0d65e6fe55cb31c7e73 /drivers/serial/ns16550.c
parent7828e3cf70513d7bd3a2bcefd52802633c78affd (diff)
downloadu-boot-c4448bdc4fb398478bc8499cfcf85fca3c36ad08.zip
u-boot-c4448bdc4fb398478bc8499cfcf85fca3c36ad08.tar.gz
u-boot-c4448bdc4fb398478bc8499cfcf85fca3c36ad08.tar.bz2
serial: ns16550: fix debug uart putc called before init
If _debug_uart_putc() is called before _debug_uart_init(), the ns16550 debug uart driver hangs in a tight loop waiting for the tx FIFO to get empty. As this can happen via a printf sneaking in before the port calls debug_uart_init(), introduce a config option to ignore characters before the debug uart is initialized. This is done by reading the baudrate divisor and aborting if is zero. The Kconfig option is required as reading the baudrate divisor does not seem to work for all ns16500 compatibles (which is why the last attempt on this has been reverted in 1a67969a99). Tested on socfpga_cyclone5_socrates. Signed-off-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/serial/ns16550.c')
-rw-r--r--drivers/serial/ns16550.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 560ca2a..6cf2be8 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -272,12 +272,28 @@ static inline void _debug_uart_init(void)
serial_dout(&com_port->lcr, UART_LCRVAL);
}
+static inline int NS16550_read_baud_divisor(struct NS16550 *com_port)
+{
+ int ret;
+
+ serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+ ret = serial_din(&com_port->dll) & 0xff;
+ ret |= (serial_din(&com_port->dlm) & 0xff) << 8;
+ serial_dout(&com_port->lcr, UART_LCRVAL);
+
+ return ret;
+}
+
static inline void _debug_uart_putc(int ch)
{
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
- while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
- ;
+ while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) {
+#ifdef CONFIG_DEBUG_UART_NS16550_CHECK_ENABLED
+ if (!NS16550_read_baud_divisor(com_port))
+ return;
+#endif
+ }
serial_dout(&com_port->thr, ch);
}