video/rockchip: rga2: use axi safe reset
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rga2 / rga2_drv.c
index d8b5d90d70bba77f8cd971c5884c04b7738ecbc5..936411d895cda3f874e71dc814b114a5f5459c1f 100644 (file)
@@ -42,6 +42,9 @@
 #include <linux/wakelock.h>
 #include <linux/scatterlist.h>
 #include <linux/rockchip_ion.h>
+#include <linux/version.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-buf.h>
 
 #include "rga2.h"
 #include "rga2_reg_info.h"
@@ -56,7 +59,7 @@
 #define RGA2_TEST_FLUSH_TIME 0
 #define RGA2_INFO_BUS_ERROR 1
 #define RGA2_POWER_OFF_DELAY   4*HZ /* 4s */
-#define RGA2_TIMEOUT_DELAY     2*HZ /* 2s */
+#define RGA2_TIMEOUT_DELAY     (HZ / 10) /* 100ms */
 #define RGA2_MAJOR             255
 #define RGA2_RESET_TIMEOUT     1000
 
@@ -75,7 +78,7 @@ long (*rga_ioctl_kernel_p)(struct rga_req *);
 
 struct rga2_drvdata_t {
        struct miscdevice miscdev;
-       struct device dev;
+       struct device *dev;
        void *rga_base;
        int irq;
 
@@ -88,6 +91,7 @@ struct rga2_drvdata_t {
        struct clk *rga2;
 
        struct ion_client * ion_client;
+       char version[16];
 };
 
 struct rga2_drvdata_t *rga2_drvdata;
@@ -145,12 +149,46 @@ static inline u32 rga2_read(u32 r)
        return *((volatile unsigned int *)(rga2_drvdata->rga_base + r));
 }
 
