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> 8427eba70SAlison Wang #include <watchdog.h> 9427eba70SAlison Wang #include <asm/io.h> 10427eba70SAlison Wang #include <serial.h> 11427eba70SAlison Wang #include <linux/compiler.h> 12427eba70SAlison Wang #include <asm/arch/imx-regs.h> 13427eba70SAlison Wang #include <asm/arch/clock.h> 14427eba70SAlison Wang 15427eba70SAlison Wang #define US1_TDRE (1 << 7) 16427eba70SAlison Wang #define US1_RDRF (1 << 5) 17a3db78d8SStefan Agner #define US1_OR (1 << 3) 18427eba70SAlison Wang #define UC2_TE (1 << 3) 19427eba70SAlison Wang #define UC2_RE (1 << 2) 2089e69fd4SStefan Agner #define CFIFO_TXFLUSH (1 << 7) 2189e69fd4SStefan Agner #define CFIFO_RXFLUSH (1 << 6) 2289e69fd4SStefan Agner #define SFIFO_RXOF (1 << 2) 2389e69fd4SStefan Agner #define SFIFO_RXUF (1 << 0) 24427eba70SAlison Wang 256209e14cSJingchang Lu #define STAT_LBKDIF (1 << 31) 266209e14cSJingchang Lu #define STAT_RXEDGIF (1 << 30) 276209e14cSJingchang Lu #define STAT_TDRE (1 << 23) 286209e14cSJingchang Lu #define STAT_RDRF (1 << 21) 296209e14cSJingchang Lu #define STAT_IDLE (1 << 20) 306209e14cSJingchang Lu #define STAT_OR (1 << 19) 316209e14cSJingchang Lu #define STAT_NF (1 << 18) 326209e14cSJingchang Lu #define STAT_FE (1 << 17) 336209e14cSJingchang Lu #define STAT_PF (1 << 16) 346209e14cSJingchang Lu #define STAT_MA1F (1 << 15) 356209e14cSJingchang Lu #define STAT_MA2F (1 << 14) 366209e14cSJingchang Lu #define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \ 376209e14cSJingchang Lu STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F) 386209e14cSJingchang Lu 396209e14cSJingchang Lu #define CTRL_TE (1 << 19) 406209e14cSJingchang Lu #define CTRL_RE (1 << 18) 416209e14cSJingchang Lu 426209e14cSJingchang Lu #define FIFO_TXFE 0x80 436209e14cSJingchang Lu #define FIFO_RXFE 0x40 446209e14cSJingchang Lu 456209e14cSJingchang Lu #define WATER_TXWATER_OFF 1 466209e14cSJingchang Lu #define WATER_RXWATER_OFF 16 476209e14cSJingchang Lu 48427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 49427eba70SAlison Wang 50427eba70SAlison Wang struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE; 51427eba70SAlison Wang 526209e14cSJingchang Lu #ifndef CONFIG_LPUART_32B_REG 53*6ca13b12SBin Meng static void _lpuart_serial_setbrg(struct lpuart_fsl *base, int baudrate) 54427eba70SAlison Wang { 55427eba70SAlison Wang u32 clk = mxc_get_clock(MXC_UART_CLK); 56427eba70SAlison Wang u16 sbr; 57427eba70SAlison Wang 58*6ca13b12SBin Meng sbr = (u16)(clk / (16 * baudrate)); 59427eba70SAlison Wang 6047f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 61427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 62427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 63427eba70SAlison Wang } 64427eba70SAlison Wang 65*6ca13b12SBin Meng static int _lpuart_serial_getc(struct lpuart_fsl *base) 66427eba70SAlison Wang { 67a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 68427eba70SAlison Wang WATCHDOG_RESET(); 69427eba70SAlison Wang 70a3db78d8SStefan Agner barrier(); 71427eba70SAlison Wang 72427eba70SAlison Wang return __raw_readb(&base->ud); 73427eba70SAlison Wang } 74427eba70SAlison Wang 75*6ca13b12SBin Meng static void _lpuart_serial_putc(struct lpuart_fsl *base, const char c) 76427eba70SAlison Wang { 77427eba70SAlison Wang if (c == '\n') 78*6ca13b12SBin Meng _lpuart_serial_putc(base, '\r'); 79427eba70SAlison Wang 80427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 81427eba70SAlison Wang WATCHDOG_RESET(); 82427eba70SAlison Wang 83427eba70SAlison Wang __raw_writeb(c, &base->ud); 84427eba70SAlison Wang } 85427eba70SAlison Wang 8647f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 87*6ca13b12SBin Meng static int _lpuart_serial_tstc(struct lpuart_fsl *base) 88427eba70SAlison Wang { 89427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 90427eba70SAlison Wang return 0; 91427eba70SAlison Wang 92427eba70SAlison Wang return 1; 93427eba70SAlison Wang } 94427eba70SAlison Wang 95427eba70SAlison Wang /* 96427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 97427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 98427eba70SAlison Wang */ 99*6ca13b12SBin Meng static int _lpuart_serial_init(struct lpuart_fsl *base) 100427eba70SAlison Wang { 101427eba70SAlison Wang u8 ctrl; 102427eba70SAlison Wang 103427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 104427eba70SAlison Wang ctrl &= ~UC2_RE; 105427eba70SAlison Wang ctrl &= ~UC2_TE; 106427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 107427eba70SAlison Wang 108427eba70SAlison Wang __raw_writeb(0, &base->umodem); 109427eba70SAlison Wang __raw_writeb(0, &base->uc1); 110427eba70SAlison Wang 11189e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 11289e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 11389e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 11489e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 11589e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 11689e69fd4SStefan Agner 117427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 118*6ca13b12SBin Meng _lpuart_serial_setbrg(base, gd->baudrate); 119427eba70SAlison Wang 120427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 121427eba70SAlison Wang 122427eba70SAlison Wang return 0; 123427eba70SAlison Wang } 124427eba70SAlison Wang 125*6ca13b12SBin Meng static void lpuart_serial_setbrg(void) 126*6ca13b12SBin Meng { 127*6ca13b12SBin Meng _lpuart_serial_setbrg(base, gd->baudrate); 128*6ca13b12SBin Meng } 129*6ca13b12SBin Meng 130*6ca13b12SBin Meng static int lpuart_serial_getc(void) 131*6ca13b12SBin Meng { 132*6ca13b12SBin Meng return _lpuart_serial_getc(base); 133*6ca13b12SBin Meng } 134*6ca13b12SBin Meng 135*6ca13b12SBin Meng static void lpuart_serial_putc(const char c) 136*6ca13b12SBin Meng { 137*6ca13b12SBin Meng _lpuart_serial_putc(base, c); 138*6ca13b12SBin Meng } 139*6ca13b12SBin Meng 140*6ca13b12SBin Meng static int lpuart_serial_tstc(void) 141*6ca13b12SBin Meng { 142*6ca13b12SBin Meng return _lpuart_serial_tstc(base); 143*6ca13b12SBin Meng } 144*6ca13b12SBin Meng 145*6ca13b12SBin Meng static int lpuart_serial_init(void) 146*6ca13b12SBin Meng { 147*6ca13b12SBin Meng return _lpuart_serial_init(base); 148*6ca13b12SBin Meng } 149*6ca13b12SBin Meng 150427eba70SAlison Wang static struct serial_device lpuart_serial_drv = { 151427eba70SAlison Wang .name = "lpuart_serial", 152427eba70SAlison Wang .start = lpuart_serial_init, 153427eba70SAlison Wang .stop = NULL, 154427eba70SAlison Wang .setbrg = lpuart_serial_setbrg, 155427eba70SAlison Wang .putc = lpuart_serial_putc, 156427eba70SAlison Wang .puts = default_serial_puts, 157427eba70SAlison Wang .getc = lpuart_serial_getc, 158427eba70SAlison Wang .tstc = lpuart_serial_tstc, 159427eba70SAlison Wang }; 1606209e14cSJingchang Lu #else 161*6ca13b12SBin Meng static void _lpuart32_serial_setbrg(struct lpuart_fsl *base, int baudrate) 1626209e14cSJingchang Lu { 1636209e14cSJingchang Lu u32 clk = CONFIG_SYS_CLK_FREQ; 1646209e14cSJingchang Lu u32 sbr; 1656209e14cSJingchang Lu 166*6ca13b12SBin Meng sbr = (clk / (16 * baudrate)); 1676209e14cSJingchang Lu 16847f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 1696209e14cSJingchang Lu out_be32(&base->baud, sbr); 1706209e14cSJingchang Lu } 1716209e14cSJingchang Lu 172*6ca13b12SBin Meng static int _lpuart32_serial_getc(struct lpuart_fsl *base) 1736209e14cSJingchang Lu { 1746209e14cSJingchang Lu u32 stat; 1756209e14cSJingchang Lu 1766209e14cSJingchang Lu while (((stat = in_be32(&base->stat)) & STAT_RDRF) == 0) { 1776209e14cSJingchang Lu out_be32(&base->stat, STAT_FLAGS); 1786209e14cSJingchang Lu WATCHDOG_RESET(); 1796209e14cSJingchang Lu } 1806209e14cSJingchang Lu 1816209e14cSJingchang Lu return in_be32(&base->data) & 0x3ff; 1826209e14cSJingchang Lu } 1836209e14cSJingchang Lu 184*6ca13b12SBin Meng static void _lpuart32_serial_putc(struct lpuart_fsl *base, const char c) 1856209e14cSJingchang Lu { 1866209e14cSJingchang Lu if (c == '\n') 187*6ca13b12SBin Meng _lpuart32_serial_putc(base, '\r'); 1886209e14cSJingchang Lu 1896209e14cSJingchang Lu while (!(in_be32(&base->stat) & STAT_TDRE)) 1906209e14cSJingchang Lu WATCHDOG_RESET(); 1916209e14cSJingchang Lu 1926209e14cSJingchang Lu out_be32(&base->data, c); 1936209e14cSJingchang Lu } 1946209e14cSJingchang Lu 19547f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 196*6ca13b12SBin Meng static int _lpuart32_serial_tstc(struct lpuart_fsl *base) 1976209e14cSJingchang Lu { 1986209e14cSJingchang Lu if ((in_be32(&base->water) >> 24) == 0) 1996209e14cSJingchang Lu return 0; 2006209e14cSJingchang Lu 2016209e14cSJingchang Lu return 1; 2026209e14cSJingchang Lu } 2036209e14cSJingchang Lu 2046209e14cSJingchang Lu /* 2056209e14cSJingchang Lu * Initialise the serial port with the given baudrate. The settings 2066209e14cSJingchang Lu * are always 8 data bits, no parity, 1 stop bit, no start bits. 2076209e14cSJingchang Lu */ 208*6ca13b12SBin Meng static int _lpuart32_serial_init(struct lpuart_fsl *base) 2096209e14cSJingchang Lu { 2106209e14cSJingchang Lu u8 ctrl; 2116209e14cSJingchang Lu 2126209e14cSJingchang Lu ctrl = in_be32(&base->ctrl); 2136209e14cSJingchang Lu ctrl &= ~CTRL_RE; 2146209e14cSJingchang Lu ctrl &= ~CTRL_TE; 2156209e14cSJingchang Lu out_be32(&base->ctrl, ctrl); 2166209e14cSJingchang Lu 2176209e14cSJingchang Lu out_be32(&base->modir, 0); 2186209e14cSJingchang Lu out_be32(&base->fifo, ~(FIFO_TXFE | FIFO_RXFE)); 2196209e14cSJingchang Lu 2206209e14cSJingchang Lu out_be32(&base->match, 0); 2216209e14cSJingchang Lu 22247f1bfcaSBin Meng /* provide data bits, parity, stop bit, etc */ 223*6ca13b12SBin Meng _lpuart32_serial_setbrg(base, gd->baudrate); 2246209e14cSJingchang Lu 2256209e14cSJingchang Lu out_be32(&base->ctrl, CTRL_RE | CTRL_TE); 2266209e14cSJingchang Lu 2276209e14cSJingchang Lu return 0; 2286209e14cSJingchang Lu } 2296209e14cSJingchang Lu 230*6ca13b12SBin Meng static void lpuart32_serial_setbrg(void) 231*6ca13b12SBin Meng { 232*6ca13b12SBin Meng _lpuart32_serial_setbrg(base, gd->baudrate); 233*6ca13b12SBin Meng } 234*6ca13b12SBin Meng 235*6ca13b12SBin Meng static int lpuart32_serial_getc(void) 236*6ca13b12SBin Meng { 237*6ca13b12SBin Meng return _lpuart32_serial_getc(base); 238*6ca13b12SBin Meng } 239*6ca13b12SBin Meng 240*6ca13b12SBin Meng static void lpuart32_serial_putc(const char c) 241*6ca13b12SBin Meng { 242*6ca13b12SBin Meng _lpuart32_serial_putc(base, c); 243*6ca13b12SBin Meng } 244*6ca13b12SBin Meng 245*6ca13b12SBin Meng static int lpuart32_serial_tstc(void) 246*6ca13b12SBin Meng { 247*6ca13b12SBin Meng return _lpuart32_serial_tstc(base); 248*6ca13b12SBin Meng } 249*6ca13b12SBin Meng 250*6ca13b12SBin Meng static int lpuart32_serial_init(void) 251*6ca13b12SBin Meng { 252*6ca13b12SBin Meng return _lpuart32_serial_init(base); 253*6ca13b12SBin Meng } 254*6ca13b12SBin Meng 2556209e14cSJingchang Lu static struct serial_device lpuart32_serial_drv = { 2566209e14cSJingchang Lu .name = "lpuart32_serial", 2576209e14cSJingchang Lu .start = lpuart32_serial_init, 2586209e14cSJingchang Lu .stop = NULL, 2596209e14cSJingchang Lu .setbrg = lpuart32_serial_setbrg, 2606209e14cSJingchang Lu .putc = lpuart32_serial_putc, 2616209e14cSJingchang Lu .puts = default_serial_puts, 2626209e14cSJingchang Lu .getc = lpuart32_serial_getc, 2636209e14cSJingchang Lu .tstc = lpuart32_serial_tstc, 2646209e14cSJingchang Lu }; 2656209e14cSJingchang Lu #endif 266427eba70SAlison Wang 267427eba70SAlison Wang void lpuart_serial_initialize(void) 268427eba70SAlison Wang { 2696209e14cSJingchang Lu #ifdef CONFIG_LPUART_32B_REG 2706209e14cSJingchang Lu serial_register(&lpuart32_serial_drv); 2716209e14cSJingchang Lu #else 272427eba70SAlison Wang serial_register(&lpuart_serial_drv); 2736209e14cSJingchang Lu #endif 274427eba70SAlison Wang } 275427eba70SAlison Wang 276427eba70SAlison Wang __weak struct serial_device *default_serial_console(void) 277427eba70SAlison Wang { 2786209e14cSJingchang Lu #ifdef CONFIG_LPUART_32B_REG 2796209e14cSJingchang Lu return &lpuart32_serial_drv; 2806209e14cSJingchang Lu #else 281427eba70SAlison Wang return &lpuart_serial_drv; 2826209e14cSJingchang Lu #endif 283427eba70SAlison Wang } 284