arm: zynq: Support the debug UART

Add support for the debug UART to assist with early debugging. Enable it
for Zybo as an example.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
This commit is contained in:
Simon Glass 2015-10-17 19:41:22 -06:00 committed by Michal Simek
parent bd44758a41
commit c54c0a4c1c
4 changed files with 78 additions and 16 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: GPL-2.0+ * SPDX-License-Identifier: GPL-2.0+
*/ */
#include <common.h> #include <common.h>
#include <debug_uart.h>
#include <spl.h> #include <spl.h>
#include <asm/io.h> #include <asm/io.h>
@ -18,6 +19,11 @@ void board_init_f(ulong dummy)
ps7_init(); ps7_init();
arch_cpu_init(); arch_cpu_init();
/*
* The debug UART can be used from this point:
* debug_uart_init();
* printch('x');
*/
} }
#ifdef CONFIG_SPL_BOARD_INIT #ifdef CONFIG_SPL_BOARD_INIT

View file

@ -11,3 +11,7 @@ CONFIG_FIT_SIGNATURE=y
# CONFIG_CMD_SETEXPR is not set # CONFIG_CMD_SETEXPR is not set
CONFIG_OF_SEPARATE=y CONFIG_OF_SEPARATE=y
CONFIG_NET_RANDOM_ETHADDR=y CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ZYNQ=y
CONFIG_DEBUG_UART_BASE=0xe0001000
CONFIG_DEBUG_UART_CLOCK=50000000

View file

@ -91,6 +91,13 @@ config DEBUG_UART_S5P
will need to provide parameters to make this work. The driver will will need to provide parameters to make this work. The driver will
be available until the real driver-model serial is running. be available until the real driver-model serial is running.
config DEBUG_UART_ZYNQ
bool "Xilinx Zynq"
help
Select this to enable a debug UART using the serial_s5p 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 endchoice
config DEBUG_UART_BASE config DEBUG_UART_BASE

View file

@ -6,6 +6,7 @@
*/ */
#include <common.h> #include <common.h>
#include <errno.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <watchdog.h> #include <watchdog.h>
#include <asm/io.h> #include <asm/io.h>
@ -43,20 +44,16 @@ static struct uart_zynq *uart_zynq_ports[2] = {
}; };
/* Set up the baud rate in gd struct */ /* Set up the baud rate in gd struct */
static void uart_zynq_serial_setbrg(const int port) static void _uart_zynq_serial_setbrg(struct uart_zynq *regs,
unsigned long clock, unsigned long baud)
{ {
/* Calculation results. */ /* Calculation results. */
unsigned int calc_bauderror, bdiv, bgen; unsigned int calc_bauderror, bdiv, bgen;
unsigned long calc_baud = 0; unsigned long calc_baud = 0;
unsigned long baud;
unsigned long clock = get_uart_clk(port);
struct uart_zynq *regs = uart_zynq_ports[port];
/* Covering case where input clock is so slow */ /* Covering case where input clock is so slow */
if (clock < 1000000 && gd->baudrate > 4800) if (clock < 1000000 && baud > 4800)
gd->baudrate = 4800; baud = 4800;
baud = gd->baudrate;
/* master clock /* master clock
* Baud rate = ------------------ * Baud rate = ------------------
@ -87,6 +84,24 @@ static void uart_zynq_serial_setbrg(const int port)
writel(bgen, &regs->baud_rate_gen); writel(bgen, &regs->baud_rate_gen);
} }
/* Set up the baud rate in gd struct */
static void uart_zynq_serial_setbrg(const int port)
{
unsigned long clock = get_uart_clk(port);
struct uart_zynq *regs = uart_zynq_ports[port];
return _uart_zynq_serial_setbrg(regs, clock, gd->baudrate);
}
/* Initialize the UART, with...some settings. */
static void _uart_zynq_serial_init(struct uart_zynq *regs)
{
/* RX/TX enabled & reset */
writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
ZYNQ_UART_CR_RXRST, &regs->control);
writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
}
/* Initialize the UART, with...some settings. */ /* Initialize the UART, with...some settings. */
static int uart_zynq_serial_init(const int port) static int uart_zynq_serial_init(const int port)
{ {
@ -95,28 +110,33 @@ static int uart_zynq_serial_init(const int port)
if (!regs) if (!regs)
return -1; return -1;
/* RX/TX enabled & reset */ _uart_zynq_serial_init(regs);
writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
ZYNQ_UART_CR_RXRST, &regs->control);
writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
uart_zynq_serial_setbrg(port); uart_zynq_serial_setbrg(port);
return 0; return 0;
} }
static int _uart_zynq_serial_putc(struct uart_zynq *regs, const char c)
{
if (readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL)
return -EAGAIN;
writel(c, &regs->tx_rx_fifo);
return 0;
}
static void uart_zynq_serial_putc(const char c, const int port) static void uart_zynq_serial_putc(const char c, const int port)
{ {
struct uart_zynq *regs = uart_zynq_ports[port]; struct uart_zynq *regs = uart_zynq_ports[port];
while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0) while (_uart_zynq_serial_putc(regs, c) == -EAGAIN)
WATCHDOG_RESET(); WATCHDOG_RESET();
if (c == '\n') { if (c == '\n') {
writel('\r', &regs->tx_rx_fifo); while (_uart_zynq_serial_putc(regs, '\r') == -EAGAIN)
while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
WATCHDOG_RESET(); WATCHDOG_RESET();
} }
writel(c, &regs->tx_rx_fifo);
} }
static void uart_zynq_serial_puts(const char *s, const int port) static void uart_zynq_serial_puts(const char *s, const int port)
@ -218,3 +238,28 @@ void zynq_serial_initialize(void)
serial_register(&uart_zynq_serial0_device); serial_register(&uart_zynq_serial0_device);
serial_register(&uart_zynq_serial1_device); serial_register(&uart_zynq_serial1_device);
} }
#ifdef CONFIG_DEBUG_UART_ZYNQ
#include <debug_uart.h>
void _debug_uart_init(void)
{
struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE;
_uart_zynq_serial_init(regs);
_uart_zynq_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
CONFIG_BAUDRATE);
}
static inline void _debug_uart_putc(int ch)
{
struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE;
while (_uart_zynq_serial_putc(regs, ch) == -EAGAIN)
WATCHDOG_RESET();
}
DEBUG_UART_FUNCS
#endif