1427eba70SAlison Wang /* 2427eba70SAlison Wang * Copyright 2013 Freescale Semiconductor, Inc. 3427eba70SAlison Wang * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 5427eba70SAlison Wang */ 6427eba70SAlison Wang 7427eba70SAlison Wang #include <common.h> 8fdbae099SBin Meng #include <dm.h> 9c40d612bSPeng Fan #include <fsl_lpuart.h> 10427eba70SAlison Wang #include <watchdog.h> 11427eba70SAlison Wang #include <asm/io.h> 12427eba70SAlison Wang #include <serial.h> 13427eba70SAlison Wang #include <linux/compiler.h> 14427eba70SAlison Wang #include <asm/arch/imx-regs.h> 15427eba70SAlison Wang #include <asm/arch/clock.h> 16427eba70SAlison Wang 17427eba70SAlison Wang #define US1_TDRE (1 << 7) 18427eba70SAlison Wang #define US1_RDRF (1 << 5) 19a3db78d8SStefan Agner #define US1_OR (1 << 3) 20427eba70SAlison Wang #define UC2_TE (1 << 3) 21427eba70SAlison Wang #define UC2_RE (1 << 2) 2289e69fd4SStefan Agner #define CFIFO_TXFLUSH (1 << 7) 2389e69fd4SStefan Agner #define CFIFO_RXFLUSH (1 << 6) 2489e69fd4SStefan Agner #define SFIFO_RXOF (1 << 2) 2589e69fd4SStefan Agner #define SFIFO_RXUF (1 << 0) 26427eba70SAlison Wang 276209e14cSJingchang Lu #define STAT_LBKDIF (1 << 31) 286209e14cSJingchang Lu #define STAT_RXEDGIF (1 << 30) 296209e14cSJingchang Lu #define STAT_TDRE (1 << 23) 306209e14cSJingchang Lu #define STAT_RDRF (1 << 21) 316209e14cSJingchang Lu #define STAT_IDLE (1 << 20) 326209e14cSJingchang Lu #define STAT_OR (1 << 19) 336209e14cSJingchang Lu #define STAT_NF (1 << 18) 346209e14cSJingchang Lu #define STAT_FE (1 << 17) 356209e14cSJingchang Lu #define STAT_PF (1 << 16) 366209e14cSJingchang Lu #define STAT_MA1F (1 << 15) 376209e14cSJingchang Lu #define STAT_MA2F (1 << 14) 386209e14cSJingchang Lu #define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \ 396209e14cSJingchang Lu STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F) 406209e14cSJingchang Lu 416209e14cSJingchang Lu #define CTRL_TE (1 << 19) 426209e14cSJingchang Lu #define CTRL_RE (1 << 18) 436209e14cSJingchang Lu 446209e14cSJingchang Lu #define FIFO_TXFE 0x80 456209e14cSJingchang Lu #define FIFO_RXFE 0x40 466209e14cSJingchang Lu 476209e14cSJingchang Lu #define WATER_TXWATER_OFF 1 486209e14cSJingchang Lu #define WATER_RXWATER_OFF 16 496209e14cSJingchang Lu 50427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 51427eba70SAlison Wang 52c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_32BIT_REG BIT(0) 53c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1) 54c40d612bSPeng Fan 557edf5c45SPeng Fan enum lpuart_devtype { 567edf5c45SPeng Fan DEV_VF610 = 1, 577edf5c45SPeng Fan DEV_LS1021A, 587edf5c45SPeng Fan DEV_MX7ULP 597edf5c45SPeng Fan }; 607edf5c45SPeng Fan 61fdbae099SBin Meng struct lpuart_serial_platdata { 62c40d612bSPeng Fan void *reg; 637edf5c45SPeng Fan enum lpuart_devtype devtype; 64c40d612bSPeng Fan ulong flags; 65fdbae099SBin Meng }; 66fdbae099SBin Meng 67c40d612bSPeng Fan static void lpuart_read32(u32 flags, u32 *addr, u32 *val) 68427eba70SAlison Wang { 69c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 70c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 71c40d612bSPeng Fan *(u32 *)val = in_be32(addr); 72c40d612bSPeng Fan else 73c40d612bSPeng Fan *(u32 *)val = in_le32(addr); 74c40d612bSPeng Fan } 75c40d612bSPeng Fan } 76c40d612bSPeng Fan 77c40d612bSPeng Fan static void lpuart_write32(u32 flags, u32 *addr, u32 val) 78c40d612bSPeng Fan { 79c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 80c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 81c40d612bSPeng Fan out_be32(addr, val); 82c40d612bSPeng Fan else 83c40d612bSPeng Fan out_le32(addr, val); 84c40d612bSPeng Fan } 85c40d612bSPeng Fan } 86c40d612bSPeng Fan 87c40d612bSPeng Fan 88c40d612bSPeng Fan #ifndef CONFIG_SYS_CLK_FREQ 89c40d612bSPeng Fan #define CONFIG_SYS_CLK_FREQ 0 90c40d612bSPeng Fan #endif 91c40d612bSPeng Fan 92c40d612bSPeng Fan u32 __weak get_lpuart_clk(void) 93c40d612bSPeng Fan { 94c40d612bSPeng Fan return CONFIG_SYS_CLK_FREQ; 95c40d612bSPeng Fan } 96c40d612bSPeng Fan 97c40d612bSPeng Fan static bool is_lpuart32(struct udevice *dev) 98c40d612bSPeng Fan { 99c40d612bSPeng Fan struct lpuart_serial_platdata *plat = dev->platdata; 100c40d612bSPeng Fan 101c40d612bSPeng Fan return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG; 102c40d612bSPeng Fan } 103c40d612bSPeng Fan 104c40d612bSPeng Fan static void _lpuart_serial_setbrg(struct lpuart_serial_platdata *plat, 105c40d612bSPeng Fan int baudrate) 106c40d612bSPeng Fan { 107c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 108c40d612bSPeng Fan u32 clk = get_lpuart_clk(); 109427eba70SAlison Wang u16 sbr; 110427eba70SAlison Wang 1116ca13b12SBin Meng sbr = (u16)(clk / (16 * baudrate)); 112427eba70SAlison Wang 11347f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 114427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 115427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 116427eba70SAlison Wang } 117427eba70SAlison Wang 118c40d612bSPeng Fan static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat) 119427eba70SAlison Wang { 120c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 121a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 122427eba70SAlison Wang WATCHDOG_RESET(); 123427eba70SAlison Wang 124a3db78d8SStefan Agner barrier(); 125427eba70SAlison Wang 126427eba70SAlison Wang return __raw_readb(&base->ud); 127427eba70SAlison Wang } 128427eba70SAlison Wang 129c40d612bSPeng Fan static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat, 130c40d612bSPeng Fan const char c) 131427eba70SAlison Wang { 132c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 133c40d612bSPeng Fan 134427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 135427eba70SAlison Wang WATCHDOG_RESET(); 136427eba70SAlison Wang 137427eba70SAlison Wang __raw_writeb(c, &base->ud); 138427eba70SAlison Wang } 139427eba70SAlison Wang 14047f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 141c40d612bSPeng Fan static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat) 142427eba70SAlison Wang { 143c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 144c40d612bSPeng Fan 145427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 146427eba70SAlison Wang return 0; 147427eba70SAlison Wang 148427eba70SAlison Wang return 1; 149427eba70SAlison Wang } 150427eba70SAlison Wang 151427eba70SAlison Wang /* 152427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 153427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 154427eba70SAlison Wang */ 155c40d612bSPeng Fan static int _lpuart_serial_init(struct lpuart_serial_platdata *plat) 156427eba70SAlison Wang { 157c40d612bSPeng Fan struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg; 158427eba70SAlison Wang u8 ctrl; 159427eba70SAlison Wang 160427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 161427eba70SAlison Wang ctrl &= ~UC2_RE; 162427eba70SAlison Wang ctrl &= ~UC2_TE; 163427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 164427eba70SAlison Wang 165427eba70SAlison Wang __raw_writeb(0, &base->umodem); 166427eba70SAlison Wang __raw_writeb(0, &base->uc1); 167427eba70SAlison Wang 16889e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 16989e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 17089e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 17189e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 17289e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 17389e69fd4SStefan Agner 174427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 175c40d612bSPeng Fan _lpuart_serial_setbrg(plat, gd->baudrate); 176427eba70SAlison Wang 177427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 178427eba70SAlison Wang 179427eba70SAlison Wang return 0; 180427eba70SAlison Wang } 181427eba70SAlison Wang 1827edf5c45SPeng Fan static void _lpuart32_serial_setbrg_7ulp(struct lpuart_serial_platdata *plat, 1837edf5c45SPeng Fan int baudrate) 1847edf5c45SPeng Fan { 1857edf5c45SPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 1867edf5c45SPeng Fan u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp; 1877edf5c45SPeng Fan u32 clk = get_lpuart_clk(); 1887edf5c45SPeng Fan 1897edf5c45SPeng Fan baud_diff = baudrate; 1907edf5c45SPeng Fan osr = 0; 1917edf5c45SPeng Fan sbr = 0; 1927edf5c45SPeng Fan 1937edf5c45SPeng Fan for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) { 1947edf5c45SPeng Fan tmp_sbr = (clk / (baudrate * tmp_osr)); 1957edf5c45SPeng Fan 1967edf5c45SPeng Fan if (tmp_sbr == 0) 1977edf5c45SPeng Fan tmp_sbr = 1; 1987edf5c45SPeng Fan 1997edf5c45SPeng Fan /*calculate difference in actual buad w/ current values */ 2007edf5c45SPeng Fan tmp_diff = (clk / (tmp_osr * tmp_sbr)); 2017edf5c45SPeng Fan tmp_diff = tmp_diff - baudrate; 2027edf5c45SPeng Fan 2037edf5c45SPeng Fan /* select best values between sbr and sbr+1 */ 2047edf5c45SPeng Fan if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) { 2057edf5c45SPeng Fan tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1))); 2067edf5c45SPeng Fan tmp_sbr++; 2077edf5c45SPeng Fan } 2087edf5c45SPeng Fan 2097edf5c45SPeng Fan if (tmp_diff <= baud_diff) { 2107edf5c45SPeng Fan baud_diff = tmp_diff; 2117edf5c45SPeng Fan osr = tmp_osr; 2127edf5c45SPeng Fan sbr = tmp_sbr; 2137edf5c45SPeng Fan } 2147edf5c45SPeng Fan } 2157edf5c45SPeng Fan 2167edf5c45SPeng Fan /* 2177edf5c45SPeng Fan * TODO: handle buadrate outside acceptable rate 2187edf5c45SPeng Fan * if (baudDiff > ((config->baudRate_Bps / 100) * 3)) 2197edf5c45SPeng Fan * { 2207edf5c45SPeng Fan * Unacceptable baud rate difference of more than 3% 2217edf5c45SPeng Fan * return kStatus_LPUART_BaudrateNotSupport; 2227edf5c45SPeng Fan * } 2237edf5c45SPeng Fan */ 2247edf5c45SPeng Fan tmp = in_le32(&base->baud); 2257edf5c45SPeng Fan 2267edf5c45SPeng Fan if ((osr > 3) && (osr < 8)) 2277edf5c45SPeng Fan tmp |= LPUART_BAUD_BOTHEDGE_MASK; 2287edf5c45SPeng Fan 2297edf5c45SPeng Fan tmp &= ~LPUART_BAUD_OSR_MASK; 2307edf5c45SPeng Fan tmp |= LPUART_BAUD_OSR(osr-1); 2317edf5c45SPeng Fan 2327edf5c45SPeng Fan tmp &= ~LPUART_BAUD_SBR_MASK; 2337edf5c45SPeng Fan tmp |= LPUART_BAUD_SBR(sbr); 2347edf5c45SPeng Fan 2357edf5c45SPeng Fan /* explicitly disable 10 bit mode & set 1 stop bit */ 2367edf5c45SPeng Fan tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK); 2377edf5c45SPeng Fan 2387edf5c45SPeng Fan out_le32(&base->baud, tmp); 2397edf5c45SPeng Fan } 2407edf5c45SPeng Fan 241c40d612bSPeng Fan static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat, 242c40d612bSPeng Fan int baudrate) 243fdbae099SBin Meng { 244c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2459b46213bSShaohui Xie u32 clk = get_lpuart_clk(); 2466209e14cSJingchang Lu u32 sbr; 2476209e14cSJingchang Lu 2486ca13b12SBin Meng sbr = (clk / (16 * baudrate)); 2496209e14cSJingchang Lu 25047f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 251c40d612bSPeng Fan lpuart_write32(plat->flags, &base->baud, sbr); 2526209e14cSJingchang Lu } 2536209e14cSJingchang Lu 254c40d612bSPeng Fan static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat) 2556209e14cSJingchang Lu { 256c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2577edf5c45SPeng Fan u32 stat, val; 2586209e14cSJingchang Lu 259c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 260c40d612bSPeng Fan while ((stat & STAT_RDRF) == 0) { 261c40d612bSPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_FLAGS); 2626209e14cSJingchang Lu WATCHDOG_RESET(); 263c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 2646209e14cSJingchang Lu } 2656209e14cSJingchang Lu 2667edf5c45SPeng Fan lpuart_read32(plat->flags, &base->data, &val); 267c40d612bSPeng Fan 2687edf5c45SPeng Fan if (plat->devtype & DEV_MX7ULP) { 2697edf5c45SPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 2707edf5c45SPeng Fan if (stat & STAT_OR) 2717edf5c45SPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_OR); 2727edf5c45SPeng Fan } 2737edf5c45SPeng Fan 2747edf5c45SPeng Fan return val & 0x3ff; 2756209e14cSJingchang Lu } 2766209e14cSJingchang Lu 277c40d612bSPeng Fan static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat, 278c40d612bSPeng Fan const char c) 2796209e14cSJingchang Lu { 280c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 281c40d612bSPeng Fan u32 stat; 2826209e14cSJingchang Lu 2837edf5c45SPeng Fan if (plat->devtype & DEV_MX7ULP) { 2847edf5c45SPeng Fan if (c == '\n') 2857edf5c45SPeng Fan serial_putc('\r'); 2867edf5c45SPeng Fan } 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 3337edf5c45SPeng Fan if (plat->devtype & DEV_MX7ULP) { 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)) { 3507edf5c45SPeng Fan if (plat->devtype & DEV_MX7ULP) 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; 4197edf5c45SPeng Fan int node = dev->of_offset; 420fdbae099SBin Meng fdt_addr_t addr; 421fdbae099SBin Meng 422*a821c4afSSimon 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; 4357edf5c45SPeng Fan 436fdbae099SBin Meng return 0; 437fdbae099SBin Meng } 438fdbae099SBin Meng 439fdbae099SBin Meng static const struct dm_serial_ops lpuart_serial_ops = { 440fdbae099SBin Meng .putc = lpuart_serial_putc, 441fdbae099SBin Meng .pending = lpuart_serial_pending, 442fdbae099SBin Meng .getc = lpuart_serial_getc, 443fdbae099SBin Meng .setbrg = lpuart_serial_setbrg, 444fdbae099SBin Meng }; 445fdbae099SBin Meng 446fdbae099SBin Meng static const struct udevice_id lpuart_serial_ids[] = { 447c40d612bSPeng Fan { .compatible = "fsl,ls1021a-lpuart", .data = 448c40d612bSPeng Fan LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG }, 4497edf5c45SPeng Fan { .compatible = "fsl,imx7ulp-lpuart", 4507edf5c45SPeng Fan .data = LPUART_FLAG_REGMAP_32BIT_REG }, 451fdbae099SBin Meng { .compatible = "fsl,vf610-lpuart"}, 452fdbae099SBin Meng { } 453fdbae099SBin Meng }; 454fdbae099SBin Meng 455fdbae099SBin Meng U_BOOT_DRIVER(serial_lpuart) = { 456fdbae099SBin Meng .name = "serial_lpuart", 457fdbae099SBin Meng .id = UCLASS_SERIAL, 458fdbae099SBin Meng .of_match = lpuart_serial_ids, 459fdbae099SBin Meng .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata, 460fdbae099SBin Meng .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata), 461fdbae099SBin Meng .probe = lpuart_serial_probe, 462fdbae099SBin Meng .ops = &lpuart_serial_ops, 463fdbae099SBin Meng .flags = DM_FLAG_PRE_RELOC, 464fdbae099SBin Meng }; 465