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/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 11af7a9..dbbe46d 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -5,11 +5,20 @@
 	- "qcom,msm-vidc"
 - reg : offset and length of the register set for the device.
 - interrupts : should contain the vidc interrupt.
+- vidc-cp-map : start and size of device virtual address range for secure buffers.
+  Video hardware uses this address range to identify if the buffers are secure
+  or non-secure.
+- vidc-ns-map : start and size of device virtual address range for non-secure buffers.
+  Video hardware uses this address range to identify if the buffers are secure
+  or non-secure.
 
 Example:
 
+
 	qcom,vidc@fdc00000 {
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
 		interrupts = <0 44 0>;
+		vidc-cp-map = <0x1000000 0x40000000>;
+		vidc-ns-map = <0x40000000 0x40000000>;
 	};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 8426b52..2eb8216 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -46,6 +46,8 @@
 		compatible = "qcom,msm-vidc";
 		reg = <0xfdc00000 0xff000>;
 		interrupts = <0 44 0>;
+		vidc-cp-map = <0x1000000 0x40000000>;
+		vidc-ns-map = <0x40000000 0x40000000>;
 	};
 
 	serial@f991f000 {
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");
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
index 84d12cc..b742c79 100644
--- a/drivers/media/video/msm_vidc/msm_smem.h
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -24,15 +24,17 @@
 	int mem_type;
 	size_t size;
 	void *kvaddr;
-	unsigned long paddr;
 	unsigned long device_addr;
-	/*Device address and others to follow*/
+	int domain;
+	int partition_num;
 	void *smem_priv;
 };
 
 void *msm_smem_new_client(enum smem_type mtype);
-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);
 void msm_smem_free(void *clt, struct msm_smem *mem);
 void msm_smem_delete_client(void *clt);
-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);
 #endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 6cd9e6b..e1a71ce 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -21,7 +21,9 @@
 #include <linux/debugfs.h>
 #include <linux/version.h>
 #include <linux/slab.h>
-
+#include <linux/of.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
 #include <media/msm_vidc.h>
 #include "msm_vidc_internal.h"
 #include "vidc_hal_api.h"
@@ -277,8 +279,10 @@
 			goto exit;
 		}
 		handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