+static inline int rga2_init_version(void)
+{
+       struct rga2_drvdata_t *rga = rga2_drvdata;
+       u32 major_version, minor_version;
+       u32 reg_version;
+
+       if (!rga) {
+               pr_err("rga2_drvdata is null\n");
+               return -EINVAL;
+       }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+       pm_runtime_get_sync(rga2_drvdata->dev);
+#endif
+
+       clk_prepare_enable(rga2_drvdata->aclk_rga2);
+       clk_prepare_enable(rga2_drvdata->hclk_rga2);
+
+       reg_version = rga2_read(0x028);
+
+       clk_disable_unprepare(rga2_drvdata->aclk_rga2);
+       clk_disable_unprepare(rga2_drvdata->hclk_rga2);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+       pm_runtime_put(rga2_drvdata->dev);
+#endif
+
+       major_version = (reg_version & RGA2_MAJOR_VERSION_MASK) >> 24;
+       minor_version = (reg_version & RGA2_MINOR_VERSION_MASK) >> 20;
+
+       sprintf(rga->version, "%d.%02d", major_version, minor_version);
+
+       return 0;
+}
+
 static void rga2_soft_reset(void)
 {
        u32 i;
        u32 reg;
 
-       rga2_write((1 << 3) | (1 << 4), RGA2_SYS_CTRL); //RGA_SYS_CTRL
+       rga2_write((1 << 3) | (1 << 4) | (1 << 6), RGA2_SYS_CTRL);
 
        for(i = 0; i < RGA2_RESET_TIMEOUT; i++)
        {
@@ -203,6 +241,10 @@ static void rga2_power_on(void)
        static ktime_t last;
        ktime_t now = ktime_get();
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+       pm_runtime_get_sync(rga2_drvdata->dev);
+#endif
+
        if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {
                cancel_delayed_work_sync(&rga2_drvdata->power_off_work);
                rga2_queue_power_off_work();
@@ -239,6 +281,11 @@ static void rga2_power_off(void)
        clk_disable_unprepare(rga2_drvdata->rga2);
        clk_disable_unprepare(rga2_drvdata->aclk_rga2);
        clk_disable_unprepare(rga2_drvdata->hclk_rga2);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+       pm_runtime_put(rga2_drvdata->dev);
+#endif
+
        wake_unlock(&rga2_drvdata->wake_lock);
     first_RGA2_proc = 0;
        rga2_service.enable = false;
@@ -415,6 +462,13 @@ static struct rga2_reg * rga2_reg_init(rga2_session *session, struct rga2_req *r
         return NULL;
     }
 
+       reg->sg_src0 = req->sg_src0;
+       reg->sg_dst = req->sg_dst;
+       reg->sg_src1 = req->sg_src1;
+       reg->attach_src0 = req->attach_src0;
+       reg->attach_dst = req->attach_dst;
+       reg->attach_src1 = req->attach_src1;
+
     mutex_lock(&rga2_service.lock);
        list_add_tail(&reg->status_link, &rga2_service.waiting);
        list_add_tail(&reg->session_link, &session->waiting);
@@ -527,22 +581,65 @@ static void rga2_try_set_reg(void)
        }
 }
 
-/* Caller must hold rga_service.lock */
+static int rga2_put_dma_buf(struct rga2_req *req, struct rga2_reg *reg)
+{
+       struct dma_buf_attachment *attach = NULL;
+       struct sg_table *sgt = NULL;
+       struct dma_buf *dma_buf = NULL;
+
+       if (!req && !reg)
+               return -EINVAL;
+
+       attach = (!reg) ? req->attach_src0 : reg->attach_src0;
+       sgt = (!reg) ? req->sg_src0 : reg->sg_src0;
+       if (attach && sgt)
+               dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+       if (attach) {
+               dma_buf = attach->dmabuf;
+               dma_buf_detach(dma_buf, attach);
+               dma_buf_put(dma_buf);
+       }
+
+       attach = (!reg) ? req->attach_dst : reg->attach_dst;
+       sgt = (!reg) ? req->sg_dst : reg->sg_dst;
+       if (attach && sgt)
+               dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+       if (attach) {
+               dma_buf = attach->dmabuf;
+               dma_buf_detach(dma_buf, attach);
+               dma_buf_put(dma_buf);
+       }
+
+       attach = (!reg) ? req->attach_src1 : reg->attach_src1;
+       sgt = (!reg) ? req->sg_src1 : reg->sg_src1;
+       if (attach && sgt)
+               dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+       if (attach) {
+               dma_buf = attach->dmabuf;
+               dma_buf_detach(dma_buf, attach);
+               dma_buf_put(dma_buf);
+       }
+
+       return 0;
+}
+
 static void rga2_del_running_list(void)
 {
+       struct rga2_mmu_buf_t *tbuf = &rga2_mmu_buf;
        struct rga2_reg *reg;
 
-       while(!list_empty(&rga2_service.running))
-       {
-               reg = list_entry(rga2_service.running.next, struct rga2_reg, status_link);
-
-               if(reg->MMU_len != 0)
-               {
-                       if (rga2_mmu_buf.back + reg->MMU_len > 2*rga2_mmu_buf.size)
-                               rga2_mmu_buf.back = reg->MMU_len + rga2_mmu_buf.size;
+       while (!list_empty(&rga2_service.running)) {
+               reg = list_entry(rga2_service.running.next, struct rga2_reg,
+                                status_link);
+               if (reg->MMU_len && tbuf) {
+                       if (tbuf->back + reg->MMU_len > 2 * tbuf->size)
+                               tbuf->back = reg->MMU_len + tbuf->size;
                        else
-                               rga2_mmu_buf.back += reg->MMU_len;
+                               tbuf->back += reg->MMU_len;
                }
+
+               rga2_put_dma_buf(NULL, reg);
+
                atomic_sub(1, &reg->session->task_running);
                atomic_sub(1, &rga2_service.total_running);
 
@@ -556,129 +653,202 @@ static void rga2_del_running_list(void)
        }
 }
 
-/* Caller must hold rga_service.lock */
 static void rga2_del_running_list_timeout(void)
 {
-    struct rga2_reg *reg;
+       struct rga2_mmu_buf_t *tbuf = &rga2_mmu_buf;
+       struct rga2_reg *reg;
 
-    while(!list_empty(&rga2_service.running))
-    {
-        reg = list_entry(rga2_service.running.next, struct rga2_reg, status_link);
+       while (!list_empty(&rga2_service.running)) {
+               reg = list_entry(rga2_service.running.next, struct rga2_reg,
+                                status_link);
+               kfree(reg->MMU_base);
+               if (reg->MMU_len && tbuf) {
+                       if (tbuf->back + reg->MMU_len > 2 * tbuf->size)
+                               tbuf->back = reg->MMU_len + tbuf->size;
+                       else
+                               tbuf->back += reg->MMU_len;
+               }
 
-        if(reg->MMU_base != NULL)
-        {
-            kfree(reg->MMU_base);
-        }
+               rga2_put_dma_buf(NULL, reg);
 
-        atomic_sub(1, &reg->session->task_running);
-        atomic_sub(1, &rga2_service.total_running);
+               atomic_sub(1, &reg->session->task_running);
+               atomic_sub(1, &rga2_service.total_running);
+               rga2_soft_reset();
+               if (list_empty(&reg->session->waiting)) {
+                       atomic_set(&reg->session->done, 1);
+                       wake_up(&reg->session->wait);
+               }
+               rga2_reg_deinit(reg);
+       }
+       return;
+}
 
-        rga2_soft_reset();
+static int rga2_get_img_info(rga_img_info_t *img,
+                            u8 mmu_flag,
+                            u8 buf_gem_type_dma,
+                            struct sg_table **psgt,
+                            struct dma_buf_attachment **pattach)
+{
+       struct dma_buf_attachment *attach = NULL;
+       struct ion_client *ion_client = NULL;
+       struct ion_handle *hdl = NULL;
+       struct device *rga_dev = NULL;
+       struct sg_table *sgt = NULL;
+       struct dma_buf *dma_buf = NULL;
+       u32 vir_w, vir_h;
+       ion_phys_addr_t phy_addr;
+       size_t len = 0;
+       int yrgb_addr = -1;
+       int ret = 0;
 
-        if(list_empty(&reg->session->waiting))
-        {
-            atomic_set(&reg->session->done, 1);
-            wake_up(&reg->session->wait);
-        }
+       ion_client = rga2_drvdata->ion_client;
+       rga_dev = rga2_drvdata->dev;
+       yrgb_addr = (int)img->yrgb_addr;
+       vir_w = img->vir_w;
+       vir_h = img->vir_h;
+
+       if (yrgb_addr > 0) {
+               if (buf_gem_type_dma) {
+                       dma_buf = dma_buf_get(img->yrgb_addr);
+                       if (IS_ERR(dma_buf)) {
+                               ret = -EINVAL;
+                               pr_err("dma_buf_get fail fd[%d]\n", yrgb_addr);
+                               return ret;
+                       }
 
-        rga2_reg_deinit(reg);
-    }
+                       attach = dma_buf_attach(dma_buf, rga_dev);
+                       if (IS_ERR(attach)) {
+                               dma_buf_put(dma_buf);
+                               ret = -EINVAL;
+                               pr_err("Failed to attach dma_buf\n");
+                               return ret;
+                       }
+
+                       *pattach = attach;
+                       sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+                       if (IS_ERR(sgt)) {
+                               ret = -EINVAL;
+                               pr_err("Failed to map src attachment\n");
+                               goto err_get_sg;
+                       }
+                       if (!mmu_flag) {
+                               ret = -EINVAL;
+                               pr_err("Fix it please enable iommu flag\n");
+                               goto err_get_sg;
+                       }
+               } else {
+                       hdl = ion_import_dma_buf(ion_client, img->yrgb_addr);
+                       if (IS_ERR(hdl)) {
+                               ret = -EINVAL;
+                               pr_err("RGA2 ERROR ion buf handle\n");
+                               return ret;
+                       }
+                       if (mmu_flag) {
+                               sgt = ion_sg_table(ion_client, hdl);
+                               if (IS_ERR(sgt)) {
+                                       ret = -EINVAL;
+                                       pr_err("Fail map src attachment\n");
+                                       goto err_get_sg;
+                               }
+                       }
+               }
+
+               if (mmu_flag) {
+                       *psgt = sgt;
+                       img->yrgb_addr = img->uv_addr;
+                       img->uv_addr = img->yrgb_addr + (vir_w * vir_h);
+                       img->v_addr = img->uv_addr + (vir_w * vir_h) / 4;
+               } else {
+                       ion_phys(ion_client, hdl, &phy_addr, &len);
+                       img->yrgb_addr = phy_addr;
+                       img->uv_addr = img->yrgb_addr + (vir_w * vir_h);
+                       img->v_addr = img->uv_addr + (vir_w * vir_h) / 4;
+               }
+       } else {
+               img->yrgb_addr = img->uv_addr;
+               img->uv_addr = img->yrgb_addr + (vir_w * vir_h);
+               img->v_addr = img->uv_addr + (vir_w * vir_h) / 4;
+       }
+
+       if (hdl)
+               ion_free(ion_client, hdl);
+
+       return ret;
+
+err_get_sg:
+       if (hdl)
+               ion_free(ion_client, hdl);
+       if (sgt && buf_gem_type_dma)
+               dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+       if (attach) {
+               dma_buf = attach->dmabuf;
+               dma_buf_detach(dma_buf, attach);
+               *pattach = NULL;
+               dma_buf_put(dma_buf);
+       }
+       return ret;
 }
 
-static int rga2_convert_dma_buf(struct rga2_req *req)
+static int rga2_get_dma_buf(struct rga2_req *req)
 {
-       struct ion_handle *hdl;
-       ion_phys_addr_t phy_addr;
-       size_t len;
-       int ret;
+       struct dma_buf *dma_buf = NULL;
+       u8 buf_gem_type_dma = 0;
+       u8 mmu_flag = 0;
+       int ret = 0;
 
+       buf_gem_type_dma = req->buf_type & RGA_BUF_GEM_TYPE_DMA;
        req->sg_src0 = NULL;
        req->sg_src1 = NULL;
-       req->sg_dst  = NULL;
-       req->sg_els  = NULL;
-
-       if((int)req->src.yrgb_addr > 0) {
-               hdl = ion_import_dma_buf(rga2_drvdata->ion_client, req->src.yrgb_addr);
-               if (IS_ERR(hdl)) {
-                       ret = PTR_ERR(hdl);
-                       printk("RGA2 SRC ERROR ion buf handle\n");
-                       return ret;
-               }
-               if (req->mmu_info.src0_mmu_flag) {
-                       req->sg_src0 = ion_sg_table(rga2_drvdata->ion_client, hdl);
-                       req->src.yrgb_addr = req->src.uv_addr;
-                       req->src.uv_addr = req->src.yrgb_addr + (req->src.vir_w * req->src.vir_h);
-                       req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h)/4;
-               }
-               else {
-                       ion_phys(rga2_drvdata->ion_client, hdl, &phy_addr, &len);
-                       req->src.yrgb_addr = phy_addr;
-                       req->src.uv_addr = req->src.yrgb_addr + (req->src.vir_w * req->src.vir_h);
-                       req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h)/4;
-               }
-               ion_free(rga2_drvdata->ion_client, hdl);
-       }
-       else {
-               req->src.yrgb_addr = req->src.uv_addr;
-               req->src.uv_addr = req->src.yrgb_addr + (req->src.vir_w * req->src.vir_h);
-               req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h)/4;
+       req->sg_dst = NULL;
+       req->sg_els = NULL;
+       req->attach_src0 = NULL;
+       req->attach_dst = NULL;
+       req->attach_src1 = NULL;
+       mmu_flag = req->mmu_info.src0_mmu_flag;
+       ret = rga2_get_img_info(&req->src, mmu_flag, buf_gem_type_dma,
+                               &req->sg_src0, &req->attach_src0);
+       if (ret) {
+               pr_err("src:rga2_get_img_info fail\n");
+               goto err_src;
        }
 
-       if((int)req->dst.yrgb_addr > 0) {
-               hdl = ion_import_dma_buf(rga2_drvdata->ion_client, req->dst.yrgb_addr);
-               if (IS_ERR(hdl)) {
-                       ret = PTR_ERR(hdl);
-                       printk("RGA2 DST ERROR ion buf handle\n");
-                       return ret;
-               }
-               if (req->mmu_info.dst_mmu_flag) {
-                       req->sg_dst = ion_sg_table(rga2_drvdata->ion_client, hdl);
-                       req->dst.yrgb_addr = req->dst.uv_addr;
-                       req->dst.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h);
-                       req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4;
-               }
-               else {
-                       ion_phys(rga2_drvdata->ion_client, hdl, &phy_addr, &len);
-                       req->dst.yrgb_addr = phy_addr;
-                       req->dst.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h);
-                       req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4;
-               }
-               ion_free(rga2_drvdata->ion_client, hdl);
+       mmu_flag = req->mmu_info.dst_mmu_flag;
+       ret = rga2_get_img_info(&req->dst, mmu_flag, buf_gem_type_dma,
+                               &req->sg_dst, &req->attach_dst);
+       if (ret) {
+               pr_err("dst:rga2_get_img_info fail\n");
+               goto err_dst;
        }
-       else {
-               req->dst.yrgb_addr = req->dst.uv_addr;
-               req->dst.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h);
-               req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4;
+
+       mmu_flag = req->mmu_info.src1_mmu_flag;
+       ret = rga2_get_img_info(&req->src1, mmu_flag, buf_gem_type_dma,
+                               &req->sg_src1, &req->attach_src1);
+       if (ret) {
+               pr_err("src1:rga2_get_img_info fail\n");
+               goto err_src1;
        }
 
-       if((int)req->src1.yrgb_addr > 0) {
-               hdl = ion_import_dma_buf(rga2_drvdata->ion_client, req->src1.yrgb_addr);
-               if (IS_ERR(hdl)) {
-                       ret = PTR_ERR(hdl);
-                       printk("RGA2 ERROR ion buf handle\n");
-                       return ret;
-               }
-               if (req->mmu_info.dst_mmu_flag) {
-                       req->sg_src1 = ion_sg_table(rga2_drvdata->ion_client, hdl);
-                       req->src1.yrgb_addr = 0;
-                       req->src1.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h);
-                       req->src1.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4;
-               }
-               else {
-                       ion_phys(rga2_drvdata->ion_client, hdl, &phy_addr, &len);
-                       req->src1.yrgb_addr = phy_addr;
-                       req->src1.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h);
-                       req->src1.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4;
-               }
-               ion_free(rga2_drvdata->ion_client, hdl);
+       return ret;
+
+err_src1:
+       if (buf_gem_type_dma && req->sg_dst && req->attach_dst) {
+               dma_buf_unmap_attachment(req->attach_dst,
+                                        req->sg_dst, DMA_BIDIRECTIONAL);
+               dma_buf = req->attach_dst->dmabuf;
+               dma_buf_detach(dma_buf, req->attach_dst);
+               dma_buf_put(dma_buf);
        }
