[ARM] tegra: Add function to copy framebuffer contents
authorColin Cross <ccross@android.com>
Wed, 20 Oct 2010 04:09:29 +0000 (21:09 -0700)
committerColin Cross <ccross@android.com>
Wed, 20 Oct 2010 21:30:17 +0000 (14:30 -0700)
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

arch/arm/mach-tegra/board.h
arch/arm/mach-tegra/common.c

index 086ec70c470d8da80f0df99db36e96e2cc506e2d..c47a21f712607b5e580b4b588124262c8b9b3682 100644 (file)
@@ -30,6 +30,8 @@ void __init tegra_init_clock(void);
 void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
        unsigned long fb2_size);
 void __init tegra_protected_aperture_init(unsigned long aperture);
+void tegra_move_framebuffer(unsigned long to, unsigned long from,
+       unsigned long size);
 
 extern unsigned long tegra_bootloader_fb_start;
 extern unsigned long tegra_bootloader_fb_size;
index 28b1e9ae7396d6b042c711fb73b891f4e96cc7d6..09fdecfc24561bf65e74b65b97903d7360d58bd3 100644 (file)
@@ -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)
 {