diff options
Diffstat (limited to 'drivers/media/platform/qcom/venus/firmware.c')
-rw-r--r-- | drivers/media/platform/qcom/venus/firmware.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c new file mode 100644 index 000000000000..1b1a4f355918 --- /dev/null +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/dma-mapping.h> +#include <linux/firmware.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_reserved_mem.h> +#include <linux/slab.h> +#include <linux/qcom_scm.h> +#include <linux/soc/qcom/mdt_loader.h> + +#include "firmware.h" + +#define VENUS_PAS_ID 9 +#define VENUS_FW_MEM_SIZE SZ_8M + +static void device_release_dummy(struct device *dev) +{ + of_reserved_mem_device_release(dev); +} + +int venus_boot(struct device *parent, struct device *fw_dev, const char *fwname) +{ + const struct firmware *mdt; + phys_addr_t mem_phys; + ssize_t fw_size; + size_t mem_size; + void *mem_va; + int ret; + + if (!qcom_scm_is_available()) + return -EPROBE_DEFER; + + fw_dev->parent = parent; + fw_dev->release = device_release_dummy; + + ret = dev_set_name(fw_dev, "%s:%s", dev_name(parent), "firmware"); + if (ret) + return ret; + + ret = device_register(fw_dev); + if (ret < 0) + return ret; + + ret = of_reserved_mem_device_init_by_idx(fw_dev, parent->of_node, 0); + if (ret) + goto err_unreg_device; + + mem_size = VENUS_FW_MEM_SIZE; + + mem_va = dmam_alloc_coherent(fw_dev, mem_size, &mem_phys, GFP_KERNEL); + if (!mem_va) { + ret = -ENOMEM; + goto err_unreg_device; + } + + ret = request_firmware(&mdt, fwname, fw_dev); + if (ret < 0) + goto err_unreg_device; + + fw_size = qcom_mdt_get_size(mdt); + if (fw_size < 0) { + ret = fw_size; + release_firmware(mdt); + goto err_unreg_device; + } + + ret = qcom_mdt_load(fw_dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, + mem_size); + + release_firmware(mdt); + + if (ret) + goto err_unreg_device; + + ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); + if (ret) + goto err_unreg_device; + + return 0; + +err_unreg_device: + device_unregister(fw_dev); + return ret; +} + +int venus_shutdown(struct device *fw_dev) +{ + int ret; + + ret = qcom_scm_pas_shutdown(VENUS_PAS_ID); + device_unregister(fw_dev); + memset(fw_dev, 0, sizeof(*fw_dev)); + + return ret; +} |