aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c')
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c
index 43489e4..f5486b1 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c
@@ -114,8 +114,48 @@ void fimg2d_clean_outer_pagetable(struct mm_struct *mm, unsigned long vaddr,
lv1++;
} while (lv1 != lv1end);
}
+
+void fimg2d_clean_outer_pagetable_clone(unsigned long *pgd_clone,
+ unsigned long vaddr, size_t size)
+{
+ unsigned long *pgd;
+ unsigned long *lv1, *lv1end;
+ unsigned long lv2pa;
+
+ pgd = (unsigned long *)pgd_clone;
+
+ lv1 = pgd + (vaddr >> LV1_SHIFT);
+ lv1end = pgd + ((vaddr + size + LV1_PT_SIZE-1) >> LV1_SHIFT);
+
+ /* clean level1 page table */
+ outer_clean_range(virt_to_phys(lv1), virt_to_phys(lv1end));
+
+ do {
+ /* if page size is 4KB, clean level2 page table entry */
+ if ((*lv1 & 0x3) == 0x1) {
+ lv2pa = *lv1 & ~LV2_BASE_MASK; /* lv2 pt base */
+ /* clean level2 page table */
+ outer_clean_range(lv2pa, lv2pa + LV2_PT_SIZE);
+ }
+ lv1++;
+ } while (lv1 != lv1end);
+}
#endif /* CONFIG_OUTER_CACHE */
+void fimg2d_clean_inner_pagetable_clone(unsigned long *pgd_clone,
+ unsigned long vaddr, size_t size)
+{
+ unsigned long *pgd;
+ unsigned long *lv1, *lv1end;
+
+ pgd = (unsigned long *)pgd_clone;
+
+ lv1 = pgd + (vaddr >> LV1_SHIFT);
+ lv1end = pgd + ((vaddr + size + LV1_PT_SIZE-1) >> LV1_SHIFT);
+ fimg2d_dma_sync_inner((unsigned long)lv1,
+ (unsigned int)lv1end - (unsigned int)lv1, DMA_TO_DEVICE);
+}
+
enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long vaddr,
size_t size)
{
@@ -166,3 +206,50 @@ enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long vaddr,
return PT_NORMAL;
}
+
+#define PT_NS 0x0 // Non Secure
+#define PT_AP 0x8c00 // Access permission
+#define PT_ENTRY 0x2 // 1MB Page
+
+enum pt_status fimg2d_migrate_pagetable(unsigned long *pgd_clone,
+ unsigned long vaddr, unsigned long paddr, size_t size)
+{
+ unsigned long *pgd;
+ unsigned long *lv1d;
+
+ pgd = (unsigned long *)pgd_clone;
+
+ size += vaddr & (SZ_1M - 1);
+ size = ALIGN(size, SZ_1M);
+
+ while ((long)size > 0) {
+ lv1d = pgd + (vaddr >> LV1_SHIFT);
+
+ *lv1d = (paddr & 0xfff00000) | PT_NS | PT_AP | PT_ENTRY;
+
+ vaddr += SZ_1M;
+ paddr += SZ_1M;
+ size -= SZ_1M;
+ }
+ return PT_NORMAL;
+}
+
+void fimg2d_mmutable_value_replace(struct fimg2d_bltcmd *cmd,
+ unsigned long fault_addr, unsigned long l2d_value)
+{
+ unsigned long *pgd;
+ unsigned long *lv1d, *lv2d;
+
+ pgd = (unsigned long *)cmd->ctx->mm->pgd;
+ lv1d = pgd + (fault_addr >> LV1_SHIFT);
+
+ lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) +
+ ((fault_addr & LV2_PT_MASK) >> LV2_SHIFT);
+
+ *lv2d = l2d_value;
+
+ flush_all_cpu_caches();
+ fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4);
+
+ printk(KERN_INFO "MMU Level2 value replaced [0x%lx]", l2d_value);
+}