rk3288: vcodec support iommu using ion mmu map functions
authorljf <ljf@rock-chips.com>
Thu, 17 Apr 2014 06:18:52 +0000 (14:18 +0800)
committerljf <ljf@rock-chips.com>
Thu, 17 Apr 2014 06:19:40 +0000 (14:19 +0800)
arch/arm/mach-rockchip/vcodec_service.c

index aba5e2358fd886aabef641bdfe88f65aa62c798d..d08f8c82d20609cd9fc0b56319bf5316f22ce8ec 100755 (executable)
@@ -43,7 +43,9 @@
 #include <linux/rockchip_ion.h>\r
 #endif\r
 \r
+#if defined(CONFIG_ROCKCHIP_IOMMU)\r
 //#define CONFIG_VCODEC_MMU\r
+#endif\r
 \r
 #ifdef CONFIG_VCODEC_MMU\r
 #include <linux/rockchip/iovmm.h>\r
@@ -62,7 +64,7 @@
 #include "vcodec_service.h"\r
 \r
 #define HEVC_TEST_ENABLE    0\r
-#define HEVC_SIM_ENABLE                0\r
+#define HEVC_SIM_ENABLE     0\r
 #define VCODEC_CLOCK_ENABLE 1\r
 \r
 typedef enum {\r
@@ -184,17 +186,19 @@ static VPU_HW_INFO_E vpu_hw_set[] = {
 #define VPU_REG_DEC_PP_GATE                    61\r
 #define VPU_REG_DEC_PP_GATE_BIT                (1<<8)\r
 \r
+#if defined(CONFIG_VCODEC_MMU)\r
 static u8 addr_tbl_vpu_dec[] = {\r
-       12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40, 41\r
+    12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40, 41\r
 };\r
 \r
 static u8 addr_tbl_vpu_enc[] = {\r
-       5, 6, 7, 8, 9, 10, 11, 12, 13, 51\r
+    5, 6, 7, 8, 9, 10, 11, 12, 13, 51\r
 };\r
 \r
 static u8 addr_tbl_hevc_dec[] = {\r
     4, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 42, 43\r
 };\r
+#endif\r
 \r
 /**\r
  * struct for process session which connect to vpu\r
@@ -251,10 +255,8 @@ struct vcodec_mem_region {
     struct list_head srv_lnk;\r
     struct list_head reg_lnk;\r
     struct list_head session_lnk;\r
-    dma_addr_t       iova;              /* virtual address for iommu */\r
-    struct dma_buf   *buf;\r
-    struct dma_buf_attachment *attachment;\r
-    struct sg_table *sg_table;\r
+    unsigned long iova;              /* virtual address for iommu */\r
+    unsigned long len;\r
     struct ion_handle *hdl;\r
 };\r
 \r
@@ -498,19 +500,19 @@ static void vpu_service_dump(struct vpu_service_info *pservice)
 \r
 static void vpu_service_power_off(struct vpu_service_info *pservice)\r
 {\r
-       int total_running;\r
-       if (!pservice->enabled) {\r
-               return;\r
-       }\r
+    int total_running;\r
+    if (!pservice->enabled) {\r
+        return;\r
+    }\r
 \r
-       pservice->enabled = false;\r
-       total_running = atomic_read(&pservice->total_running);\r
-       if (total_running) {\r
-               pr_alert("alert: power off when %d task running!!\n", total_running);\r
-               mdelay(50);\r
-               pr_alert("alert: delay 50 ms for running task\n");\r
-               vpu_service_dump(pservice);\r
-       }\r
+    pservice->enabled = false;\r
+    total_running = atomic_read(&pservice->total_running);\r
+    if (total_running) {\r
+        pr_alert("alert: power off when %d task running!!\n", total_running);\r
+        mdelay(50);\r
+        pr_alert("alert: delay 50 ms for running task\n");\r
+        vpu_service_dump(pservice);\r
+    }\r
 \r
     printk("%s: power off...", dev_name(pservice->dev));\r
     udelay(10);\r
@@ -610,111 +612,102 @@ static inline int reg_probe_width(vpu_reg *reg)
 \r
 #if defined(CONFIG_VCODEC_MMU)\r
 \r
-static unsigned int vcodec_map_ion_handle(vpu_service_info *pservice, \r
-                                          vpu_reg *reg,\r
-                                          struct ion_handle *ion_handle,\r
-                                          struct dma_buf *buf, int offset)\r
+static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, int size, vpu_reg *reg)\r
 {\r
-    struct vcodec_mem_region *mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL);\r
-    if (mem_region == NULL) {\r
-        dev_err(pservice->dev, "allocate memory for iommu memory region failed\n");\r
-        return -1;\r
-    }\r
-    \r
-    mem_region->buf = buf;\r
-    mem_region->hdl = ion_handle;\r
+    int i;\r
+    int usr_fd = 0;\r
+    int offset = 0;\r
     \r
-    mem_region->attachment = dma_buf_attach(buf, pservice->dev);\r
-    if (IS_ERR_OR_NULL(mem_region->attachment)) {\r
-        dev_err(pservice->dev, "dma_buf_attach() failed: %ld\n", PTR_ERR(mem_region->attachment));\r
-        goto err_buf_map_attach;\r
+    if (tbl == NULL || size <= 0) {\r
+        dev_err(pservice->dev, "input arguments invalidate\n");\r
+        return -1;\r
     }\r
     \r
-    mem_region->sg_table = dma_buf_map_attachment(mem_region->attachment, DMA_BIDIRECTIONAL);\r
-    if (IS_ERR_OR_NULL(mem_region->sg_table)) {\r
-        dev_err(pservice->dev, "dma_buf_map_attachment() failed: %ld\n", PTR_ERR(mem_region->sg_table));\r
-        goto err_buf_map_attachment;\r
-    }\r
+    for (i=0; i<size; i++) {\r
+#if 0\r
+        if (copy_from_user(&usr_fd, &reg->reg[addr_tbl_vpu_dec[i]], sizeof(usr_fd)))\r
+            return -EFAULT;\r
+#else\r
+        usr_fd = reg->reg[tbl[i]] & 0xFF;\r
+        offset = reg->reg[tbl[i]] >> 8;\r
+        \r
+#endif\r
+        if (usr_fd != 0) {\r
+            struct ion_handle *hdl;\r
+            \r
+            hdl = ion_import_dma_buf(pservice->ion_client, usr_fd);\r
+            if (IS_ERR(hdl)) {\r
+                dev_err(pservice->dev, "import dma-buf from fd %d failed, reg[%d]\n", usr_fd, tbl[i]);\r
+                return PTR_ERR(hdl);\r
+            }\r
+\r
+#if 0\r
+            {\r
+                ion_phys_addr_t phy_addr;\r
+                size_t len;\r
+                ion_phys(pservice->ion_client, hdl, &phy_addr, &len);\r
     \r
-    mem_region->iova = iovmm_map(pservice->dev, mem_region->sg_table->sgl, offset, buf->size);\r
-    if (mem_region->iova == 0 || IS_ERR_VALUE(mem_region->iova)) {\r
-        dev_err(pservice->dev, "iovmm_map() failed: %d\n", mem_region->iova);\r
-        goto err_iovmm_map;\r
+                reg->reg[tbl[i]] = phy_addr + offset;\r
+                \r
+                ion_free(pservice->ion_client, hdl);\r
+            }\r
+#else \r
+            {\r
+                int ret;\r
+                struct vcodec_mem_region *mem_region;\r
+                mem_region = kzalloc(sizeof(struct vcodec_mem_region), GFP_KERNEL);\r
+     \r
+                if (mem_region == NULL) {\r
+                    dev_err(pservice->dev, "allocate memory for iommu memory region failed\n");\r
+                    ion_free(pservice->ion_client, hdl);\r
+                    return -1;\r
+                }\r
+                \r
+                ret = ion_map_iommu(pservice->dev, pservice->ion_client, hdl, &mem_region->iova, &mem_region->len);\r
+                if (ret < 0) {\r
+                    dev_err(pservice->dev, "ion map iommu failed\n");\r
+                    kfree(mem_region);\r
+                    ion_free(pservice->ion_client, hdl);\r
+                    return ret;\r
+                }\r
+                \r
+                reg->reg[tbl[i]] = mem_region->iova + offset;\r
+                INIT_LIST_HEAD(&mem_region->reg_lnk);\r
+                list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);\r
+            }\r
+#endif\r
+        }\r
     }\r
     \r
-    INIT_LIST_HEAD(&mem_region->reg_lnk);\r
-    list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);\r
-    \r
-    return mem_region->iova;\r
-    \r
-err_iovmm_map:\r
-       dma_buf_unmap_attachment(mem_region->attachment, mem_region->sg_table, DMA_BIDIRECTIONAL);\r
-err_buf_map_attachment:\r
-       dma_buf_detach(buf, mem_region->attachment);\r
-err_buf_map_attach:\r
-    kfree(mem_region);\r
-       return 0;\r
+    return 0;\r
 }\r
 \r
 static int vcodec_reg_address_translate(struct vpu_service_info *pservice, vpu_reg *reg)\r
 {\r
-       VPU_HW_ID hw_id;\r
-       int i;\r
-\r
-       hw_id = pservice->hw_info->hw_id;\r
-\r
+    VPU_HW_ID hw_id;\r
+    u8 *tbl;\r
+    int size = 0;\r
+    \r
+    hw_id = pservice->hw_info->hw_id;\r
+    \r
     if (hw_id == HEVC_ID) {\r
-\r
+        tbl = addr_tbl_hevc_dec;\r
+        size = sizeof(addr_tbl_hevc_dec);\r
     } else {\r
-        if (reg->type == VPU_DEC) {\r
-            for (i=0; i<sizeof(addr_tbl_vpu_dec); i++) {\r
-                               int usr_fd;\r
-                               struct ion_handle *hdl;\r
-                               //ion_phys_addr_t phy_addr;\r
-                struct dma_buf *buf;\r
-                               //size_t len;\r
-                               int offset;\r
-\r
-#if 0\r
-                               if (copy_from_user(&usr_fd, &reg->reg[addr_tbl_vpu_dec[i]], sizeof(usr_fd)))\r
-                                       return -EFAULT;\r
-#else\r
-                               usr_fd = reg->reg[addr_tbl_vpu_dec[i]] & 0xFF;\r
-                               offset = reg->reg[addr_tbl_vpu_dec[i]] >> 8;\r
-#endif\r
-                if (usr_fd != 0) {\r
-\r
-                                       hdl = ion_import_dma_buf(pservice->ion_client, usr_fd);\r
-                    if (IS_ERR(hdl)) {\r
-                                               pr_err("import dma-buf from fd %d failed\n", usr_fd);\r
-                                               return PTR_ERR(hdl);\r
-                    }\r
-\r
-#if 0\r
-                                       ion_phys(pservice->ion_client, hdl, &phy_addr, &len);\r
-\r
-                                       reg->reg[addr_tbl_vpu_dec[i]] = phy_addr + offset;\r
-                    \r
-                    ion_free(pservice->ion_client, hdl);\r
-#else \r
-                    buf = ion_share_dma_buf(pservice->ion_client, hdl);\r
-                    if (IS_ERR_OR_NULL(buf)) {\r
-                        dev_err(pservice->dev, "ion_share_dma_buf() failed\n");\r
-                        ion_free(pservice->ion_client, hdl);\r
-                        return PTR_ERR(buf);\r
-                    }\r
-                    \r
-                    reg->reg[addr_tbl_vpu_dec[i]] = vcodec_map_ion_handle(pservice, reg, hdl, buf, offset);\r
-#endif\r
-                                       \r
-                }\r
-            }\r
+        if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {\r
+            tbl = addr_tbl_vpu_dec;\r
+            size = sizeof(addr_tbl_vpu_dec);\r
         } else if (reg->type == VPU_ENC) {\r
-\r
+            tbl = addr_tbl_vpu_enc;\r
+            size = sizeof(addr_tbl_vpu_enc);\r
         }\r
-       }\r
-\r
-       return 0;\r
+    }\r
+    \r
+    if (size != 0) {\r
+        return vcodec_bufid_to_iova(pservice, tbl, size, reg);\r
+    } else {\r
+        return -1;\r
+    }\r
 }\r
 #endif\r
 \r
