OMAP: Add VRAM manager
authorTomi Valkeinen <tomi.valkeinen@nokia.com>
Fri, 7 Aug 2009 09:01:55 +0000 (12:01 +0300)
committerTomi Valkeinen <tomi.valkeinen@nokia.com>
Wed, 9 Dec 2009 10:04:33 +0000 (12:04 +0200)
Add a Video RAM manager for OMAP 2 and 3 platforms. VRAM manager is used
to allocate large continuous blocks of SDRAM or SRAM. The features VRAM
manager has that are missing from dma_alloc_* functions are:

- Support for OMAP2's SRAM
- Allocate without ioremapping
- Allocate at defined physical addresses
- Allows larger VRAM area and larger allocations

The upcoming DSS2 uses VRAM manager.

VRAM area size can be defined in kernel config, board file or with
kernel boot parameters. Board file definition overrides kernel config,
and boot parameter overrides kernel config and board file.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
arch/arm/mach-omap2/io.c
arch/arm/plat-omap/include/plat/vram.h [new file with mode: 0644]
arch/arm/plat-omap/sram.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/omap2/Kconfig [new file with mode: 0644]
drivers/video/omap2/Makefile [new file with mode: 0644]
drivers/video/omap2/vram.c [new file with mode: 0644]

index 9f22c201ef9d9b885c508fded7dc7df72738561c..6a4d8e468703a691a1d348b4355ade8b6e36b252 100644 (file)
@@ -33,6 +33,7 @@
 #include <plat/sdrc.h>
 #include <plat/gpmc.h>
 #include <plat/serial.h>
+#include <plat/vram.h>
 
 #ifndef CONFIG_ARCH_OMAP4      /* FIXME: Remove this once clkdev is ready */
 #include "clock.h"
@@ -264,6 +265,7 @@ void __init omap2_map_common_io(void)
        omap2_check_revision();
        omap_sram_init();
        omapfb_reserve_sdram();
