blob: 778a04d87e0cc7dde746884fd7c395c8136f7d2a [file] [log] [blame]
Ryder Lee849b1162018-11-15 10:08:02 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * MediaTek High-speed UART driver
4 *
5 * Copyright (C) 2018 MediaTek Inc.
6 * Author: Weijie Gao <weijie.gao@mediatek.com>
7 */
8
9#include <clk.h>
10#include <common.h>
11#include <div64.h>
12#include <dm.h>
13#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060014#include <log.h>
Ryder Lee849b1162018-11-15 10:08:02 +080015#include <serial.h>
16#include <watchdog.h>
17#include <asm/io.h>
18#include <asm/types.h>
Simon Glass61b29b82020-02-03 07:36:15 -070019#include <linux/err.h>
Ryder Lee849b1162018-11-15 10:08:02 +080020
21struct mtk_serial_regs {
22 u32 rbr;
23 u32 ier;
24 u32 fcr;
25 u32 lcr;
26 u32 mcr;
27 u32 lsr;
28 u32 msr;
29 u32 spr;
30 u32 mdr1;
31 u32 highspeed;
32 u32 sample_count;
33 u32 sample_point;
34 u32 fracdiv_l;
35 u32 fracdiv_m;
36 u32 escape_en;
37 u32 guard;
38 u32 rx_sel;
39};
40
41#define thr rbr
42#define iir fcr
43#define dll rbr
44#define dlm ier
45
46#define UART_LCR_WLS_8 0x03 /* 8 bit character length */
47#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
48
49#define UART_LSR_DR 0x01 /* Data ready */
50#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
Weijie Gao99ced532019-09-25 17:45:17 +080051#define UART_LSR_TEMT 0x40 /* Xmitter empty */
52
53#define UART_MCR_DTR 0x01 /* DTR */
54#define UART_MCR_RTS 0x02 /* RTS */
55
56#define UART_FCR_FIFO_EN 0x01 /* Fifo enable */
57#define UART_FCR_RXSR 0x02 /* Receiver soft reset */
58#define UART_FCR_TXSR 0x04 /* Transmitter soft reset */
59
60#define UART_MCRVAL (UART_MCR_DTR | \
61 UART_MCR_RTS)
62
63/* Clear & enable FIFOs */
64#define UART_FCRVAL (UART_FCR_FIFO_EN | \
65 UART_FCR_RXSR | \
66 UART_FCR_TXSR)
Ryder Lee849b1162018-11-15 10:08:02 +080067
68/* the data is correct if the real baud is within 3%. */
69#define BAUD_ALLOW_MAX(baud) ((baud) + (baud) * 3 / 100)
70#define BAUD_ALLOW_MIX(baud) ((baud) - (baud) * 3 / 100)
71
72struct mtk_serial_priv {
73 struct mtk_serial_regs __iomem *regs;
74 u32 clock;
75};
76
77static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
78{
79 bool support_clk12m_baud115200;
80 u32 quot, samplecount, realbaud;
81
82 if ((baud <= 115200) && (priv->clock == 12000000))
83 support_clk12m_baud115200 = true;
84 else
85 support_clk12m_baud115200 = false;
86
87 if (baud <= 115200) {
88 writel(0, &priv->regs->highspeed);
89 quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
90
91 if (support_clk12m_baud115200) {
92 writel(3, &priv->regs->highspeed);
93 quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
94 if (quot == 0)
95 quot = 1;
96
97 samplecount = DIV_ROUND_CLOSEST(priv->clock,
98 quot * baud);
99 if (samplecount != 0) {
100 realbaud = priv->clock / samplecount / quot;
101 if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
102 (realbaud < BAUD_ALLOW_MIX(baud))) {
103 pr_info("baud %d can't be handled\n",
104 baud);
105 }
106 } else {
107 pr_info("samplecount is 0\n");
108 }
109 }
110 } else if (baud <= 576000) {
111 writel(2, &priv->regs->highspeed);
112
113 /* Set to next lower baudrate supported */
114 if ((baud == 500000) || (baud == 576000))
115 baud = 460800;
116 quot = DIV_ROUND_UP(priv->clock, 4 * baud);
117 } else {
118 writel(3, &priv->regs->highspeed);
119 quot = DIV_ROUND_UP(priv->clock, 256 * baud);
120 }
121
122 /* set divisor */
123 writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
124 writel(quot & 0xff, &priv->regs->dll);
125 writel((quot >> 8) & 0xff, &priv->regs->dlm);
126 writel(UART_LCR_WLS_8, &priv->regs->lcr);
127
128 if (baud > 460800) {
129 u32 tmp;
130
131 tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
132 writel(tmp - 1, &priv->regs->sample_count);
133 writel((tmp - 2) >> 1, &priv->regs->sample_point);
134 } else {
135 writel(0, &priv->regs->sample_count);
136 writel(0xff, &priv->regs->sample_point);
137 }
138
139 if (support_clk12m_baud115200) {
140 writel(samplecount - 1, &priv->regs->sample_count);
141 writel((samplecount - 2) >> 1, &priv->regs->sample_point);
142 }
143}
144
Weijie Gao44fa6762019-09-25 17:45:18 +0800145static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch)
146{
147 if (!(readl(&priv->regs->lsr) & UART_LSR_THRE))
148 return -EAGAIN;
149
150 writel(ch, &priv->regs->thr);
151
152 if (ch == '\n')
153 WATCHDOG_RESET();
154
155 return 0;
156}
157
158static int _mtk_serial_getc(struct mtk_serial_priv *priv)
159{
160 if (!(readl(&priv->regs->lsr) & UART_LSR_DR))
161 return -EAGAIN;
162
163 return readl(&priv->regs->rbr);
164}
165
166static int _mtk_serial_pending(struct mtk_serial_priv *priv, bool input)
167{
168 if (input)
169 return (readl(&priv->regs->lsr) & UART_LSR_DR) ? 1 : 0;
170 else
171 return (readl(&priv->regs->lsr) & UART_LSR_THRE) ? 0 : 1;
172}
173
174#if defined(CONFIG_DM_SERIAL) && \
175 (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_DM))
Ryder Lee849b1162018-11-15 10:08:02 +0800176static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
177{
178 struct mtk_serial_priv *priv = dev_get_priv(dev);
179
180 _mtk_serial_setbrg(priv, baudrate);
181
182 return 0;
183}
184
185static int mtk_serial_putc(struct udevice *dev, const char ch)
186{
187 struct mtk_serial_priv *priv = dev_get_priv(dev);
188
Weijie Gao44fa6762019-09-25 17:45:18 +0800189 return _mtk_serial_putc(priv, ch);
Ryder Lee849b1162018-11-15 10:08:02 +0800190}
191
192static int mtk_serial_getc(struct udevice *dev)
193{
194 struct mtk_serial_priv *priv = dev_get_priv(dev);
195
Weijie Gao44fa6762019-09-25 17:45:18 +0800196 return _mtk_serial_getc(priv);
Ryder Lee849b1162018-11-15 10:08:02 +0800197}
198
199static int mtk_serial_pending(struct udevice *dev, bool input)
200{
201 struct mtk_serial_priv *priv = dev_get_priv(dev);
202
Weijie Gao44fa6762019-09-25 17:45:18 +0800203 return _mtk_serial_pending(priv, input);
Ryder Lee849b1162018-11-15 10:08:02 +0800204}
205
206static int mtk_serial_probe(struct udevice *dev)
207{
208 struct mtk_serial_priv *priv = dev_get_priv(dev);
209
210 /* Disable interrupt */
211 writel(0, &priv->regs->ier);
212
Weijie Gao99ced532019-09-25 17:45:17 +0800213 writel(UART_MCRVAL, &priv->regs->mcr);
214 writel(UART_FCRVAL, &priv->regs->fcr);
215
Ryder Lee849b1162018-11-15 10:08:02 +0800216 return 0;
217}
218
219static int mtk_serial_ofdata_to_platdata(struct udevice *dev)
220{
221 struct mtk_serial_priv *priv = dev_get_priv(dev);
222 fdt_addr_t addr;
223 struct clk clk;
224 int err;
225
226 addr = dev_read_addr(dev);
227 if (addr == FDT_ADDR_T_NONE)
228 return -EINVAL;
229
230 priv->regs = map_physmem(addr, 0, MAP_NOCACHE);
231
232 err = clk_get_by_index(dev, 0, &clk);
233 if (!err) {
234 err = clk_get_rate(&clk);
235 if (!IS_ERR_VALUE(err))
236 priv->clock = err;
237 } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
238 debug("mtk_serial: failed to get clock\n");
239 return err;
240 }
241
242 if (!priv->clock)
243 priv->clock = dev_read_u32_default(dev, "clock-frequency", 0);
244
245 if (!priv->clock) {
246 debug("mtk_serial: clock not defined\n");
247 return -EINVAL;
248 }
249
250 return 0;
251}
252
253static const struct dm_serial_ops mtk_serial_ops = {
254 .putc = mtk_serial_putc,
255 .pending = mtk_serial_pending,
256 .getc = mtk_serial_getc,
257 .setbrg = mtk_serial_setbrg,
258};
259
260static const struct udevice_id mtk_serial_ids[] = {
261 { .compatible = "mediatek,hsuart" },
262 { .compatible = "mediatek,mt6577-uart" },
263 { }
264};
265
266U_BOOT_DRIVER(serial_mtk) = {
267 .name = "serial_mtk",
268 .id = UCLASS_SERIAL,
269 .of_match = mtk_serial_ids,
270 .ofdata_to_platdata = mtk_serial_ofdata_to_platdata,
271 .priv_auto_alloc_size = sizeof(struct mtk_serial_priv),
272 .probe = mtk_serial_probe,
273 .ops = &mtk_serial_ops,
274 .flags = DM_FLAG_PRE_RELOC,
275};
Weijie Gao44fa6762019-09-25 17:45:18 +0800276#else
277
278DECLARE_GLOBAL_DATA_PTR;
279
280#define DECLARE_HSUART_PRIV(port) \
281 static struct mtk_serial_priv mtk_hsuart##port = { \
282 .regs = (struct mtk_serial_regs *)CONFIG_SYS_NS16550_COM##port, \
283 .clock = CONFIG_SYS_NS16550_CLK \
284};
285
286#define DECLARE_HSUART_FUNCTIONS(port) \
287 static int mtk_serial##port##_init(void) \
288 { \
289 writel(0, &mtk_hsuart##port.regs->ier); \
290 writel(UART_MCRVAL, &mtk_hsuart##port.regs->mcr); \
291 writel(UART_FCRVAL, &mtk_hsuart##port.regs->fcr); \
292 _mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
293 return 0 ; \
294 } \
295 static void mtk_serial##port##_setbrg(void) \
296 { \
297 _mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
298 } \
299 static int mtk_serial##port##_getc(void) \
300 { \
301 int err; \
302 do { \
303 err = _mtk_serial_getc(&mtk_hsuart##port); \
304 if (err == -EAGAIN) \
305 WATCHDOG_RESET(); \
306 } while (err == -EAGAIN); \
307 return err >= 0 ? err : 0; \
308 } \
309 static int mtk_serial##port##_tstc(void) \
310 { \
311 return _mtk_serial_pending(&mtk_hsuart##port, true); \
312 } \
313 static void mtk_serial##port##_putc(const char c) \
314 { \
315 int err; \
316 if (c == '\n') \
317 mtk_serial##port##_putc('\r'); \
318 do { \
319 err = _mtk_serial_putc(&mtk_hsuart##port, c); \
320 } while (err == -EAGAIN); \
321 } \
322 static void mtk_serial##port##_puts(const char *s) \
323 { \
324 while (*s) { \
325 mtk_serial##port##_putc(*s++); \
326 } \
327 }
328
329/* Serial device descriptor */
330#define INIT_HSUART_STRUCTURE(port, __name) { \
331 .name = __name, \
332 .start = mtk_serial##port##_init, \
333 .stop = NULL, \
334 .setbrg = mtk_serial##port##_setbrg, \
335 .getc = mtk_serial##port##_getc, \
336 .tstc = mtk_serial##port##_tstc, \
337 .putc = mtk_serial##port##_putc, \
338 .puts = mtk_serial##port##_puts, \
339}
340
341#define DECLARE_HSUART(port, __name) \
342 DECLARE_HSUART_PRIV(port); \
343 DECLARE_HSUART_FUNCTIONS(port); \
344 struct serial_device mtk_hsuart##port##_device = \
345 INIT_HSUART_STRUCTURE(port, __name);
346
347#if !defined(CONFIG_CONS_INDEX)
348#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6)
349#error "Invalid console index value."
350#endif
351
352#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1)
353#error "Console port 1 defined but not configured."
354#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2)
355#error "Console port 2 defined but not configured."
356#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3)
357#error "Console port 3 defined but not configured."
358#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4)
359#error "Console port 4 defined but not configured."
360#elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5)
361#error "Console port 5 defined but not configured."
362#elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6)
363#error "Console port 6 defined but not configured."
364#endif
365
366#if defined(CONFIG_SYS_NS16550_COM1)
367DECLARE_HSUART(1, "mtk-hsuart0");
368#endif
369#if defined(CONFIG_SYS_NS16550_COM2)
370DECLARE_HSUART(2, "mtk-hsuart1");
371#endif
372#if defined(CONFIG_SYS_NS16550_COM3)
373DECLARE_HSUART(3, "mtk-hsuart2");
374#endif
375#if defined(CONFIG_SYS_NS16550_COM4)
376DECLARE_HSUART(4, "mtk-hsuart3");
377#endif
378#if defined(CONFIG_SYS_NS16550_COM5)
379DECLARE_HSUART(5, "mtk-hsuart4");
380#endif
381#if defined(CONFIG_SYS_NS16550_COM6)
382DECLARE_HSUART(6, "mtk-hsuart5");
383#endif
384
385__weak struct serial_device *default_serial_console(void)
386{
387#if CONFIG_CONS_INDEX == 1
388 return &mtk_hsuart1_device;
389#elif CONFIG_CONS_INDEX == 2
390 return &mtk_hsuart2_device;
391#elif CONFIG_CONS_INDEX == 3
392 return &mtk_hsuart3_device;
393#elif CONFIG_CONS_INDEX == 4
394 return &mtk_hsuart4_device;
395#elif CONFIG_CONS_INDEX == 5
396 return &mtk_hsuart5_device;
397#elif CONFIG_CONS_INDEX == 6
398 return &mtk_hsuart6_device;
399#else
400#error "Bad CONFIG_CONS_INDEX."
401#endif
402}
403
404void mtk_serial_initialize(void)
405{
406#if defined(CONFIG_SYS_NS16550_COM1)
407 serial_register(&mtk_hsuart1_device);
408#endif
409#if defined(CONFIG_SYS_NS16550_COM2)
410 serial_register(&mtk_hsuart2_device);
411#endif
412#if defined(CONFIG_SYS_NS16550_COM3)
413 serial_register(&mtk_hsuart3_device);
414#endif
415#if defined(CONFIG_SYS_NS16550_COM4)
416 serial_register(&mtk_hsuart4_device);
417#endif
418#if defined(CONFIG_SYS_NS16550_COM5)
419 serial_register(&mtk_hsuart5_device);
420#endif
421#if defined(CONFIG_SYS_NS16550_COM6)
422 serial_register(&mtk_hsuart6_device);
423#endif
424}
425
426#endif
Ryder Lee849b1162018-11-15 10:08:02 +0800427
428#ifdef CONFIG_DEBUG_UART_MTK
429
430#include <debug_uart.h>
431
432static inline void _debug_uart_init(void)
433{
434 struct mtk_serial_priv priv;
435
436 priv.regs = (void *) CONFIG_DEBUG_UART_BASE;
437 priv.clock = CONFIG_DEBUG_UART_CLOCK;
438
439 writel(0, &priv.regs->ier);
Weijie Gao99ced532019-09-25 17:45:17 +0800440 writel(UART_MCRVAL, &priv.regs->mcr);
441 writel(UART_FCRVAL, &priv.regs->fcr);
Ryder Lee849b1162018-11-15 10:08:02 +0800442
443 _mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
444}
445
446static inline void _debug_uart_putc(int ch)
447{
448 struct mtk_serial_regs __iomem *regs =
449 (void *) CONFIG_DEBUG_UART_BASE;
450
451 while (!(readl(&regs->lsr) & UART_LSR_THRE))
452 ;
453
454 writel(ch, &regs->thr);
455}
456
457DEBUG_UART_FUNCS
458
Simon Glass61b29b82020-02-03 07:36:15 -0700459#endif