Commit c54c0a4c1c745a009565ceb2a5c564d4d9418476

Authored by Simon Glass
Committed by Michal Simek
1 parent bd44758a41

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>

Showing 4 changed files with 78 additions and 16 deletions Side-by-side Diff

arch/arm/mach-zynq/spl.c
... ... @@ -4,6 +4,7 @@
4 4 * SPDX-License-Identifier: GPL-2.0+
5 5 */
6 6 #include <common.h>
  7 +#include <debug_uart.h>
7 8 #include <spl.h>
8 9  
9 10 #include <asm/io.h>
... ... @@ -18,6 +19,11 @@
18 19 ps7_init();
19 20  
20 21 arch_cpu_init();
  22 + /*
  23 + * The debug UART can be used from this point:
  24 + * debug_uart_init();
  25 + * printch('x');
  26 + */
21 27 }
22 28  
23 29 #ifdef CONFIG_SPL_BOARD_INIT
configs/zynq_zybo_defconfig
... ... @@ -11,4 +11,8 @@
11 11 # CONFIG_CMD_SETEXPR is not set
12 12 CONFIG_OF_SEPARATE=y
13 13 CONFIG_NET_RANDOM_ETHADDR=y
  14 +CONFIG_DEBUG_UART=y
  15 +CONFIG_DEBUG_UART_ZYNQ=y
  16 +CONFIG_DEBUG_UART_BASE=0xe0001000
  17 +CONFIG_DEBUG_UART_CLOCK=50000000
drivers/serial/Kconfig
... ... @@ -91,6 +91,13 @@
91 91 will need to provide parameters to make this work. The driver will
92 92 be available until the real driver-model serial is running.
93 93  
  94 +config DEBUG_UART_ZYNQ
  95 + bool "Xilinx Zynq"
  96 + help
  97 + Select this to enable a debug UART using the serial_s5p driver. You
  98 + will need to provide parameters to make this work. The driver will
  99 + be available until the real driver-model serial is running.
  100 +
94 101 endchoice
95 102  
96 103 config DEBUG_UART_BASE
drivers/serial/serial_zynq.c
... ... @@ -6,6 +6,7 @@
6 6 */
7 7  
8 8 #include <common.h>
  9 +#include <errno.h>
9 10 #include <fdtdec.h>
10 11 #include <watchdog.h>
11 12 #include <asm/io.h>
12 13  
13 14  
14 15  
... ... @@ -43,21 +44,17 @@
43 44 };
44 45  
45 46 /* Set up the baud rate in gd struct */
46   -static void uart_zynq_serial_setbrg(const int port)
  47 +static void _uart_zynq_serial_setbrg(struct uart_zynq *regs,
  48 + unsigned long clock, unsigned long baud)
47 49 {
48 50 /* Calculation results. */
49 51 unsigned int calc_bauderror, bdiv, bgen;
50 52 unsigned long calc_baud = 0;
51   - unsigned long baud;
52   - unsigned long clock = get_uart_clk(port);
53   - struct uart_zynq *regs = uart_zynq_ports[port];
54 53  
55 54 /* Covering case where input clock is so slow */
56   - if (clock < 1000000 && gd->baudrate > 4800)
57   - gd->baudrate = 4800;
  55 + if (clock < 1000000 && baud > 4800)
  56 + baud = 4800;
58 57  
59   - baud = gd->baudrate;
60   -
61 58 /* master clock
62 59 * Baud rate = ------------------
63 60 * bgen * (bdiv + 1)
64 61  
65 62  
66 63  
67 64  
68 65  
69 66  
70 67  
71 68  
... ... @@ -87,36 +84,59 @@
87 84 writel(bgen, &regs->baud_rate_gen);
88 85 }
89 86  
90   -/* Initialize the UART, with...some settings. */
91   -static int uart_zynq_serial_init(const int port)
  87 +/* Set up the baud rate in gd struct */
  88 +static void uart_zynq_serial_setbrg(const int port)
92 89 {
  90 + unsigned long clock = get_uart_clk(port);
93 91 struct uart_zynq *regs = uart_zynq_ports[port];
94 92  
95   - if (!regs)
96   - return -1;
  93 + return _uart_zynq_serial_setbrg(regs, clock, gd->baudrate);
  94 +}
97 95  
  96 +/* Initialize the UART, with...some settings. */
  97 +static void _uart_zynq_serial_init(struct uart_zynq *regs)
  98 +{
98 99 /* RX/TX enabled & reset */
99 100 writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
100 101 ZYNQ_UART_CR_RXRST, &regs->control);
101 102 writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
  103 +}
  104 +
  105 +/* Initialize the UART, with...some settings. */
  106 +static int uart_zynq_serial_init(const int port)
  107 +{
  108 + struct uart_zynq *regs = uart_zynq_ports[port];
  109 +
  110 + if (!regs)
  111 + return -1;
  112 +
  113 + _uart_zynq_serial_init(regs);
102 114 uart_zynq_serial_setbrg(port);
103 115  
104 116 return 0;
105 117 }
106 118  
  119 +static int _uart_zynq_serial_putc(struct uart_zynq *regs, const char c)
  120 +{
  121 + if (readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL)
  122 + return -EAGAIN;
  123 +
  124 + writel(c, &regs->tx_rx_fifo);
  125 +
  126 + return 0;
  127 +}
  128 +
107 129 static void uart_zynq_serial_putc(const char c, const int port)
108 130 {
109 131 struct uart_zynq *regs = uart_zynq_ports[port];
110 132  
111   - while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
  133 + while (_uart_zynq_serial_putc(regs, c) == -EAGAIN)
112 134 WATCHDOG_RESET();
113 135  
114 136 if (c == '\n') {
115   - writel('\r', &regs->tx_rx_fifo);
116   - while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
  137 + while (_uart_zynq_serial_putc(regs, '\r') == -EAGAIN)
117 138 WATCHDOG_RESET();
118 139 }
119   - writel(c, &regs->tx_rx_fifo);
120 140 }
121 141  
122 142 static void uart_zynq_serial_puts(const char *s, const int port)
... ... @@ -218,4 +238,29 @@
218 238 serial_register(&uart_zynq_serial0_device);
219 239 serial_register(&uart_zynq_serial1_device);
220 240 }
  241 +
  242 +#ifdef CONFIG_DEBUG_UART_ZYNQ
  243 +
  244 +#include <debug_uart.h>
  245 +
  246 +void _debug_uart_init(void)
  247 +{
  248 + struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE;
  249 +
  250 + _uart_zynq_serial_init(regs);
  251 + _uart_zynq_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
  252 + CONFIG_BAUDRATE);
  253 +}
  254 +
  255 +static inline void _debug_uart_putc(int ch)
  256 +{
  257 + struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE;
  258 +
  259 + while (_uart_zynq_serial_putc(regs, ch) == -EAGAIN)
  260 + WATCHDOG_RESET();
  261 +}
  262 +
  263 +DEBUG_UART_FUNCS
  264 +
  265 +#endif