-				b->m.planes[i].reserved[0],
-				b->m.planes[i].reserved[1]);
+			b->m.planes[i].reserved[0],
+			b->m.planes[i].reserved[1],
+			vidc_inst->core->resources.io_map[NS_MAP].domain,
+			0);
 		if (!handle) {
 			pr_err("Failed to get device buffer address\n");
 			kfree(binfo);
@@ -420,11 +424,92 @@
 {
 }
 
+static size_t read_u32_array(struct platform_device *pdev,
+		char *name, u32 *arr, size_t size)
+{
+	int len;
+	size_t sz = 0;
+	struct device_node *np = pdev->dev.of_node;
+	if (!of_get_property(np, name, &len)) {
+		pr_err("Failed to read %s from device tree\n",
+			name);
+		goto fail_read;
+	}
+	sz = len / sizeof(u32);
+	if (sz <= 0) {
+		pr_err("%s not specified in device tree\n", name);
+		goto fail_read;
+	}
+	if (sz > size) {
+		pr_err("Not enough memory to store %s values\n", name);
+		goto fail_read;
+	}
+	if (of_property_read_u32_array(np, name, arr, sz)) {
+		pr_err("error while reading %s from device tree\n",
+			name);
+		goto fail_read;
+	}
+	return sz;
+fail_read:
+	sz = 0;
+	return sz;
+}
+
+static int register_iommu_domains(struct platform_device *pdev,
+	struct msm_vidc_core *core)
+{
+	size_t len;
+	struct msm_iova_partition partition;
+	struct msm_iova_layout layout;
+	int rc = 0;
+	int i;
+	struct iommu_info *io_map = core->resources.io_map;
+	strlcpy(io_map[CP_MAP].name, "vidc-cp-map",
+			sizeof(io_map[CP_MAP].name));
+	strlcpy(io_map[CP_MAP].ctx, "venus_cp",
+			sizeof(io_map[CP_MAP].ctx));
+	strlcpy(io_map[NS_MAP].name, "vidc-ns-map",
+			sizeof(io_map[NS_MAP].name));
+	strlcpy(io_map[NS_MAP].ctx, "venus_ns",
+			sizeof(io_map[NS_MAP].ctx));
+
+	for (i = 0; i < MAX_MAP; i++) {
+		len = read_u32_array(pdev, io_map[i].name,
+				io_map[i].addr_range,
+				(sizeof(io_map[i].addr_range)/sizeof(u32)));
+		if (!len) {
+			pr_err("Error in reading cp address range\n");
+			rc = -EINVAL;
+			break;
+		}
+		partition.start = io_map[i].addr_range[0];
+		partition.size = io_map[i].addr_range[1];
+		layout.partitions = &partition;
+		layout.npartitions = 1;
+		layout.client_name = io_map[i].name;
+		layout.domain_flags = 0;
+		pr_debug("Registering domain with: %lx, %lx, %s\n",
+			partition.start, partition.size, layout.client_name);
+		io_map[i].domain = msm_register_domain(&layout);
+		if (io_map[i].domain < 0) {
+			pr_err("Failed to register cp domain\n");
+			rc = -EINVAL;
+			break;
+		}
+	}
+	/* There is no api provided as msm_unregister_domain, so
+	 * we are not able to unregister the previously
+	 * registered domains if any domain registration fails.*/
+	BUG_ON(i < MAX_MAP);
+	return rc;
+}
+
 static int msm_vidc_initialize_core(struct platform_device *pdev,
 				struct msm_vidc_core *core)
 {
 	struct resource *res;
 	int i = 0;
+	int rc = 0;
 	if (!core)
 		return -EINVAL;
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -443,13 +528,19 @@
 	INIT_LIST_HEAD(&core->instances);
 	mutex_init(&core->sync_lock);
 	spin_lock_init(&core->lock);
-	core->base_addr = 0x14f00000;
+	core->base_addr = 0x0;
 	core->state = VIDC_CORE_UNINIT;
 	for (i = SYS_MSG_INDEX(SYS_MSG_START);
 		i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
 		init_completion(&core->completions[i]);
 	}
-	return 0;
+	rc = register_iommu_domains(pdev, core);
+	if (rc) {
+		pr_err("Failed to register iommu domains: %d\n", rc);
+		goto fail_domain_register;
+	}
+fail_domain_register:
+	return rc;
 }
 
 static int __devinit msm_vidc_probe(struct platform_device *pdev)
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index a2e42e6..a8c6428 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -309,8 +309,21 @@
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
 				b->m.planes[i].m.userptr;
-			buffer_info.extradata_size = 0;
-			buffer_info.extradata_addr = 0;
+			if (!inst->extradata_handle) {
+				inst->extradata_handle =
+				msm_smem_alloc(inst->mem_client,
+				4096 * 1024, 1, 0,
+				inst->core->resources.io_map[NS_MAP].domain,
+				0);
+				if (!inst->extradata_handle) {
+					pr_err("Failed to allocate extradta memory\n");
+					rc = -ENOMEM;
+					break;
+				}
+			}
+			buffer_info.extradata_addr =
+				inst->extradata_handle->device_addr;
+			buffer_info.extradata_size = 4096 * 1024;
 			rc = vidc_hal_session_set_buffers((void *)inst->session,
 					&buffer_info);
 			if (rc) {
@@ -346,7 +359,8 @@
 			buffer_info.num_buffers = 1;
 			buffer_info.align_device_addr =
 				 b->m.planes[i].m.userptr;
-			buffer_info.extradata_addr = 0;
+			buffer_info.extradata_addr =
+				inst->extradata_handle->device_addr;
 			rc = vidc_hal_session_release_buffers(
 				(void *)inst->session, &buffer_info);
 			if (rc)
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 28fe2b8..4d4cec5 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -316,6 +316,8 @@
 				kfree(buf);
 			}
 		}
+		if (inst->extradata_handle)
+			msm_smem_free(inst->mem_client, inst->extradata_handle);
 		spin_unlock_irqrestore(&inst->lock, flags);
 		msm_smem_delete_client(inst->mem_client);
 	}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 261879d..cd330316 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -13,6 +13,10 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/iommu.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/peripheral-loader.h>
 
 #include "msm_vidc_common.h"
 #include "vidc_hal_api.h"
@@ -52,6 +56,60 @@
 	return NULL;
 }
 
