Merge branch 'next'
[platform/kernel/u-boot.git] / drivers / serial / serial_mt7620.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * UART driver for MediaTek MT7620 and earlier SoCs
4  *
5  * Copyright (C) 2020 MediaTek Inc.
6  * Author: Weijie Gao <weijie.gao@mediatek.com>
7  */
8
9 #include <clk.h>
10 #include <div64.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <log.h>
14 #include <reset.h>
15 #include <serial.h>
16 #include <watchdog.h>
17 #include <asm/io.h>
18 #include <asm/types.h>
19 #include <asm/addrspace.h>
20 #include <dm/device_compat.h>
21 #include <linux/err.h>
22
23 #if CONFIG_IS_ENABLED(OF_PLATDATA)
24 #include <dt-structs.h>
25 #endif
26
27 struct mt7620_serial_regs {
28         u32 rbr;
29         u32 thr;
30         u32 ier;
31         u32 iir;
32         u32 fcr;
33         u32 lcr;
34         u32 mcr;
35         u32 lsr;
36         u32 msr;
37         u32 scratch;
38         u32 dl;
39         u32 dll;
40         u32 dlm;
41         u32 ifctl;
42 };
43
44 #define UART_LCR_WLS_8          0x03    /* 8 bit character length */
45
46 #define UART_LSR_DR             0x01    /* Data ready */
47 #define UART_LSR_THRE           0x20    /* Xmit holding register empty */
48 #define UART_LSR_TEMT           0x40    /* Xmitter empty */
49
50 #define UART_MCR_DTR            0x01    /* DTR */
51 #define UART_MCR_RTS            0x02    /* RTS */
52
53 #define UART_FCR_FIFO_EN        0x01    /* Fifo enable */
54 #define UART_FCR_RXSR           0x02    /* Receiver soft reset */
55 #define UART_FCR_TXSR           0x04    /* Transmitter soft reset */
56
57 #define UART_MCRVAL (UART_MCR_DTR | \
58                      UART_MCR_RTS)
59
60 /* Clear & enable FIFOs */
61 #define UART_FCRVAL (UART_FCR_FIFO_EN | \
62                      UART_FCR_RXSR |    \
63                      UART_FCR_TXSR)
64
65 struct mt7620_serial_plat {
66 #if CONFIG_IS_ENABLED(OF_PLATDATA)
67         struct dtd_serial_mt7620 dtplat;
68 #endif
69
70         struct mt7620_serial_regs __iomem *regs;
71         u32 clock;
72 };
73
74 static void _mt7620_serial_setbrg(struct mt7620_serial_plat *plat, int baud)
75 {
76         u32 quot;
77
78         /* set divisor */
79         quot = DIV_ROUND_CLOSEST(plat->clock, 16 * baud);
80         writel(quot, &plat->regs->dl);
81
82         /* set character length and stop bits */
83         writel(UART_LCR_WLS_8, &plat->regs->lcr);
84 }
85
86 static int mt7620_serial_setbrg(struct udevice *dev, int baudrate)
87 {
88         struct mt7620_serial_plat *plat = dev_get_plat(dev);
89
90         _mt7620_serial_setbrg(plat, baudrate);
91
92         return 0;
93 }
94
95 static int mt7620_serial_putc(struct udevice *dev, const char ch)
96 {
97         struct mt7620_serial_plat *plat = dev_get_plat(dev);
98
99         if (!(readl(&plat->regs->lsr) & UART_LSR_THRE))
100                 return -EAGAIN;
101
102         writel(ch, &plat->regs->thr);
103
104         if (ch == '\n')
105                 WATCHDOG_RESET();
106
107         return 0;
108 }
109
110 static int mt7620_serial_getc(struct udevice *dev)
111 {
112         struct mt7620_serial_plat *plat = dev_get_plat(dev);
113
114         if (!(readl(&plat->regs->lsr) & UART_LSR_DR))
115                 return -EAGAIN;
116
117         return readl(&plat->regs->rbr);
118 }
119
120 static int mt7620_serial_pending(struct udevice *dev, bool input)
121 {
122         struct mt7620_serial_plat *plat = dev_get_plat(dev);
123
124         if (input)
125                 return (readl(&plat->regs->lsr) & UART_LSR_DR) ? 1 : 0;
126
127         return (readl(&plat->regs->lsr) & UART_LSR_THRE) ? 0 : 1;
128 }
129
130 static int mt7620_serial_probe(struct udevice *dev)
131 {
132         struct mt7620_serial_plat *plat = dev_get_plat(dev);
133
134 #if CONFIG_IS_ENABLED(OF_PLATDATA)
135         plat->regs = (void __iomem *)KSEG1ADDR(plat->dtplat.reg[0]);
136         plat->clock = plat->dtplat.clock_frequency;
137 #endif
138
139         /* Disable interrupt */
140         writel(0, &plat->regs->ier);
141
142         writel(UART_MCRVAL, &plat->regs->mcr);
143         writel(UART_FCRVAL, &plat->regs->fcr);
144
145         return 0;
146 }
147
148 #if CONFIG_IS_ENABLED(OF_REAL)
149 static int mt7620_serial_of_to_plat(struct udevice *dev)
150 {
151         struct mt7620_serial_plat *plat = dev_get_plat(dev);
152         struct reset_ctl reset_uart;
153         struct clk clk;
154         int err;
155
156         err = reset_get_by_index(dev, 0, &reset_uart);
157         if (!err)
158                 reset_deassert(&reset_uart);
159
160         plat->regs = dev_remap_addr_index(dev, 0);
161         if (!plat->regs) {
162                 dev_err(dev, "mt7620_serial: unable to map UART registers\n");
163                 return -EINVAL;
164         }
165
166         err = clk_get_by_index(dev, 0, &clk);
167         if (!err) {
168                 err = clk_get_rate(&clk);
169                 if (!IS_ERR_VALUE(err))
170                         plat->clock = err;
171         } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
172                 dev_err(dev, "mt7620_serial: failed to get clock\n");
173                 return err;
174         }
175
176         if (!plat->clock)
177                 plat->clock = dev_read_u32_default(dev, "clock-frequency", 0);
178
179         if (!plat->clock) {
180                 dev_err(dev, "mt7620_serial: clock not defined\n");
181                 return -EINVAL;
182         }
183
184         return 0;
185 }
186
187 static const struct udevice_id mt7620_serial_ids[] = {
188         { .compatible = "mediatek,mt7620-uart" },
189         { }
190 };
191 #endif
192
193 static const struct dm_serial_ops mt7620_serial_ops = {
194         .putc = mt7620_serial_putc,
195         .pending = mt7620_serial_pending,
196         .getc = mt7620_serial_getc,
197         .setbrg = mt7620_serial_setbrg,
198 };
199
200 U_BOOT_DRIVER(serial_mt7620) = {
201         .name = "serial_mt7620",
202         .id = UCLASS_SERIAL,
203 #if CONFIG_IS_ENABLED(OF_REAL)
204         .of_match = mt7620_serial_ids,
205         .of_to_plat = mt7620_serial_of_to_plat,
206 #endif
207         .plat_auto = sizeof(struct mt7620_serial_plat),
208         .probe = mt7620_serial_probe,
209         .ops = &mt7620_serial_ops,
210         .flags = DM_FLAG_PRE_RELOC,
211 };
212
213 DM_DRIVER_ALIAS(serial_mt7620, mediatek_mt7620_uart);
214
215 #ifdef CONFIG_DEBUG_UART_MT7620
216
217 #include <debug_uart.h>
218
219 static inline void _debug_uart_init(void)
220 {
221         struct mt7620_serial_plat plat;
222
223         plat.regs = (void *)CONFIG_DEBUG_UART_BASE;
224         plat.clock = CONFIG_DEBUG_UART_CLOCK;
225
226         writel(0, &plat.regs->ier);
227         writel(UART_MCRVAL, &plat.regs->mcr);
228         writel(UART_FCRVAL, &plat.regs->fcr);
229
230         _mt7620_serial_setbrg(&plat, CONFIG_BAUDRATE);
231 }
232
233 static inline void _debug_uart_putc(int ch)
234 {
235         struct mt7620_serial_regs __iomem *regs =
236                 (void *)CONFIG_DEBUG_UART_BASE;
237
238         while (!(readl(&regs->lsr) & UART_LSR_THRE))
239                 ;
240
241         writel(ch, &regs->thr);
242 }
243
244 DEBUG_UART_FUNCS
245
246 #endif