diff options
Diffstat (limited to 'recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP-Add-VRAM-manager.patch')
-rw-r--r-- | recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP-Add-VRAM-manager.patch | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP-Add-VRAM-manager.patch b/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP-Add-VRAM-manager.patch new file mode 100644 index 0000000000..13fe0b0234 --- /dev/null +++ b/recipes/linux/linux-omap-2.6.31/dss2/0004-OMAP-Add-VRAM-manager.patch @@ -0,0 +1,854 @@ +From cb8ce54283e64bd30636b7bcd2d7bb4e200825d2 Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen <tomi.valkeinen@nokia.com> +Date: Fri, 7 Aug 2009 12:01:55 +0300 +Subject: [PATCH 04/18] OMAP: Add VRAM manager + +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 | 2 + + arch/arm/plat-omap/include/mach/vram.h | 63 +++ + arch/arm/plat-omap/sram.c | 8 + + drivers/video/Kconfig | 1 + + drivers/video/Makefile | 1 + + drivers/video/omap2/Kconfig | 2 + + drivers/video/omap2/Makefile | 1 + + drivers/video/omap2/vram.c | 655 ++++++++++++++++++++++++++++++++ + 8 files changed, 733 insertions(+), 0 deletions(-) + create mode 100644 arch/arm/plat-omap/include/mach/vram.h + create mode 100644 drivers/video/omap2/Kconfig + create mode 100644 drivers/video/omap2/Makefile + create mode 100644 drivers/video/omap2/vram.c + +diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c +index 49199a3..f837063 100644 +--- a/arch/arm/mach-omap2/io.c ++++ b/arch/arm/mach-omap2/io.c +@@ -32,6 +32,7 @@ + #include <mach/sram.h> + #include <mach/sdrc.h> + #include <mach/gpmc.h> ++#include <mach/vram.h> + + #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */ + #include "clock.h" +@@ -240,6 +241,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/mach/vram.h b/arch/arm/plat-omap/include/mach/vram.h +new file mode 100644 +index 0000000..fe72f81 +--- /dev/null ++++ b/arch/arm/plat-omap/include/mach/vram.h +@@ -0,0 +1,63 @@ ++/* ++ * 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/autoconf.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 +diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c +index 5eae787..c9b89cd 100644 +--- a/arch/arm/plat-omap/sram.c ++++ b/arch/arm/plat-omap/sram.c +@@ -28,6 +28,7 @@ + #include <mach/sram.h> + #include <mach/board.h> + #include <mach/cpu.h> ++#include <mach/vram.h> + + #include <mach/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; + } + +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 3b54b39..e09367a 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -2149,6 +2149,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" +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index 01a819f..cc7f5c8 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -123,6 +123,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 +index 0000000..7a6c4c9 +--- /dev/null ++++ b/drivers/video/omap2/Kconfig +@@ -0,0 +1,2 @@ ++config OMAP2_VRAM ++ bool +diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile +new file mode 100644 +index 0000000..7fdf7bd +--- /dev/null ++++ b/drivers/video/omap2/Makefile +@@ -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 +index 0000000..634ce23 +--- /dev/null ++++ b/drivers/video/omap2/vram.c +@@ -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 <mach/sram.h> ++#include <mach/vram.h> ++#include <mach/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, ®ion_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(®ion_mutex); ++ ++ list_for_each_entry(rm, ®ion_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(®ion_mutex); ++ return -EINVAL; ++ ++found: ++ omap_vram_free_allocation(alloc); ++ ++ mutex_unlock(®ion_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, ®ion_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(®ion_mutex); ++ ++ r = _omap_vram_reserve(paddr, pages); ++ ++ mutex_unlock(®ion_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, ®ion_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(®ion_mutex); ++ ++ r = _omap_vram_alloc(mtype, pages, paddr); ++ ++ mutex_unlock(®ion_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(®ion_mutex); ++ ++ list_for_each_entry(vr, ®ion_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(®ion_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(®ion_mutex); ++ ++ list_for_each_entry(vr, ®ion_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(®ion_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; ++} +-- +1.6.2.4 + |