diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 35787c2f42758..8b0629d57acdc 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -124,6 +124,12 @@ struct iris_core { /* encoder and decoder have overlapping caps, so two different arrays are required */ struct platform_inst_fw_cap inst_fw_caps_dec[INST_FW_CAP_MAX]; struct platform_inst_fw_cap inst_fw_caps_enc[INST_FW_CAP_MAX]; + bool use_tz; + struct video_firmware { + struct platform_device *pdev; + struct iommu_domain *iommu_domain; + size_t mapped_mem_size; + } fw; }; int iris_core_init(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 64a2170bf538a..05e437fdd9105 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include #include @@ -93,6 +95,45 @@ static const struct firmware *iris_detect_firmware(struct iris_core *core, return firmware; } +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 + +#define WRAPPER_TZ_XTSS_SW_RESET (WRAPPER_TZ_BASE_OFFS + 0x1000) +#define WRAPPER_XTSS_SW_RESET_BIT BIT(0) + +#define WRAPPER_CPA_START_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1020) +#define WRAPPER_CPA_END_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1024) +#define WRAPPER_FW_START_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1028) +#define WRAPPER_FW_END_ADDR (WRAPPER_TZ_BASE_OFFS + 0x102C) +#define WRAPPER_NONPIX_START_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1030) +#define WRAPPER_NONPIX_END_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1034) + +#define IRIS_FW_START_ADDR 0x0 + +static void iris_reset_cpu_no_tz(struct iris_core *core) +{ + u32 fw_size = core->fw.mapped_mem_size; + + writel(0, core->reg_base + WRAPPER_FW_START_ADDR); + writel(fw_size, core->reg_base + WRAPPER_FW_END_ADDR); + writel(0, core->reg_base + WRAPPER_CPA_START_ADDR); + writel(fw_size, core->reg_base + WRAPPER_CPA_END_ADDR); + writel(fw_size, core->reg_base + WRAPPER_NONPIX_START_ADDR); + writel(fw_size, core->reg_base + WRAPPER_NONPIX_END_ADDR); + + /* Bring XTSS out of reset */ + writel(0, core->reg_base + WRAPPER_TZ_XTSS_SW_RESET); +} + +static int iris_set_hw_state_no_tz(struct iris_core *core, bool resume) +{ + if (resume) + iris_reset_cpu_no_tz(core); + else + writel(WRAPPER_XTSS_SW_RESET_BIT, core->reg_base + WRAPPER_TZ_XTSS_SW_RESET); + + return 0; +} + static int iris_load_fw_to_memory(struct iris_core *core) { const struct firmware *firmware = NULL; @@ -130,10 +171,29 @@ static int iris_load_fw_to_memory(struct iris_core *core) goto err_release_fw; } - ret = qcom_mdt_load(dev, firmware, fw_name, - IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL); + if (core->use_tz) + ret = qcom_mdt_load(dev, firmware, fw_name, + IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL); + else + ret = qcom_mdt_load_no_init(dev, firmware, fw_name, + mem_virt, mem_phys, res_size, NULL); + /* Unmap memory on our side before we give firmware access to it */ memunmap(mem_virt); + if (ret) + goto err_release_fw; + + if (core->fw.iommu_domain) { + ret = iommu_map(core->fw.iommu_domain, IRIS_FW_START_ADDR, mem_phys, res_size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + if (ret) { + dev_err(core->dev, "failed to map firmware in IOMMU: %d\n", ret); + goto err_release_fw; + } + + core->fw.mapped_mem_size = res_size; + } + err_release_fw: release_firmware(firmware); @@ -151,23 +211,28 @@ int iris_fw_load(struct iris_core *core) return ret; } - ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID); - if (ret) { - dev_err(core->dev, "auth and reset failed: %d\n", ret); - return ret; - } - - for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { - cp_config = &core->iris_platform_data->tz_cp_config_data[i]; - ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, - cp_config->cp_size, - cp_config->cp_nonpixel_start, - 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); + if (core->use_tz) { + ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID); + if (ret) { + dev_err(core->dev, "auth and reset failed: %d\n", ret); return ret; } + + for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { + cp_config = &core->iris_platform_data->tz_cp_config_data[i]; + ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, + cp_config->cp_size, + cp_config->cp_nonpixel_start, + 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; + } + } + } else { + iris_reset_cpu_no_tz(core); } return 0; @@ -175,10 +240,98 @@ int iris_fw_load(struct iris_core *core) int iris_fw_unload(struct iris_core *core) { - return qcom_scm_pas_shutdown(IRIS_PAS_ID); + int ret; + + if (core->use_tz) + ret = qcom_scm_pas_shutdown(IRIS_PAS_ID); + else + ret = iris_set_hw_state_no_tz(core, false); + + if (core->fw.mapped_mem_size) { + size_t unmapped = iommu_unmap(core->fw.iommu_domain, IRIS_FW_START_ADDR, + core->fw.mapped_mem_size); + + if (unmapped != core->fw.mapped_mem_size) + dev_err(core->dev, "failed to unmap firmware in IOMMU\n"); + + core->fw.mapped_mem_size = 0; + } + + return ret; } int iris_set_hw_state(struct iris_core *core, bool resume) { - return qcom_scm_set_remote_state(resume, 0); + if (core->use_tz) + return qcom_scm_set_remote_state(resume, 0); + else + return iris_set_hw_state_no_tz(core, resume); +} + +int iris_fw_init(struct iris_core *core) +{ + struct iommu_domain *iommu_domain; + struct platform_device_info info; + struct platform_device *pdev; + struct device_node *np; + int ret; + + np = of_get_child_by_name(core->dev->of_node, "video-firmware"); + if (!np) { + core->use_tz = true; + return 0; + } + + memset(&info, 0, sizeof(info)); + info.parent = core->dev; + info.fwnode = &np->fwnode; + info.name = np->name; + info.dma_mask = DMA_BIT_MASK(32); + + pdev = platform_device_register_full(&info); + if (IS_ERR(pdev)) { + of_node_put(np); + return PTR_ERR(pdev); + } + + ret = of_dma_configure(&pdev->dev, np, true); + of_node_put(np); + if (ret) { + dev_err(&pdev->dev, "failed to configure dma: %d\n", ret); + goto err_unregister; + } + + iommu_domain = iommu_paging_domain_alloc(&pdev->dev); + if (IS_ERR(iommu_domain)) { + dev_err(&pdev->dev, "failed to allocate iommu domain: %pe\n", iommu_domain); + ret = PTR_ERR(iommu_domain); + goto err_unregister; + } + + ret = iommu_attach_device(iommu_domain, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "could not attach device to IOMMU: %d\n", ret); + goto err_iommu_free; + } + + core->fw.pdev = pdev; + core->fw.iommu_domain = iommu_domain; + + return 0; + +err_iommu_free: + iommu_domain_free(iommu_domain); +err_unregister: + platform_device_unregister(pdev); + return ret; +} + +void iris_fw_deinit(struct iris_core *core) +{ + if (!core->fw.iommu_domain) + return; + + iommu_detach_device(core->fw.iommu_domain, &core->fw.pdev->dev); + iommu_domain_free(core->fw.iommu_domain); + platform_device_unregister(core->fw.pdev); } diff --git a/drivers/media/platform/qcom/iris/iris_firmware.h b/drivers/media/platform/qcom/iris/iris_firmware.h index e833ecd348871..1a077a587c805 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.h +++ b/drivers/media/platform/qcom/iris/iris_firmware.h @@ -12,4 +12,7 @@ int iris_fw_load(struct iris_core *core); int iris_fw_unload(struct iris_core *core); int iris_set_hw_state(struct iris_core *core, bool resume); +int iris_fw_init(struct iris_core *core); +void iris_fw_deinit(struct iris_core *core); + #endif diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 8b9d0c1fd2375..2e7408ae69904 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -14,6 +14,7 @@ #include "iris_core.h" #include "iris_ctrls.h" +#include "iris_firmware.h" #include "iris_vidc.h" static int iris_init_icc(struct iris_core *core) @@ -207,6 +208,8 @@ static void iris_remove(struct platform_device *pdev) v4l2_device_unregister(&core->v4l2_dev); + iris_fw_deinit(core); + mutex_destroy(&core->lock); } @@ -271,6 +274,10 @@ static int iris_probe(struct platform_device *pdev) if (ret) return ret; + ret = iris_fw_init(core); + if (ret) + return ret; + ret = v4l2_device_register(dev, &core->v4l2_dev); if (ret) return ret;