@@ -750,9 +743,9 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session
 \r
 #if defined(CONFIG_VCODEC_MMU)\r
     if (0 > vcodec_reg_address_translate(pservice, reg)) {\r
-               pr_err("error: translate reg address failed\n");\r
-               kfree(reg);\r
-               return NULL;\r
+        pr_err("error: translate reg address failed\n");\r
+        kfree(reg);\r
+        return NULL;\r
     }\r
 #endif\r
 \r
@@ -792,24 +785,17 @@ static void reg_deinit(struct vpu_service_info *pservice, vpu_reg *reg)
     struct vcodec_mem_region *mem_region = NULL, *n;\r
 #endif\r
     \r
-       list_del_init(&reg->session_link);\r
-       list_del_init(&reg->status_link);\r
-       if (reg == pservice->reg_codec) pservice->reg_codec = NULL;\r
-       if (reg == pservice->reg_pproc) pservice->reg_pproc = NULL;\r
+    list_del_init(&reg->session_link);\r
+    list_del_init(&reg->status_link);\r
+    if (reg == pservice->reg_codec) pservice->reg_codec = NULL;\r
+    if (reg == pservice->reg_pproc) pservice->reg_pproc = NULL;\r
     \r
 #if defined(CONFIG_VCODEC_MMU)\r
     // release memory region attach to this registers table.\r
     list_for_each_entry_safe(mem_region, n, &reg->mem_region_list, reg_lnk) {\r
-        iovmm_unmap(pservice->dev, mem_region->iova);\r
-        \r
-        dma_buf_unmap_attachment(mem_region->attachment, mem_region->sg_table, DMA_BIDIRECTIONAL);\r
-        dma_buf_detach(mem_region->buf, mem_region->attachment);\r
-        \r
-        dma_buf_put(mem_region->buf);\r
+        ion_unmap_iommu(pservice->dev, pservice->ion_client, mem_region->hdl);\r
         ion_free(pservice->ion_client, mem_region->hdl);\r
-        \r
         list_del_init(&mem_region->reg_lnk);\r
-        \r
         kfree(mem_region);\r
     }\r
 #endif    \r
@@ -1544,12 +1530,18 @@ static int vcodec_probe(struct platform_device *pdev)
         dev_info(&pdev->dev, "vcodec ion client create success!\n");\r
     }\r
     \r
-    sprintf(mmu_dev_dts_name, "iommu,%s", dev_name(dev));\r
+    if (pservice->hw_info->hw_id == HEVC_ID) {\r
+        sprintf(mmu_dev_dts_name, "iommu,hevc_mmu");\r
+    } else {\r
+        sprintf(mmu_dev_dts_name, "iommu,vpu_mmu");\r
+    }\r
     \r
     mmu_dev = rockchip_get_sysmmu_device_by_compatible(mmu_dev_dts_name);\r
-    platform_set_sysmmu(mmu_dev, pservice->dev);\r
     \r
-    iovmm_activate(pservice->dev);\r
+    if (mmu_dev) {\r
+        platform_set_sysmmu(mmu_dev, pservice->dev);\r
+        iovmm_activate(pservice->dev);\r
+    }\r
 #endif\r
 \r
 #if HEVC_SIM_ENABLE\r