+static int msm_comm_iommu_attach(struct msm_vidc_core *core)
+{
+	int rc;
+	struct iommu_domain *domain;
+	int i;
+	struct iommu_info *io_map;
+	struct device *dev;
+	for (i = 0; i < MAX_MAP; i++) {
+		io_map = &core->resources.io_map[i];
+		dev = msm_iommu_get_ctx(io_map->ctx);
+		domain = msm_get_iommu_domain(io_map->domain);
+		if (IS_ERR_OR_NULL(domain)) {
+			pr_err("Failed to get domain: %s\n", io_map->name);
+			rc = PTR_ERR(domain);
+			break;
+		}
+		rc = iommu_attach_device(domain, dev);
+		if (rc) {
+			pr_err("IOMMU attach failed: %s\n", io_map->name);
+			break;
+		}
+	}
+	if (i < MAX_MAP) {
+		i--;
+		for (; i >= 0; i--) {
+			io_map = &core->resources.io_map[i];
+			dev = msm_iommu_get_ctx(io_map->ctx);
+			domain = msm_get_iommu_domain(io_map->domain);
+			if (dev && domain)
+				iommu_detach_device(domain, dev);
+		}
+	}
+	return rc;
+}
+
+static void msm_comm_iommu_detach(struct msm_vidc_core *core)
+{
+	struct device *dev;
+	struct iommu_domain *domain;
+	struct iommu_info *io_map;
+	int i;
+	if (!core) {
+		pr_err("Invalid paramter: %p\n", core);
+		return;
+	}
+	for (i = 0; i < MAX_MAP; i++) {
+		io_map = &core->resources.io_map[i];
+		dev = msm_iommu_get_ctx(io_map->ctx);
+		domain = msm_get_iommu_domain(io_map->domain);
+		if (dev && domain)
+			iommu_detach_device(domain, dev);
+	}
+}
+
 const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
 	const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
 {
@@ -454,6 +512,47 @@
 		break;
 	}
 }
+static int msm_comm_load_fw(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	if (!core) {
+		pr_err("Invalid paramter: %p\n", core);
+		return -EINVAL;
+	}
+
+	if (!core->resources.fw.cookie)
+		core->resources.fw.cookie = pil_get("venus");
+
+	if (IS_ERR_OR_NULL(core->resources.fw.cookie)) {
+		pr_err("Failed to download firmware\n");
+		rc = -ENOMEM;
+		goto fail_pil_get;
+	}
+	rc = msm_comm_iommu_attach(core);
+	if (rc) {
+		pr_err("Failed to attach iommu");
+		goto fail_iommu_attach;
+	}
+	return rc;
+fail_iommu_attach:
+	pil_put(core->resources.fw.cookie);
+	core->resources.fw.cookie = NULL;
+fail_pil_get:
+	return rc;
+}
+
+static void msm_comm_unload_fw(struct msm_vidc_core *core)
+{
+	if (!core) {
+		pr_err("Invalid paramter: %p\n", core);
+		return;
+	}
+	if (core->resources.fw.cookie) {
+		pil_put(core->resources.fw.cookie);
+		core->resources.fw.cookie = NULL;
+		msm_comm_iommu_detach(core);
+	}
+}
 
 static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
 {
@@ -499,18 +598,28 @@
 				core->id, core->state);
 		goto core_already_inited;
 	}
+	rc = msm_comm_load_fw(core);
+	if (rc) {
+		pr_err("Failed to load video firmware\n");
+		goto fail_fw_download;
+	}
 	init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
-	rc = vidc_hal_core_init(core->device);
+	rc = vidc_hal_core_init(core->device,
+		core->resources.io_map[NS_MAP].domain);
 	if (rc) {
 		pr_err("Failed to init core, id = %d\n", core->id);
-		goto exit;
+		goto fail_core_init;
 	}
 	spin_lock_irqsave(&core->lock, flags);
 	core->state = VIDC_CORE_INIT;
 	spin_unlock_irqrestore(&core->lock, flags);
 core_already_inited:
 	change_inst_state(inst, MSM_VIDC_CORE_INIT);
-exit:
+	mutex_unlock(&core->sync_lock);
+	return rc;
+fail_core_init:
+	msm_comm_unload_fw(core);
+fail_fw_download:
 	mutex_unlock(&core->sync_lock);
 	return rc;
 }
