Commit aeb81be7 authored by Hugo Villeneuve's avatar Hugo Villeneuve Committed by Kevin Hilman

ARM: Davinci: UART: Fix bug with serial ports registration

This bug occurs when the davinci serial code tries to register UART(X) when
UART(X-1) or UART(X-2) is not enabled in the structure uart_config of the board
setup code:

This works: .enabled_uarts = (1 << 0)
This works: .enabled_uarts = (1 << 0) | (1 << 1)
This works: .enabled_uarts = (1 << 0) | (1 << 1) | | (1 << 2)
This fails: .enabled_uarts = (1 << 1)
This fails: .enabled_uarts = (1 << 1) | (1 << 2)
This fails: .enabled_uarts = (1 << 0) | (1 << 2)

The bug is triggered by the fact that the 8250 serial driver stops parsing the
serial_platform_data structure as soon as it sees a zero flags entry. Thus the
davinci serial registration code (serial.c) must <pack> the serial_platform_data
structure and only clear the flags entry when there is no more devices following.

Tested on DM6446 and DM355 custom boards.
Signed-off-by: default avatarHugo Villeneuve <hugo@hugovil.com>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent 03218638
...@@ -49,36 +49,24 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, ...@@ -49,36 +49,24 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
__raw_writel(value, IO_ADDRESS(p->mapbase) + offset); __raw_writel(value, IO_ADDRESS(p->mapbase) + offset);
} }
static struct plat_serial8250_port serial_platform_data[] = { static const resource_size_t serial_mapbase[] = {
{ DAVINCI_UART0_BASE,
.mapbase = DAVINCI_UART0_BASE, DAVINCI_UART1_BASE,
.irq = IRQ_UARTINT0, DAVINCI_UART2_BASE,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | };
UPF_IOREMAP,
.iotype = UPIO_MEM, static const unsigned int serial_irq[] = {
.regshift = 2, IRQ_UARTINT0,
}, IRQ_UARTINT1,
{ IRQ_UARTINT2,
.mapbase = DAVINCI_UART1_BASE,
.irq = IRQ_UARTINT1,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
UPF_IOREMAP,
.iotype = UPIO_MEM,
.regshift = 2,
},
{
.mapbase = DAVINCI_UART2_BASE,
.irq = IRQ_UARTINT2,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
UPF_IOREMAP,
.iotype = UPIO_MEM,
.regshift = 2,
},
{
.flags = 0
},
}; };
/*
* The additional entry is present because the list must be terminated with a
* zero flags entry.
*/
static struct plat_serial8250_port serial_platform_data[DAVINCI_MAX_NR_UARTS + 1];
static struct platform_device serial_device = { static struct platform_device serial_device = {
.name = "serial8250", .name = "serial8250",
.id = PLAT8250_DEV_PLATFORM, .id = PLAT8250_DEV_PLATFORM,
...@@ -112,29 +100,31 @@ void __init davinci_serial_init(struct davinci_uart_config *info) ...@@ -112,29 +100,31 @@ void __init davinci_serial_init(struct davinci_uart_config *info)
char name[16]; char name[16];
struct clk *uart_clk; struct clk *uart_clk;
struct device *dev = &serial_device.dev; struct device *dev = &serial_device.dev;
struct plat_serial8250_port *p = serial_platform_data;
/* /*
* Make sure the serial ports are muxed on at this point. * Make sure the serial ports are muxed on at this point.
* You have to mux them off in device drivers later on * You have to mux them off in device drivers later on if not needed.
* if not needed.
*/ */
for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) { for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) {
struct plat_serial8250_port *p = serial_platform_data + i; if (!(info->enabled_uarts & (1 << i)))
if (!(info->enabled_uarts & (1 << i))) {
p->flags = 0;
continue; continue;
}
if (cpu_is_davinci_dm646x()) { /* fill-in common members */
p->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP;
p->regshift = 2;
if (cpu_is_davinci_dm646x())
p->iotype = UPIO_MEM32; p->iotype = UPIO_MEM32;
} else
p->iotype = UPIO_MEM;
if (cpu_is_davinci_dm355()) { if (cpu_is_davinci_dm355() && (i == 2)) {
if (i == 2) { p->mapbase = DM355_UART2_BASE;
p->mapbase = (unsigned long)DM355_UART2_BASE;
p->irq = IRQ_DM355_UARTINT2; p->irq = IRQ_DM355_UARTINT2;
} } else {
p->mapbase = serial_mapbase[i];
p->irq = serial_irq[i];
} }
sprintf(name, "uart%d", i); sprintf(name, "uart%d", i);
...@@ -147,7 +137,12 @@ void __init davinci_serial_init(struct davinci_uart_config *info) ...@@ -147,7 +137,12 @@ void __init davinci_serial_init(struct davinci_uart_config *info)
clk_enable(uart_clk); clk_enable(uart_clk);
davinci_serial_reset(p); davinci_serial_reset(p);
} }
p++; /* Point to next entry */
} }
/* Terminate the list with a zero flags entry */
p->flags = 0;
} }
static int __init davinci_init(void) static int __init davinci_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment