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
committerColin Cross <ccross@android.com>2010-10-20 14:30:17 -0700
commit00eb0f29e9e3c9882b334a7fffa13f63085e8117 (patch)
tree87e90cae36fc57b3be7aedffdf6a97cd63c6844d /arch/arm/mach-tegra/common.c
parentbd5e7b5939316ebd8c063107b88cf89c53b37dc9 (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 28b1e9ae7396..09fdecfc2456 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>
@@ -144,6 +145,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)
{