SC7280 supports both Gen1 and Gen2 HFI firmware. To support both
dynamically, update the firmware loading mechanism to prioritize
Gen2 availability and detect the loaded firmware version at runtime.
The firmware loading logic is updated with the following priority:
1. Device Tree (`firmware-name`): If specified, load unconditionally.
2. Gen2 Autodetect : If no DT property exists, attempt to load the
Gen2 firmware image.
3. Gen1 Fallback (SC7280 only): If Gen2 loading fails, fallback to
the Gen1 firmware image.
At probe time, SC7280 now defaults to the Gen2 firmware descriptor and
Gen2 HFI when available. Introduce iris_detect_gen2_from_fwdata() to
detect the firmware generation by inspecting the loaded firmware image
before authentication, based on QC_IMAGE_VERSION_STRING and classify
the firmware as Gen2 if the version string starts with "vfw" or matches
"video-firmware.N.M" with N >= 2.
If the loaded firmware on SC7280 is detected as Gen1, the driver
switches the firmware descriptor and platform data to the Gen1
configuration so that the correct HFI implementation is used.
This preserves DT overrides, prefers Gen2 firmware, and maintains
compatibility with Gen1-only SC7280 devices.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_firmware.c | 65 +++++++++++++++++++---
.../platform/qcom/iris/iris_platform_common.h | 6 +-
.../media/platform/qcom/iris/iris_platform_vpu2.c | 11 +++-
.../media/platform/qcom/iris/iris_platform_vpu3x.c | 8 +--
drivers/media/platform/qcom/iris/iris_probe.c | 8 ++-
drivers/media/platform/qcom/iris/iris_vidc.c | 3 +
6 files changed, 80 insertions(+), 21 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
index 1a476146d7580849d7b68c7c15dd7f82f89a680b..481c33c9fb4daa0d547c43f776f188c17de6b35e 100644
--- a/drivers/media/platform/qcom/iris/iris_firmware.c
+++ b/drivers/media/platform/qcom/iris/iris_firmware.c
@@ -16,6 +16,39 @@
#define MAX_FIRMWARE_NAME_SIZE 128
+/* Detect Gen2 firmware by scanning the blob for:
+ * QC_IMAGE_VERSION_STRING=<version>
+ * and then checking:
+ * - version starts with "vfw", OR
+ * - version matches "video-firmware.N.M" with N >= 2
+ */
+
+static bool iris_detect_gen2_from_fwdata(const u8 *data, size_t size)
+{
+ const char *marker = "QC_IMAGE_VERSION_STRING=";
+ const size_t mlen = strlen(marker);
+ int major = 0, minor = 0;
+ char version_buf[64];
+ size_t max;
+
+ max = (size > mlen) ? size - mlen : 0;
+ for (size_t i = 0; i < max; i++) {
+ if (!memcmp(data + i, marker, mlen)) {
+ const char *found = (const char *)(data + i + mlen);
+
+ strscpy(version_buf, found, sizeof(version_buf));
+ if (!strncmp(version_buf, "vfw", 3))
+ return true;
+ if (sscanf(version_buf, "video-firmware.%d.%d", &major, &minor) == 2 &&
+ major >= 2)
+ return true;
+ break;
+ }
+ }
+
+ return false;
+}
+
static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
{
const struct firmware *firmware = NULL;
@@ -47,6 +80,14 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
goto err_release_fw;
}
+ if (of_device_is_compatible(core->dev->of_node, "qcom,sc7280-venus")) {
+ if (!iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) {
+ dev_info(core->dev, "Gen1 FW detected in %s\n", fw_name);
+ core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1;
+ core->iris_firmware_data = core->iris_firmware_desc->firmware_data;
+ }
+ }
+
mem_virt = memremap(mem_phys, res_size, MEMREMAP_WC);
if (!mem_virt) {
ret = -ENOMEM;
@@ -65,19 +106,29 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
int iris_fw_load(struct iris_core *core)
{
+ struct device_node *node = core->dev->of_node;
const struct tz_cp_config *cp_config;
const char *fwpath = NULL;
+ bool is_sc7280;
int i, ret;
- ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0,
- &fwpath);
- if (ret)
+ is_sc7280 = of_device_is_compatible(node, "qcom,sc7280-venus");
+
+ ret = of_property_read_string_index(node, "firmware-name", 0, &fwpath);
+ if (!ret) {
+ ret = iris_load_fw_to_memory(core, fwpath);
+ } else {
fwpath = core->iris_firmware_desc->fwname;
+ ret = iris_load_fw_to_memory(core, fwpath);
+ if (ret == -ENOENT && is_sc7280) {
+ dev_dbg(core->dev, "Gen2 FW not found, falling back to Gen1\n");
+ ret = iris_load_fw_to_memory(core, sc7280_data.firmware_desc_gen1->fwname);
+ }
+ }
- ret = iris_load_fw_to_memory(core, fwpath);
if (ret) {
- dev_err(core->dev, "firmware download failed\n");
- return -ENOMEM;
+ dev_err(core->dev, "firmware download failed %d\n", ret);
+ return ret;
}
ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID);
@@ -99,7 +150,7 @@ int iris_fw_load(struct iris_core *core)
}
}
- return ret;
+ return 0;
}
int iris_fw_unload(struct iris_core *core)
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index 0408d51188b27251986780de6b4672b155ab1005..7acb073f719746f57ebaa2afd9061db9239f860e 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -257,11 +257,7 @@ struct iris_firmware_desc {
};
struct iris_platform_data {
- /*
- * XXX: replace with gen1 / gen2 pointers once we have platforms
- * supporting both firmware kinds.
- */
- const struct iris_firmware_desc *firmware_desc;
+ const struct iris_firmware_desc *firmware_desc_gen1, *firmware_desc_gen2;
const struct vpu_ops *vpu_ops;
const struct icc_info *icc_tbl;
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
index 00d6244bc92fd9216bd7c0e6153689e7d8982a67..8259709ba203eac2230da3048166b33892b337b2 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
@@ -22,6 +22,12 @@ const struct iris_firmware_desc iris_vpu20_p1_gen1_desc = {
.fwname = "qcom/vpu/vpu20_p1.mbn",
};
+const struct iris_firmware_desc iris_vpu20_p1_gen2_s6_desc = {
+ .firmware_data = &iris_hfi_gen2_data,
+ .get_vpu_buffer_size = iris_vpu33_buf_size,
+ .fwname = "qcom/vpu/vpu20_p1_gen2_s6.mbn",
+};
+
const struct iris_firmware_desc iris_vpu20_p4_gen1_desc = {
.firmware_data = &iris_hfi_gen1_data,
.get_vpu_buffer_size = iris_vpu_buf_size,
@@ -65,7 +71,8 @@ static const struct tz_cp_config tz_cp_config_vpu2[] = {
};
const struct iris_platform_data sc7280_data = {
- .firmware_desc = &iris_vpu20_p1_gen1_desc,
+ .firmware_desc_gen1 = &iris_vpu20_p1_gen1_desc,
+ .firmware_desc_gen2 = &iris_vpu20_p1_gen2_s6_desc,
.vpu_ops = &iris_vpu2_ops,
.icc_tbl = iris_icc_info_vpu2,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu2),
@@ -94,7 +101,7 @@ const struct iris_platform_data sc7280_data = {
};
const struct iris_platform_data sm8250_data = {
- .firmware_desc = &iris_vpu20_p4_gen1_desc,
+ .firmware_desc_gen1 = &iris_vpu20_p4_gen1_desc,
.vpu_ops = &iris_vpu2_ops,
.icc_tbl = iris_icc_info_vpu2,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu2),
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
index 6180104f3b94bf0d5e3206481816802fbd09849d..829dc37b4058101e7dddd484533724272b502560 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
@@ -83,7 +83,7 @@ static const struct tz_cp_config tz_cp_config_vpu3[] = {
* - inst_caps to platform_inst_cap_qcs8300
*/
const struct iris_platform_data qcs8300_data = {
- .firmware_desc = &iris_vpu30_p4_s6_gen2_desc,
+ .firmware_desc_gen2 = &iris_vpu30_p4_s6_gen2_desc,
.vpu_ops = &iris_vpu3_ops,
.icc_tbl = iris_icc_info_vpu3x,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x),
@@ -112,7 +112,7 @@ const struct iris_platform_data qcs8300_data = {
};
const struct iris_platform_data sm8550_data = {
- .firmware_desc = &iris_vpu30_p4_gen2_desc,
+ .firmware_desc_gen2 = &iris_vpu30_p4_gen2_desc,
.vpu_ops = &iris_vpu3_ops,
.icc_tbl = iris_icc_info_vpu3x,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x),
@@ -147,7 +147,7 @@ const struct iris_platform_data sm8550_data = {
* - controller_rst_tbl to sm8650_controller_reset_table
*/
const struct iris_platform_data sm8650_data = {
- .firmware_desc = &iris_vpu33_p4_gen2_desc,
+ .firmware_desc_gen2 = &iris_vpu33_p4_gen2_desc,
.vpu_ops = &iris_vpu33_ops,
.icc_tbl = iris_icc_info_vpu3x,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x),
@@ -178,7 +178,7 @@ const struct iris_platform_data sm8650_data = {
};
const struct iris_platform_data sm8750_data = {
- .firmware_desc = &iris_vpu35_p4_gen2_desc,
+ .firmware_desc_gen2 = &iris_vpu35_p4_gen2_desc,
.vpu_ops = &iris_vpu35_ops,
.icc_tbl = iris_icc_info_vpu3x,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x),
diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index dbc15edc602b72fdec8bb2d8d3623676afee728c..898260a1a1ea65ba8e082b1d1df0ef5f34a733eb 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -251,7 +251,11 @@ static int iris_probe(struct platform_device *pdev)
return core->irq;
core->iris_platform_data = of_device_get_match_data(core->dev);
- core->iris_firmware_desc = core->iris_platform_data->firmware_desc;
+
+ if (core->iris_platform_data->firmware_desc_gen2)
+ core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen2;
+ else
+ core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1;
core->iris_firmware_data = core->iris_firmware_desc->firmware_data;
core->ubwc_cfg = qcom_ubwc_config_get_data();
@@ -271,8 +275,6 @@ static int iris_probe(struct platform_device *pdev)
if (ret)
return ret;
- iris_session_init_caps(core);
-
ret = v4l2_device_register(dev, &core->v4l2_dev);
if (ret)
return ret;
diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
index 807c9a20b6ba17fdda8e7e91956bdf19e83a3ad8..6fbc20366f5fd3a80468d90d813851ecf54e4cef 100644
--- a/drivers/media/platform/qcom/iris/iris_vidc.c
+++ b/drivers/media/platform/qcom/iris/iris_vidc.c
@@ -9,6 +9,7 @@
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-dma-contig.h>
+#include "iris_ctrls.h"
#include "iris_vidc.h"
#include "iris_instance.h"
#include "iris_vdec.h"
@@ -196,6 +197,8 @@ int iris_open(struct file *filp)
goto fail_m2m_release;
}
+ iris_session_init_caps(core);
+
if (inst->domain == DECODER)
ret = iris_vdec_inst_init(inst);
else if (inst->domain == ENCODER)
--
2.34.1
© 2016 - 2026 Red Hat, Inc.