1*83d290c5STom 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 446209e14cSJingchang Lu #define FIFO_RXFE 0x40 456209e14cSJingchang Lu 466209e14cSJingchang Lu #define WATER_TXWATER_OFF 1 476209e14cSJingchang Lu #define WATER_RXWATER_OFF 16 486209e14cSJingchang Lu 49427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 50427eba70SAlison Wang 51c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_32BIT_REG BIT(0) 52c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1) 53c40d612bSPeng Fan 547edf5c45SPeng Fan enum lpuart_devtype { 557edf5c45SPeng Fan DEV_VF610 = 1, 567edf5c45SPeng Fan DEV_LS1021A, 577edf5c45SPeng Fan DEV_MX7ULP 587edf5c45SPeng Fan }; 597edf5c45SPeng Fan 60fdbae099SBin Meng struct lpuart_serial_platdata { 61c40d612bSPeng Fan void *reg; 627edf5c45SPeng Fan enum lpuart_devtype devtype; 63c40d612bSPeng Fan ulong flags; 64fdbae099SBin Meng }; 65fdbae099SBin Meng 66c40d612bSPeng Fan static void lpuart_read32(u32 flags, u32 *addr, u32 *val) 67427eba70SAlison Wang { 68c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 69c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 70c40d612bSPeng Fan *(u32 *)val = in_be32(addr); 71c40d612bSPeng Fan else 72c40d612bSPeng Fan *(u32 *)val = in_le32(addr); 73c40d612bSPeng Fan } 74c40d612bSPeng Fan } 75c40d612bSPeng Fan 76c40d612bSPeng Fan static void lpuart_write32(u32 flags, u32 *addr, u32 val) 77c40d612bSPeng Fan { 78c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 79c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 80c40d612bSPeng Fan out_be32(addr, val); 81c40d612bSPeng Fan else 82c40d612bSPeng Fan out_le32(addr, val); 83c40d612bSPeng Fan } 84c40d612bSPeng Fan } 85c40d612bSPeng Fan 86c40d612bSPeng Fan 87c40d612bSPeng Fan #ifndef CONFIG_SYS_CLK_FREQ 88c40d612bSPeng Fan #define CONFIG_SYS_CLK_FREQ 0 89c40d612bSPeng Fan #endif 90c40d612bSPeng Fan 91c40d612bSPeng Fan u32 __weak get_lpuart_clk(void) 92c40d612bSPeng Fan { 93c40d612bSPeng Fan return CONFIG_SYS_CLK_FREQ; 94c40d612bSPeng Fan } 95c40d612bSPeng Fan 96c40d612bSPeng Fan static bool is_lpuart32(struct udevice *dev) 97c40d612bSPeng Fan { 98c40d612bSPeng Fan struct lpuart_serial_platdata *plat = dev->platdata; 99c40d612bSPeng Fan 100c40d612bSPeng Fan return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG; 101c40d612bSPeng Fan } 102c40d612bSPeng Fan 103c40d612bSPeng Fan static void _lpuart_serial_setbrg(struct lpuart_serial_platdata *plat, 104c40d612bSPeng Fan int baudrate) 105c40d612bSPeng Fan { 106c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 107c40d612bSPeng Fan u32 clk = get_lpuart_clk(); 108427eba70SAlison Wang u16 sbr; 109427eba70SAlison Wang 1106ca13b12SBin Meng sbr = (u16)(clk / (16 * baudrate)); 111427eba70SAlison Wang 11247f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 113427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 114427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 115427eba70SAlison Wang } 116427eba70SAlison Wang 117c40d612bSPeng Fan static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat) 118427eba70SAlison Wang { 119c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 120a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 121427eba70SAlison Wang WATCHDOG_RESET(); 122427eba70SAlison Wang 123a3db78d8SStefan Agner barrier(); 124427eba70SAlison Wang 125427eba70SAlison Wang return __raw_readb(&base->ud); 126427eba70SAlison Wang } 127427eba70SAlison Wang 128c40d612bSPeng Fan static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat, 129c40d612bSPeng Fan const char c) 130427eba70SAlison Wang { 131c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 132c40d612bSPeng Fan 133427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 134427eba70SAlison Wang WATCHDOG_RESET(); 135427eba70SAlison Wang 136427eba70SAlison Wang __raw_writeb(c, &base->ud); 137427eba70SAlison Wang } 138427eba70SAlison Wang 13947f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 140c40d612bSPeng Fan static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat) 141427eba70SAlison Wang { 142c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 143c40d612bSPeng Fan 144427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 145427eba70SAlison Wang return 0; 146427eba70SAlison Wang 147427eba70SAlison Wang return 1; 148427eba70SAlison Wang } 149427eba70SAlison Wang 150427eba70SAlison Wang /* 151427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 152427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 153427eba70SAlison Wang */ 154c40d612bSPeng Fan static int _lpuart_serial_init(struct lpuart_serial_platdata *plat) 155427eba70SAlison Wang { 156c40d612bSPeng Fan struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg; 157427eba70SAlison Wang u8 ctrl; 158427eba70SAlison Wang 159427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 160427eba70SAlison Wang ctrl &= ~UC2_RE; 161427eba70SAlison Wang ctrl &= ~UC2_TE; 162427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 163427eba70SAlison Wang 164427eba70SAlison Wang __raw_writeb(0, &base->umodem); 165427eba70SAlison Wang __raw_writeb(0, &base->uc1); 166427eba70SAlison Wang 16789e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 16889e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 16989e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 17089e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 17189e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 17289e69fd4SStefan Agner 173427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 174c40d612bSPeng Fan _lpuart_serial_setbrg(plat, gd->baudrate); 175427eba70SAlison Wang 176427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 177427eba70SAlison Wang 178427eba70SAlison Wang return 0; 179427eba70SAlison Wang } 180427eba70SAlison Wang 1817edf5c45SPeng Fan static void _lpuart32_serial_setbrg_7ulp(struct lpuart_serial_platdata *plat, 1827edf5c45SPeng Fan int baudrate) 1837edf5c45SPeng Fan { 1847edf5c45SPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 1857edf5c45SPeng Fan u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp; 1867edf5c45SPeng Fan u32 clk = get_lpuart_clk(); 1877edf5c45SPeng Fan 1887edf5c45SPeng Fan baud_diff = baudrate; 1897edf5c45SPeng Fan osr = 0; 1907edf5c45SPeng Fan sbr = 0; 1917edf5c45SPeng Fan 1927edf5c45SPeng Fan for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) { 1937edf5c45SPeng Fan tmp_sbr = (clk / (baudrate * tmp_osr)); 1947edf5c45SPeng Fan 1957edf5c45SPeng Fan if (tmp_sbr == 0) 1967edf5c45SPeng Fan tmp_sbr = 1; 1977edf5c45SPeng Fan 1987edf5c45SPeng Fan /*calculate difference in actual buad w/ current values */ 1997edf5c45SPeng Fan tmp_diff = (clk / (tmp_osr * tmp_sbr)); 2007edf5c45SPeng Fan tmp_diff = tmp_diff - baudrate; 2017edf5c45SPeng Fan 2027edf5c45SPeng Fan /* select best values between sbr and sbr+1 */ 2037edf5c45SPeng Fan if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) { 2047edf5c45SPeng Fan tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1))); 2057edf5c45SPeng Fan tmp_sbr++; 2067edf5c45SPeng Fan } 2077edf5c45SPeng Fan 2087edf5c45SPeng Fan if (tmp_diff <= baud_diff) { 2097edf5c45SPeng Fan baud_diff = tmp_diff; 2107edf5c45SPeng Fan osr = tmp_osr; 2117edf5c45SPeng Fan sbr = tmp_sbr; 2127edf5c45SPeng Fan } 2137edf5c45SPeng Fan } 2147edf5c45SPeng Fan 2157edf5c45SPeng Fan /* 2167edf5c45SPeng Fan * TODO: handle buadrate outside acceptable rate 2177edf5c45SPeng Fan * if (baudDiff > ((config->baudRate_Bps / 100) * 3)) 2187edf5c45SPeng Fan * { 2197edf5c45SPeng Fan * Unacceptable baud rate difference of more than 3% 2207edf5c45SPeng Fan * return kStatus_LPUART_BaudrateNotSupport; 2217edf5c45SPeng Fan * } 2227edf5c45SPeng Fan */ 2237edf5c45SPeng Fan tmp = in_le32(&base->baud); 2247edf5c45SPeng Fan 2257edf5c45SPeng Fan if ((osr > 3) && (osr < 8)) 2267edf5c45SPeng Fan tmp |= LPUART_BAUD_BOTHEDGE_MASK; 2277edf5c45SPeng Fan 2287edf5c45SPeng Fan tmp &= ~LPUART_BAUD_OSR_MASK; 2297edf5c45SPeng Fan tmp |= LPUART_BAUD_OSR(osr-1); 2307edf5c45SPeng Fan 2317edf5c45SPeng Fan tmp &= ~LPUART_BAUD_SBR_MASK; 2327edf5c45SPeng Fan tmp |= LPUART_BAUD_SBR(sbr); 2337edf5c45SPeng Fan 2347edf5c45SPeng Fan /* explicitly disable 10 bit mode & set 1 stop bit */ 2357edf5c45SPeng Fan tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK); 2367edf5c45SPeng Fan 2377edf5c45SPeng Fan out_le32(&base->baud, tmp); 2387edf5c45SPeng Fan } 2397edf5c45SPeng Fan 240c40d612bSPeng Fan static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat, 241c40d612bSPeng Fan int baudrate) 242fdbae099SBin Meng { 243c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2449b46213bSShaohui Xie u32 clk = get_lpuart_clk(); 2456209e14cSJingchang Lu u32 sbr; 2466209e14cSJingchang Lu 2476ca13b12SBin Meng sbr = (clk / (16 * baudrate)); 2486209e14cSJingchang Lu 24947f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 250c40d612bSPeng Fan lpuart_write32(plat->flags, &base->baud, sbr); 2516209e14cSJingchang Lu } 2526209e14cSJingchang Lu 253c40d612bSPeng Fan static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat) 2546209e14cSJingchang Lu { 255c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2567edf5c45SPeng Fan u32 stat, val; 2576209e14cSJingchang Lu 258c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 259c40d612bSPeng Fan while ((stat & STAT_RDRF) == 0) { 260c40d612bSPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_FLAGS); 2616209e14cSJingchang Lu WATCHDOG_RESET(); 262c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 2636209e14cSJingchang Lu } 2646209e14cSJingchang Lu 2657edf5c45SPeng Fan lpuart_read32(plat->flags, &base->data, &val); 266c40d612bSPeng Fan 2677edf5c45SPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 2687edf5c45SPeng Fan if (stat & STAT_OR) 2697edf5c45SPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_OR); 2707edf5c45SPeng Fan 2717edf5c45SPeng Fan return val & 0x3ff; 2726209e14cSJingchang Lu } 2736209e14cSJingchang Lu 274c40d612bSPeng Fan static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat, 275c40d612bSPeng Fan const char c) 2766209e14cSJingchang Lu { 277c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 278c40d612bSPeng Fan u32 stat; 2796209e14cSJingchang Lu 2807edf5c45SPeng Fan if (c == '\n') 2817edf5c45SPeng Fan serial_putc('\r'); 2827edf5c45SPeng Fan 283c40d612bSPeng Fan while (true) { 284c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 285c40d612bSPeng Fan 286c40d612bSPeng Fan if ((stat & STAT_TDRE)) 287c40d612bSPeng Fan break; 288c40d612bSPeng Fan 289c40d612bSPeng Fan WATCHDOG_RESET(); 290c40d612bSPeng Fan } 291c40d612bSPeng Fan 292c40d612bSPeng Fan lpuart_write32(plat->flags, &base->data, c); 2936209e14cSJingchang Lu } 2946209e14cSJingchang Lu 29547f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 296c40d612bSPeng Fan static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat) 2976209e14cSJingchang Lu { 298c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 299c40d612bSPeng Fan u32 water; 300c40d612bSPeng Fan 301c40d612bSPeng Fan lpuart_read32(plat->flags, &base->water, &water); 302c40d612bSPeng Fan 303c40d612bSPeng Fan if ((water >> 24) == 0) 3046209e14cSJingchang Lu return 0; 3056209e14cSJingchang Lu 3066209e14cSJingchang Lu return 1; 3076209e14cSJingchang Lu } 3086209e14cSJingchang Lu 3096209e14cSJingchang Lu /* 3106209e14cSJingchang Lu * Initialise the serial port with the given baudrate. The settings 3116209e14cSJingchang Lu * are always 8 data bits, no parity, 1 stop bit, no start bits. 3126209e14cSJingchang Lu */ 313c40d612bSPeng Fan static int _lpuart32_serial_init(struct lpuart_serial_platdata *plat) 3146209e14cSJingchang Lu { 315c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg; 316c40d612bSPeng Fan u32 ctrl; 3176209e14cSJingchang Lu 318c40d612bSPeng Fan lpuart_read32(plat->flags, &base->ctrl, &ctrl); 3196209e14cSJingchang Lu ctrl &= ~CTRL_RE; 3206209e14cSJingchang Lu ctrl &= ~CTRL_TE; 321c40d612bSPeng Fan lpuart_write32(plat->flags, &base->ctrl, ctrl); 3226209e14cSJingchang Lu 323c40d612bSPeng Fan lpuart_write32(plat->flags, &base->modir, 0); 324c40d612bSPeng Fan lpuart_write32(plat->flags, &base->fifo, ~(FIFO_TXFE | FIFO_RXFE)); 3256209e14cSJingchang Lu 326c40d612bSPeng Fan lpuart_write32(plat->flags, &base->match, 0); 3276209e14cSJingchang Lu 328a2bbfc54SSriram Dash if (plat->devtype == DEV_MX7ULP) { 3297edf5c45SPeng Fan _lpuart32_serial_setbrg_7ulp(plat, gd->baudrate); 3307edf5c45SPeng Fan } else { 33147f1bfcaSBin Meng /* provide data bits, parity, stop bit, etc */ 332c40d612bSPeng Fan _lpuart32_serial_setbrg(plat, gd->baudrate); 3337edf5c45SPeng Fan } 3346209e14cSJingchang Lu 335c40d612bSPeng Fan lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE); 3366209e14cSJingchang Lu 3376209e14cSJingchang Lu return 0; 3386209e14cSJingchang Lu } 3396209e14cSJingchang Lu 340c40d612bSPeng Fan static int lpuart_serial_setbrg(struct udevice *dev, int baudrate) 341fdbae099SBin Meng { 342fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 343fdbae099SBin Meng 3447edf5c45SPeng Fan if (is_lpuart32(dev)) { 345a2bbfc54SSriram Dash if (plat->devtype == DEV_MX7ULP) 3467edf5c45SPeng Fan _lpuart32_serial_setbrg_7ulp(plat, baudrate); 347c40d612bSPeng Fan else 3487edf5c45SPeng Fan _lpuart32_serial_setbrg(plat, baudrate); 3497edf5c45SPeng Fan } else { 350c40d612bSPeng Fan _lpuart_serial_setbrg(plat, baudrate); 3517edf5c45SPeng Fan } 352fdbae099SBin Meng 353fdbae099SBin Meng return 0; 354fdbae099SBin Meng } 355fdbae099SBin Meng 356c40d612bSPeng Fan static int lpuart_serial_getc(struct udevice *dev) 357fdbae099SBin Meng { 358fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 359fdbae099SBin Meng 360c40d612bSPeng Fan if (is_lpuart32(dev)) 361c40d612bSPeng Fan return _lpuart32_serial_getc(plat); 362c40d612bSPeng Fan 363c40d612bSPeng Fan return _lpuart_serial_getc(plat); 364fdbae099SBin Meng } 365fdbae099SBin Meng 366c40d612bSPeng Fan static int lpuart_serial_putc(struct udevice *dev, const char c) 367fdbae099SBin Meng { 368fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 369fdbae099SBin Meng 370c40d612bSPeng Fan if (is_lpuart32(dev)) 371c40d612bSPeng Fan _lpuart32_serial_putc(plat, c); 372c40d612bSPeng Fan else 373c40d612bSPeng Fan _lpuart_serial_putc(plat, c); 374fdbae099SBin Meng 375fdbae099SBin Meng return 0; 376fdbae099SBin Meng } 377fdbae099SBin Meng 378c40d612bSPeng Fan static int lpuart_serial_pending(struct udevice *dev, bool input) 379fdbae099SBin Meng { 380fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 381fdbae099SBin Meng struct lpuart_fsl *reg = plat->reg; 382c40d612bSPeng Fan struct lpuart_fsl_reg32 *reg32 = plat->reg; 383c40d612bSPeng Fan u32 stat; 384c40d612bSPeng Fan 385c40d612bSPeng Fan if (is_lpuart32(dev)) { 386c40d612bSPeng Fan if (input) { 387c40d612bSPeng Fan return _lpuart32_serial_tstc(plat); 388c40d612bSPeng Fan } else { 389c40d612bSPeng Fan lpuart_read32(plat->flags, ®32->stat, &stat); 390c40d612bSPeng Fan return stat & STAT_TDRE ? 0 : 1; 391c40d612bSPeng Fan } 392c40d612bSPeng Fan } 393fdbae099SBin Meng 394fdbae099SBin Meng if (input) 395c40d612bSPeng Fan return _lpuart_serial_tstc(plat); 396fdbae099SBin Meng else 397c40d612bSPeng Fan return __raw_readb(®->us1) & US1_TDRE ? 0 : 1; 398fdbae099SBin Meng } 399fdbae099SBin Meng 400c40d612bSPeng Fan static int lpuart_serial_probe(struct udevice *dev) 401fdbae099SBin Meng { 402fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 403fdbae099SBin Meng 404c40d612bSPeng Fan if (is_lpuart32(dev)) 405c40d612bSPeng Fan return _lpuart32_serial_init(plat); 406c40d612bSPeng Fan else 407c40d612bSPeng Fan return _lpuart_serial_init(plat); 408fdbae099SBin Meng } 409427eba70SAlison Wang 410fdbae099SBin Meng static int lpuart_serial_ofdata_to_platdata(struct udevice *dev) 411fdbae099SBin Meng { 412fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 4137edf5c45SPeng Fan const void *blob = gd->fdt_blob; 414da409cccSSimon Glass int node = dev_of_offset(dev); 415fdbae099SBin Meng fdt_addr_t addr; 416fdbae099SBin Meng 417a821c4afSSimon Glass addr = devfdt_get_addr(dev); 418fdbae099SBin Meng if (addr == FDT_ADDR_T_NONE) 419fdbae099SBin Meng return -EINVAL; 420fdbae099SBin Meng 421c40d612bSPeng Fan plat->reg = (void *)addr; 422c40d612bSPeng Fan plat->flags = dev_get_driver_data(dev); 423fdbae099SBin Meng 4247edf5c45SPeng Fan if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart")) 4257edf5c45SPeng Fan plat->devtype = DEV_LS1021A; 4267edf5c45SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart")) 4277edf5c45SPeng Fan plat->devtype = DEV_MX7ULP; 4287edf5c45SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart")) 4297edf5c45SPeng Fan plat->devtype = DEV_VF610; 4307edf5c45SPeng Fan 431fdbae099SBin Meng return 0; 432fdbae099SBin Meng } 433fdbae099SBin Meng 434fdbae099SBin Meng static const struct dm_serial_ops lpuart_serial_ops = { 435fdbae099SBin Meng .putc = lpuart_serial_putc, 436fdbae099SBin Meng .pending = lpuart_serial_pending, 437fdbae099SBin Meng .getc = lpuart_serial_getc, 438fdbae099SBin Meng .setbrg = lpuart_serial_setbrg, 439fdbae099SBin Meng }; 440fdbae099SBin Meng 441fdbae099SBin Meng static const struct udevice_id lpuart_serial_ids[] = { 442c40d612bSPeng Fan { .compatible = "fsl,ls1021a-lpuart", .data = 443c40d612bSPeng Fan LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG }, 4447edf5c45SPeng Fan { .compatible = "fsl,imx7ulp-lpuart", 4457edf5c45SPeng Fan .data = LPUART_FLAG_REGMAP_32BIT_REG }, 446fdbae099SBin Meng { .compatible = "fsl,vf610-lpuart"}, 447fdbae099SBin Meng { } 448fdbae099SBin Meng }; 449fdbae099SBin Meng 450fdbae099SBin Meng U_BOOT_DRIVER(serial_lpuart) = { 451fdbae099SBin Meng .name = "serial_lpuart", 452fdbae099SBin Meng .id = UCLASS_SERIAL, 453fdbae099SBin Meng .of_match = lpuart_serial_ids, 454fdbae099SBin Meng .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata, 455fdbae099SBin Meng .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata), 456fdbae099SBin Meng .probe = lpuart_serial_probe, 457fdbae099SBin Meng .ops = &lpuart_serial_ops, 458fdbae099SBin Meng .flags = DM_FLAG_PRE_RELOC, 459fdbae099SBin Meng }; 460