1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright 2013 Freescale Semiconductor, Inc.
10 #include <fsl_lpuart.h>
14 #include <linux/compiler.h>
15 #include <asm/arch/imx-regs.h>
16 #include <asm/arch/clock.h>
18 #define US1_TDRE (1 << 7)
19 #define US1_RDRF (1 << 5)
20 #define US1_OR (1 << 3)
21 #define UC2_TE (1 << 3)
22 #define UC2_RE (1 << 2)
23 #define CFIFO_TXFLUSH (1 << 7)
24 #define CFIFO_RXFLUSH (1 << 6)
25 #define SFIFO_RXOF (1 << 2)
26 #define SFIFO_RXUF (1 << 0)
28 #define STAT_LBKDIF (1 << 31)
29 #define STAT_RXEDGIF (1 << 30)
30 #define STAT_TDRE (1 << 23)
31 #define STAT_RDRF (1 << 21)
32 #define STAT_IDLE (1 << 20)
33 #define STAT_OR (1 << 19)
34 #define STAT_NF (1 << 18)
35 #define STAT_FE (1 << 17)
36 #define STAT_PF (1 << 16)
37 #define STAT_MA1F (1 << 15)
38 #define STAT_MA2F (1 << 14)
39 #define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \
40 STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
42 #define CTRL_TE (1 << 19)
43 #define CTRL_RE (1 << 18)
45 #define FIFO_RXFLUSH BIT(14)
46 #define FIFO_TXFLUSH BIT(15)
47 #define FIFO_TXSIZE_MASK 0x70
48 #define FIFO_TXSIZE_OFF 4
49 #define FIFO_RXSIZE_MASK 0x7
50 #define FIFO_RXSIZE_OFF 0
51 #define FIFO_TXFE 0x80
52 #if defined(CONFIG_ARCH_IMX8) || defined(CONFIG_ARCH_IMXRT)
53 #define FIFO_RXFE 0x08
55 #define FIFO_RXFE 0x40
58 #define WATER_TXWATER_OFF 0
59 #define WATER_RXWATER_OFF 16
61 DECLARE_GLOBAL_DATA_PTR;
63 #define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
64 #define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
74 struct lpuart_serial_platdata {
76 enum lpuart_devtype devtype;
80 static void lpuart_read32(u32 flags, u32 *addr, u32 *val)
82 if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
83 if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
84 *(u32 *)val = in_be32(addr);
86 *(u32 *)val = in_le32(addr);
90 static void lpuart_write32(u32 flags, u32 *addr, u32 val)
92 if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
93 if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
101 #ifndef CONFIG_SYS_CLK_FREQ
102 #define CONFIG_SYS_CLK_FREQ 0
105 u32 __weak get_lpuart_clk(void)
107 return CONFIG_SYS_CLK_FREQ;
110 #if CONFIG_IS_ENABLED(CLK)
111 static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk)
117 ret = clk_get_by_name(dev, "per", &per_clk);
119 dev_err(dev, "Failed to get per clk: %d\n", ret);
123 rate = clk_get_rate(&per_clk);
124 if ((long)rate <= 0) {
125 dev_err(dev, "Failed to get per clk rate: %ld\n", (long)rate);
132 static inline int get_lpuart_clk_rate(struct udevice *dev, u32 *clk)
136 static bool is_lpuart32(struct udevice *dev)
138 struct lpuart_serial_platdata *plat = dev->platdata;
140 return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG;
143 static void _lpuart_serial_setbrg(struct udevice *dev,
146 struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
147 struct lpuart_fsl *base = plat->reg;
152 if (CONFIG_IS_ENABLED(CLK)) {
153 ret = get_lpuart_clk_rate(dev, &clk);
157 clk = get_lpuart_clk();
160 sbr = (u16)(clk / (16 * baudrate));
162 /* place adjustment later - n/32 BRFA */
163 __raw_writeb(sbr >> 8, &base->ubdh);
164 __raw_writeb(sbr & 0xff, &base->ubdl);
167 static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat)
169 struct lpuart_fsl *base = plat->reg;
170 while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
175 return __raw_readb(&base->ud);
178 static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat,
181 struct lpuart_fsl *base = plat->reg;
183 while (!(__raw_readb(&base->us1) & US1_TDRE))
186 __raw_writeb(c, &base->ud);
189 /* Test whether a character is in the RX buffer */
190 static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat)
192 struct lpuart_fsl *base = plat->reg;
194 if (__raw_readb(&base->urcfifo) == 0)
201 * Initialise the serial port with the given baudrate. The settings
202 * are always 8 data bits, no parity, 1 stop bit, no start bits.
204 static int _lpuart_serial_init(struct udevice *dev)
206 struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
207 struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg;
210 ctrl = __raw_readb(&base->uc2);
213 __raw_writeb(ctrl, &base->uc2);
215 __raw_writeb(0, &base->umodem);
216 __raw_writeb(0, &base->uc1);
218 /* Disable FIFO and flush buffer */
219 __raw_writeb(0x0, &base->upfifo);
220 __raw_writeb(0x0, &base->utwfifo);
221 __raw_writeb(0x1, &base->urwfifo);
222 __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
224 /* provide data bits, parity, stop bit, etc */
225 _lpuart_serial_setbrg(dev, gd->baudrate);
227 __raw_writeb(UC2_RE | UC2_TE, &base->uc2);
232 static void _lpuart32_serial_setbrg_7ulp(struct udevice *dev,
235 struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
236 struct lpuart_fsl_reg32 *base = plat->reg;
237 u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
241 if (CONFIG_IS_ENABLED(CLK)) {
242 ret = get_lpuart_clk_rate(dev, &clk);
246 clk = get_lpuart_clk();
249 baud_diff = baudrate;
253 for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
254 tmp_sbr = (clk / (baudrate * tmp_osr));
259 /*calculate difference in actual buad w/ current values */
260 tmp_diff = (clk / (tmp_osr * tmp_sbr));
261 tmp_diff = tmp_diff - baudrate;
263 /* select best values between sbr and sbr+1 */
264 if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) {
265 tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1)));
269 if (tmp_diff <= baud_diff) {
270 baud_diff = tmp_diff;
277 * TODO: handle buadrate outside acceptable rate
278 * if (baudDiff > ((config->baudRate_Bps / 100) * 3))
280 * Unacceptable baud rate difference of more than 3%
281 * return kStatus_LPUART_BaudrateNotSupport;
284 tmp = in_le32(&base->baud);
286 if ((osr > 3) && (osr < 8))
287 tmp |= LPUART_BAUD_BOTHEDGE_MASK;
289 tmp &= ~LPUART_BAUD_OSR_MASK;
290 tmp |= LPUART_BAUD_OSR(osr-1);
292 tmp &= ~LPUART_BAUD_SBR_MASK;
293 tmp |= LPUART_BAUD_SBR(sbr);
295 /* explicitly disable 10 bit mode & set 1 stop bit */
296 tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
298 out_le32(&base->baud, tmp);
301 static void _lpuart32_serial_setbrg(struct udevice *dev,
304 struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
305 struct lpuart_fsl_reg32 *base = plat->reg;
310 if (CONFIG_IS_ENABLED(CLK)) {
311 ret = get_lpuart_clk_rate(dev, &clk);
315 clk = get_lpuart_clk();
318 sbr = (clk / (16 * baudrate));
320 /* place adjustment later - n/32 BRFA */
321 lpuart_write32(plat->flags, &base->baud, sbr);
324 static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
326 struct lpuart_fsl_reg32 *base = plat->reg;
329 lpuart_read32(plat->flags, &base->stat, &stat);
330 while ((stat & STAT_RDRF) == 0) {
331 lpuart_write32(plat->flags, &base->stat, STAT_FLAGS);
333 lpuart_read32(plat->flags, &base->stat, &stat);
336 lpuart_read32(plat->flags, &base->data, &val);
338 lpuart_read32(plat->flags, &base->stat, &stat);
340 lpuart_write32(plat->flags, &base->stat, STAT_OR);
345 static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
348 struct lpuart_fsl_reg32 *base = plat->reg;
355 lpuart_read32(plat->flags, &base->stat, &stat);
357 if ((stat & STAT_TDRE))
363 lpuart_write32(plat->flags, &base->data, c);
366 /* Test whether a character is in the RX buffer */
367 static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat)
369 struct lpuart_fsl_reg32 *base = plat->reg;
372 lpuart_read32(plat->flags, &base->water, &water);
374 if ((water >> 24) == 0)
381 * Initialise the serial port with the given baudrate. The settings
382 * are always 8 data bits, no parity, 1 stop bit, no start bits.
384 static int _lpuart32_serial_init(struct udevice *dev)
386 struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
387 struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg;
388 u32 val, tx_fifo_size;
390 lpuart_read32(plat->flags, &base->ctrl, &val);
393 lpuart_write32(plat->flags, &base->ctrl, val);
395 lpuart_write32(plat->flags, &base->modir, 0);
397 lpuart_read32(plat->flags, &base->fifo, &val);
398 tx_fifo_size = (val & FIFO_TXSIZE_MASK) >> FIFO_TXSIZE_OFF;
399 /* Set the TX water to half of FIFO size */
400 if (tx_fifo_size > 1)
401 tx_fifo_size = tx_fifo_size >> 1;
403 /* Set RX water to 0, to be triggered by any receive data */
404 lpuart_write32(plat->flags, &base->water,
405 (tx_fifo_size << WATER_TXWATER_OFF));
407 /* Enable TX and RX FIFO */
408 val |= (FIFO_TXFE | FIFO_RXFE | FIFO_TXFLUSH | FIFO_RXFLUSH);
409 lpuart_write32(plat->flags, &base->fifo, val);
411 lpuart_write32(plat->flags, &base->match, 0);
413 if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 ||
414 plat->devtype == DEV_IMXRT) {
415 _lpuart32_serial_setbrg_7ulp(dev, gd->baudrate);
417 /* provide data bits, parity, stop bit, etc */
418 _lpuart32_serial_setbrg(dev, gd->baudrate);
421 lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
426 static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
428 struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
430 if (is_lpuart32(dev)) {
431 if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 ||
432 plat->devtype == DEV_IMXRT)
433 _lpuart32_serial_setbrg_7ulp(dev, baudrate);
435 _lpuart32_serial_setbrg(dev, baudrate);
437 _lpuart_serial_setbrg(dev, baudrate);
443 static int lpuart_serial_getc(struct udevice *dev)
445 struct lpuart_serial_platdata *plat = dev->platdata;
447 if (is_lpuart32(dev))
448 return _lpuart32_serial_getc(plat);
450 return _lpuart_serial_getc(plat);
453 static int lpuart_serial_putc(struct udevice *dev, const char c)
455 struct lpuart_serial_platdata *plat = dev->platdata;
457 if (is_lpuart32(dev))
458 _lpuart32_serial_putc(plat, c);
460 _lpuart_serial_putc(plat, c);
465 static int lpuart_serial_pending(struct udevice *dev, bool input)
467 struct lpuart_serial_platdata *plat = dev->platdata;
468 struct lpuart_fsl *reg = plat->reg;
469 struct lpuart_fsl_reg32 *reg32 = plat->reg;
472 if (is_lpuart32(dev)) {
474 return _lpuart32_serial_tstc(plat);
476 lpuart_read32(plat->flags, ®32->stat, &stat);
477 return stat & STAT_TDRE ? 0 : 1;
482 return _lpuart_serial_tstc(plat);
484 return __raw_readb(®->us1) & US1_TDRE ? 0 : 1;
487 static int lpuart_serial_probe(struct udevice *dev)
489 #if CONFIG_IS_ENABLED(CLK)
493 ret = clk_get_by_name(dev, "per", &per_clk);
495 ret = clk_enable(&per_clk);
497 dev_err(dev, "Failed to get per clk: %d\n", ret);
501 dev_warn(dev, "Failed to get per clk: %d\n", ret);
505 if (is_lpuart32(dev))
506 return _lpuart32_serial_init(dev);
508 return _lpuart_serial_init(dev);
511 static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
513 struct lpuart_serial_platdata *plat = dev->platdata;
514 const void *blob = gd->fdt_blob;
515 int node = dev_of_offset(dev);
518 addr = devfdt_get_addr(dev);
519 if (addr == FDT_ADDR_T_NONE)
522 plat->reg = (void *)addr;
523 plat->flags = dev_get_driver_data(dev);
525 if (fdtdec_get_bool(blob, node, "little-endian"))
526 plat->flags &= ~LPUART_FLAG_REGMAP_ENDIAN_BIG;
528 if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart"))
529 plat->devtype = DEV_LS1021A;
530 else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart"))
531 plat->devtype = DEV_MX7ULP;
532 else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart"))
533 plat->devtype = DEV_VF610;
534 else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart"))
535 plat->devtype = DEV_IMX8;
536 else if (!fdt_node_check_compatible(blob, node, "fsl,imxrt-lpuart"))
537 plat->devtype = DEV_IMXRT;
542 static const struct dm_serial_ops lpuart_serial_ops = {
543 .putc = lpuart_serial_putc,
544 .pending = lpuart_serial_pending,
545 .getc = lpuart_serial_getc,
546 .setbrg = lpuart_serial_setbrg,
549 static const struct udevice_id lpuart_serial_ids[] = {
550 { .compatible = "fsl,ls1021a-lpuart", .data =
551 LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
552 { .compatible = "fsl,imx7ulp-lpuart",
553 .data = LPUART_FLAG_REGMAP_32BIT_REG },
554 { .compatible = "fsl,vf610-lpuart"},
555 { .compatible = "fsl,imx8qm-lpuart",
556 .data = LPUART_FLAG_REGMAP_32BIT_REG },
557 { .compatible = "fsl,imxrt-lpuart",
558 .data = LPUART_FLAG_REGMAP_32BIT_REG },
562 U_BOOT_DRIVER(serial_lpuart) = {
563 .name = "serial_lpuart",
565 .of_match = lpuart_serial_ids,
566 .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
567 .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
568 .probe = lpuart_serial_probe,
569 .ops = &lpuart_serial_ops,