@@ -536,6 +645,7 @@
 		spin_lock_irqsave(&core->lock, flags);
 		core->state = VIDC_CORE_UNINIT;
 		spin_unlock_irqrestore(&core->lock, flags);
+		msm_comm_unload_fw(core);
 	}
 core_already_uninited:
 	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
@@ -889,9 +999,16 @@
 		} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 			frame_data.filled_len = 0;
 			frame_data.buffer_type = HAL_BUFFER_OUTPUT;
-			frame_data.extradata_addr = 0;
-			pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d\n",
+			if (inst->extradata_handle) {
+				frame_data.extradata_addr =
+					inst->extradata_handle->device_addr;
+			} else {
+				frame_data.extradata_addr = 0;
+			}
+			pr_debug("Sending ftb to hal..: Alloc: %d :filled: %d",
 				frame_data.alloc_len, frame_data.filled_len);
+			pr_debug(" extradata_addr: %d\n",
+				frame_data.extradata_addr);
 			rc = vidc_hal_session_ftb((void *) inst->session,
 					&frame_data);
 		} else {
@@ -1020,7 +1137,8 @@
 	for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
 				i++) {
 		handle = msm_smem_alloc(inst->mem_client,
-				inst->buff_req.buffer[6].buffer_size, 1, 0);
+				inst->buff_req.buffer[6].buffer_size, 1, 0,
+				inst->core->resources.io_map[NS_MAP].domain, 0);
 		if (!handle) {
 			pr_err("Failed to allocate scratch memory\n");
 			rc = -ENOMEM;
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index fb8fbc4..151fb21 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -106,6 +106,29 @@
 	struct video_device vdev;
 };
 
+struct msm_vidc_fw {
+	void *cookie;
+};
+
+struct iommu_info {
+	u32 addr_range[2];
+	char name[64];
+	char ctx[64];
+	int domain;
+	int partition;
+};
+
+enum io_maps {
+	CP_MAP,
+	NS_MAP,
+	MAX_MAP
+};
+
+struct msm_vidc_resources {
+	struct msm_vidc_fw fw;
+	struct iommu_info io_map[MAX_MAP];
+};
+
 struct msm_vidc_core {
 	struct list_head list;
 	struct mutex sync_lock;
@@ -121,6 +144,7 @@
 	u32 register_size;
 	u32 irq;
 	enum vidc_core_state state;
+	struct msm_vidc_resources resources;
 	struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
 };
 
@@ -146,6 +170,7 @@
 	bool in_reconfig;
 	u32 reconfig_width;
 	u32 reconfig_height;
+	struct msm_smem *extradata_handle;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 0372f90..9052a63 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -23,7 +23,7 @@
 #define REG_ADDR_OFFSET_BITMASK	0x000FFFFF
 
 /*Workaround for virtio */
-#define HFI_VIRTIO_FW_BIAS		0x14f00000
+#define HFI_VIRTIO_FW_BIAS		0x0
 
 struct hal_device_data hal_ctxt;
 
@@ -300,7 +300,8 @@
 	return 0;
 }
 
