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) 17427eba70SAlison Wang #define UC2_TE (1 << 3) 18427eba70SAlison Wang #define UC2_RE (1 << 2) 19427eba70SAlison Wang 20*6209e14cSJingchang Lu #define STAT_LBKDIF (1 << 31) 21*6209e14cSJingchang Lu #define STAT_RXEDGIF (1 << 30) 22*6209e14cSJingchang Lu #define STAT_TDRE (1 << 23) 23*6209e14cSJingchang Lu #define STAT_RDRF (1 << 21) 24*6209e14cSJingchang Lu #define STAT_IDLE (1 << 20) 25*6209e14cSJingchang Lu #define STAT_OR (1 << 19) 26*6209e14cSJingchang Lu #define STAT_NF (1 << 18) 27*6209e14cSJingchang Lu #define STAT_FE (1 << 17) 28*6209e14cSJingchang Lu #define STAT_PF (1 << 16) 29*6209e14cSJingchang Lu #define STAT_MA1F (1 << 15) 30*6209e14cSJingchang Lu #define STAT_MA2F (1 << 14) 31*6209e14cSJingchang Lu #define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \ 32*6209e14cSJingchang Lu STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F) 33*6209e14cSJingchang Lu 34*6209e14cSJingchang Lu #define CTRL_TE (1 << 19) 35*6209e14cSJingchang Lu #define CTRL_RE (1 << 18) 36*6209e14cSJingchang Lu 37*6209e14cSJingchang Lu #define FIFO_TXFE 0x80 38*6209e14cSJingchang Lu #define FIFO_RXFE 0x40 39*6209e14cSJingchang Lu 40*6209e14cSJingchang Lu #define WATER_TXWATER_OFF 1 41*6209e14cSJingchang Lu #define WATER_RXWATER_OFF 16 42*6209e14cSJingchang Lu 43427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 44427eba70SAlison Wang 45427eba70SAlison Wang struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE; 46427eba70SAlison Wang 47*6209e14cSJingchang Lu #ifndef CONFIG_LPUART_32B_REG 48427eba70SAlison Wang static void lpuart_serial_setbrg(void) 49427eba70SAlison Wang { 50427eba70SAlison Wang u32 clk = mxc_get_clock(MXC_UART_CLK); 51427eba70SAlison Wang u16 sbr; 52427eba70SAlison Wang 53427eba70SAlison Wang if (!gd->baudrate) 54427eba70SAlison Wang gd->baudrate = CONFIG_BAUDRATE; 55427eba70SAlison Wang 56427eba70SAlison Wang sbr = (u16)(clk / (16 * gd->baudrate)); 57427eba70SAlison Wang /* place adjustment later - n/32 BRFA */ 58427eba70SAlison Wang 59427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 60427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 61427eba70SAlison Wang } 62427eba70SAlison Wang 63427eba70SAlison Wang static int lpuart_serial_getc(void) 64427eba70SAlison Wang { 65427eba70SAlison Wang u8 status; 66427eba70SAlison Wang 67427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_RDRF)) 68427eba70SAlison Wang WATCHDOG_RESET(); 69427eba70SAlison Wang 70427eba70SAlison Wang status = __raw_readb(&base->us1); 71427eba70SAlison Wang status |= US1_RDRF; 72427eba70SAlison Wang __raw_writeb(status, &base->us1); 73427eba70SAlison Wang 74427eba70SAlison Wang return __raw_readb(&base->ud); 75427eba70SAlison Wang } 76427eba70SAlison Wang 77427eba70SAlison Wang static void lpuart_serial_putc(const char c) 78427eba70SAlison Wang { 79427eba70SAlison Wang if (c == '\n') 80427eba70SAlison Wang serial_putc('\r'); 81427eba70SAlison Wang 82427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 83427eba70SAlison Wang WATCHDOG_RESET(); 84427eba70SAlison Wang 85427eba70SAlison Wang __raw_writeb(c, &base->ud); 86427eba70SAlison Wang } 87427eba70SAlison Wang 88427eba70SAlison Wang /* 89427eba70SAlison Wang * Test whether a character is in the RX buffer 90427eba70SAlison Wang */ 91427eba70SAlison Wang static int lpuart_serial_tstc(void) 92427eba70SAlison Wang { 93427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 94427eba70SAlison Wang return 0; 95427eba70SAlison Wang 96427eba70SAlison Wang return 1; 97427eba70SAlison Wang } 98427eba70SAlison Wang 99427eba70SAlison Wang /* 100427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 101427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 102427eba70SAlison Wang */ 103427eba70SAlison Wang static int lpuart_serial_init(void) 104427eba70SAlison Wang { 105427eba70SAlison Wang u8 ctrl; 106427eba70SAlison Wang 107427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 108427eba70SAlison Wang ctrl &= ~UC2_RE; 109427eba70SAlison Wang ctrl &= ~UC2_TE; 110427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 111427eba70SAlison Wang 112427eba70SAlison Wang __raw_writeb(0, &base->umodem); 113427eba70SAlison Wang __raw_writeb(0, &base->uc1); 114427eba70SAlison Wang 115427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 116427eba70SAlison Wang 117427eba70SAlison Wang serial_setbrg(); 118427eba70SAlison Wang 119427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 120427eba70SAlison Wang 121427eba70SAlison Wang return 0; 122427eba70SAlison Wang } 123427eba70SAlison Wang 124427eba70SAlison Wang static struct serial_device lpuart_serial_drv = { 125427eba70SAlison Wang .name = "lpuart_serial", 126427eba70SAlison Wang .start = lpuart_serial_init, 127427eba70SAlison Wang .stop = NULL, 128427eba70SAlison Wang .setbrg = lpuart_serial_setbrg, 129427eba70SAlison Wang .putc = lpuart_serial_putc, 130427eba70SAlison Wang .puts = default_serial_puts, 131427eba70SAlison Wang .getc = lpuart_serial_getc, 132427eba70SAlison Wang .tstc = lpuart_serial_tstc, 133427eba70SAlison Wang }; 134*6209e14cSJingchang Lu #else 135*6209e14cSJingchang Lu static void lpuart32_serial_setbrg(void) 136*6209e14cSJingchang Lu { 137*6209e14cSJingchang Lu u32 clk = CONFIG_SYS_CLK_FREQ; 138*6209e14cSJingchang Lu u32 sbr; 139*6209e14cSJingchang Lu 140*6209e14cSJingchang Lu if (!gd->baudrate) 141*6209e14cSJingchang Lu gd->baudrate = CONFIG_BAUDRATE; 142*6209e14cSJingchang Lu 143*6209e14cSJingchang Lu sbr = (clk / (16 * gd->baudrate)); 144*6209e14cSJingchang Lu /* place adjustment later - n/32 BRFA */ 145*6209e14cSJingchang Lu 146*6209e14cSJingchang Lu out_be32(&base->baud, sbr); 147*6209e14cSJingchang Lu } 148*6209e14cSJingchang Lu 149*6209e14cSJingchang Lu static int lpuart32_serial_getc(void) 150*6209e14cSJingchang Lu { 151*6209e14cSJingchang Lu u32 stat; 152*6209e14cSJingchang Lu 153*6209e14cSJingchang Lu while (((stat = in_be32(&base->stat)) & STAT_RDRF) == 0) { 154*6209e14cSJingchang Lu out_be32(&base->stat, STAT_FLAGS); 155*6209e14cSJingchang Lu WATCHDOG_RESET(); 156*6209e14cSJingchang Lu } 157*6209e14cSJingchang Lu 158*6209e14cSJingchang Lu return in_be32(&base->data) & 0x3ff; 159*6209e14cSJingchang Lu } 160*6209e14cSJingchang Lu 161*6209e14cSJingchang Lu static void lpuart32_serial_putc(const char c) 162*6209e14cSJingchang Lu { 163*6209e14cSJingchang Lu if (c == '\n') 164*6209e14cSJingchang Lu serial_putc('\r'); 165*6209e14cSJingchang Lu 166*6209e14cSJingchang Lu while (!(in_be32(&base->stat) & STAT_TDRE)) 167*6209e14cSJingchang Lu WATCHDOG_RESET(); 168*6209e14cSJingchang Lu 169*6209e14cSJingchang Lu out_be32(&base->data, c); 170*6209e14cSJingchang Lu } 171*6209e14cSJingchang Lu 172*6209e14cSJingchang Lu /* 173*6209e14cSJingchang Lu * Test whether a character is in the RX buffer 174*6209e14cSJingchang Lu */ 175*6209e14cSJingchang Lu static int lpuart32_serial_tstc(void) 176*6209e14cSJingchang Lu { 177*6209e14cSJingchang Lu if ((in_be32(&base->water) >> 24) == 0) 178*6209e14cSJingchang Lu return 0; 179*6209e14cSJingchang Lu 180*6209e14cSJingchang Lu return 1; 181*6209e14cSJingchang Lu } 182*6209e14cSJingchang Lu 183*6209e14cSJingchang Lu /* 184*6209e14cSJingchang Lu * Initialise the serial port with the given baudrate. The settings 185*6209e14cSJingchang Lu * are always 8 data bits, no parity, 1 stop bit, no start bits. 186*6209e14cSJingchang Lu */ 187*6209e14cSJingchang Lu static int lpuart32_serial_init(void) 188*6209e14cSJingchang Lu { 189*6209e14cSJingchang Lu u8 ctrl; 190*6209e14cSJingchang Lu 191*6209e14cSJingchang Lu ctrl = in_be32(&base->ctrl); 192*6209e14cSJingchang Lu ctrl &= ~CTRL_RE; 193*6209e14cSJingchang Lu ctrl &= ~CTRL_TE; 194*6209e14cSJingchang Lu out_be32(&base->ctrl, ctrl); 195*6209e14cSJingchang Lu 196*6209e14cSJingchang Lu out_be32(&base->modir, 0); 197*6209e14cSJingchang Lu out_be32(&base->fifo, ~(FIFO_TXFE | FIFO_RXFE)); 198*6209e14cSJingchang Lu 199*6209e14cSJingchang Lu out_be32(&base->match, 0); 200*6209e14cSJingchang Lu /* provide data bits, parity, stop bit, etc */ 201*6209e14cSJingchang Lu 202*6209e14cSJingchang Lu serial_setbrg(); 203*6209e14cSJingchang Lu 204*6209e14cSJingchang Lu out_be32(&base->ctrl, CTRL_RE | CTRL_TE); 205*6209e14cSJingchang Lu 206*6209e14cSJingchang Lu return 0; 207*6209e14cSJingchang Lu } 208*6209e14cSJingchang Lu 209*6209e14cSJingchang Lu static struct serial_device lpuart32_serial_drv = { 210*6209e14cSJingchang Lu .name = "lpuart32_serial", 211*6209e14cSJingchang Lu .start = lpuart32_serial_init, 212*6209e14cSJingchang Lu .stop = NULL, 213*6209e14cSJingchang Lu .setbrg = lpuart32_serial_setbrg, 214*6209e14cSJingchang Lu .putc = lpuart32_serial_putc, 215*6209e14cSJingchang Lu .puts = default_serial_puts, 216*6209e14cSJingchang Lu .getc = lpuart32_serial_getc, 217*6209e14cSJingchang Lu .tstc = lpuart32_serial_tstc, 218*6209e14cSJingchang Lu }; 219*6209e14cSJingchang Lu #endif 220427eba70SAlison Wang 221427eba70SAlison Wang void lpuart_serial_initialize(void) 222427eba70SAlison Wang { 223*6209e14cSJingchang Lu #ifdef CONFIG_LPUART_32B_REG 224*6209e14cSJingchang Lu serial_register(&lpuart32_serial_drv); 225*6209e14cSJingchang Lu #else 226427eba70SAlison Wang serial_register(&lpuart_serial_drv); 227*6209e14cSJingchang Lu #endif 228427eba70SAlison Wang } 229427eba70SAlison Wang 230427eba70SAlison Wang __weak struct serial_device *default_serial_console(void) 231427eba70SAlison Wang { 232*6209e14cSJingchang Lu #ifdef CONFIG_LPUART_32B_REG 233*6209e14cSJingchang Lu return &lpuart32_serial_drv; 234*6209e14cSJingchang Lu #else 235427eba70SAlison Wang return &lpuart_serial_drv; 236*6209e14cSJingchang Lu #endif 237427eba70SAlison Wang } 238