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) 20*89e69fd4SStefan Agner #define CFIFO_TXFLUSH (1 << 7) 21*89e69fd4SStefan Agner #define CFIFO_RXFLUSH (1 << 6) 22*89e69fd4SStefan Agner #define SFIFO_RXOF (1 << 2) 23*89e69fd4SStefan Agner #define SFIFO_RXUF (1 << 0) 24427eba70SAlison Wang 25427eba70SAlison Wang DECLARE_GLOBAL_DATA_PTR; 26427eba70SAlison Wang 27427eba70SAlison Wang struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE; 28427eba70SAlison Wang 29427eba70SAlison Wang static void lpuart_serial_setbrg(void) 30427eba70SAlison Wang { 31427eba70SAlison Wang u32 clk = mxc_get_clock(MXC_UART_CLK); 32427eba70SAlison Wang u16 sbr; 33427eba70SAlison Wang 34427eba70SAlison Wang if (!gd->baudrate) 35427eba70SAlison Wang gd->baudrate = CONFIG_BAUDRATE; 36427eba70SAlison Wang 37427eba70SAlison Wang sbr = (u16)(clk / (16 * gd->baudrate)); 38427eba70SAlison Wang /* place adjustment later - n/32 BRFA */ 39427eba70SAlison Wang 40427eba70SAlison Wang __raw_writeb(sbr >> 8, &base->ubdh); 41427eba70SAlison Wang __raw_writeb(sbr & 0xff, &base->ubdl); 42427eba70SAlison Wang } 43427eba70SAlison Wang 44427eba70SAlison Wang static int lpuart_serial_getc(void) 45427eba70SAlison Wang { 46a3db78d8SStefan Agner while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR))) 47427eba70SAlison Wang WATCHDOG_RESET(); 48427eba70SAlison Wang 49a3db78d8SStefan Agner barrier(); 50427eba70SAlison Wang 51427eba70SAlison Wang return __raw_readb(&base->ud); 52427eba70SAlison Wang } 53427eba70SAlison Wang 54427eba70SAlison Wang static void lpuart_serial_putc(const char c) 55427eba70SAlison Wang { 56427eba70SAlison Wang if (c == '\n') 57427eba70SAlison Wang serial_putc('\r'); 58427eba70SAlison Wang 59427eba70SAlison Wang while (!(__raw_readb(&base->us1) & US1_TDRE)) 60427eba70SAlison Wang WATCHDOG_RESET(); 61427eba70SAlison Wang 62427eba70SAlison Wang __raw_writeb(c, &base->ud); 63427eba70SAlison Wang } 64427eba70SAlison Wang 65427eba70SAlison Wang /* 66427eba70SAlison Wang * Test whether a character is in the RX buffer 67427eba70SAlison Wang */ 68427eba70SAlison Wang static int lpuart_serial_tstc(void) 69427eba70SAlison Wang { 70427eba70SAlison Wang if (__raw_readb(&base->urcfifo) == 0) 71427eba70SAlison Wang return 0; 72427eba70SAlison Wang 73427eba70SAlison Wang return 1; 74427eba70SAlison Wang } 75427eba70SAlison Wang 76427eba70SAlison Wang /* 77427eba70SAlison Wang * Initialise the serial port with the given baudrate. The settings 78427eba70SAlison Wang * are always 8 data bits, no parity, 1 stop bit, no start bits. 79427eba70SAlison Wang */ 80427eba70SAlison Wang static int lpuart_serial_init(void) 81427eba70SAlison Wang { 82427eba70SAlison Wang u8 ctrl; 83427eba70SAlison Wang 84427eba70SAlison Wang ctrl = __raw_readb(&base->uc2); 85427eba70SAlison Wang ctrl &= ~UC2_RE; 86427eba70SAlison Wang ctrl &= ~UC2_TE; 87427eba70SAlison Wang __raw_writeb(ctrl, &base->uc2); 88427eba70SAlison Wang 89427eba70SAlison Wang __raw_writeb(0, &base->umodem); 90427eba70SAlison Wang __raw_writeb(0, &base->uc1); 91427eba70SAlison Wang 92*89e69fd4SStefan Agner /* Disable FIFO and flush buffer */ 93*89e69fd4SStefan Agner __raw_writeb(0x0, &base->upfifo); 94*89e69fd4SStefan Agner __raw_writeb(0x0, &base->utwfifo); 95*89e69fd4SStefan Agner __raw_writeb(0x1, &base->urwfifo); 96*89e69fd4SStefan Agner __raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo); 97*89e69fd4SStefan Agner 98427eba70SAlison Wang /* provide data bits, parity, stop bit, etc */ 99427eba70SAlison Wang 100427eba70SAlison Wang serial_setbrg(); 101427eba70SAlison Wang 102427eba70SAlison Wang __raw_writeb(UC2_RE | UC2_TE, &base->uc2); 103427eba70SAlison Wang 104427eba70SAlison Wang return 0; 105427eba70SAlison Wang } 106427eba70SAlison Wang 107427eba70SAlison Wang static struct serial_device lpuart_serial_drv = { 108427eba70SAlison Wang .name = "lpuart_serial", 109427eba70SAlison Wang .start = lpuart_serial_init, 110427eba70SAlison Wang .stop = NULL, 111427eba70SAlison Wang .setbrg = lpuart_serial_setbrg, 112427eba70SAlison Wang .putc = lpuart_serial_putc, 113427eba70SAlison Wang .puts = default_serial_puts, 114427eba70SAlison Wang .getc = lpuart_serial_getc, 115427eba70SAlison Wang .tstc = lpuart_serial_tstc, 116427eba70SAlison Wang }; 117427eba70SAlison Wang 118427eba70SAlison Wang void lpuart_serial_initialize(void) 119427eba70SAlison Wang { 120427eba70SAlison Wang serial_register(&lpuart_serial_drv); 121427eba70SAlison Wang } 122427eba70SAlison Wang 123427eba70SAlison Wang __weak struct serial_device *default_serial_console(void) 124427eba70SAlison Wang { 125427eba70SAlison Wang return &lpuart_serial_drv; 126427eba70SAlison Wang } 127