aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/fimg2d4x-exynos4
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/samsung/fimg2d4x-exynos4')
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h12
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c9
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c17
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c87
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h10
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c64
-rw-r--r--drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c64
7 files changed, 239 insertions, 24 deletions
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h
index 2d8f3b7..3bbb194 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h
@@ -41,6 +41,15 @@
#define FIMG2D_BITBLT_SYNC _IOW(FIMG2D_IOCTL_MAGIC, 1, int)
#define FIMG2D_BITBLT_VERSION _IOR(FIMG2D_IOCTL_MAGIC, 2, struct fimg2d_version)
#define FIMG2D_BITBLT_SECURE _IOW(FIMG2D_IOCTL_MAGIC, 3, unsigned int)
+#define FIMG2D_BITBLT_DBUFFER _IOW(FIMG2D_IOCTL_MAGIC, 4, unsigned long)
+
+#define SEQ_NO_BLT_SKIA 0x00000001
+#define SEQ_NO_BLT_HWC_SEC 0x00000012
+#define SEQ_NO_BLT_HWC_NOSEC 0x00000002
+#define SEQ_NO_BLT_HDMI 0x00000003
+#define SEQ_NO_CMD_SECURE_ON 0x10000001
+#define SEQ_NO_CMD_SECURE_OFF 0x10000002
+#define SEQ_NO_CMD_SET_DBUFFER 0x10000003
struct fimg2d_version {
unsigned int hw;
@@ -429,6 +438,7 @@ struct fimg2d_context {
atomic_t ncmd;
wait_queue_head_t wait_q;
struct fimg2d_perf perf[MAX_PERF_DESCS];
+ unsigned long *pgd_clone;
};
/**
@@ -486,6 +496,8 @@ struct fimg2d_control {
int irq;
unsigned int secure;
+ unsigned int dbuffer_addr;
+ unsigned long fault_addr;
atomic_t nctx;
atomic_t busy;
atomic_t active;
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c
index fc6016c..1eb8d63 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c
@@ -83,7 +83,12 @@ void fimg2d4x_bitblt(struct fimg2d_control *info)
goto blitend;
if (cmd->image[IDST].addr.type != ADDR_PHYS) {
- pgd = (unsigned long *)ctx->mm->pgd;
+ if ((cmd->image[IDST].addr.type == ADDR_USER_CONTIG) ||
+ (cmd->image[ISRC].addr.type == ADDR_USER_CONTIG))
+ pgd = (unsigned long *)ctx->pgd_clone;
+ else
+ pgd = (unsigned long *)ctx->mm->pgd;
+
s5p_sysmmu_enable(info->dev, (unsigned long)virt_to_phys(pgd));
fimg2d_debug("sysmmu enable: pgd %p ctx %p seq_no(%u)\n",
pgd, ctx, cmd->seq_no);
@@ -98,6 +103,8 @@ void fimg2d4x_bitblt(struct fimg2d_control *info)
info->run(info);
fimg2d4x_blit_wait(info, cmd);
+ if (info->fault_addr)
+ fimg2d_mmutable_value_replace(cmd, info->fault_addr, 0);
#ifdef PERF_PROFILE
perf_end(cmd->ctx, PERF_BLIT);
#endif
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c
index 4eb4d04..7835dee 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c
@@ -16,6 +16,7 @@
#include "fimg2d.h"
#include "fimg2d4x.h"
#include "fimg2d_clk.h"
+#include "fimg2d_cache.h"
#define wr(d, a) writel((d), info->regs + (a))
#define rd(a) readl(info->regs + (a))
@@ -124,7 +125,13 @@ void fimg2d4x_set_src_image(struct fimg2d_control *info, struct fimg2d_image *s)
{
unsigned long cfg;
- wr(FIMG2D_ADDR(s->addr.start), FIMG2D_SRC_BASE_ADDR_REG);
+ if ((s->addr.type == ADDR_USER_CONTIG) && (s->order < ARGB_ORDER_END)) {
+ wr(FIMG2D_ADDR(GET_MVA(s->addr.start, s->plane2.start)),
+ FIMG2D_SRC_BASE_ADDR_REG);
+ } else {
+ wr(FIMG2D_ADDR(s->addr.start), FIMG2D_SRC_BASE_ADDR_REG);
+ }
+
wr(FIMG2D_STRIDE(s->stride), FIMG2D_SRC_STRIDE_REG);
if (s->order < ARGB_ORDER_END) { /* argb */
@@ -173,7 +180,13 @@ void fimg2d4x_set_dst_image(struct fimg2d_control *info, struct fimg2d_image *d)
{
unsigned long cfg;
- wr(FIMG2D_ADDR(d->addr.start), FIMG2D_DST_BASE_ADDR_REG);
+ if ((d->addr.type == ADDR_USER_CONTIG) && (d->order < ARGB_ORDER_END)) {
+ wr(FIMG2D_ADDR(GET_MVA(d->addr.start, d->plane2.start)),
+ FIMG2D_DST_BASE_ADDR_REG);
+ } else {
+ wr(FIMG2D_ADDR(d->addr.start), FIMG2D_DST_BASE_ADDR_REG);
+ }
+
wr(FIMG2D_STRIDE(d->stride), FIMG2D_DST_STRIDE_REG);
if (d->order < ARGB_ORDER_END) {
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);
+}
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h
index f337ea5..7699a37 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h
@@ -18,6 +18,10 @@
#define L1_CACHE_SIZE SZ_64K
#define L2_CACHE_SIZE SZ_1M
#define LINE_FLUSH_THRESHOLD SZ_1K
+#define L1_DESCRIPTOR_SIZE SZ_16K
+
+/* Get Modified virtual address to use 1MB page */
+#define GET_MVA(V, P) ((V & 0xfff00000) | (P & 0x000fffff))
/**
* cache_opr - [kernel] cache operation mode
@@ -92,5 +96,11 @@ static inline void fimg2d_dma_unsync_inner(unsigned long addr, size_t size, int
}
void fimg2d_clean_outer_pagetable(struct mm_struct *mm, unsigned long addr, size_t size);
+void fimg2d_clean_outer_pagetable_clone(unsigned long *pgd_clone, unsigned long addr, size_t size);
+void fimg2d_clean_inner_pagetable_clone(unsigned long *pgd_clone, unsigned long addr, size_t size);
void fimg2d_dma_sync_outer(struct mm_struct *mm, unsigned long addr, size_t size, enum cache_opr opr);
enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long addr, size_t size);
+enum pt_status fimg2d_migrate_pagetable(unsigned long *pgd_clone,
+ unsigned long vaddr, unsigned long paddr, size_t size);
+void fimg2d_mmutable_value_replace(struct fimg2d_bltcmd *cmd,
+ unsigned long fault_addr, unsigned long l2d_value);
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c
index eaa722c..0c6c590 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c
@@ -130,6 +130,7 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd)
enum pt_status pt;
int clip_x, clip_w, clip_h, y, dir, i;
unsigned long clip_start;
+ unsigned long modified_addr;
clp = &p->clipping;
@@ -155,6 +156,13 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd)
pt = fimg2d_check_pagetable(mm, c->addr, c->size);
if (pt == PT_FAULT)
return -1;
+ } else if (img->addr.type == ADDR_USER_CONTIG) {
+ modified_addr = GET_MVA(img->addr.start, img->plane2.start);
+ pt = fimg2d_migrate_pagetable(cmd->ctx->pgd_clone,
+ modified_addr, img->plane2.start, img->height * img->stride);
+ if (pt != PT_NORMAL) {
+ return -1;
+ }
}
if (img->need_cacheopr && i != IMAGE_TMP) {
@@ -175,7 +183,25 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd)
c = &cmd->dma[i];
r = &img->rect;
- if (!img->addr.type || !c->cached)
+ if (!img->addr.type)
+ continue;
+
+ if ((cmd->image[IMAGE_SRC].addr.type == ADDR_USER_CONTIG) ||
+ (cmd->image[IMAGE_DST].addr.type == ADDR_USER_CONTIG)) {
+ if (img->addr.type == ADDR_USER_CONTIG) {
+ if (i == IMAGE_DST && clp->enable)
+ modified_addr = GET_MVA(img->addr.start, img->plane2.start) +
+ (img->stride * clp->y1);
+ else
+ modified_addr = GET_MVA(img->addr.start, img->plane2.start) +
+ (img->stride * r->y1);
+ } else {
+ modified_addr = c->addr;
+ }
+ fimg2d_clean_inner_pagetable_clone(cmd->ctx->pgd_clone, modified_addr, c->size);
+ }
+
+ if ( !c->cached)
continue;
if (i == IMAGE_DST)
@@ -226,8 +252,22 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd)
continue;
/* clean pagetable */
- if (img->addr.type == ADDR_USER)
+ if ((cmd->image[IMAGE_SRC].addr.type == ADDR_USER_CONTIG) ||
+ (cmd->image[IMAGE_DST].addr.type == ADDR_USER_CONTIG)) {
+ if (img->addr.type == ADDR_USER_CONTIG) {
+ if (i == IMAGE_DST && clp->enable)
+ modified_addr = GET_MVA(img->addr.start, img->plane2.start) +
+ (img->stride * clp->y1);
+ else
+ modified_addr = GET_MVA(img->addr.start, img->plane2.start) +
+ (img->stride * r->y1);
+ } else {
+ modified_addr = c->addr;
+ }
+ fimg2d_clean_outer_pagetable_clone(cmd->ctx->pgd_clone, modified_addr, c->size);
+ } else {
fimg2d_clean_outer_pagetable(mm, c->addr, c->size);
+ }
if (!c->cached)
continue;
@@ -275,14 +315,17 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx,
int i, ret;
struct fimg2d_image *buf[MAX_IMAGES] = image_table(blit);
struct fimg2d_bltcmd *cmd;
+ struct fimg2d_image *img;
- if ((blit->dst) && (type == ADDR_USER))
+ if ((blit->dst) && (type == ADDR_USER)
+ && (blit->seq_no == SEQ_NO_BLT_SKIA))
up_write(&page_alloc_slow_rwsem);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
- if ((blit->dst) && (type == ADDR_USER))
+ if ((blit->dst) && (type == ADDR_USER)
+ && (blit->seq_no == SEQ_NO_BLT_SKIA))
if (!down_write_trylock(&page_alloc_slow_rwsem))
return -EAGAIN;
return -ENOMEM;
@@ -294,7 +337,8 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx,
if (copy_from_user(&cmd->image[i], buf[i],
sizeof(struct fimg2d_image))) {
- if ((blit->dst) && (type == ADDR_USER))
+ if ((blit->dst) && (type == ADDR_USER)
+ && (blit->seq_no == SEQ_NO_BLT_SKIA))
if (!down_write_trylock(&page_alloc_slow_rwsem)) {
ret = -EAGAIN;
goto err_user;
@@ -304,7 +348,8 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx,
}
}
- if ((blit->dst) && (type == ADDR_USER))
+ if ((blit->dst) && (type == ADDR_USER)
+ && (blit->seq_no == SEQ_NO_BLT_SKIA))
if (!down_write_trylock(&page_alloc_slow_rwsem)) {
ret = -EAGAIN;
goto err_user;
@@ -329,6 +374,13 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx,
fimg2d_fixup_params(cmd);
+ for (i = 0; i < MAX_IMAGES; i++) {
+ img = &cmd->image[i];
+ if (img->addr.type == ADDR_USER_CONTIG) {
+ memcpy(cmd->ctx->pgd_clone, cmd->ctx->mm->pgd, L1_DESCRIPTOR_SIZE);
+ }
+ }
+
if (fimg2d_check_dma_sync(cmd)) {
ret = -EFAULT;
goto err_user;
diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c
index ed14901..84c7db5 100644
--- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c
+++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c
@@ -46,6 +46,8 @@
#define LV2_PT_MASK 0xff000
#define LV2_SHIFT 12
#define LV1_DESC_MASK 0x3
+#define LV2_VALUE_META 0xc7f
+#define LV2_VALUE_BASE_MASK 0xfff
static struct fimg2d_control *info;
@@ -116,7 +118,12 @@ static int fimg2d_sysmmu_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) +
((fault_addr & LV2_PT_MASK) >> LV2_SHIFT);
printk(KERN_ERR " Level 2 descriptor(0x%lx)\n", *lv2d);
- fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4);
+ if (*lv2d == 0) {
+ fimg2d_mmutable_value_replace(cmd, fault_addr,
+ (info->dbuffer_addr & ~LV2_VALUE_BASE_MASK) | LV2_VALUE_META);
+ info->fault_addr = fault_addr;
+ } else
+ fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4);
next:
return 0;
@@ -161,6 +168,8 @@ static int fimg2d_open(struct inode *inode, struct file *file)
ctx, (unsigned long *)ctx->mm->pgd,
(unsigned long *)init_mm.pgd);
+ ctx->pgd_clone = kzalloc(L1_DESCRIPTOR_SIZE, GFP_KERNEL);
+
fimg2d_add_context(info, ctx);
return 0;
}
@@ -178,6 +187,7 @@ static int fimg2d_release(struct inode *inode, struct file *file)
}
fimg2d_del_context(info, ctx);
+ kfree(ctx->pgd_clone);
kfree(ctx);
return 0;
}
@@ -223,7 +233,8 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
dev_lock(info->bus_dev, info->dev, 160160);
#endif
#endif
- if ((blit.dst) && (dst.addr.type == ADDR_USER))
+ if ((blit.dst) && (dst.addr.type == ADDR_USER)
+ && (blit.seq_no == SEQ_NO_BLT_SKIA))
if (!down_write_trylock(&page_alloc_slow_rwsem))
ret = -EAGAIN;
@@ -238,7 +249,9 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
perf_print(ctx, blit.seq_no);
perf_clear(ctx);
#endif
- if ((blit.dst) && (dst.addr.type == ADDR_USER) && ret != -EAGAIN)
+ if ((blit.dst) && (dst.addr.type == ADDR_USER)
+ && (blit.seq_no == SEQ_NO_BLT_SKIA)
+ && ret != -EAGAIN)
up_write(&page_alloc_slow_rwsem);
#ifdef CONFIG_BUSFREQ_OPP
@@ -246,6 +259,13 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
dev_unlock(info->bus_dev, info->dev);
#endif
#endif
+
+ if (info->fault_addr) {
+ printk(KERN_INFO "Return by G2D fault handler");
+ info->fault_addr = 0;
+ ret = -EFAULT;
+ }
+
break;
case FIMG2D_BITBLT_SYNC:
@@ -281,6 +301,17 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
+ case FIMG2D_BITBLT_DBUFFER:
+ if (copy_from_user(&info->dbuffer_addr,
+ (unsigned long *)arg,
+ sizeof(unsigned long))) {
+ printk(KERN_ERR
+ "[%s] failed to FIMG2D_BITBLT_DBUFFER: copy_from_user error\n\n",
+ __func__);
+ return -EFAULT;
+ }
+ break;
+
default:
printk(KERN_ERR "[%s] unknown ioctl\n", __func__);
ret = -EFAULT;
@@ -315,6 +346,7 @@ static int fimg2d_setup_controller(struct fimg2d_control *info)
atomic_set(&info->nctx, 0);
atomic_set(&info->active, 0);
info->secure = 0;
+ info->fault_addr = 0;
spin_lock_init(&info->bltlock);
@@ -384,12 +416,20 @@ static int fimg2d_probe(struct platform_device *pdev)
fimg2d_debug("device name: %s base address: 0x%lx\n",
pdev->name, (unsigned long)res->start);
+ /* Clock setup */
+ ret = fimg2d_clk_setup(info);
+ if (ret) {
+ printk(KERN_ERR "FIMG2D failed to setup clk\n");
+ ret = -ENOENT;
+ goto err_clk;
+ }
+
/* irq */
info->irq = platform_get_irq(pdev, 0);
if (!info->irq) {
printk(KERN_ERR "FIMG2D failed to get irq resource\n");
ret = -ENOENT;
- goto err_map;
+ goto err_irq;
}
fimg2d_debug("irq: %d\n", info->irq);
@@ -400,13 +440,6 @@ static int fimg2d_probe(struct platform_device *pdev)
goto err_irq;
}
- ret = fimg2d_clk_setup(info);
- if (ret) {
- printk(KERN_ERR "FIMG2D failed to setup clk\n");
- ret = -ENOENT;
- goto err_clk;
- }
-
#ifdef CONFIG_PM_RUNTIME
pm_runtime_enable(info->dev);
fimg2d_debug("enable runtime pm\n");
@@ -432,19 +465,20 @@ static int fimg2d_probe(struct platform_device *pdev)
return 0;
err_reg:
- fimg2d_clk_release(info);
-
-err_clk:
free_irq(info->irq, NULL);
err_irq:
+ fimg2d_clk_release(info);
+
+err_clk:
iounmap(info->regs);
err_map:
+ release_mem_region(res->start, resource_size(res));
kfree(info->mem);
err_region:
- release_resource(info->mem);
+ release_resource(res);
err_res:
destroy_workqueue(info->work_q);