diff options
Diffstat (limited to 'arch/arm/mach-omap2/serial.c')
| -rw-r--r-- | arch/arm/mach-omap2/serial.c | 123 | 
1 files changed, 93 insertions, 30 deletions
| diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 54dfeb5d5667..19805a7de06c 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -24,15 +24,16 @@  #include <linux/clk.h>  #include <linux/io.h> -#include <mach/common.h> -#include <mach/board.h> -#include <mach/clock.h> -#include <mach/control.h> +#include <plat/common.h> +#include <plat/board.h> +#include <plat/clock.h> +#include <plat/control.h>  #include "prm.h"  #include "pm.h"  #include "prm-regbits-34xx.h" +#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV	0x52  #define UART_OMAP_WER		0x17	/* Wake-up enable register */  #define DEFAULT_TIMEOUT (5 * HZ) @@ -73,7 +74,6 @@ static LIST_HEAD(uart_list);  static struct plat_serial8250_port serial_platform_data0[] = {  	{ -		.membase	= OMAP2_IO_ADDRESS(OMAP_UART1_BASE),  		.mapbase	= OMAP_UART1_BASE,  		.irq		= 72,  		.flags		= UPF_BOOT_AUTOCONF, @@ -87,7 +87,6 @@ static struct plat_serial8250_port serial_platform_data0[] = {  static struct plat_serial8250_port serial_platform_data1[] = {  	{ -		.membase	= OMAP2_IO_ADDRESS(OMAP_UART2_BASE),  		.mapbase	= OMAP_UART2_BASE,  		.irq		= 73,  		.flags		= UPF_BOOT_AUTOCONF, @@ -101,7 +100,6 @@ static struct plat_serial8250_port serial_platform_data1[] = {  static struct plat_serial8250_port serial_platform_data2[] = {  	{ -		.membase	= OMAP2_IO_ADDRESS(OMAP_UART3_BASE),  		.mapbase	= OMAP_UART3_BASE,  		.irq		= 74,  		.flags		= UPF_BOOT_AUTOCONF, @@ -116,7 +114,6 @@ static struct plat_serial8250_port serial_platform_data2[] = {  #ifdef CONFIG_ARCH_OMAP4  static struct plat_serial8250_port serial_platform_data3[] = {  	{ -		.membase	= OMAP2_IO_ADDRESS(OMAP_UART4_BASE),  		.mapbase	= OMAP_UART4_BASE,  		.irq		= 70,  		.flags		= UPF_BOOT_AUTOCONF, @@ -159,8 +156,6 @@ static inline void __init omap_uart_reset(struct omap_uart_state *uart)  #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) -static int enable_off_mode; /* to be removed by full off-mode patches */ -  static void omap_uart_save_context(struct omap_uart_state *uart)  {  	u16 lcr = 0; @@ -539,7 +534,7 @@ static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}  #define DEV_CREATE_FILE(dev, attr)  #endif /* CONFIG_PM */ -static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = { +static struct omap_uart_state omap_uart[] = {  	{  		.pdev = {  			.name			= "serial8250", @@ -578,6 +573,23 @@ static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = {  #endif  }; +/* + * Override the default 8250 read handler: mem_serial_in() + * Empty RX fifo read causes an abort on omap3630 and omap4 + * This function makes sure that an empty rx fifo is not read on these silicons + * (OMAP1/2/3430 are not affected) + */ +static unsigned int serial_in_override(struct uart_port *up, int offset) +{ +	if (UART_RX == offset) { +		unsigned int lsr; +		lsr = serial_read_reg(omap_uart[up->line].p, UART_LSR); +		if (!(lsr & UART_LSR_DR)) +			return -EPERM; +	} +	return serial_read_reg(omap_uart[up->line].p, offset); +} +  void __init omap_serial_early_init(void)  {  	int i; @@ -589,12 +601,22 @@ void __init omap_serial_early_init(void)  	 * if not needed.  	 */ -	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { +	for (i = 0; i < ARRAY_SIZE(omap_uart); i++) {  		struct omap_uart_state *uart = &omap_uart[i];  		struct platform_device *pdev = &uart->pdev;  		struct device *dev = &pdev->dev;  		struct plat_serial8250_port *p = dev->platform_data; +		/* +		 * Module 4KB + L4 interconnect 4KB +		 * Static mapping, never released +		 */ +		p->membase = ioremap(p->mapbase, SZ_8K); +		if (!p->membase) { +			printk(KERN_ERR "ioremap failed for uart%i\n", i + 1); +			continue; +		} +  		sprintf(name, "uart%d_ick", i+1);  		uart->ick = clk_get(NULL, name);  		if (IS_ERR(uart->ick)) { @@ -618,33 +640,74 @@ void __init omap_serial_early_init(void)  		uart->num = i;  		p->private_data = uart;  		uart->p = p; -		list_add_tail(&uart->node, &uart_list);  		if (cpu_is_omap44xx())  			p->irq += 32; - -		omap_uart_enable_clocks(uart);  	}  } -void __init omap_serial_init(void) +/** + * omap_serial_init_port() - initialize single serial port + * @port: serial port number (0-3) + * + * This function initialies serial driver for given @port only. + * Platforms can call this function instead of omap_serial_init() + * if they don't plan to use all available UARTs as serial ports. + * + * Don't mix calls to omap_serial_init_port() and omap_serial_init(), + * use only one of the two. + */ +void __init omap_serial_init_port(int port)  { -	int i; +	struct omap_uart_state *uart; +	struct platform_device *pdev; +	struct device *dev; -	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { -		struct omap_uart_state *uart = &omap_uart[i]; -		struct platform_device *pdev = &uart->pdev; -		struct device *dev = &pdev->dev; +	BUG_ON(port < 0); +	BUG_ON(port >= ARRAY_SIZE(omap_uart)); -		omap_uart_reset(uart); -		omap_uart_idle_init(uart); +	uart = &omap_uart[port]; +	pdev = &uart->pdev; +	dev = &pdev->dev; -		if (WARN_ON(platform_device_register(pdev))) -			continue; -		if ((cpu_is_omap34xx() && uart->padconf) || -		    (uart->wk_en && uart->wk_mask)) { -			device_init_wakeup(dev, true); -			DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout); -		} +	omap_uart_enable_clocks(uart); + +	omap_uart_reset(uart); +	omap_uart_idle_init(uart); + +	list_add_tail(&uart->node, &uart_list); + +	if (WARN_ON(platform_device_register(pdev))) +		return; + +	if ((cpu_is_omap34xx() && uart->padconf) || +	    (uart->wk_en && uart->wk_mask)) { +		device_init_wakeup(dev, true); +		DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);  	} + +		/* omap44xx: Never read empty UART fifo +		 * omap3xxx: Never read empty UART fifo on UARTs +		 * with IP rev >=0x52 +		 */ +		if (cpu_is_omap44xx()) +			uart->p->serial_in = serial_in_override; +		else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF) +				>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV) +			uart->p->serial_in = serial_in_override; +} + +/** + * omap_serial_init() - intialize all supported serial ports + * + * Initializes all available UARTs as serial ports. Platforms + * can call this function when they want to have default behaviour + * for serial ports (e.g initialize them all as serial ports). + */ +void __init omap_serial_init(void) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(omap_uart); i++) +		omap_serial_init_port(i);  } | 