-       else {
-               req->src1.yrgb_addr = req->dst.uv_addr;
-               req->src1.uv_addr = req->dst.yrgb_addr + (req->dst.vir_w * req->dst.vir_h);
-               req->src1.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h)/4;
+err_dst:
+       if (buf_gem_type_dma && req->sg_src0 && req->attach_src0) {
+               dma_buf_unmap_attachment(req->attach_src0,
+                                        req->sg_src0, DMA_BIDIRECTIONAL);
+               dma_buf = req->attach_src0->dmabuf;
+               dma_buf_detach(dma_buf, req->attach_src0);
+               dma_buf_put(dma_buf);
        }
+err_src:
 
-       return 0;
+       return ret;
 }
 
 static int rga2_blit(rga2_session *session, struct rga2_req *req)
@@ -687,8 +857,8 @@ static int rga2_blit(rga2_session *session, struct rga2_req *req)
        int num = 0;
        struct rga2_reg *reg;
 
-       if(rga2_convert_dma_buf(req)) {
-               printk("RGA2 : DMA buf copy error\n");
+       if (rga2_get_dma_buf(req)) {
+               pr_err("RGA2 : DMA buf copy error\n");
                return -EFAULT;
        }
 
@@ -696,16 +866,17 @@ static int rga2_blit(rga2_session *session, struct rga2_req *req)
                /* check value if legal */
                ret = rga2_check_param(req);
                if(ret == -EINVAL) {
-                       printk("req argument is inval\n");
-                       break;
+                       pr_err("req argument is inval\n");
+                       goto err_put_dma_buf;
                }
 
                reg = rga2_reg_init(session, req);
                if(reg == NULL) {
-                       break;
+                       pr_err("init reg fail\n");
+                       goto err_put_dma_buf;
                }
-               num = 1;
 
+               num = 1;
                mutex_lock(&rga2_service.lock);
                atomic_add(num, &rga2_service.total_running);
                rga2_try_set_reg();
@@ -715,6 +886,9 @@ static int rga2_blit(rga2_session *session, struct rga2_req *req)
        }
        while(0);
 
