* [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:58 ` sashiko-bot
2026-07-10 4:23 ` Vishnu Reddy
2026-07-09 13:41 ` [PATCH v7 02/18] media: iris: Skip UBWC configuration when not supported Dmitry Baryshkov
` (16 subsequent siblings)
17 siblings, 2 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Some Iris platforms support both Gen1 and Gen2 HFI firmware images.
Update the firmware loading logic to handle this generically by
preferring Gen2 when available, while safely falling back to Gen1
when required.
The firmware loading logic is updated with the following priority:
1. Device Tree (`firmware-name`): If specified, load unconditionally.
2. Gen2 default : If no DT override exists, select the Gen2 firmware
descriptor when present and attempt to load the corresponding
firmware image.
3. Gen1 Fallback: If loading the Gen2 firmware fails and a Gen1
descriptor is available, retry with the Gen1 firmware image.
When a platform provides both Gen1 and Gen2 firmware descriptors and the
firmware is loaded via a DT override, the driver detects the
firmware generation at runtime before authentication by inspecting
the firmware data. The firmware is classified as Gen2 if the
QC_IMAGE_VERSION_STRING starts with "vfw" or matches the
"video-firmware.N.M" format with N >= 2.
If a Gen1 firmware image is detected in this case, the driver switches
to the Gen1 firmware descriptor and associated platform data so that
the correct HFI implementation is used.
This change makes firmware generation detection platform‑agnostic,
preserves DT overrides, prefers newer Gen2 firmware when available,
and maintains compatibility with platforms that only support Gen1.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Co-developed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_core.c | 2 +
drivers/media/platform/qcom/iris/iris_firmware.c | 146 ++++++++++++++++++---
.../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 | 10 +-
drivers/media/platform/qcom/iris/iris_probe.c | 4 -
drivers/media/platform/qcom/iris/iris_vidc.c | 1 +
7 files changed, 147 insertions(+), 33 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c
index 52bf56e517f9..6dbe18be5b49 100644
--- a/drivers/media/platform/qcom/iris/iris_core.c
+++ b/drivers/media/platform/qcom/iris/iris_core.c
@@ -6,6 +6,7 @@
#include <linux/pm_runtime.h>
#include "iris_core.h"
+#include "iris_ctrls.h"
#include "iris_firmware.h"
#include "iris_state.h"
#include "iris_vpu_common.h"
@@ -79,6 +80,7 @@ int iris_core_init(struct iris_core *core)
goto error_unload_fw;
core->iris_firmware_data->init_hfi_ops(core);
+ iris_session_init_caps(core);
ret = iris_hfi_core_init(core);
if (ret)
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
index 1a476146d758..a3aa41aa1e66 100644
--- a/drivers/media/platform/qcom/iris/iris_firmware.c
+++ b/drivers/media/platform/qcom/iris/iris_firmware.c
@@ -16,20 +16,138 @@
#define MAX_FIRMWARE_NAME_SIZE 128
-static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
+/* 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)
+{
+ static const char *marker = "QC_IMAGE_VERSION_STRING=";
+ const size_t mlen = strlen(marker);
+ static const char *vfw = "vfw";
+ const size_t vfwlen = strlen(vfw);
+ static const char *vf = "video-firmware.";
+ const size_t vflen = strlen(vf);
+
+ for (size_t i = 0; i + mlen < size; i++) {
+ const char *found;
+
+ if (memcmp(data + i, marker, mlen))
+ continue;
+
+ found = data + i + mlen;
+ size -= i + mlen;
+
+ /* vfw => Gen2 */
+ if (size > vfwlen && !memcmp(found, vfw, vfwlen))
+ return true;
+
+ if (size < vflen ||
+ memcmp(found, vf, vflen))
+ return false;
+
+ found += vflen;
+ size -= vflen;
+
+ /*
+ * video-firmware.1.x is Gen1.
+ * video-firmware.2.x and video-firmware.10.x are Gen2.
+ */
+ return size >= 2 &&
+ (*found >= '2' || (*found == '1' && found[1] != '.'));
+ }
+
+ return false;
+}
+
+static const struct firmware *iris_detect_firmware(struct iris_core *core,
+ const char **fw_name)
+{
+ const struct iris_firmware_desc *desc;
+ const struct firmware *firmware;
+ bool has_both_gens;
+ int ret;
+
+ *fw_name = NULL;
+ ret = of_property_read_string_index(dev_of_node(core->dev), "firmware-name", 0, fw_name);
+
+ /*
+ * A platform may support both Gen1 and Gen2 firmware; which one is used
+ * depends on the firmware image installed on the system, not on the
+ * hardware. That installed image does not change while the device is
+ * bound, so detect the generation only once and reuse the chosen
+ * descriptor on later core bring-ups (e.g. after a system error
+ * recovery). Besides avoiding the redundant probing, this ensures
+ * core->iris_firmware_desc and iris_firmware_data are published exactly
+ * once, before any session exists, so the lockless readers in the ioctl
+ * paths never observe a reassignment.
+ */
+ if (core->iris_firmware_desc) {
+ if (ret)
+ *fw_name = core->iris_firmware_desc->fwname;
+ ret = request_firmware(&firmware, *fw_name, core->dev);
+ return ret ? ERR_PTR(ret) : firmware;
+ }
+
+ has_both_gens = core->iris_platform_data->firmware_desc_gen2 &&
+ core->iris_platform_data->firmware_desc_gen1;
+
+ if (core->iris_platform_data->firmware_desc_gen2)
+ desc = core->iris_platform_data->firmware_desc_gen2;
+ else if (core->iris_platform_data->firmware_desc_gen1)
+ desc = core->iris_platform_data->firmware_desc_gen1;
+ else
+ return ERR_PTR(-EINVAL);
+
+ if (ret) {
+ /* No firmware-name in DT: select by probing Gen2 then Gen1. */
+ *fw_name = desc->fwname;
+ if (has_both_gens)
+ ret = firmware_request_nowarn(&firmware, *fw_name, core->dev);
+ else
+ ret = request_firmware(&firmware, *fw_name, core->dev);
+ if (ret && has_both_gens) {
+ desc = core->iris_platform_data->firmware_desc_gen1;
+ *fw_name = desc->fwname;
+ ret = request_firmware(&firmware, *fw_name, core->dev);
+ }
+ if (ret)
+ return ERR_PTR(ret);
+ } else {
+ /* firmware-name given: load it and detect its generation. */
+ ret = request_firmware(&firmware, *fw_name, core->dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (has_both_gens &&
+ !iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) {
+ dev_info(core->dev, "Gen1 FW detected in %s\n", *fw_name);
+ desc = core->iris_platform_data->firmware_desc_gen1;
+ }
+ }
+
+ /* Publish iris_firmware_data first, then iris_firmware_desc (the guard). */
+ core->iris_firmware_data = desc->firmware_data;
+ core->iris_firmware_desc = desc;
+
+ return firmware;
+}
+
+static int iris_load_fw_to_memory(struct iris_core *core)
{
const struct firmware *firmware = NULL;
struct device *dev = core->dev;
struct resource res;
phys_addr_t mem_phys;
+ const char *fw_name;
size_t res_size;
ssize_t fw_size;
void *mem_virt;
int ret;
- if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4)
- return -EINVAL;
-
ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
if (ret)
return ret;
@@ -37,9 +155,9 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
mem_phys = res.start;
res_size = resource_size(&res);
- ret = request_firmware(&firmware, fw_name, dev);
- if (ret)
- return ret;
+ firmware = iris_detect_firmware(core, &fw_name);
+ if (IS_ERR(firmware))
+ return PTR_ERR(firmware);
fw_size = qcom_mdt_get_size(firmware);
if (fw_size < 0 || res_size < (size_t)fw_size) {
@@ -66,18 +184,12 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
int iris_fw_load(struct iris_core *core)
{
const struct tz_cp_config *cp_config;
- const char *fwpath = NULL;
int i, ret;
- ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0,
- &fwpath);
- if (ret)
- fwpath = core->iris_firmware_desc->fwname;
-
- ret = iris_load_fw_to_memory(core, fwpath);
+ ret = iris_load_fw_to_memory(core);
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 +211,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 c9256f2323dc..55a4fa356985 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -289,11 +289,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 6e06a32822bb..961dce2e6aa9 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 @@ static const struct iris_firmware_desc iris_vpu20_p1_gen1_desc = {
.fwname = "qcom/vpu/vpu20_p1.mbn",
};
+static 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",
+};
+
static 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 2c63adbc5579..74626b35d9cb 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
@@ -90,7 +90,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),
@@ -119,7 +119,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),
@@ -154,7 +154,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),
@@ -185,7 +185,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),
@@ -220,7 +220,7 @@ const struct iris_platform_data sm8750_data = {
* - different num_vpp_pipe
*/
const struct iris_platform_data x1p42100_data = {
- .firmware_desc = &iris_vpu30_p1_gen2_desc,
+ .firmware_desc_gen2 = &iris_vpu30_p1_gen2_desc,
.vpu_ops = &iris_vpu3_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 c2dcb50a2782..7fe31136df21 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -251,8 +251,6 @@ 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;
- core->iris_firmware_data = core->iris_firmware_desc->firmware_data;
core->ubwc_cfg = qcom_ubwc_config_get_data();
if (IS_ERR(core->ubwc_cfg))
@@ -271,8 +269,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 14d63dc76c9b..33edbc5cab8f 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"
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback
2026-07-09 13:41 ` [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback Dmitry Baryshkov
@ 2026-07-09 13:58 ` sashiko-bot
2026-07-10 4:23 ` Vishnu Reddy
1 sibling, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 13:58 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [High] Firmware generation detection fails for split `.mdt` firmware files provided via DT override.
- [High] Firmware generation detection aborts on the first occurrence of the marker string, risking false Gen1 classification.
- [Low] MAX_FIRMWARE_NAME_SIZE macro is unused after the patch.
Pre-existing issues:
- [Critical] Lockless traversal of `core->instances` linked list leads to potential Use-After-Free.
- [High] Possible NULL pointer dereference of `core->hfi_sys_ops` in the interrupt handler.
- [High] Concurrent open() allows userspace to issue ioctls to uninitialized or failed firmware.
- [Medium] iris_add_session silently fails if max_session_count is reached, causing ioctl timeouts.
--
--- Patch [1]: [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback ---
commit 895d948eb718207e479cf98e9811c2b53fd39e23
Author: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
media: iris: Add Gen2 firmware autodetect and fallback
Some Iris platforms support both Gen1 and Gen2 HFI firmware images.
Update the firmware loading logic to handle this generically by
preferring Gen2 when available, while safely falling back to Gen1
when required.
> diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c
> index 52bf56e517f91..6dbe18be5b495 100644
> --- a/drivers/media/platform/qcom/iris/iris_core.c
> +++ b/drivers/media/platform/qcom/iris/iris_core.c
> @@ -79,6 +80,7 @@ int iris_core_init(struct iris_core *core)
> goto error_unload_fw;
>
> core->iris_firmware_data->init_hfi_ops(core);
[Severity: High]
This is a pre-existing issue, but can the interrupt handler dereference a NULL
core->hfi_sys_ops here?
Looking at iris_core_init(), iris_vpu_power_on(core) is called earlier, which
enables interrupts. However, core->hfi_sys_ops is not populated until this
init_hfi_ops() call. If an interrupt fires during this window,
iris_hfi_isr_handler() will unconditionally dereference core->hfi_sys_ops and
cause a kernel panic.
[Severity: High]
This is a pre-existing issue, but can a concurrent open() cause userspace to
issue ioctls to uninitialized hardware?
In iris_core_init(), the core state is set to IRIS_CORE_INIT before waiting
for the firmware SYS_INIT_DONE response. The lock is dropped during the wait.
If a second thread concurrently calls iris_open(), it sees
core->state == IRIS_CORE_INIT, bypasses the wait, and returns success
immediately. The second thread can then issue V4L2 ioctls while the firmware
is still booting.
> + iris_session_init_caps(core);
>
> ret = iris_hfi_core_init(core);
> if (ret)
> diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
> index 1a476146d7580..a3aa41aa1e66b 100644
> --- a/drivers/media/platform/qcom/iris/iris_firmware.c
> +++ b/drivers/media/platform/qcom/iris/iris_firmware.c
> @@ -16,20 +16,138 @@
>
> #define MAX_FIRMWARE_NAME_SIZE 128
[Severity: Low]
Is the MAX_FIRMWARE_NAME_SIZE macro still needed? It appears to be unused
after the removal of the strlen check in this patch.
> -static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
> +/* 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)
> +{
> + static const char *marker = "QC_IMAGE_VERSION_STRING=";
> + const size_t mlen = strlen(marker);
> + static const char *vfw = "vfw";
> + const size_t vfwlen = strlen(vfw);
> + static const char *vf = "video-firmware.";
> + const size_t vflen = strlen(vf);
> +
> + for (size_t i = 0; i + mlen < size; i++) {
> + const char *found;
> +
> + if (memcmp(data + i, marker, mlen))
> + continue;
> +
> + found = data + i + mlen;
> + size -= i + mlen;
> +
> + /* vfw => Gen2 */
> + if (size > vfwlen && !memcmp(found, vfw, vfwlen))
> + return true;
> +
> + if (size < vflen ||
> + memcmp(found, vf, vflen))
> + return false;
[Severity: High]
Will this prematurely abort the search if the marker string is encountered but
the prefix doesn't match?
If a debug or format string matches "QC_IMAGE_VERSION_STRING=" earlier in the
binary (e.g., "Error parsing QC_IMAGE_VERSION_STRING=%s"), this function
returns false immediately instead of continuing to scan, missing the actual
version string. Should it continue searching instead?
> +
> + found += vflen;
> + size -= vflen;
[ ... ]
> + if (ret) {
> + /* No firmware-name in DT: select by probing Gen2 then Gen1. */
> + *fw_name = desc->fwname;
> + if (has_both_gens)
> + ret = firmware_request_nowarn(&firmware, *fw_name, core->dev);
> + else
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + if (ret && has_both_gens) {
> + desc = core->iris_platform_data->firmware_desc_gen1;
> + *fw_name = desc->fwname;
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + }
> + if (ret)
> + return ERR_PTR(ret);
> + } else {
> + /* firmware-name given: load it and detect its generation. */
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + if (has_both_gens &&
> + !iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) {
[Severity: High]
Does this code fail to detect Gen2 firmware when a standard split .mdt file is
provided via DT override?
If request_firmware() is called on a split .mdt file, it provides only the
ELF headers. Since the actual version string resides in the .bXX data segments,
scanning the header will miss the version string and falsely assume Gen1.
Subsequently, qcom_mdt_load() will properly load the Gen2 segments into
memory, causing a mismatch between the running firmware and the driver's HFI
operations.
> + dev_info(core->dev, "Gen1 FW detected in %s\n", *fw_name);
> + desc = core->iris_platform_data->firmware_desc_gen1;
> + }
> + }
[ ... ]
> diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c
> index 14d63dc76c9ba..33edbc5cab8f0 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"
[Severity: Medium]
This isn't a bug introduced by this patch, but does iris_add_session() silently
fail when max_session_count is reached?
When userspace opens more instances than max_session_count, iris_add_session()
skips adding the instance but returns void. iris_open() continues as if
successful and provides an FD to userspace. Subsequent ioctls will timeout
because the responses are dropped since the instance is missing from
core->instances.
[Severity: Critical]
This is a pre-existing issue, but is it safe to traverse core->instances
without holding core->lock in iris_check_session_supported()?
iris_check_session_supported() uses list_for_each_entry() to traverse the
core->instances list holding only inst->lock. Concurrently, another thread
executing iris_close() can call iris_remove_session() (which holds
core->lock), remove a different instance from the list via list_del_init(),
and free it. The lockless traversal will then follow a freed pointer,
leading to a use-after-free.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback
2026-07-09 13:41 ` [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback Dmitry Baryshkov
2026-07-09 13:58 ` sashiko-bot
@ 2026-07-10 4:23 ` Vishnu Reddy
1 sibling, 0 replies; 30+ messages in thread
From: Vishnu Reddy @ 2026-07-10 4:23 UTC (permalink / raw)
To: Dmitry Baryshkov, Vikash Garodia, Abhinav Kumar,
Bryan O'Donoghue, Mauro Carvalho Chehab, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
On 7/9/2026 7:11 PM, Dmitry Baryshkov wrote:
> From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
>
> Some Iris platforms support both Gen1 and Gen2 HFI firmware images.
> Update the firmware loading logic to handle this generically by
> preferring Gen2 when available, while safely falling back to Gen1
> when required.
>
> The firmware loading logic is updated with the following priority:
> 1. Device Tree (`firmware-name`): If specified, load unconditionally.
> 2. Gen2 default : If no DT override exists, select the Gen2 firmware
> descriptor when present and attempt to load the corresponding
> firmware image.
> 3. Gen1 Fallback: If loading the Gen2 firmware fails and a Gen1
> descriptor is available, retry with the Gen1 firmware image.
>
> When a platform provides both Gen1 and Gen2 firmware descriptors and the
> firmware is loaded via a DT override, the driver detects the
> firmware generation at runtime before authentication by inspecting
> the firmware data. The firmware is classified as Gen2 if the
> QC_IMAGE_VERSION_STRING starts with "vfw" or matches the
> "video-firmware.N.M" format with N >= 2.
>
> If a Gen1 firmware image is detected in this case, the driver switches
> to the Gen1 firmware descriptor and associated platform data so that
> the correct HFI implementation is used.
>
> This change makes firmware generation detection platform‑agnostic,
> preserves DT overrides, prefers newer Gen2 firmware when available,
> and maintains compatibility with platforms that only support Gen1.
>
> Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
> Co-developed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> ---
> drivers/media/platform/qcom/iris/iris_core.c | 2 +
> drivers/media/platform/qcom/iris/iris_firmware.c | 146 ++++++++++++++++++---
> .../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 | 10 +-
> drivers/media/platform/qcom/iris/iris_probe.c | 4 -
> drivers/media/platform/qcom/iris/iris_vidc.c | 1 +
> 7 files changed, 147 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c
> index 52bf56e517f9..6dbe18be5b49 100644
> --- a/drivers/media/platform/qcom/iris/iris_core.c
> +++ b/drivers/media/platform/qcom/iris/iris_core.c
> @@ -6,6 +6,7 @@
> #include <linux/pm_runtime.h>
>
> #include "iris_core.h"
> +#include "iris_ctrls.h"
> #include "iris_firmware.h"
> #include "iris_state.h"
> #include "iris_vpu_common.h"
> @@ -79,6 +80,7 @@ int iris_core_init(struct iris_core *core)
> goto error_unload_fw;
>
> core->iris_firmware_data->init_hfi_ops(core);
> + iris_session_init_caps(core);
>
> ret = iris_hfi_core_init(core);
> if (ret)
> diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
> index 1a476146d758..a3aa41aa1e66 100644
> --- a/drivers/media/platform/qcom/iris/iris_firmware.c
> +++ b/drivers/media/platform/qcom/iris/iris_firmware.c
> @@ -16,20 +16,138 @@
>
> #define MAX_FIRMWARE_NAME_SIZE 128
>
> -static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
> +/* 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)
> +{
> + static const char *marker = "QC_IMAGE_VERSION_STRING=";
> + const size_t mlen = strlen(marker);
> + static const char *vfw = "vfw";
> + const size_t vfwlen = strlen(vfw);
> + static const char *vf = "video-firmware.";
> + const size_t vflen = strlen(vf);
> +
> + for (size_t i = 0; i + mlen < size; i++) {
> + const char *found;
> +
> + if (memcmp(data + i, marker, mlen))
> + continue;
> +
> + found = data + i + mlen;
> + size -= i + mlen;
> +
> + /* vfw => Gen2 */
> + if (size > vfwlen && !memcmp(found, vfw, vfwlen))
> + return true;
> +
> + if (size < vflen ||
> + memcmp(found, vf, vflen))
> + return false;
> +
> + found += vflen;
> + size -= vflen;
> +
> + /*
> + * video-firmware.1.x is Gen1.
> + * video-firmware.2.x and video-firmware.10.x are Gen2.
> + */
> + return size >= 2 &&
> + (*found >= '2' || (*found == '1' && found[1] != '.'));
> + }
> +
> + return false;
> +}
> +
> +static const struct firmware *iris_detect_firmware(struct iris_core *core,
> + const char **fw_name)
> +{
> + const struct iris_firmware_desc *desc;
> + const struct firmware *firmware;
> + bool has_both_gens;
> + int ret;
> +
> + *fw_name = NULL;
> + ret = of_property_read_string_index(dev_of_node(core->dev), "firmware-name", 0, fw_name);
> +
> + /*
> + * A platform may support both Gen1 and Gen2 firmware; which one is used
> + * depends on the firmware image installed on the system, not on the
> + * hardware. That installed image does not change while the device is
> + * bound, so detect the generation only once and reuse the chosen
> + * descriptor on later core bring-ups (e.g. after a system error
> + * recovery). Besides avoiding the redundant probing, this ensures
> + * core->iris_firmware_desc and iris_firmware_data are published exactly
> + * once, before any session exists, so the lockless readers in the ioctl
> + * paths never observe a reassignment.
> + */
> + if (core->iris_firmware_desc) {
> + if (ret)
> + *fw_name = core->iris_firmware_desc->fwname;
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + return ret ? ERR_PTR(ret) : firmware;
> + }
> +
> + has_both_gens = core->iris_platform_data->firmware_desc_gen2 &&
> + core->iris_platform_data->firmware_desc_gen1;
> +
> + if (core->iris_platform_data->firmware_desc_gen2)
> + desc = core->iris_platform_data->firmware_desc_gen2;
> + else if (core->iris_platform_data->firmware_desc_gen1)
> + desc = core->iris_platform_data->firmware_desc_gen1;
> + else
> + return ERR_PTR(-EINVAL);
> +
> + if (ret) {
> + /* No firmware-name in DT: select by probing Gen2 then Gen1. */
> + *fw_name = desc->fwname;
> + if (has_both_gens)
> + ret = firmware_request_nowarn(&firmware, *fw_name, core->dev);
> + else
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + if (ret && has_both_gens) {
> + desc = core->iris_platform_data->firmware_desc_gen1;
> + *fw_name = desc->fwname;
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + }
> + if (ret)
> + return ERR_PTR(ret);
> + } else {
> + /* firmware-name given: load it and detect its generation. */
> + ret = request_firmware(&firmware, *fw_name, core->dev);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + if (has_both_gens &&
> + !iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) {
> + dev_info(core->dev, "Gen1 FW detected in %s\n", *fw_name);
> + desc = core->iris_platform_data->firmware_desc_gen1;
> + }
> + }
> +
> + /* Publish iris_firmware_data first, then iris_firmware_desc (the guard). */
> + core->iris_firmware_data = desc->firmware_data;
> + core->iris_firmware_desc = desc;
> +
> + return firmware;
> +}
> +
> +static int iris_load_fw_to_memory(struct iris_core *core)
> {
> const struct firmware *firmware = NULL;
> struct device *dev = core->dev;
> struct resource res;
> phys_addr_t mem_phys;
> + const char *fw_name;
> size_t res_size;
> ssize_t fw_size;
> void *mem_virt;
> int ret;
>
> - if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4)
> - return -EINVAL;
> -
> ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
> if (ret)
> return ret;
> @@ -37,9 +155,9 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
> mem_phys = res.start;
> res_size = resource_size(&res);
>
> - ret = request_firmware(&firmware, fw_name, dev);
> - if (ret)
> - return ret;
> + firmware = iris_detect_firmware(core, &fw_name);
> + if (IS_ERR(firmware))
> + return PTR_ERR(firmware);
>
> fw_size = qcom_mdt_get_size(firmware);
> if (fw_size < 0 || res_size < (size_t)fw_size) {
> @@ -66,18 +184,12 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
> int iris_fw_load(struct iris_core *core)
> {
> const struct tz_cp_config *cp_config;
> - const char *fwpath = NULL;
> int i, ret;
>
> - ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0,
> - &fwpath);
> - if (ret)
> - fwpath = core->iris_firmware_desc->fwname;
> -
> - ret = iris_load_fw_to_memory(core, fwpath);
> + ret = iris_load_fw_to_memory(core);
> 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 +211,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 c9256f2323dc..55a4fa356985 100644
> --- a/drivers/media/platform/qcom/iris/iris_platform_common.h
> +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
> @@ -289,11 +289,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 6e06a32822bb..961dce2e6aa9 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 @@ static const struct iris_firmware_desc iris_vpu20_p1_gen1_desc = {
> .fwname = "qcom/vpu/vpu20_p1.mbn",
> };
>
> +static 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",
> +};
> +
> static 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 2c63adbc5579..74626b35d9cb 100644
> --- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
> +++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
> @@ -90,7 +90,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),
> @@ -119,7 +119,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),
> @@ -154,7 +154,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),
> @@ -185,7 +185,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),
> @@ -220,7 +220,7 @@ const struct iris_platform_data sm8750_data = {
> * - different num_vpp_pipe
> */
> const struct iris_platform_data x1p42100_data = {
> - .firmware_desc = &iris_vpu30_p1_gen2_desc,
> + .firmware_desc_gen2 = &iris_vpu30_p1_gen2_desc,
> .vpu_ops = &iris_vpu3_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 c2dcb50a2782..7fe31136df21 100644
> --- a/drivers/media/platform/qcom/iris/iris_probe.c
> +++ b/drivers/media/platform/qcom/iris/iris_probe.c
> @@ -251,8 +251,6 @@ 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;
> - core->iris_firmware_data = core->iris_firmware_desc->firmware_data;
>
> core->ubwc_cfg = qcom_ubwc_config_get_data();
> if (IS_ERR(core->ubwc_cfg))
> @@ -271,8 +269,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 14d63dc76c9b..33edbc5cab8f 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"
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 02/18] media: iris: Skip UBWC configuration when not supported
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 03/18] media: iris: drop IRIS_FMT_foo enumeration Dmitry Baryshkov
` (15 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal, Konrad Dybcio
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
UBWC configuration is not applicable to all SoCs. Add a check to avoid
configuring UBWC during sys init on unsupported platforms.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c
index 0d05dd2afc07..6e04175eb904 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c
@@ -140,6 +140,9 @@ void iris_hfi_gen2_packet_sys_init(struct iris_core *core, struct iris_hfi_heade
&payload,
sizeof(u32));
+ if (!ubwc->ubwc_enc_version)
+ return;
+
payload = qcom_ubwc_macrotile_mode(ubwc) ? 8 : 4;
iris_hfi_gen2_create_packet(hdr,
HFI_PROP_UBWC_MAX_CHANNELS,
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 03/18] media: iris: drop IRIS_FMT_foo enumeration
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 01/18] media: iris: Add Gen2 firmware autodetect and fallback Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 02/18] media: iris: Skip UBWC configuration when not supported Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 04/18] media: iris: Filter UBWC raw formats based on hardware capabilities Dmitry Baryshkov
` (14 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
The IRIS_FMT_foo defines are only used for indexing values in the format
enumeration arrays. However this kind of enumeration doesn't follow the
V4L2 logic (which expects an array with consequtive indexing rather
than a sparse array) and complicates adding support for platforms which
support different sets of formats. Drop this enumeration and use flat
lists of supported formats.
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_instance.h | 14 --------------
drivers/media/platform/qcom/iris/iris_platform_vpu2.c | 6 +++---
drivers/media/platform/qcom/iris/iris_platform_vpu3x.c | 8 ++++----
drivers/media/platform/qcom/iris/iris_vdec.c | 8 ++++----
drivers/media/platform/qcom/iris/iris_venc.c | 8 ++++----
5 files changed, 15 insertions(+), 29 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h
index a770331d1675..ffdbbd20901a 100644
--- a/drivers/media/platform/qcom/iris/iris_instance.h
+++ b/drivers/media/platform/qcom/iris/iris_instance.h
@@ -17,20 +17,6 @@
struct iris_hfi_session_ops;
-enum iris_fmt_type_out {
- IRIS_FMT_H264,
- IRIS_FMT_HEVC,
- IRIS_FMT_VP9,
- IRIS_FMT_AV1,
-};
-
-enum iris_fmt_type_cap {
- IRIS_FMT_NV12,
- IRIS_FMT_QC08C,
- IRIS_FMT_TP10,
- IRIS_FMT_QC10C,
-};
-
/**
* struct iris_inst - holds per video instance parameters
*
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
index 961dce2e6aa9..ba91672df1bb 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
@@ -35,9 +35,9 @@ static const struct iris_firmware_desc iris_vpu20_p4_gen1_desc = {
};
static const u32 iris_fmts_vpu2_dec[] = {
- [IRIS_FMT_H264] = V4L2_PIX_FMT_H264,
- [IRIS_FMT_HEVC] = V4L2_PIX_FMT_HEVC,
- [IRIS_FMT_VP9] = V4L2_PIX_FMT_VP9,
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_HEVC,
+ V4L2_PIX_FMT_VP9,
};
static struct platform_inst_caps platform_inst_cap_vpu2 = {
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
index 74626b35d9cb..7098b652c117 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
@@ -49,10 +49,10 @@ static const struct iris_firmware_desc iris_vpu35_p4_gen2_desc = {
};
static const u32 iris_fmts_vpu3x_dec[] = {
- [IRIS_FMT_H264] = V4L2_PIX_FMT_H264,
- [IRIS_FMT_HEVC] = V4L2_PIX_FMT_HEVC,
- [IRIS_FMT_VP9] = V4L2_PIX_FMT_VP9,
- [IRIS_FMT_AV1] = V4L2_PIX_FMT_AV1,
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_HEVC,
+ V4L2_PIX_FMT_VP9,
+ V4L2_PIX_FMT_AV1,
};
static const struct icc_info iris_icc_info_vpu3x[] = {
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c
index 9e228b70420e..4c8bc7aac135 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/iris/iris_vdec.c
@@ -63,10 +63,10 @@ int iris_vdec_inst_init(struct iris_inst *inst)
}
static const u32 iris_vdec_formats_cap[] = {
- [IRIS_FMT_NV12] = V4L2_PIX_FMT_NV12,
- [IRIS_FMT_QC08C] = V4L2_PIX_FMT_QC08C,
- [IRIS_FMT_TP10] = V4L2_PIX_FMT_P010,
- [IRIS_FMT_QC10C] = V4L2_PIX_FMT_QC10C,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_QC08C,
+ V4L2_PIX_FMT_P010,
+ V4L2_PIX_FMT_QC10C,
};
static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c
index a945992f63aa..16c52ad07e2c 100644
--- a/drivers/media/platform/qcom/iris/iris_venc.c
+++ b/drivers/media/platform/qcom/iris/iris_venc.c
@@ -80,13 +80,13 @@ int iris_venc_inst_init(struct iris_inst *inst)
}
static const u32 iris_venc_formats_cap[] = {
- [IRIS_FMT_H264] = V4L2_PIX_FMT_H264,
- [IRIS_FMT_HEVC] = V4L2_PIX_FMT_HEVC,
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_HEVC,
};
static const u32 iris_venc_formats_out[] = {
- [IRIS_FMT_NV12] = V4L2_PIX_FMT_NV12,
- [IRIS_FMT_QC08C] = V4L2_PIX_FMT_QC08C,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_QC08C,
};
static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 04/18] media: iris: Filter UBWC raw formats based on hardware capabilities
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (2 preceding siblings ...)
2026-07-09 13:41 ` [PATCH v7 03/18] media: iris: drop IRIS_FMT_foo enumeration Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 05/18] media: iris: Introduce set_preset_register as a vpu_op Dmitry Baryshkov
` (13 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
The raw formats supported by Iris were previously advertised
unconditionally, assuming UBWC support on all platforms. However, some
platforms do not support UBWC which results in incorrect format
capability exposure.
Use the UBWC configuration provided by the platform to dynamically
filter raw formats at runtime. If UBWC is not supported, UBWC-based
formats are omitted from the advertised capability list, while linear
formats remain available.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_vdec.c | 26 ++++++++++++++++++++++----
drivers/media/platform/qcom/iris/iris_venc.c | 25 +++++++++++++++++++++----
2 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c
index 4c8bc7aac135..9fee5f28097d 100644
--- a/drivers/media/platform/qcom/iris/iris_vdec.c
+++ b/drivers/media/platform/qcom/iris/iris_vdec.c
@@ -3,6 +3,7 @@
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/soc/qcom/ubwc.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
@@ -69,8 +70,14 @@ static const u32 iris_vdec_formats_cap[] = {
V4L2_PIX_FMT_QC10C,
};
+static const u32 iris_vdec_formats_noubwc_cap[] = {
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_P010,
+};
+
static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size, i;
const u32 *fmt;
@@ -80,8 +87,13 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
size = inst->core->iris_platform_data->inst_iris_fmts_size;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- fmt = iris_vdec_formats_cap;
- size = ARRAY_SIZE(iris_vdec_formats_cap);
+ if (ubwc->ubwc_enc_version) {
+ fmt = iris_vdec_formats_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_cap);
+ } else {
+ fmt = iris_vdec_formats_noubwc_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_noubwc_cap);
+ }
break;
default:
return false;
@@ -110,6 +122,7 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size;
const u32 *fmt;
@@ -119,8 +132,13 @@ static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
size = inst->core->iris_platform_data->inst_iris_fmts_size;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- fmt = iris_vdec_formats_cap;
- size = ARRAY_SIZE(iris_vdec_formats_cap);
+ if (ubwc->ubwc_enc_version) {
+ fmt = iris_vdec_formats_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_cap);
+ } else {
+ fmt = iris_vdec_formats_noubwc_cap;
+ size = ARRAY_SIZE(iris_vdec_formats_noubwc_cap);
+ }
break;
default:
return 0;
diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c
index 16c52ad07e2c..2f2c56bf9122 100644
--- a/drivers/media/platform/qcom/iris/iris_venc.c
+++ b/drivers/media/platform/qcom/iris/iris_venc.c
@@ -3,6 +3,7 @@
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/soc/qcom/ubwc.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
@@ -89,15 +90,25 @@ static const u32 iris_venc_formats_out[] = {
V4L2_PIX_FMT_QC08C,
};
+static const u32 iris_venc_formats_noubwc_out[] = {
+ V4L2_PIX_FMT_NV12,
+};
+
static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size, i;
const u32 *fmt;
switch (type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- fmt = iris_venc_formats_out;
- size = ARRAY_SIZE(iris_venc_formats_out);
+ if (ubwc->ubwc_enc_version) {
+ fmt = iris_venc_formats_out;
+ size = ARRAY_SIZE(iris_venc_formats_out);
+ } else {
+ fmt = iris_venc_formats_noubwc_out;
+ size = ARRAY_SIZE(iris_venc_formats_noubwc_out);
+ }
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
fmt = iris_venc_formats_cap;
@@ -117,13 +128,19 @@ static bool check_format(struct iris_inst *inst, u32 pixfmt, u32 type)
static u32 find_format_by_index(struct iris_inst *inst, u32 index, u32 type)
{
+ const struct qcom_ubwc_cfg_data *ubwc = inst->core->ubwc_cfg;
unsigned int size;
const u32 *fmt;
switch (type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- fmt = iris_venc_formats_out;
- size = ARRAY_SIZE(iris_venc_formats_out);
+ if (ubwc->ubwc_enc_version) {
+ fmt = iris_venc_formats_out;
+ size = ARRAY_SIZE(iris_venc_formats_out);
+ } else {
+ fmt = iris_venc_formats_noubwc_out;
+ size = ARRAY_SIZE(iris_venc_formats_noubwc_out);
+ }
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
fmt = iris_venc_formats_cap;
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 05/18] media: iris: Introduce set_preset_register as a vpu_op
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (3 preceding siblings ...)
2026-07-09 13:41 ` [PATCH v7 04/18] media: iris: Filter UBWC raw formats based on hardware capabilities Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 06/18] media: iris: Introduce interrupt_init " Dmitry Baryshkov
` (12 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
The set_preset_registers sequence is currently shared across all
supported devices. Starting with Qualcomm QCM2290 (AR50LT), the register
programming would differ.
Move set_preset_register into a vpu_op to allow per-device
customization.
This change prepares the driver for upcoming hardware variants.
No functional change so far for existing devices.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_vpu2.c | 1 +
drivers/media/platform/qcom/iris/iris_vpu3x.c | 3 +++
drivers/media/platform/qcom/iris/iris_vpu4x.c | 1 +
drivers/media/platform/qcom/iris/iris_vpu_common.c | 2 +-
drivers/media/platform/qcom/iris/iris_vpu_common.h | 1 +
5 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c
index b8714dcbad10..2dc121a3f5e8 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu2.c
@@ -45,4 +45,5 @@ const struct vpu_ops iris_vpu2_ops = {
.power_on_controller = iris_vpu_power_on_controller,
.calc_freq = iris_vpu2_calc_freq,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c
index 3dad47be78b5..dc02ced1b931 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c
@@ -261,6 +261,7 @@ const struct vpu_ops iris_vpu3_ops = {
.power_on_controller = iris_vpu_power_on_controller,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
const struct vpu_ops iris_vpu33_ops = {
@@ -270,6 +271,7 @@ const struct vpu_ops iris_vpu33_ops = {
.power_on_controller = iris_vpu_power_on_controller,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
const struct vpu_ops iris_vpu35_ops = {
@@ -280,4 +282,5 @@ const struct vpu_ops iris_vpu35_ops = {
.program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu4x.c b/drivers/media/platform/qcom/iris/iris_vpu4x.c
index 02e100a4045f..f608a297d4a3 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu4x.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu4x.c
@@ -368,4 +368,5 @@ const struct vpu_ops iris_vpu4x_ops = {
.program_bootup_registers = iris_vpu35_vpu4x_program_bootup_registers,
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu4x_set_hwmode,
+ .set_preset_registers = iris_vpu_set_preset_registers,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c
index ab41da1f47c8..a49113b0da23 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c
@@ -483,7 +483,7 @@ int iris_vpu_power_on(struct iris_core *core)
iris_opp_set_rate(core->dev, freq);
- iris_vpu_set_preset_registers(core);
+ core->iris_platform_data->vpu_ops->set_preset_registers(core);
iris_vpu_interrupt_init(core);
core->intr_status = 0;
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h
index 09799a375c14..21ed4c9bd5e3 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h
@@ -22,6 +22,7 @@ struct vpu_ops {
void (*program_bootup_registers)(struct iris_core *core);
u64 (*calc_freq)(struct iris_inst *inst, size_t data_size);
int (*set_hwmode)(struct iris_core *core);
+ void (*set_preset_registers)(struct iris_core *core);
};
int iris_vpu_boot_firmware(struct iris_core *core);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 06/18] media: iris: Introduce interrupt_init as a vpu_op
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (4 preceding siblings ...)
2026-07-09 13:41 ` [PATCH v7 05/18] media: iris: Introduce set_preset_register as a vpu_op Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 07/18] media: iris: add vpu op hook to disable ARP buffer Dmitry Baryshkov
` (11 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
The interrupt_init sequence is currently shared across all supported
devices. Starting with Qualcomm QCM2290 (AR50LT), the register
programming would differ.
Move interrupt_init into a vpu_op to allow per-device customization.
This change prepares the driver for upcoming hardware variants.
No functional change so far for existing devices.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_vpu2.c | 1 +
drivers/media/platform/qcom/iris/iris_vpu3x.c | 3 +++
drivers/media/platform/qcom/iris/iris_vpu4x.c | 1 +
drivers/media/platform/qcom/iris/iris_vpu_common.c | 4 ++--
drivers/media/platform/qcom/iris/iris_vpu_common.h | 2 ++
5 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c
index 2dc121a3f5e8..dd2eeae0d9eb 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu2.c
@@ -46,4 +46,5 @@ const struct vpu_ops iris_vpu2_ops = {
.calc_freq = iris_vpu2_calc_freq,
.set_hwmode = iris_vpu_set_hwmode,
.set_preset_registers = iris_vpu_set_preset_registers,
+ .interrupt_init = iris_vpu_interrupt_init,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c
index dc02ced1b931..c3b760730c98 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c
@@ -262,6 +262,7 @@ const struct vpu_ops iris_vpu3_ops = {
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
.set_preset_registers = iris_vpu_set_preset_registers,
+ .interrupt_init = iris_vpu_interrupt_init,
};
const struct vpu_ops iris_vpu33_ops = {
@@ -272,6 +273,7 @@ const struct vpu_ops iris_vpu33_ops = {
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
.set_preset_registers = iris_vpu_set_preset_registers,
+ .interrupt_init = iris_vpu_interrupt_init,
};
const struct vpu_ops iris_vpu35_ops = {
@@ -283,4 +285,5 @@ const struct vpu_ops iris_vpu35_ops = {
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
.set_preset_registers = iris_vpu_set_preset_registers,
+ .interrupt_init = iris_vpu_interrupt_init,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu4x.c b/drivers/media/platform/qcom/iris/iris_vpu4x.c
index f608a297d4a3..90ccdc0d2a07 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu4x.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu4x.c
@@ -369,4 +369,5 @@ const struct vpu_ops iris_vpu4x_ops = {
.calc_freq = iris_vpu3x_vpu4x_calculate_frequency,
.set_hwmode = iris_vpu4x_set_hwmode,
.set_preset_registers = iris_vpu_set_preset_registers,
+ .interrupt_init = iris_vpu_interrupt_init,
};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c
index a49113b0da23..375bcd923476 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c
@@ -31,7 +31,7 @@
#define UC_REGION_ADDR (CPU_CS_BASE_OFFS + 0x64)
#define UC_REGION_SIZE (CPU_CS_BASE_OFFS + 0x68)
-static void iris_vpu_interrupt_init(struct iris_core *core)
+void iris_vpu_interrupt_init(struct iris_core *core)
{
u32 mask_val;
@@ -485,7 +485,7 @@ int iris_vpu_power_on(struct iris_core *core)
core->iris_platform_data->vpu_ops->set_preset_registers(core);
- iris_vpu_interrupt_init(core);
+ core->iris_platform_data->vpu_ops->interrupt_init(core);
core->intr_status = 0;
enable_irq(core->irq);
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h
index 21ed4c9bd5e3..9151545065cd 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h
@@ -23,6 +23,7 @@ struct vpu_ops {
u64 (*calc_freq)(struct iris_inst *inst, size_t data_size);
int (*set_hwmode)(struct iris_core *core);
void (*set_preset_registers)(struct iris_core *core);
+ void (*interrupt_init)(struct iris_core *core);
};
int iris_vpu_boot_firmware(struct iris_core *core);
@@ -44,5 +45,6 @@ void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core);
u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size);
void iris_vpu_set_preset_registers(struct iris_core *core);
+void iris_vpu_interrupt_init(struct iris_core *core);
#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 07/18] media: iris: add vpu op hook to disable ARP buffer
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (5 preceding siblings ...)
2026-07-09 13:41 ` [PATCH v7 06/18] media: iris: Introduce interrupt_init " Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:41 ` [PATCH v7 08/18] media: iris: Add platform data field for watchdog interrupt mask Dmitry Baryshkov
` (10 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
On AR50LT platforms AbsolutelyPerfectRouting (ARP) needs to be disabled
so firmware can configure the ARP internal buffer as non-secure for
encoder usage. In preparation of adding support for AR50LT platforms,
add an optional disable_arp callback to the VPU ops and invoke it from
core init and resume paths.
No functional change for existing platforms.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_core.c | 4 ++++
drivers/media/platform/qcom/iris/iris_hfi_common.c | 4 ++++
drivers/media/platform/qcom/iris/iris_vpu_common.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c
index 6dbe18be5b49..526f92575264 100644
--- a/drivers/media/platform/qcom/iris/iris_core.c
+++ b/drivers/media/platform/qcom/iris/iris_core.c
@@ -46,6 +46,7 @@ static int iris_wait_for_system_response(struct iris_core *core)
int iris_core_init(struct iris_core *core)
{
+ const struct vpu_ops *vpu_ops = core->iris_platform_data->vpu_ops;
int ret;
mutex_lock(&core->lock);
@@ -79,6 +80,9 @@ int iris_core_init(struct iris_core *core)
if (ret)
goto error_unload_fw;
+ if (vpu_ops->disable_arp)
+ vpu_ops->disable_arp(core);
+
core->iris_firmware_data->init_hfi_ops(core);
iris_session_init_caps(core);
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.c b/drivers/media/platform/qcom/iris/iris_hfi_common.c
index 8769ec61f117..8f04f3793d9a 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_common.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_common.c
@@ -144,6 +144,7 @@ int iris_hfi_pm_suspend(struct iris_core *core)
int iris_hfi_pm_resume(struct iris_core *core)
{
+ const struct vpu_ops *vpu_ops = core->iris_platform_data->vpu_ops;
const struct iris_hfi_sys_ops *ops = core->hfi_sys_ops;
int ret;
@@ -163,6 +164,9 @@ int iris_hfi_pm_resume(struct iris_core *core)
if (ret)
goto err_suspend_hw;
+ if (vpu_ops->disable_arp)
+ vpu_ops->disable_arp(core);
+
ret = ops->sys_interframe_powercollapse(core);
if (ret)
goto err_suspend_hw;
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h
index 9151545065cd..71d96921ed37 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h
@@ -24,6 +24,7 @@ struct vpu_ops {
int (*set_hwmode)(struct iris_core *core);
void (*set_preset_registers)(struct iris_core *core);
void (*interrupt_init)(struct iris_core *core);
+ void (*disable_arp)(struct iris_core *core);
};
int iris_vpu_boot_firmware(struct iris_core *core);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 08/18] media: iris: Add platform data field for watchdog interrupt mask
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (6 preceding siblings ...)
2026-07-09 13:41 ` [PATCH v7 07/18] media: iris: add vpu op hook to disable ARP buffer Dmitry Baryshkov
@ 2026-07-09 13:41 ` Dmitry Baryshkov
2026-07-09 13:42 ` [PATCH v7 09/18] media: iris: Add platform flag for instantaneous bandwidth voting Dmitry Baryshkov
` (9 subsequent siblings)
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:41 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
For AR50LT core, the value of WRAPPER_INTR_STATUS_A2HWD_BMASK differs
from the currently supported VPUs. In preparation for adding AR50LT
support in subsequent patches, introduce a platform data field,
wd_intr_mask, to capture the watchdog interrupt bitmask per platform.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_platform_common.h | 1 +
drivers/media/platform/qcom/iris/iris_platform_vpu2.c | 4 ++++
drivers/media/platform/qcom/iris/iris_platform_vpu3x.c | 7 +++++++
drivers/media/platform/qcom/iris/iris_vpu_common.c | 8 +++++---
drivers/media/platform/qcom/iris/iris_vpu_register_defines.h | 1 -
5 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index 55a4fa356985..81fcb2854772 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -315,6 +315,7 @@ struct iris_platform_data {
u32 tz_cp_config_data_size;
u32 num_vpp_pipe;
bool no_aon;
+ u32 wd_intr_mask;
u32 max_session_count;
/* max number of macroblocks per frame supported */
u32 max_core_mbpf;
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
index ba91672df1bb..940daddbafcf 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
@@ -16,6 +16,8 @@
#include "iris_platform_sc7280.h"
#include "iris_platform_sm8250.h"
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3)
+
static const struct iris_firmware_desc iris_vpu20_p1_gen1_desc = {
.firmware_data = &iris_hfi_gen1_data,
.get_vpu_buffer_size = iris_vpu_buf_size,
@@ -94,6 +96,7 @@ const struct iris_platform_data sc7280_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu2),
.num_vpp_pipe = 1,
.no_aon = true,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = 4096 * 2176 / 256 * 2 + 1920 * 1088 / 256,
/* max spec for SC7280 is 4096x2176@60fps */
@@ -124,6 +127,7 @@ const struct iris_platform_data sm8250_data = {
.tz_cp_config_data = tz_cp_config_vpu2,
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu2),
.num_vpp_pipe = 4,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
index 7098b652c117..eeedde8fc9ce 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
@@ -18,6 +18,8 @@
#include "iris_platform_sm8750.h"
#include "iris_platform_x1p42100.h"
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3)
+
static const struct iris_firmware_desc iris_vpu30_p4_s6_gen2_desc = {
.firmware_data = &iris_hfi_gen2_data,
.get_vpu_buffer_size = iris_vpu_buf_size,
@@ -113,6 +115,7 @@ const struct iris_platform_data qcs8300_data = {
.tz_cp_config_data = tz_cp_config_vpu3,
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 2,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = ((4096 * 2176) / 256) * 4,
.max_core_mbps = (((3840 * 2176) / 256) * 120),
@@ -142,6 +145,7 @@ const struct iris_platform_data sm8550_data = {
.tz_cp_config_data = tz_cp_config_vpu3,
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 4,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
@@ -179,6 +183,7 @@ const struct iris_platform_data sm8650_data = {
.tz_cp_config_data = tz_cp_config_vpu3,
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 4,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
@@ -208,6 +213,7 @@ const struct iris_platform_data sm8750_data = {
.tz_cp_config_data = tz_cp_config_vpu3,
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 4,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
@@ -243,6 +249,7 @@ const struct iris_platform_data x1p42100_data = {
.tz_cp_config_data = tz_cp_config_vpu3,
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 1,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c
index 375bcd923476..41498f94480e 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c
@@ -109,11 +109,11 @@ void iris_vpu_raise_interrupt(struct iris_core *core)
void iris_vpu_clear_interrupt(struct iris_core *core)
{
+ u32 wd_intr_mask = core->iris_platform_data->wd_intr_mask;
u32 intr_status, mask;
intr_status = readl(core->reg_base + WRAPPER_INTR_STATUS);
- mask = (WRAPPER_INTR_STATUS_A2H_BMSK |
- WRAPPER_INTR_STATUS_A2HWD_BMSK |
+ mask = (WRAPPER_INTR_STATUS_A2H_BMSK | wd_intr_mask |
CTRL_INIT_IDLE_MSG_BMSK);
if (intr_status & mask)
@@ -124,7 +124,9 @@ void iris_vpu_clear_interrupt(struct iris_core *core)
int iris_vpu_watchdog(struct iris_core *core, u32 intr_status)
{
- if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK) {
+ u32 wd_intr_mask = core->iris_platform_data->wd_intr_mask;
+
+ if (intr_status & wd_intr_mask) {
dev_err(core->dev, "received watchdog interrupt\n");
return -ETIME;
}
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h b/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h
index 72168b9ffa73..4fffa094c52f 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_register_defines.h
@@ -41,7 +41,6 @@
#define MSK_CORE_POWER_ON BIT(1)
#define WRAPPER_INTR_STATUS (WRAPPER_BASE_OFFS + 0x0C)
-#define WRAPPER_INTR_STATUS_A2HWD_BMSK BIT(3)
#define WRAPPER_INTR_STATUS_A2H_BMSK BIT(2)
#define WRAPPER_INTR_MASK (WRAPPER_BASE_OFFS + 0x10)
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 09/18] media: iris: Add platform flag for instantaneous bandwidth voting
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (7 preceding siblings ...)
2026-07-09 13:41 ` [PATCH v7 08/18] media: iris: Add platform data field for watchdog interrupt mask Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 13:59 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 10/18] media: iris: skip PIPE if it is not supported by the platform Dmitry Baryshkov
` (8 subsequent siblings)
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
AR50LT require explicit instantaneous bandwidth (IB) voting in addition
to average bandwidth (AB) when configuring interconnect QoS. This
requirement is due to QSB (Qualcomm System Bus) 128b to
QNS ( Qualcomm Network Switch) 256b conversion at video noc in AR50LT
which is not needed for other IRIS cores.
In preparation of adding support for AR50LT core, introduce
platform-configurable IB multiplier and enable IB voting for all SoCs.
Existing platforms default to IB == AB, while AR50LT requires 2x peak
bandwidth.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_platform_common.h | 1 +
drivers/media/platform/qcom/iris/iris_platform_vpu2.c | 2 ++
drivers/media/platform/qcom/iris/iris_platform_vpu3x.c | 5 +++++
drivers/media/platform/qcom/iris/iris_resources.c | 2 ++
4 files changed, 10 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index 81fcb2854772..accc1627defd 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -316,6 +316,7 @@ struct iris_platform_data {
u32 num_vpp_pipe;
bool no_aon;
u32 wd_intr_mask;
+ u32 icc_ib_multiplier;
u32 max_session_count;
/* max number of macroblocks per frame supported */
u32 max_core_mbpf;
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
index 940daddbafcf..e194f67a6f48 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
@@ -97,6 +97,7 @@ const struct iris_platform_data sc7280_data = {
.num_vpp_pipe = 1,
.no_aon = true,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = 4096 * 2176 / 256 * 2 + 1920 * 1088 / 256,
/* max spec for SC7280 is 4096x2176@60fps */
@@ -128,6 +129,7 @@ const struct iris_platform_data sm8250_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu2),
.num_vpp_pipe = 4,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
index eeedde8fc9ce..b8099d7ce556 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
@@ -116,6 +116,7 @@ const struct iris_platform_data qcs8300_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 2,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = ((4096 * 2176) / 256) * 4,
.max_core_mbps = (((3840 * 2176) / 256) * 120),
@@ -146,6 +147,7 @@ const struct iris_platform_data sm8550_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 4,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
@@ -184,6 +186,7 @@ const struct iris_platform_data sm8650_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 4,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
@@ -214,6 +217,7 @@ const struct iris_platform_data sm8750_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 4,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
@@ -250,6 +254,7 @@ const struct iris_platform_data x1p42100_data = {
.tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
.num_vpp_pipe = 1,
.wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 1,
.max_session_count = 16,
.max_core_mbpf = NUM_MBS_8K * 2,
.max_core_mbps = ((7680 * 4320) / 256) * 60,
diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c
index 773f6548370a..caeaf199cef7 100644
--- a/drivers/media/platform/qcom/iris/iris_resources.c
+++ b/drivers/media/platform/qcom/iris/iris_resources.c
@@ -18,6 +18,7 @@
int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw)
{
+ u32 icc_ib_multiplier = core->iris_platform_data->icc_ib_multiplier;
unsigned long bw_kbps = 0, bw_prev = 0;
const struct icc_info *icc_tbl;
int ret = 0, i;
@@ -36,6 +37,7 @@ int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw)
return ret;
core->icc_tbl[i].avg_bw = bw_kbps;
+ core->icc_tbl[i].peak_bw = bw_kbps * icc_ib_multiplier;
core->power.icc_bw = bw_kbps;
break;
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 09/18] media: iris: Add platform flag for instantaneous bandwidth voting
2026-07-09 13:42 ` [PATCH v7 09/18] media: iris: Add platform flag for instantaneous bandwidth voting Dmitry Baryshkov
@ 2026-07-09 13:59 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 13:59 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] This problem wasn't introduced by this patch, but the `iris_core` structure is allocated with `devm_kzalloc`, leading to a Use-After-Free during device unbind because the video device and delayed work outlive the device-managed allocation.
--
--- Patch [9]: [PATCH v7 09/18] media: iris: Add platform flag for instantaneous bandwidth voting ---
commit 5567f5c1da418821cf2cb0c55e4585a7cba76a62
Author: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
media: iris: Add platform flag for instantaneous bandwidth voting
This commit introduces a platform-configurable instantaneous bandwidth (IB)
multiplier and enables IB voting for all SoCs. It prepares for AR50LT core
support, which requires explicit IB voting in addition to average bandwidth
(AB) for interconnect QoS. Existing platforms will default to an equal IB
and AB, whereas AR50LT will require 2x peak bandwidth.
> diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c
> index 773f6548370a2..caeaf199cef74 100644
> --- a/drivers/media/platform/qcom/iris/iris_resources.c
> +++ b/drivers/media/platform/qcom/iris/iris_resources.c
> @@ -18,6 +18,7 @@
>
> int iris_set_icc_bw(struct iris_core *core, unsigned long icc_bw)
> {
> + u32 icc_ib_multiplier = core->iris_platform_data->icc_ib_multiplier;
> unsigned long bw_kbps = 0, bw_prev = 0;
> const struct icc_info *icc_tbl;
> int ret = 0, i;
[Severity: Critical]
This is a pre-existing issue, but the iris_core structure is allocated with
devm_kzalloc, which can lead to a use-after-free regression during device
unbind. The video device and delayed work appear to outlive the
device-managed allocation.
In drivers/media/platform/qcom/iris/iris_probe.c:iris_probe():
core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
The unbind path fails to explicitly cancel the delayed work and exits,
triggering devm to free the core structure while V4L2 file descriptors may
still be open:
drivers/media/platform/qcom/iris/iris_probe.c:iris_remove() {
struct iris_core *core;
core = platform_get_drvdata(pdev);
if (!core)
return;
iris_core_deinit(core);
video_unregister_device(core->vdev_dec);
video_unregister_device(core->vdev_enc);
v4l2_device_unregister(&core->v4l2_dev);
mutex_destroy(&core->lock);
}
When a lingering file descriptor is eventually closed, iris_close() invokes
iris_remove_session(), which dereferences the freed core structure and its
destroyed lock:
drivers/media/platform/qcom/iris/iris_vidc.c:iris_remove_session() {
struct iris_core *core = inst->core;
mutex_lock(&core->lock);
...
}
Can this corrupt memory if the driver is unbound while the video node is in
use, or while the error handling delayed work is active?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=9
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 10/18] media: iris: skip PIPE if it is not supported by the platform
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (8 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 09/18] media: iris: Add platform flag for instantaneous bandwidth voting Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 14:14 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core Dmitry Baryshkov
` (7 subsequent siblings)
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
AR50Lt doesn't support HFI_PROPERTY_PARAM_WORK_ROUTE. Tables for AR50LT
won't have corresponding entry in the capability tables. Let
iris_set_pipe() silently skip propgramming the property if there is no
corresponding capability.
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_ctrls.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c
index 10e33b8a73f6..33a34573391a 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.c
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.c
@@ -534,6 +534,9 @@ int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
u32 work_route = inst->fw_caps[PIPE].value;
u32 hfi_id = inst->fw_caps[cap_id].hfi_id;
+ if (!hfi_id)
+ return 0;
+
return hfi_ops->session_set_property(inst, hfi_id,
HFI_HOST_FLAGS_NONE,
iris_get_port_info(inst, cap_id),
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 10/18] media: iris: skip PIPE if it is not supported by the platform
2026-07-09 13:42 ` [PATCH v7 10/18] media: iris: skip PIPE if it is not supported by the platform Dmitry Baryshkov
@ 2026-07-09 14:14 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 14:14 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Missing `PIPE` capability results in a latent division by zero in `iris_vpu3x_vpu4x_calculate_frequency()`.
--
--- Patch [10]: [PATCH v7 10/18] media: iris: skip PIPE if it is not supported by the platform ---
commit 3fc5cca6cb7d8fdca8a5f48a5b724d09591a0347
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
media: iris: skip PIPE if it is not supported by the platform
This commit skips programming the HFI_PROPERTY_PARAM_WORK_ROUTE property
in iris_set_pipe() if the platform lacks the corresponding capability.
This prevents failures on platforms like AR50LT that do not support it.
> diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c
> index 10e33b8a73f60..33a34573391a4 100644
> --- a/drivers/media/platform/qcom/iris/iris_ctrls.c
> +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c
> @@ -534,6 +534,9 @@ int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
> u32 work_route = inst->fw_caps[PIPE].value;
> u32 hfi_id = inst->fw_caps[cap_id].hfi_id;
>
> + if (!hfi_id)
> + return 0;
> +
[Severity: Critical]
This is a pre-existing issue, but does skipping the PIPE capability here mean
inst->fw_caps[PIPE].value remains 0?
If so, could this cause a division by zero later in the VPU clock calculation?
Looking at iris_vpu3x_vpu4x_calculate_frequency() in iris_vpu_common.c:
drivers/media/platform/qcom/iris/iris_vpu_common.c:iris_vpu3x_vpu4x_calculate_frequency() {
...
vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value);
...
}
Because mult_frac() divides by its third argument without a zero check,
this could result in a fatal division by zero when a userspace application
opens the encoder on a VPU3x/VPU4x platform omitting the PIPE capability.
> return hfi_ops->session_set_property(inst, hfi_id,
> HFI_HOST_FLAGS_NONE,
> iris_get_port_info(inst, cap_id),
> HFI_PAYLOAD_U32,
> &work_route, sizeof(u32));
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=10
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (9 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 10/18] media: iris: skip PIPE if it is not supported by the platform Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 13:59 ` sashiko-bot
2026-07-10 10:25 ` Vikash Garodia
2026-07-09 13:42 ` [PATCH v7 12/18] media: iris: add minimal GET_PROPERTY implementation Dmitry Baryshkov
` (6 subsequent siblings)
17 siblings, 2 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Add power sequence for ar5lt core.
Add register handling for ar50lt by hooking up vpu op with ar50lt
specific implemtation or resue from earlier generation wherever
feasible.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/Makefile | 1 +
.../platform/qcom/iris/iris_platform_common.h | 2 +
drivers/media/platform/qcom/iris/iris_vpu2.c | 28 +----
drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c | 130 +++++++++++++++++++++
drivers/media/platform/qcom/iris/iris_vpu_common.c | 29 ++++-
drivers/media/platform/qcom/iris/iris_vpu_common.h | 2 +
6 files changed, 164 insertions(+), 28 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile
index 48e415cbc439..f1b204b95694 100644
--- a/drivers/media/platform/qcom/iris/Makefile
+++ b/drivers/media/platform/qcom/iris/Makefile
@@ -26,6 +26,7 @@ qcom-iris-objs += iris_buffer.o \
iris_vpu2.o \
iris_vpu3x.o \
iris_vpu4x.o \
+ iris_vpu_ar50lt.o \
iris_vpu_buffer.o \
iris_vpu_common.o \
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index accc1627defd..6a189489369f 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -74,6 +74,7 @@ enum platform_clk_type {
IRIS_VPP0_HW_CLK,
IRIS_VPP1_HW_CLK,
IRIS_APV_HW_CLK,
+ IRIS_THROTTLE_CLK,
};
struct platform_clk_data {
@@ -315,6 +316,7 @@ struct iris_platform_data {
u32 tz_cp_config_data_size;
u32 num_vpp_pipe;
bool no_aon;
+ bool no_rpmh;
u32 wd_intr_mask;
u32 icc_ib_multiplier;
u32 max_session_count;
diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c
index dd2eeae0d9eb..5419a5096b00 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu2.c
@@ -12,38 +12,12 @@
#include "iris_vpu_register_defines.h"
-static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size)
-{
- struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps;
- struct v4l2_format *inp_f = inst->fmt_src;
- u32 mbs_per_second, mbpf, height, width;
- unsigned long vpp_freq, vsp_freq;
- u32 fps = inst->frame_rate;
-
- width = max(inp_f->fmt.pix_mp.width, inst->crop.width);
- height = max(inp_f->fmt.pix_mp.height, inst->crop.height);
-
- mbpf = NUM_MBS_PER_FRAME(height, width);
- mbs_per_second = mbpf * fps;
-
- vpp_freq = mbs_per_second * caps->mb_cycles_vpp;
-
- /* 21 / 20 is overhead factor */
- vpp_freq += vpp_freq / 20;
- vsp_freq = mbs_per_second * caps->mb_cycles_vsp;
-
- /* 10 / 7 is overhead factor */
- vsp_freq += ((fps * data_size * 8) * 10) / 7;
-
- return max(vpp_freq, vsp_freq);
-}
-
const struct vpu_ops iris_vpu2_ops = {
.power_off_hw = iris_vpu_power_off_hw,
.power_on_hw = iris_vpu_power_on_hw,
.power_off_controller = iris_vpu_power_off_controller,
.power_on_controller = iris_vpu_power_on_controller,
- .calc_freq = iris_vpu2_calc_freq,
+ .calc_freq = iris_vpu2_calculate_frequency,
.set_hwmode = iris_vpu_set_hwmode,
.set_preset_registers = iris_vpu_set_preset_registers,
.interrupt_init = iris_vpu_interrupt_init,
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c b/drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c
new file mode 100644
index 000000000000..e084a5b49f2e
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/bits.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include "iris_instance.h"
+#include "iris_vpu_common.h"
+
+#include "iris_vpu_register_defines.h"
+
+#define WRAPPER_INTR_MASK_A2HVCODEC_BMSK_AR50LT BIT(3)
+
+#define WRAPPER_VCODEC0_CLOCK_CONFIG_AR50LT 0xb0080
+
+#define CPU_CS_VCICMD 0xa0020
+#define CPU_CS_VCICMD_ARP_OFF 0x1
+
+static void iris_vpu_ar50lt_set_preset_registers(struct iris_core *core)
+{
+ writel(0x0, core->reg_base + WRAPPER_VCODEC0_CLOCK_CONFIG_AR50LT);
+}
+
+static void iris_vpu_ar50lt_interrupt_init(struct iris_core *core)
+{
+ writel(WRAPPER_INTR_MASK_A2HVCODEC_BMSK_AR50LT, core->reg_base + WRAPPER_INTR_MASK);
+}
+
+static void iris_vpu_ar50lt_disable_arp(struct iris_core *core)
+{
+ writel(CPU_CS_VCICMD_ARP_OFF, core->reg_base + CPU_CS_VCICMD);
+}
+
+static int iris_vpu_ar50lt_power_off_controller(struct iris_core *core)
+{
+ iris_disable_unprepare_clock(core, IRIS_AHB_CLK);
+ iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
+ iris_disable_unprepare_clock(core, IRIS_CTRL_CLK);
+ iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]);
+
+ return 0;
+}
+
+static void iris_vpu_ar50lt_power_off_hw(struct iris_core *core)
+{
+ dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], false);
+ iris_disable_unprepare_clock(core, IRIS_THROTTLE_CLK);
+ iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK);
+ iris_disable_unprepare_clock(core, IRIS_HW_CLK);
+ iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
+}
+
+static int iris_vpu_ar50lt_power_on_controller(struct iris_core *core)
+{
+ int ret;
+
+ ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]);
+ if (ret)
+ return ret;
+
+ ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK);
+ if (ret)
+ goto err_disable_power;
+
+ ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK);
+ if (ret && ret != -ENOENT)
+ goto err_disable_ctrl_clock;
+
+ ret = iris_prepare_enable_clock(core, IRIS_AHB_CLK);
+ if (ret)
+ goto err_disable_axi_clock;
+
+ return 0;
+
+err_disable_axi_clock:
+ iris_disable_unprepare_clock(core, IRIS_AXI_CLK);
+err_disable_ctrl_clock:
+ iris_disable_unprepare_clock(core, IRIS_CTRL_CLK);
+err_disable_power:
+ iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]);
+
+ return ret;
+}
+
+static int iris_vpu_ar50lt_power_on_hw(struct iris_core *core)
+{
+ int ret;
+
+ ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
+ if (ret)
+ return ret;
+
+ ret = iris_prepare_enable_clock(core, IRIS_HW_CLK);
+ if (ret)
+ goto err_disable_power;
+
+ ret = iris_prepare_enable_clock(core, IRIS_HW_AHB_CLK);
+ if (ret)
+ goto err_disable_hw_clock;
+
+ ret = iris_prepare_enable_clock(core, IRIS_THROTTLE_CLK);
+ if (ret)
+ goto err_disable_hw_ahb_clock;
+
+ return 0;
+
+err_disable_hw_ahb_clock:
+ iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK);
+err_disable_hw_clock:
+ iris_disable_unprepare_clock(core, IRIS_HW_CLK);
+err_disable_power:
+ iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
+
+ return ret;
+}
+
+const struct vpu_ops iris_vpu_ar50lt_ops = {
+ .power_off_hw = iris_vpu_ar50lt_power_off_hw,
+ .power_on_hw = iris_vpu_ar50lt_power_on_hw,
+ .power_off_controller = iris_vpu_ar50lt_power_off_controller,
+ .power_on_controller = iris_vpu_ar50lt_power_on_controller,
+ .calc_freq = iris_vpu2_calculate_frequency,
+ .set_hwmode = iris_vpu_set_hwmode,
+ .set_preset_registers = iris_vpu_ar50lt_set_preset_registers,
+ .interrupt_init = iris_vpu_ar50lt_interrupt_init,
+ .disable_arp = iris_vpu_ar50lt_disable_arp,
+};
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c
index 41498f94480e..d64e7745a63d 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c
@@ -97,7 +97,8 @@ int iris_vpu_boot_firmware(struct iris_core *core)
}
writel(HOST2XTENSA_INTR_ENABLE, core->reg_base + CPU_CS_H2XSOFTINTEN);
- writel(0x0, core->reg_base + CPU_CS_X2RPMH);
+ if (!core->iris_platform_data->no_rpmh)
+ writel(0x0, core->reg_base + CPU_CS_X2RPMH);
return 0;
}
@@ -422,6 +423,32 @@ void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core)
writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0);
}
+u64 iris_vpu2_calculate_frequency(struct iris_inst *inst, size_t data_size)
+{
+ struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps;
+ struct v4l2_format *inp_f = inst->fmt_src;
+ u32 mbs_per_second, mbpf, height, width;
+ unsigned long vpp_freq, vsp_freq;
+ u32 fps = inst->frame_rate;
+
+ width = max(inp_f->fmt.pix_mp.width, inst->crop.width);
+ height = max(inp_f->fmt.pix_mp.height, inst->crop.height);
+
+ mbpf = NUM_MBS_PER_FRAME(height, width);
+ mbs_per_second = mbpf * fps;
+
+ vpp_freq = mbs_per_second * caps->mb_cycles_vpp;
+
+ /* 21 / 20 is overhead factor */
+ vpp_freq += vpp_freq / 20;
+ vsp_freq = mbs_per_second * caps->mb_cycles_vsp;
+
+ /* 10 / 7 is overhead factor */
+ vsp_freq += ((fps * data_size * 8) * 10) / 7;
+
+ return max(vpp_freq, vsp_freq);
+}
+
u64 iris_vpu3x_vpu4x_calculate_frequency(struct iris_inst *inst, size_t data_size)
{
struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps;
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h
index 71d96921ed37..a62b6184bde7 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_common.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h
@@ -13,6 +13,7 @@ extern const struct vpu_ops iris_vpu3_ops;
extern const struct vpu_ops iris_vpu33_ops;
extern const struct vpu_ops iris_vpu35_ops;
extern const struct vpu_ops iris_vpu4x_ops;
+extern const struct vpu_ops iris_vpu_ar50lt_ops;
struct vpu_ops {
void (*power_off_hw)(struct iris_core *core);
@@ -40,6 +41,7 @@ int iris_vpu_power_on(struct iris_core *core);
int iris_vpu_power_off_controller(struct iris_core *core);
void iris_vpu_power_off_hw(struct iris_core *core);
void iris_vpu_power_off(struct iris_core *core);
+u64 iris_vpu2_calculate_frequency(struct iris_inst *inst, size_t data_size);
int iris_vpu35_vpu4x_power_off_controller(struct iris_core *core);
int iris_vpu35_vpu4x_power_on_controller(struct iris_core *core);
void iris_vpu35_vpu4x_program_bootup_registers(struct iris_core *core);
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core
2026-07-09 13:42 ` [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core Dmitry Baryshkov
@ 2026-07-09 13:59 ` sashiko-bot
2026-07-10 10:25 ` Vikash Garodia
1 sibling, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 13:59 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] The `iris_vpu_boot_firmware` function incorrectly returns success (0) when a firmware boot error is detected.
- [High] Hardware clocks are unprepared after disabling the power domain, causing a teardown ordering violation in `iris_vpu_power_off_hw`.
--
--- Patch [11]: [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core ---
commit 4e8fec9384d1018aa16fad1dc0afb88de83d8e99
Author: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
media: iris: Add framework support for AR50_LITE video core
Add power sequence for ar5lt core.
Add register handling for ar50lt by hooking up vpu op with ar50lt
specific implemtation or resue from earlier generation wherever
feasible.
> diff --git a/drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c b/drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c
> new file mode 100644
> index 0000000000000..e084a5b49f2e3
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c
[ ... ]
> +static void iris_vpu_ar50lt_power_off_hw(struct iris_core *core)
> +{
> + dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], false);
> + iris_disable_unprepare_clock(core, IRIS_THROTTLE_CLK);
> + iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK);
> + iris_disable_unprepare_clock(core, IRIS_HW_CLK);
> + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
> +}
[Severity: High]
This is a pre-existing issue on the older platforms, but I noticed you are
correctly disabling the clocks before the power domains here for the new AR50LT
platform.
However, in the shared common function iris_vpu_power_off_hw() for the older
platforms, the power domain is disabled before the clocks:
drivers/media/platform/qcom/iris/iris_vpu_common.c:iris_vpu_power_off_hw() {
iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]);
iris_disable_unprepare_clock(core, IRIS_BSE_HW_CLK);
iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK);
...
}
Does this teardown ordering violation in the older platforms cause system bus
hangs or unclocked access faults when the clock controller attempts to interact
with the unpowered block?
[ ... ]
> diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c
> index 41498f94480e8..d64e7745a63dc 100644
> --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c
> +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c
> @@ -97,7 +97,8 @@ int iris_vpu_boot_firmware(struct iris_core *core)
> }
>
> writel(HOST2XTENSA_INTR_ENABLE, core->reg_base + CPU_CS_H2XSOFTINTEN);
> - writel(0x0, core->reg_base + CPU_CS_X2RPMH);
> + if (!core->iris_platform_data->no_rpmh)
> + writel(0x0, core->reg_base + CPU_CS_X2RPMH);
>
> return 0;
> }
[Severity: High]
This isn't a bug introduced by this patch, but while modifying this function, I
noticed a potential issue in the firmware boot wait loop just above this code:
while (!ctrl_status && count < max_tries) {
ctrl_status = readl(core->reg_base + CTRL_STATUS);
if ((ctrl_status & CTRL_ERROR_STATUS__M) == 0x4) {
dev_err(core->dev, "invalid setting for uc_region\n");
break;
}
...
}
If the hardware reports an invalid uc_region, the loop breaks immediately.
Because the variable count will be less than max_tries, the subsequent timeout
check evaluates to false, and the function mistakenly falls through to return
success (0) here.
Can this bypass of the error return cause the driver to incorrectly assume the
firmware booted successfully and proceed to enable host interrupts, potentially
leading to unhandled timeouts, hardware hangs, or system crashes?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=11
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core
2026-07-09 13:42 ` [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core Dmitry Baryshkov
2026-07-09 13:59 ` sashiko-bot
@ 2026-07-10 10:25 ` Vikash Garodia
1 sibling, 0 replies; 30+ messages in thread
From: Vikash Garodia @ 2026-07-10 10:25 UTC (permalink / raw)
To: Dmitry Baryshkov, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
On 7/9/2026 7:12 PM, Dmitry Baryshkov wrote:
> From: Dikshita Agarwal<dikshita.agarwal@oss.qualcomm.com>
>
> Add power sequence for ar5lt core.
> Add register handling for ar50lt by hooking up vpu op with ar50lt
> specific implemtation or resue from earlier generation wherever
> feasible.
>
> Signed-off-by: Dikshita Agarwal<dikshita.agarwal@oss.qualcomm.com>
> Signed-off-by: Dmitry Baryshkov<dmitry.baryshkov@oss.qualcomm.com>
> ---
> drivers/media/platform/qcom/iris/Makefile | 1 +
> .../platform/qcom/iris/iris_platform_common.h | 2 +
> drivers/media/platform/qcom/iris/iris_vpu2.c | 28 +----
> drivers/media/platform/qcom/iris/iris_vpu_ar50lt.c | 130 +++++++++++++++++++++
> drivers/media/platform/qcom/iris/iris_vpu_common.c | 29 ++++-
> drivers/media/platform/qcom/iris/iris_vpu_common.h | 2 +
> 6 files changed, 164 insertions(+), 28 deletions(-)
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 12/18] media: iris: add minimal GET_PROPERTY implementation
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (10 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 11/18] media: iris: Add framework support for AR50_LITE video core Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 14:06 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 13/18] media: iris: update buffer requirements based on received info Dmitry Baryshkov
` (5 subsequent siblings)
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
AR50Lt with the Gen1 firmware requires host to read
HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS property, otherwise it doesn't
update internal data and fails the HFI_CMD_SESSION_LOAD_RESOURCES
command. Implement minimal support for querying the properties from the
firmware. It is used by one of the following patches, adding support for
Agatti.
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Reviewed-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_hfi_common.h | 1 +
.../platform/qcom/iris/iris_hfi_gen1_command.c | 21 +++++++++++++++++++++
.../platform/qcom/iris/iris_hfi_gen1_defines.h | 15 +++++++++++++++
.../platform/qcom/iris/iris_hfi_gen1_response.c | 6 ++++++
4 files changed, 43 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h
index a27447eb2519..16099f9a25b6 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_common.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h
@@ -121,6 +121,7 @@ struct iris_hfi_session_ops {
int (*session_set_property)(struct iris_inst *inst,
u32 packet_type, u32 flag, u32 plane, u32 payload_type,
void *payload, u32 payload_size);
+ int (*session_get_property)(struct iris_inst *inst, u32 packet_type);
int (*session_open)(struct iris_inst *inst);
int (*session_start)(struct iris_inst *inst, u32 plane);
int (*session_queue_buf)(struct iris_inst *inst, struct iris_buffer *buffer);
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
index 7674b47ad6c4..99e82e5510ab 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
@@ -1117,10 +1117,31 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p
return 0;
}
+static int iris_hfi_gen1_session_get_property(struct iris_inst *inst, u32 packet_type)
+{
+ struct hfi_session_get_property_pkt pkt;
+ int ret;
+
+ pkt.shdr.hdr.size = sizeof(pkt);
+ pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_GET_PROPERTY;
+ pkt.shdr.session_id = inst->session_id;
+ pkt.num_properties = 1;
+ pkt.data = packet_type;
+
+ reinit_completion(&inst->completion);
+
+ ret = iris_hfi_queue_cmd_write(inst->core, &pkt, pkt.shdr.hdr.size);
+ if (ret)
+ return ret;
+
+ return iris_wait_for_session_response(inst, false);
+}
+
static const struct iris_hfi_session_ops iris_hfi_gen1_session_ops = {
.session_open = iris_hfi_gen1_session_open,
.session_set_config_params = iris_hfi_gen1_session_set_config_params,
.session_set_property = iris_hfi_gen1_session_set_property,
+ .session_get_property = iris_hfi_gen1_session_get_property,
.session_start = iris_hfi_gen1_session_start,
.session_queue_buf = iris_hfi_gen1_session_queue_buffer,
.session_release_buf = iris_hfi_gen1_session_unset_buffers,
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
index 0e4dee192384..bb495a1d2623 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h
@@ -35,6 +35,7 @@
#define HFI_CMD_SESSION_EMPTY_BUFFER 0x211004
#define HFI_CMD_SESSION_FILL_BUFFER 0x211005
#define HFI_CMD_SESSION_FLUSH 0x211008
+#define HFI_CMD_SESSION_GET_PROPERTY 0x211009
#define HFI_CMD_SESSION_RELEASE_BUFFERS 0x21100b
#define HFI_CMD_SESSION_RELEASE_RESOURCES 0x21100c
#define HFI_CMD_SESSION_CONTINUE 0x21100d
@@ -113,6 +114,7 @@
#define HFI_MSG_SESSION_FLUSH 0x221006
#define HFI_MSG_SESSION_EMPTY_BUFFER 0x221007
#define HFI_MSG_SESSION_FILL_BUFFER 0x221008
+#define HFI_MSG_SESSION_PROPERTY_INFO 0x221009
#define HFI_MSG_SESSION_RELEASE_RESOURCES 0x22100a
#define HFI_MSG_SESSION_RELEASE_BUFFERS 0x22100c
@@ -205,6 +207,12 @@ struct hfi_session_set_property_pkt {
u32 data[];
};
+struct hfi_session_get_property_pkt {
+ struct hfi_session_hdr_pkt shdr;
+ u32 num_properties;
+ u32 data;
+};
+
struct hfi_sys_pc_prep_pkt {
struct hfi_pkt_hdr hdr;
};
@@ -574,6 +582,13 @@ struct hfi_msg_session_fbd_uncompressed_plane0_pkt {
u32 data[];
};
+struct hfi_msg_session_property_info_pkt {
+ struct hfi_session_hdr_pkt shdr;
+ u32 num_properties;
+ u32 property;
+ u8 data[];
+};
+
struct hfi_msg_session_release_buffers_done_pkt {
struct hfi_msg_session_hdr_pkt shdr;
u32 num_buffers;
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
index bfd7495bf44f..23fc7194b1e3 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
@@ -591,6 +591,10 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = {
.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
.pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
},
+ {
+ .pkt = HFI_MSG_SESSION_PROPERTY_INFO,
+ .pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt),
+ },
};
static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response)
@@ -652,6 +656,8 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response
iris_hfi_gen1_session_etb_done(inst, hdr);
} else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) {
iris_hfi_gen1_session_ftb_done(inst, hdr);
+ } else if (hdr->pkt_type == HFI_MSG_SESSION_PROPERTY_INFO) {
+ complete(&inst->completion);
} else {
struct hfi_msg_session_hdr_pkt *shdr;
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 12/18] media: iris: add minimal GET_PROPERTY implementation
2026-07-09 13:42 ` [PATCH v7 12/18] media: iris: add minimal GET_PROPERTY implementation Dmitry Baryshkov
@ 2026-07-09 14:06 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 14:06 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-After-Free (UAF) occurs in the HFI response handler when an instance is concurrently closed.
- [High] Concurrent V4L2 ioctls can race and corrupt `inst->completion` due to dropping `inst->lock` while waiting for firmware responses.
--
--- Patch [12]: [PATCH v7 12/18] media: iris: add minimal GET_PROPERTY implementation ---
commit a6032a96e9889c0a8753d5947e2b2a2b8f59d3be
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
media: iris: add minimal GET_PROPERTY implementation
AR50Lt with the Gen1 firmware requires host to read
HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS property, otherwise it doesn't
update internal data and fails the HFI_CMD_SESSION_LOAD_RESOURCES
command. Implement minimal support for querying the properties from the
firmware. It is used by one of the following patches, adding support for
Agatti.
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> index 7674b47ad6c49..99e82e5510abe 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> @@ -1117,10 +1117,31 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p
> return 0;
> }
>
> +static int iris_hfi_gen1_session_get_property(struct iris_inst *inst, u32 packet_type)
> +{
> + struct hfi_session_get_property_pkt pkt;
> + int ret;
> +
> + pkt.shdr.hdr.size = sizeof(pkt);
> + pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_GET_PROPERTY;
> + pkt.shdr.session_id = inst->session_id;
> + pkt.num_properties = 1;
> + pkt.data = packet_type;
> +
> + reinit_completion(&inst->completion);
> +
> + ret = iris_hfi_queue_cmd_write(inst->core, &pkt, pkt.shdr.hdr.size);
> + if (ret)
> + return ret;
> +
> + return iris_wait_for_session_response(inst, false);
[Severity: High]
This is a pre-existing issue, but can concurrent ioctls on the same file
descriptor corrupt inst->completion here?
The driver implements manual ioctl serialization by acquiring inst->lock.
However, iris_wait_for_session_response() drops inst->lock while waiting:
drivers/media/platform/qcom/iris/iris_utils.c:iris_wait_for_session_response() {
...
mutex_unlock(&inst->lock);
ret = wait_for_completion_timeout(done, msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE));
mutex_lock(&inst->lock);
...
}
Doesn't dropping the lock allow a concurrent ioctl to acquire inst->lock, issue
a new command, and call reinit_completion(&inst->completion) again, thereby
wiping out the completion state for the first thread?
> +}
> +
[ ... ]
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> index bfd7495bf44f0..23fc7194b1e3a 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
[ ... ]
> @@ -652,6 +656,8 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response
> iris_hfi_gen1_session_etb_done(inst, hdr);
> } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) {
> iris_hfi_gen1_session_ftb_done(inst, hdr);
> + } else if (hdr->pkt_type == HFI_MSG_SESSION_PROPERTY_INFO) {
> + complete(&inst->completion);
[Severity: High]
This isn't a bug introduced by this patch, but is there a use-after-free risk
when accessing inst here if the instance is concurrently closed?
The threaded IRQ handler iris_hfi_gen1_handle_response() retrieves the instance
via iris_get_instance(), which finds inst but drops core->lock without taking
a reference count:
drivers/media/platform/qcom/iris/iris_utils.c:iris_get_instance() {
...
mutex_unlock(&core->lock);
return inst;
...
}
If a user-space process closes the file descriptor concurrently, iris_close()
acquires inst->lock, calls iris_remove_session(), drops the lock, and frees inst:
drivers/media/platform/qcom/iris/iris_vidc.c:iris_close() {
...
iris_remove_session(inst);
mutex_unlock(&inst->lock);
mutex_destroy(&inst->ctx_q_lock);
mutex_destroy(&inst->lock);
kfree(inst->fmt_src);
kfree(inst->fmt_dst);
kfree(inst);
}
When the IRQ handler iris_hfi_gen1_handle_response() resumes and attempts to
acquire inst->lock or call complete(&inst->completion), could it dereference
the freed inst pointer?
> } else {
> struct hfi_msg_session_hdr_pkt *shdr;
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=12
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 13/18] media: iris: update buffer requirements based on received info
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (11 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 12/18] media: iris: add minimal GET_PROPERTY implementation Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 14:05 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 14/18] media: iris: implement support for the Agatti platform Dmitry Baryshkov
` (4 subsequent siblings)
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
Upon receiving data for HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS the
driver should update buffer sizes and counts from the received data.
Implement corresponding functionality updating buffers data. This will
be used for upcoming support of AR50Lt platforms with Gen1 firmware.
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
.../platform/qcom/iris/iris_hfi_gen1_response.c | 76 +++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
index 23fc7194b1e3..7ad6f0bb4677 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
@@ -533,6 +533,80 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet)
dev_err(core->dev, "error in ftb done\n");
}
+static enum iris_buffer_type iris_hfi_gen1_buf_type(struct iris_inst *inst, u32 type)
+{
+ switch (type) {
+ case HFI_BUFFER_INPUT:
+ return BUF_INPUT;
+ case HFI_BUFFER_OUTPUT:
+ if (iris_split_mode_enabled(inst))
+ return BUF_DPB;
+ return BUF_OUTPUT;
+ case HFI_BUFFER_OUTPUT2:
+ if (iris_split_mode_enabled(inst))
+ return BUF_OUTPUT;
+ return BUF_DPB;
+ case HFI_BUFFER_INTERNAL_PERSIST_1:
+ return BUF_PERSIST;
+ case HFI_BUFFER_INTERNAL_SCRATCH:
+ return BUF_BIN;
+ case HFI_BUFFER_INTERNAL_SCRATCH_1:
+ return BUF_SCRATCH_1;
+ case HFI_BUFFER_INTERNAL_SCRATCH_2:
+ return BUF_SCRATCH_2;
+ case HFI_BUFFER_INTERNAL_PERSIST:
+ return BUF_ARP;
+ default:
+ return BUF_TYPE_MAX;
+ }
+}
+
+static void iris_hfi_gen1_session_buffer_requirements(struct iris_inst *inst,
+ void *data, size_t size)
+{
+ struct hfi_buffer_requirements *req;
+
+ if (!size || size % sizeof(*req))
+ return;
+
+ for (req = data; size; size -= sizeof(*req), req++) {
+ enum iris_buffer_type type = iris_hfi_gen1_buf_type(inst, req->type);
+
+ if (type == BUF_TYPE_MAX)
+ continue;
+
+ /* on relevant platforms hold_count and min_count are swapped */
+ inst->buffers[type].min_count = req->hold_count;
+ inst->buffers[type].size = req->size;
+
+ if (type == BUF_OUTPUT)
+ inst->fw_min_count = req->count_actual;
+ }
+}
+
+static void iris_hfi_gen1_session_property_info(struct iris_inst *inst, void *packet)
+{
+ struct hfi_msg_session_property_info_pkt *pkt = packet;
+
+ if (pkt->num_properties != 1) {
+ dev_warn_ratelimited(inst->core->dev, "%s: expected 1 property, got %u\n",
+ __func__, pkt->num_properties);
+ goto out;
+ }
+
+ switch (pkt->property) {
+ case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+ iris_hfi_gen1_session_buffer_requirements(inst, pkt->data,
+ pkt->shdr.hdr.size - sizeof(*pkt));
+ break;
+ default:
+ dev_warn(inst->core->dev, "unknown property id: %x\n", pkt->property);
+ }
+
+out:
+ complete(&inst->completion);
+}
+
struct iris_hfi_gen1_response_pkt_info {
u32 pkt;
u32 pkt_sz;
@@ -657,7 +731,7 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response
} else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) {
iris_hfi_gen1_session_ftb_done(inst, hdr);
} else if (hdr->pkt_type == HFI_MSG_SESSION_PROPERTY_INFO) {
- complete(&inst->completion);
+ iris_hfi_gen1_session_property_info(inst, hdr);
} else {
struct hfi_msg_session_hdr_pkt *shdr;
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 13/18] media: iris: update buffer requirements based on received info
2026-07-09 13:42 ` [PATCH v7 13/18] media: iris: update buffer requirements based on received info Dmitry Baryshkov
@ 2026-07-09 14:05 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 14:05 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing reference counting on `iris_inst` objects allows an interrupt handler to use a freed instance.
--
--- Patch [13]: [PATCH v7 13/18] media: iris: update buffer requirements based on received info ---
commit fb9888a16075cc5bb0904df74da5c901575cc14f
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
media: iris: update buffer requirements based on received info
Upon receiving data for HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS the
driver should update buffer sizes and counts from the received data.
Implement corresponding functionality updating buffers data.
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> index 23fc7194b1e3a..7ad6f0bb46770 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c
[ ... ]
> @@ -657,7 +731,7 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response
> } else if (hdr->pkt_type == HFI_MSG_SESSION_FILL_BUFFER) {
> iris_hfi_gen1_session_ftb_done(inst, hdr);
> } else if (hdr->pkt_type == HFI_MSG_SESSION_PROPERTY_INFO) {
> - complete(&inst->completion);
> + iris_hfi_gen1_session_property_info(inst, hdr);
> } else {
> struct hfi_msg_session_hdr_pkt *shdr;
[Severity: High]
This is a pre-existing issue, but since we are modifying the message
handling flow here, there appears to be a use-after-free race condition in
iris_hfi_gen1_handle_response().
Can an interrupt handler access a freed instance if iris_close() is called
concurrently?
If a user closes the device, iris_close() executes. Concurrently, the
threaded IRQ handler reads a message and looks up the instance:
IRQ Thread:
iris_hfi_gen1_handle_response() {
...
inst = iris_get_instance(core, pkt->shdr.session_id);
// iris_get_instance returns the pointer without acquiring a reference
mutex_lock(&inst->lock); // blocks if iris_close() is holding the lock
...
}
User Thread:
iris_close() {
...
mutex_lock(&inst->lock);
iris_remove_session(inst);
mutex_unlock(&inst->lock);
mutex_destroy(&inst->lock);
kfree(inst);
...
}
Once iris_close() frees the instance, the IRQ thread unblocks and attempts
to use the destroyed mutex and freed instance memory. Does the driver need
reference counting (e.g., kref) on the iris_inst structure to prevent it
from being freed while the IRQ thread is processing messages for it?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=13
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 14/18] media: iris: implement support for the Agatti platform
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (12 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 13/18] media: iris: update buffer requirements based on received info Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 14:19 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 15/18] media: iris: Introduce buffer size calculations for AR50LT Dmitry Baryshkov
` (3 subsequent siblings)
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
Port support for the AR50Lt video codec core (present for example on the
Agatti platform) to the Iris driver. Unlike more recent cores this
generation doesn't have the PIPE property (as it always has only one
pipe). Also, unlike newer platforms, buffer sizes are requested from the
firmware instead of being calculated by the driver.
Co-developed-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/Makefile | 1 +
drivers/media/platform/qcom/iris/iris_hfi_gen1.c | 241 +++++++++++++++++++++
.../platform/qcom/iris/iris_hfi_gen1_command.c | 7 +
.../platform/qcom/iris/iris_platform_common.h | 6 +
.../platform/qcom/iris/iris_platform_vpu_ar50lt.c | 110 ++++++++++
drivers/media/platform/qcom/iris/iris_probe.c | 4 +
drivers/media/platform/qcom/iris/iris_vpu_buffer.c | 5 +
drivers/media/platform/qcom/iris/iris_vpu_buffer.h | 1 +
8 files changed, 375 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile
index f1b204b95694..bbd1f724963e 100644
--- a/drivers/media/platform/qcom/iris/Makefile
+++ b/drivers/media/platform/qcom/iris/Makefile
@@ -14,6 +14,7 @@ qcom-iris-objs += iris_buffer.o \
iris_hfi_queue.o \
iris_platform_vpu2.o \
iris_platform_vpu3x.o \
+ iris_platform_vpu_ar50lt.o \
iris_power.o \
iris_probe.o \
iris_resources.o \
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
index ca1545d28b53..60bc1339ddd4 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
@@ -443,3 +443,244 @@ const struct iris_firmware_data iris_hfi_gen1_data = {
.enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl,
.enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl),
};
+
+static const struct platform_inst_fw_cap iris_inst_fw_cap_gen1_ar50lt_dec[] = {
+ {
+ .cap_id = STAGE,
+ .min = STAGE_1,
+ .max = STAGE_2,
+ .step_or_mask = 1,
+ .value = STAGE_2,
+ .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE,
+ .set = iris_set_stage,
+ },
+};
+
+static const struct platform_inst_fw_cap inst_fw_cap_gen1_ar50lt_enc[] = {
+ {
+ .cap_id = STAGE,
+ .min = STAGE_1,
+ .max = STAGE_2,
+ .step_or_mask = 1,
+ .value = STAGE_2,
+ .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE,
+ .set = iris_set_stage,
+ },
+ {
+ .cap_id = PROFILE_H264,
+ .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .max = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH),
+ .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+ .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_profile_level_gen1,
+ },
+ {
+ .cap_id = PROFILE_HEVC,
+ .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+ .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_profile_level_gen1,
+ },
+ {
+ .cap_id = LEVEL_H264,
+ .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2),
+ .value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_profile_level_gen1,
+ },
+ {
+ .cap_id = LEVEL_HEVC,
+ .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1),
+ .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_profile_level_gen1,
+ },
+ {
+ .cap_id = HEADER_MODE,
+ .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+ BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
+ .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ .hfi_id = HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_header_mode_gen1,
+ },
+ {
+ .cap_id = BITRATE,
+ .min = BITRATE_MIN,
+ .max = BITRATE_MAX_AR50LT,
+ .step_or_mask = BITRATE_STEP,
+ .value = BITRATE_DEFAULT_AR50LT,
+ .hfi_id = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_bitrate_gen1,
+ },
+ {
+ .cap_id = BITRATE_MODE,
+ .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+ BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR),
+ .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .hfi_id = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_bitrate_mode_gen1,
+ },
+ {
+ .cap_id = FRAME_SKIP_MODE,
+ .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
+ BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT),
+ .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ },
+ {
+ .cap_id = FRAME_RC_ENABLE,
+ .min = 0,
+ .max = 1,
+ .step_or_mask = 1,
+ .value = 1,
+ },
+ {
+ .cap_id = GOP_SIZE,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step_or_mask = 1,
+ .value = 30,
+ .set = iris_set_u32
+ },
+ {
+ .cap_id = ENTROPY_MODE,
+ .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+ BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
+ .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .hfi_id = HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_entropy_mode_gen1,
+ },
+ {
+ .cap_id = MIN_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_qp_range,
+ },
+ {
+ .cap_id = MIN_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP_HEVC,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_qp_range,
+ },
+ {
+ .cap_id = MAX_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_qp_range,
+ },
+ {
+ .cap_id = MAX_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP_HEVC,
+ .step_or_mask = 1,
+ .value = MAX_QP_HEVC,
+ .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_qp_range,
+ },
+};
+
+static const u32 iris_hfi_gen1_ar50lt_dec_ip_int_buf_tbl[] = {
+ BUF_BIN,
+ BUF_SCRATCH_1,
+};
+
+/*
+ * Unlike sm8250, on AR50Lt the internal buffer sizes are provided by the
+ * firmware. Request HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL so that the encoder
+ * queries HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS before allocating them.
+ */
+static const u32 iris_hfi_gen1_ar50lt_venc_input_config_param[] = {
+ HFI_PROPERTY_CONFIG_FRAME_RATE,
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
+ HFI_PROPERTY_PARAM_FRAME_SIZE,
+ HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL,
+ HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL,
+};
+
+const struct iris_firmware_data iris_hfi_gen1_ar50lt_data = {
+ .init_hfi_ops = &iris_hfi_gen1_sys_ops_init,
+
+ .inst_fw_caps_dec = iris_inst_fw_cap_gen1_ar50lt_dec,
+ .inst_fw_caps_dec_size = ARRAY_SIZE(iris_inst_fw_cap_gen1_ar50lt_dec),
+ .inst_fw_caps_enc = inst_fw_cap_gen1_ar50lt_enc,
+ .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_gen1_ar50lt_enc),
+
+ .dec_input_config_params_default =
+ sm8250_vdec_input_config_param_default,
+ .dec_input_config_params_default_size =
+ ARRAY_SIZE(sm8250_vdec_input_config_param_default),
+ .enc_input_config_params = iris_hfi_gen1_ar50lt_venc_input_config_param,
+ .enc_input_config_params_size =
+ ARRAY_SIZE(iris_hfi_gen1_ar50lt_venc_input_config_param),
+
+ .dec_ip_int_buf_tbl = iris_hfi_gen1_ar50lt_dec_ip_int_buf_tbl,
+ .dec_ip_int_buf_tbl_size = ARRAY_SIZE(iris_hfi_gen1_ar50lt_dec_ip_int_buf_tbl),
+ .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl,
+ .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl),
+
+ .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl,
+ .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl),
+};
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
index 99e82e5510ab..c4baabbacefd 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
@@ -970,6 +970,11 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst, u32 plane)
struct hfi_buffer_size_actual bufsz;
int ret;
+ ret = inst->hfi_session_ops->session_get_property(inst,
+ HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS);
+ if (ret)
+ return ret;
+
if (iris_split_mode_enabled(inst)) {
bufsz.type = HFI_BUFFER_OUTPUT;
bufsz.size = inst->core->iris_firmware_desc->get_vpu_buffer_size(inst, BUF_DPB);
@@ -1084,6 +1089,8 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p
iris_hfi_gen1_set_raw_format},
{HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL,
iris_hfi_gen1_set_num_bufs},
+ {HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL,
+ iris_hfi_gen1_set_bufsize},
};
if (inst->domain == DECODER) {
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index 6a189489369f..bc04831ae7fc 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -39,6 +39,10 @@ struct iris_inst;
#define MAX_HEVC_VBR_LAYER_HP_SLIDING_WINDOW 5
#define MAX_HIER_CODING_LAYER_GEN1 6
+#define BITRATE_MAX_AR50LT 100000000
+#define BITRATE_DEFAULT_AR50LT 20000000
+#define MIN_QP_8BIT_AR50LT 0
+
enum stage_type {
STAGE_1 = 1,
STAGE_2 = 2,
@@ -51,8 +55,10 @@ enum pipe_type {
};
extern const struct iris_firmware_data iris_hfi_gen1_data;
+extern const struct iris_firmware_data iris_hfi_gen1_ar50lt_data;
extern const struct iris_firmware_data iris_hfi_gen2_data;
+extern const struct iris_platform_data qcm2290_data;
extern const struct iris_platform_data qcs8300_data;
extern const struct iris_platform_data sc7280_data;
extern const struct iris_platform_data sm8250_data;
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c b/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
new file mode 100644
index 000000000000..92f7e2546539
--- /dev/null
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "iris_core.h"
+#include "iris_ctrls.h"
+#include "iris_hfi_gen2.h"
+#include "iris_hfi_gen2_defines.h"
+#include "iris_platform_common.h"
+#include "iris_vpu_buffer.h"
+#include "iris_vpu_common.h"
+
+#define WRAPPER_INTR_STATUS_A2HWD_BMSK 0x10
+
+static const struct iris_firmware_desc iris_vpu_ar50lt_p1_gen1_s6_desc = {
+ .firmware_data = &iris_hfi_gen1_ar50lt_data,
+ .get_vpu_buffer_size = iris_vpu_ar50lt_gen1_buf_size,
+ .fwname = "qcom/venus-6.0/venus.mbn",
+};
+
+static const u32 iris_fmts_ar50lt_dec[] = {
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_HEVC,
+ V4L2_PIX_FMT_VP9,
+};
+
+static const struct bw_info iris_bw_table_dec_ar50lt[] = {
+ { ((1920 * 1080) / 256) * 60, 1564000, },
+ { ((1920 * 1080) / 256) * 30, 791000, },
+ { ((1280 * 720) / 256) * 60, 688000, },
+ { ((1280 * 720) / 256) * 30, 347000, },
+};
+
+static const struct icc_info iris_icc_info_ar50lt[] = {
+ { "cpu-cfg", 1000, 1000 },
+ { "video-mem", 1000, 6500000 },
+};
+
+static const char * const iris_pmdomain_table_ar50lt[] = { "venus", "vcodec0" };
+
+static const char * const iris_opp_pd_table_ar50lt[] = { "cx" };
+
+static const struct platform_clk_data iris_clk_table_ar50lt[] = {
+ {IRIS_CTRL_CLK, "core" },
+ {IRIS_AXI_CLK, "iface" },
+ {IRIS_AHB_CLK, "bus" },
+ {IRIS_HW_CLK, "vcodec0_core" },
+ {IRIS_HW_AHB_CLK, "vcodec0_bus" },
+ {IRIS_THROTTLE_CLK, "throttle" },
+};
+
+static const char * const iris_opp_clk_table_ar50lt[] = {
+ "vcodec0_core",
+ NULL,
+};
+
+static const struct tz_cp_config tz_cp_config_ar50lt[] = {
+ {
+ .cp_start = 0,
+ .cp_size = 0x25800000,
+ .cp_nonpixel_start = 0x01000000,
+ .cp_nonpixel_size = 0x24800000,
+ },
+};
+
+static struct platform_inst_caps platform_inst_cap_ar50lt = {
+ .min_frame_width = 128,
+ .max_frame_width = 1920,
+ .min_frame_height = 128,
+ .max_frame_height = 1920,
+ .max_mbpf = (1920 * 1088) / 256,
+ .mb_cycles_vpp = 440,
+ .mb_cycles_fw = 733003,
+ .mb_cycles_fw_vpp = 225975,
+ .max_frame_rate = 120,
+ .max_operating_rate = 120,
+};
+
+const struct iris_platform_data qcm2290_data = {
+ .firmware_desc_gen1 = &iris_vpu_ar50lt_p1_gen1_s6_desc,
+ .vpu_ops = &iris_vpu_ar50lt_ops,
+ .icc_tbl = iris_icc_info_ar50lt,
+ .icc_tbl_size = ARRAY_SIZE(iris_icc_info_ar50lt),
+ .bw_tbl_dec = iris_bw_table_dec_ar50lt,
+ .bw_tbl_dec_size = ARRAY_SIZE(iris_bw_table_dec_ar50lt),
+ .pmdomain_tbl = iris_pmdomain_table_ar50lt,
+ .pmdomain_tbl_size = ARRAY_SIZE(iris_pmdomain_table_ar50lt),
+ .opp_pd_tbl = iris_opp_pd_table_ar50lt,
+ .opp_pd_tbl_size = ARRAY_SIZE(iris_opp_pd_table_ar50lt),
+ .clk_tbl = iris_clk_table_ar50lt,
+ .clk_tbl_size = ARRAY_SIZE(iris_clk_table_ar50lt),
+ .opp_clk_tbl = iris_opp_clk_table_ar50lt,
+ /* Upper bound of DMA address range */
+ .dma_mask = 0xe0000000 - 1,
+ .inst_iris_fmts = iris_fmts_ar50lt_dec,
+ .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_ar50lt_dec),
+ .inst_caps = &platform_inst_cap_ar50lt,
+ .tz_cp_config_data = tz_cp_config_ar50lt,
+ .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_ar50lt),
+ .num_vpp_pipe = 1,
+ .no_rpmh = true,
+ .wd_intr_mask = WRAPPER_INTR_STATUS_A2HWD_BMSK,
+ .icc_ib_multiplier = 2,
+ .max_session_count = 8,
+ .max_core_mbpf = ((1920 * 1088) / 256) * 4,
+ /* Concurrency: 1080p@30 decode + 1080p@30 encode */
+ /* Concurrency: 3 * 1080p@30 decode */
+ .max_core_mbps = (((1920 * 1088) / 256) * 90),
+};
diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
index 7fe31136df21..472d9e293ece 100644
--- a/drivers/media/platform/qcom/iris/iris_probe.c
+++ b/drivers/media/platform/qcom/iris/iris_probe.c
@@ -356,6 +356,10 @@ static const struct dev_pm_ops iris_pm_ops = {
};
static const struct of_device_id iris_dt_match[] = {
+ {
+ .compatible = "qcom,qcm2290-venus",
+ .data = &qcm2290_data,
+ },
{
.compatible = "qcom,qcs8300-iris",
.data = &qcs8300_data,
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
index fb6f1016415e..511502d4ea6c 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
@@ -2194,6 +2194,11 @@ u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_typ
return size;
}
+u32 iris_vpu_ar50lt_gen1_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type)
+{
+ return inst->buffers[buffer_type].size;
+}
+
static u32 internal_buffer_count(struct iris_inst *inst,
enum iris_buffer_type buffer_type)
{
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
index 8c0d6b7b5de8..1d07137c70cd 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
@@ -288,6 +288,7 @@ static inline u32 size_av1d_qp(u32 frame_width, u32 frame_height)
u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
+u32 iris_vpu_ar50lt_gen1_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type);
#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 14/18] media: iris: implement support for the Agatti platform
2026-07-09 13:42 ` [PATCH v7 14/18] media: iris: implement support for the Agatti platform Dmitry Baryshkov
@ 2026-07-09 14:19 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 14:19 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Critical] Unconditional firmware query for buffer requirements during STREAMON overwrites driver-calculated sizes, breaking Gen1 decoders and causing DMA buffer overflows.
Pre-existing issues:
- [High] Completion crosstalk between a timed out `GET_PROPERTY` command and a subsequent `SESSION_STOP` command causes premature buffer freeing, leading to use-after-free.
- [Medium] The GOP_SIZE capability is missing the .hfi_id field in Gen1 encoder configurations, causing silent failures when setting the property.
--
--- Patch [14]: [PATCH v7 14/18] media: iris: implement support for the Agatti platform ---
commit 50a13c3b4c9f960eb99c4401684a9076ce008a44
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
media: iris: implement support for the Agatti platform
Port support for the AR50Lt video codec core (present for example on the
Agatti platform) to the Iris driver. Unlike more recent cores this
generation doesn't have the PIPE property (as it always has only one
pipe). Also, unlike newer platforms, buffer sizes are requested from the
firmware instead of being calculated by the driver.
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
> index ca1545d28b531..60bc1339ddd41 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
[ ... ]
> + {
> + .cap_id = GOP_SIZE,
> + .min = 0,
> + .max = (1 << 16) - 1,
> + .step_or_mask = 1,
> + .value = 30,
> + .set = iris_set_u32
> + },
[Severity: Medium]
This is a pre-existing issue, but the GOP_SIZE capability is missing the
.hfi_id field here, meaning it defaults to 0.
Because of this, when iris_set_u32() invokes session_set_property() with
ID 0, the default case in iris_hfi_gen1_packet_session_set_property()
will return -EINVAL. The caller, iris_set_properties(), explicitly ignores
this return value:
if (cap->cap_id && cap->set)
cap->set(inst, i);
Since AR50Lt lacks the B_FRAME capability (which applies GOP size on other
platforms), does this completely prevent the GOP size from being configured
on the firmware?
[ ... ]
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> index 99e82e5510abe..c4baabbacefda 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c
> @@ -970,6 +970,11 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst, u32 plane)
> struct hfi_buffer_size_actual bufsz;
> int ret;
>
> + ret = inst->hfi_session_ops->session_get_property(inst,
> + HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS);
[Severity: Critical]
Does this unconditional firmware query during STREAMON break existing Gen1
decoders and lead to DMA buffer overflows?
When the firmware responds to this property,
iris_hfi_gen1_session_buffer_requirements() blindly overwrites
inst->buffers[type].size with the firmware's required size:
inst->buffers[type].size = req->size;
However, userspace allocated these V4L2 DMA buffers during REQBUFS based on
the mathematical size from iris_get_buffer_size(). During QBUF,
iris_vb2_buf_prepare() incorrectly validates against this smaller size instead
of the firmware's newly required size:
if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT))
return -EINVAL;
If the driver then passes the firmware's required size (via
HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL), could the firmware write past the end
of the physically allocated DMA memory?
Additionally, does applying this unconditional query to existing SM8250 decoders
force an unsupported state transition?
[Severity: High]
This isn't a bug introduced by this patch, but can this session_get_property()
call lead to a use-after-free if it times out?
iris_hfi_gen1_session_get_property() waits synchronously on inst->completion.
If it times out, the command is left pending in the firmware. Later, if
userspace stops the stream, iris_hfi_gen1_session_stop() reinitializes
inst->completion and waits for HFI_CMD_SESSION_STOP.
If the delayed HFI_MSG_SESSION_PROPERTY_INFO arrives during this wait,
iris_hfi_gen1_session_property_info() handles it and blindly calls:
complete(&inst->completion);
Will this prematurely wake the SESSION_STOP wait, causing the driver to
mistakenly believe the session has stopped and free internal buffers while
the firmware is still accessing them?
> + if (ret)
> + return ret;
> +
> if (iris_split_mode_enabled(inst)) {
> bufsz.type = HFI_BUFFER_OUTPUT;
> bufsz.size = inst->core->iris_firmware_desc->get_vpu_buffer_size(inst, BUF_DPB);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=14
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 15/18] media: iris: Introduce buffer size calculations for AR50LT
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (13 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 14/18] media: iris: implement support for the Agatti platform Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 14:09 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 16/18] media: iris: add Gen2 firmware support on the Agatti platform Dmitry Baryshkov
` (2 subsequent siblings)
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Introduces AR50LT buffer size calculation for both encoder and
decoder. Reuse the buffer size calculation which are common, while
adding the AR50LT specific ones separately.
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_vpu_buffer.c | 365 +++++++++++++++++++++
drivers/media/platform/qcom/iris/iris_vpu_buffer.h | 37 +++
2 files changed, 402 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
index 511502d4ea6c..00dbb091c54e 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
@@ -50,6 +50,26 @@ static u32 hfi_buffer_bin_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_p
return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes);
}
+static u32 hfi_buffer_bin_h264d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 n_aligned_h = ALIGN(frame_height, 16);
+ u32 n_aligned_w = ALIGN(frame_width, 16);
+ u32 size_yuv, size_bin_hdr, size_bin_res;
+
+ size_yuv = ((n_aligned_w * n_aligned_h * 3) >> 1);
+ if (size_yuv <= 1920 * 1088 * 3 / 2) {
+ size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_SM_TOT;
+ size_bin_res = size_yuv * H264_CABAC_RES_RATIO_SM_TOT;
+ } else {
+ size_bin_hdr = (size_yuv * 3) / 5;
+ size_bin_res = (size_yuv * 3) / 2;
+ }
+ size_bin_hdr = ALIGN(size_bin_hdr, DMA_ALIGNMENT);
+ size_bin_res = ALIGN(size_bin_res, DMA_ALIGNMENT);
+
+ return size_bin_hdr + size_bin_res;
+}
+
static u32 size_av1d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
{
u32 size_yuv, size_bin_hdr, size_bin_res;
@@ -103,6 +123,19 @@ static u32 hfi_buffer_bin_vp9d(u32 frame_width, u32 frame_height, u32 num_vpp_pi
return _size * num_vpp_pipes;
}
+static u32 hfi_buffer_bin_vp9d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 size_yuv, size;
+
+ size_yuv = ALIGN(frame_width, 16) * ALIGN(frame_height, 16) * 3 / 2;
+ size_yuv = ALIGN(size_yuv, DMA_ALIGNMENT);
+
+ size = ALIGN(((max(size_yuv, VPX_DECODER_FRAME_BIN_BUFFER_SIZE)) * 6) / 5, DMA_ALIGNMENT) +
+ ALIGN(((max(size_yuv, VPX_DECODER_FRAME_BIN_BUFFER_SIZE)) * 4), DMA_ALIGNMENT);
+
+ return size;
+}
+
static u32 hfi_buffer_bin_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
{
u32 n_aligned_w = ALIGN(frame_width, 16);
@@ -111,6 +144,27 @@ static u32 hfi_buffer_bin_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_p
return size_h265d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes);
}
+static u32 hfi_buffer_bin_h265d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 n_aligned_w = ALIGN(frame_width, 16);
+ u32 n_aligned_h = ALIGN(frame_height, 16);
+
+ u32 size_yuv, size_bin_hdr, size_bin_res;
+
+ size_yuv = ((n_aligned_w * n_aligned_h * 3) >> 1);
+ if (size_yuv <= ((BIN_BUFFER_THRESHOLD * 3) >> 1)) {
+ size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_SM_TOT;
+ size_bin_res = size_yuv * H265_CABAC_RES_RATIO_SM_TOT;
+ } else {
+ size_bin_hdr = (size_yuv * 41) / 50;
+ size_bin_res = (size_yuv * 59) / 50;
+ }
+ size_bin_hdr = ALIGN(size_bin_hdr, DMA_ALIGNMENT);
+ size_bin_res = ALIGN(size_bin_res, DMA_ALIGNMENT);
+
+ return size_bin_hdr + size_bin_res;
+}
+
static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bufcount)
{
u32 frame_height_in_mbs = DIV_ROUND_UP(frame_height, 16);
@@ -174,6 +228,14 @@ static u32 size_h264d_bse_cmd_buf(u32 frame_height)
SIZE_H264D_BSE_CMD_PER_BUF;
}
+static u32 size_h264d_bse_cmd_buf_ar50lt(u32 frame_height)
+{
+ u32 height = ALIGN(frame_height, 32);
+
+ return min_t(u32, (DIV_ROUND_UP(height, 16) * 12), H264D_MAX_SLICE) *
+ SIZE_H264D_BSE_CMD_PER_BUF;
+}
+
static u32 size_h265d_bse_cmd_buf(u32 frame_width, u32 frame_height)
{
u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) *
@@ -185,6 +247,18 @@ static u32 size_h265d_bse_cmd_buf(u32 frame_width, u32 frame_height)
return _size;
}
+static u32 size_h265d_bse_cmd_buf_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) *
+ (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) *
+ NUM_HW_PIC_BUF, DMA_ALIGNMENT);
+
+ _size = min_t(u32, _size, H265D_MAX_SLICE_AR50LT + 1);
+ _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF;
+
+ return _size;
+}
+
static u32 hfi_buffer_persist_h265d(u32 rpu_enabled)
{
return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 +
@@ -195,6 +269,13 @@ static u32 hfi_buffer_persist_h265d(u32 rpu_enabled)
DMA_ALIGNMENT);
}
+static u32 hfi_buffer_persist_h265d_ar50lt(void)
+{
+ return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 +
+ H265_NUM_TILE * sizeof(u32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA),
+ DMA_ALIGNMENT);
+}
+
static inline
u32 hfi_iris3_vp9d_comv_size(void)
{
@@ -212,6 +293,13 @@ static u32 hfi_buffer_persist_vp9d(void)
HDR10_HIST_EXTRADATA_SIZE;
}
+static u32 hfi_buffer_persist_vp9d_ar50lt(void)
+{
+ return ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, DMA_ALIGNMENT) +
+ ALIGN(hfi_iris3_vp9d_comv_size(), DMA_ALIGNMENT) +
+ ALIGN(MAX_SUPERFRAME_HEADER_LEN, DMA_ALIGNMENT);
+}
+
static u32 size_h264d_vpp_cmd_buf(u32 frame_height)
{
u32 size, height = ALIGN(frame_height, 32);
@@ -222,6 +310,16 @@ static u32 size_h264d_vpp_cmd_buf(u32 frame_height)
return size > VPP_CMD_MAX_SIZE ? VPP_CMD_MAX_SIZE : size;
}
+static u32 size_h264d_vpp_cmd_buf_ar50lt(u32 frame_height)
+{
+ u32 size, height = ALIGN(frame_height, 32);
+
+ size = min_t(u32, (DIV_ROUND_UP(height, 16) * 12), H264D_MAX_SLICE) *
+ SIZE_H264D_VPP_CMD_PER_BUF;
+
+ return size > VPP_CMD_MAX_SIZE ? VPP_CMD_MAX_SIZE : size;
+}
+
static u32 hfi_buffer_persist_h264d(void)
{
return ALIGN(SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 +
@@ -230,6 +328,11 @@ static u32 hfi_buffer_persist_h264d(void)
DMA_ALIGNMENT);
}
+static u32 hfi_buffer_persist_h264d_ar50lt(void)
+{
+ return ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264), DMA_ALIGNMENT);
+}
+
static u32 hfi_buffer_persist_av1d(u32 max_width, u32 max_height, u32 total_ref_count)
{
u32 comv_size, size;
@@ -255,6 +358,17 @@ static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 num_
return ALIGN(size, DMA_ALIGNMENT);
}
+static u32 hfi_buffer_non_comv_h264d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 size_bse = size_h264d_bse_cmd_buf_ar50lt(frame_height);
+ u32 size_vpp = size_h264d_vpp_cmd_buf_ar50lt(frame_height);
+ u32 size = ALIGN(size_bse, DMA_ALIGNMENT) +
+ ALIGN(size_vpp, DMA_ALIGNMENT) +
+ ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT);
+
+ return ALIGN(size, DMA_ALIGNMENT);
+}
+
static u32 size_h265d_vpp_cmd_buf(u32 frame_width, u32 frame_height)
{
u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) *
@@ -269,6 +383,20 @@ static u32 size_h265d_vpp_cmd_buf(u32 frame_width, u32 frame_height)
return _size;
}
+static u32 size_h265d_vpp_cmd_buf_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) *
+ (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) *
+ NUM_HW_PIC_BUF, DMA_ALIGNMENT);
+ _size = min_t(u32, _size, H265D_MAX_SLICE_AR50LT + 1);
+ _size = ALIGN(_size, 4);
+ _size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF_AR50LT;
+ if (_size > VPP_CMD_MAX_SIZE)
+ _size = VPP_CMD_MAX_SIZE;
+
+ return _size;
+}
+
static u32 hfi_buffer_non_comv_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
{
u32 _size_bse = size_h265d_bse_cmd_buf(frame_width, frame_height);
@@ -285,6 +413,20 @@ static u32 hfi_buffer_non_comv_h265d(u32 frame_width, u32 frame_height, u32 num_
return ALIGN(_size, DMA_ALIGNMENT);
}
+static u32 hfi_buffer_non_comv_h265d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 _size_bse = size_h265d_bse_cmd_buf_ar50lt(frame_width, frame_height);
+ u32 _size_vpp = size_h265d_vpp_cmd_buf_ar50lt(frame_width, frame_height);
+ u32 _size = ALIGN(_size_bse, DMA_ALIGNMENT) +
+ ALIGN(_size_vpp, DMA_ALIGNMENT) +
+ ALIGN(2 * sizeof(u16) *
+ (ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) *
+ (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), DMA_ALIGNMENT) +
+ ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), DMA_ALIGNMENT);
+
+ return ALIGN(_size, DMA_ALIGNMENT);
+}
+
static u32 size_vpss_lb(u32 frame_width, u32 frame_height)
{
u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size;
@@ -317,6 +459,13 @@ u32 size_h265d_lb_fe_top_data(u32 frame_width, u32 frame_height)
(ALIGN(frame_width, 64) + 8) * 2;
}
+static inline
+u32 size_h265d_lb_fe_top_data_ar50lt(u32 frame_width, u32 frame_height)
+{
+ return ALIGN(MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE *
+ (ALIGN(frame_width, 64) + 8), DMA_ALIGNMENT) * 2;
+}
+
static inline
u32 size_h265d_lb_fe_top_ctrl(u32 frame_width, u32 frame_height)
{
@@ -348,6 +497,17 @@ u32 size_h265d_lb_se_left_ctrl(u32 frame_width, u32 frame_height)
MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE));
}
+static inline
+u32 size_h265d_lb_se_left_ctrl_ar50lt(u32 frame_width, u32 frame_height)
+{
+ return max_t(u32, ((frame_height + 16 - 1) / 8) *
+ MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE_AR50LT,
+ max_t(u32, ((frame_height + 32 - 1) / 8) *
+ MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE_AR50LT,
+ ((frame_height + 64 - 1) / 8) *
+ MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE_AR50LT));
+}
+
static inline
u32 size_h265d_lb_pe_top_data(u32 frame_width, u32 frame_height)
{
@@ -355,6 +515,13 @@ u32 size_h265d_lb_pe_top_data(u32 frame_width, u32 frame_height)
(ALIGN(frame_width, LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS);
}
+static inline
+u32 size_h265d_lb_pe_top_data_ar50lt(u32 frame_width, u32 frame_height)
+{
+ return MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE_AR50LT *
+ (ALIGN(frame_width, LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS);
+}
+
static inline
u32 size_h265d_lb_vsp_top(u32 frame_width, u32 frame_height)
{
@@ -404,6 +571,25 @@ u32 hfi_buffer_line_h265d(u32 frame_width, u32 frame_height, bool is_opb, u32 nu
return ALIGN((_size + vpss_lb_size), DMA_ALIGNMENT);
}
+static inline
+u32 hfi_buffer_line_h265d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 size;
+
+ size = ALIGN(size_h265d_lb_fe_top_data_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_fe_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_fe_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_se_left_ctrl_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_pe_top_data_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_vsp_left(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h265d_lb_recon_dma_metadata_wr(frame_width, frame_height), DMA_ALIGNMENT) * 4 +
+ ALIGN(size_h265d_qp(frame_width, frame_height), DMA_ALIGNMENT);
+
+ return ALIGN(size, DMA_ALIGNMENT);
+}
+
static inline
u32 size_vpxd_lb_fe_left_ctrl(u32 frame_width, u32 frame_height)
{
@@ -438,6 +624,17 @@ u32 size_vpxd_lb_se_left_ctrl(u32 frame_width, u32 frame_height)
MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE));
}
+static inline
+u32 size_vpxd_lb_se_left_ctrl_ar50lt(u32 frame_width, u32 frame_height)
+{
+ return max_t(u32, ((frame_height + 15) >> 4) *
+ MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE_AR50LT,
+ max_t(u32, ((frame_height + 31) >> 5) *
+ MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE_AR50LT,
+ ((frame_height + 63) >> 6) *
+ MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE_AR50LT));
+}
+
static inline
u32 size_vpxd_lb_recon_dma_metadata_wr(u32 frame_width, u32 frame_height)
{
@@ -492,6 +689,17 @@ u32 hfi_iris3_vp9d_lb_size(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
ALIGN(size_vp9d_qp(frame_width, frame_height), DMA_ALIGNMENT);
}
+static inline
+u32 hfi_buffer_line_vp9d_ar50lt(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min)
+{
+ return ALIGN(size_vpxd_lb_fe_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_vpxd_lb_se_left_ctrl_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_vp9d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_vpxd_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_vp9d_lb_pe_top_data(frame_width, frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_vp9d_lb_fe_top_data(frame_width, frame_height), DMA_ALIGNMENT);
+}
+
static inline
u32 hfi_buffer_line_vp9d(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min, bool is_opb,
u32 num_vpp_pipes)
@@ -529,6 +737,23 @@ static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height,
return ALIGN((size + vpss_lb_size), DMA_ALIGNMENT);
}
+static u32 hfi_buffer_line_h264d_ar50lt(u32 frame_width, u32 frame_height)
+{
+ u32 size;
+
+ size = ALIGN(size_h264d_lb_fe_top_data_ar50lt(frame_width), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_fe_top_ctrl_ar50lt(frame_width), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_fe_left_ctrl(frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_se_top_ctrl_ar50lt(frame_width), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_se_left_ctrl_ar50lt(frame_height), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_pe_top_data_ar50lt(frame_width), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_vsp_top(frame_width), DMA_ALIGNMENT) +
+ ALIGN(size_h264d_lb_recon_dma_metadata_wr(frame_height), DMA_ALIGNMENT) * 2 +
+ ALIGN(size_h264d_qp(frame_width, frame_height), DMA_ALIGNMENT);
+
+ return ALIGN(size, DMA_ALIGNMENT);
+}
+
static u32 size_av1d_lb_opb_wr1_nv12_ubwc(u32 frame_width, u32 frame_height)
{
u32 size, y_width, y_width_a = 128;
@@ -724,6 +949,22 @@ static u32 iris_vpu_dec_bin_size(struct iris_inst *inst)
return 0;
}
+static u32 iris_vpu_ar50lt_dec_bin_size(struct iris_inst *inst)
+{
+ struct v4l2_format *f = inst->fmt_src;
+ u32 height = f->fmt.pix_mp.height;
+ u32 width = f->fmt.pix_mp.width;
+
+ if (inst->codec == V4L2_PIX_FMT_H264)
+ return hfi_buffer_bin_h264d_ar50lt(width, height);
+ else if (inst->codec == V4L2_PIX_FMT_HEVC)
+ return hfi_buffer_bin_h265d_ar50lt(width, height);
+ else if (inst->codec == V4L2_PIX_FMT_VP9)
+ return hfi_buffer_bin_vp9d_ar50lt(width, height);
+
+ return 0;
+}
+
static u32 iris_vpu_dec_comv_size(struct iris_inst *inst)
{
u32 num_comv = VIDEO_MAX_FRAME;
@@ -785,6 +1026,18 @@ static u32 iris_vpu_dec_persist_size(struct iris_inst *inst)
return 0;
}
+static u32 iris_vpu_ar50lt_dec_persist_size(struct iris_inst *inst)
+{
+ if (inst->codec == V4L2_PIX_FMT_H264)
+ return hfi_buffer_persist_h264d_ar50lt();
+ else if (inst->codec == V4L2_PIX_FMT_HEVC)
+ return hfi_buffer_persist_h265d_ar50lt();
+ else if (inst->codec == V4L2_PIX_FMT_VP9)
+ return hfi_buffer_persist_vp9d_ar50lt();
+
+ return 0;
+}
+
static u32 iris_vpu_dec_dpb_size(struct iris_inst *inst)
{
if (iris_split_mode_enabled(inst))
@@ -808,6 +1061,20 @@ static u32 iris_vpu_dec_non_comv_size(struct iris_inst *inst)
return 0;
}
+static u32 iris_vpu_ar50lt_dec_non_comv_size(struct iris_inst *inst)
+{
+ struct v4l2_format *f = inst->fmt_src;
+ u32 height = f->fmt.pix_mp.height;
+ u32 width = f->fmt.pix_mp.width;
+
+ if (inst->codec == V4L2_PIX_FMT_H264)
+ return hfi_buffer_non_comv_h264d_ar50lt(width, height);
+ else if (inst->codec == V4L2_PIX_FMT_HEVC)
+ return hfi_buffer_non_comv_h265d_ar50lt(width, height);
+
+ return 0;
+}
+
static u32 iris_vpu_dec_line_size(struct iris_inst *inst)
{
u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
@@ -833,6 +1100,23 @@ static u32 iris_vpu_dec_line_size(struct iris_inst *inst)
return 0;
}
+static u32 iris_vpu_ar50lt_dec_line_size(struct iris_inst *inst)
+{
+ struct v4l2_format *f = inst->fmt_src;
+ u32 height = f->fmt.pix_mp.height;
+ u32 width = f->fmt.pix_mp.width;
+ u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count;
+
+ if (inst->codec == V4L2_PIX_FMT_H264)
+ return hfi_buffer_line_h264d_ar50lt(width, height);
+ else if (inst->codec == V4L2_PIX_FMT_HEVC)
+ return hfi_buffer_line_h265d_ar50lt(width, height);
+ else if (inst->codec == V4L2_PIX_FMT_VP9)
+ return hfi_buffer_line_vp9d_ar50lt(width, height, out_min_count);
+
+ return 0;
+}
+
static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst)
{
return iris_vpu_dec_comv_size(inst) +
@@ -840,6 +1124,13 @@ static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst)
iris_vpu_dec_line_size(inst);
}
+static u32 iris_vpu_ar50lt_dec_scratch1_size(struct iris_inst *inst)
+{
+ return iris_vpu_dec_comv_size(inst) +
+ iris_vpu_ar50lt_dec_non_comv_size(inst) +
+ iris_vpu_ar50lt_dec_line_size(inst);
+}
+
static inline u32 iris_vpu_enc_get_bitstream_width(struct iris_inst *inst)
{
if (is_rotation_90_or_270(inst))
@@ -1470,6 +1761,15 @@ u32 hfi_buffer_dpb_enc(u32 frame_width, u32 frame_height, bool is_ten_bit)
return size;
}
+static inline
+u32 hfi_buffer_dpb_enc_ar50lt(u32 frame_width, u32 frame_height, bool is_ten_bit)
+{
+ if (!is_ten_bit)
+ return size_enc_ref_buffer(frame_width, frame_height);
+ else
+ return size_enc_ten_bit_ref_buffer(frame_width, frame_height);
+}
+
static u32 iris_vpu_enc_arp_size(struct iris_inst *inst)
{
return HFI_BUFFER_ARP_ENC;
@@ -1494,6 +1794,16 @@ u32 hfi_buffer_vpss_enc(u32 dswidth, u32 dsheight, bool ds_enable,
return 0;
}
+static inline
+u32 hfi_buffer_vpss_enc_ar50lt(u32 dswidth, u32 dsheight, bool ds_enable,
+ u32 blur, bool is_ten_bit)
+{
+ if (ds_enable || blur)
+ return hfi_buffer_dpb_enc_ar50lt(dswidth, dsheight, is_ten_bit);
+
+ return 0;
+}
+
static inline u32 hfi_buffer_scratch1_enc(u32 frame_width, u32 frame_height,
u32 lcu_size, u32 num_ref,
bool ten_bit, u32 num_vpp_pipes,
@@ -1752,6 +2062,16 @@ static u32 iris_vpu_enc_vpss_size(struct iris_inst *inst)
return hfi_buffer_vpss_enc(width, height, ds_enable, 0, 0);
}
+static u32 iris_vpu_ar50lt_enc_vpss_size(struct iris_inst *inst)
+{
+ u32 ds_enable = is_scaling_enabled(inst);
+ struct v4l2_format *f = inst->fmt_dst;
+ u32 height = f->fmt.pix_mp.height;
+ u32 width = f->fmt.pix_mp.width;
+
+ return hfi_buffer_vpss_enc_ar50lt(width, height, ds_enable, 0, 0);
+}
+
static inline u32 size_dpb_opb(u32 height, u32 lcu_size)
{
u32 max_tile_height = ((height + lcu_size - 1) / lcu_size) * lcu_size + 8;
@@ -2199,6 +2519,51 @@ u32 iris_vpu_ar50lt_gen1_buf_size(struct iris_inst *inst, enum iris_buffer_type
return inst->buffers[buffer_type].size;
}
+u32 iris_vpu_ar50lt_gen2_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type)
+{
+ const struct iris_vpu_buf_type_handle *buf_type_handle_arr = NULL;
+ u32 size = 0, buf_type_handle_size = 0, i;
+
+ static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = {
+ {BUF_BIN, iris_vpu_ar50lt_dec_bin_size },
+ {BUF_COMV, iris_vpu_dec_comv_size },
+ {BUF_NON_COMV, iris_vpu_ar50lt_dec_non_comv_size },
+ {BUF_LINE, iris_vpu_ar50lt_dec_line_size },
+ {BUF_PERSIST, iris_vpu_ar50lt_dec_persist_size },
+ {BUF_DPB, iris_vpu_dec_dpb_size },
+ {BUF_SCRATCH_1, iris_vpu_ar50lt_dec_scratch1_size },
+ {BUF_PARTIAL, iris_vpu_dec_partial_size },
+ };
+
+ static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = {
+ {BUF_BIN, iris_vpu_enc_bin_size },
+ {BUF_COMV, iris_vpu_enc_comv_size },
+ {BUF_NON_COMV, iris_vpu_enc_non_comv_size },
+ {BUF_LINE, iris_vpu_enc_line_size },
+ {BUF_ARP, iris_vpu_enc_arp_size },
+ {BUF_VPSS, iris_vpu_ar50lt_enc_vpss_size },
+ {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size },
+ {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size },
+ };
+
+ if (inst->domain == DECODER) {
+ buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle);
+ buf_type_handle_arr = dec_internal_buf_type_handle;
+ } else if (inst->domain == ENCODER) {
+ buf_type_handle_size = ARRAY_SIZE(enc_internal_buf_type_handle);
+ buf_type_handle_arr = enc_internal_buf_type_handle;
+ }
+
+ for (i = 0; i < buf_type_handle_size; i++) {
+ if (buf_type_handle_arr[i].type == buffer_type) {
+ size = buf_type_handle_arr[i].handle(inst);
+ break;
+ }
+ }
+
+ return size;
+}
+
static u32 internal_buffer_count(struct iris_inst *inst,
enum iris_buffer_type buffer_type)
{
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
index 1d07137c70cd..2085e316a6bd 100644
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h
@@ -61,17 +61,26 @@ struct iris_inst;
#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64
#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8)
#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8)
+#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE_AR50LT (8 / 8)
+#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE_AR50LT (16 / 8)
+#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE_AR50LT (32 / 8)
#define VP9_UDC_HEADER_BUF_SIZE (3 * 128)
#define SIZE_SEI_USERDATA 4096
#define SIZE_DOLBY_RPU_METADATA (41 * 1024)
#define H264_CABAC_HDR_RATIO_HD_TOT 1
#define H264_CABAC_RES_RATIO_HD_TOT 3
+#define H264_CABAC_HDR_RATIO_SM_TOT 1
+#define H264_CABAC_RES_RATIO_SM_TOT 2
#define H265D_MAX_SLICE 3600
+#define H265D_MAX_SLICE_AR50LT 600
#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T
#define H265_CABAC_HDR_RATIO_HD_TOT 2
#define H265_CABAC_RES_RATIO_HD_TOT 2
+#define H265_CABAC_HDR_RATIO_SM_TOT 1
+#define H265_CABAC_RES_RATIO_SM_TOT 6
#define SIZE_H265D_VPP_CMD_PER_BUF (256)
+#define SIZE_H265D_VPP_CMD_PER_BUF_AR50LT (192)
#define SIZE_THREE_DIMENSION_USERDATA 768
#define SIZE_H265D_ARP 9728
@@ -81,6 +90,7 @@ struct iris_inst;
#define VPX_DECODER_FRAME_BIN_DENOMINATOR 2
#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO (3 / 2)
+#define VPX_DECODER_FRAME_BIN_BUFFER_SIZE (1024 * 1024)
#define SIZE_H264D_HW_PIC_T (BIT(11))
@@ -99,6 +109,7 @@ struct iris_inst;
#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64
#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 16
#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE 384
+#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE_AR50LT 176
#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640
#define AV1_CABAC_HDR_RATIO_HD_TOT 2
@@ -155,11 +166,21 @@ static inline u32 size_h264d_lb_fe_top_data(u32 frame_width)
return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * ALIGN(frame_width, 16) * 3;
}
+static inline u32 size_h264d_lb_fe_top_data_ar50lt(u32 frame_width)
+{
+ return 16 * ALIGN(frame_width, 16) * 2;
+}
+
static inline u32 size_h264d_lb_fe_top_ctrl(u32 frame_width)
{
return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * DIV_ROUND_UP(frame_width, 16);
}
+static inline u32 size_h264d_lb_fe_top_ctrl_ar50lt(u32 frame_width)
+{
+ return 16 * DIV_ROUND_UP(frame_width, 16);
+}
+
static inline u32 size_h264d_lb_fe_left_ctrl(u32 frame_height)
{
return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * DIV_ROUND_UP(frame_height, 16);
@@ -170,16 +191,31 @@ static inline u32 size_h264d_lb_se_top_ctrl(u32 frame_width)
return MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * DIV_ROUND_UP(frame_width, 16);
}
+static inline u32 size_h264d_lb_se_top_ctrl_ar50lt(u32 frame_width)
+{
+ return MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE_AR50LT * DIV_ROUND_UP(frame_width, 16);
+}
+
static inline u32 size_h264d_lb_se_left_ctrl(u32 frame_height)
{
return MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * DIV_ROUND_UP(frame_height, 16);
}
+static inline u32 size_h264d_lb_se_left_ctrl_ar50lt(u32 frame_height)
+{
+ return MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE_AR50LT * DIV_ROUND_UP(frame_height, 16);
+}
+
static inline u32 size_h264d_lb_pe_top_data(u32 frame_width)
{
return MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * DIV_ROUND_UP(frame_width, 16);
}
+static inline u32 size_h264d_lb_pe_top_data_ar50lt(u32 frame_width)
+{
+ return 64 * DIV_ROUND_UP(frame_width, 16);
+}
+
static inline u32 size_h264d_lb_vsp_top(u32 frame_width)
{
return (DIV_ROUND_UP(frame_width, 16) << 7);
@@ -289,6 +325,7 @@ u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type)
u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
u32 iris_vpu4x_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
u32 iris_vpu_ar50lt_gen1_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
+u32 iris_vpu_ar50lt_gen2_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type);
int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type);
#endif
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 15/18] media: iris: Introduce buffer size calculations for AR50LT
2026-07-09 13:42 ` [PATCH v7 15/18] media: iris: Introduce buffer size calculations for AR50LT Dmitry Baryshkov
@ 2026-07-09 14:09 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 14:09 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] AR50LT decoder line buffer calculations fail to allocate required VPSS (Video Processing Subsystem) line buffers when OPB (Output Picture Buffer) is enabled.
- [Medium] AR50LT VP9 line buffer size calculation omits key sub-buffer components (`fe_top_ctrl`, `recon_dma_metadata_wr`, and `qp`) present in other codecs.
--
--- Patch [15]: [PATCH v7 15/18] media: iris: Introduce buffer size calculations for AR50LT ---
commit 706f1cfb849daea9c7ee9eb5866f06341b85640c
Author: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
media: iris: Introduce buffer size calculations for AR50LT
Introduces AR50LT buffer size calculation for both encoder and
decoder. Reuse the buffer size calculation which are common, while
adding the AR50LT specific ones separately.
diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
--- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
+++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
[ ... ]
> @@ -571,6 +571,25 @@ u32 hfi_buffer_line_h265d(u32 frame_width, u32 frame_height, bool is_opb, u32 nu
> return ALIGN((_size + vpss_lb_size), DMA_ALIGNMENT);
> }
>
> +static inline
> +u32 hfi_buffer_line_h265d_ar50lt(u32 frame_width, u32 frame_height)
> +{
> + u32 size;
> +
> + size = ALIGN(size_h265d_lb_fe_top_data_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_fe_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_fe_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_se_left_ctrl_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_pe_top_data_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_vsp_left(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_h265d_lb_recon_dma_metadata_wr(frame_width, frame_height), DMA_ALIGNMENT) * 4 +
> + ALIGN(size_h265d_qp(frame_width, frame_height), DMA_ALIGNMENT);
> +
> + return ALIGN(size, DMA_ALIGNMENT);
> +}
> +
[Severity: Medium]
Does this code need to handle the VPSS line buffer allocation when the
Output Picture Buffer (OPB) is enabled?
The baseline functions like hfi_buffer_line_h265d() check for is_opb
and add size_vpss_lb(frame_width, frame_height) to the total allocation.
Could the AR50LT hardware experience an out-of-bounds memory write
during decoding if the VPSS line buffer size is omitted here?
[ ... ]
> @@ -689,6 +689,17 @@ u32 hfi_iris3_vp9d_lb_size(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
> ALIGN(size_vp9d_qp(frame_width, frame_height), DMA_ALIGNMENT);
> }
>
> +static inline
> +u32 hfi_buffer_line_vp9d_ar50lt(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min)
> +{
> + return ALIGN(size_vpxd_lb_fe_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_vpxd_lb_se_left_ctrl_ar50lt(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_vp9d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_vpxd_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_vp9d_lb_pe_top_data(frame_width, frame_height), DMA_ALIGNMENT) +
> + ALIGN(size_vp9d_lb_fe_top_data(frame_width, frame_height), DMA_ALIGNMENT);
> +}
> +
[Severity: Medium]
Are there some missing sub-buffer sizes in this VP9 line buffer calculation?
Looking at the baseline hfi_iris3_vp9d_lb_size(), as well as the AR50LT
H.264 and H.265 calculations, they seem to include sizes for fe_top_ctrl,
recon_dma_metadata_wr, and qp. If the AR50LT hardware requires these
buffers for VP9, could omitting them cause out-of-bounds memory writes?
[ ... ]
> @@ -1100,6 +1100,23 @@ static u32 iris_vpu_dec_line_size(struct iris_inst *inst)
> return 0;
> }
>
> +static u32 iris_vpu_ar50lt_dec_line_size(struct iris_inst *inst)
> +{
> + struct v4l2_format *f = inst->fmt_src;
> + u32 height = f->fmt.pix_mp.height;
> + u32 width = f->fmt.pix_mp.width;
> + u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count;
> +
> + if (inst->codec == V4L2_PIX_FMT_H264)
> + return hfi_buffer_line_h264d_ar50lt(width, height);
> + else if (inst->codec == V4L2_PIX_FMT_HEVC)
> + return hfi_buffer_line_h265d_ar50lt(width, height);
> + else if (inst->codec == V4L2_PIX_FMT_VP9)
> + return hfi_buffer_line_vp9d_ar50lt(width, height, out_min_count);
> +
> + return 0;
> +}
> +
[Severity: Medium]
Should this function check for iris_split_mode_enabled() to determine OPB
state, similar to how iris_vpu_dec_line_size() does?
If the VPSS line buffer size allocation is required for AR50LT when OPB
is enabled, it seems the is_opb flag would need to be passed down to the
buffer calculations here as well to prevent buffer under-allocation.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=15
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 16/18] media: iris: add Gen2 firmware support on the Agatti platform
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (14 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 15/18] media: iris: Introduce buffer size calculations for AR50LT Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 14:25 ` sashiko-bot
2026-07-09 13:42 ` [PATCH v7 17/18] media: venus: skip QCM2290 if Iris driver is enabled Dmitry Baryshkov
2026-07-09 13:42 ` [PATCH v7 18/18] media: iris: constify inst_fw_cap_sm8250_dec Dmitry Baryshkov
17 siblings, 1 reply; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
From: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Agatti platform is using HFI Gen1 firmware, which is considered to be
legacy firmware branch. Follow the example of the SC7280 platform and
extend the driver with supporting both HFI Gen1 and Gen2 firmwares for
this platform. Like HFI Gen1 this firmware doesn't have PIPE property
(but unlike Gen1 buffer sizes are calculated on the driver side).
Signed-off-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_hfi_gen2.c | 613 +++++++++++++++++++++
.../platform/qcom/iris/iris_platform_common.h | 1 +
.../platform/qcom/iris/iris_platform_vpu_ar50lt.c | 7 +
3 files changed, 621 insertions(+)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
index acc0ed8adda1..f89245269e8c 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
@@ -1118,3 +1118,616 @@ const struct iris_firmware_data iris_hfi_gen2_data = {
.enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl,
.enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl),
};
+
+static const struct platform_inst_fw_cap inst_fw_cap_gen2_ar50lt_dec[] = {
+ {
+ .cap_id = PROFILE_H264,
+ .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH),
+ .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+ .hfi_id = HFI_PROP_PROFILE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = PROFILE_HEVC,
+ .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+ .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .hfi_id = HFI_PROP_PROFILE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = PROFILE_VP9,
+ .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ .max = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0),
+ .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ .hfi_id = HFI_PROP_PROFILE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = LEVEL_H264,
+ .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2),
+ .value = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ .hfi_id = HFI_PROP_LEVEL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = LEVEL_HEVC,
+ .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1),
+ .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1,
+ .hfi_id = HFI_PROP_LEVEL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = LEVEL_VP9,
+ .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0,
+ .max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) |
+ BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1),
+ .value = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
+ .hfi_id = HFI_PROP_LEVEL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = TIER,
+ .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
+ .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH),
+ .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
+ .hfi_id = HFI_PROP_TIER,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_u32_enum,
+ },
+ {
+ .cap_id = INPUT_BUF_HOST_MAX_COUNT,
+ .min = DEFAULT_MAX_HOST_BUF_COUNT,
+ .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT,
+ .step_or_mask = 1,
+ .value = DEFAULT_MAX_HOST_BUF_COUNT,
+ .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT,
+ .flags = CAP_FLAG_INPUT_PORT,
+ .set = iris_set_u32,
+ },
+ {
+ .cap_id = STAGE,
+ .min = STAGE_1,
+ .max = STAGE_2,
+ .step_or_mask = 1,
+ .value = STAGE_2,
+ .hfi_id = HFI_PROP_STAGE,
+ .set = iris_set_stage,
+ },
+ {
+ .cap_id = POC,
+ .min = 0,
+ .max = 2,
+ .step_or_mask = 1,
+ .value = 1,
+ .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE,
+ },
+ {
+ .cap_id = CODED_FRAMES,
+ .min = CODED_FRAMES_PROGRESSIVE,
+ .max = CODED_FRAMES_PROGRESSIVE,
+ .step_or_mask = 0,
+ .value = CODED_FRAMES_PROGRESSIVE,
+ .hfi_id = HFI_PROP_CODED_FRAMES,
+ },
+ {
+ .cap_id = BIT_DEPTH,
+ .min = BIT_DEPTH_8,
+ .max = BIT_DEPTH_8,
+ .step_or_mask = 1,
+ .value = BIT_DEPTH_8,
+ .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH,
+ },
+ {
+ .cap_id = RAP_FRAME,
+ .min = 0,
+ .max = 1,
+ .step_or_mask = 1,
+ .value = 1,
+ .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME,
+ .flags = CAP_FLAG_INPUT_PORT,
+ .set = iris_set_u32,
+ },
+};
+
+static const struct platform_inst_fw_cap inst_fw_cap_gen2_ar50lt_enc[] = {
+ {
+ .cap_id = PROFILE_H264,
+ .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH),
+ .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+ .hfi_id = HFI_PROP_PROFILE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_profile,
+ },
+ {
+ .cap_id = PROFILE_HEVC,
+ .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE),
+ .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
+ .hfi_id = HFI_PROP_PROFILE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_profile,
+ },
+ {
+ .cap_id = LEVEL_H264,
+ .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+ BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2),
+ .value = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ .hfi_id = HFI_PROP_LEVEL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_level,
+ },
+ {
+ .cap_id = LEVEL_HEVC,
+ .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) |
+ BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1),
+ .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1,
+ .hfi_id = HFI_PROP_LEVEL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_level,
+ },
+ {
+ .cap_id = STAGE,
+ .min = STAGE_1,
+ .max = STAGE_2,
+ .step_or_mask = 1,
+ .value = STAGE_2,
+ .hfi_id = HFI_PROP_STAGE,
+ .set = iris_set_stage,
+ },
+ {
+ .cap_id = HEADER_MODE,
+ .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+ BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
+ .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ .hfi_id = HFI_PROP_SEQ_HEADER_MODE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_header_mode_gen2,
+ },
+ {
+ .cap_id = PREPEND_SPSPPS_TO_IDR,
+ .min = 0,
+ .max = 1,
+ .step_or_mask = 1,
+ .value = 0,
+ },
+ {
+ .cap_id = BITRATE,
+ .min = 1,
+ .max = BITRATE_MAX_AR50LT,
+ .step_or_mask = 1,
+ .value = BITRATE_DEFAULT_AR50LT,
+ .hfi_id = HFI_PROP_TOTAL_BITRATE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_bitrate_gen2,
+ },
+ {
+ .cap_id = BITRATE_PEAK,
+ .min = 1,
+ .max = BITRATE_MAX_AR50LT,
+ .step_or_mask = 1,
+ .value = BITRATE_DEFAULT_AR50LT,
+ .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_peak_bitrate,
+ },
+ {
+ .cap_id = BITRATE_MODE,
+ .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+ BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR),
+ .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .hfi_id = HFI_PROP_RATE_CONTROL,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_bitrate_mode_gen2,
+ },
+ {
+ .cap_id = FRAME_SKIP_MODE,
+ .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
+ BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) |
+ BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT),
+ .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ },
+ {
+ .cap_id = FRAME_RC_ENABLE,
+ .min = 0,
+ .max = 1,
+ .step_or_mask = 1,
+ .value = 1,
+ },
+ {
+ .cap_id = GOP_SIZE,
+ .min = 0,
+ .max = INT_MAX,
+ .step_or_mask = 1,
+ .value = 2 * DEFAULT_FPS - 1,
+ .hfi_id = HFI_PROP_MAX_GOP_FRAMES,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_u32,
+ },
+ {
+ .cap_id = ENTROPY_MODE,
+ .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+ BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC),
+ .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .hfi_id = HFI_PROP_CABAC_SESSION,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_entropy_mode_gen2,
+ },
+ {
+ .cap_id = MIN_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ .hfi_id = HFI_PROP_MIN_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_min_qp,
+ },
+ {
+ .cap_id = MIN_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ .hfi_id = HFI_PROP_MIN_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_min_qp,
+ },
+ {
+ .cap_id = MAX_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ .hfi_id = HFI_PROP_MAX_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_max_qp,
+ },
+ {
+ .cap_id = MAX_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ .hfi_id = HFI_PROP_MAX_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_max_qp,
+ },
+ {
+ .cap_id = I_FRAME_MIN_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ },
+ {
+ .cap_id = I_FRAME_MIN_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ },
+ {
+ .cap_id = P_FRAME_MIN_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ },
+ {
+ .cap_id = P_FRAME_MIN_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ },
+ {
+ .cap_id = B_FRAME_MIN_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ },
+ {
+ .cap_id = B_FRAME_MIN_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MIN_QP_8BIT_AR50LT,
+ },
+ {
+ .cap_id = I_FRAME_MAX_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ },
+ {
+ .cap_id = I_FRAME_MAX_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ },
+ {
+ .cap_id = P_FRAME_MAX_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ },
+ {
+ .cap_id = P_FRAME_MAX_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ },
+ {
+ .cap_id = B_FRAME_MAX_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ },
+ {
+ .cap_id = B_FRAME_MAX_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = MAX_QP,
+ },
+ {
+ .cap_id = I_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = DEFAULT_QP,
+ .hfi_id = HFI_PROP_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_frame_qp,
+ },
+ {
+ .cap_id = I_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = DEFAULT_QP,
+ .hfi_id = HFI_PROP_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_frame_qp,
+ },
+ {
+ .cap_id = P_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = DEFAULT_QP,
+ .hfi_id = HFI_PROP_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_frame_qp,
+ },
+ {
+ .cap_id = P_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = DEFAULT_QP,
+ .hfi_id = HFI_PROP_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_frame_qp,
+ },
+ {
+ .cap_id = B_FRAME_QP_H264,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = DEFAULT_QP,
+ .hfi_id = HFI_PROP_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_frame_qp,
+ },
+ {
+ .cap_id = B_FRAME_QP_HEVC,
+ .min = MIN_QP_8BIT_AR50LT,
+ .max = MAX_QP,
+ .step_or_mask = 1,
+ .value = DEFAULT_QP,
+ .hfi_id = HFI_PROP_QP_PACKED,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_frame_qp,
+ },
+ {
+ .cap_id = INPUT_BUF_HOST_MAX_COUNT,
+ .min = DEFAULT_MAX_HOST_BUF_COUNT,
+ .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT,
+ .step_or_mask = 1,
+ .value = DEFAULT_MAX_HOST_BUF_COUNT,
+ .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT,
+ .flags = CAP_FLAG_INPUT_PORT,
+ .set = iris_set_u32,
+ },
+ {
+ .cap_id = OUTPUT_BUF_HOST_MAX_COUNT,
+ .min = DEFAULT_MAX_HOST_BUF_COUNT,
+ .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT,
+ .step_or_mask = 1,
+ .value = DEFAULT_MAX_HOST_BUF_COUNT,
+ .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ .set = iris_set_u32,
+ },
+ {
+ .cap_id = IR_TYPE,
+ .min = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
+ .max = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
+ .step_or_mask = BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM),
+ .value = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ },
+ {
+ .cap_id = IR_PERIOD,
+ .min = 0,
+ .max = INT_MAX,
+ .step_or_mask = 1,
+ .value = 0,
+ .flags = CAP_FLAG_OUTPUT_PORT |
+ CAP_FLAG_DYNAMIC_ALLOWED,
+ .set = iris_set_ir_period_gen2,
+ },
+};
+
+static const u32 iris_hfi_gen2_ar50lt_dec_ip_int_buf_tbl[] = {
+ BUF_BIN,
+ BUF_COMV,
+ BUF_NON_COMV,
+ BUF_LINE,
+};
+
+const struct iris_firmware_data iris_hfi_gen2_ar50lt_data = {
+ .init_hfi_ops = iris_hfi_gen2_sys_ops_init,
+
+ .core_arch = VIDEO_ARCH_LX,
+
+ .inst_fw_caps_dec = inst_fw_cap_gen2_ar50lt_dec,
+ .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_gen2_ar50lt_dec),
+ .inst_fw_caps_enc = inst_fw_cap_gen2_ar50lt_enc,
+ .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_gen2_ar50lt_enc),
+ .dec_input_config_params_default =
+ sm8550_vdec_input_config_params_default,
+ .dec_input_config_params_default_size =
+ ARRAY_SIZE(sm8550_vdec_input_config_params_default),
+ .dec_input_config_params_hevc =
+ sm8550_vdec_input_config_param_hevc,
+ .dec_input_config_params_hevc_size =
+ ARRAY_SIZE(sm8550_vdec_input_config_param_hevc),
+ .dec_input_config_params_vp9 =
+ sm8550_vdec_input_config_param_vp9,
+ .dec_input_config_params_vp9_size =
+ ARRAY_SIZE(sm8550_vdec_input_config_param_vp9),
+ .dec_output_config_params =
+ sm8550_vdec_output_config_params,
+ .dec_output_config_params_size =
+ ARRAY_SIZE(sm8550_vdec_output_config_params),
+ .enc_input_config_params =
+ sm8550_venc_input_config_params,
+ .enc_input_config_params_size =
+ ARRAY_SIZE(sm8550_venc_input_config_params),
+ .enc_output_config_params =
+ sm8550_venc_output_config_params,
+ .enc_output_config_params_size =
+ ARRAY_SIZE(sm8550_venc_output_config_params),
+ .dec_input_prop = sm8550_vdec_subscribe_input_properties,
+ .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties),
+ .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc,
+ .dec_output_prop_avc_size =
+ ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc),
+ .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc,
+ .dec_output_prop_hevc_size =
+ ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc),
+ .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9,
+ .dec_output_prop_vp9_size =
+ ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9),
+ .dec_ip_int_buf_tbl = iris_hfi_gen2_ar50lt_dec_ip_int_buf_tbl,
+ .dec_ip_int_buf_tbl_size = ARRAY_SIZE(iris_hfi_gen2_ar50lt_dec_ip_int_buf_tbl),
+ .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl,
+ .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl),
+ .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl,
+ .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl),
+ .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl,
+ .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl),
+};
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index bc04831ae7fc..5afe395cc4a0 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -57,6 +57,7 @@ enum pipe_type {
extern const struct iris_firmware_data iris_hfi_gen1_data;
extern const struct iris_firmware_data iris_hfi_gen1_ar50lt_data;
extern const struct iris_firmware_data iris_hfi_gen2_data;
+extern const struct iris_firmware_data iris_hfi_gen2_ar50lt_data;
extern const struct iris_platform_data qcm2290_data;
extern const struct iris_platform_data qcs8300_data;
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c b/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
index 92f7e2546539..99c839a0424f 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
@@ -19,6 +19,12 @@ static const struct iris_firmware_desc iris_vpu_ar50lt_p1_gen1_s6_desc = {
.fwname = "qcom/venus-6.0/venus.mbn",
};
+static const struct iris_firmware_desc iris_vpu_ar50lt_p1_gen2_s6_desc = {
+ .firmware_data = &iris_hfi_gen2_ar50lt_data,
+ .get_vpu_buffer_size = iris_vpu_ar50lt_gen2_buf_size,
+ .fwname = "qcom/vpu/ar50lt_p1_gen2_s6.mbn",
+};
+
static const u32 iris_fmts_ar50lt_dec[] = {
V4L2_PIX_FMT_H264,
V4L2_PIX_FMT_HEVC,
@@ -79,6 +85,7 @@ static struct platform_inst_caps platform_inst_cap_ar50lt = {
const struct iris_platform_data qcm2290_data = {
.firmware_desc_gen1 = &iris_vpu_ar50lt_p1_gen1_s6_desc,
+ .firmware_desc_gen2 = &iris_vpu_ar50lt_p1_gen2_s6_desc,
.vpu_ops = &iris_vpu_ar50lt_ops,
.icc_tbl = iris_icc_info_ar50lt,
.icc_tbl_size = ARRAY_SIZE(iris_icc_info_ar50lt),
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH v7 16/18] media: iris: add Gen2 firmware support on the Agatti platform
2026-07-09 13:42 ` [PATCH v7 16/18] media: iris: add Gen2 firmware support on the Agatti platform Dmitry Baryshkov
@ 2026-07-09 14:25 ` sashiko-bot
0 siblings, 0 replies; 30+ messages in thread
From: sashiko-bot @ 2026-07-09 14:25 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect maximum QP limit for HEVC encoding in the Gen2 firmware capabilities for the Agatti platform.
--
--- Patch [16]: [PATCH v7 16/18] media: iris: add Gen2 firmware support on the Agatti platform ---
commit c95f463971a4ef87470f272f24b4d448ca8c4ba8
Author: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
media: iris: add Gen2 firmware support on the Agatti platform
This commit extends the Agatti platform support in the iris driver to
include HFI Gen2 firmware capabilities. It defines the capability
structures, configuration parameters, and initialization data for Gen2
encoding and decoding on the AR50LT VPU.
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
> @@ -1118,3 +1118,616 @@ const struct iris_firmware_data iris_hfi_gen2_data = {
[ ... ]
> +static const struct platform_inst_fw_cap inst_fw_cap_gen2_ar50lt_enc[] = {
[ ... ]
> + {
> + .cap_id = MAX_FRAME_QP_HEVC,
> + .min = MIN_QP_8BIT_AR50LT,
> + .max = MAX_QP,
> + .step_or_mask = 1,
> + .value = MAX_QP,
> + .hfi_id = HFI_PROP_MAX_QP_PACKED,
> + .flags = CAP_FLAG_OUTPUT_PORT,
> + .set = iris_set_max_qp,
> + },
[Severity: Medium]
Should the maximum bound for MAX_FRAME_QP_HEVC be set to MAX_QP_HEVC (63)
instead of MAX_QP (51)? This limits userspace from setting HEVC QPs between
52 and 63, which are valid values for HEVC encoding.
[ ... ]
> + {
> + .cap_id = I_FRAME_MAX_QP_HEVC,
> + .min = MIN_QP_8BIT_AR50LT,
> + .max = MAX_QP,
> + .step_or_mask = 1,
> + .value = MAX_QP,
> + },
[Severity: Medium]
Does this also incorrectly limit the I-frame maximum QP to 51 instead of 63?
This same MAX_QP limit appears to be applied to P_FRAME_MAX_QP_HEVC and
B_FRAME_MAX_QP_HEVC in the array below.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260709-iris-ar50lt-v7-0-76af9dd4d1f6@oss.qualcomm.com?part=16
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v7 17/18] media: venus: skip QCM2290 if Iris driver is enabled
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (15 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 16/18] media: iris: add Gen2 firmware support on the Agatti platform Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
2026-07-09 13:42 ` [PATCH v7 18/18] media: iris: constify inst_fw_cap_sm8250_dec Dmitry Baryshkov
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
As the Iris driver now supports the QCM2290 hardware too, there is a
race between Venus and Iris drivers on binding to the corresponding
device. Follow the approach used by other platforms and skip QCM2290 in
the Venus driver if Iris is enabled.
Reviewed-by: Dikshita Agarwal <dikshita.agarwal@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/venus/core.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 243e342b0ae7..3c88594eb1d0 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -1118,7 +1118,6 @@ static const struct venus_resources sc7280_res = {
.dec_nodename = "video-decoder",
.enc_nodename = "video-encoder",
};
-#endif
static const struct bw_tbl qcm2290_bw_table_dec[] = {
{ 352800, 597000, 0, 746000, 0 }, /* 1080p@30 + 720p@30 */
@@ -1169,13 +1168,16 @@ static const struct venus_resources qcm2290_res = {
.enc_nodename = "video-encoder",
.min_fw = &min_fw,
};
+#endif
static const struct of_device_id venus_dt_match[] = {
{ .compatible = "qcom,msm8916-venus", .data = &msm8916_res, },
{ .compatible = "qcom,msm8939-venus", .data = &msm8939_res, },
{ .compatible = "qcom,msm8996-venus", .data = &msm8996_res, },
{ .compatible = "qcom,msm8998-venus", .data = &msm8998_res, },
+#if (!IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS))
{ .compatible = "qcom,qcm2290-venus", .data = &qcm2290_res, },
+#endif
{ .compatible = "qcom,sc7180-venus", .data = &sc7180_res, },
{ .compatible = "qcom,sdm660-venus", .data = &sdm660_res, },
{ .compatible = "qcom,sdm845-venus", .data = &sdm845_res, },
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH v7 18/18] media: iris: constify inst_fw_cap_sm8250_dec
2026-07-09 13:41 [PATCH v7 00/18] media: iris: Add AR50LT core support and enable Agatti platform Dmitry Baryshkov
` (16 preceding siblings ...)
2026-07-09 13:42 ` [PATCH v7 17/18] media: venus: skip QCM2290 if Iris driver is enabled Dmitry Baryshkov
@ 2026-07-09 13:42 ` Dmitry Baryshkov
17 siblings, 0 replies; 30+ messages in thread
From: Dmitry Baryshkov @ 2026-07-09 13:42 UTC (permalink / raw)
To: Vikash Garodia, Abhinav Kumar, Bryan O'Donoghue,
Mauro Carvalho Chehab, Bjorn Andersson, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Vishnu Reddy
Cc: linux-media, linux-arm-msm, linux-kernel, devicetree,
Dikshita Agarwal
Mark inst_fw_cap_sm8250_dec as a const array, the data is read-only.
Suggested-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
Reviewed-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/iris_hfi_gen1.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
index 60bc1339ddd4..4f205757647a 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c
@@ -13,7 +13,7 @@
#define BITRATE_MAX 160000000
#define BITRATE_STEP 100
-static struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = {
+static const struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = {
{
.cap_id = PIPE,
/* .max, .min and .value are set via platform data */
--
2.47.3
^ permalink raw reply related [flat|nested] 30+ messages in thread