rk3288: iep support iommu
authorljf <ljf@rock-chips.com>
Tue, 22 Apr 2014 08:53:43 +0000 (16:53 +0800)
committerljf <ljf@rock-chips.com>
Tue, 22 Apr 2014 08:53:53 +0000 (16:53 +0800)
drivers/video/rockchip/iep/hw_iep_reg.c
drivers/video/rockchip/iep/iep_drv.c
drivers/video/rockchip/iep/iep_drv.h

index b52210f9fb011fd9ec0222923c263dd3ae999d12..f926bee4404c754e62286bd71938fb40a5c9aef5 100755 (executable)
@@ -1111,6 +1111,89 @@ void iep_switch_input_address(void *base) {
     IEP_REGB_SRC_ADDR_CR1  (base, src_addr_cr);\r
 }\r
 \r
+#if defined(CONFIG_IEP_IOMMU)\r
+static int iep_bufid_to_iova(iep_service_info *pservice, u8 *tbl, int size, struct iep_reg *reg)\r
+{\r
+    int i;\r
+    int usr_fd = 0;\r
+    int offset = 0;\r
+    \r
+    if (tbl == NULL || size <= 0) {\r
+        dev_err(pservice->iommu_dev, "input arguments invalidate\n");\r
+        return -1;\r
+    }\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]] & 0x3FF;\r
+        offset = reg->reg[tbl[i]] >> 10;\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->iommu_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
+                reg->reg[tbl[i]] = phy_addr + offset;\r
+                \r
+                ion_free(pservice->ion_client, hdl);\r
+            }\r
+#else \r
+            {\r
+                int ret;\r
+                struct iep_mem_region *mem_region;\r
+                mem_region = kzalloc(sizeof(struct iep_mem_region), GFP_KERNEL);\r
+     \r
+                if (mem_region == NULL) {\r
+                    dev_err(pservice->iommu_dev, "allocate memory for iommu memory region failed\n");\r
+                    ion_free(pservice->ion_client, hdl);\r
+                    return -1;\r
+                }\r
+                \r
+                mem_region->hdl = hdl;\r
+                \r
+                ret = ion_map_iommu(pservice->iommu_dev, pservice->ion_client, mem_region->hdl, &mem_region->iova, &mem_region->len);\r
+                if (ret < 0) {\r
+                    dev_err(pservice->iommu_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
+    return 0;\r
+}\r
+\r
+static u8 addr_tbl_iep[] = {\r
+    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55\r
+};\r
+\r
+static int iep_reg_address_translate(iep_service_info *pservice, struct iep_reg *reg)\r
+{\r
+    return iep_bufid_to_iova(pservice, addr_tbl_iep, sizeof(addr_tbl_iep), reg);\r
+}\r
+#endif\r
+\r
 /**\r
  * generating a series of registers copy from iep message\r
  */\r
@@ -1125,6 +1208,10 @@ void iep_config(iep_session *session, IEP_MSG *iep_msg)
 \r
     INIT_LIST_HEAD(&reg->session_link);\r
     INIT_LIST_HEAD(&reg->status_link);\r
+    \r
+#if defined(CONFIG_IEP_IOMMU)\r
+    INIT_LIST_HEAD(&reg->mem_region_list);    \r
+#endif    \r
 \r
     //write config\r
     iep_config_src_size(iep_msg);\r
@@ -1177,6 +1264,14 @@ void iep_config(iep_session *session, IEP_MSG *iep_msg)
     iep_config_mmu_dte_addr(iep_msg->base, (uint32_t)virt_to_phys((uint32_t*)session->dte_table));\r
 #endif\r
 \r
+#if defined(CONFIG_IEP_IOMMU)\r
+    if (0 > iep_reg_address_translate(&iep_service, reg)) {\r
+        pr_err("error: translate reg address failed\n");\r
+        kfree(reg);\r
+        return;\r
+    }\r
+#endif\r
+\r
     mutex_lock(&iep_service.lock);\r
 \r
     list_add_tail(&reg->status_link, &iep_service.waiting);\r
index 55fcf2ddfcbd52c81333c054e18cbd8bea0c8150..7135b7bd0ca34b988b4cd186e5b7b2a2b8b90e90 100755 (executable)
@@ -76,6 +76,16 @@ iep_service_info iep_service;
 \r
 static void iep_reg_deinit(struct iep_reg *reg)\r
 {\r
+#if defined(CONFIG_IEP_IOMMU)\r
+    struct iep_mem_region *mem_region = NULL, *n;\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
+        ion_unmap_iommu(iep_service.iommu_dev, iep_service.ion_client, mem_region->hdl);\r
+        ion_free(iep_service.ion_client, mem_region->hdl);\r
+        list_del_init(&mem_region->reg_lnk);\r
+        kfree(mem_region);\r
+    }\r
+#endif \r
     list_del_init(&reg->session_link);\r
     list_del_init(&reg->status_link);\r
     kfree(reg);\r
@@ -710,6 +720,9 @@ static long iep_ioctl(struct file *filp, uint32_t cmd, unsigned long arg)
             \r
             if (ret == 0) {\r
                 if (atomic_read(&iep_service.waitcnt) < 10) {\r
+#if defined(CONFIG_IEP_IOMMU)\r
+                    iep_power_on(); /* for iep iommu reg configure. */\r
+#endif\r
                     iep_config(session, msg);\r
                     atomic_inc(&iep_service.waitcnt);\r
                 } else {\r
@@ -762,11 +775,17 @@ static struct miscdevice iep_dev = {
     .fops  = &iep_fops,\r
 };\r
 \r
+#if defined(CONFIG_IEP_IOMMU)\r
+extern struct ion_client *rockchip_ion_client_create(const char * name);\r
+#endif\r
 static int iep_drv_probe(struct platform_device *pdev)\r
 {\r
     struct iep_drvdata *data;\r
     int ret = 0;\r
     struct resource *res = NULL;\r
+#if defined(CONFIG_IEP_IOMMU)\r
+    struct device *mmu_dev = NULL;\r
+#endif\r
 \r
     data = (struct iep_drvdata*)devm_kzalloc(&pdev->dev, sizeof(struct iep_drvdata), GFP_KERNEL);\r
     if (NULL == data) {\r
@@ -849,6 +868,27 @@ static int iep_drv_probe(struct platform_device *pdev)
         IEP_ERR("cannot register miscdev (%d)\n", ret);\r
         goto err_misc_register;\r
     }\r
+    \r
+#if defined(CONFIG_IEP_IOMMU)\r
+    iep_power_on();\r
+    iep_service.ion_client = rockchip_ion_client_create("iep");\r
+    if (IS_ERR(iep_service.ion_client)) {\r
+        dev_err(&pdev->dev, "failed to create ion client for vcodec");\r
+        return PTR_ERR(iep_service.ion_client);\r
+    } else {\r
+        dev_info(&pdev->dev, "vcodec ion client create success!\n");\r
+    }\r
+   \r
+    mmu_dev = rockchip_get_sysmmu_device_by_compatible("iommu,iep");\r
+    \r
+    if (mmu_dev) {\r
+        platform_set_sysmmu(mmu_dev, &pdev->dev);\r
+        iovmm_activate(&pdev->dev);\r
+    }\r
+    \r
+    iep_service.iommu_dev = &pdev->dev;\r
+    iep_power_off();\r
+#endif\r
 \r
     IEP_INFO("IEP Driver loaded succesfully\n");\r
 \r
index 5ebbe3fec9a5fbd9de022b6589e80ddd6e9d5c8a..39c650a6a4fd5de7c078b9adb42a59ddab98e20f 100755 (executable)
@@ -4,6 +4,17 @@
 #include <linux/device.h>\r
 #include <linux/miscdevice.h>\r
 #include <linux/mutex.h>\r
+\r
+#if defined(CONFIG_ROCKCHIP_IOMMU) && defined(CONFIG_ION_ROCKCHIP)\r
+//#define CONFIG_IEP_IOMMU\r
+#endif\r
+\r
+#ifdef CONFIG_IEP_IOMMU\r
+#include <linux/rockchip_ion.h>\r
+#include <linux/rockchip/iovmm.h>\r
+#include <linux/rockchip/sysmmu.h>\r
+#include <linux/dma-buf.h>\r
+#endif\r
 #include "iep.h"\r
 \r
 #define IEP_REG_LEN         0x100\r
@@ -131,6 +142,11 @@ typedef struct iep_service_info {
     bool                enable;\r
 \r
     struct mutex           mutex;  // mutex\r
+    \r
+#ifdef CONFIG_IEP_IOMMU\r
+    struct ion_client *ion_client;\r
+    struct device *iommu_dev;\r
+#endif \r
 } iep_service_info;\r
 \r
 struct iep_reg {\r
@@ -147,7 +163,21 @@ struct iep_reg {
     int                 vir_height;\r
     int                 layer;\r
     unsigned int        format;\r
+#if defined(CONFIG_IEP_IOMMU)    \r
+    struct list_head    mem_region_list;\r
+#endif        \r
 };\r
 \r
+#if defined(CONFIG_IEP_IOMMU)\r
+struct iep_mem_region {\r
+    struct list_head srv_lnk;\r
+    struct list_head reg_lnk;\r
+    struct list_head session_lnk;\r
+    unsigned long iova;              /* virtual address for iommu */\r
+    unsigned long len;\r
+    struct ion_handle *hdl;\r
+};\r
+#endif\r
+\r
 #endif\r
 \r