From: Zeng Zhaoming Date: Fri, 24 Jun 2011 01:02:35 +0000 (+0800) Subject: ENGR00139229-3 tty:early-uart: add early-uart support for i.mx platforms X-Git-Tag: v3.0.35-fsl~2312 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=f8354992f88678c32f96700881f247e3989e4cf5;p=karo-tx-linux.git ENGR00139229-3 tty:early-uart: add early-uart support for i.mx platforms Add early uart support for i.MX platforms Signed-off-by: Anson Huang Signed-off-by: Zeng Zhaoming Reviewed-by: Robby Cai --- diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index cb2628fee4c7..5f9f9e69a4dc 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -96,3 +96,4 @@ obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o +obj-$(CONFIG_SERIAL_IMX_CONSOLE) += mxc_uart_early.o diff --git a/drivers/tty/serial/mxc_uart_early.c b/drivers/tty/serial/mxc_uart_early.c new file mode 100644 index 000000000000..46ca2b1817ac --- /dev/null +++ b/drivers/tty/serial/mxc_uart_early.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + * @file drivers/serial/mxc_uart_early.c + * + * @brief Driver for the Freescale Semiconductor MXC serial ports based on + * drivers/char/8250_early.c, + * Copyright 2004 Hewlett-Packard Development Company, + * L.P.by Bjorn Helgaasby. + * + * Early serial console for MXC UARTS. + * + * This is for use before the serial driver has initialized, in + * particular, before the UARTs have been discovered and named. + * Instead of specifying the console device as, e.g., "ttymxc0", + * we locate the device directly by its MMIO or I/O port address. + * + * The user can specify the device directly, e.g., + * console=mxcuart,0x43f90000,115200n8 + * or platform code can call early_uart_console_init() to set + * the early UART device. + * + * After the normal serial driver starts, we try to locate the + * matching ttymxc device and start a console there. + */ + +/* + * Include Files + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct mxc_early_uart_device { + struct uart_port port; + char options[16]; /* e.g., 115200n8 */ + unsigned int baud; + struct clk *clk; +}; +static struct mxc_early_uart_device mxc_early_device __initdata; + +/* + * Write out a character once the UART is ready + */ +static void __init mxcuart_console_write_char(struct uart_port *port, int ch) +{ + unsigned int status; + + do { + status = readl(port->membase + MXC_UARTUSR2); + } while ((status & MXC_UARTUSR2_TXFE) == 0); + writel(ch, port->membase + MXC_UARTUTXD); +} + +/*! + * This function is called to write the console messages through the UART port. + * + * @param co the console structure + * @param s the log message to be written to the UART + * @param count length of the message + */ +void __init early_mxcuart_console_write(struct console *co, const char *s, + u_int count) +{ + struct uart_port *port = &mxc_early_device.port; + unsigned int status, oldcr1, oldcr2, oldcr3, cr2, cr3; + + /* + * First save the control registers and then disable the interrupts + */ + oldcr1 = readl(port->membase + MXC_UARTUCR1); + oldcr2 = readl(port->membase + MXC_UARTUCR2); + oldcr3 = readl(port->membase + MXC_UARTUCR3); + cr2 = + oldcr2 & ~(MXC_UARTUCR2_ATEN | MXC_UARTUCR2_RTSEN | + MXC_UARTUCR2_ESCI); + cr3 = + oldcr3 & ~(MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI | + MXC_UARTUCR3_DTRDEN); + writel(MXC_UARTUCR1_UARTEN, port->membase + MXC_UARTUCR1); + writel(cr2, port->membase + MXC_UARTUCR2); + writel(cr3, port->membase + MXC_UARTUCR3); + + /* Transmit string */ + uart_console_write(port, s, count, mxcuart_console_write_char); + + /* + * Finally, wait for the transmitter to become empty + */ + do { + status = readl(port->membase + MXC_UARTUSR2); + } while (!(status & MXC_UARTUSR2_TXDC)); + + /* + * Restore the control registers + */ + writel(oldcr1, port->membase + MXC_UARTUCR1); + writel(oldcr2, port->membase + MXC_UARTUCR2); + writel(oldcr3, port->membase + MXC_UARTUCR3); +} + +static unsigned int __init probe_baud(struct uart_port *port) +{ + /* FIXME Return Default Baud Rate */ + return 115200; +} + +static int __init mxc_early_uart_setup(struct console *console, char *options) +{ + struct mxc_early_uart_device *device = &mxc_early_device; + struct uart_port *port = &device->port; + int length; + + if (device->port.membase || device->port.iobase) + return -ENODEV; + + /* Enable Early MXC UART Clock */ + clk_enable(device->clk); + + port->uartclk = 5600000; + port->iotype = UPIO_MEM; + port->membase = ioremap(port->mapbase, SZ_4K); + + if (options) { + device->baud = simple_strtoul(options, NULL, 0); + length = min(strlen(options), sizeof(device->options)); + strncpy(device->options, options, length); + } else { + device->baud = probe_baud(port); + snprintf(device->options, sizeof(device->options), "%u", + device->baud); + } + printk(KERN_INFO + "MXC_Early serial console at MMIO 0x%x (options '%s')\n", + port->mapbase, device->options); + return 0; +} + +static struct console mxc_early_uart_console __initdata = { + .name = "ttymxc", + .write = early_mxcuart_console_write, + .setup = mxc_early_uart_setup, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1, +}; + +int __init mxc_early_serial_console_init(unsigned long base, struct clk *clk) +{ + mxc_early_device.clk = clk; + mxc_early_device.port.mapbase = base; + + register_console(&mxc_early_uart_console); + return 0; +} + +int __init mxc_early_uart_console_disable(void) +{ + struct mxc_early_uart_device *device = &mxc_early_device; + struct uart_port *port = &device->port; + + if (mxc_early_uart_console.index >= 0) { + iounmap(port->membase); + clk_disable(device->clk); + clk_put(device->clk); + } + return 0; +} +late_initcall(mxc_early_uart_console_disable);