Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fecb9640 authored by Vinay Kalia's avatar Vinay Kalia Committed by Stephen Boyd
Browse files

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: default avatarVinay Kalia <vkalia@codeaurora.org>
parent 8bedd401
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -5,11 +5,20 @@ Required properties:
	- "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>;
	};
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@
		compatible = "qcom,msm-vidc";
		reg = <0xfdc00000 0xff000>;
		interrupts = <0 44 0>;
		vidc-cp-map = <0x1000000 0x40000000>;
		vidc-ns-map = <0x40000000 0x40000000>;
	};

	serial@f991f000 {
+78 −23
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
 */

#include <linux/slab.h>
#include <mach/iommu_domains.h>
#include "msm_smem.h"

struct smem_client {
@@ -19,12 +20,44 @@ struct smem_client {
	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 @@ static int ion_user_to_kernel(struct smem_client *client,
		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 @@ fail_import_fd:
}

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 @@ static int alloc_ion_mem(struct smem_client *client, size_t size,
	}
	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 @@ skip_mem_alloc:

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 @@ static void ion_delete_client(struct smem_client *client)
	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 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
	}
	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 @@ void *msm_smem_new_client(enum smem_type mtype)
	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 @@ struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
	}
	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");
+6 −4
Original line number Diff line number Diff line
@@ -24,15 +24,17 @@ struct msm_smem {
	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
+96 −5
Original line number Diff line number Diff line
@@ -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"
@@ -278,7 +280,9 @@ int msm_v4l2_prepare_buf(struct file *file, void *fh,
		}
		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[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 @@ void msm_vidc_release_video_device(struct video_device *pvdev)
{
}

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 @@ static int msm_vidc_initialize_core(struct platform_device *pdev,
	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 msm_vidc_probe(struct platform_device *pdev)
Loading