drm/rockchip: rga: replace primitive api with dma sync api
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_drm_rga.c
index 19045b14431d7db8683d5ba122d56e58be3cd39a..95da17bbb983bc688f9d6fc61712d40f636f29f5 100644 (file)
 #define RGA_MMU_SRC1_BASE              0x0174
 #define RGA_MMU_DST_BASE               0x0178
 
-static void rga_dma_flush_range(void *ptr, int size)
+static void __user *rga_compat_ptr(u64 value)
 {
-#ifdef CONFIG_ARM
-       dmac_flush_range(ptr, ptr + size);
-       outer_flush_range(virt_to_phys(ptr), virt_to_phys(ptr + size));
-#elif CONFIG_ARM64
-       __dma_flush_range(ptr, ptr + size);
+#ifdef CONFIG_ARM64
+       return (void __user *)(value);
+#else
+       return (void __user *)((u32)(value));
 #endif
 }
 
@@ -187,7 +186,9 @@ static int rga_alloc_dma_buf_for_cmdlist(struct rga_runqueue_node *runqueue)
                dest[reg >> 2] = mmu_ctrl;
        }
 
-       rga_dma_flush_range(cmdlist_pool_virt, cmdlist_cnt * RGA_CMDLIST_SIZE);
+       dma_sync_single_for_device(runqueue->drm_dev->dev,
+                                  virt_to_phys(cmdlist_pool_virt),
+                                  PAGE_SIZE, DMA_TO_DEVICE);
 
        runqueue->cmdlist_dma_attrs = cmdlist_dma_attrs;
        runqueue->cmdlist_pool_virt = cmdlist_pool_virt;
