summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/common.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-10-19 21:09:29 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:36:32 -0800
commit115467a62b551ffd17a9cb992113f0bf55f8c15b (patch)
tree976f551de87a3d1fb3b423878b2cfc1ac71ede8c /arch/arm/mach-tegra/common.c
parent020d1849c0d6ec848e579e6330e36602557ba7e5 (diff)
[ARM] tegra: Add function to copy framebuffer contents
Due to conflicting restrictions on the location of the framebuffer between the bootloader and the protected aperture, the framebuffer is likely to need to be moved during boot. This patch provides tegra_move_framebuffer, which can handle move the framebuffer from lowmem, highmem, or unmapped memory into unmapped memory. Change-Id: Ic37e5e337cd3129065fe56fd7777a86d06ad69ac
Diffstat (limited to 'arch/arm/mach-tegra/common.c')
-rw-r--r--arch/arm/mach-tegra/common.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index b490e42ef8ab..ca8c232a88b8 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/highmem.h>
#include <linux/memblock.h>
#include <asm/hardware/cache-l2x0.h>
@@ -173,6 +174,58 @@ void __init tegra_protected_aperture_init(unsigned long aperture)
#endif
}
+/*
+ * Due to conflicting restrictions on the placement of the framebuffer,
+ * the bootloader is likely to leave the framebuffer pointed at a location
+ * in memory that is outside the grhost aperture. This function will move
+ * the framebuffer contents from a physical address that is anywher (lowmem,
+ * highmem, or outside the memory map) to a physical address that is outside
+ * the memory map.
+ */
+void tegra_move_framebuffer(unsigned long to, unsigned long from,
+ unsigned long size)
+{
+ struct page *page;
+ void __iomem *to_io;
+ void *from_virt;
+ unsigned long i;
+
+ BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to);
+ BUG_ON(PAGE_ALIGN(from) != from);
+ BUG_ON(PAGE_ALIGN(size) != size);
+
+ to_io = ioremap(to, size);
+ if (!to_io) {
+ pr_err("%s: Failed to map target framebuffer\n", __func__);
+ return;
+ }
+
+ pr_info("%s: %08lx %08lx %08lx %p", __func__, to, from, size, to_io);
+
+ if (pfn_valid(page_to_pfn(phys_to_page(from)))) {
+ for (i = 0 ; i < size; i += PAGE_SIZE) {
+ page = phys_to_page(from + i);
+ from_virt = kmap(page);
+ memcpy_toio(to_io + i, from_virt, PAGE_SIZE);
+ kunmap(page);
+ }
+ } else {
+ void __iomem *from_io = ioremap(from, size);
+ if (!from_io) {
+ pr_err("%s: Failed to map source framebuffer\n",
+ __func__);
+ goto out;
+ }
+
+ for (i = 0; i < size; i+= 4)
+ writel(readl(from_io + i), to_io + i);
+
+ iounmap(from_io);
+ }
+out:
+ iounmap(to_io);
+}
+
void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
unsigned long fb2_size)
{