diff options
author | Frank Li <Frank.Li@freescale.com> | 2010-07-19 14:23:01 +0800 |
---|---|---|
committer | Frank Li <Frank.Li@freescale.com> | 2010-07-22 13:17:28 +0800 |
commit | 6135f6d8f5dcb9dd98a17145edb0be95dfd2500e (patch) | |
tree | 1779fbe144bd488abdc25de64cf75ebd9920b3f6 /drivers | |
parent | 233385b9265cb16bad197e166751a0d3da5eafba (diff) |
ENGR00125339-2 uart: application uart support console and early console
Add UART2 for mx23 EVK board. EVK board needs rework.
Add console support for application uart according to customer requirement
Signed-off-by: Frank Li <Frank.Li@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/Kconfig | 18 | ||||
-rw-r--r-- | drivers/serial/mxs-auart.c | 163 |
2 files changed, 181 insertions, 0 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 869337a7fd68..b41db4d22436 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -373,6 +373,24 @@ config SERIAL_MXS_AUART help Driver for Freescale i.MXS internal application serial port +config SERIAL_MXS_AUART_CONSOLE + bool "Support for console on i.MXS application serial port" + depends on SERIAL_MXS_AUART=y + select SERIAL_CORE_CONSOLE + ---help--- + Say Y here if you wish to use the i.MXS app serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySP1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + + config SERIAL_MXS_DUART_CONSOLE bool "Support for console on i.MXS debug serial port" depends on SERIAL_MXS_DUART=y diff --git a/drivers/serial/mxs-auart.c b/drivers/serial/mxs-auart.c index 0791af105f72..63d7d9128efc 100644 --- a/drivers/serial/mxs-auart.c +++ b/drivers/serial/mxs-auart.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/console.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/slab.h> @@ -47,6 +48,8 @@ #define MXS_AUART_MAJOR 242 #define MXS_AUART_RX_THRESHOLD 16 +static struct uart_driver auart_driver; + struct mxs_auart_port { struct uart_port port; @@ -785,7 +788,160 @@ static struct uart_ops mxs_auart_ops = { .config_port = mxs_auart_config_port, .verify_port = mxs_auart_verify_port, }; +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE +static struct mxs_auart_port auart_port[CONFIG_MXS_AUART_PORTS] = {}; + +static void +auart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port; + unsigned int status, old_cr; + int i; + + if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0) + return; + port = &auart_port[co->index].port; + + /* First save the CR then disable the interrupts */ + old_cr = __raw_readl(port->membase + HW_UARTAPP_CTRL2); + __raw_writel(BM_UARTAPP_CTRL2_UARTEN | BM_UARTAPP_CTRL2_TXE, + port->membase + HW_UARTAPP_CTRL2_SET); + + /* Now, do each character */ + for (i = 0; i < count; i++) { + do { + status = __raw_readl(port->membase + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_TXFF); + + __raw_writel(s[i], port->membase + HW_UARTAPP_DATA); + if (s[i] == '\n') { + do { + status = __raw_readl(port->membase + + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_TXFF); + __raw_writel('\r', port->membase + HW_UARTAPP_DATA); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = __raw_readl(port->membase + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_BUSY); + __raw_writel(old_cr, port->membase + HW_UARTAPP_CTRL2); +} + +static void __init +auart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (__raw_readl(port->membase + HW_UARTAPP_CTRL2) + & BM_UARTAPP_CTRL2_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = __raw_readl(port->membase + HW_UARTAPP_LINECTRL); + + *parity = 'n'; + if (lcr_h & BM_UARTAPP_LINECTRL_PEN) { + if (lcr_h & BM_UARTAPP_LINECTRL_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & BM_UARTAPP_LINECTRL_WLEN) + == BF_UARTAPP_LINECTRL_WLEN(2)) + *bits = 7; + else + *bits = 8; + + quot = (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL) + & BM_UARTAPP_LINECTRL_BAUD_DIVINT)) + >> (BP_UARTAPP_LINECTRL_BAUD_DIVINT - 6)) + | (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL) + & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC)) + >> BP_UARTAPP_LINECTRL_BAUD_DIVFRAC); + if (quot == 0) + quot = 1; + *baud = (port->uartclk << 2) / quot; + } +} + +static int __init auart_console_setup(struct console *co, char *options) +{ + struct mxs_auart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0) + return -EINVAL; + + port = &auart_port[co->index].port; + + if (port->port.membase == 0) { + if (cpu_is_mx23()) { + if (co->index == 1) { + port->port.membase = IO_ADDRESS(0x8006C000); + port->port.mapbase = 0x8006C000; + } else { + port->port.membase = IO_ADDRESS(0x8006E000); + port->port.mapbase = 0x8006E000; + } + } + + port->port.fifosize = 16; + port->port.ops = &mxs_auart_ops; + port->port.flags = ASYNC_BOOT_AUTOCONF; + port->port.line = 0; + } + mxs_auart_reset(port); + + __raw_writel(BM_UARTAPP_CTRL2_UARTEN, + port->port.membase + HW_UARTAPP_CTRL2_SET); + + if (port->clk == NULL || IS_ERR(port->clk)) { + port->clk = clk_get(NULL, "uart"); + if (port->clk == NULL || IS_ERR(port->clk)) + return -ENODEV; + port->port.uartclk = clk_get_rate(port->clk); + } + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + auart_console_get_options(port, &baud, &parity, &bits); + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console auart_console = { + .name = "ttySP", + .write = auart_console_write, + .device = uart_console_device, + .setup = auart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &auart_driver, +}; + +#ifdef CONFIG_MXS_EARLY_CONSOLE +static int __init auart_console_init(void) +{ + register_console(&auart_console); + return 0; +} + +console_initcall(auart_console_init); +#endif + +#endif static struct uart_driver auart_driver = { .owner = THIS_MODULE, .driver_name = "auart", @@ -793,6 +949,9 @@ static struct uart_driver auart_driver = { .major = MXS_AUART_MAJOR, .minor = 0, .nr = CONFIG_MXS_AUART_PORTS, +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE + .cons = &auart_console, +#endif }; static int __devinit mxs_auart_probe(struct platform_device *pdev) @@ -873,6 +1032,10 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE + memcpy(&auart_port[pdev->id], s, sizeof(struct mxs_auart_port)); +#endif + ret = uart_add_one_port(&auart_driver, &s->port); if (ret) goto out_free_clk; |