+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 void omapfb_reserve_mem(void)
 {
        const struct omap_fbmem_config *fbmem_conf;
+       unsigned long total_size;
+       int i;
+
+       if (!omap_fb_sram_valid) {
+               /* FBMEM SRAM configuration was already found to be invalid.
+                * Ignore the whole configuration block. */
+               omapfb_config.mem_desc.region_cnt = 0;
+               return;
+       }
+
+       i = 0;
+       total_size = 0;
+       while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+                               struct omap_fbmem_config, i)) != NULL) {
+               unsigned long start;
+               unsigned long size;
 
-       omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
-       omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
-
-       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
-
-       if (fbmem_conf != NULL) {
-               /* indicate that the bootloader already initialized the
-                * fb device, so we'll skip that part in the fb driver
-                */
-               omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
-               omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
-               if (fbmem_conf->fb_sdram_size) {
-                       pr_info("Reserving %u bytes SDRAM for frame buffer\n",
-                               fbmem_conf->fb_sdram_size);
-                       reserve_bootmem(fbmem_conf->fb_sdram_start,
-                                       fbmem_conf->fb_sdram_size);
+               if (i == OMAPFB_PLANE_NUM) {
+                       printk(KERN_ERR "ignoring extra plane info\n");
+                       break;
                }
+               start = fbmem_conf->start;
+               size  = fbmem_conf->size;
+               omapfb_config.mem_desc.region[i].paddr = start;
+               omapfb_config.mem_desc.region[i].size = size;
+               if (omap_fb_sram_plane != i && start) {
+                       reserve_bootmem(start, size);
+                       total_size += size;
+               }
+               i++;
        }
+       omapfb_config.mem_desc.region_cnt = i;
+       if (total_size)
+               pr_info("Reserving %lu bytes SDRAM for frame buffer\n",
+                        total_size);
+
 }
 
 static inline int omap_init_fb(void)
 
 
 #define ROUND_DOWN(value,boundary)     ((value) & (~((boundary)-1)))
 
+static unsigned long omap_sram_start;
 static unsigned long omap_sram_base;
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
-unsigned long omap_fb_sram_start;
-unsigned long omap_fb_sram_size;
+int    omap_fb_sram_plane = -1;
+int    omap_fb_sram_valid;
 
 /* Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessable size for all device types is 2k. A GP
                return 1; /* assume locked with no PPA or security driver */
 }
 
-void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
-                     unsigned long *start, unsigned long *size)
+static int get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
+                             unsigned long *start, int *plane_idx)
 {
        const struct omap_fbmem_config *fbmem_conf;
-
-       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
-       if (fbmem_conf != NULL) {
-               *start = fbmem_conf->fb_sram_start;
-               *size = fbmem_conf->fb_sram_size;
-       } else {
-               *size = 0;
-               *start = 0;
+       unsigned long size = 0;
+       int i;
+
+       i = 0;
+       *start = 0;
+       *plane_idx = -1;
+       while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+                               struct omap_fbmem_config, i)) != NULL) {
+               u32 paddr, end;
+
+               paddr = fbmem_conf->start;
+               end = fbmem_conf->start + fbmem_conf->size;
+               if (paddr > omap_sram_start &&
+                   paddr < omap_sram_start + omap_sram_size) {
+                       if (*plane_idx != -1 || paddr < start_avail ||
+                           paddr == end ||
+                           end > start_avail + size_avail) {
+                               printk(KERN_ERR "invalid FB SRAM configuration");
+                               *start = 0;
+                               return -1;
+                       }
+                       *plane_idx = i;
+                       *start = fbmem_conf->start;
+                       size = fbmem_conf->size;
+               }
+               i++;
        }
 
-       if (*size && (
-           *start < start_avail ||
-           *start + *size > start_avail + size_avail)) {
-               printk(KERN_ERR "invalid FB SRAM configuration\n");
-               *start = start_avail;
-               *size = size_avail;
-       }
+       if (*plane_idx >= 0)
+               pr_info("Reserving %lu bytes SRAM frame buffer "
+                       "for plane %d\n", size, *plane_idx);
 
-       if (*size)
-               pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
+       return 0;
 }
 
 /*
  */
 void __init omap_detect_sram(void)
 {
-       unsigned long sram_start;
+       unsigned long fb_sram_start;
 
        if (cpu_is_omap24xx()) {
                if (is_sram_locked()) {
                        omap_sram_base = OMAP2_SRAM_PUB_VA;
-                       sram_start = OMAP2_SRAM_PUB_PA;
+                       omap_sram_start = OMAP2_SRAM_PUB_PA;
                        omap_sram_size = 0x800; /* 2K */
                } else {
                        omap_sram_base = OMAP2_SRAM_VA;
-                       sram_start = OMAP2_SRAM_PA;
+                       omap_sram_start = OMAP2_SRAM_PA;
                        if (cpu_is_omap242x())
                                omap_sram_size = 0xa0000; /* 640K */
                        else if (cpu_is_omap243x())
                }
        } else {
                omap_sram_base = OMAP1_SRAM_VA;
-               sram_start = OMAP1_SRAM_PA;
+               omap_sram_start = OMAP1_SRAM_PA;
 
                if (cpu_is_omap730())
                        omap_sram_size = 0x32000;       /* 200K */
                        omap_sram_size = 0x4000;
                }
        }
-       get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
-                        omap_sram_size - SRAM_BOOTLOADER_SZ,
-                        &omap_fb_sram_start, &omap_fb_sram_size);
-       if (omap_fb_sram_size)
-               omap_sram_size -= sram_start + omap_sram_size -
-                                 omap_fb_sram_start;
+       if (get_fb_sram_conf(omap_sram_start + SRAM_BOOTLOADER_SZ,
+                           omap_sram_size - SRAM_BOOTLOADER_SZ,
+                           &fb_sram_start, &omap_fb_sram_plane) == 0)
+               omap_fb_sram_valid = 1;
+       if (omap_fb_sram_valid && omap_fb_sram_plane >= 0)
+               omap_sram_size -= omap_sram_start + omap_sram_size -
+                                 fb_sram_start;
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 }