blob: 3f030a622f2f7ed9440084dae5be8718ea700e68 [file] [log] [blame]
Alison Wange2830532013-05-27 22:55:45 +00001/*
2 * Copyright 2013 Freescale Semiconductor, Inc.
3 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Alison Wange2830532013-05-27 22:55:45 +00005 */
6
7#include <common.h>
Bin Meng8a70d6d2016-01-13 19:39:04 -08008#include <dm.h>
Peng Fan836a6cc2017-02-22 16:21:51 +08009#include <fsl_lpuart.h>
Alison Wange2830532013-05-27 22:55:45 +000010#include <watchdog.h>
11#include <asm/io.h>
12#include <serial.h>
13#include <linux/compiler.h>
14#include <asm/arch/imx-regs.h>
15#include <asm/arch/clock.h>
16
Bin Menga8cc1722016-01-13 19:39:01 -080017#define US1_TDRE (1 << 7)
18#define US1_RDRF (1 << 5)
19#define US1_OR (1 << 3)
20#define UC2_TE (1 << 3)
21#define UC2_RE (1 << 2)
22#define CFIFO_TXFLUSH (1 << 7)
23#define CFIFO_RXFLUSH (1 << 6)
24#define SFIFO_RXOF (1 << 2)
25#define SFIFO_RXUF (1 << 0)
Alison Wange2830532013-05-27 22:55:45 +000026
Jingchang Lu4a7154e2014-09-05 13:52:47 +080027#define STAT_LBKDIF (1 << 31)
28#define STAT_RXEDGIF (1 << 30)
29#define STAT_TDRE (1 << 23)
30#define STAT_RDRF (1 << 21)
31#define STAT_IDLE (1 << 20)
32#define STAT_OR (1 << 19)
33#define STAT_NF (1 << 18)
34#define STAT_FE (1 << 17)
35#define STAT_PF (1 << 16)
36#define STAT_MA1F (1 << 15)
37#define STAT_MA2F (1 << 14)
38#define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \
Bin Menga8cc1722016-01-13 19:39:01 -080039 STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
Jingchang Lu4a7154e2014-09-05 13:52:47 +080040
41#define CTRL_TE (1 << 19)
42#define CTRL_RE (1 << 18)
43
44#define FIFO_TXFE 0x80
45#define FIFO_RXFE 0x40
46
47#define WATER_TXWATER_OFF 1
48#define WATER_RXWATER_OFF 16
49
Alison Wange2830532013-05-27 22:55:45 +000050DECLARE_GLOBAL_DATA_PTR;
51
Peng Fan836a6cc2017-02-22 16:21:51 +080052#define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
53#define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
54
Bin Meng8a70d6d2016-01-13 19:39:04 -080055struct lpuart_serial_platdata {
Peng Fan836a6cc2017-02-22 16:21:51 +080056 void *reg;
57 ulong flags;
Bin Meng8a70d6d2016-01-13 19:39:04 -080058};
59
Peng Fan836a6cc2017-02-22 16:21:51 +080060static void lpuart_read32(u32 flags, u32 *addr, u32 *val)
61{
62 if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
63 if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
64 *(u32 *)val = in_be32(addr);
65 else
66 *(u32 *)val = in_le32(addr);
67 }
68}
69
70static void lpuart_write32(u32 flags, u32 *addr, u32 val)
71{
72 if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
73 if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
74 out_be32(addr, val);
75 else
76 out_le32(addr, val);
77 }
78}
79
80
81#ifndef CONFIG_SYS_CLK_FREQ
82#define CONFIG_SYS_CLK_FREQ 0
83#endif
84
85u32 __weak get_lpuart_clk(void)
Alison Wange2830532013-05-27 22:55:45 +000086{
Peng Fan836a6cc2017-02-22 16:21:51 +080087 return CONFIG_SYS_CLK_FREQ;
88}
89
90static bool is_lpuart32(struct udevice *dev)
91{
92 struct lpuart_serial_platdata *plat = dev->platdata;
93
94 return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG;
95}
96
97static void _lpuart_serial_setbrg(struct lpuart_serial_platdata *plat,
98 int baudrate)
99{
100 struct lpuart_fsl *base = plat->reg;
101 u32 clk = get_lpuart_clk();
Alison Wange2830532013-05-27 22:55:45 +0000102 u16 sbr;
103
Bin Meng6338fbd2016-01-13 19:39:03 -0800104 sbr = (u16)(clk / (16 * baudrate));
Alison Wange2830532013-05-27 22:55:45 +0000105
Bin Menga8cc1722016-01-13 19:39:01 -0800106 /* place adjustment later - n/32 BRFA */
Alison Wange2830532013-05-27 22:55:45 +0000107 __raw_writeb(sbr >> 8, &base->ubdh);
108 __raw_writeb(sbr & 0xff, &base->ubdl);
109}
110
Peng Fan836a6cc2017-02-22 16:21:51 +0800111static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat)
Alison Wange2830532013-05-27 22:55:45 +0000112{
Peng Fan836a6cc2017-02-22 16:21:51 +0800113 struct lpuart_fsl *base = plat->reg;
Stefan Agner24482912014-08-19 17:54:27 +0200114 while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
Alison Wange2830532013-05-27 22:55:45 +0000115 WATCHDOG_RESET();
116
Stefan Agner24482912014-08-19 17:54:27 +0200117 barrier();
Alison Wange2830532013-05-27 22:55:45 +0000118
119 return __raw_readb(&base->ud);
120}
121
Peng Fan836a6cc2017-02-22 16:21:51 +0800122static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat,
123 const char c)
Alison Wange2830532013-05-27 22:55:45 +0000124{
Peng Fan836a6cc2017-02-22 16:21:51 +0800125 struct lpuart_fsl *base = plat->reg;
126
Alison Wange2830532013-05-27 22:55:45 +0000127 while (!(__raw_readb(&base->us1) & US1_TDRE))
128 WATCHDOG_RESET();
129
130 __raw_writeb(c, &base->ud);
131}
132
Bin Menga8cc1722016-01-13 19:39:01 -0800133/* Test whether a character is in the RX buffer */
Peng Fan836a6cc2017-02-22 16:21:51 +0800134static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat)
Alison Wange2830532013-05-27 22:55:45 +0000135{
Peng Fan836a6cc2017-02-22 16:21:51 +0800136 struct lpuart_fsl *base = plat->reg;
137
Alison Wange2830532013-05-27 22:55:45 +0000138 if (__raw_readb(&base->urcfifo) == 0)
139 return 0;
140
141 return 1;
142}
143
144/*
145 * Initialise the serial port with the given baudrate. The settings
146 * are always 8 data bits, no parity, 1 stop bit, no start bits.
147 */
Peng Fan836a6cc2017-02-22 16:21:51 +0800148static int _lpuart_serial_init(struct lpuart_serial_platdata *plat)
Alison Wange2830532013-05-27 22:55:45 +0000149{
Peng Fan836a6cc2017-02-22 16:21:51 +0800150 struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg;
Alison Wange2830532013-05-27 22:55:45 +0000151 u8 ctrl;
152
153 ctrl = __raw_readb(&base->uc2);
154 ctrl &= ~UC2_RE;
155 ctrl &= ~UC2_TE;
156 __raw_writeb(ctrl, &base->uc2);
157
158 __raw_writeb(0, &base->umodem);
159 __raw_writeb(0, &base->uc1);
160
Stefan Agner190f1d22014-08-19 17:54:28 +0200161 /* Disable FIFO and flush buffer */
162 __raw_writeb(0x0, &base->upfifo);
163 __raw_writeb(0x0, &base->utwfifo);
164 __raw_writeb(0x1, &base->urwfifo);
165 __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
166
Alison Wange2830532013-05-27 22:55:45 +0000167 /* provide data bits, parity, stop bit, etc */
Peng Fan836a6cc2017-02-22 16:21:51 +0800168 _lpuart_serial_setbrg(plat, gd->baudrate);
Alison Wange2830532013-05-27 22:55:45 +0000169
170 __raw_writeb(UC2_RE | UC2_TE, &base->uc2);
171
172 return 0;
173}
174
Peng Fan836a6cc2017-02-22 16:21:51 +0800175static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat,
176 int baudrate)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800177{
Peng Fan836a6cc2017-02-22 16:21:51 +0800178 struct lpuart_fsl_reg32 *base = plat->reg;
Shaohui Xie957b6722016-10-28 14:23:30 +0800179 u32 clk = get_lpuart_clk();
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800180 u32 sbr;
181
Bin Meng6338fbd2016-01-13 19:39:03 -0800182 sbr = (clk / (16 * baudrate));
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800183
Bin Menga8cc1722016-01-13 19:39:01 -0800184 /* place adjustment later - n/32 BRFA */
Peng Fan836a6cc2017-02-22 16:21:51 +0800185 lpuart_write32(plat->flags, &base->baud, sbr);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800186}
187
Peng Fan836a6cc2017-02-22 16:21:51 +0800188static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800189{
Peng Fan836a6cc2017-02-22 16:21:51 +0800190 struct lpuart_fsl_reg32 *base = plat->reg;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800191 u32 stat;
192
Peng Fan836a6cc2017-02-22 16:21:51 +0800193 lpuart_read32(plat->flags, &base->stat, &stat);
194 while ((stat & STAT_RDRF) == 0) {
195 lpuart_write32(plat->flags, &base->stat, STAT_FLAGS);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800196 WATCHDOG_RESET();
Peng Fan836a6cc2017-02-22 16:21:51 +0800197 lpuart_read32(plat->flags, &base->stat, &stat);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800198 }
199
Peng Fan836a6cc2017-02-22 16:21:51 +0800200 /* Reuse stat */
201 lpuart_read32(plat->flags, &base->data, &stat);
202
203 return stat & 0x3ff;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800204}
205
Peng Fan836a6cc2017-02-22 16:21:51 +0800206static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
207 const char c)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800208{
Peng Fan836a6cc2017-02-22 16:21:51 +0800209 struct lpuart_fsl_reg32 *base = plat->reg;
210 u32 stat;
211
212 while (true) {
213 lpuart_read32(plat->flags, &base->stat, &stat);
214
215 if ((stat & STAT_TDRE))
216 break;
217
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800218 WATCHDOG_RESET();
Peng Fan836a6cc2017-02-22 16:21:51 +0800219 }
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800220
Peng Fan836a6cc2017-02-22 16:21:51 +0800221 lpuart_write32(plat->flags, &base->data, c);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800222}
223
Bin Menga8cc1722016-01-13 19:39:01 -0800224/* Test whether a character is in the RX buffer */
Peng Fan836a6cc2017-02-22 16:21:51 +0800225static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800226{
Peng Fan836a6cc2017-02-22 16:21:51 +0800227 struct lpuart_fsl_reg32 *base = plat->reg;
228 u32 water;
229
230 lpuart_read32(plat->flags, &base->water, &water);
231
232 if ((water >> 24) == 0)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800233 return 0;
234
235 return 1;
236}
237
238/*
239 * Initialise the serial port with the given baudrate. The settings
240 * are always 8 data bits, no parity, 1 stop bit, no start bits.
241 */
Peng Fan836a6cc2017-02-22 16:21:51 +0800242static int _lpuart32_serial_init(struct lpuart_serial_platdata *plat)
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800243{
Peng Fan836a6cc2017-02-22 16:21:51 +0800244 struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg;
245 u32 ctrl;
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800246
Peng Fan836a6cc2017-02-22 16:21:51 +0800247 lpuart_read32(plat->flags, &base->ctrl, &ctrl);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800248 ctrl &= ~CTRL_RE;
249 ctrl &= ~CTRL_TE;
Peng Fan836a6cc2017-02-22 16:21:51 +0800250 lpuart_write32(plat->flags, &base->ctrl, ctrl);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800251
Peng Fan836a6cc2017-02-22 16:21:51 +0800252 lpuart_write32(plat->flags, &base->modir, 0);
253 lpuart_write32(plat->flags, &base->fifo, ~(FIFO_TXFE | FIFO_RXFE));
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800254
Peng Fan836a6cc2017-02-22 16:21:51 +0800255 lpuart_write32(plat->flags, &base->match, 0);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800256
Bin Menga8cc1722016-01-13 19:39:01 -0800257 /* provide data bits, parity, stop bit, etc */
Peng Fan836a6cc2017-02-22 16:21:51 +0800258 _lpuart32_serial_setbrg(plat, gd->baudrate);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800259
Peng Fan836a6cc2017-02-22 16:21:51 +0800260 lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
Jingchang Lu4a7154e2014-09-05 13:52:47 +0800261
262 return 0;
263}
264
Peng Fan836a6cc2017-02-22 16:21:51 +0800265static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800266{
267 struct lpuart_serial_platdata *plat = dev->platdata;
Bin Meng8a70d6d2016-01-13 19:39:04 -0800268
Peng Fan836a6cc2017-02-22 16:21:51 +0800269 if (is_lpuart32(dev))
270 _lpuart32_serial_setbrg(plat, baudrate);
271 else
272 _lpuart_serial_setbrg(plat, baudrate);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800273
274 return 0;
275}
276
Peng Fan836a6cc2017-02-22 16:21:51 +0800277static int lpuart_serial_getc(struct udevice *dev)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800278{
279 struct lpuart_serial_platdata *plat = dev->platdata;
Bin Meng8a70d6d2016-01-13 19:39:04 -0800280
Peng Fan836a6cc2017-02-22 16:21:51 +0800281 if (is_lpuart32(dev))
282 return _lpuart32_serial_getc(plat);
283
284 return _lpuart_serial_getc(plat);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800285}
286
Peng Fan836a6cc2017-02-22 16:21:51 +0800287static int lpuart_serial_putc(struct udevice *dev, const char c)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800288{
289 struct lpuart_serial_platdata *plat = dev->platdata;
Bin Meng8a70d6d2016-01-13 19:39:04 -0800290
Peng Fan836a6cc2017-02-22 16:21:51 +0800291 if (is_lpuart32(dev))
292 _lpuart32_serial_putc(plat, c);
293 else
294 _lpuart_serial_putc(plat, c);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800295
296 return 0;
297}
298
Peng Fan836a6cc2017-02-22 16:21:51 +0800299static int lpuart_serial_pending(struct udevice *dev, bool input)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800300{
301 struct lpuart_serial_platdata *plat = dev->platdata;
302 struct lpuart_fsl *reg = plat->reg;
Peng Fan836a6cc2017-02-22 16:21:51 +0800303 struct lpuart_fsl_reg32 *reg32 = plat->reg;
304 u32 stat;
305
306 if (is_lpuart32(dev)) {
307 if (input) {
308 return _lpuart32_serial_tstc(plat);
309 } else {
310 lpuart_read32(plat->flags, &reg32->stat, &stat);
311 return stat & STAT_TDRE ? 0 : 1;
312 }
313 }
Bin Meng8a70d6d2016-01-13 19:39:04 -0800314
315 if (input)
Peng Fan836a6cc2017-02-22 16:21:51 +0800316 return _lpuart_serial_tstc(plat);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800317 else
Peng Fan836a6cc2017-02-22 16:21:51 +0800318 return __raw_readb(&reg->us1) & US1_TDRE ? 0 : 1;
Bin Meng8a70d6d2016-01-13 19:39:04 -0800319}
320
Peng Fan836a6cc2017-02-22 16:21:51 +0800321static int lpuart_serial_probe(struct udevice *dev)
Bin Meng8a70d6d2016-01-13 19:39:04 -0800322{
323 struct lpuart_serial_platdata *plat = dev->platdata;
Bin Meng8a70d6d2016-01-13 19:39:04 -0800324
Peng Fan836a6cc2017-02-22 16:21:51 +0800325 if (is_lpuart32(dev))
326 return _lpuart32_serial_init(plat);
327 else
328 return _lpuart_serial_init(plat);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800329}
Alison Wange2830532013-05-27 22:55:45 +0000330
Bin Meng8a70d6d2016-01-13 19:39:04 -0800331static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
332{
333 struct lpuart_serial_platdata *plat = dev->platdata;
334 fdt_addr_t addr;
335
336 addr = dev_get_addr(dev);
337 if (addr == FDT_ADDR_T_NONE)
338 return -EINVAL;
339
Peng Fan836a6cc2017-02-22 16:21:51 +0800340 plat->reg = (void *)addr;
341 plat->flags = dev_get_driver_data(dev);
Bin Meng8a70d6d2016-01-13 19:39:04 -0800342
343 return 0;
344}
345
Bin Meng8a70d6d2016-01-13 19:39:04 -0800346static const struct dm_serial_ops lpuart_serial_ops = {
347 .putc = lpuart_serial_putc,
348 .pending = lpuart_serial_pending,
349 .getc = lpuart_serial_getc,
350 .setbrg = lpuart_serial_setbrg,
351};
352
353static const struct udevice_id lpuart_serial_ids[] = {
Peng Fan836a6cc2017-02-22 16:21:51 +0800354 { .compatible = "fsl,ls1021a-lpuart", .data =
355 LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
356 { .compatible = "fsl,vf610-lpuart"},
Bin Meng8a70d6d2016-01-13 19:39:04 -0800357 { }
358};
359
360U_BOOT_DRIVER(serial_lpuart) = {
361 .name = "serial_lpuart",
362 .id = UCLASS_SERIAL,
363 .of_match = lpuart_serial_ids,
364 .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
365 .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
366 .probe = lpuart_serial_probe,
367 .ops = &lpuart_serial_ops,
368 .flags = DM_FLAG_PRE_RELOC,
369};