+err_put_dma_buf:
+       rga2_put_dma_buf(req, NULL);
+
        return -EFAULT;
 }
 
@@ -739,9 +913,14 @@ static int rga2_blit_async(rga2_session *session, struct rga2_req *req)
 
 static int rga2_blit_sync(rga2_session *session, struct rga2_req *req)
 {
+       struct rga2_req req_bak;
+       int try = 10;
        int ret = -1;
        int ret_timeout = 0;
 
+       memcpy(&req_bak, req, sizeof(req_bak));
+retry:
+
 #if RGA2_TEST_MSG
        if (1) {//req->bitblt_mode == 0x2) {
                print_info(req);
@@ -783,17 +962,26 @@ static int rga2_blit_sync(rga2_session *session, struct rga2_req *req)
        rga2_end = ktime_sub(rga2_end, rga2_start);
        printk("sync one cmd end time %d\n", (int)ktime_to_us(rga2_end));
 #endif
+       if (ret == -ETIMEDOUT && try--) {
+               memcpy(req, &req_bak, sizeof(req_bak));
+               goto retry;
+       }
 
        return ret;
        }
 
 static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
 {
+       struct rga2_drvdata_t *rga = rga2_drvdata;
        struct rga2_req req, req_first;
        struct rga_req req_rga;
        int ret = 0;
        rga2_session *session;
 
+       if (!rga) {
+               pr_err("rga2_drvdata is null, rga2 is not init\n");
+               return -ENODEV;
+       }
        memset(&req, 0x0, sizeof(req));
 
        mutex_lock(&rga2_service.mutex);
@@ -900,8 +1088,7 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
                        break;
                case RGA_GET_VERSION:
                case RGA2_GET_VERSION:
-                       ret = copy_to_user((void *)arg, RGA2_VERSION, sizeof(RGA2_VERSION));
-                       //ret = 0;
+                       ret = copy_to_user((void *)arg, rga->version, 16);
                        break;
                default:
                        ERR("unknown ioctl cmd!\n");
@@ -917,11 +1104,16 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
 #ifdef CONFIG_COMPAT
 static long compat_rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
 {
+       struct rga2_drvdata_t *rga = rga2_drvdata;
        struct rga2_req req, req_first;
        struct rga_req_32 req_rga;
        int ret = 0;
        rga2_session *session;
 
+       if (!rga) {
+               pr_err("rga2_drvdata is null, rga2 is not init\n");
+               return -ENODEV;
+       }
        memset(&req, 0x0, sizeof(req));
 
        mutex_lock(&rga2_service.mutex);
@@ -1033,8 +1225,7 @@ static long compat_rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
                        break;
                case RGA_GET_VERSION:
                case RGA2_GET_VERSION:
-                       ret = copy_to_user((void *)arg, RGA2_VERSION, sizeof(RGA2_VERSION));
-                       //ret = 0;
+                       ret = copy_to_user((void *)arg, rga->version, 16);
                        break;
                default:
                        ERR("unknown ioctl cmd!\n");
@@ -1219,6 +1410,7 @@ static int rga2_drv_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, data);
+       data->dev = &pdev->dev;
        rga2_drvdata = data;
        of_property_read_u32(np, "dev_mode", &rga2_service.dev_mode);
 
@@ -1238,8 +1430,11 @@ static int rga2_drv_probe(struct platform_device *pdev)
                ERR("cannot register miscdev (%d)\n", ret);
                goto err_misc_register;
        }
-
-       pr_info("Driver loaded succesfully\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+       pm_runtime_enable(&pdev->dev);
+#endif
+       rga2_init_version();
+       pr_info("Driver loaded successfully ver:%s\n", rga2_drvdata->version);
 
        return 0;
 
@@ -1268,6 +1463,10 @@ static int rga2_drv_remove(struct platform_device *pdev)
        devm_clk_put(&pdev->dev, data->aclk_rga2);
        devm_clk_put(&pdev->dev, data->hclk_rga2);
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
+       pm_runtime_disable(&pdev->dev);
+#endif
+
        kfree(data);
        return 0;
 }
@@ -1300,8 +1499,8 @@ static int __init rga2_init(void)
 
        rga2_mmu_buf.pages = kmalloc(32768 * sizeof(struct page *), GFP_KERNEL);
 
-       if ((ret = platform_driver_register(&rga2_driver)) != 0)
-       {
+       ret = platform_driver_register(&rga2_driver);
+       if (ret != 0) {
                printk(KERN_ERR "Platform device register failed (%d).\n", ret);
                return ret;
        }
@@ -1349,8 +1548,6 @@ void rga2_test_0(void)
        struct rga2_req req;
        rga2_session session;
        unsigned int *src, *dst;
-       uint32_t i, j;
-       uint32_t *dst0;
 
        session.pid     = current->pid;
        INIT_LIST_HEAD(&session.waiting);
@@ -1361,9 +1558,6 @@ void rga2_test_0(void)
        list_add_tail(&session.list_session, &rga2_service.session);
        atomic_set(&session.task_running, 0);
        atomic_set(&session.num_done, 0);
-       //file->private_data = (void *)session;
-
-       //fb = rk_get_fb(0);
 
        memset(&req, 0, sizeof(struct rga2_req));
        src = kmalloc(800*480*4, GFP_KERNEL);
@@ -1373,22 +1567,18 @@ void rga2_test_0(void)
        printk("************ RGA2_TEST ************\n");
        printk("********************************\n\n");
 
-       memset(src, 0x80, 800*480*4);
-       memset(dst, 0x0, 800*480*4);
-
-       //dmac_flush_range(&src, &src[800*480*4]);
-       //outer_flush_range(virt_to_phys(&src),virt_to_phys(&src[800*480*4]));
-
+#if 1
+       memset(src, 0x80, 800 * 480 * 4);
+       memset(dst, 0xcc, 800 * 480 * 4);
+#endif
 #if 0
-       memset(src_buf, 0x80, 800*480*4);
-       memset(dst_buf, 0xcc, 800*480*4);
+       dmac_flush_range(src, &src[800 * 480]);
+       outer_flush_range(virt_to_phys(src), virt_to_phys(&src[800 * 480]));
 
-       dmac_flush_range(&dst_buf[0], &dst_buf[800*480]);
-       outer_flush_range(virt_to_phys(&dst_buf[0]),virt_to_phys(&dst_buf[800*480]));
+       dmac_flush_range(dst, &dst[800 * 480]);
+       outer_flush_range(virt_to_phys(dst), virt_to_phys(&dst[800 * 480]));
 #endif
 
-       dst0 = (uint32_t *)&dst;
-       i = j = 0;
 #if 0
        req.pat.act_w = 16;
        req.pat.act_h = 16;
@@ -1398,16 +1588,39 @@ void rga2_test_0(void)
        req.render_mode = 0;
        rga2_blit_sync(&session, &req);
 #endif
-
-       req.src.act_w  = 320;
+       {
+               uint32_t i, j;
+               uint8_t *sp;
+
+               sp = (uint8_t *)src;
+               for (j = 0; j < 240; j++) {
+                       sp = (uint8_t *)src + j * 320 * 10 / 8;
+                       for (i = 0; i < 320; i++) {
+                               if ((i & 3) == 0) {
+                                       sp[i * 5 / 4] = 0;
+                                       sp[i * 5 / 4+1] = 0x1;
+                               } else if ((i & 3) == 1) {
+                                       sp[i * 5 / 4+1] = 0x4;
+                               } else if ((i & 3) == 2) {
+                                       sp[i * 5 / 4+1] = 0x10;
+                               } else if ((i & 3) == 3) {
+                                       sp[i * 5 / 4+1] = 0x40;
+                           }
+                       }
+               }
+               sp = (uint8_t *)src;
+               for (j = 0; j < 100; j++)
+                       printk("src %.2x\n", sp[j]);
+       }
+       req.src.act_w = 320;
        req.src.act_h = 240;
 
-       req.src.vir_w  = 320;
+       req.src.vir_w = 320;
        req.src.vir_h = 240;
        req.src.yrgb_addr = 0;//(uint32_t)virt_to_phys(src);
        req.src.uv_addr = (unsigned long)virt_to_phys(src);
        req.src.v_addr = 0;
-       req.src.format = RGA2_FORMAT_RGBA_8888;
+       req.src.format = RGA2_FORMAT_YCbCr_420_SP_10B;
 
        req.dst.act_w  = 320;
        req.dst.act_h = 240;
@@ -1419,7 +1632,7 @@ void rga2_test_0(void)
 
        req.dst.yrgb_addr = 0;//((uint32_t)virt_to_phys(dst));
        req.dst.uv_addr = (unsigned long)virt_to_phys(dst);
-       req.dst.format = RGA2_FORMAT_RGBA_8888;
+       req.dst.format = RGA2_FORMAT_YCbCr_420_SP;
 
        //dst = dst0;
 
@@ -1429,6 +1642,7 @@ void rga2_test_0(void)
        req.rotate_mode = 0;
        req.scale_bicu_mode = 2;
 
+#if 0
        //req.alpha_rop_flag = 0;
        //req.alpha_rop_mode = 0x19;
        //req.PD_mode = 3;
@@ -1439,12 +1653,28 @@ void rga2_test_0(void)
        //printk("src = %.8x\n", req.src.yrgb_addr);
        //printk("src = %.8x\n", req.src.uv_addr);
        //printk("dst = %.8x\n", req.dst.yrgb_addr);
+#endif
 
        rga2_blit_sync(&session, &req);
 
-       for(j=0; j<100; j++) {
-               printk("%.8x\n", dst[j]);
+#if 0
+       uint32_t j;
+       for (j = 0; j < 320 * 240 * 10 / 8; j++) {
+        if (src[j] != dst[j])
+               printk("error value dst not equal src j %d, s %.2x d %.2x\n",
+                       j, src[j], dst[j]);
+       }
+#endif
+
+#if 1
+       {
+               uint32_t j;
+               uint8_t *dp = (uint8_t *)dst;
+
+               for (j = 0; j < 100; j++)
+                       printk("%d %.2x\n", j, dp[j]);
        }
+#endif
 
        if(src)
                kfree(src);