]> git.sur5r.net Git - u-boot/blob - drivers/serial/serial_zynq.c
serial: uartlite: Reset RX/TX in init
[u-boot] / drivers / serial / serial_zynq.c
1 /*
2  * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
3  * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <watchdog.h>
10 #include <asm/io.h>
11 #include <linux/compiler.h>
12 #include <serial.h>
13
14 #define ZYNQ_UART_SR_TXFULL     0x00000010 /* TX FIFO full */
15 #define ZYNQ_UART_SR_RXEMPTY    0x00000002 /* RX FIFO empty */
16
17 #define ZYNQ_UART_CR_TX_EN      0x00000010 /* TX enabled */
18 #define ZYNQ_UART_CR_RX_EN      0x00000004 /* RX enabled */
19 #define ZYNQ_UART_CR_TXRST      0x00000002 /* TX logic reset */
20 #define ZYNQ_UART_CR_RXRST      0x00000001 /* RX logic reset */
21
22 #define ZYNQ_UART_MR_PARITY_NONE        0x00000020  /* No parity mode */
23
24 struct uart_zynq {
25         u32 control; /* Control Register [8:0] */
26         u32 mode; /* Mode Register [10:0] */
27         u32 reserved1[4];
28         u32 baud_rate_gen; /* Baud Rate Generator [15:0] */
29         u32 reserved2[4];
30         u32 channel_sts; /* Channel Status [11:0] */
31         u32 tx_rx_fifo; /* FIFO [15:0] or [7:0] */
32         u32 baud_rate_divider; /* Baud Rate Divider [7:0] */
33 };
34
35 static struct uart_zynq *uart_zynq_ports[2] = {
36 #ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0
37         [0] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR0,
38 #endif
39 #ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1
40         [1] = (struct uart_zynq *)CONFIG_ZYNQ_SERIAL_BASEADDR1,
41 #endif
42 };
43
44 struct uart_zynq_params {
45         u32 baudrate;
46         u32 clock;
47 };
48
49 static struct uart_zynq_params uart_zynq_ports_param[2] = {
50 #if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE0) && defined(CONFIG_ZYNQ_SERIAL_CLOCK0)
51         [0].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE0,
52         [0].clock = CONFIG_ZYNQ_SERIAL_CLOCK0,
53 #endif
54 #if defined(CONFIG_ZYNQ_SERIAL_BAUDRATE1) && defined(CONFIG_ZYNQ_SERIAL_CLOCK1)
55         [1].baudrate = CONFIG_ZYNQ_SERIAL_BAUDRATE1,
56         [1].clock = CONFIG_ZYNQ_SERIAL_CLOCK1,
57 #endif
58 };
59
60 /* Set up the baud rate in gd struct */
61 static void uart_zynq_serial_setbrg(const int port)
62 {
63         /* Calculation results. */
64         unsigned int calc_bauderror, bdiv, bgen;
65         unsigned long calc_baud = 0;
66         unsigned long baud = uart_zynq_ports_param[port].baudrate;
67         unsigned long clock = uart_zynq_ports_param[port].clock;
68         struct uart_zynq *regs = uart_zynq_ports[port];
69
70         /*                master clock
71          * Baud rate = ------------------
72          *              bgen * (bdiv + 1)
73          *
74          * Find acceptable values for baud generation.
75          */
76         for (bdiv = 4; bdiv < 255; bdiv++) {
77                 bgen = clock / (baud * (bdiv + 1));
78                 if (bgen < 2 || bgen > 65535)
79                         continue;
80
81                 calc_baud = clock / (bgen * (bdiv + 1));
82
83                 /*
84                  * Use first calculated baudrate with
85                  * an acceptable (<3%) error
86                  */
87                 if (baud > calc_baud)
88                         calc_bauderror = baud - calc_baud;
89                 else
90                         calc_bauderror = calc_baud - baud;
91                 if (((calc_bauderror * 100) / baud) < 3)
92                         break;
93         }
94
95         writel(bdiv, &regs->baud_rate_divider);
96         writel(bgen, &regs->baud_rate_gen);
97 }
98
99 /* Initialize the UART, with...some settings. */
100 static int uart_zynq_serial_init(const int port)
101 {
102         struct uart_zynq *regs = uart_zynq_ports[port];
103
104         if (!regs)
105                 return -1;
106
107         /* RX/TX enabled & reset */
108         writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
109                                         ZYNQ_UART_CR_RXRST, &regs->control);
110         writel(ZYNQ_UART_MR_PARITY_NONE, &regs->mode); /* 8 bit, no parity */
111         uart_zynq_serial_setbrg(port);
112
113         return 0;
114 }
115
116 static void uart_zynq_serial_putc(const char c, const int port)
117 {
118         struct uart_zynq *regs = uart_zynq_ports[port];
119
120         while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
121                 WATCHDOG_RESET();
122
123         if (c == '\n') {
124                 writel('\r', &regs->tx_rx_fifo);
125                 while ((readl(&regs->channel_sts) & ZYNQ_UART_SR_TXFULL) != 0)
126                         WATCHDOG_RESET();
127         }
128         writel(c, &regs->tx_rx_fifo);
129 }
130
131 static void uart_zynq_serial_puts(const char *s, const int port)
132 {
133         while (*s)
134                 uart_zynq_serial_putc(*s++, port);
135 }
136
137 static int uart_zynq_serial_tstc(const int port)
138 {
139         struct uart_zynq *regs = uart_zynq_ports[port];
140
141         return (readl(&regs->channel_sts) & ZYNQ_UART_SR_RXEMPTY) == 0;
142 }
143
144 static int uart_zynq_serial_getc(const int port)
145 {
146         struct uart_zynq *regs = uart_zynq_ports[port];
147
148         while (!uart_zynq_serial_tstc(port))
149                 WATCHDOG_RESET();
150         return readl(&regs->tx_rx_fifo);
151 }
152
153 /* Multi serial device functions */
154 #define DECLARE_PSSERIAL_FUNCTIONS(port) \
155         int uart_zynq##port##_init(void) \
156                                 { return uart_zynq_serial_init(port); } \
157         void uart_zynq##port##_setbrg(void) \
158                                 { return uart_zynq_serial_setbrg(port); } \
159         int uart_zynq##port##_getc(void) \
160                                 { return uart_zynq_serial_getc(port); } \
161         int uart_zynq##port##_tstc(void) \
162                                 { return uart_zynq_serial_tstc(port); } \
163         void uart_zynq##port##_putc(const char c) \
164                                 { uart_zynq_serial_putc(c, port); } \
165         void uart_zynq##port##_puts(const char *s) \
166                                 { uart_zynq_serial_puts(s, port); }
167
168 /* Serial device descriptor */
169 #define INIT_PSSERIAL_STRUCTURE(port, __name) { \
170           .name   = __name,                     \
171           .start  = uart_zynq##port##_init,     \
172           .stop   = NULL,                       \
173           .setbrg = uart_zynq##port##_setbrg,   \
174           .getc   = uart_zynq##port##_getc,     \
175           .tstc   = uart_zynq##port##_tstc,     \
176           .putc   = uart_zynq##port##_putc,     \
177           .puts   = uart_zynq##port##_puts,     \
178 }
179
180 DECLARE_PSSERIAL_FUNCTIONS(0);
181 struct serial_device uart_zynq_serial0_device =
182         INIT_PSSERIAL_STRUCTURE(0, "ttyPS0");
183 DECLARE_PSSERIAL_FUNCTIONS(1);
184 struct serial_device uart_zynq_serial1_device =
185         INIT_PSSERIAL_STRUCTURE(1, "ttyPS1");
186
187 __weak struct serial_device *default_serial_console(void)
188 {
189         if (uart_zynq_ports[0])
190                 return &uart_zynq_serial0_device;
191         if (uart_zynq_ports[1])
192                 return &uart_zynq_serial1_device;
193
194         return NULL;
195 }
196
197 void zynq_serial_initalize(void)
198 {
199 #ifdef CONFIG_ZYNQ_SERIAL_BASEADDR0
200         serial_register(&uart_zynq_serial0_device);
201 #endif
202 #ifdef CONFIG_ZYNQ_SERIAL_BASEADDR1
203         serial_register(&uart_zynq_serial1_device);
204 #endif
205 }