arm: zynq: Support the debug UART
authorSimon Glass <sjg@chromium.org>
Sun, 18 Oct 2015 01:41:22 +0000 (19:41 -0600)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 4 Nov 2015 13:49:52 +0000 (14:49 +0100)
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>
arch/arm/mach-zynq/spl.c
configs/zynq_zybo_defconfig
drivers/serial/Kconfig
drivers/serial/serial_zynq.c

index 1805455..723019d 100644 (file)
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 #include <common.h>
+#include <debug_uart.h>
 #include <spl.h>
 
 #include <asm/io.h>
@@ -18,6 +19,11 @@ void board_init_f(ulong dummy)
        ps7_init();
 
        arch_cpu_init();
+       /*
+        * The debug UART can be used from this point:
+        * debug_uart_init();
+        * printch('x');
+        */
 }
 
 #ifdef CONFIG_SPL_BOARD_INIT
index fc251dc..b7531d6 100644 (file)
@@ -11,3 +11,7 @@ CONFIG_FIT_SIGNATURE=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_OF_SEPARATE=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
index 53b4e1b..d462244 100644 (file)
@@ -91,6 +91,13 @@ config DEBUG_UART_S5P
          will need to provide parameters to make this work. The driver will
          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
 
 config DEBUG_UART_BASE
index 9d84290..3b12c01 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <watchdog.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 */
-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. */
        unsigned int calc_bauderror, bdiv, bgen;
        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 */
-       if (clock < 1000000 && gd->baudrate > 4800)
-               gd->baudrate = 4800;
-
-       baud = gd->baudrate;
+       if (clock < 1000000 && baud > 4800)
+               baud = 4800;
 
        /*                master clock
         * Baud rate = ------------------
@@ -87,36 +84,59 @@ static void uart_zynq_serial_setbrg(const int port)
        writel(bgen, &regs->baud_rate_gen);
 }
 
-/* Initialize the UART, with...some settings. */
-static int uart_zynq_serial_init(const int port)
+/* 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];
 
-       if (!regs)
-               return -1;
+       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. */
+static int uart_zynq_serial_init(const int port)
+{
+       struct uart_zynq *regs = uart_zynq_ports[port];
+
+       if (!regs)
+               return -1;
+
+       _uart_zynq_serial_init(regs);
        uart_zynq_serial_setbrg(port);
 
        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)
 {
        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();
 
        if (c == '\n') {
-               writel('\r', &regs->tx_rx_fifo);
-               while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
+               while (_uart_zynq_serial_putc(regs, '\r') == -EAGAIN)
                        WATCHDOG_RESET();
        }
-       writel(c, &regs->tx_rx_fifo);
 }
 
 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_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