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