183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2427eba70SAlison Wang /* 3427eba70SAlison Wang * Copyright 2013 Freescale Semiconductor, Inc. 4427eba70SAlison Wang */ 5427eba70SAlison Wang 6427eba70SAlison Wang #include <common.h> 7fdbae099SBin Meng #include <dm.h> 8c40d612bSPeng Fan #include <fsl_lpuart.h> 9427eba70SAlison Wang #include <watchdog.h> 10427eba70SAlison Wang #include <asm/io.h> 11427eba70SAlison Wang #include <serial.h> 12427eba70SAlison Wang #include <linux/compiler.h> 13427eba70SAlison Wang #include <asm/arch/imx-regs.h> 14427eba70SAlison Wang #include <asm/arch/clock.h> 15427eba70SAlison Wang 16427eba70SAlison Wang #define US1_TDRE (1 << 7) 17427eba70SAlison Wang #define US1_RDRF (1 << 5) 18a3db78d8SStefan Agner #define US1_OR (1 << 3) 19427eba70SAlison Wang #define UC2_TE (1 << 3) 20427eba70SAlison Wang #define UC2_RE (1 << 2) 2189e69fd4SStefan Agner #define CFIFO_TXFLUSH (1 << 7) 2289e69fd4SStefan Agner #define CFIFO_RXFLUSH (1 << 6) 2389e69fd4SStefan Agner #define SFIFO_RXOF (1 << 2) 2489e69fd4SStefan Agner #define SFIFO_RXUF (1 << 0) 25427eba70SAlison Wang 266209e14cSJingchang Lu #define STAT_LBKDIF (1 << 31) 276209e14cSJingchang Lu #define STAT_RXEDGIF (1 << 30) 286209e14cSJingchang Lu #define STAT_TDRE (1 << 23) 296209e14cSJingchang Lu #define STAT_RDRF (1 << 21) 306209e14cSJingchang Lu #define STAT_IDLE (1 << 20) 316209e14cSJingchang Lu #define STAT_OR (1 << 19) 326209e14cSJingchang Lu #define STAT_NF (1 << 18) 336209e14cSJingchang Lu #define STAT_FE (1 << 17) 346209e14cSJingchang Lu #define STAT_PF (1 << 16) 356209e14cSJingchang Lu #define STAT_MA1F (1 << 15) 366209e14cSJingchang Lu #define STAT_MA2F (1 << 14) 376209e14cSJingchang Lu #define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \ 386209e14cSJingchang Lu STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F) 396209e14cSJingchang Lu 406209e14cSJingchang Lu #define CTRL_TE (1 << 19) 416209e14cSJingchang Lu #define CTRL_RE (1 << 18) 426209e14cSJingchang Lu 436209e14cSJingchang Lu #define FIFO_TXFE 0x80 44*126f8849SPeng Fan #ifdef CONFIG_ARCH_IMX8 45*126f8849SPeng Fan #define FIFO_RXFE 0x08 46*126f8849SPeng Fan #else 476209e14cSJingchang Lu #define FIFO_RXFE 0x40 48*126f8849SPeng Fan #endif 496209e14cSJingchang Lu 506209e14cSJingchang Lu #define WATER_TXWATER_OFF 1 516209e14cSJingchang Lu #define WATER_RXWATER_OFF 16 526209e14cSJingchang Lu 53427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 54427eba70SAlison Wang 55c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_32BIT_REG BIT(0) 56c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1) 57c40d612bSPeng Fan 587edf5c45SPeng Fan enum lpuart_devtype { 597edf5c45SPeng Fan DEV_VF610 = 1, 607edf5c45SPeng Fan DEV_LS1021A, 61*126f8849SPeng Fan DEV_MX7ULP, 62*126f8849SPeng Fan DEV_IMX8 637edf5c45SPeng Fan }; 647edf5c45SPeng Fan 65fdbae099SBin Meng struct lpuart_serial_platdata { 66c40d612bSPeng Fan void *reg; 677edf5c45SPeng Fan enum lpuart_devtype devtype; 68c40d612bSPeng Fan ulong flags; 69fdbae099SBin Meng }; 70fdbae099SBin Meng 71c40d612bSPeng Fan static void lpuart_read32(u32 flags, u32 *addr, u32 *val) 72427eba70SAlison Wang { 73c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 74c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 75c40d612bSPeng Fan *(u32 *)val = in_be32(addr); 76c40d612bSPeng Fan else 77c40d612bSPeng Fan *(u32 *)val = in_le32(addr); 78c40d612bSPeng Fan } 79c40d612bSPeng Fan } 80c40d612bSPeng Fan 81c40d612bSPeng Fan static void lpuart_write32(u32 flags, u32 *addr, u32 val) 82c40d612bSPeng Fan { 83c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 84c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 85c40d612bSPeng Fan out_be32(addr, val); 86c40d612bSPeng Fan else 87c40d612bSPeng Fan out_le32(addr, val); 88c40d612bSPeng Fan } 89c40d612bSPeng Fan } 90c40d612bSPeng Fan 91c40d612bSPeng Fan 92c40d612bSPeng Fan #ifndef CONFIG_SYS_CLK_FREQ 93c40d612bSPeng Fan #define CONFIG_SYS_CLK_FREQ 0 94c40d612bSPeng Fan #endif 95c40d612bSPeng Fan 96c40d612bSPeng Fan u32 __weak get_lpuart_clk(void) 97c40d612bSPeng Fan { 98c40d612bSPeng Fan return CONFIG_SYS_CLK_FREQ; 99c40d612bSPeng Fan } 100c40d612bSPeng Fan 101c40d612bSPeng Fan static bool is_lpuart32(struct udevice *dev) 102c40d612bSPeng Fan { 103c40d612bSPeng Fan struct lpuart_serial_platdata *plat = dev->platdata; 104c40d612bSPeng Fan 105c40d612bSPeng Fan return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG; 106c40d612bSPeng Fan } 107c40d612bSPeng Fan 108c40d612bSPeng Fan static void _lpuart_serial_setbrg(struct lpuart_serial_platdata *plat, 109c40d612bSPeng Fan int baudrate) 110c40d612bSPeng Fan { 111c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 112c40d612bSPeng Fan u32 clk = get_lpuart_clk(); 113427eba70SAlison Wang u16 sbr; 114427eba70SAlison Wang 1156ca13b12SBin Meng sbr = (u16)(clk / (16 * baudrate)); 116427eba70SAlison Wang 11747f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 118427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 119427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 120427eba70SAlison Wang } 121427eba70SAlison Wang 122c40d612bSPeng Fan static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat) 123427eba70SAlison Wang { 124c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 125a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 126427eba70SAlison Wang WATCHDOG_RESET(); 127427eba70SAlison Wang 128a3db78d8SStefan Agner barrier(); 129427eba70SAlison Wang 130427eba70SAlison Wang return __raw_readb(&base->ud); 131427eba70SAlison Wang } 132427eba70SAlison Wang 133c40d612bSPeng Fan static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat, 134c40d612bSPeng Fan const char c) 135427eba70SAlison Wang { 136c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 137c40d612bSPeng Fan 138427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 139427eba70SAlison Wang WATCHDOG_RESET(); 140427eba70SAlison Wang 141427eba70SAlison Wang __raw_writeb(c, &base->ud); 142427eba70SAlison Wang } 143427eba70SAlison Wang 14447f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 145c40d612bSPeng Fan static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat) 146427eba70SAlison Wang { 147c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 148c40d612bSPeng Fan 149427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 150427eba70SAlison Wang return 0; 151427eba70SAlison Wang 152427eba70SAlison Wang return 1; 153427eba70SAlison Wang } 154427eba70SAlison Wang 155427eba70SAlison Wang /* 156427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 157427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 158427eba70SAlison Wang */ 159c40d612bSPeng Fan static int _lpuart_serial_init(struct lpuart_serial_platdata *plat) 160427eba70SAlison Wang { 161c40d612bSPeng Fan struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg; 162427eba70SAlison Wang u8 ctrl; 163427eba70SAlison Wang 164427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 165427eba70SAlison Wang ctrl &= ~UC2_RE; 166427eba70SAlison Wang ctrl &= ~UC2_TE; 167427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 168427eba70SAlison Wang 169427eba70SAlison Wang __raw_writeb(0, &base->umodem); 170427eba70SAlison Wang __raw_writeb(0, &base->uc1); 171427eba70SAlison Wang 17289e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 17389e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 17489e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 17589e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 17689e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 17789e69fd4SStefan Agner 178427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 179c40d612bSPeng Fan _lpuart_serial_setbrg(plat, gd->baudrate); 180427eba70SAlison Wang 181427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 182427eba70SAlison Wang 183427eba70SAlison Wang return 0; 184427eba70SAlison Wang } 185427eba70SAlison Wang 1867edf5c45SPeng Fan static void _lpuart32_serial_setbrg_7ulp(struct lpuart_serial_platdata *plat, 1877edf5c45SPeng Fan int baudrate) 1887edf5c45SPeng Fan { 1897edf5c45SPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 1907edf5c45SPeng Fan u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp; 1917edf5c45SPeng Fan u32 clk = get_lpuart_clk(); 1927edf5c45SPeng Fan 1937edf5c45SPeng Fan baud_diff = baudrate; 1947edf5c45SPeng Fan osr = 0; 1957edf5c45SPeng Fan sbr = 0; 1967edf5c45SPeng Fan 1977edf5c45SPeng Fan for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) { 1987edf5c45SPeng Fan tmp_sbr = (clk / (baudrate * tmp_osr)); 1997edf5c45SPeng Fan 2007edf5c45SPeng Fan if (tmp_sbr == 0) 2017edf5c45SPeng Fan tmp_sbr = 1; 2027edf5c45SPeng Fan 2037edf5c45SPeng Fan /*calculate difference in actual buad w/ current values */ 2047edf5c45SPeng Fan tmp_diff = (clk / (tmp_osr * tmp_sbr)); 2057edf5c45SPeng Fan tmp_diff = tmp_diff - baudrate; 2067edf5c45SPeng Fan 2077edf5c45SPeng Fan /* select best values between sbr and sbr+1 */ 2087edf5c45SPeng Fan if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) { 2097edf5c45SPeng Fan tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1))); 2107edf5c45SPeng Fan tmp_sbr++; 2117edf5c45SPeng Fan } 2127edf5c45SPeng Fan 2137edf5c45SPeng Fan if (tmp_diff <= baud_diff) { 2147edf5c45SPeng Fan baud_diff = tmp_diff; 2157edf5c45SPeng Fan osr = tmp_osr; 2167edf5c45SPeng Fan sbr = tmp_sbr; 2177edf5c45SPeng Fan } 2187edf5c45SPeng Fan } 2197edf5c45SPeng Fan 2207edf5c45SPeng Fan /* 2217edf5c45SPeng Fan * TODO: handle buadrate outside acceptable rate 2227edf5c45SPeng Fan * if (baudDiff > ((config->baudRate_Bps / 100) * 3)) 2237edf5c45SPeng Fan * { 2247edf5c45SPeng Fan * Unacceptable baud rate difference of more than 3% 2257edf5c45SPeng Fan * return kStatus_LPUART_BaudrateNotSupport; 2267edf5c45SPeng Fan * } 2277edf5c45SPeng Fan */ 2287edf5c45SPeng Fan tmp = in_le32(&base->baud); 2297edf5c45SPeng Fan 2307edf5c45SPeng Fan if ((osr > 3) && (osr < 8)) 2317edf5c45SPeng Fan tmp |= LPUART_BAUD_BOTHEDGE_MASK; 2327edf5c45SPeng Fan 2337edf5c45SPeng Fan tmp &= ~LPUART_BAUD_OSR_MASK; 2347edf5c45SPeng Fan tmp |= LPUART_BAUD_OSR(osr-1); 2357edf5c45SPeng Fan 2367edf5c45SPeng Fan tmp &= ~LPUART_BAUD_SBR_MASK; 2377edf5c45SPeng Fan tmp |= LPUART_BAUD_SBR(sbr); 2387edf5c45SPeng Fan 2397edf5c45SPeng Fan /* explicitly disable 10 bit mode & set 1 stop bit */ 2407edf5c45SPeng Fan tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK); 2417edf5c45SPeng Fan 2427edf5c45SPeng Fan out_le32(&base->baud, tmp); 2437edf5c45SPeng Fan } 2447edf5c45SPeng Fan 245c40d612bSPeng Fan static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat, 246c40d612bSPeng Fan int baudrate) 247fdbae099SBin Meng { 248c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2499b46213bSShaohui Xie u32 clk = get_lpuart_clk(); 2506209e14cSJingchang Lu u32 sbr; 2516209e14cSJingchang Lu 2526ca13b12SBin Meng sbr = (clk / (16 * baudrate)); 2536209e14cSJingchang Lu 25447f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 255c40d612bSPeng Fan lpuart_write32(plat->flags, &base->baud, sbr); 2566209e14cSJingchang Lu } 2576209e14cSJingchang Lu 258c40d612bSPeng Fan static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat) 2596209e14cSJingchang Lu { 260c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2617edf5c45SPeng Fan u32 stat, val; 2626209e14cSJingchang Lu 263c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 264c40d612bSPeng Fan while ((stat & STAT_RDRF) == 0) { 265c40d612bSPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_FLAGS); 2666209e14cSJingchang Lu WATCHDOG_RESET(); 267c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 2686209e14cSJingchang Lu } 2696209e14cSJingchang Lu 2707edf5c45SPeng Fan lpuart_read32(plat->flags, &base->data, &val); 271c40d612bSPeng Fan 2727edf5c45SPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 2737edf5c45SPeng Fan if (stat & STAT_OR) 2747edf5c45SPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_OR); 2757edf5c45SPeng Fan 2767edf5c45SPeng Fan return val & 0x3ff; 2776209e14cSJingchang Lu } 2786209e14cSJingchang Lu 279c40d612bSPeng Fan static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat, 280c40d612bSPeng Fan const char c) 2816209e14cSJingchang Lu { 282c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 283c40d612bSPeng Fan u32 stat; 2846209e14cSJingchang Lu 2857edf5c45SPeng Fan if (c == '\n') 2867edf5c45SPeng Fan serial_putc('\r'); 2877edf5c45SPeng Fan 288c40d612bSPeng Fan while (true) { 289c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 290c40d612bSPeng Fan 291c40d612bSPeng Fan if ((stat & STAT_TDRE)) 292c40d612bSPeng Fan break; 293c40d612bSPeng Fan 294c40d612bSPeng Fan WATCHDOG_RESET(); 295c40d612bSPeng Fan } 296c40d612bSPeng Fan 297c40d612bSPeng Fan lpuart_write32(plat->flags, &base->data, c); 2986209e14cSJingchang Lu } 2996209e14cSJingchang Lu 30047f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 301c40d612bSPeng Fan static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat) 3026209e14cSJingchang Lu { 303c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 304c40d612bSPeng Fan u32 water; 305c40d612bSPeng Fan 306c40d612bSPeng Fan lpuart_read32(plat->flags, &base->water, &water); 307c40d612bSPeng Fan 308c40d612bSPeng Fan if ((water >> 24) == 0) 3096209e14cSJingchang Lu return 0; 3106209e14cSJingchang Lu 3116209e14cSJingchang Lu return 1; 3126209e14cSJingchang Lu } 3136209e14cSJingchang Lu 3146209e14cSJingchang Lu /* 3156209e14cSJingchang Lu * Initialise the serial port with the given baudrate. The settings 3166209e14cSJingchang Lu * are always 8 data bits, no parity, 1 stop bit, no start bits. 3176209e14cSJingchang Lu */ 318c40d612bSPeng Fan static int _lpuart32_serial_init(struct lpuart_serial_platdata *plat) 3196209e14cSJingchang Lu { 320c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg; 321c40d612bSPeng Fan u32 ctrl; 3226209e14cSJingchang Lu 323c40d612bSPeng Fan lpuart_read32(plat->flags, &base->ctrl, &ctrl); 3246209e14cSJingchang Lu ctrl &= ~CTRL_RE; 3256209e14cSJingchang Lu ctrl &= ~CTRL_TE; 326c40d612bSPeng Fan lpuart_write32(plat->flags, &base->ctrl, ctrl); 3276209e14cSJingchang Lu 328c40d612bSPeng Fan lpuart_write32(plat->flags, &base->modir, 0); 329c40d612bSPeng Fan lpuart_write32(plat->flags, &base->fifo, ~(FIFO_TXFE | FIFO_RXFE)); 3306209e14cSJingchang Lu 331c40d612bSPeng Fan lpuart_write32(plat->flags, &base->match, 0); 3326209e14cSJingchang Lu 333*126f8849SPeng Fan if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) { 3347edf5c45SPeng Fan _lpuart32_serial_setbrg_7ulp(plat, gd->baudrate); 3357edf5c45SPeng Fan } else { 33647f1bfcaSBin Meng /* provide data bits, parity, stop bit, etc */ 337c40d612bSPeng Fan _lpuart32_serial_setbrg(plat, gd->baudrate); 3387edf5c45SPeng Fan } 3396209e14cSJingchang Lu 340c40d612bSPeng Fan lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE); 3416209e14cSJingchang Lu 3426209e14cSJingchang Lu return 0; 3436209e14cSJingchang Lu } 3446209e14cSJingchang Lu 345c40d612bSPeng Fan static int lpuart_serial_setbrg(struct udevice *dev, int baudrate) 346fdbae099SBin Meng { 347fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 348fdbae099SBin Meng 3497edf5c45SPeng Fan if (is_lpuart32(dev)) { 350*126f8849SPeng Fan if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) 3517edf5c45SPeng Fan _lpuart32_serial_setbrg_7ulp(plat, baudrate); 352c40d612bSPeng Fan else 3537edf5c45SPeng Fan _lpuart32_serial_setbrg(plat, baudrate); 3547edf5c45SPeng Fan } else { 355c40d612bSPeng Fan _lpuart_serial_setbrg(plat, baudrate); 3567edf5c45SPeng Fan } 357fdbae099SBin Meng 358fdbae099SBin Meng return 0; 359fdbae099SBin Meng } 360fdbae099SBin Meng 361c40d612bSPeng Fan static int lpuart_serial_getc(struct udevice *dev) 362fdbae099SBin Meng { 363fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 364fdbae099SBin Meng 365c40d612bSPeng Fan if (is_lpuart32(dev)) 366c40d612bSPeng Fan return _lpuart32_serial_getc(plat); 367c40d612bSPeng Fan 368c40d612bSPeng Fan return _lpuart_serial_getc(plat); 369fdbae099SBin Meng } 370fdbae099SBin Meng 371c40d612bSPeng Fan static int lpuart_serial_putc(struct udevice *dev, const char c) 372fdbae099SBin Meng { 373fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 374fdbae099SBin Meng 375c40d612bSPeng Fan if (is_lpuart32(dev)) 376c40d612bSPeng Fan _lpuart32_serial_putc(plat, c); 377c40d612bSPeng Fan else 378c40d612bSPeng Fan _lpuart_serial_putc(plat, c); 379fdbae099SBin Meng 380fdbae099SBin Meng return 0; 381fdbae099SBin Meng } 382fdbae099SBin Meng 383c40d612bSPeng Fan static int lpuart_serial_pending(struct udevice *dev, bool input) 384fdbae099SBin Meng { 385fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 386fdbae099SBin Meng struct lpuart_fsl *reg = plat->reg; 387c40d612bSPeng Fan struct lpuart_fsl_reg32 *reg32 = plat->reg; 388c40d612bSPeng Fan u32 stat; 389c40d612bSPeng Fan 390c40d612bSPeng Fan if (is_lpuart32(dev)) { 391c40d612bSPeng Fan if (input) { 392c40d612bSPeng Fan return _lpuart32_serial_tstc(plat); 393c40d612bSPeng Fan } else { 394c40d612bSPeng Fan lpuart_read32(plat->flags, ®32->stat, &stat); 395c40d612bSPeng Fan return stat & STAT_TDRE ? 0 : 1; 396c40d612bSPeng Fan } 397c40d612bSPeng Fan } 398fdbae099SBin Meng 399fdbae099SBin Meng if (input) 400c40d612bSPeng Fan return _lpuart_serial_tstc(plat); 401fdbae099SBin Meng else 402c40d612bSPeng Fan return __raw_readb(®->us1) & US1_TDRE ? 0 : 1; 403fdbae099SBin Meng } 404fdbae099SBin Meng 405c40d612bSPeng Fan static int lpuart_serial_probe(struct udevice *dev) 406fdbae099SBin Meng { 407fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 408fdbae099SBin Meng 409c40d612bSPeng Fan if (is_lpuart32(dev)) 410c40d612bSPeng Fan return _lpuart32_serial_init(plat); 411c40d612bSPeng Fan else 412c40d612bSPeng Fan return _lpuart_serial_init(plat); 413fdbae099SBin Meng } 414427eba70SAlison Wang 415fdbae099SBin Meng static int lpuart_serial_ofdata_to_platdata(struct udevice *dev) 416fdbae099SBin Meng { 417fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 4187edf5c45SPeng Fan const void *blob = gd->fdt_blob; 419da409cccSSimon Glass int node = dev_of_offset(dev); 420fdbae099SBin Meng fdt_addr_t addr; 421fdbae099SBin Meng 422a821c4afSSimon Glass addr = devfdt_get_addr(dev); 423fdbae099SBin Meng if (addr == FDT_ADDR_T_NONE) 424fdbae099SBin Meng return -EINVAL; 425fdbae099SBin Meng 426c40d612bSPeng Fan plat->reg = (void *)addr; 427c40d612bSPeng Fan plat->flags = dev_get_driver_data(dev); 428fdbae099SBin Meng 4297edf5c45SPeng Fan if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart")) 4307edf5c45SPeng Fan plat->devtype = DEV_LS1021A; 4317edf5c45SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart")) 4327edf5c45SPeng Fan plat->devtype = DEV_MX7ULP; 4337edf5c45SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart")) 4347edf5c45SPeng Fan plat->devtype = DEV_VF610; 435*126f8849SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart")) 436*126f8849SPeng Fan plat->devtype = DEV_IMX8; 4377edf5c45SPeng Fan 438fdbae099SBin Meng return 0; 439fdbae099SBin Meng } 440fdbae099SBin Meng 441fdbae099SBin Meng static const struct dm_serial_ops lpuart_serial_ops = { 442fdbae099SBin Meng .putc = lpuart_serial_putc, 443fdbae099SBin Meng .pending = lpuart_serial_pending, 444fdbae099SBin Meng .getc = lpuart_serial_getc, 445fdbae099SBin Meng .setbrg = lpuart_serial_setbrg, 446fdbae099SBin Meng }; 447fdbae099SBin Meng 448fdbae099SBin Meng static const struct udevice_id lpuart_serial_ids[] = { 449c40d612bSPeng Fan { .compatible = "fsl,ls1021a-lpuart", .data = 450c40d612bSPeng Fan LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG }, 4517edf5c45SPeng Fan { .compatible = "fsl,imx7ulp-lpuart", 4527edf5c45SPeng Fan .data = LPUART_FLAG_REGMAP_32BIT_REG }, 453fdbae099SBin Meng { .compatible = "fsl,vf610-lpuart"}, 454*126f8849SPeng Fan { .compatible = "fsl,imx8qm-lpuart", 455*126f8849SPeng Fan .data = LPUART_FLAG_REGMAP_32BIT_REG }, 456fdbae099SBin Meng { } 457fdbae099SBin Meng }; 458fdbae099SBin Meng 459fdbae099SBin Meng U_BOOT_DRIVER(serial_lpuart) = { 460fdbae099SBin Meng .name = "serial_lpuart", 461fdbae099SBin Meng .id = UCLASS_SERIAL, 462fdbae099SBin Meng .of_match = lpuart_serial_ids, 463fdbae099SBin Meng .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata, 464fdbae099SBin Meng .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata), 465fdbae099SBin Meng .probe = lpuart_serial_probe, 466fdbae099SBin Meng .ops = &lpuart_serial_ops, 467fdbae099SBin Meng .flags = DM_FLAG_PRE_RELOC, 468fdbae099SBin Meng }; 469