-static int vidc_hal_alloc(void *mem, void *clnt, u32 size, u32 align, u32 flags)
+static int vidc_hal_alloc(void *mem, void *clnt, u32 size, u32 align, u32 flags,
+		int domain)
 {
 	struct vidc_mem_addr *vmem;
 	struct msm_smem *alloc;
@@ -312,7 +313,7 @@
 	vmem = (struct vidc_mem_addr *)mem;
 	HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
 
-	alloc  = msm_smem_alloc(clnt, size, align, flags);
+	alloc  = msm_smem_alloc(clnt, size, align, flags, domain, 0);
 	HAL_MSG_LOW("Alloc done");
 	if (!alloc) {
 		HAL_MSG_HIGH("Alloc fail in %s", __func__);
@@ -503,7 +504,7 @@
 	device->hal_client = NULL;
 }
 
-static int vidc_hal_interface_queues_init(struct hal_device *dev)
+static int vidc_hal_interface_queues_init(struct hal_device *dev, int domain)
 {
 	struct hfi_queue_table_header *q_tbl_hdr;
 	struct hfi_queue_header *q_hdr;
@@ -513,7 +514,7 @@
 
 	rc = vidc_hal_alloc((void *) &dev->iface_q_table,
 					dev->hal_client,
-			VIDC_IFACEQ_TABLE_SIZE, 1, 0);
+			VIDC_IFACEQ_TABLE_SIZE, 1, 0, domain);
 	if (rc) {
 		HAL_MSG_ERROR("%s:iface_q_table_alloc_fail", __func__);
 		return -ENOMEM;
@@ -533,7 +534,7 @@
 		iface_q = &dev->iface_queues[i];
 		rc = vidc_hal_alloc((void *) &iface_q->q_array,
 				dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
-				1, 0);
+				1, 0, domain);
 		if (rc) {
 			HAL_MSG_ERROR("%s:iface_q_table_alloc[%d]_fail",
 						__func__, i);
@@ -592,7 +593,7 @@
 	return rc;
 }
 
-int vidc_hal_core_init(void *device)
+int vidc_hal_core_init(void *device, int domain)
 {
 	struct hfi_cmd_sys_init_packet pkt;
 	int rc = 0;
@@ -619,10 +620,10 @@
 
 		HAL_MSG_ERROR("Device_Virt_Address : 0x%x,"
 		"Register_Virt_Addr: 0x%x",
-		(u32) dev->hal_data->device_base_addr,
+		dev->hal_data->device_base_addr,
 		(u32) dev->hal_data->register_base_addr);
 
-		rc = vidc_hal_interface_queues_init(dev);
+		rc = vidc_hal_interface_queues_init(dev, domain);
 		if (rc) {
 			HAL_MSG_ERROR("failed to init queues");
 			rc = -ENOMEM;
@@ -1989,11 +1990,11 @@
 		list_for_each_safe(curr, next, &core.dev_head) {
 			device = list_entry(curr, struct hal_device, list);
 			if (device && device->hal_data->irq == irq &&
-				(CONTAINS((u32)device->hal_data->
+				(CONTAINS(device->hal_data->
 						device_base_addr,
 						FIRMWARE_SIZE, fw_addr) ||
 				CONTAINS(fw_addr, FIRMWARE_SIZE,
-						(u32)device->hal_data->
+						device->hal_data->
 						device_base_addr) ||
 				CONTAINS((u32)device->hal_data->
 						register_base_addr,
@@ -2007,12 +2008,12 @@
 				OVERLAPS(reg_addr, reg_size,
 						(u32)device->hal_data->
 						register_base_addr, reg_size) ||
-				OVERLAPS((u32)device->hal_data->
+				OVERLAPS(device->hal_data->
 						device_base_addr,
 						FIRMWARE_SIZE, fw_addr,
 						FIRMWARE_SIZE) ||
 				OVERLAPS(fw_addr, FIRMWARE_SIZE,
-						(u32)device->hal_data->
+						device->hal_data->
 						device_base_addr,
 						FIRMWARE_SIZE))) {
 				return 0;
@@ -2062,7 +2063,7 @@
 	struct hal_data *hal = NULL;
 	int rc = 0;
 
-	if (device_id || !fw_base_addr || !reg_base || !reg_size ||
+	if (device_id || !reg_base || !reg_size ||
 			!irq || !callback) {
 		HAL_MSG_ERROR("Invalid Paramters");
 		return NULL;
@@ -2080,13 +2081,7 @@
 			return NULL;
 		}
 		hal->irq = irq;
-		hal->device_base_addr =
-			ioremap_nocache(fw_base_addr, FIRMWARE_SIZE);
-		if (!hal->device_base_addr) {
-			HAL_MSG_ERROR("could not map fw addr %d of size %d",
-						  fw_base_addr, FIRMWARE_SIZE);
-			goto err_map;
-		}
+		hal->device_base_addr = fw_base_addr;
 		hal->register_base_addr =
 			ioremap_nocache(reg_base, reg_size);
 		if (!hal->register_base_addr) {
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 6c7e5df..8e7c3d3 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -834,7 +834,7 @@
 
 struct hal_data {
 	u32 irq;
-	u8 *device_base_addr;
+	u32 device_base_addr;
 	u8 *register_base_addr;
 };
 
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 332bbac..c77ae12 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -943,7 +943,7 @@
 };
 
 /* VIDC_HAL CORE API's */
-int vidc_hal_core_init(void *device);
+int vidc_hal_core_init(void *device, int domain);
 int vidc_hal_core_release(void *device);
 int vidc_hal_core_pc_prep(void *device);
 int vidc_hal_core_set_resource(void *device,