blob: 93602797b833469a2ebf4efe760369ac89e1027f [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alison Wange2830532013-05-27 22:55:45 +00002/*
Vabhav Sharmaa8f78c62019-01-31 12:08:10 +00003 * Copyright 2019 NXP
Alison Wange2830532013-05-27 22:55:45 +00004 * Copyright 2013 Freescale Semiconductor, Inc.
Alison Wange2830532013-05-27 22:55:45 +00005 */
6
Tom Rini8c70baa2021-12-14 13:36:40 -05007#include <clock_legacy.h>
Peng Fan68e45632018-10-19 00:26:23 +02008#include <clk.h>
Bin Meng8a70d6d2016-01-13 19:39:04 -08009#include <dm.h>
Peng Fan836a6cc2017-02-22 16:21:51 +080010#include <fsl_lpuart.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Alison Wange2830532013-05-27 22:55:45 +000012#include <watchdog.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060013#include <asm/global_data.h>
Alison Wange2830532013-05-27 22:55:45 +000014#include <asm/io.h>
15#include <serial.h>
Simon Glass9bc15642020-02-03 07:36:16 -070016#include <dm/device_compat.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060017#include <linux/bitops.h>
Alison Wange2830532013-05-27 22:55:45 +000018#include <linux/compiler.h>
19#include <asm/arch/imx-regs.h>
20#include <asm/arch/clock.h>
21
Bin Menga8cc1722016-01-13 19:39:01 -080022#define US1_TDRE (1 << 7)
23#define US1_RDRF (1 << 5)
24#define US1_OR (1 << 3)
25#define UC2_TE (1 << 3)
26#define UC2_RE (1 << 2)
27#define CFIFO_TXFLUSH (1 << 7)
28#define CFIFO_RXFLUSH (1 << 6)
29#define SFIFO_RXOF (1 << 2)
30#define SFIFO_RXUF (1 << 0)
Alison Wange2830532013-05-27 22:55:45 +000031
Jingchang Lu4a7154e2014-09-05 13:52:47 +080032#define STAT_LBKDIF (1 << 31)
33#define STAT_RXEDGIF (1 << 30)
34#define STAT_TDRE (1 << 23)
35#define STAT_RDRF (1 << 21)
36#define STAT_IDLE (1 << 20)
37#define STAT_OR (1 << 19)
38#define STAT_NF (1 << 18)
39#define STAT_FE (1 << 17)
40#define STAT_PF (1 << 16)
41#define STAT_MA1F (1 << 15)
42#define STAT_MA2F (1 << 14)
43#define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \
Bin Menga8cc1722016-01-13 19:39:01 -080044 STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
Jingchang Lu4a7154e2014-09-05 13:52:47 +080045
46#define CTRL_TE (1 << 19)
47#define CTRL_RE (1 << 18)
48
Ye Lia2aedcb2018-10-18 14:28:32 +020049#define FIFO_RXFLUSH BIT(14)
50#define FIFO_TXFLUSH BIT(15)
51#define FIFO_TXSIZE_MASK 0x70
52#define FIFO_TXSIZE_OFF 4
53#define FIFO_RXSIZE_MASK 0x7
54#define FIFO_RXSIZE_OFF 0
Jingchang Lu4a7154e2014-09-05 13:52:47 +080055#define FIFO_TXFE 0x80
Giulio Benetti5eaa97e2020-01-10 15:51:43 +010056#if defined(CONFIG_ARCH_IMX8) || defined(CONFIG_ARCH_IMXRT)
Peng Fanb7f9ea92018-10-18 14:28:31 +020057#define FIFO_RXFE 0x08
58#else
Jingchang Lu4a7154e2014-09-05 13:52:47 +080059#define FIFO_RXFE 0x40
Peng Fanb7f9ea92018-10-18 14:28:31 +020060#endif
Jingchang Lu4a7154e2014-09-05 13:52:47 +080061
Ye Lia2aedcb2018-10-18 14:28:32 +020062#define WATER_TXWATER_OFF 0
Jingchang Lu4a7154e2014-09-05 13:52:47 +080063#define WATER_RXWATER_OFF 16
64
Alison Wange2830532013-05-27 22:55:45 +000065DECLARE_GLOBAL_DATA_PTR;
66
Peng Fan836a6cc2017-02-22 16:21:51 +080067#define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
68#define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
69
Peng Fandac2c942017-02-22 16:21:52 +080070enum lpuart_devtype {
71 DEV_VF610 = 1,
72 DEV_LS1021A,
Peng Fanb7f9ea92018-10-18 14:28:31 +020073 DEV_MX7ULP,
Giulio Benetti5eaa97e2020-01-10 15:51:43 +010074 DEV_IMX8,
75 DEV_IMXRT,
Peng Fandac2c942017-02-22 16:21:52 +080076};
77
Simon Glassb75b15b2020-12-03 16:55:23 -070078struct lpuart_serial_plat {
Peng Fan836a6cc2017-02-22 16:21:51 +080079 void *reg;
Peng Fandac2c942017-02-22 16:21:52 +080080 enum lpuart_devtype devtype;
Peng Fan836a6cc2017-02-22 16:21:51 +080081 ulong flags;
Bin Meng8a70d6d2016-01-13 19:39:04 -080082};
83
Peng Fan836a6cc2017-02-22 16:21:51 +080084static void lpuart_read32(u32 flags, u32 *addr, u32 *val)
85{
86 if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
87 if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
88 *(u32 *)val = in_be32(addr);
89 else
90 *(u32 *)val = in_le32(addr);
91 }
92}
93
94static void lpuart_write32(u32 flags, u32 *addr, u32 val)
95{
96 if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
97 if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
98 out_be32(addr, val);
99 else
100 out_le32(addr, val);
101 }
102}
103
Peng Fan836a6cc2017-02-22 16:21:51 +0800104u32 __weak get_lpuart_clk(void)
Alison Wange2830532013-05-27 22:55:45 +0000105{
Tom Rini8c70baa2021-12-14 13:36:40 -0500106 return get_board_sys_clk();
Peng Fan836a6cc2017-02-22 16:21:51 +0800107}
108
Ye Li86cf6992019-07-11 03:33:34 +0000109#if CONFIG_IS_ENABLED(CLK)
Peng Faneec6f382024-04-12 22:24:52 +0800110static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk_rate)
Peng Fan68e45632018-10-19 00:26:23 +0200111{
Peng Faneec6f382024-04-12 22:24:52 +0800112 struct lpuart_serial_plat *plat = dev_get_plat(dev);
113 struct clk clk;
Peng Fan68e45632018-10-19 00:26:23 +0200114 ulong rate;
115 int ret;
Peng Faneec6f382024-04-12 22:24:52 +0800116 char *name;
Peng Fan68e45632018-10-19 00:26:23 +0200117
Peng Faneec6f382024-04-12 22:24:52 +0800118 if (plat->devtype == DEV_MX7ULP)
119 name = "ipg";
120 else
121 name = "per";
122
123 ret = clk_get_by_name(dev, name, &clk);
Peng Fan68e45632018-10-19 00:26:23 +0200124 if (ret) {
Peng Faneec6f382024-04-12 22:24:52 +0800125 dev_err(dev, "Failed to get clk: %d\n", ret);
Peng Fan68e45632018-10-19 00:26:23 +0200126 return ret;
127 }
128
Peng Faneec6f382024-04-12 22:24:52 +0800129 rate = clk_get_rate(&clk);
Peng Fan68e45632018-10-19 00:26:23 +0200130 if ((long)rate <= 0) {
Peng Faneec6f382024-04-12 22:24:52 +0800131 dev_err(dev, "Failed to get clk rate: %ld\n", (long)rate);
Peng Fan68e45632018-10-19 00:26:23 +0200132 return ret;
133 }
Peng Faneec6f382024-04-12 22:24:52 +0800134 *clk_rate = rate;
Peng Fan68e45632018-10-19 00:26:23 +0200135 return 0;
136}
137#else
Peng Faneec6f382024-04-12 22:24:52 +0800138static inline int get_lpuart_clk_rate(struct udevice *dev, u32 *clk_rate)
Peng Fan68e45632018-10-19 00:26:23 +0200139{ return -ENOSYS; }
140#endif
141
Peng Fan836a6cc2017-02-22 16:21:51 +0800142static bool is_lpuart32(struct udevice *dev)
143{
Simon Glass95588622020-12-22 19:30:28 -0700144 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fan836a6cc2017-02-22 16:21:51 +0800145
146 return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG;
147}
148
Peng Fan68e45632018-10-19 00:26:23 +0200149static void _lpuart_serial_setbrg(struct udevice *dev,
Peng Fan836a6cc2017-02-22 16:21:51 +0800150 int baudrate)
151{
Simon Glassb75b15b2020-12-03 16:55:23 -0700152 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fan836a6cc2017-02-22 16:21:51 +0800153 struct lpuart_fsl *base = plat->reg;
Peng Fan68e45632018-10-19 00:26:23 +0200154 u32 clk;
Alison Wange2830532013-05-27 22:55:45 +0000155 u16 sbr;
Peng Fan68e45632018-10-19 00:26:23 +0200156 int ret;
157
Ye Li86cf6992019-07-11 03:33:34 +0000158 if (CONFIG_IS_ENABLED(CLK)) {
Peng Fan68e45632018-10-19 00:26:23 +0200159 ret = get_lpuart_clk_rate(dev, &clk);
160 if (ret)
161 return;
162 } else {
163 clk = get_lpuart_clk();
164 }
Alison Wange2830532013-05-27 22:55:45 +0000165
Bin Meng6338fbd2016-01-13 19:39:03 -0800166 sbr = (u16)(clk / (16 * baudrate));
Alison Wange2830532013-05-27 22:55:45 +0000167
Bin Menga8cc1722016-01-13 19:39:01 -0800168 /* place adjustment later - n/32 BRFA */
Alison Wange2830532013-05-27 22:55:45 +0000169 __raw_writeb(sbr >> 8, &base->ubdh);
170 __raw_writeb(sbr & 0xff, &base->ubdl);
171}
172
Simon Glassb75b15b2020-12-03 16:55:23 -0700173static int _lpuart_serial_getc(struct lpuart_serial_plat *plat)
Alison Wange2830532013-05-27 22:55:45 +0000174{
Peng Fan836a6cc2017-02-22 16:21:51 +0800175 struct lpuart_fsl *base = plat->reg;
Pali Rohár241f12d2022-12-11 00:31:21 +0100176 if (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
177 return -EAGAIN;
Alison Wange2830532013-05-27 22:55:45 +0000178
Stefan Agner24482912014-08-19 17:54:27 +0200179 barrier();
Alison Wange2830532013-05-27 22:55:45 +0000180
181 return __raw_readb(&base->ud);
182}
183
Pali Rohár241f12d2022-12-11 00:31:21 +0100184static int _lpuart_serial_putc(struct lpuart_serial_plat *plat,
Peng Fan836a6cc2017-02-22 16:21:51 +0800185 const char c)
Alison Wange2830532013-05-27 22:55:45 +0000186{
Peng Fan836a6cc2017-02-22 16:21:51 +0800187 struct lpuart_fsl *base = plat->reg;
188
Pali Rohár241f12d2022-12-11 00:31:21 +0100189 if (!(__raw_readb(&base->us1) & US1_TDRE))
190 return -EAGAIN;
Alison Wange2830532013-05-27 22:55:45 +0000191
192 __raw_writeb(c, &base->ud);
Pali Rohár241f12d2022-12-11 00:31:21 +0100193 return 0;
Alison Wange2830532013-05-27 22:55:45 +0000194}
195
Bin Menga8cc1722016-01-13 19:39:01 -0800196/* Test whether a character is in the RX buffer */
Simon Glassb75b15b2020-12-03 16:55:23 -0700197static int _lpuart_serial_tstc(struct lpuart_serial_plat *plat)
Alison Wange2830532013-05-27 22:55:45 +0000198{
Peng Fan836a6cc2017-02-22 16:21:51 +0800199 struct lpuart_fsl *base = plat->reg;
200
Alison Wange2830532013-05-27 22:55:45 +0000201 if (__raw_readb(&base->urcfifo) == 0)
202 return 0;
203
204 return 1;
205}
206
207/*
208 * Initialise the serial port with the given baudrate. The settings
209 * are always 8 data bits, no parity, 1 stop bit, no start bits.
210 */
Peng Fan68e45632018-10-19 00:26:23 +0200211static int _lpuart_serial_init(struct udevice *dev)
Alison Wange2830532013-05-27 22:55:45 +0000212{
Simon Glassb75b15b2020-12-03 16:55:23 -0700213 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fan836a6cc2017-02-22 16:21:51 +0800214 struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg;
Alison Wange2830532013-05-27 22:55:45 +0000215 u8 ctrl;
216
217 ctrl = __raw_readb(&base->uc2);
218 ctrl &= ~UC2_RE;
219 ctrl &= ~UC2_TE;
220 __raw_writeb(ctrl, &base->uc2);
221
222 __raw_writeb(0, &base->umodem);
223 __raw_writeb(0, &base->uc1);
224
Stefan Agner190f1d22014-08-19 17:54:28 +0200225 /* Disable FIFO and flush buffer */
226 __raw_writeb(0x0, &base->upfifo);
227 __raw_writeb(0x0, &base->utwfifo);
228 __raw_writeb(0x1, &base->urwfifo);
229 __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
230
Alison Wange2830532013-05-27 22:55:45 +0000231 /* provide data bits, parity, stop bit, etc */
Peng Fan68e45632018-10-19 00:26:23 +0200232 _lpuart_serial_setbrg(dev, gd->baudrate);
Alison Wange2830532013-05-27 22:55:45 +0000233
234 __raw_writeb(UC2_RE | UC2_TE, &base->uc2);
235
236 return 0;
237}
238
Peng Fan68e45632018-10-19 00:26:23 +0200239static void _lpuart32_serial_setbrg_7ulp(struct udevice *dev,
Peng Fandac2c942017-02-22 16:21:52 +0800240 int baudrate)
241{
Simon Glassb75b15b2020-12-03 16:55:23 -0700242 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fandac2c942017-02-22 16:21:52 +0800243 struct lpuart_fsl_reg32 *base = plat->reg;
244 u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
Peng Fan68e45632018-10-19 00:26:23 +0200245 u32 clk;
246 int ret;
247
Ye Li86cf6992019-07-11 03:33:34 +0000248 if (CONFIG_IS_ENABLED(CLK)) {
Peng Fan68e45632018-10-19 00:26:23 +0200249 ret = get_lpuart_clk_rate(dev, &clk);
250 if (ret)
251 return;
252 } else {
253 clk = get_lpuart_clk();
254 }
Peng Fandac2c942017-02-22 16:21:52 +0800255
256 baud_diff = baudrate;
257 osr = 0;
258 sbr = 0;
259
260 for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
261 tmp_sbr = (clk / (baudrate * tmp_osr));
262
263 if (tmp_sbr == 0)
264 tmp_sbr = 1;
265
266 /*calculate difference in actual buad w/ current values */
267 tmp_diff = (clk / (tmp_osr * tmp_sbr));
268 tmp_diff = tmp_diff - baudrate;
269
270 /* select best values between sbr and sbr+1 */
271 if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) {
272 tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1)));
273 tmp_sbr++;
274 }
275
276 if (tmp_diff <= baud_diff) {
277 baud_diff = tmp_diff;
278 osr = tmp_osr;
279 sbr = tmp_sbr;
280 }
281 }
282
283 /*
284 * TODO: handle buadrate outside acceptable rate
285 * if (baudDiff > ((config->baudRate_Bps / 100) * 3))
286 * {
287 * Unacceptable baud rate difference of more than 3%
288 * return kStatus_LPUART_BaudrateNotSupport;
289 * }
290 */
291 tmp = in_le32(&base->baud);
292
293 if ((osr > 3) && (osr < 8))
294 tmp |= LPUART_BAUD_BOTHEDGE_MASK;
295
296 tmp &= ~LPUART_BAUD_OSR_MASK;
297 tmp |= LPUART_BAUD_OSR(osr-1);
298
299 tmp &= ~LPUART_BAUD_SBR_MASK;
300 tmp |= LPUART_BAUD_SBR(sbr);
301
302 /* explicitly disable 10 bit mode & set 1 stop bit */
303 tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
304
305 out_le32(&base->baud, tmp);
306}
307
Peng Fan68e45632018-10-19 00:26:23 +0200308static void _lpuart32_serial_setbrg(struct udevice *dev,
Peng Fan836a6cc2017-02-22 16:21:51 +0800309 int baudrate)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800310{
Simon Glassb75b15b2020-12-03 16:55:23 -0700311 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fan836a6cc2017-02-22 16:21:51 +0800312 struct lpuart_fsl_reg32 *base = plat->reg;
Peng Fan68e45632018-10-19 00:26:23 +0200313 u32 clk;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800314 u32 sbr;
Peng Fan68e45632018-10-19 00:26:23 +0200315 int ret;
316
Ye Li86cf6992019-07-11 03:33:34 +0000317 if (CONFIG_IS_ENABLED(CLK)) {
Peng Fan68e45632018-10-19 00:26:23 +0200318 ret = get_lpuart_clk_rate(dev, &clk);
319 if (ret)
320 return;
321 } else {
322 clk = get_lpuart_clk();
323 }
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800324
Bin Meng6338fbd2016-01-13 19:39:03 -0800325 sbr = (clk / (16 * baudrate));
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800326
Bin Menga8cc1722016-01-13 19:39:01 -0800327 /* place adjustment later - n/32 BRFA */
Peng Fan836a6cc2017-02-22 16:21:51 +0800328 lpuart_write32(plat->flags, &base->baud, sbr);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800329}
330
Simon Glassb75b15b2020-12-03 16:55:23 -0700331static int _lpuart32_serial_getc(struct lpuart_serial_plat *plat)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800332{
Peng Fan836a6cc2017-02-22 16:21:51 +0800333 struct lpuart_fsl_reg32 *base = plat->reg;
Peng Fandac2c942017-02-22 16:21:52 +0800334 u32 stat, val;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800335
Peng Fan836a6cc2017-02-22 16:21:51 +0800336 lpuart_read32(plat->flags, &base->stat, &stat);
Pali Rohár241f12d2022-12-11 00:31:21 +0100337 if ((stat & STAT_RDRF) == 0) {
Peng Fan836a6cc2017-02-22 16:21:51 +0800338 lpuart_write32(plat->flags, &base->stat, STAT_FLAGS);
Pali Rohár241f12d2022-12-11 00:31:21 +0100339 return -EAGAIN;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800340 }
341
Peng Fandac2c942017-02-22 16:21:52 +0800342 lpuart_read32(plat->flags, &base->data, &val);
Peng Fan836a6cc2017-02-22 16:21:51 +0800343
Sriram Dash32cf46c2018-01-10 11:57:14 +0530344 lpuart_read32(plat->flags, &base->stat, &stat);
345 if (stat & STAT_OR)
346 lpuart_write32(plat->flags, &base->stat, STAT_OR);
Peng Fandac2c942017-02-22 16:21:52 +0800347
348 return val & 0x3ff;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800349}
350
Pali Rohár241f12d2022-12-11 00:31:21 +0100351static int _lpuart32_serial_putc(struct lpuart_serial_plat *plat,
Peng Fan836a6cc2017-02-22 16:21:51 +0800352 const char c)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800353{
Peng Fan836a6cc2017-02-22 16:21:51 +0800354 struct lpuart_fsl_reg32 *base = plat->reg;
355 u32 stat;
356
Pali Rohár241f12d2022-12-11 00:31:21 +0100357 lpuart_read32(plat->flags, &base->stat, &stat);
358 if (!(stat & STAT_TDRE))
359 return -EAGAIN;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800360
Peng Fan836a6cc2017-02-22 16:21:51 +0800361 lpuart_write32(plat->flags, &base->data, c);
Pali Rohár241f12d2022-12-11 00:31:21 +0100362 return 0;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800363}
364
Bin Menga8cc1722016-01-13 19:39:01 -0800365/* Test whether a character is in the RX buffer */
Simon Glassb75b15b2020-12-03 16:55:23 -0700366static int _lpuart32_serial_tstc(struct lpuart_serial_plat *plat)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800367{
Peng Fan836a6cc2017-02-22 16:21:51 +0800368 struct lpuart_fsl_reg32 *base = plat->reg;
369 u32 water;
370
371 lpuart_read32(plat->flags, &base->water, &water);
372
373 if ((water >> 24) == 0)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800374 return 0;
375
376 return 1;
377}
378
379/*
380 * Initialise the serial port with the given baudrate. The settings
381 * are always 8 data bits, no parity, 1 stop bit, no start bits.
382 */
Peng Fan68e45632018-10-19 00:26:23 +0200383static int _lpuart32_serial_init(struct udevice *dev)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800384{
Simon Glassb75b15b2020-12-03 16:55:23 -0700385 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fan836a6cc2017-02-22 16:21:51 +0800386 struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg;
Ye Lia2aedcb2018-10-18 14:28:32 +0200387 u32 val, tx_fifo_size;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800388
Ye Lia2aedcb2018-10-18 14:28:32 +0200389 lpuart_read32(plat->flags, &base->ctrl, &val);
390 val &= ~CTRL_RE;
391 val &= ~CTRL_TE;
392 lpuart_write32(plat->flags, &base->ctrl, val);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800393
Peng Fan836a6cc2017-02-22 16:21:51 +0800394 lpuart_write32(plat->flags, &base->modir, 0);
Ye Lia2aedcb2018-10-18 14:28:32 +0200395
396 lpuart_read32(plat->flags, &base->fifo, &val);
397 tx_fifo_size = (val & FIFO_TXSIZE_MASK) >> FIFO_TXSIZE_OFF;
398 /* Set the TX water to half of FIFO size */
399 if (tx_fifo_size > 1)
400 tx_fifo_size = tx_fifo_size >> 1;
401
402 /* Set RX water to 0, to be triggered by any receive data */
403 lpuart_write32(plat->flags, &base->water,
404 (tx_fifo_size << WATER_TXWATER_OFF));
405
406 /* Enable TX and RX FIFO */
407 val |= (FIFO_TXFE | FIFO_RXFE | FIFO_TXFLUSH | FIFO_RXFLUSH);
408 lpuart_write32(plat->flags, &base->fifo, val);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800409
Peng Fan836a6cc2017-02-22 16:21:51 +0800410 lpuart_write32(plat->flags, &base->match, 0);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800411
Giulio Benetti5eaa97e2020-01-10 15:51:43 +0100412 if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 ||
413 plat->devtype == DEV_IMXRT) {
Peng Fan68e45632018-10-19 00:26:23 +0200414 _lpuart32_serial_setbrg_7ulp(dev, gd->baudrate);
Peng Fandac2c942017-02-22 16:21:52 +0800415 } else {
416 /* provide data bits, parity, stop bit, etc */
Peng Fan68e45632018-10-19 00:26:23 +0200417 _lpuart32_serial_setbrg(dev, gd->baudrate);
Peng Fandac2c942017-02-22 16:21:52 +0800418 }
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800419
Peng Fan836a6cc2017-02-22 16:21:51 +0800420 lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800421
422 return 0;
423}
424
Peng Fan836a6cc2017-02-22 16:21:51 +0800425static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800426{
Simon Glassb75b15b2020-12-03 16:55:23 -0700427 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800428
Peng Fandac2c942017-02-22 16:21:52 +0800429 if (is_lpuart32(dev)) {
Giulio Benetti5eaa97e2020-01-10 15:51:43 +0100430 if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 ||
431 plat->devtype == DEV_IMXRT)
Peng Fan68e45632018-10-19 00:26:23 +0200432 _lpuart32_serial_setbrg_7ulp(dev, baudrate);
Peng Fandac2c942017-02-22 16:21:52 +0800433 else
Peng Fan68e45632018-10-19 00:26:23 +0200434 _lpuart32_serial_setbrg(dev, baudrate);
Peng Fandac2c942017-02-22 16:21:52 +0800435 } else {
Peng Fan68e45632018-10-19 00:26:23 +0200436 _lpuart_serial_setbrg(dev, baudrate);
Peng Fandac2c942017-02-22 16:21:52 +0800437 }
Bin Meng8a70d6d2016-01-13 19:39:04 -0800438
439 return 0;
440}
441
Peng Fan836a6cc2017-02-22 16:21:51 +0800442static int lpuart_serial_getc(struct udevice *dev)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800443{
Simon Glass95588622020-12-22 19:30:28 -0700444 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800445
Peng Fan836a6cc2017-02-22 16:21:51 +0800446 if (is_lpuart32(dev))
447 return _lpuart32_serial_getc(plat);
448
449 return _lpuart_serial_getc(plat);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800450}
451
Peng Fan836a6cc2017-02-22 16:21:51 +0800452static int lpuart_serial_putc(struct udevice *dev, const char c)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800453{
Simon Glass95588622020-12-22 19:30:28 -0700454 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800455
Peng Fan836a6cc2017-02-22 16:21:51 +0800456 if (is_lpuart32(dev))
Pali Rohár241f12d2022-12-11 00:31:21 +0100457 return _lpuart32_serial_putc(plat, c);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800458
Pali Rohár241f12d2022-12-11 00:31:21 +0100459 return _lpuart_serial_putc(plat, c);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800460}
461
Peng Fan836a6cc2017-02-22 16:21:51 +0800462static int lpuart_serial_pending(struct udevice *dev, bool input)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800463{
Simon Glass95588622020-12-22 19:30:28 -0700464 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800465 struct lpuart_fsl *reg = plat->reg;
Peng Fan836a6cc2017-02-22 16:21:51 +0800466 struct lpuart_fsl_reg32 *reg32 = plat->reg;
467 u32 stat;
468
469 if (is_lpuart32(dev)) {
470 if (input) {
471 return _lpuart32_serial_tstc(plat);
472 } else {
473 lpuart_read32(plat->flags, &reg32->stat, &stat);
474 return stat & STAT_TDRE ? 0 : 1;
475 }
476 }
Bin Meng8a70d6d2016-01-13 19:39:04 -0800477
478 if (input)
Peng Fan836a6cc2017-02-22 16:21:51 +0800479 return _lpuart_serial_tstc(plat);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800480 else
Peng Fan836a6cc2017-02-22 16:21:51 +0800481 return __raw_readb(&reg->us1) & US1_TDRE ? 0 : 1;
Bin Meng8a70d6d2016-01-13 19:39:04 -0800482}
483
Peng Fan836a6cc2017-02-22 16:21:51 +0800484static int lpuart_serial_probe(struct udevice *dev)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800485{
Giulio Benetti0ad8b9c2020-01-10 15:47:05 +0100486#if CONFIG_IS_ENABLED(CLK)
Peng Faneec6f382024-04-12 22:24:52 +0800487 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Giulio Benetti0ad8b9c2020-01-10 15:47:05 +0100488 struct clk per_clk;
Ye Li3759c0a2023-07-25 10:08:55 +0200489 struct clk ipg_clk;
Giulio Benetti0ad8b9c2020-01-10 15:47:05 +0100490 int ret;
491
Peng Faneec6f382024-04-12 22:24:52 +0800492 if (plat->devtype != DEV_MX7ULP) {
493 ret = clk_get_by_name(dev, "per", &per_clk);
494 if (!ret) {
495 ret = clk_enable(&per_clk);
496 if (ret) {
497 dev_err(dev, "Failed to enable per clk: %d\n", ret);
498 return ret;
499 }
500 } else {
501 debug("%s: Failed to get per clk: %d\n", __func__, ret);
Giulio Benetti0ad8b9c2020-01-10 15:47:05 +0100502 }
Giulio Benetti0ad8b9c2020-01-10 15:47:05 +0100503 }
Ye Li3759c0a2023-07-25 10:08:55 +0200504
505 ret = clk_get_by_name(dev, "ipg", &ipg_clk);
506 if (!ret) {
507 ret = clk_enable(&ipg_clk);
508 if (ret) {
509 dev_err(dev, "Failed to enable ipg clk: %d\n", ret);
510 return ret;
511 }
512 } else {
513 debug("%s: Failed to get ipg clk: %d\n", __func__, ret);
514 }
Giulio Benetti0ad8b9c2020-01-10 15:47:05 +0100515#endif
516
Peng Fan836a6cc2017-02-22 16:21:51 +0800517 if (is_lpuart32(dev))
Peng Fan68e45632018-10-19 00:26:23 +0200518 return _lpuart32_serial_init(dev);
Peng Fan836a6cc2017-02-22 16:21:51 +0800519 else
Peng Fan68e45632018-10-19 00:26:23 +0200520 return _lpuart_serial_init(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800521}
Alison Wange2830532013-05-27 22:55:45 +0000522
Simon Glassaad29ae2020-12-03 16:55:21 -0700523static int lpuart_serial_of_to_plat(struct udevice *dev)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800524{
Simon Glass95588622020-12-22 19:30:28 -0700525 struct lpuart_serial_plat *plat = dev_get_plat(dev);
Peng Fandac2c942017-02-22 16:21:52 +0800526 const void *blob = gd->fdt_blob;
Simon Glass7a494432017-05-17 17:18:09 -0600527 int node = dev_of_offset(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800528 fdt_addr_t addr;
529
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900530 addr = dev_read_addr(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800531 if (addr == FDT_ADDR_T_NONE)
532 return -EINVAL;
533
Peng Fan836a6cc2017-02-22 16:21:51 +0800534 plat->reg = (void *)addr;
535 plat->flags = dev_get_driver_data(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800536
Vabhav Sharmaa8f78c62019-01-31 12:08:10 +0000537 if (fdtdec_get_bool(blob, node, "little-endian"))
538 plat->flags &= ~LPUART_FLAG_REGMAP_ENDIAN_BIG;
539
Peng Fandac2c942017-02-22 16:21:52 +0800540 if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart"))
541 plat->devtype = DEV_LS1021A;
542 else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart"))
543 plat->devtype = DEV_MX7ULP;
544 else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart"))
545 plat->devtype = DEV_VF610;
Peng Fanb7f9ea92018-10-18 14:28:31 +0200546 else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart"))
547 plat->devtype = DEV_IMX8;
Giulio Benetti5eaa97e2020-01-10 15:51:43 +0100548 else if (!fdt_node_check_compatible(blob, node, "fsl,imxrt-lpuart"))
549 plat->devtype = DEV_IMXRT;
Peng Fandac2c942017-02-22 16:21:52 +0800550
Bin Meng8a70d6d2016-01-13 19:39:04 -0800551 return 0;
552}
553
Bin Meng8a70d6d2016-01-13 19:39:04 -0800554static const struct dm_serial_ops lpuart_serial_ops = {
555 .putc = lpuart_serial_putc,
556 .pending = lpuart_serial_pending,
557 .getc = lpuart_serial_getc,
558 .setbrg = lpuart_serial_setbrg,
559};
560
561static const struct udevice_id lpuart_serial_ids[] = {
Peng Fan836a6cc2017-02-22 16:21:51 +0800562 { .compatible = "fsl,ls1021a-lpuart", .data =
563 LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
Michael Walleb285de42021-10-13 18:14:19 +0200564 { .compatible = "fsl,ls1028a-lpuart",
565 .data = LPUART_FLAG_REGMAP_32BIT_REG },
Peng Fandac2c942017-02-22 16:21:52 +0800566 { .compatible = "fsl,imx7ulp-lpuart",
567 .data = LPUART_FLAG_REGMAP_32BIT_REG },
Peng Fan836a6cc2017-02-22 16:21:51 +0800568 { .compatible = "fsl,vf610-lpuart"},
Peng Fanb7f9ea92018-10-18 14:28:31 +0200569 { .compatible = "fsl,imx8qm-lpuart",
570 .data = LPUART_FLAG_REGMAP_32BIT_REG },
Giulio Benetti5eaa97e2020-01-10 15:51:43 +0100571 { .compatible = "fsl,imxrt-lpuart",
572 .data = LPUART_FLAG_REGMAP_32BIT_REG },
Bin Meng8a70d6d2016-01-13 19:39:04 -0800573 { }
574};
575
576U_BOOT_DRIVER(serial_lpuart) = {
577 .name = "serial_lpuart",
578 .id = UCLASS_SERIAL,
579 .of_match = lpuart_serial_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700580 .of_to_plat = lpuart_serial_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700581 .plat_auto = sizeof(struct lpuart_serial_plat),
Bin Meng8a70d6d2016-01-13 19:39:04 -0800582 .probe = lpuart_serial_probe,
583 .ops = &lpuart_serial_ops,
Bin Meng8a70d6d2016-01-13 19:39:04 -0800584};