msm: vidc: Download firmware using PIL.

Video driver uses PIL and IOMMU to download video
firmware.Video firmware is downloaded during the
start of video session using PIL apis.

Change-Id: If285e9b6df57ecdfa379fa82b9eef542e6aa9bba
Signed-off-by: Vinay Kalia <vkalia@codeaurora.org>
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 2913d74..76e3592 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/slab.h>
+#include <mach/iommu_domains.h>
 #include "msm_smem.h"
 
 struct smem_client {
@@ -19,12 +20,44 @@
 	void *clnt;
 };
 
+static int get_device_address(struct ion_client *clnt,
+		struct ion_handle *hndl, int domain_num, int partition_num,
+		unsigned long align, unsigned long *iova,
+		unsigned long *buffer_size,	unsigned long flags)
+{
+	int rc;
+
+	if (!iova || !buffer_size || !hndl || !clnt) {
+		pr_err("Invalid params: %p, %p, %p, %p\n",
+				clnt, hndl, iova, buffer_size);
+		return -EINVAL;
+	}
+	if (align < 4096)
+		align = 4096;
+	flags |= UNCACHED;
+	rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
+			0, iova, buffer_size, flags, 0);
+	if (rc)
+		pr_err("ion_map_iommu failed(%d).domain: %d,partition: %d\n",
+				rc, domain_num, partition_num);
+
+	return rc;
+}
+
+static void put_device_address(struct ion_client *clnt,
+		struct ion_handle *hndl, int domain_num)
+{
+	ion_unmap_iommu(clnt, hndl, domain_num, 0);
+}
+
 static int ion_user_to_kernel(struct smem_client *client,
-			int fd, u32 offset, struct msm_smem *mem)
+			int fd, u32 offset, int domain, int partition,
+			struct msm_smem *mem)
 {
 	struct ion_handle *hndl;
 	unsigned long ionflag;
-	size_t len;
+	unsigned long iova = 0;
+	unsigned long buffer_size = 0;
 	int rc = 0;
 	hndl = ion_import_dma_buf(client->clnt, fd);
 	if (IS_ERR_OR_NULL(hndl)) {
@@ -38,25 +71,29 @@
 		pr_err("Failed to get ion flags: %d", rc);
 		goto fail_map;
 	}
-	rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
-	if (rc) {
-		pr_err("Failed to get physical address\n");
-		goto fail_map;
-	}
 	mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
 	if (!mem->kvaddr) {
 		pr_err("Failed to map shared mem in kernel\n");
 		rc = -EIO;
 		goto fail_map;
 	}
+	mem->domain = domain;
+	mem->partition_num = partition;
+	rc = get_device_address(client->clnt, hndl, mem->domain,
+		mem->partition_num, 4096, &iova, &buffer_size, UNCACHED);
+	if (rc) {
+		pr_err("Failed to get device address: %d\n", rc);
+		goto fail_device_address;
+	}
 
 	mem->kvaddr += offset;
-	mem->paddr += offset;
 	mem->mem_type = client->mem_type;
 	mem->smem_priv = hndl;
-	mem->device_addr = mem->paddr;
-	mem->size = len;
+	mem->device_addr = iova + offset;
+	mem->size = buffer_size;
 	return rc;
+fail_device_address:
+	ion_unmap_kernel(client->clnt, hndl);
 fail_map:
 	ion_free(client->clnt, hndl);
 fail_import_fd:
@@ -64,14 +101,19 @@
 }
 
 static int alloc_ion_mem(struct smem_client *client, size_t size,
-		u32 align, u32 flags, struct msm_smem *mem)
+		u32 align, u32 flags, int domain, int partition,
+		struct msm_smem *mem)
 {
 	struct ion_handle *hndl;
-	size_t len;
+	unsigned long iova = 0;
+	unsigned long buffer_size = 0;
 	int rc = 0;
 	if (size == 0)
 		goto skip_mem_alloc;
 	flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+	if (align < 4096)
+		align = 4096;
+	size = (size + 4095) & (~4095);
 	hndl = ion_alloc(client->clnt, size, align, flags);
 	if (IS_ERR_OR_NULL(hndl)) {
 		pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
@@ -81,20 +123,27 @@
 	}
 	mem->mem_type = client->mem_type;
 	mem->smem_priv = hndl;
-	if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
-		pr_err("Failed to get physical address\n");
-		rc = -EIO;
-		goto fail_map;
-	}
-	mem->device_addr = mem->paddr;
-	mem->size = size;
+	mem->domain = domain;
+	mem->partition_num = partition;
 	mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
 	if (!mem->kvaddr) {
 		pr_err("Failed to map shared mem in kernel\n");
 		rc = -EIO;
 		goto fail_map;
 	}
+	rc = get_device_address(client->clnt, hndl, mem->domain,
+		mem->partition_num, align, &iova, &buffer_size, UNCACHED);
+	if (rc) {
+		pr_err("Failed to get device address: %d\n", rc);
+		goto fail_device_address;
+	}
+	mem->device_addr = iova;
+	pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
+		mem->device_addr, mem->kvaddr);
+	mem->size = size;
 	return rc;
+fail_device_address:
+	ion_unmap_kernel(client->clnt, hndl);
 fail_map:
 	ion_free(client->clnt, hndl);
 fail_shared_mem_alloc:
@@ -104,6 +153,8 @@
 
 static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
 {
+	put_device_address(client->clnt,
+		mem->smem_priv, mem->domain);
 	ion_unmap_kernel(client->clnt, mem->smem_priv);
 	ion_free(client->clnt, mem->smem_priv);
 }
@@ -122,7 +173,8 @@
 	ion_client_destroy(client->clnt);
 }
 
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+	int domain, int partition)
 {
 	struct smem_client *client = clt;
 	int rc = 0;
@@ -138,7 +190,8 @@
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = ion_user_to_kernel(clt, fd, offset, mem);
+		rc = ion_user_to_kernel(clt, fd, offset,
+			domain, partition, mem);
 		break;
 	default:
 		pr_err("Mem type not supported\n");
@@ -177,7 +230,8 @@
 	return client;
 };
 
-struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+		int domain, int partition)
 {
 	struct smem_client *client;
 	int rc = 0;
@@ -195,7 +249,8 @@
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = alloc_ion_mem(client, size, align, flags, mem);
+		rc = alloc_ion_mem(client, size, align, flags,
+			domain, partition, mem);
 		break;
 	default:
 		pr_err("Mem type not supported\n");