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 53427eba70SAlison Wang static void lpuart_serial_setbrg(void) 54427eba70SAlison Wang { 55427eba70SAlison Wang u32 clk = mxc_get_clock(MXC_UART_CLK); 56427eba70SAlison Wang u16 sbr; 57427eba70SAlison Wang 58427eba70SAlison Wang if (!gd->baudrate) 59427eba70SAlison Wang gd->baudrate = CONFIG_BAUDRATE; 60427eba70SAlison Wang 61427eba70SAlison Wang sbr = (u16)(clk / (16 * gd->baudrate)); 62427eba70SAlison Wang 63*47f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 64427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 65427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 66427eba70SAlison Wang } 67427eba70SAlison Wang 68427eba70SAlison Wang static int lpuart_serial_getc(void) 69427eba70SAlison Wang { 70a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 71427eba70SAlison Wang WATCHDOG_RESET(); 72427eba70SAlison Wang 73a3db78d8SStefan Agner barrier(); 74427eba70SAlison Wang 75427eba70SAlison Wang return __raw_readb(&base->ud); 76427eba70SAlison Wang } 77427eba70SAlison Wang 78427eba70SAlison Wang static void lpuart_serial_putc(const char c) 79427eba70SAlison Wang { 80427eba70SAlison Wang if (c == '\n') 81427eba70SAlison Wang serial_putc('\r'); 82427eba70SAlison Wang 83427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 84427eba70SAlison Wang WATCHDOG_RESET(); 85427eba70SAlison Wang 86427eba70SAlison Wang __raw_writeb(c, &base->ud); 87427eba70SAlison Wang } 88427eba70SAlison Wang 89*47f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 90427eba70SAlison Wang static int lpuart_serial_tstc(void) 91427eba70SAlison Wang { 92427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 93427eba70SAlison Wang return 0; 94427eba70SAlison Wang 95427eba70SAlison Wang return 1; 96427eba70SAlison Wang } 97427eba70SAlison Wang 98427eba70SAlison Wang /* 99427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 100427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 101427eba70SAlison Wang */ 102427eba70SAlison Wang static int lpuart_serial_init(void) 103427eba70SAlison Wang { 104427eba70SAlison Wang u8 ctrl; 105427eba70SAlison Wang 106427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 107427eba70SAlison Wang ctrl &= ~UC2_RE; 108427eba70SAlison Wang ctrl &= ~UC2_TE; 109427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 110427eba70SAlison Wang 111427eba70SAlison Wang __raw_writeb(0, &base->umodem); 112427eba70SAlison Wang __raw_writeb(0, &base->uc1); 113427eba70SAlison Wang 11489e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 11589e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 11689e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 11789e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 11889e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 11989e69fd4SStefan Agner 120427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 121427eba70SAlison Wang serial_setbrg(); 122427eba70SAlison Wang 123427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 124427eba70SAlison Wang 125427eba70SAlison Wang return 0; 126427eba70SAlison Wang } 127427eba70SAlison Wang 128427eba70SAlison Wang static struct serial_device lpuart_serial_drv = { 129427eba70SAlison Wang .name = "lpuart_serial", 130427eba70SAlison Wang .start = lpuart_serial_init, 131427eba70SAlison Wang .stop = NULL, 132427eba70SAlison Wang .setbrg = lpuart_serial_setbrg, 133427eba70SAlison Wang .putc = lpuart_serial_putc, 134427eba70SAlison Wang .puts = default_serial_puts, 135427eba70SAlison Wang .getc = lpuart_serial_getc, 136427eba70SAlison Wang .tstc = lpuart_serial_tstc, 137427eba70SAlison Wang }; 1386209e14cSJingchang Lu #else 1396209e14cSJingchang Lu static void lpuart32_serial_setbrg(void) 1406209e14cSJingchang Lu { 1416209e14cSJingchang Lu u32 clk = CONFIG_SYS_CLK_FREQ; 1426209e14cSJingchang Lu u32 sbr; 1436209e14cSJingchang Lu 1446209e14cSJingchang Lu if (!gd->baudrate) 1456209e14cSJingchang Lu gd->baudrate = CONFIG_BAUDRATE; 1466209e14cSJingchang Lu 1476209e14cSJingchang Lu sbr = (clk / (16 * gd->baudrate)); 1486209e14cSJingchang Lu 149*47f1bfcaSBin Meng /* place adjustment later - n/32 BRFA */ 1506209e14cSJingchang Lu out_be32(&base->baud, sbr); 1516209e14cSJingchang Lu } 1526209e14cSJingchang Lu 1536209e14cSJingchang Lu static int lpuart32_serial_getc(void) 1546209e14cSJingchang Lu { 1556209e14cSJingchang Lu u32 stat; 1566209e14cSJingchang Lu 1576209e14cSJingchang Lu while (((stat = in_be32(&base->stat)) & STAT_RDRF) == 0) { 1586209e14cSJingchang Lu out_be32(&base->stat, STAT_FLAGS); 1596209e14cSJingchang Lu WATCHDOG_RESET(); 1606209e14cSJingchang Lu } 1616209e14cSJingchang Lu 1626209e14cSJingchang Lu return in_be32(&base->data) & 0x3ff; 1636209e14cSJingchang Lu } 1646209e14cSJingchang Lu 1656209e14cSJingchang Lu static void lpuart32_serial_putc(const char c) 1666209e14cSJingchang Lu { 1676209e14cSJingchang Lu if (c == '\n') 1686209e14cSJingchang Lu serial_putc('\r'); 1696209e14cSJingchang Lu 1706209e14cSJingchang Lu while (!(in_be32(&base->stat) & STAT_TDRE)) 1716209e14cSJingchang Lu WATCHDOG_RESET(); 1726209e14cSJingchang Lu 1736209e14cSJingchang Lu out_be32(&base->data, c); 1746209e14cSJingchang Lu } 1756209e14cSJingchang Lu 176*47f1bfcaSBin Meng /* Test whether a character is in the RX buffer */ 1776209e14cSJingchang Lu static int lpuart32_serial_tstc(void) 1786209e14cSJingchang Lu { 1796209e14cSJingchang Lu if ((in_be32(&base->water) >> 24) == 0) 1806209e14cSJingchang Lu return 0; 1816209e14cSJingchang Lu 1826209e14cSJingchang Lu return 1; 1836209e14cSJingchang Lu } 1846209e14cSJingchang Lu 1856209e14cSJingchang Lu /* 1866209e14cSJingchang Lu * Initialise the serial port with the given baudrate. The settings 1876209e14cSJingchang Lu * are always 8 data bits, no parity, 1 stop bit, no start bits. 1886209e14cSJingchang Lu */ 1896209e14cSJingchang Lu static int lpuart32_serial_init(void) 1906209e14cSJingchang Lu { 1916209e14cSJingchang Lu u8 ctrl; 1926209e14cSJingchang Lu 1936209e14cSJingchang Lu ctrl = in_be32(&base->ctrl); 1946209e14cSJingchang Lu ctrl &= ~CTRL_RE; 1956209e14cSJingchang Lu ctrl &= ~CTRL_TE; 1966209e14cSJingchang Lu out_be32(&base->ctrl, ctrl); 1976209e14cSJingchang Lu 1986209e14cSJingchang Lu out_be32(&base->modir, 0); 1996209e14cSJingchang Lu out_be32(&base->fifo, ~(FIFO_TXFE | FIFO_RXFE)); 2006209e14cSJingchang Lu 2016209e14cSJingchang Lu out_be32(&base->match, 0); 2026209e14cSJingchang Lu 203*47f1bfcaSBin Meng /* provide data bits, parity, stop bit, etc */ 2046209e14cSJingchang Lu serial_setbrg(); 2056209e14cSJingchang Lu 2066209e14cSJingchang Lu out_be32(&base->ctrl, CTRL_RE | CTRL_TE); 2076209e14cSJingchang Lu 2086209e14cSJingchang Lu return 0; 2096209e14cSJingchang Lu } 2106209e14cSJingchang Lu 2116209e14cSJingchang Lu static struct serial_device lpuart32_serial_drv = { 2126209e14cSJingchang Lu .name = "lpuart32_serial", 2136209e14cSJingchang Lu .start = lpuart32_serial_init, 2146209e14cSJingchang Lu .stop = NULL, 2156209e14cSJingchang Lu .setbrg = lpuart32_serial_setbrg, 2166209e14cSJingchang Lu .putc = lpuart32_serial_putc, 2176209e14cSJingchang Lu .puts = default_serial_puts, 2186209e14cSJingchang Lu .getc = lpuart32_serial_getc, 2196209e14cSJingchang Lu .tstc = lpuart32_serial_tstc, 2206209e14cSJingchang Lu }; 2216209e14cSJingchang Lu #endif 222427eba70SAlison Wang 223427eba70SAlison Wang void lpuart_serial_initialize(void) 224427eba70SAlison Wang { 2256209e14cSJingchang Lu #ifdef CONFIG_LPUART_32B_REG 2266209e14cSJingchang Lu serial_register(&lpuart32_serial_drv); 2276209e14cSJingchang Lu #else 228427eba70SAlison Wang serial_register(&lpuart_serial_drv); 2296209e14cSJingchang Lu #endif 230427eba70SAlison Wang } 231427eba70SAlison Wang 232427eba70SAlison Wang __weak struct serial_device *default_serial_console(void) 233427eba70SAlison Wang { 2346209e14cSJingchang Lu #ifdef CONFIG_LPUART_32B_REG 2356209e14cSJingchang Lu return &lpuart32_serial_drv; 2366209e14cSJingchang Lu #else 237427eba70SAlison Wang return &lpuart_serial_drv; 2386209e14cSJingchang Lu #endif 239427eba70SAlison Wang } 240