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> 7*8f5b6299SPeng Fan #include <clk.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 44cdc16f61SYe Li #define FIFO_RXFLUSH BIT(14) 45cdc16f61SYe Li #define FIFO_TXFLUSH BIT(15) 46cdc16f61SYe Li #define FIFO_TXSIZE_MASK 0x70 47cdc16f61SYe Li #define FIFO_TXSIZE_OFF 4 48cdc16f61SYe Li #define FIFO_RXSIZE_MASK 0x7 49cdc16f61SYe Li #define FIFO_RXSIZE_OFF 0 506209e14cSJingchang Lu #define FIFO_TXFE 0x80 51126f8849SPeng Fan #ifdef CONFIG_ARCH_IMX8 52126f8849SPeng Fan #define FIFO_RXFE 0x08 53126f8849SPeng Fan #else 546209e14cSJingchang Lu #define FIFO_RXFE 0x40 55126f8849SPeng Fan #endif 566209e14cSJingchang Lu 57cdc16f61SYe Li #define WATER_TXWATER_OFF 0 586209e14cSJingchang Lu #define WATER_RXWATER_OFF 16 596209e14cSJingchang Lu 60427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 61427eba70SAlison Wang 62c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_32BIT_REG BIT(0) 63c40d612bSPeng Fan #define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1) 64c40d612bSPeng Fan 657edf5c45SPeng Fan enum lpuart_devtype { 667edf5c45SPeng Fan DEV_VF610 = 1, 677edf5c45SPeng Fan DEV_LS1021A, 68126f8849SPeng Fan DEV_MX7ULP, 69126f8849SPeng Fan DEV_IMX8 707edf5c45SPeng Fan }; 717edf5c45SPeng Fan 72fdbae099SBin Meng struct lpuart_serial_platdata { 73c40d612bSPeng Fan void *reg; 747edf5c45SPeng Fan enum lpuart_devtype devtype; 75c40d612bSPeng Fan ulong flags; 76fdbae099SBin Meng }; 77fdbae099SBin Meng 78c40d612bSPeng Fan static void lpuart_read32(u32 flags, u32 *addr, u32 *val) 79427eba70SAlison Wang { 80c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 81c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 82c40d612bSPeng Fan *(u32 *)val = in_be32(addr); 83c40d612bSPeng Fan else 84c40d612bSPeng Fan *(u32 *)val = in_le32(addr); 85c40d612bSPeng Fan } 86c40d612bSPeng Fan } 87c40d612bSPeng Fan 88c40d612bSPeng Fan static void lpuart_write32(u32 flags, u32 *addr, u32 val) 89c40d612bSPeng Fan { 90c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_32BIT_REG) { 91c40d612bSPeng Fan if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG) 92c40d612bSPeng Fan out_be32(addr, val); 93c40d612bSPeng Fan else 94c40d612bSPeng Fan out_le32(addr, val); 95c40d612bSPeng Fan } 96c40d612bSPeng Fan } 97c40d612bSPeng Fan 98c40d612bSPeng Fan 99c40d612bSPeng Fan #ifndef CONFIG_SYS_CLK_FREQ 100c40d612bSPeng Fan #define CONFIG_SYS_CLK_FREQ 0 101c40d612bSPeng Fan #endif 102c40d612bSPeng Fan 103c40d612bSPeng Fan u32 __weak get_lpuart_clk(void) 104c40d612bSPeng Fan { 105c40d612bSPeng Fan return CONFIG_SYS_CLK_FREQ; 106c40d612bSPeng Fan } 107c40d612bSPeng Fan 108*8f5b6299SPeng Fan #if IS_ENABLED(CONFIG_CLK) 109*8f5b6299SPeng Fan static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk) 110*8f5b6299SPeng Fan { 111*8f5b6299SPeng Fan struct clk per_clk; 112*8f5b6299SPeng Fan ulong rate; 113*8f5b6299SPeng Fan int ret; 114*8f5b6299SPeng Fan 115*8f5b6299SPeng Fan ret = clk_get_by_name(dev, "per", &per_clk); 116*8f5b6299SPeng Fan if (ret) { 117*8f5b6299SPeng Fan dev_err(dev, "Failed to get per clk: %d\n", ret); 118*8f5b6299SPeng Fan return ret; 119*8f5b6299SPeng Fan } 120*8f5b6299SPeng Fan 121*8f5b6299SPeng Fan rate = clk_get_rate(&per_clk); 122*8f5b6299SPeng Fan if ((long)rate <= 0) { 123*8f5b6299SPeng Fan dev_err(dev, "Failed to get per clk rate: %ld\n", (long)rate); 124*8f5b6299SPeng Fan return ret; 125*8f5b6299SPeng Fan } 126*8f5b6299SPeng Fan *clk = rate; 127*8f5b6299SPeng Fan return 0; 128*8f5b6299SPeng Fan } 129*8f5b6299SPeng Fan #else 130*8f5b6299SPeng Fan static inline int get_lpuart_clk_rate(struct udevice *dev, u32 *clk) 131*8f5b6299SPeng Fan { return -ENOSYS; } 132*8f5b6299SPeng Fan #endif 133*8f5b6299SPeng Fan 134c40d612bSPeng Fan static bool is_lpuart32(struct udevice *dev) 135c40d612bSPeng Fan { 136c40d612bSPeng Fan struct lpuart_serial_platdata *plat = dev->platdata; 137c40d612bSPeng Fan 138c40d612bSPeng Fan return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG; 139c40d612bSPeng Fan } 140c40d612bSPeng Fan 141*8f5b6299SPeng Fan static void _lpuart_serial_setbrg(struct udevice *dev, 142c40d612bSPeng Fan int baudrate) 143c40d612bSPeng Fan { 144*8f5b6299SPeng Fan struct lpuart_serial_platdata *plat = dev_get_platdata(dev); 145c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 146*8f5b6299SPeng Fan u32 clk; 147427eba70SAlison Wang u16 sbr; 148*8f5b6299SPeng Fan int ret; 149*8f5b6299SPeng Fan 150*8f5b6299SPeng Fan if (IS_ENABLED(CONFIG_CLK)) { 151*8f5b6299SPeng Fan ret = get_lpuart_clk_rate(dev, &clk); 152*8f5b6299SPeng Fan if (ret) 153*8f5b6299SPeng Fan return; 154*8f5b6299SPeng Fan } else { 155*8f5b6299SPeng Fan clk = get_lpuart_clk(); 156*8f5b6299SPeng Fan } 157427eba70SAlison Wang 1586ca13b12SBin Meng sbr = (u16)(clk / (16 * baudrate)); 159427eba70SAlison Wang 16047f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 161427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 162427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 163427eba70SAlison Wang } 164427eba70SAlison Wang 165c40d612bSPeng Fan static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat) 166427eba70SAlison Wang { 167c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 168a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 169427eba70SAlison Wang WATCHDOG_RESET(); 170427eba70SAlison Wang 171a3db78d8SStefan Agner barrier(); 172427eba70SAlison Wang 173427eba70SAlison Wang return __raw_readb(&base->ud); 174427eba70SAlison Wang } 175427eba70SAlison Wang 176c40d612bSPeng Fan static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat, 177c40d612bSPeng Fan const char c) 178427eba70SAlison Wang { 179c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 180c40d612bSPeng Fan 181427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 182427eba70SAlison Wang WATCHDOG_RESET(); 183427eba70SAlison Wang 184427eba70SAlison Wang __raw_writeb(c, &base->ud); 185427eba70SAlison Wang } 186427eba70SAlison Wang 18747f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 188c40d612bSPeng Fan static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat) 189427eba70SAlison Wang { 190c40d612bSPeng Fan struct lpuart_fsl *base = plat->reg; 191c40d612bSPeng Fan 192427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 193427eba70SAlison Wang return 0; 194427eba70SAlison Wang 195427eba70SAlison Wang return 1; 196427eba70SAlison Wang } 197427eba70SAlison Wang 198427eba70SAlison Wang /* 199427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 200427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 201427eba70SAlison Wang */ 202*8f5b6299SPeng Fan static int _lpuart_serial_init(struct udevice *dev) 203427eba70SAlison Wang { 204*8f5b6299SPeng Fan struct lpuart_serial_platdata *plat = dev_get_platdata(dev); 205c40d612bSPeng Fan struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg; 206427eba70SAlison Wang u8 ctrl; 207427eba70SAlison Wang 208427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 209427eba70SAlison Wang ctrl &= ~UC2_RE; 210427eba70SAlison Wang ctrl &= ~UC2_TE; 211427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 212427eba70SAlison Wang 213427eba70SAlison Wang __raw_writeb(0, &base->umodem); 214427eba70SAlison Wang __raw_writeb(0, &base->uc1); 215427eba70SAlison Wang 21689e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 21789e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 21889e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 21989e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 22089e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 22189e69fd4SStefan Agner 222427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 223*8f5b6299SPeng Fan _lpuart_serial_setbrg(dev, gd->baudrate); 224427eba70SAlison Wang 225427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 226427eba70SAlison Wang 227427eba70SAlison Wang return 0; 228427eba70SAlison Wang } 229427eba70SAlison Wang 230*8f5b6299SPeng Fan static void _lpuart32_serial_setbrg_7ulp(struct udevice *dev, 2317edf5c45SPeng Fan int baudrate) 2327edf5c45SPeng Fan { 233*8f5b6299SPeng Fan struct lpuart_serial_platdata *plat = dev_get_platdata(dev); 2347edf5c45SPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 2357edf5c45SPeng Fan u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp; 236*8f5b6299SPeng Fan u32 clk; 237*8f5b6299SPeng Fan int ret; 238*8f5b6299SPeng Fan 239*8f5b6299SPeng Fan if (IS_ENABLED(CONFIG_CLK)) { 240*8f5b6299SPeng Fan ret = get_lpuart_clk_rate(dev, &clk); 241*8f5b6299SPeng Fan if (ret) 242*8f5b6299SPeng Fan return; 243*8f5b6299SPeng Fan } else { 244*8f5b6299SPeng Fan clk = get_lpuart_clk(); 245*8f5b6299SPeng Fan } 2467edf5c45SPeng Fan 2477edf5c45SPeng Fan baud_diff = baudrate; 2487edf5c45SPeng Fan osr = 0; 2497edf5c45SPeng Fan sbr = 0; 2507edf5c45SPeng Fan 2517edf5c45SPeng Fan for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) { 2527edf5c45SPeng Fan tmp_sbr = (clk / (baudrate * tmp_osr)); 2537edf5c45SPeng Fan 2547edf5c45SPeng Fan if (tmp_sbr == 0) 2557edf5c45SPeng Fan tmp_sbr = 1; 2567edf5c45SPeng Fan 2577edf5c45SPeng Fan /*calculate difference in actual buad w/ current values */ 2587edf5c45SPeng Fan tmp_diff = (clk / (tmp_osr * tmp_sbr)); 2597edf5c45SPeng Fan tmp_diff = tmp_diff - baudrate; 2607edf5c45SPeng Fan 2617edf5c45SPeng Fan /* select best values between sbr and sbr+1 */ 2627edf5c45SPeng Fan if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) { 2637edf5c45SPeng Fan tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1))); 2647edf5c45SPeng Fan tmp_sbr++; 2657edf5c45SPeng Fan } 2667edf5c45SPeng Fan 2677edf5c45SPeng Fan if (tmp_diff <= baud_diff) { 2687edf5c45SPeng Fan baud_diff = tmp_diff; 2697edf5c45SPeng Fan osr = tmp_osr; 2707edf5c45SPeng Fan sbr = tmp_sbr; 2717edf5c45SPeng Fan } 2727edf5c45SPeng Fan } 2737edf5c45SPeng Fan 2747edf5c45SPeng Fan /* 2757edf5c45SPeng Fan * TODO: handle buadrate outside acceptable rate 2767edf5c45SPeng Fan * if (baudDiff > ((config->baudRate_Bps / 100) * 3)) 2777edf5c45SPeng Fan * { 2787edf5c45SPeng Fan * Unacceptable baud rate difference of more than 3% 2797edf5c45SPeng Fan * return kStatus_LPUART_BaudrateNotSupport; 2807edf5c45SPeng Fan * } 2817edf5c45SPeng Fan */ 2827edf5c45SPeng Fan tmp = in_le32(&base->baud); 2837edf5c45SPeng Fan 2847edf5c45SPeng Fan if ((osr > 3) && (osr < 8)) 2857edf5c45SPeng Fan tmp |= LPUART_BAUD_BOTHEDGE_MASK; 2867edf5c45SPeng Fan 2877edf5c45SPeng Fan tmp &= ~LPUART_BAUD_OSR_MASK; 2887edf5c45SPeng Fan tmp |= LPUART_BAUD_OSR(osr-1); 2897edf5c45SPeng Fan 2907edf5c45SPeng Fan tmp &= ~LPUART_BAUD_SBR_MASK; 2917edf5c45SPeng Fan tmp |= LPUART_BAUD_SBR(sbr); 2927edf5c45SPeng Fan 2937edf5c45SPeng Fan /* explicitly disable 10 bit mode & set 1 stop bit */ 2947edf5c45SPeng Fan tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK); 2957edf5c45SPeng Fan 2967edf5c45SPeng Fan out_le32(&base->baud, tmp); 2977edf5c45SPeng Fan } 2987edf5c45SPeng Fan 299*8f5b6299SPeng Fan static void _lpuart32_serial_setbrg(struct udevice *dev, 300c40d612bSPeng Fan int baudrate) 301fdbae099SBin Meng { 302*8f5b6299SPeng Fan struct lpuart_serial_platdata *plat = dev_get_platdata(dev); 303c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 304*8f5b6299SPeng Fan u32 clk; 3056209e14cSJingchang Lu u32 sbr; 306*8f5b6299SPeng Fan int ret; 307*8f5b6299SPeng Fan 308*8f5b6299SPeng Fan if (IS_ENABLED(CONFIG_CLK)) { 309*8f5b6299SPeng Fan ret = get_lpuart_clk_rate(dev, &clk); 310*8f5b6299SPeng Fan if (ret) 311*8f5b6299SPeng Fan return; 312*8f5b6299SPeng Fan } else { 313*8f5b6299SPeng Fan clk = get_lpuart_clk(); 314*8f5b6299SPeng Fan } 3156209e14cSJingchang Lu 3166ca13b12SBin Meng sbr = (clk / (16 * baudrate)); 3176209e14cSJingchang Lu 31847f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 319c40d612bSPeng Fan lpuart_write32(plat->flags, &base->baud, sbr); 3206209e14cSJingchang Lu } 3216209e14cSJingchang Lu 322c40d612bSPeng Fan static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat) 3236209e14cSJingchang Lu { 324c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 3257edf5c45SPeng Fan u32 stat, val; 3266209e14cSJingchang Lu 327c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 328c40d612bSPeng Fan while ((stat & STAT_RDRF) == 0) { 329c40d612bSPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_FLAGS); 3306209e14cSJingchang Lu WATCHDOG_RESET(); 331c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 3326209e14cSJingchang Lu } 3336209e14cSJingchang Lu 3347edf5c45SPeng Fan lpuart_read32(plat->flags, &base->data, &val); 335c40d612bSPeng Fan 3367edf5c45SPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 3377edf5c45SPeng Fan if (stat & STAT_OR) 3387edf5c45SPeng Fan lpuart_write32(plat->flags, &base->stat, STAT_OR); 3397edf5c45SPeng Fan 3407edf5c45SPeng Fan return val & 0x3ff; 3416209e14cSJingchang Lu } 3426209e14cSJingchang Lu 343c40d612bSPeng Fan static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat, 344c40d612bSPeng Fan const char c) 3456209e14cSJingchang Lu { 346c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 347c40d612bSPeng Fan u32 stat; 3486209e14cSJingchang Lu 3497edf5c45SPeng Fan if (c == '\n') 3507edf5c45SPeng Fan serial_putc('\r'); 3517edf5c45SPeng Fan 352c40d612bSPeng Fan while (true) { 353c40d612bSPeng Fan lpuart_read32(plat->flags, &base->stat, &stat); 354c40d612bSPeng Fan 355c40d612bSPeng Fan if ((stat & STAT_TDRE)) 356c40d612bSPeng Fan break; 357c40d612bSPeng Fan 358c40d612bSPeng Fan WATCHDOG_RESET(); 359c40d612bSPeng Fan } 360c40d612bSPeng Fan 361c40d612bSPeng Fan lpuart_write32(plat->flags, &base->data, c); 3626209e14cSJingchang Lu } 3636209e14cSJingchang Lu 36447f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 365c40d612bSPeng Fan static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat) 3666209e14cSJingchang Lu { 367c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = plat->reg; 368c40d612bSPeng Fan u32 water; 369c40d612bSPeng Fan 370c40d612bSPeng Fan lpuart_read32(plat->flags, &base->water, &water); 371c40d612bSPeng Fan 372c40d612bSPeng Fan if ((water >> 24) == 0) 3736209e14cSJingchang Lu return 0; 3746209e14cSJingchang Lu 3756209e14cSJingchang Lu return 1; 3766209e14cSJingchang Lu } 3776209e14cSJingchang Lu 3786209e14cSJingchang Lu /* 3796209e14cSJingchang Lu * Initialise the serial port with the given baudrate. The settings 3806209e14cSJingchang Lu * are always 8 data bits, no parity, 1 stop bit, no start bits. 3816209e14cSJingchang Lu */ 382*8f5b6299SPeng Fan static int _lpuart32_serial_init(struct udevice *dev) 3836209e14cSJingchang Lu { 384*8f5b6299SPeng Fan struct lpuart_serial_platdata *plat = dev_get_platdata(dev); 385c40d612bSPeng Fan struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg; 386cdc16f61SYe Li u32 val, tx_fifo_size; 3876209e14cSJingchang Lu 388cdc16f61SYe Li lpuart_read32(plat->flags, &base->ctrl, &val); 389cdc16f61SYe Li val &= ~CTRL_RE; 390cdc16f61SYe Li val &= ~CTRL_TE; 391cdc16f61SYe Li lpuart_write32(plat->flags, &base->ctrl, val); 3926209e14cSJingchang Lu 393c40d612bSPeng Fan lpuart_write32(plat->flags, &base->modir, 0); 394cdc16f61SYe Li 395cdc16f61SYe Li lpuart_read32(plat->flags, &base->fifo, &val); 396cdc16f61SYe Li tx_fifo_size = (val & FIFO_TXSIZE_MASK) >> FIFO_TXSIZE_OFF; 397cdc16f61SYe Li /* Set the TX water to half of FIFO size */ 398cdc16f61SYe Li if (tx_fifo_size > 1) 399cdc16f61SYe Li tx_fifo_size = tx_fifo_size >> 1; 400cdc16f61SYe Li 401cdc16f61SYe Li /* Set RX water to 0, to be triggered by any receive data */ 402cdc16f61SYe Li lpuart_write32(plat->flags, &base->water, 403cdc16f61SYe Li (tx_fifo_size << WATER_TXWATER_OFF)); 404cdc16f61SYe Li 405cdc16f61SYe Li /* Enable TX and RX FIFO */ 406cdc16f61SYe Li val |= (FIFO_TXFE | FIFO_RXFE | FIFO_TXFLUSH | FIFO_RXFLUSH); 407cdc16f61SYe Li lpuart_write32(plat->flags, &base->fifo, val); 4086209e14cSJingchang Lu 409c40d612bSPeng Fan lpuart_write32(plat->flags, &base->match, 0); 4106209e14cSJingchang Lu 411126f8849SPeng Fan if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) { 412*8f5b6299SPeng Fan _lpuart32_serial_setbrg_7ulp(dev, gd->baudrate); 4137edf5c45SPeng Fan } else { 41447f1bfcaSBin Meng /* provide data bits, parity, stop bit, etc */ 415*8f5b6299SPeng Fan _lpuart32_serial_setbrg(dev, gd->baudrate); 4167edf5c45SPeng Fan } 4176209e14cSJingchang Lu 418c40d612bSPeng Fan lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE); 4196209e14cSJingchang Lu 4206209e14cSJingchang Lu return 0; 4216209e14cSJingchang Lu } 4226209e14cSJingchang Lu 423c40d612bSPeng Fan static int lpuart_serial_setbrg(struct udevice *dev, int baudrate) 424fdbae099SBin Meng { 425*8f5b6299SPeng Fan struct lpuart_serial_platdata *plat = dev_get_platdata(dev); 426fdbae099SBin Meng 4277edf5c45SPeng Fan if (is_lpuart32(dev)) { 428126f8849SPeng Fan if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) 429*8f5b6299SPeng Fan _lpuart32_serial_setbrg_7ulp(dev, baudrate); 430c40d612bSPeng Fan else 431*8f5b6299SPeng Fan _lpuart32_serial_setbrg(dev, baudrate); 4327edf5c45SPeng Fan } else { 433*8f5b6299SPeng Fan _lpuart_serial_setbrg(dev, baudrate); 4347edf5c45SPeng Fan } 435fdbae099SBin Meng 436fdbae099SBin Meng return 0; 437fdbae099SBin Meng } 438fdbae099SBin Meng 439c40d612bSPeng Fan static int lpuart_serial_getc(struct udevice *dev) 440fdbae099SBin Meng { 441fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 442fdbae099SBin Meng 443c40d612bSPeng Fan if (is_lpuart32(dev)) 444c40d612bSPeng Fan return _lpuart32_serial_getc(plat); 445c40d612bSPeng Fan 446c40d612bSPeng Fan return _lpuart_serial_getc(plat); 447fdbae099SBin Meng } 448fdbae099SBin Meng 449c40d612bSPeng Fan static int lpuart_serial_putc(struct udevice *dev, const char c) 450fdbae099SBin Meng { 451fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 452fdbae099SBin Meng 453c40d612bSPeng Fan if (is_lpuart32(dev)) 454c40d612bSPeng Fan _lpuart32_serial_putc(plat, c); 455c40d612bSPeng Fan else 456c40d612bSPeng Fan _lpuart_serial_putc(plat, c); 457fdbae099SBin Meng 458fdbae099SBin Meng return 0; 459fdbae099SBin Meng } 460fdbae099SBin Meng 461c40d612bSPeng Fan static int lpuart_serial_pending(struct udevice *dev, bool input) 462fdbae099SBin Meng { 463fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 464fdbae099SBin Meng struct lpuart_fsl *reg = plat->reg; 465c40d612bSPeng Fan struct lpuart_fsl_reg32 *reg32 = plat->reg; 466c40d612bSPeng Fan u32 stat; 467c40d612bSPeng Fan 468c40d612bSPeng Fan if (is_lpuart32(dev)) { 469c40d612bSPeng Fan if (input) { 470c40d612bSPeng Fan return _lpuart32_serial_tstc(plat); 471c40d612bSPeng Fan } else { 472c40d612bSPeng Fan lpuart_read32(plat->flags, ®32->stat, &stat); 473c40d612bSPeng Fan return stat & STAT_TDRE ? 0 : 1; 474c40d612bSPeng Fan } 475c40d612bSPeng Fan } 476fdbae099SBin Meng 477fdbae099SBin Meng if (input) 478c40d612bSPeng Fan return _lpuart_serial_tstc(plat); 479fdbae099SBin Meng else 480c40d612bSPeng Fan return __raw_readb(®->us1) & US1_TDRE ? 0 : 1; 481fdbae099SBin Meng } 482fdbae099SBin Meng 483c40d612bSPeng Fan static int lpuart_serial_probe(struct udevice *dev) 484fdbae099SBin Meng { 485c40d612bSPeng Fan if (is_lpuart32(dev)) 486*8f5b6299SPeng Fan return _lpuart32_serial_init(dev); 487c40d612bSPeng Fan else 488*8f5b6299SPeng Fan return _lpuart_serial_init(dev); 489fdbae099SBin Meng } 490427eba70SAlison Wang 491fdbae099SBin Meng static int lpuart_serial_ofdata_to_platdata(struct udevice *dev) 492fdbae099SBin Meng { 493fdbae099SBin Meng struct lpuart_serial_platdata *plat = dev->platdata; 4947edf5c45SPeng Fan const void *blob = gd->fdt_blob; 495da409cccSSimon Glass int node = dev_of_offset(dev); 496fdbae099SBin Meng fdt_addr_t addr; 497fdbae099SBin Meng 498a821c4afSSimon Glass addr = devfdt_get_addr(dev); 499fdbae099SBin Meng if (addr == FDT_ADDR_T_NONE) 500fdbae099SBin Meng return -EINVAL; 501fdbae099SBin Meng 502c40d612bSPeng Fan plat->reg = (void *)addr; 503c40d612bSPeng Fan plat->flags = dev_get_driver_data(dev); 504fdbae099SBin Meng 5057edf5c45SPeng Fan if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart")) 5067edf5c45SPeng Fan plat->devtype = DEV_LS1021A; 5077edf5c45SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart")) 5087edf5c45SPeng Fan plat->devtype = DEV_MX7ULP; 5097edf5c45SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart")) 5107edf5c45SPeng Fan plat->devtype = DEV_VF610; 511126f8849SPeng Fan else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart")) 512126f8849SPeng Fan plat->devtype = DEV_IMX8; 5137edf5c45SPeng Fan 514fdbae099SBin Meng return 0; 515fdbae099SBin Meng } 516fdbae099SBin Meng 517fdbae099SBin Meng static const struct dm_serial_ops lpuart_serial_ops = { 518fdbae099SBin Meng .putc = lpuart_serial_putc, 519fdbae099SBin Meng .pending = lpuart_serial_pending, 520fdbae099SBin Meng .getc = lpuart_serial_getc, 521fdbae099SBin Meng .setbrg = lpuart_serial_setbrg, 522fdbae099SBin Meng }; 523fdbae099SBin Meng 524fdbae099SBin Meng static const struct udevice_id lpuart_serial_ids[] = { 525c40d612bSPeng Fan { .compatible = "fsl,ls1021a-lpuart", .data = 526c40d612bSPeng Fan LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG }, 5277edf5c45SPeng Fan { .compatible = "fsl,imx7ulp-lpuart", 5287edf5c45SPeng Fan .data = LPUART_FLAG_REGMAP_32BIT_REG }, 529fdbae099SBin Meng { .compatible = "fsl,vf610-lpuart"}, 530126f8849SPeng Fan { .compatible = "fsl,imx8qm-lpuart", 531126f8849SPeng Fan .data = LPUART_FLAG_REGMAP_32BIT_REG }, 532fdbae099SBin Meng { } 533fdbae099SBin Meng }; 534fdbae099SBin Meng 535fdbae099SBin Meng U_BOOT_DRIVER(serial_lpuart) = { 536fdbae099SBin Meng .name = "serial_lpuart", 537fdbae099SBin Meng .id = UCLASS_SERIAL, 538fdbae099SBin Meng .of_match = lpuart_serial_ids, 539fdbae099SBin Meng .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata, 540fdbae099SBin Meng .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata), 541fdbae099SBin Meng .probe = lpuart_serial_probe, 542fdbae099SBin Meng .ops = &lpuart_serial_ops, 543fdbae099SBin Meng .flags = DM_FLAG_PRE_RELOC, 544fdbae099SBin Meng }; 545