aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass2015-01-26 18:27:09 -0700
committerSimon Glass2015-02-19 06:20:28 -0700
commit21d004368fc8a4da07147c58dfe9a4e16d4ab761 (patch)
tree0d6b2bc4ce8caf0d56e74084c66f05d761d28ed7
parent765716744f6743d6c1e6b3c92eea163b4ee59f3c (diff)
serial: ns16550: Support debug UART
Add debug UART functions to permit ns16550 to provide an early debug UART. Try to avoid using the stack so that this can be called from assembler before a stack is set up (at least on ARM and PowerPC). Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r--drivers/serial/Kconfig13
-rw-r--r--drivers/serial/ns16550.c50
2 files changed, 61 insertions, 2 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6313258eac6..1686a1f951e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -33,6 +33,19 @@ config DEBUG_UART
serial drivers are up and running (done in serial_init()). Otherwise
the drivers may conflict and you will get strange output.
+choice
+ prompt "Select which UART will provide the debug UART"
+ depends on DEBUG_UART
+
+config DEBUG_UART_NS16550
+ bool "ns16550"
+ help
+ Select this to enable a debug UART using the ns16550 driver. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver model serial is running.
+
+endchoice
+
config DEBUG_UART_BASE
hex "Base address of UART"
depends on DEBUG_UART
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 57e6125de20..eb00f1ca8a2 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -118,10 +118,15 @@ static int ns16550_readb(NS16550_t port, int offset)
ns16550_readb(com_port, addr - (unsigned char *)com_port)
#endif
-int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
+static inline int calc_divisor(NS16550_t port, int clock, int baudrate)
{
const unsigned int mode_x_div = 16;
+ return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
+}
+
+int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
+{
#ifdef CONFIG_OMAP1510
/* If can't cleanly clock 115200 set div to 1 */
if ((clock == 12000000) && (baudrate == 115200)) {
@@ -131,7 +136,7 @@ int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
port->osc_12m_sel = 0; /* clear if previsouly set */
#endif
- return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
+ return calc_divisor(port, clock, baudrate);
}
static void NS16550_setbrg(NS16550_t com_port, int baud_divisor)
@@ -231,6 +236,47 @@ int NS16550_tstc(NS16550_t com_port)
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */
+#ifdef CONFIG_DEBUG_UART_NS16550
+
+#include <debug_uart.h>
+
+void debug_uart_init(void)
+{
+ struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
+ int baud_divisor;
+
+ /*
+ * We copy the code from above because it is already horribly messy.
+ * Trying to refactor to nicely remove the duplication doesn't seem
+ * feasible. The better fix is to move all users of this driver to
+ * driver model.
+ */
+ baud_divisor = calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
+ CONFIG_BAUDRATE);
+
+ serial_out_shift(&com_port->ier, 0, CONFIG_SYS_NS16550_IER);
+ serial_out_shift(&com_port->mcr, 0, UART_MCRVAL);
+ serial_out_shift(&com_port->fcr, 0, UART_FCRVAL);
+
+ serial_out_shift(&com_port->lcr, 0, UART_LCR_BKSE | UART_LCRVAL);
+ serial_out_shift(&com_port->dll, 0, baud_divisor & 0xff);
+ serial_out_shift(&com_port->dlm, 0, (baud_divisor >> 8) & 0xff);
+ serial_out_shift(&com_port->lcr, 0, UART_LCRVAL);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
+
+ while (!(serial_in_shift(&com_port->lsr, 0) & UART_LSR_THRE))
+ ;
+ serial_out_shift(&com_port->thr, 0, ch);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
+
#ifdef CONFIG_DM_SERIAL
static int ns16550_serial_putc(struct udevice *dev, const char ch)
{