Re: [PATCH v3 2/2] media: iris: add support for multi_slice in iris encoder
From: Sachin Kumar Garg
Date: Thu Jul 23 2026 - 06:37:53 EST
On 7/22/2026 11:31 AM, Vikash Garodia wrote:
On 7/21/2026 3:23 PM, Sachin Kumar Garg wrote:
Add multi-slice encoding support with MAX_MB and MAX_BYTES modes.
Clients can enable slice mode using V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE
control and configure slice size via V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB
or V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES controls.
Signed-off-by: Sachin Kumar Garg <sachin.garg@xxxxxxxxxxxxxxxx>
---
drivers/media/platform/qcom/iris/iris_ctrls.c | 82 ++++++++++++ ++++++++++
drivers/media/platform/qcom/iris/iris_ctrls.h | 1 +
drivers/media/platform/qcom/iris/iris_hfi_gen2.c | 33 ++++++++-
.../platform/qcom/iris/iris_hfi_gen2_defines.h | 2 +
.../platform/qcom/iris/iris_platform_common.h | 12 ++++
.../platform/qcom/iris/iris_platform_qcs8300.h | 9 +++
.../platform/qcom/iris/iris_platform_sm8550.h | 9 +++
.../media/platform/qcom/iris/iris_platform_vpu2.c | 9 +++
8 files changed, 156 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/ media/platform/qcom/iris/iris_ctrls.c
index d7cbf6c3614a..36ccb9918921 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.c
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.c
@@ -154,6 +154,12 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id)
return LAYER4_BITRATE_HEVC;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR:
return LAYER5_BITRATE_HEVC;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ return SLICE_MODE;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ return SLICE_MAX_BYTES;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ return SLICE_MAX_MB;
default:
return INST_FW_CAP_MAX;
}
@@ -297,6 +303,12 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id)
return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR;
case LAYER5_BITRATE_HEVC:
return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR;
+ case SLICE_MODE:
+ return V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE;
+ case SLICE_MAX_BYTES:
+ return V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+ case SLICE_MAX_MB:
+ return V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
default:
return 0;
}
@@ -1482,6 +1494,76 @@ int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_typ
&bitrate, sizeof(u32));
}
+int iris_set_slice_count(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
+{
+ const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops;
+ struct platform_inst_caps *caps = inst->core->iris_platform_data- >inst_caps;
+ u32 slice_mode = inst->fw_caps[SLICE_MODE].value;
+ u32 bitrate = inst->fw_caps[BITRATE].value;
+ u32 rc_type = inst->hfi_rc_type;
+ u32 fps = inst->frame_rate;
+ u32 output_width = inst->fmt_dst->fmt.pix_mp.width;
+ u32 output_height = inst->fmt_dst->fmt.pix_mp.height;
+ u32 mbpf = NUM_MBS_PER_FRAME(output_height, output_width);
+ u32 max_width, max_height, min_width, min_height;
+ u32 max_avg_slicesize, hfi_value, hfi_id;
+
+ if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) {
+ dev_dbg(inst->core->dev, "slice mode is: %u, ignore setting to fw\n", slice_mode);
+ return 0;
+ }
+ if (!fps) {
+ dev_err(inst->core->dev, "Invalid frame rate %d\n", fps);
+ return -EINVAL;
+ }
+ if (fps > caps->max_slice_frame_rate ||
+ (rc_type != HFI_RC_OFF && rc_type != HFI_RC_CBR_CFR &&
+ rc_type != HFI_RC_CBR_VFR && rc_type != HFI_RC_VBR_CFR)) {
+ dev_err(inst->core->dev, "slice unsupported, fps: %u, rc_type: %#x\n",
+ fps, rc_type);
+ return -EINVAL;
+ }
+
+ max_width = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+ caps->max_mb_slice_width : caps->max_bytes_slice_width;
+ max_height = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+ caps->max_mb_slice_height : caps->max_bytes_slice_height;
+ min_width = (inst->codec == V4L2_PIX_FMT_HEVC) ?
+ caps->min_hevc_slice_width : caps->min_avc_slice_width;
+ min_height = caps->min_slice_height;
+
+ if (output_width < min_width || output_height < min_height ||
+ output_width > max_width || output_height > max_height) {
+ dev_err(inst->core->dev, "slice unsupported, codec: %#x wxh: [%dx%d]\n",
+ inst->codec, output_width, output_height);
+ return -EINVAL;
+ }
+
+ if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) {
+ hfi_value = inst->fw_caps[SLICE_MAX_MB].value;
+ hfi_value = max(hfi_value, DIV_ROUND_UP(mbpf, caps- >max_slices_per_frame));
+ if (inst->codec == V4L2_PIX_FMT_HEVC)
+ hfi_value = (hfi_value + 3) / 4;
+ hfi_id = inst->fw_caps[SLICE_MAX_MB].hfi_id;
+ } else if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) {
+ hfi_value = inst->fw_caps[SLICE_MAX_BYTES].value;
+ if (rc_type != HFI_RC_OFF) {
+ max_avg_slicesize = DIV_ROUND_UP((bitrate / fps) / 8,
+ caps->max_slices_per_frame);
+ hfi_value = max(hfi_value, max_avg_slicesize);
+ }
+ hfi_id = inst->fw_caps[SLICE_MAX_BYTES].hfi_id;
+ } else {
+ return -EINVAL;
+ }
+
+ return hfi_ops->session_set_property(inst, hfi_id,
+ HFI_HOST_FLAGS_NONE,
+ iris_get_port_info(inst, cap_id),
+ HFI_PAYLOAD_U32,
+ &hfi_value, sizeof(u32));
+}
+
int iris_set_properties(struct iris_inst *inst, u32 plane)
{
const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops;
diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/ media/platform/qcom/iris/iris_ctrls.h
index 3c462ec9190b..5a73c7c49d36 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.h
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.h
@@ -47,6 +47,7 @@ int iris_set_layer_type(struct iris_inst *inst, enum platform_inst_fw_cap_type c
int iris_set_layer_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
int iris_set_layer_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
+int iris_set_slice_count(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id);
int iris_set_properties(struct iris_inst *inst, u32 plane);
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c b/ drivers/media/platform/qcom/iris/iris_hfi_gen2.c
index acc0ed8adda1..fcbebced05c3 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
@@ -12,6 +12,8 @@
#define VIDEO_ARCH_LX 1
#define BITRATE_MAX 245000000
+#define MAX_SLICE_MB_SIZE \
+ (((4096 + 15) >> 4) * ((2160 + 15) >> 4))
static const struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = {
{
@@ -937,7 +939,36 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = {
.flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT |
CAP_FLAG_DYNAMIC_ALLOWED,
.set = iris_set_layer_bitrate,
- }
+ },
+ {
+ .cap_id = SLICE_MODE,
+ .min = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .max = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
+ .step_or_mask = BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+ BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) |
+ BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES),
+ .value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU,
+ .set = iris_set_slice_count,
+ },
+ {
+ .cap_id = SLICE_MAX_BYTES,
+ .min = 512,
+ .max = BITRATE_MAX >> 3,
+ .step_or_mask = 1,
+ .value = 512,
+ .hfi_id = HFI_PROP_MULTI_SLICE_BYTES_COUNT,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ },
+ {
+ .cap_id = SLICE_MAX_MB,
+ .min = 1,
+ .max = MAX_SLICE_MB_SIZE,
+ .step_or_mask = 1,
+ .value = 1,
+ .hfi_id = HFI_PROP_MULTI_SLICE_MB_COUNT,
+ .flags = CAP_FLAG_OUTPUT_PORT,
+ },
};
static const u32 sm8550_vdec_input_config_params_default[] = {
diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
index 776b21cd11b2..226894b99dcc 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
@@ -71,6 +71,8 @@ enum hfi_rate_control {
#define HFI_PROP_MIN_QP_PACKED 0x0300012f
#define HFI_PROP_MAX_QP_PACKED 0x03000130
#define HFI_PROP_IR_RANDOM_PERIOD 0x03000131
+#define HFI_PROP_MULTI_SLICE_MB_COUNT 0x03000132
+#define HFI_PROP_MULTI_SLICE_BYTES_COUNT 0x03000133
#define HFI_PROP_LTR_COUNT 0x03000134
#define HFI_PROP_LTR_MARK 0x03000135
#define HFI_PROP_LTR_USE 0x03000136
diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
index c9256f2323dc..659d15166365 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -100,6 +100,15 @@ struct platform_inst_caps {
u32 mb_cycles_fw_vpp;
u32 max_frame_rate;
u32 max_operating_rate;
+ u32 max_slices_per_frame;
+ u32 max_slice_frame_rate;
+ u32 max_mb_slice_width;
+ u32 max_mb_slice_height;
+ u32 max_bytes_slice_width;
+ u32 max_bytes_slice_height;
+ u32 min_hevc_slice_width;
+ u32 min_avc_slice_width;
+ u32 min_slice_height;
};
enum platform_inst_fw_cap_type {
@@ -183,6 +192,9 @@ enum platform_inst_fw_cap_type {
LAYER3_BITRATE_HEVC,
LAYER4_BITRATE_HEVC,
LAYER5_BITRATE_HEVC,
+ SLICE_MODE,
+ SLICE_MAX_BYTES,
+ SLICE_MAX_MB,
INST_FW_CAP_MAX,
};
diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h
index 3cfecae80d1e..764acf71c72b 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h
@@ -17,6 +17,15 @@ static struct platform_inst_caps platform_inst_cap_qcs8300 = {
.mb_cycles_fw_vpp = 44156,
.max_frame_rate = MAXIMUM_FPS,
.max_operating_rate = MAXIMUM_FPS,
+ .max_slices_per_frame = 128,
+ .max_slice_frame_rate = 60,
+ .max_mb_slice_width = 4096,
+ .max_mb_slice_height = 2160,
+ .max_bytes_slice_width = 1920,
+ .max_bytes_slice_height = 1088,
+ .min_hevc_slice_width = 384,
+ .min_avc_slice_width = 192,
+ .min_slice_height = 128,
};
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.h b/drivers/media/platform/qcom/iris/iris_platform_sm8550.h
index 3c9dae995bb2..ef87976c2360 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.h
@@ -25,6 +25,15 @@ static struct platform_inst_caps platform_inst_cap_sm8550 = {
.mb_cycles_fw_vpp = 66234,
.max_frame_rate = MAXIMUM_FPS,
.max_operating_rate = MAXIMUM_FPS,
+ .max_slices_per_frame = 128,
+ .max_slice_frame_rate = 60,
+ .max_mb_slice_width = 4096,
+ .max_mb_slice_height = 2160,
+ .max_bytes_slice_width = 1920,
+ .max_bytes_slice_height = 1088,
+ .min_hevc_slice_width = 384,
+ .min_avc_slice_width = 192,
+ .min_slice_height = 128,
};
#endif
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/ drivers/media/platform/qcom/iris/iris_platform_vpu2.c
index 6e06a32822bb..39720e7af889 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
@@ -44,6 +44,15 @@ static struct platform_inst_caps platform_inst_cap_vpu2 = {
.mb_cycles_vpp = 200,
.max_frame_rate = MAXIMUM_FPS,
.max_operating_rate = MAXIMUM_FPS,
+ .max_slices_per_frame = 128,
+ .max_slice_frame_rate = 60,
+ .max_mb_slice_width = 4096,
+ .max_mb_slice_height = 2160,
+ .max_bytes_slice_width = 1920,
+ .max_bytes_slice_height = 1088,
+ .min_hevc_slice_width = 384,
+ .min_avc_slice_width = 192,
+ .min_slice_height = 128,
I do not see these values are changing for different SOC data here. Would prefer to do the macro instead of inflating the platform struct.
Regards,
Vikash
Thanks for the review, Vikash.
Agreed these were duplicated. In v[4], I've introduced struct platform_inst_slice_caps and moved it to iris_platform_data (one level above platform_inst_caps), since all Gen2 targets share the same encoder capability table and slice limits. A single default_slice_caps_vpu3x instance is now referenced via .slice_caps from all Gen2 targets, instead of being duplicated per-target.
Used a shared struct pointer rather than a macro so a future chipset with different limits can point at its own instance without touching the others.
};
static const struct icc_info iris_icc_info_vpu2[] = {