On 8/14/2025 2:22 PM, Jorge Ramirez-Ortiz wrote: > 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@xxxxxxxxxxxxxxxx> > --- > drivers/media/platform/qcom/venus/core.c | 40 +++++++++++--------- > drivers/media/platform/qcom/venus/core.h | 13 ++++--- > drivers/media/platform/qcom/venus/firmware.c | 20 ++++++++++ > drivers/media/platform/qcom/venus/firmware.h | 1 + > drivers/media/platform/qcom/venus/hfi_msgs.c | 11 +++++- > 5 files changed, 61 insertions(+), 24 deletions(-) > > diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c > index 90de29f166ad..5d76e50234f6 100644 > --- a/drivers/media/platform/qcom/venus/core.c > +++ b/drivers/media/platform/qcom/venus/core.c > @@ -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); > diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h > index db7b69b91db5..58da4752569a 100644 > --- a/drivers/media/platform/qcom/venus/core.h > +++ b/drivers/media/platform/qcom/venus/core.h > @@ -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; > diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c > index 66a18830e66d..3666675ae298 100644 > --- a/drivers/media/platform/qcom/venus/firmware.c > +++ b/drivers/media/platform/qcom/venus/firmware.c > @@ -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; > diff --git a/drivers/media/platform/qcom/venus/firmware.h b/drivers/media/platform/qcom/venus/firmware.h > index aaccd847fa30..ead39e3797f0 100644 > --- a/drivers/media/platform/qcom/venus/firmware.h > +++ b/drivers/media/platform/qcom/venus/firmware.h > @@ -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); > diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c > index cf0d97cbc463..47b99d5b5af7 100644 > --- a/drivers/media/platform/qcom/venus/hfi_msgs.c > +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c > @@ -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 @@ sys_get_prop_image_version(struct venus_core *core, > 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, Reviewed-by: Dikshita Agarwal <dikshita.agarwal@xxxxxxxxxxxxxxxx> Thanks, Dikshita