diff options
Diffstat (limited to 'drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c')
-rw-r--r-- | drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c | 87 |
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); +} |