+       omap_vram_reserve_sdram();
 }
 
 /*
diff --git a/arch/arm/plat-omap/include/plat/vram.h b/arch/arm/plat-omap/include/plat/vram.h
new file mode 100644 (file)
index 0000000..edd4987
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * VRAM manager for OMAP
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __OMAP_VRAM_H__
+#define __OMAP_VRAM_H__
+
+#include <linux/types.h>
+
+#define OMAP_VRAM_MEMTYPE_SDRAM                0
+#define OMAP_VRAM_MEMTYPE_SRAM         1
+#define OMAP_VRAM_MEMTYPE_MAX          1
+
+extern int omap_vram_add_region(unsigned long paddr, size_t size);
+extern int omap_vram_free(unsigned long paddr, size_t size);
+extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr);
+extern int omap_vram_reserve(unsigned long paddr, size_t size);
+extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
+               unsigned long *largest_free_block);
+
+#ifdef CONFIG_OMAP2_VRAM
+extern void omap_vram_set_sdram_vram(u32 size, u32 start);
+extern void omap_vram_set_sram_vram(u32 size, u32 start);
+
+extern void omap_vram_reserve_sdram(void);
+extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
+                                           unsigned long sram_vstart,
+                                           unsigned long sram_size,
+                                           unsigned long pstart_avail,
+                                           unsigned long size_avail);
+#else
+static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
+static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
+
+static inline void omap_vram_reserve_sdram(void) { }
+static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
+                                           unsigned long sram_vstart,
+                                           unsigned long sram_size,
+                                           unsigned long pstart_avail,
+                                           unsigned long size_avail)
+{
+       return 0;
+}
+#endif
+
+#endif
index 3e923668778d8aa88018837e39ae5ca9586226fb..ad2bf07d30b548ffabd4ff1c6ac44d910d1ba664 100644 (file)
@@ -28,6 +28,7 @@
 #include <plat/sram.h>
 #include <plat/board.h>
 #include <plat/cpu.h>
+#include <plat/vram.h>
 
 #include <plat/control.h>
 
@@ -185,6 +186,13 @@ void __init omap_detect_sram(void)
                                       omap_sram_start + SRAM_BOOTLOADER_SZ,
                                       omap_sram_size - SRAM_BOOTLOADER_SZ);
        omap_sram_size -= reserved;
+
+       reserved = omap_vram_reserve_sram(omap_sram_start, omap_sram_base,
+                       omap_sram_size,
+                       omap_sram_start + SRAM_BOOTLOADER_SZ,
+                       omap_sram_size - SRAM_BOOTLOADER_SZ);
+       omap_sram_size -= reserved;
+
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 }
 
index 6b89eb55ed327d56bf16e02d58db2aebac611d67..8be523f9a3f720e19686115887f6e1e9b6f80d31 100644 (file)
@@ -2164,6 +2164,7 @@ config FB_BROADSHEET
          a bridge adapter.
 
 source "drivers/video/omap/Kconfig"
+source "drivers/video/omap2/Kconfig"
 
 source "drivers/video/backlight/Kconfig"
 source "drivers/video/display/Kconfig"
index 80232e124889b1eab9b26f4869c3a1a010aaade4..0f8da331ba0f7d76a80eb98216d95f4aa9ea6284 100644 (file)
@@ -124,6 +124,7 @@ obj-$(CONFIG_FB_SM501)            += sm501fb.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)          += sh_mobile_lcdcfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
+obj-y                             += omap2/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)         += mb862xx/
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
new file mode 100644 (file)
index 0000000..7a6c4c9
--- /dev/null
@@ -0,0 +1,2 @@
+config OMAP2_VRAM
+       bool
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
new file mode 100644 (file)
index 0000000..7fdf7bd
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_OMAP2_VRAM) += vram.o
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
new file mode 100644 (file)
index 0000000..55a4de5
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * VRAM manager for OMAP
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include <linux/bootmem.h>
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+
+#include <asm/setup.h>
+
+#include <plat/sram.h>
+#include <plat/vram.h>
+#include <plat/dma.h>
+
+#ifdef DEBUG
+#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
+#else
+#define DBG(format, ...)
+#endif
+
+#define OMAP2_SRAM_START               0x40200000
+/* Maximum size, in reality this is smaller if SRAM is partially locked. */
+#define OMAP2_SRAM_SIZE                        0xa0000         /* 640k */
+
+/* postponed regions are used to temporarily store region information at boot
+ * time when we cannot yet allocate the region list */
+#define MAX_POSTPONED_REGIONS 10
+
+static bool vram_initialized;
+static int postponed_cnt;
+static struct {
+       unsigned long paddr;
+       size_t size;
+} postponed_regions[MAX_POSTPONED_REGIONS];
+
+struct vram_alloc {
+       struct list_head list;
+       unsigned long paddr;
+       unsigned pages;
+};
+
+struct vram_region {
+       struct list_head list;
+       struct list_head alloc_list;
+       unsigned long paddr;
+       unsigned pages;
+};
+
+static DEFINE_MUTEX(region_mutex);
+static LIST_HEAD(region_list);
+
+static inline int region_mem_type(unsigned long paddr)
+{
+       if (paddr >= OMAP2_SRAM_START &&
+           paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
+               return OMAP_VRAM_MEMTYPE_SRAM;
+       else
+               return OMAP_VRAM_MEMTYPE_SDRAM;
+}
+
+static struct vram_region *omap_vram_create_region(unsigned long paddr,
+               unsigned pages)
+{
+       struct vram_region *rm;
+
+       rm = kzalloc(sizeof(*rm), GFP_KERNEL);
+
+       if (rm) {
+               INIT_LIST_HEAD(&rm->alloc_list);
+               rm->paddr = paddr;
+               rm->pages = pages;
+       }
+
+       return rm;
+}
+
+#if 0
+static void omap_vram_free_region(struct vram_region *vr)
+{
+       list_del(&vr->list);
+       kfree(vr);
+}
+#endif
+
+static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
+               unsigned long paddr, unsigned pages)
+{
+       struct vram_alloc *va;
+       struct vram_alloc *new;
+
+       new = kzalloc(sizeof(*va), GFP_KERNEL);
+
+       if (!new)
+               return NULL;
+
+       new->paddr = paddr;
+       new->pages = pages;
+
+       list_for_each_entry(va, &vr->alloc_list, list) {
+               if (va->paddr > new->paddr)
+                       break;
+       }
+
+       list_add_tail(&new->list, &va->list);
+
+       return new;
+}
+
+static void omap_vram_free_allocation(struct vram_alloc *va)
+{
+       list_del(&va->list);
+       kfree(va);
+}
+
+int omap_vram_add_region(unsigned long paddr, size_t size)
+{
+       struct vram_region *rm;
+       unsigned pages;
+
+       if (vram_initialized) {
+               DBG("adding region paddr %08lx size %d\n",
+                               paddr, size);
+
+               size &= PAGE_MASK;
+               pages = size >> PAGE_SHIFT;
+
+               rm = omap_vram_create_region(paddr, pages);
+               if (rm == NULL)
+                       return -ENOMEM;
+
+               list_add(&rm->list, &region_list);
+       } else {
+               if (postponed_cnt == MAX_POSTPONED_REGIONS)
+                       return -ENOMEM;
+
+               postponed_regions[postponed_cnt].paddr = paddr;
+               postponed_regions[postponed_cnt].size = size;
+
+               ++postponed_cnt;
+       }
+       return 0;
+}
+
+int omap_vram_free(unsigned long paddr, size_t size)
+{
+       struct vram_region *rm;
+       struct vram_alloc *alloc;
+       unsigned start, end;
+
+       DBG("free mem paddr %08lx size %d\n", paddr, size);
+
+       size = PAGE_ALIGN(size);
+
+       mutex_lock(&region_mutex);
+
+       list_for_each_entry(rm, &region_list, list) {
+               list_for_each_entry(alloc, &rm->alloc_list, list) {
+                       start = alloc->paddr;
+                       end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
+
+                       if (start >= paddr && end < paddr + size)
+                               goto found;
+               }
+       }
+
+       mutex_unlock(&region_mutex);
+       return -EINVAL;
+
+found:
+       omap_vram_free_allocation(alloc);
+
+       mutex_unlock(&region_mutex);
+       return 0;
+}
+EXPORT_SYMBOL(omap_vram_free);
+
+static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
+{
+       struct vram_region *rm;
+       struct vram_alloc *alloc;
+       size_t size;
+
+       size = pages << PAGE_SHIFT;
+
+       list_for_each_entry(rm, &region_list, list) {
+               unsigned long start, end;
+
+               DBG("checking region %lx %d\n", rm->paddr, rm->pages);
+
+               if (region_mem_type(rm->paddr) != region_mem_type(paddr))
+                       continue;
+
+               start = rm->paddr;
+               end = start + (rm->pages << PAGE_SHIFT) - 1;
+               if (start > paddr || end < paddr + size - 1)
+                       continue;
+
+               DBG("block ok, checking allocs\n");
+
+               list_for_each_entry(alloc, &rm->alloc_list, list) {
+                       end = alloc->paddr - 1;
+
+                       if (start <= paddr && end >= paddr + size - 1)
+                               goto found;
+
+                       start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
+               }
+
+               end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
+
+               if (!(start <= paddr && end >= paddr + size - 1))
+                       continue;
+found:
+               DBG("found area start %lx, end %lx\n", start, end);
+
+               if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
+                       return -ENOMEM;
+
+               return 0;
+       }
+
+       return -ENOMEM;
+}
+
+int omap_vram_reserve(unsigned long paddr, size_t size)
+{
+       unsigned pages;
+       int r;
+
+       DBG("reserve mem paddr %08lx size %d\n", paddr, size);
+
+       size = PAGE_ALIGN(size);
+       pages = size >> PAGE_SHIFT;
+
+       mutex_lock(&region_mutex);
+
+       r = _omap_vram_reserve(paddr, pages);
+
+       mutex_unlock(&region_mutex);
+
+       return r;
+}
+EXPORT_SYMBOL(omap_vram_reserve);
+
+static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct completion *compl = data;
+       complete(compl);
+}
+
+static int _omap_vram_clear(u32 paddr, unsigned pages)
+{
+       struct completion compl;
+       unsigned elem_count;
+       unsigned frame_count;
+       int r;
+       int lch;
+
+       init_completion(&compl);
+
+       r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
+                       _omap_vram_dma_cb,
+                       &compl, &lch);
+       if (r) {
+               pr_err("VRAM: request_dma failed for memory clear\n");
+               return -EBUSY;
+       }
+
+       elem_count = pages * PAGE_SIZE / 4;
+       frame_count = 1;
+
+       omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
+                       elem_count, frame_count,
+                       OMAP_DMA_SYNC_ELEMENT,
+                       0, 0);
+
+       omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
+                       paddr, 0, 0);
+
+       omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
+
+       omap_start_dma(lch);
+
+       if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
+               omap_stop_dma(lch);
+               pr_err("VRAM: dma timeout while clearing memory\n");
+               r = -EIO;
+               goto err;
+       }
+
+       r = 0;
+err:
+       omap_free_dma(lch);
+
+       return r;
+}
+
+static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
+{
+       struct vram_region *rm;
+       struct vram_alloc *alloc;
+
+       list_for_each_entry(rm, &region_list, list) {
+               unsigned long start, end;
+
+               DBG("checking region %lx %d\n", rm->paddr, rm->pages);
+
+               if (region_mem_type(rm->paddr) != mtype)
+                       continue;
+
+               start = rm->paddr;
+
+               list_for_each_entry(alloc, &rm->alloc_list, list) {
+                       end = alloc->paddr;
+
+                       if (end - start >= pages << PAGE_SHIFT)
+                               goto found;
+
+                       start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
+               }
+
+               end = rm->paddr + (rm->pages << PAGE_SHIFT);
+found:
+               if (end - start < pages << PAGE_SHIFT)
+                       continue;
+
+               DBG("found %lx, end %lx\n", start, end);
+
+               alloc = omap_vram_create_allocation(rm, start, pages);
+               if (alloc == NULL)
+                       return -ENOMEM;
+
+               *paddr = start;
+
+               _omap_vram_clear(start, pages);
+
+               return 0;
+       }
+
+       return -ENOMEM;
+}
+
+int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
+{
+       unsigned pages;
+       int r;
+
+       BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
+
+       DBG("alloc mem type %d size %d\n", mtype, size);
+
+       size = PAGE_ALIGN(size);
+       pages = size >> PAGE_SHIFT;
+
+       mutex_lock(&region_mutex);
+
+       r = _omap_vram_alloc(mtype, pages, paddr);
+
+       mutex_unlock(&region_mutex);
+
+       return r;
+}
+EXPORT_SYMBOL(omap_vram_alloc);
+
+void omap_vram_get_info(unsigned long *vram,
+               unsigned long *free_vram,
+               unsigned long *largest_free_block)
+{
+       struct vram_region *vr;
+       struct vram_alloc *va;
+
+       *vram = 0;
+       *free_vram = 0;
+       *largest_free_block = 0;
+
+       mutex_lock(&region_mutex);
+
+       list_for_each_entry(vr, &region_list, list) {
+               unsigned free;
+               unsigned long pa;
+
+               pa = vr->paddr;
+               *vram += vr->pages << PAGE_SHIFT;
+
+               list_for_each_entry(va, &vr->alloc_list, list) {
+                       free = va->paddr - pa;
+                       *free_vram += free;
+                       if (free > *largest_free_block)
+                               *largest_free_block = free;
+                       pa = va->paddr + (va->pages << PAGE_SHIFT);
+               }
+
+               free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
+               *free_vram += free;
+               if (free > *largest_free_block)
+                       *largest_free_block = free;
+       }
+
+       mutex_unlock(&region_mutex);
+}
+EXPORT_SYMBOL(omap_vram_get_info);
+
+#if defined(CONFIG_DEBUG_FS)
+static int vram_debug_show(struct seq_file *s, void *unused)
+{
+       struct vram_region *vr;
+       struct vram_alloc *va;
+       unsigned size;
+
+       mutex_lock(&region_mutex);
+
+       list_for_each_entry(vr, &region_list, list) {
+               size = vr->pages << PAGE_SHIFT;
+               seq_printf(s, "%08lx-%08lx (%d bytes)\n",
+                               vr->paddr, vr->paddr + size - 1,
+                               size);
+
+               list_for_each_entry(va, &vr->alloc_list, list) {
+                       size = va->pages << PAGE_SHIFT;
+                       seq_printf(s, "    %08lx-%08lx (%d bytes)\n",
+                                       va->paddr, va->paddr + size - 1,
+                                       size);
+               }
+       }
+
+       mutex_unlock(&region_mutex);
+
+       return 0;
+}
+
+static int vram_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, vram_debug_show, inode->i_private);
+}
+
+static const struct file_operations vram_debug_fops = {
+       .open           = vram_debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init omap_vram_create_debugfs(void)
+{
+       struct dentry *d;
+
+       d = debugfs_create_file("vram", S_IRUGO, NULL,
+                       NULL, &vram_debug_fops);
+       if (IS_ERR(d))
+               return PTR_ERR(d);
+
+       return 0;
+}
+#endif
+
+static __init int omap_vram_init(void)
+{
+       int i;
+
+       vram_initialized = 1;
+
+       for (i = 0; i < postponed_cnt; i++)
+               omap_vram_add_region(postponed_regions[i].paddr,
+                               postponed_regions[i].size);
+
+#ifdef CONFIG_DEBUG_FS
+       if (omap_vram_create_debugfs())
+               pr_err("VRAM: Failed to create debugfs file\n");
+#endif
+
+       return 0;
+}
+
+arch_initcall(omap_vram_init);
+
+/* boottime vram alloc stuff */
+
+/* set from board file */
+static u32 omap_vram_sram_start __initdata;
+static u32 omap_vram_sram_size __initdata;
+
+/* set from board file */
+static u32 omap_vram_sdram_start __initdata;
+static u32 omap_vram_sdram_size __initdata;
+
+/* set from kernel cmdline */
+static u32 omap_vram_def_sdram_size __initdata;
+static u32 omap_vram_def_sdram_start __initdata;
+
+static void __init omap_vram_early_vram(char **p)
+{
+       omap_vram_def_sdram_size = memparse(*p, p);
+       if (**p == ',')
+               omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
+}
+__early_param("vram=", omap_vram_early_vram);
+
+/*
+ * Called from map_io. We need to call to this early enough so that we
+ * can reserve the fixed SDRAM regions before VM could get hold of them.
+ */
+void __init omap_vram_reserve_sdram(void)
+{
+       struct bootmem_data     *bdata;
+       unsigned long           sdram_start, sdram_size;
+       u32 paddr;
+       u32 size = 0;
+
+       /* cmdline arg overrides the board file definition */
+       if (omap_vram_def_sdram_size) {
+               size = omap_vram_def_sdram_size;
+               paddr = omap_vram_def_sdram_start;
+       }
+
+       if (!size) {
+               size = omap_vram_sdram_size;
+               paddr = omap_vram_sdram_start;
+       }
+
+#ifdef CONFIG_OMAP2_VRAM_SIZE
+       if (!size) {
+               size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
+               paddr = 0;
+       }
+#endif
+
+       if (!size)
+               return;
+
+       size = PAGE_ALIGN(size);
+
+       bdata = NODE_DATA(0)->bdata;
+       sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
+       sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
+
+       if (paddr) {
+               if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
+                               paddr + size > sdram_start + sdram_size) {
+                       pr_err("Illegal SDRAM region for VRAM\n");
+                       return;
+               }
+
+               if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
+                       pr_err("FB: failed to reserve VRAM\n");
+                       return;
+               }
+       } else {
+               if (size > sdram_size) {
+                       pr_err("Illegal SDRAM size for VRAM\n");
+                       return;
+               }
+
+               paddr = virt_to_phys(alloc_bootmem_pages(size));
+               BUG_ON(paddr & ~PAGE_MASK);
+       }
+
+       omap_vram_add_region(paddr, size);
+
+       pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
+}
+
+/*
+ * Called at sram init time, before anything is pushed to the SRAM stack.
+ * Because of the stack scheme, we will allocate everything from the
+ * start of the lowest address region to the end of SRAM. This will also
+ * include padding for page alignment and possible holes between regions.
+ *
+ * As opposed to the SDRAM case, we'll also do any dynamic allocations at
+ * this point, since the driver built as a module would have problem with
+ * freeing / reallocating the regions.
+ */
+unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
+                                 unsigned long sram_vstart,
+                                 unsigned long sram_size,
+                                 unsigned long pstart_avail,
+                                 unsigned long size_avail)
+{
+       unsigned long                   pend_avail;
+       unsigned long                   reserved;
+       u32 paddr;
+       u32 size;
+
+       paddr = omap_vram_sram_start;
+       size = omap_vram_sram_size;
+
+       if (!size)
+               return 0;
+
+       reserved = 0;
+       pend_avail = pstart_avail + size_avail;
+
+       if (!paddr) {
+               /* Dynamic allocation */
+               if ((size_avail & PAGE_MASK) < size) {
+                       pr_err("Not enough SRAM for VRAM\n");
+                       return 0;
+               }
+               size_avail = (size_avail - size) & PAGE_MASK;
+               paddr = pstart_avail + size_avail;
+       }
+
+       if (paddr < sram_pstart ||
+                       paddr + size > sram_pstart + sram_size) {
+               pr_err("Illegal SRAM region for VRAM\n");
+               return 0;
+       }
+
+       /* Reserve everything above the start of the region. */
+       if (pend_avail - paddr > reserved)
+               reserved = pend_avail - paddr;
+       size_avail = pend_avail - reserved - pstart_avail;
+
+       omap_vram_add_region(paddr, size);
+
+       if (reserved)
+               pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
+
+       return reserved;
+}
+
+void __init omap_vram_set_sdram_vram(u32 size, u32 start)
+{
+       omap_vram_sdram_start = start;
+       omap_vram_sdram_size = size;
+}
+
+void __init omap_vram_set_sram_vram(u32 size, u32 start)
+{
+       omap_vram_sram_start = start;
+       omap_vram_sram_size = size;
+}