]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: venus: Define minimum valid firmware version
authorJorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
Thu, 14 Aug 2025 08:52:42 +0000 (10:52 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Tue, 9 Sep 2025 13:59:15 +0000 (15:59 +0200)
Add support for specifying the minimum firmware version required for
correct operation.

When set, the driver compares this value against the version reported by
the firmware: if the firmware is older than required, driver
initialization will fail.

The version check is performed before creating dynamic device tree
nodes, to avoid the need for reverting nodes on failure.

Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
Reviewed-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/platform/qcom/venus/core.c
drivers/media/platform/qcom/venus/core.h
drivers/media/platform/qcom/venus/firmware.c
drivers/media/platform/qcom/venus/firmware.h
drivers/media/platform/qcom/venus/hfi_msgs.c

index 90de29f166ada7aa5afe611041df308b5dfe8312..5d76e50234f676d6f86bd011096a1f0b0f737fe2 100644 (file)
@@ -448,19 +448,9 @@ static int venus_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_runtime_disable;
 
-       if (core->res->dec_nodename || core->res->enc_nodename) {
-               ret = venus_add_dynamic_nodes(core);
-               if (ret)
-                       goto err_runtime_disable;
-       }
-
-       ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
-       if (ret)
-               goto err_remove_dynamic_nodes;
-
        ret = venus_firmware_init(core);
        if (ret)
-               goto err_of_depopulate;
+               goto err_runtime_disable;
 
        ret = venus_boot(core);
        if (ret)
@@ -474,34 +464,48 @@ static int venus_probe(struct platform_device *pdev)
        if (ret)
                goto err_venus_shutdown;
 
-       ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC);
+       ret = venus_firmware_check(core);
        if (ret)
                goto err_core_deinit;
 
+       if (core->res->dec_nodename || core->res->enc_nodename) {
+               ret = venus_add_dynamic_nodes(core);
+               if (ret)
+                       goto err_core_deinit;
+       }
+
+       ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+       if (ret)
+               goto err_remove_dynamic_nodes;
+
+       ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC);
+       if (ret)
+               goto err_of_depopulate;
+
        ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC);
        if (ret)
-               goto err_core_deinit;
+               goto err_of_depopulate;
 
        ret = pm_runtime_put_sync(dev);
        if (ret) {
                pm_runtime_get_noresume(dev);
-               goto err_core_deinit;
+               goto err_of_depopulate;
        }
 
        venus_dbgfs_init(core);
 
        return 0;
 
+err_of_depopulate:
+       of_platform_depopulate(dev);
+err_remove_dynamic_nodes:
+       venus_remove_dynamic_nodes(core);
 err_core_deinit:
        hfi_core_deinit(core, false);
 err_venus_shutdown:
        venus_shutdown(core);
 err_firmware_deinit:
        venus_firmware_deinit(core);
-err_of_depopulate:
-       of_platform_depopulate(dev);
-err_remove_dynamic_nodes:
-       venus_remove_dynamic_nodes(core);
 err_runtime_disable:
        pm_runtime_put_noidle(dev);
        pm_runtime_disable(dev);
index db7b69b91db5649bbd9cad0866f0853f796897ac..58da4752569a306fec8c41aa89dbb90cb4a06303 100644 (file)
@@ -58,6 +58,12 @@ enum vpu_version {
        VPU_VERSION_IRIS2_1,
 };
 
+struct firmware_version {
+       u32 major;
+       u32 minor;
+       u32 rev;
+};
+
 struct venus_resources {
        u64 dma_mask;
        const struct freq_tbl *freq_tbl;
@@ -94,6 +100,7 @@ struct venus_resources {
        const char *fwname;
        const char *enc_nodename;
        const char *dec_nodename;
+       const struct firmware_version *min_fw;
 };
 
 enum venus_fmt {
@@ -231,11 +238,7 @@ struct venus_core {
        unsigned int core0_usage_count;
        unsigned int core1_usage_count;
        struct dentry *root;
-       struct venus_img_version {
-               u32 major;
-               u32 minor;
-               u32 rev;
-       } venus_ver;
+       struct firmware_version venus_ver;
        unsigned long dump_core;
        struct of_changeset *ocs;
        bool hwmode_dev;
index 4e2636b0536693a86dc51503d01dc2bca40b532a..8d80e7e44f58fa54e907bf346a8f86747ffb5d11 100644 (file)
@@ -280,6 +280,26 @@ int venus_shutdown(struct venus_core *core)
        return ret;
 }
 
+int venus_firmware_check(struct venus_core *core)
+{
+       const struct firmware_version *req = core->res->min_fw;
+       const struct firmware_version *run = &core->venus_ver;
+
+       if (!req)
+               return 0;
+
+       if (!is_fw_rev_or_newer(core, req->major, req->minor, req->rev))
+               goto error;
+
+       return 0;
+error:
+       dev_err(core->dev, "Firmware v%d.%d.%d < v%d.%d.%d\n",
+               run->major, run->minor, run->rev,
+               req->major, req->minor, req->rev);
+
+       return -EINVAL;
+}
+
 int venus_firmware_init(struct venus_core *core)
 {
        struct platform_device_info info;
index aaccd847fa30c0d146088cf77eb156b858b793e0..ead39e3797f0110e3037b427ce3de6999047ae2d 100644 (file)
@@ -9,6 +9,7 @@ struct device;
 
 int venus_firmware_init(struct venus_core *core);
 void venus_firmware_deinit(struct venus_core *core);
+int venus_firmware_check(struct venus_core *core);
 int venus_boot(struct venus_core *core);
 int venus_shutdown(struct venus_core *core);
 int venus_set_hw_state(struct venus_core *core, bool suspend);
index cf0d97cbc4631f907faf255a338ceca673eaab2b..47b99d5b5af73fd769ae024c00e86b9fe79a1cd2 100644 (file)
@@ -277,7 +277,12 @@ static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst,
 
 done:
        core->error = error;
-       complete(&core->done);
+       /*
+        * Since core_init could ask for the firmware version to be validated,
+        * completion might have to wait until the version is retrieved.
+        */
+       if (!core->res->min_fw)
+               complete(&core->done);
 }
 
 static void
@@ -328,6 +333,10 @@ done:
        if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ)
                memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS,
                       img_ver, VER_STR_SZ);
+
+       /* core_init could have had to wait for a version check */
+       if (core->res->min_fw)
+               complete(&core->done);
 }
 
 static void hfi_sys_property_info(struct venus_core *core,