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: Hugo Villeneuve <[email protected]>
---
 arch/arm/mach-davinci/serial.c |   81 +++++++++++++++++++---------------------
 1 files changed, 38 insertions(+), 43 deletions(-)

diff --git a/arch/arm/mach-davinci/serial.c b/arch/arm/mach-davinci/serial.c
index 95c71b9..99102ac 100644
--- a/arch/arm/mach-davinci/serial.c
+++ b/arch/arm/mach-davinci/serial.c
@@ -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);
 }
 
-static struct plat_serial8250_port serial_platform_data[] = {
-       {
-               .mapbase        = DAVINCI_UART0_BASE,
-               .irq            = IRQ_UARTINT0,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
-                                 UPF_IOREMAP,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-       },
-       {
-               .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
-       },
+static const resource_size_t serial_mapbase[] = {
+       DAVINCI_UART0_BASE,
+       DAVINCI_UART1_BASE,
+       DAVINCI_UART2_BASE,
 };
 
+static const unsigned int serial_irq[] = {
+       IRQ_UARTINT0,
+       IRQ_UARTINT1,
+       IRQ_UARTINT2,
+};
+
+/*
+ * 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 = {
        .name                   = "serial8250",
        .id                     = PLAT8250_DEV_PLATFORM,
@@ -112,29 +100,31 @@ void __init davinci_serial_init(struct 
davinci_uart_config *info)
        char name[16];
        struct clk *uart_clk;
        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.
-        * You have to mux them off in device drivers later on
-        * if not needed.
+        * You have to mux them off in device drivers later on if not needed.
         */
        for (i = 0; i < DAVINCI_MAX_NR_UARTS; i++) {
-               struct plat_serial8250_port *p = serial_platform_data + i;
-
-               if (!(info->enabled_uarts & (1 << i))) {
-                       p->flags = 0;
+               if (!(info->enabled_uarts & (1 << i)))
                        continue;
-               }
 
-               if (cpu_is_davinci_dm646x()) {
-                       p->iotype = UPIO_MEM32;
-               }
+               /* fill-in common members */
+               p->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP;
+               p->regshift = 2;
 
-               if (cpu_is_davinci_dm355()) {
-                       if (i == 2) {
-                               p->mapbase = (unsigned long)DM355_UART2_BASE;
-                               p->irq = IRQ_DM355_UARTINT2;
-                       }
+               if (cpu_is_davinci_dm646x())
+                       p->iotype = UPIO_MEM32;
+               else
+                       p->iotype = UPIO_MEM;
+
+               if (cpu_is_davinci_dm355() && (i == 2)) {
+                       p->mapbase = DM355_UART2_BASE;
+                       p->irq = IRQ_DM355_UARTINT2;
+               } else {
+                       p->mapbase = serial_mapbase[i];
+                       p->irq = serial_irq[i];
                }
 
                sprintf(name, "uart%d", i);
@@ -147,7 +137,12 @@ void __init davinci_serial_init(struct davinci_uart_config 
*info)
                        clk_enable(uart_clk);
                        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)
-- 
1.5.4.5


_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to