@@ -212,10 +213,12 @@ static int rga_check_reg_offset(struct device *dev,
                switch (reg) {
                case RGA_BUF_TYPE_GEMFD | RGA_DST_Y_RGB_BASE_ADDR:
                case RGA_BUF_TYPE_GEMFD | RGA_SRC_Y_RGB_BASE_ADDR:
+               case RGA_BUF_TYPE_GEMFD | RGA_SRC1_RGB_BASE_ADDR:
                        break;
 
                case RGA_BUF_TYPE_USERPTR | RGA_DST_Y_RGB_BASE_ADDR:
                case RGA_BUF_TYPE_USERPTR | RGA_SRC_Y_RGB_BASE_ADDR:
+               case RGA_BUF_TYPE_USERPTR | RGA_SRC1_RGB_BASE_ADDR:
                        goto err;
 
                default:
@@ -280,16 +283,15 @@ rga_gem_buf_to_pages(struct rockchip_rga *rga, void **mmu_pages, int fd)
 
                for (p = 0; p < len; p++) {
                        dma_addr_t phys = address + (p << PAGE_SHIFT);
-                       void *virt = phys_to_virt(phys);
 
-                       rga_dma_flush_range(virt, 4 * 1024);
                        pages[mapped_size + p] = phys;
                }
 
                mapped_size += len;
        }
 
-       rga_dma_flush_range(pages, 32 * 1024);
+       dma_sync_single_for_device(rga->drm_dev->dev, virt_to_phys(pages),
+                                  8 * PAGE_SIZE, DMA_TO_DEVICE);
 
        *mmu_pages = pages;
 
@@ -320,9 +322,21 @@ static int rga_map_cmdlist_gem(struct rockchip_rga *rga,
                int index = cmdlist->last - 2 * (i + 1);
 
                switch (cmdlist->data[index]) {
+               case RGA_SRC1_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD:
+                       fd = cmdlist->data[index + 1];
+                       attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd);
+                       if (IS_ERR(attach))
+                               return PTR_ERR(attach);
+
+                       cmdlist->src1_attach = attach;
+                       cmdlist->src1_mmu_pages = mmu_pages;
+                       break;
+
                case RGA_SRC_Y_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD:
                        fd = cmdlist->data[index + 1];
                        attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd);
+                       if (IS_ERR(attach))
+                               return PTR_ERR(attach);
 
                        cmdlist->src_attach = attach;
                        cmdlist->src_mmu_pages = mmu_pages;
@@ -331,6 +345,8 @@ static int rga_map_cmdlist_gem(struct rockchip_rga *rga,
                case RGA_DST_Y_RGB_BASE_ADDR | RGA_BUF_TYPE_GEMFD:
                        fd = cmdlist->data[index + 1];
                        attach = rga_gem_buf_to_pages(rga, &mmu_pages, fd);
+                       if (IS_ERR(attach))
+                               return PTR_ERR(attach);
 
                        cmdlist->dst_attach = attach;
                        cmdlist->dst_mmu_pages = mmu_pages;
@@ -355,6 +371,14 @@ static void rga_unmap_cmdlist_gem(struct rockchip_rga *rga,
        }
        node->cmdlist.src_attach = NULL;
 
+       attach = node->cmdlist.src1_attach;
+       if (attach) {
+               dma_buf = attach->dmabuf;
+               dma_buf_detach(dma_buf, attach);
+               dma_buf_put(dma_buf);
+       }
+       node->cmdlist.src1_attach = NULL;
+
        attach = node->cmdlist.dst_attach;
        if (attach) {
                dma_buf = attach->dmabuf;
@@ -464,6 +488,13 @@ static struct rga_cmdlist_node *rga_get_cmdlist(struct rockchip_rga *rga)
        return node;
 }
 
+static void rga_put_cmdlist(struct rockchip_rga *rga, struct rga_cmdlist_node *node)
+{
+       mutex_lock(&rga->cmdlist_mutex);
+       list_move_tail(&node->list, &rga->free_cmdlist);
+       mutex_unlock(&rga->cmdlist_mutex);
+}
+
 static void rga_add_cmdlist_to_inuse(struct rockchip_drm_rga_private *rga_priv,
                                     struct rga_cmdlist_node *node)
 {
@@ -533,6 +564,11 @@ int rockchip_rga_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
        if (!rga)
                return -EFAULT;
 
+       if (req->cmd_nr > RGA_CMDLIST_SIZE || req->cmd_buf_nr > RGA_CMDBUF_SIZE) {
+               dev_err(rga->dev, "cmdlist size is too big\n");
+               return -EINVAL;
+       }
+
        node = rga_get_cmdlist(rga);
        if (!node)
                return -ENOMEM;
@@ -540,23 +576,18 @@ int rockchip_rga_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
        cmdlist = &node->cmdlist;
        cmdlist->last = 0;
 
-       if (req->cmd_nr > RGA_CMDLIST_SIZE || req->cmd_buf_nr > RGA_CMDBUF_SIZE) {
-               dev_err(rga->dev, "cmdlist size is too big\n");
-               return -EINVAL;
-       }
-
        /*
         * Copy the command / buffer registers setting from userspace, each
         * command have two integer, one for register offset, another for
         * register value.
         */
-       if (copy_from_user(cmdlist->data, compat_ptr((compat_uptr_t)req->cmd),
+       if (copy_from_user(cmdlist->data, rga_compat_ptr(req->cmd),
                           sizeof(struct drm_rockchip_rga_cmd) * req->cmd_nr))
                return -EFAULT;
        cmdlist->last += req->cmd_nr * 2;
 
        if (copy_from_user(&cmdlist->data[cmdlist->last],
-                          compat_ptr((compat_uptr_t)req->cmd_buf),
+                          rga_compat_ptr(req->cmd_buf),
                           sizeof(struct drm_rockchip_rga_cmd) * req->cmd_buf_nr))
                return -EFAULT;
        cmdlist->last += req->cmd_buf_nr * 2;
@@ -566,16 +597,27 @@ int rockchip_rga_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
         * create the RGA mmu pages or get the framebuffer dma address.
         */
        ret = rga_check_reg_offset(rga->dev, node);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               dev_err(rga->dev, "Check reg offset failed\n");
+               goto err_free_cmdlist;
+       }
 
        ret = rga_map_cmdlist_gem(rga, node, drm_dev, file);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               dev_err(rga->dev, "Failed to map cmdlist\n");
+               goto err_unmap_cmdlist;
+       }
 
        rga_add_cmdlist_to_inuse(rga_priv, node);
 
        return 0;
+
+err_unmap_cmdlist:
+       rga_unmap_cmdlist_gem(rga, node);
+err_free_cmdlist:
+       rga_put_cmdlist(rga, node);
+
+       return ret;
 }
 
 /*
@@ -608,6 +650,7 @@ int rockchip_rga_exec_ioctl(struct drm_device *drm_dev, void *data,
                return -ENOMEM;
        }
 
+       runqueue->drm_dev = drm_dev;
        runqueue->dev = rga->dev;
 
        init_completion(&runqueue->complete);
@@ -647,6 +690,10 @@ static int rockchip_rga_open(struct drm_device *drm_dev, struct device *dev,
 {
        struct rockchip_drm_file_private *file_priv = file->driver_priv;
        struct rockchip_drm_rga_private *rga_priv;
+       struct rockchip_rga *rga;
+
+       rga = dev_get_drvdata(dev);
+       rga->drm_dev = drm_dev;
 
        rga_priv = kzalloc(sizeof(*rga_priv), GFP_KERNEL);
        if (!rga_priv)
@@ -814,7 +861,7 @@ static int rga_probe(struct platform_device *pdev)
        rga->rga_workq = create_singlethread_workqueue("rga");
        if (!rga->rga_workq) {
                dev_err(rga->dev, "failed to create workqueue\n");
-               ret = PTR_ERR(rga->rga_workq);
+               ret = -ENOMEM;
                goto err_destroy_slab;
        }