diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 3c96f46cf567..5ed2ec0b97ec 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -38,6 +38,8 @@ struct qcom_ubwc_cfg_data; * @dev: reference to device structure * @np_dev: reference to non-pixel device structure * @p_dev: reference to pixel device structure + * @fw_dev: reference to firmware device structure + * @pas_ctx: PAS context for authenticated firmware load and shutdown * @reg_base: IO memory base address * @irq: iris irq * @v4l2_dev: a holder for v4l2 device structure @@ -85,6 +87,8 @@ struct iris_core { struct device *dev; struct device *np_dev; struct device *p_dev; + struct device *fw_dev; + struct qcom_pas_context *pas_ctx; void __iomem *reg_base; int irq; struct v4l2_device v4l2_dev; diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 1a476146d758..56c477b36b61 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -4,7 +4,9 @@ */ #include +#include #include +#include #include #include #include @@ -15,11 +17,14 @@ #define IRIS_PAS_ID 9 #define MAX_FIRMWARE_NAME_SIZE 128 +#define IRIS_FW_START_ADDR 0 static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) { + struct device *fw_dev = core->fw_dev ? core->fw_dev : core->dev; const struct firmware *firmware = NULL; - struct device *dev = core->dev; + struct qcom_pas_context *ctx; + struct iommu_domain *domain; struct resource res; phys_addr_t mem_phys; size_t res_size; @@ -30,14 +35,21 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) return -EINVAL; - ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + ret = of_reserved_mem_region_to_resource(core->dev->of_node, 0, &res); if (ret) return ret; mem_phys = res.start; res_size = resource_size(&res); - ret = request_firmware(&firmware, fw_name, dev); + if (!core->pas_ctx) { + ctx = devm_qcom_pas_context_alloc(core->dev, IRIS_PAS_ID, mem_phys, res_size); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + core->pas_ctx = ctx; + } + + ret = request_firmware(&firmware, fw_name, fw_dev); if (ret) return ret; @@ -53,9 +65,23 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) goto err_release_fw; } - ret = qcom_mdt_load(dev, firmware, fw_name, - IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL); + core->pas_ctx->use_tzmem = !!core->fw_dev; + ret = qcom_mdt_pas_load(core->pas_ctx, firmware, fw_name, mem_virt, NULL); + if (ret) + goto err_mem_unmap; + if (core->pas_ctx->use_tzmem) { + domain = iommu_get_domain_for_dev(fw_dev); + if (!domain) { + ret = -ENODEV; + goto err_mem_unmap; + } + + ret = iommu_map(domain, IRIS_FW_START_ADDR, mem_phys, res_size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + } + +err_mem_unmap: memunmap(mem_virt); err_release_fw: release_firmware(firmware); @@ -63,6 +89,18 @@ err_release_fw: return ret; } +static void iris_fw_iommu_unmap(struct iris_core *core) +{ + struct iommu_domain *domain; + + if (!core->fw_dev) + return; + + domain = iommu_get_domain_for_dev(core->fw_dev); + if (domain) + iommu_unmap(domain, IRIS_FW_START_ADDR, core->pas_ctx->mem_size); +} + int iris_fw_load(struct iris_core *core) { const struct tz_cp_config *cp_config; @@ -77,13 +115,13 @@ int iris_fw_load(struct iris_core *core) ret = iris_load_fw_to_memory(core, fwpath); if (ret) { dev_err(core->dev, "firmware download failed\n"); - return -ENOMEM; + return ret; } - ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID); + ret = qcom_pas_prepare_and_auth_reset(core->pas_ctx); if (ret) { dev_err(core->dev, "auth and reset failed: %d\n", ret); - return ret; + goto err_unmap; } for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { @@ -94,20 +132,31 @@ int iris_fw_load(struct iris_core *core) cp_config->cp_nonpixel_size); if (ret) { dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret); - qcom_scm_pas_shutdown(IRIS_PAS_ID); - return ret; + goto err_pas_shutdown; } } + return 0; + +err_pas_shutdown: + qcom_pas_shutdown(IRIS_PAS_ID); +err_unmap: + iris_fw_iommu_unmap(core); + return ret; } int iris_fw_unload(struct iris_core *core) { - return qcom_scm_pas_shutdown(IRIS_PAS_ID); + int ret; + + ret = qcom_pas_shutdown(IRIS_PAS_ID); + iris_fw_iommu_unmap(core); + + return ret; } int iris_set_hw_state(struct iris_core *core, bool resume) { - return qcom_scm_set_remote_state(resume, 0); + return qcom_pas_set_remote_state(resume, 0); }