]> git.sur5r.net Git - u-boot/blob - drivers/serial/serial_pxa.c
dm: core: Add a function to decode a memory region
[u-boot] / drivers / serial / serial_pxa.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
4  *
5  * (C) Copyright 2002
6  * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
7  *
8  * (C) Copyright 2002
9  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
10  * Marius Groeger <mgroeger@sysgo.de>
11  *
12  * (C) Copyright 2002
13  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
14  * Alex Zuepke <azu@sysgo.de>
15  *
16  * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
17  *
18  * Modified to add driver model (DM) support
19  * (C) Copyright 2016 Marcel Ziswiler <marcel.ziswiler@toradex.com>
20  */
21
22 #include <common.h>
23 #include <asm/arch/pxa-regs.h>
24 #include <asm/arch/regs-uart.h>
25 #include <asm/io.h>
26 #include <dm.h>
27 #include <dm/platform_data/serial_pxa.h>
28 #include <linux/compiler.h>
29 #include <serial.h>
30 #include <watchdog.h>
31
32 DECLARE_GLOBAL_DATA_PTR;
33
34 static uint32_t pxa_uart_get_baud_divider(int baudrate)
35 {
36         return 921600 / baudrate;
37 }
38
39 static void pxa_uart_toggle_clock(uint32_t uart_index, int enable)
40 {
41         uint32_t clk_reg, clk_offset, reg;
42
43         clk_reg = UART_CLK_REG;
44         clk_offset = UART_CLK_BASE << uart_index;
45
46         reg = readl(clk_reg);
47
48         if (enable)
49                 reg |= clk_offset;
50         else
51                 reg &= ~clk_offset;
52
53         writel(reg, clk_reg);
54 }
55
56 /*
57  * Enable clock and set baud rate, parity etc.
58  */
59 void pxa_setbrg_common(struct pxa_uart_regs *uart_regs, int port, int baudrate)
60 {
61         uint32_t divider = pxa_uart_get_baud_divider(baudrate);
62         if (!divider)
63                 hang();
64
65
66         pxa_uart_toggle_clock(port, 1);
67
68         /* Disable interrupts and FIFOs */
69         writel(0, &uart_regs->ier);
70         writel(0, &uart_regs->fcr);
71
72         /* Set baud rate */
73         writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, &uart_regs->lcr);
74         writel(divider & 0xff, &uart_regs->dll);
75         writel(divider >> 8, &uart_regs->dlh);
76         writel(LCR_WLS0 | LCR_WLS1, &uart_regs->lcr);
77
78         /* Enable UART */
79         writel(IER_UUE, &uart_regs->ier);
80 }
81
82 #ifndef CONFIG_DM_SERIAL
83 static struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index)
84 {
85         switch (uart_index) {
86         case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE;
87         case BTUART_INDEX: return (struct pxa_uart_regs *)BTUART_BASE;
88         case STUART_INDEX: return (struct pxa_uart_regs *)STUART_BASE;
89         case HWUART_INDEX: return (struct pxa_uart_regs *)HWUART_BASE;
90         default:
91                 return NULL;
92         }
93 }
94
95 /*
96  * Enable clock and set baud rate, parity etc.
97  */
98 void pxa_setbrg_dev(uint32_t uart_index)
99 {
100         struct pxa_uart_regs *uart_regs = pxa_uart_index_to_regs(uart_index);
101         if (!uart_regs)
102                 panic("Failed getting UART registers\n");
103
104         pxa_setbrg_common(uart_regs, uart_index, gd->baudrate);
105 }
106
107 /*
108  * Initialise the serial port with the given baudrate. The settings
109  * are always 8 data bits, no parity, 1 stop bit, no start bits.
110  */
111 int pxa_init_dev(unsigned int uart_index)
112 {
113         pxa_setbrg_dev(uart_index);
114         return 0;
115 }
116
117 /*
118  * Output a single byte to the serial port.
119  */
120 void pxa_putc_dev(unsigned int uart_index, const char c)
121 {
122         struct pxa_uart_regs *uart_regs;
123
124         /* If \n, also do \r */
125         if (c == '\n')
126                 pxa_putc_dev(uart_index, '\r');
127
128         uart_regs = pxa_uart_index_to_regs(uart_index);
129         if (!uart_regs)
130                 hang();
131
132         while (!(readl(&uart_regs->lsr) & LSR_TEMT))
133                 WATCHDOG_RESET();
134         writel(c, &uart_regs->thr);
135 }
136
137 /*
138  * Read a single byte from the serial port. Returns 1 on success, 0
139  * otherwise. When the function is succesfull, the character read is
140  * written into its argument c.
141  */
142 int pxa_tstc_dev(unsigned int uart_index)
143 {
144         struct pxa_uart_regs *uart_regs;
145
146         uart_regs = pxa_uart_index_to_regs(uart_index);
147         if (!uart_regs)
148                 return -1;
149
150         return readl(&uart_regs->lsr) & LSR_DR;
151 }
152
153 /*
154  * Read a single byte from the serial port. Returns 1 on success, 0
155  * otherwise. When the function is succesfull, the character read is
156  * written into its argument c.
157  */
158 int pxa_getc_dev(unsigned int uart_index)
159 {
160         struct pxa_uart_regs *uart_regs;
161
162         uart_regs = pxa_uart_index_to_regs(uart_index);
163         if (!uart_regs)
164                 return -1;
165
166         while (!(readl(&uart_regs->lsr) & LSR_DR))
167                 WATCHDOG_RESET();
168         return readl(&uart_regs->rbr) & 0xff;
169 }
170
171 void pxa_puts_dev(unsigned int uart_index, const char *s)
172 {
173         while (*s)
174                 pxa_putc_dev(uart_index, *s++);
175 }
176
177 #define pxa_uart(uart, UART)                                            \
178         int uart##_init(void)                                           \
179         {                                                               \
180                 return pxa_init_dev(UART##_INDEX);                      \
181         }                                                               \
182                                                                         \
183         void uart##_setbrg(void)                                        \
184         {                                                               \
185                 return pxa_setbrg_dev(UART##_INDEX);                    \
186         }                                                               \
187                                                                         \
188         void uart##_putc(const char c)                                  \
189         {                                                               \
190                 return pxa_putc_dev(UART##_INDEX, c);                   \
191         }                                                               \
192                                                                         \
193         void uart##_puts(const char *s)                                 \
194         {                                                               \
195                 return pxa_puts_dev(UART##_INDEX, s);                   \
196         }                                                               \
197                                                                         \
198         int uart##_getc(void)                                           \
199         {                                                               \
200                 return pxa_getc_dev(UART##_INDEX);                      \
201         }                                                               \
202                                                                         \
203         int uart##_tstc(void)                                           \
204         {                                                               \
205                 return pxa_tstc_dev(UART##_INDEX);                      \
206         }                                                               \
207
208 #define pxa_uart_desc(uart)                                             \
209         struct serial_device serial_##uart##_device =                   \
210         {                                                               \
211                 .name   = "serial_"#uart,                               \
212                 .start  = uart##_init,                                  \
213                 .stop   = NULL,                                         \
214                 .setbrg = uart##_setbrg,                                \
215                 .getc   = uart##_getc,                                  \
216                 .tstc   = uart##_tstc,                                  \
217                 .putc   = uart##_putc,                                  \
218                 .puts   = uart##_puts,                                  \
219         };
220
221 #define pxa_uart_multi(uart, UART)                                      \
222         pxa_uart(uart, UART)                                            \
223         pxa_uart_desc(uart)
224
225 #if defined(CONFIG_HWUART)
226         pxa_uart_multi(hwuart, HWUART)
227 #endif
228 #if defined(CONFIG_STUART)
229         pxa_uart_multi(stuart, STUART)
230 #endif
231 #if defined(CONFIG_FFUART)
232         pxa_uart_multi(ffuart, FFUART)
233 #endif
234 #if defined(CONFIG_BTUART)
235         pxa_uart_multi(btuart, BTUART)
236 #endif
237
238 __weak struct serial_device *default_serial_console(void)
239 {
240 #if CONFIG_CONS_INDEX == 1
241         return &serial_hwuart_device;
242 #elif CONFIG_CONS_INDEX == 2
243         return &serial_stuart_device;
244 #elif CONFIG_CONS_INDEX == 3
245         return &serial_ffuart_device;
246 #elif CONFIG_CONS_INDEX == 4
247         return &serial_btuart_device;
248 #else
249 #error "Bad CONFIG_CONS_INDEX."
250 #endif
251 }
252
253 void pxa_serial_initialize(void)
254 {
255 #if defined(CONFIG_FFUART)
256         serial_register(&serial_ffuart_device);
257 #endif
258 #if defined(CONFIG_BTUART)
259         serial_register(&serial_btuart_device);
260 #endif
261 #if defined(CONFIG_STUART)
262         serial_register(&serial_stuart_device);
263 #endif
264 }
265 #endif /* CONFIG_DM_SERIAL */
266
267 #ifdef CONFIG_DM_SERIAL
268 static int pxa_serial_probe(struct udevice *dev)
269 {
270         struct pxa_serial_platdata *plat = dev->platdata;
271
272         pxa_setbrg_common((struct pxa_uart_regs *)plat->base, plat->port,
273                           plat->baudrate);
274         return 0;
275 }
276
277 static int pxa_serial_putc(struct udevice *dev, const char ch)
278 {
279         struct pxa_serial_platdata *plat = dev->platdata;
280         struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
281
282         /* Wait for last character to go. */
283         if (!(readl(&uart_regs->lsr) & LSR_TEMT))
284                 return -EAGAIN;
285
286         writel(ch, &uart_regs->thr);
287
288         return 0;
289 }
290
291 static int pxa_serial_getc(struct udevice *dev)
292 {
293         struct pxa_serial_platdata *plat = dev->platdata;
294         struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
295
296         /* Wait for a character to arrive. */
297         if (!(readl(&uart_regs->lsr) & LSR_DR))
298                 return -EAGAIN;
299
300         return readl(&uart_regs->rbr) & 0xff;
301 }
302
303 int pxa_serial_setbrg(struct udevice *dev, int baudrate)
304 {
305         struct pxa_serial_platdata *plat = dev->platdata;
306         struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
307         int port = plat->port;
308
309         pxa_setbrg_common(uart_regs, port, baudrate);
310
311         return 0;
312 }
313
314 static int pxa_serial_pending(struct udevice *dev, bool input)
315 {
316         struct pxa_serial_platdata *plat = dev->platdata;
317         struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
318
319         if (input)
320                 return readl(&uart_regs->lsr) & LSR_DR ? 1 : 0;
321         else
322                 return readl(&uart_regs->lsr) & LSR_TEMT ? 0 : 1;
323
324         return 0;
325 }
326
327 static const struct dm_serial_ops pxa_serial_ops = {
328         .putc           = pxa_serial_putc,
329         .pending        = pxa_serial_pending,
330         .getc           = pxa_serial_getc,
331         .setbrg         = pxa_serial_setbrg,
332 };
333
334 U_BOOT_DRIVER(serial_pxa) = {
335         .name   = "serial_pxa",
336         .id     = UCLASS_SERIAL,
337         .probe  = pxa_serial_probe,
338         .ops    = &pxa_serial_ops,
339         .flags  = DM_FLAG_PRE_RELOC,
340 };
341 #endif /* CONFIG_DM_SERIAL */