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>
This commit is contained in:
Simon Glass 2015-01-26 18:27:09 -07:00
parent 765716744f
commit 21d004368f
2 changed files with 61 additions and 2 deletions

View File

@ -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

View File

@ -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)
{