From 895a251832f2e73c067a64872fb2041936124a1c Mon Sep 17 00:00:00 2001 From: Gourav Kumar Date: Thu, 17 Sep 2026 12:20:03 +0530 Subject: [PATCH 1/8] Revert "PENDING: media: qcom: venus: support PAS boot and flexible IOMMU handling" This reverts commit bfab35ed24034deed5d01ab0dbfde7b4d5f1b831. Signed-off-by: Gourav Kumar --- drivers/media/platform/qcom/venus/core.h | 2 - drivers/media/platform/qcom/venus/firmware.c | 294 +++++-------------- 2 files changed, 79 insertions(+), 217 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 2d5a8a690d373..46705a6667762 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -223,8 +223,6 @@ struct venus_core { size_t mapped_mem_size; phys_addr_t mem_phys; size_t mem_size; - struct qcom_pas_context *ctx; - bool iommu_domain_owned; } fw; struct mutex lock; struct list_head instances; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index faede668d0b19..3a38ff985822f 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "core.h" #include "firmware.h" @@ -80,125 +79,87 @@ int venus_set_hw_state(struct venus_core *core, bool resume) return 0; } -static int venus_load_fw_prepare(struct venus_core *core, const char *fwname, - phys_addr_t *mem_phys, size_t *res_size, - const struct firmware **mdt) +static int venus_load_fw(struct venus_core *core, const char *fwname, + phys_addr_t *mem_phys, size_t *mem_size) { + const struct firmware *mdt; struct resource res; + struct device *dev; ssize_t fw_size; + void *mem_va; int ret; - ret = of_reserved_mem_region_to_resource(core->dev->of_node, 0, &res); + *mem_phys = 0; + *mem_size = 0; + + dev = core->dev; + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); if (ret) { - dev_err(core->dev, "failed to lookup reserved memory-region\n"); + dev_err(dev, "failed to lookup reserved memory-region\n"); return -EINVAL; } - *mem_phys = res.start; - *res_size = resource_size(&res); - - ret = request_firmware(mdt, fwname, core->dev); - if (ret < 0) { - dev_err(core->dev, "%s: request_firmware: %d\n", __func__, ret); + ret = request_firmware(&mdt, fwname, dev); + if (ret < 0) return ret; - } - fw_size = qcom_mdt_get_size(*mdt); + fw_size = qcom_mdt_get_size(mdt); if (fw_size < 0) { ret = fw_size; - goto err_release; - } - - if (*res_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { - ret = -EINVAL; - goto err_release; + goto err_release_fw; } - return 0; - -err_release: - release_firmware(*mdt); - return ret; -} - -static int venus_load_fw(struct venus_core *core, - const struct firmware *mdt, const char *fwname, - phys_addr_t mem_phys, size_t res_size) -{ - struct qcom_pas_context *ctx; - struct device *dev; - int ret; - - dev = core->fw.dev ? core->fw.dev : core->dev; - ctx = devm_qcom_pas_context_alloc(dev, VENUS_PAS_ID, mem_phys, res_size); - if (!ctx) { - dev_err(core->dev, "%s: ctx is null\n", __func__); - return -ENOMEM; - } - - ctx->use_tzmem = !!core->fw.dev; + *mem_phys = res.start; + *mem_size = resource_size(&res); - ret = qcom_mdt_pas_load(ctx, mdt, fwname, NULL); - qcom_pas_metadata_release(ctx); - if (ret) { - dev_err(core->dev, "%s: qcom_mdt_pas_load: %d\n", __func__, ret); - return ret; + if (*mem_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { + ret = -EINVAL; + goto err_release_fw; } - if (core->fw.iommu_domain) { - ret = iommu_map(core->fw.iommu_domain, 0, mem_phys, res_size, - IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); - if (ret) { - dev_err(core->dev, "%s: iommu_map: %d\n", __func__, ret); - return ret; - } + mem_va = memremap(*mem_phys, *mem_size, MEMREMAP_WC); + if (!mem_va) { + dev_err(dev, "unable to map memory region %pa size %#zx\n", mem_phys, *mem_size); + ret = -ENOMEM; + goto err_release_fw; } - core->fw.mapped_mem_size = res_size; - - ret = qcom_pas_prepare_and_auth_reset(ctx); - if (ret) { - dev_err(core->dev, "%s: qcom_pas_prepare_and_auth_reset: %d\n", __func__, ret); - if (core->fw.iommu_domain) - iommu_unmap(core->fw.iommu_domain, 0, res_size); - core->fw.mapped_mem_size = 0; - return ret; - } + if (core->use_tz) + ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, + mem_va, *mem_phys, *mem_size, NULL); + else + ret = qcom_mdt_load_no_init(dev, mdt, fwname, mem_va, + *mem_phys, *mem_size, NULL); - core->fw.ctx = ctx; - return 0; + memunmap(mem_va); +err_release_fw: + release_firmware(mdt); + return ret; } -static int venus_load_fw_no_tz(struct venus_core *core, - const struct firmware *mdt, const char *fwname, - phys_addr_t mem_phys, size_t res_size) +static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys, + size_t mem_size) { - void *mem_va; + struct iommu_domain *iommu; + struct device *dev; int ret; - mem_va = memremap(mem_phys, res_size, MEMREMAP_WC); - if (!mem_va) { - dev_err(core->dev, - "unable to map memory region %pa size %#zx\n", &mem_phys, res_size); - return -ENOMEM; - } + dev = core->fw.dev; + if (!dev) + return -EPROBE_DEFER; - ret = qcom_mdt_load_no_init(core->fw.dev, mdt, fwname, mem_va, mem_phys, res_size, NULL); - memunmap(mem_va); - if (ret) { - dev_err(core->dev, "%s: qcom_mdt_load_no_init: %d\n", __func__, ret); - return ret; - } + iommu = core->fw.iommu_domain; + core->fw.mapped_mem_size = mem_size; - ret = iommu_map(core->fw.iommu_domain, VENUS_FW_START_ADDR, mem_phys, - res_size, IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); if (ret) { - dev_err(core->dev, "could not map video firmware region\n"); + dev_err(dev, "could not map video firmware region\n"); return ret; } - core->fw.mapped_mem_size = res_size; venus_reset_cpu(core); + return 0; } @@ -252,35 +213,36 @@ int venus_boot(struct venus_core *core) { struct device *dev = core->dev; const struct venus_resources *res = core->res; - const struct firmware *mdt; const char *fwpath = NULL; phys_addr_t mem_phys; - size_t res_size; + size_t mem_size; int ret; if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || - (!core->use_tz && !core->fw.dev)) - return driver_deferred_probe_check_state(core->dev); + (core->use_tz && !qcom_pas_is_available())) + return -EPROBE_DEFER; - ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, &fwpath); + ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, + &fwpath); if (ret) fwpath = core->res->fwname; - ret = venus_load_fw_prepare(core, fwpath, &mem_phys, &res_size, &mdt); - if (ret) - return ret; + ret = venus_load_fw(core, fwpath, &mem_phys, &mem_size); + if (ret) { + dev_err(dev, "fail to load video firmware\n"); + return -EINVAL; + } + + core->fw.mem_size = mem_size; + core->fw.mem_phys = mem_phys; if (core->use_tz) - ret = venus_load_fw(core, mdt, fwpath, mem_phys, res_size); + ret = qcom_pas_auth_and_reset(VENUS_PAS_ID); else - ret = venus_load_fw_no_tz(core, mdt, fwpath, mem_phys, res_size); - - release_firmware(mdt); + ret = venus_boot_no_tz(core, mem_phys, mem_size); - if (ret) { - dev_err(dev, "fail to load video firmware\n"); + if (ret) return ret; - } if (core->use_tz && res->cp_size) { /* @@ -298,29 +260,24 @@ int venus_boot(struct venus_core *core) res->cp_nonpixel_start, res->cp_nonpixel_size); if (ret) { - venus_shutdown(core); - dev_err(dev, "set virtual address ranges fail (%d)\n", ret); + qcom_pas_shutdown(VENUS_PAS_ID); + dev_err(dev, "set virtual address ranges fail (%d)\n", + ret); return ret; } } - return ret; + return 0; } int venus_shutdown(struct venus_core *core) { int ret; - if (core->use_tz) { + if (core->use_tz) ret = qcom_pas_shutdown(VENUS_PAS_ID); - if (core->fw.iommu_domain && core->fw.mapped_mem_size) { - iommu_unmap(core->fw.iommu_domain, 0, core->fw.mapped_mem_size); - core->fw.mapped_mem_size = 0; - } - core->fw.ctx = NULL; - } else { + else ret = venus_shutdown_no_tz(core); - } return ret; } @@ -345,94 +302,6 @@ int venus_firmware_check(struct venus_core *core) return -EINVAL; } -static struct device *venus_firmware_alloc_platform_dev(struct venus_core *core, - const char *name, const u32 *f_id) -{ - struct platform_device *pdev; - int ret; - - pdev = platform_device_alloc(name, 0); - if (!pdev) { - dev_err(core->dev, "%s: platform_device_alloc err\n", __func__); - return ERR_PTR(-ENOMEM); - } - - pdev->dev.parent = core->dev; - - ret = platform_device_add(pdev); - if (ret) { - dev_err(core->dev, "%s: platform_device_add err(%d)\n", __func__, ret); - platform_device_put(pdev); - return ERR_PTR(ret); - } - - ret = of_dma_configure_id(&pdev->dev, core->dev->of_node, true, f_id); - if (ret) { - dev_err(core->dev, "%s: of_dma_configure_id err(%d)\n", __func__, ret); - platform_device_unregister(to_platform_device(&pdev->dev)); - return ERR_PTR(ret); - } - - return &pdev->dev; -} - -static int venus_firmware_setup_iommu_dev(struct venus_core *core) -{ - const u32 f_id = VENUS_FIRMWARE; - struct device *dev; - int ret = 0; - - dev = venus_firmware_alloc_platform_dev(core, "video_firmware", &f_id); - if (IS_ERR(dev)) { - dev_err(core->dev, "%s: err\n", __func__); - return PTR_ERR(dev); - } - - if (!device_iommu_mapped(dev)) { - device_unregister(dev); - return -ENODEV; - } - - ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); - if (ret) { - device_unregister(dev); - return ret; - } - - core->fw.dev = dev; - core->fw.iommu_domain = iommu_get_domain_for_dev(core->fw.dev); - core->fw.iommu_domain_owned = false; - - return 0; -} - -static int venus_firmware_init_auto_detect(struct venus_core *core) -{ - int ret; - - core->use_tz = false; - if (qcom_scm_is_available()) { - if (qcom_scm_pas_supported(VENUS_PAS_ID)) - core->use_tz = true; - } else { - ret = driver_deferred_probe_check_state(core->dev); - if (ret == -EPROBE_DEFER) - return ret; - } - - /* - * 1. use_tz is false: No authentication is performed. - * 2. use_tz is true: TZ perform authentication. - * a. device_iommu_mapped true: Linux config smmu - * b. device_iommu_mapped false: TZ config smmu - */ - ret = venus_firmware_setup_iommu_dev(core); - if (ret == -ENODEV && core->use_tz) - ret = 0; - - return ret; -} - int venus_firmware_init(struct venus_core *core) { struct platform_device_info info; @@ -443,8 +312,8 @@ int venus_firmware_init(struct venus_core *core) np = of_get_child_by_name(core->dev->of_node, "video-firmware"); if (!np) { - ret = venus_firmware_init_auto_detect(core); - return ret; + core->use_tz = true; + return 0; } memset(&info, 0, sizeof(info)); @@ -483,7 +352,6 @@ int venus_firmware_init(struct venus_core *core) } core->fw.iommu_domain = iommu_dom; - core->fw.iommu_domain_owned = true; of_node_put(np); @@ -492,7 +360,6 @@ int venus_firmware_init(struct venus_core *core) err_iommu_free: iommu_domain_free(iommu_dom); err_unregister: - core->fw.dev = NULL; platform_device_unregister(pdev); of_node_put(np); return ret; @@ -505,17 +372,14 @@ void venus_firmware_deinit(struct venus_core *core) if (!core->fw.dev) return; - if (!core->use_tz && core->fw.iommu_domain_owned) { - iommu = core->fw.iommu_domain; + iommu = core->fw.iommu_domain; - if (iommu) { - iommu_detach_device(iommu, core->fw.dev); - iommu_domain_free(iommu); - } + iommu_detach_device(iommu, core->fw.dev); + + if (core->fw.iommu_domain) { + iommu_domain_free(iommu); + core->fw.iommu_domain = NULL; } + platform_device_unregister(to_platform_device(core->fw.dev)); - core->fw.dev = NULL; - core->fw.ctx = NULL; - core->fw.iommu_domain = NULL; - core->fw.iommu_domain_owned = false; } From 944f789d3a4d60c8c635a0e27c84093bb61be855 Mon Sep 17 00:00:00 2001 From: Gourav Kumar Date: Thu, 17 Sep 2026 12:22:22 +0530 Subject: [PATCH 2/8] Revert "PENDING: media: iris: update MDT PAS load call for new API" This reverts commit 6852eb7d4a59fe7a0ea09c04cade6dc164bd01e8. Signed-off-by: Gourav Kumar --- drivers/media/platform/qcom/iris/iris_firmware.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 31edb6c704e15..9bdc9ab14f5ed 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -121,6 +121,7 @@ static int iris_load_fw_to_memory(struct iris_core *core) const char *fw_name; size_t res_size; ssize_t fw_size; + void *mem_virt; int ret; ret = of_reserved_mem_region_to_resource(core->dev->of_node, 0, &res); @@ -149,22 +150,30 @@ static int iris_load_fw_to_memory(struct iris_core *core) goto err_release_fw; } + mem_virt = memremap(mem_phys, res_size, MEMREMAP_WC); + if (!mem_virt) { + ret = -ENOMEM; + goto err_release_fw; + } + core->pas_ctx->use_tzmem = !!core->fw_dev; - ret = qcom_mdt_pas_load(core->pas_ctx, firmware, fw_name, NULL); + ret = qcom_mdt_pas_load(core->pas_ctx, firmware, fw_name, mem_virt, NULL); if (ret) - goto err_release_fw; + goto err_mem_unmap; if (core->pas_ctx->use_tzmem) { domain = iommu_get_domain_for_dev(fw_dev); if (!domain) { ret = -ENODEV; - goto err_release_fw; + 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); From dfbafee64231dd6d796d21d3def3f8e93a447732 Mon Sep 17 00:00:00 2001 From: Gourav Kumar Date: Thu, 17 Sep 2026 12:22:52 +0530 Subject: [PATCH 3/8] Revert "FROMLIST: media: iris: Enable Secure PAS support with IOMMU managed by Linux" This reverts commit a41bd3e2f960034eb1943ea2f72432a114368d1c. Signed-off-by: Gourav Kumar --- drivers/media/platform/qcom/iris/iris_core.h | 4 -- .../media/platform/qcom/iris/iris_firmware.c | 66 +++---------------- 2 files changed, 9 insertions(+), 61 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 1e47546dc4132..b822cbc811249 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -51,8 +51,6 @@ struct dentry; * @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 @@ -104,8 +102,6 @@ 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 9bdc9ab14f5ed..21cdf1c398357 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -17,7 +16,6 @@ #define IRIS_PAS_ID 9 #define MAX_FIRMWARE_NAME_SIZE 128 -#define IRIS_FW_START_ADDR 0 /* Detect Gen2 firmware by scanning the blob for: * QC_IMAGE_VERSION_STRING= @@ -112,10 +110,8 @@ static const struct firmware *iris_detect_firmware(struct iris_core *core, static int iris_load_fw_to_memory(struct iris_core *core) { - struct device *fw_dev = core->fw_dev ? core->fw_dev : core->dev; const struct firmware *firmware = NULL; - struct qcom_pas_context *ctx; - struct iommu_domain *domain; + struct device *dev = core->dev; struct resource res; phys_addr_t mem_phys; const char *fw_name; @@ -124,7 +120,7 @@ static int iris_load_fw_to_memory(struct iris_core *core) void *mem_virt; int ret; - ret = of_reserved_mem_region_to_resource(core->dev->of_node, 0, &res); + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); if (ret) return ret; @@ -137,13 +133,6 @@ static int iris_load_fw_to_memory(struct iris_core *core) core->iris_firmware_data = core->iris_firmware_desc->firmware_data; - 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; - } - fw_size = qcom_mdt_get_size(firmware); if (fw_size < 0 || res_size < (size_t)fw_size) { ret = -EINVAL; @@ -156,23 +145,9 @@ static int iris_load_fw_to_memory(struct iris_core *core) goto err_release_fw; } - 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); - } + ret = qcom_mdt_load(dev, firmware, fw_name, + IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL); -err_mem_unmap: memunmap(mem_virt); err_release_fw: release_firmware(firmware); @@ -180,18 +155,6 @@ static int iris_load_fw_to_memory(struct iris_core *core) 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; @@ -203,10 +166,10 @@ int iris_fw_load(struct iris_core *core) return ret; } - ret = qcom_pas_prepare_and_auth_reset(core->pas_ctx); + ret = qcom_pas_auth_and_reset(IRIS_PAS_ID); if (ret) { dev_err(core->dev, "auth and reset failed: %d\n", ret); - goto err_unmap; + return ret; } for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) { @@ -217,28 +180,17 @@ 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); - goto err_pas_shutdown; + qcom_pas_shutdown(IRIS_PAS_ID); + return ret; } } return 0; - -err_pas_shutdown: - qcom_scm_pas_shutdown(IRIS_PAS_ID); -err_unmap: - iris_fw_iommu_unmap(core); - - return ret; } int iris_fw_unload(struct iris_core *core) { - int ret; - - ret = qcom_scm_pas_shutdown(IRIS_PAS_ID); - iris_fw_iommu_unmap(core); - - return ret; + return qcom_pas_shutdown(IRIS_PAS_ID); } int iris_set_hw_state(struct iris_core *core, bool resume) From 020b9fdb188ebddfbfcaf91f0ab21195db7aa6d7 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 15 Jul 2026 19:40:00 +0530 Subject: [PATCH 4/8] FROMLIST: media: iris: Enable Secure PAS support with IOMMU managed by Linux On platforms where a hypervisor is present, all Secure Monitor Calls (SMC) are intercepted. For qcom_scm_pas_auth_and_reset(), the hypervisor registers a Shared Memory (SHM) bridge over the Peripheral Image Loader (PIL) memory region so that TrustZone (TZ) can access it, forwards the authentication SMC to TZ, and upon return maps the PIL region and triggers the co-processor bring-up sequence: HLOS -> Hypervisor(SHM setup) -> TZ(auth) -> Hypervisor(map+reset) -> IRIS On platforms without a hypervisor, Linux drives these steps directly. The SHM bridge infrastructure required for this is already upstream [1]. To isolate firmware memory in its own Input-Output Memory Management Unit (IOMMU) context, a dedicated stream ID (SID) is required, tied to the firmware function ID. This SID is specified via the iommu-map property in the device tree using the firmware function ID as the lookup key. A firmware device is created and mapped to this SID. The presence of a SID mapped to the firmware device via iommu-map is used to detect whether a hypervisor is absent: when the firmware device has a SID mapped, Linux manages the IOMMU directly; when no SID is mapped, a hypervisor is assumed to be present and these steps are skipped. Extend the Iris driver to support Secure Peripheral Authentication Service (PAS) on platforms where Linux manages the IOMMU, by creating the firmware context device and performing the necessary IOMMU mapping when the firmware device SID is present. [1] https://lore.kernel.org/lkml/20260105-kvmrprocv10-v10-0-022e96815380 @oss.qualcomm.com/ Link: https://lore.kernel.org/all/20260715-glymur-v9-6-8cf2cbe12a07@oss.qualcomm.com/ Reviewed-by: Vishnu Reddy Co-developed-by: Vikash Garodia Signed-off-by: Vikash Garodia Signed-off-by: Mukesh Ojha Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/lkml/20260105-kvmrprocv10-v10-0-022e96815380@oss.qualcomm.com/ Signed-off-by: Vishnu Reddy --- drivers/media/platform/qcom/iris/iris_core.h | 4 ++ .../media/platform/qcom/iris/iris_firmware.c | 66 ++++++++++++++++--- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index b822cbc811249..1e47546dc4132 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -51,6 +51,8 @@ struct dentry; * @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 @@ -102,6 +104,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 21cdf1c398357..501b43f580b8f 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #define IRIS_PAS_ID 9 #define MAX_FIRMWARE_NAME_SIZE 128 +#define IRIS_FW_START_ADDR 0 /* Detect Gen2 firmware by scanning the blob for: * QC_IMAGE_VERSION_STRING= @@ -110,8 +112,10 @@ static const struct firmware *iris_detect_firmware(struct iris_core *core, static int iris_load_fw_to_memory(struct iris_core *core) { + 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; const char *fw_name; @@ -120,7 +124,7 @@ static int iris_load_fw_to_memory(struct iris_core *core) void *mem_virt; int ret; - 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; @@ -133,6 +137,13 @@ static int iris_load_fw_to_memory(struct iris_core *core) core->iris_firmware_data = core->iris_firmware_desc->firmware_data; + 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; + } + fw_size = qcom_mdt_get_size(firmware); if (fw_size < 0 || res_size < (size_t)fw_size) { ret = -EINVAL; @@ -145,9 +156,23 @@ 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); + 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); @@ -155,6 +180,18 @@ static int iris_load_fw_to_memory(struct iris_core *core) 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; @@ -166,10 +203,10 @@ int iris_fw_load(struct iris_core *core) return ret; } - ret = qcom_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++) { @@ -180,17 +217,28 @@ 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_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_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) From 850828ab17c1b4a2abb25dc5a2aa82fd1aeffda1 Mon Sep 17 00:00:00 2001 From: Gourav Kumar Date: Thu, 2 Apr 2026 11:44:12 +0530 Subject: [PATCH 5/8] PENDING: media: iris: update MDT PAS load call for new API The Qualcomm MDT loader changed qcom_mdt_pas_load() to take only four arguments and use the PAS context for relocation and memory handling. Update the iris firmware loading path to match that interface by dropping the temporary memremap/memunmap flow, removing the extra mem_virt argument from qcom_mdt_pas_load(), and simplifying the error path accordingly. This keeps the iris driver aligned with the SCM/PAS loader changes and fixes the build failure caused by the old five-argument call. Signed-off-by: Gourav Kumar --- drivers/media/platform/qcom/iris/iris_firmware.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 501b43f580b8f..3d181d1aea5ab 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -121,7 +121,6 @@ static int iris_load_fw_to_memory(struct iris_core *core) const char *fw_name; size_t res_size; ssize_t fw_size; - void *mem_virt; int ret; ret = of_reserved_mem_region_to_resource(core->dev->of_node, 0, &res); @@ -150,30 +149,22 @@ static int iris_load_fw_to_memory(struct iris_core *core) goto err_release_fw; } - mem_virt = memremap(mem_phys, res_size, MEMREMAP_WC); - if (!mem_virt) { - ret = -ENOMEM; - goto err_release_fw; - } - core->pas_ctx->use_tzmem = !!core->fw_dev; - ret = qcom_mdt_pas_load(core->pas_ctx, firmware, fw_name, mem_virt, NULL); + ret = qcom_mdt_pas_load(core->pas_ctx, firmware, fw_name, NULL); if (ret) - goto err_mem_unmap; + goto err_release_fw; if (core->pas_ctx->use_tzmem) { domain = iommu_get_domain_for_dev(fw_dev); if (!domain) { ret = -ENODEV; - goto err_mem_unmap; + goto err_release_fw; } 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); From 4d5100afc393581af94edd21c2938bbcdb57043f Mon Sep 17 00:00:00 2001 From: Renjiang Han Date: Thu, 30 Apr 2026 15:56:48 +0530 Subject: [PATCH 6/8] PENDING: media: qcom: venus: support PAS boot and flexible IOMMU handling On platforms where PAS is available, firmware authentication and reset are performed via the secure world, while IOMMU configuration may be handled either by Linux or outside of it. Extend the Venus firmware flow to support both PAS and non-PAS setups. When PAS is available, load the firmware using a PAS context and trigger the prepare/auth/reset sequence. If the firmware device is IOMMU-mapped, use its IOMMU domain to map the reserved firmware memory before reset; otherwise, retain the existing secure-world-managed behavior. When PAS is not available, fall back to the existing non-PAS firmware loading path where Linux performs firmware loading and IOMMU mapping. The firmware stream ID is described via the iommu-map function identifier in the device tree. Signed-off-by: Renjiang Han --- drivers/media/platform/qcom/venus/core.h | 2 + drivers/media/platform/qcom/venus/firmware.c | 294 ++++++++++++++----- 2 files changed, 217 insertions(+), 79 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 46705a6667762..2d5a8a690d373 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -223,6 +223,8 @@ struct venus_core { size_t mapped_mem_size; phys_addr_t mem_phys; size_t mem_size; + struct qcom_pas_context *ctx; + bool iommu_domain_owned; } fw; struct mutex lock; struct list_head instances; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 3a38ff985822f..ca20eba43540e 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "core.h" #include "firmware.h" @@ -79,87 +80,125 @@ int venus_set_hw_state(struct venus_core *core, bool resume) return 0; } -static int venus_load_fw(struct venus_core *core, const char *fwname, - phys_addr_t *mem_phys, size_t *mem_size) +static int venus_load_fw_prepare(struct venus_core *core, const char *fwname, + phys_addr_t *mem_phys, size_t *res_size, + const struct firmware **mdt) { - const struct firmware *mdt; struct resource res; - struct device *dev; ssize_t fw_size; - void *mem_va; int ret; - *mem_phys = 0; - *mem_size = 0; - - dev = core->dev; - 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) { - dev_err(dev, "failed to lookup reserved memory-region\n"); + dev_err(core->dev, "failed to lookup reserved memory-region\n"); return -EINVAL; } - ret = request_firmware(&mdt, fwname, dev); - if (ret < 0) + *mem_phys = res.start; + *res_size = resource_size(&res); + + ret = request_firmware(mdt, fwname, core->dev); + if (ret < 0) { + dev_err(core->dev, "%s: request_firmware: %d\n", __func__, ret); return ret; + } - fw_size = qcom_mdt_get_size(mdt); + fw_size = qcom_mdt_get_size(*mdt); if (fw_size < 0) { ret = fw_size; - goto err_release_fw; + goto err_release; } - *mem_phys = res.start; - *mem_size = resource_size(&res); - - if (*mem_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { + if (*res_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { ret = -EINVAL; - goto err_release_fw; - } - - mem_va = memremap(*mem_phys, *mem_size, MEMREMAP_WC); - if (!mem_va) { - dev_err(dev, "unable to map memory region %pa size %#zx\n", mem_phys, *mem_size); - ret = -ENOMEM; - goto err_release_fw; + goto err_release; } - if (core->use_tz) - ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, - mem_va, *mem_phys, *mem_size, NULL); - else - ret = qcom_mdt_load_no_init(dev, mdt, fwname, mem_va, - *mem_phys, *mem_size, NULL); + return 0; - memunmap(mem_va); -err_release_fw: - release_firmware(mdt); +err_release: + release_firmware(*mdt); return ret; } -static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys, - size_t mem_size) +static int venus_load_fw(struct venus_core *core, + const struct firmware *mdt, const char *fwname, + phys_addr_t mem_phys, size_t res_size) { - struct iommu_domain *iommu; + struct qcom_pas_context *ctx; struct device *dev; int ret; - dev = core->fw.dev; - if (!dev) - return -EPROBE_DEFER; + dev = core->fw.dev ? core->fw.dev : core->dev; + ctx = devm_qcom_pas_context_alloc(dev, VENUS_PAS_ID, mem_phys, res_size); + if (!ctx) { + dev_err(core->dev, "%s: ctx is null\n", __func__); + return -ENOMEM; + } - iommu = core->fw.iommu_domain; - core->fw.mapped_mem_size = mem_size; + ctx->use_tzmem = !!core->fw.dev; - ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size, - IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + ret = qcom_mdt_pas_load(ctx, mdt, fwname, NULL); + qcom_pas_metadata_release(ctx); if (ret) { - dev_err(dev, "could not map video firmware region\n"); + dev_err(core->dev, "%s: qcom_mdt_pas_load: %d\n", __func__, ret); return ret; } - venus_reset_cpu(core); + if (core->fw.iommu_domain) { + ret = iommu_map(core->fw.iommu_domain, 0, mem_phys, res_size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + if (ret) { + dev_err(core->dev, "%s: iommu_map: %d\n", __func__, ret); + return ret; + } + } + + core->fw.mapped_mem_size = res_size; + + ret = qcom_pas_prepare_and_auth_reset(ctx); + if (ret) { + dev_err(core->dev, "%s: qcom_pas_prepare_and_auth_reset: %d\n", __func__, ret); + if (core->fw.iommu_domain) + iommu_unmap(core->fw.iommu_domain, 0, res_size); + core->fw.mapped_mem_size = 0; + return ret; + } + core->fw.ctx = ctx; + return 0; +} + +static int venus_load_fw_no_tz(struct venus_core *core, + const struct firmware *mdt, const char *fwname, + phys_addr_t mem_phys, size_t res_size) +{ + void *mem_va; + int ret; + + mem_va = memremap(mem_phys, res_size, MEMREMAP_WC); + if (!mem_va) { + dev_err(core->dev, + "unable to map memory region %pa size %#zx\n", &mem_phys, res_size); + return -ENOMEM; + } + + ret = qcom_mdt_load_no_init(core->fw.dev, mdt, fwname, mem_va, mem_phys, res_size, NULL); + memunmap(mem_va); + if (ret) { + dev_err(core->dev, "%s: qcom_mdt_load_no_init: %d\n", __func__, ret); + return ret; + } + + ret = iommu_map(core->fw.iommu_domain, VENUS_FW_START_ADDR, mem_phys, + res_size, IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL); + if (ret) { + dev_err(core->dev, "could not map video firmware region\n"); + return ret; + } + + core->fw.mapped_mem_size = res_size; + venus_reset_cpu(core); return 0; } @@ -213,36 +252,35 @@ int venus_boot(struct venus_core *core) { struct device *dev = core->dev; const struct venus_resources *res = core->res; + const struct firmware *mdt; const char *fwpath = NULL; phys_addr_t mem_phys; - size_t mem_size; + size_t res_size; int ret; if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || - (core->use_tz && !qcom_pas_is_available())) - return -EPROBE_DEFER; + (!core->use_tz && !qcom_pas_is_available())) + return driver_deferred_probe_check_state(core->dev); - ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, - &fwpath); + ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, &fwpath); if (ret) fwpath = core->res->fwname; - ret = venus_load_fw(core, fwpath, &mem_phys, &mem_size); - if (ret) { - dev_err(dev, "fail to load video firmware\n"); - return -EINVAL; - } - - core->fw.mem_size = mem_size; - core->fw.mem_phys = mem_phys; + ret = venus_load_fw_prepare(core, fwpath, &mem_phys, &res_size, &mdt); + if (ret) + return ret; if (core->use_tz) - ret = qcom_pas_auth_and_reset(VENUS_PAS_ID); + ret = venus_load_fw(core, mdt, fwpath, mem_phys, res_size); else - ret = venus_boot_no_tz(core, mem_phys, mem_size); + ret = venus_load_fw_no_tz(core, mdt, fwpath, mem_phys, res_size); - if (ret) + release_firmware(mdt); + + if (ret) { + dev_err(dev, "fail to load video firmware\n"); return ret; + } if (core->use_tz && res->cp_size) { /* @@ -260,24 +298,29 @@ int venus_boot(struct venus_core *core) res->cp_nonpixel_start, res->cp_nonpixel_size); if (ret) { - qcom_pas_shutdown(VENUS_PAS_ID); - dev_err(dev, "set virtual address ranges fail (%d)\n", - ret); + venus_shutdown(core); + dev_err(dev, "set virtual address ranges fail (%d)\n", ret); return ret; } } - return 0; + return ret; } int venus_shutdown(struct venus_core *core) { int ret; - if (core->use_tz) + if (core->use_tz) { ret = qcom_pas_shutdown(VENUS_PAS_ID); - else + if (core->fw.iommu_domain && core->fw.mapped_mem_size) { + iommu_unmap(core->fw.iommu_domain, 0, core->fw.mapped_mem_size); + core->fw.mapped_mem_size = 0; + } + core->fw.ctx = NULL; + } else { ret = venus_shutdown_no_tz(core); + } return ret; } @@ -302,6 +345,94 @@ int venus_firmware_check(struct venus_core *core) return -EINVAL; } +static struct device *venus_firmware_alloc_platform_dev(struct venus_core *core, + const char *name, const u32 *f_id) +{ + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc(name, 0); + if (!pdev) { + dev_err(core->dev, "%s: platform_device_alloc err\n", __func__); + return ERR_PTR(-ENOMEM); + } + + pdev->dev.parent = core->dev; + + ret = platform_device_add(pdev); + if (ret) { + dev_err(core->dev, "%s: platform_device_add err(%d)\n", __func__, ret); + platform_device_put(pdev); + return ERR_PTR(ret); + } + + ret = of_dma_configure_id(&pdev->dev, core->dev->of_node, true, f_id); + if (ret) { + dev_err(core->dev, "%s: of_dma_configure_id err(%d)\n", __func__, ret); + platform_device_unregister(to_platform_device(&pdev->dev)); + return ERR_PTR(ret); + } + + return &pdev->dev; +} + +static int venus_firmware_setup_iommu_dev(struct venus_core *core) +{ + const u32 f_id = VENUS_FIRMWARE; + struct device *dev; + int ret = 0; + + dev = venus_firmware_alloc_platform_dev(core, "video_firmware", &f_id); + if (IS_ERR(dev)) { + dev_err(core->dev, "%s: err\n", __func__); + return PTR_ERR(dev); + } + + if (!device_iommu_mapped(dev)) { + device_unregister(dev); + return -ENODEV; + } + + ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); + if (ret) { + device_unregister(dev); + return ret; + } + + core->fw.dev = dev; + core->fw.iommu_domain = iommu_get_domain_for_dev(core->fw.dev); + core->fw.iommu_domain_owned = false; + + return 0; +} + +static int venus_firmware_init_auto_detect(struct venus_core *core) +{ + int ret; + + core->use_tz = false; + if (qcom_pas_is_available()) { + if (qcom_pas_supported(VENUS_PAS_ID)) + core->use_tz = true; + } else { + ret = driver_deferred_probe_check_state(core->dev); + if (ret == -EPROBE_DEFER) + return ret; + } + + /* + * 1. use_tz is false: No authentication is performed. + * 2. use_tz is true: TZ perform authentication. + * a. device_iommu_mapped true: Linux config smmu + * b. device_iommu_mapped false: TZ config smmu + */ + ret = venus_firmware_setup_iommu_dev(core); + if (ret == -ENODEV && core->use_tz) + ret = 0; + + return ret; +} + int venus_firmware_init(struct venus_core *core) { struct platform_device_info info; @@ -312,8 +443,8 @@ int venus_firmware_init(struct venus_core *core) np = of_get_child_by_name(core->dev->of_node, "video-firmware"); if (!np) { - core->use_tz = true; - return 0; + ret = venus_firmware_init_auto_detect(core); + return ret; } memset(&info, 0, sizeof(info)); @@ -352,6 +483,7 @@ int venus_firmware_init(struct venus_core *core) } core->fw.iommu_domain = iommu_dom; + core->fw.iommu_domain_owned = true; of_node_put(np); @@ -360,6 +492,7 @@ int venus_firmware_init(struct venus_core *core) err_iommu_free: iommu_domain_free(iommu_dom); err_unregister: + core->fw.dev = NULL; platform_device_unregister(pdev); of_node_put(np); return ret; @@ -372,14 +505,17 @@ void venus_firmware_deinit(struct venus_core *core) if (!core->fw.dev) return; - iommu = core->fw.iommu_domain; - - iommu_detach_device(iommu, core->fw.dev); + if (!core->use_tz && core->fw.iommu_domain_owned) { + iommu = core->fw.iommu_domain; - if (core->fw.iommu_domain) { - iommu_domain_free(iommu); - core->fw.iommu_domain = NULL; + if (iommu) { + iommu_detach_device(iommu, core->fw.dev); + iommu_domain_free(iommu); + } } - platform_device_unregister(to_platform_device(core->fw.dev)); + core->fw.dev = NULL; + core->fw.ctx = NULL; + core->fw.iommu_domain = NULL; + core->fw.iommu_domain_owned = false; } From a1dcd26808200508dcfc48ea1f53a869302a57cb Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Fri, 11 Sep 2026 18:08:56 +0530 Subject: [PATCH 7/8] FROMLIST: media: iris: Skip SCM call for non-SCM PAS backend qcom_scm_mem_protect_video_var() is only serviced by the SCM backend; with OP-TEE the TEE owns secure memory protection. Use qcom_pas_get_backend() to issue the SCM call only for the SCM backend. Link: https://lore.kernel.org/all/20260911-video-optee-pas-v1-v1-2-7bbddaaac5ba@kernel.org/ Assisted-by: Copilot:claude-opus-4.8 Signed-off-by: Jorge Ramirez-Ortiz Co-developed-by: Sumit Garg Signed-off-by: Sumit Garg --- drivers/media/platform/qcom/iris/iris_firmware.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 3d181d1aea5ab..a8b52bc9dd554 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "iris_core.h" #include "iris_firmware.h" @@ -186,6 +187,7 @@ static void iris_fw_iommu_unmap(struct iris_core *core) int iris_fw_load(struct iris_core *core) { const struct tz_cp_config *cp_config; + const char *pas_backend; int i, ret; ret = iris_load_fw_to_memory(core); @@ -200,6 +202,15 @@ int iris_fw_load(struct iris_core *core) goto err_unmap; } + /* + * qcom_scm_mem_protect_video_var() only applies to the SCM backend; + * other backends (e.g. OP-TEE) own secure memory protection and do + * not service this call. + */ + pas_backend = qcom_pas_get_backend(); + if (!pas_backend || strcmp(pas_backend, QCOM_PAS_BACKEND_SCM)) + return 0; + 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, From 4fd5b125c7dbaab1bb45b710a961ef9b6b4e47a4 Mon Sep 17 00:00:00 2001 From: Sumit Garg Date: Fri, 11 Sep 2026 18:08:57 +0530 Subject: [PATCH 8/8] FROMLIST: media: venus: Skip SCM call for non-SCM PAS backend qcom_scm_mem_protect_video_var() is only serviced by the SCM backend; with OP-TEE the TEE owns secure memory protection. Use qcom_pas_get_backend() to issue the SCM call only for the SCM backend. Link: https://lore.kernel.org/all/20260911-video-optee-pas-v1-v1-3-7bbddaaac5ba@kernel.org/ Assisted-by: Copilot:claude-opus-4.8 Signed-off-by: Sumit Garg --- drivers/media/platform/qcom/venus/firmware.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index ca20eba43540e..078ff59d55df2 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "core.h" #include "firmware.h" @@ -254,6 +255,7 @@ int venus_boot(struct venus_core *core) const struct venus_resources *res = core->res; const struct firmware *mdt; const char *fwpath = NULL; + const char *pas_backend; phys_addr_t mem_phys; size_t res_size; int ret; @@ -283,6 +285,14 @@ int venus_boot(struct venus_core *core) } if (core->use_tz && res->cp_size) { + /* + * qcom_scm_mem_protect_video_var() only applies to the SCM + * backend; other backends (e.g. OP-TEE) own secure memory + * protection and do not service this call. + */ + pas_backend = qcom_pas_get_backend(); + if (!pas_backend || strcmp(pas_backend, QCOM_PAS_BACKEND_SCM)) + return ret; /* * Clues for porting using downstream data: * cp_start = 0