On Sat Aug 1 12:14:50 2026 +0530, 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.
> 
> Reviewed-by: Vikash Garodia <[email protected]>
> Signed-off-by: Sachin Kumar Garg <[email protected]>
> Signed-off-by: Bryan O'Donoghue <[email protected]>

Patch committed.

Thanks,
Bryan O'Donoghue

 drivers/media/platform/qcom/iris/iris_ctrls.c      | 86 ++++++++++++++++++++++
 drivers/media/platform/qcom/iris/iris_ctrls.h      |  1 +
 drivers/media/platform/qcom/iris/iris_hfi_gen2.c   | 86 ++++++++++++++++++++++
 .../platform/qcom/iris/iris_hfi_gen2_defines.h     |  2 +
 .../platform/qcom/iris/iris_platform_common.h      | 18 +++++
 .../media/platform/qcom/iris/iris_platform_vpu2.c  |  1 +
 .../media/platform/qcom/iris/iris_platform_vpu3x.c |  5 ++
 .../platform/qcom/iris/iris_platform_vpu_ar50lt.c  |  1 +
 8 files changed, 200 insertions(+)

---

diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c 
b/drivers/media/platform/qcom/iris/iris_ctrls.c
index 98d4ec122da9..8c4c47944f22 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.c
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.c
@@ -156,6 +156,12 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 
id)
                return LAYER5_BITRATE_HEVC;
        case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
                return REQUEST_SYNC_FRAME;
+       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;
        }
@@ -301,6 +307,12 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type 
cap_id)
                return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR;
        case REQUEST_SYNC_FRAME:
                return V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME;
+       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;
        }
@@ -1526,6 +1538,80 @@ int iris_set_time_delta_based_rc(struct iris_inst *inst, 
enum platform_inst_fw_c
                                             &value, sizeof(u32));
 }
 
+int iris_set_slice_count(struct iris_inst *inst, enum 
platform_inst_fw_cap_type cap_id)
+{
+       const struct platform_inst_slice_caps *slice_caps =
+               inst->core->iris_platform_data->slice_caps;
+       const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops;
+       u32 output_height = inst->fmt_dst->fmt.pix_mp.height;
+       u32 output_width = inst->fmt_dst->fmt.pix_mp.width;
+       u32 mbpf = NUM_MBS_PER_FRAME(output_height, output_width);
+       u32 max_width, max_height, min_width, min_height;
+       u32 slice_mode = inst->fw_caps[cap_id].value;
+       u32 max_avg_slicesize, hfi_value, hfi_id;
+       u32 rc_type = inst->hfi_rc_type;
+       u32 fps = inst->frame_rate;
+
+       if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) {
+               dev_dbg(inst->core->dev, "slice mode is single slice, ignore 
setting to fw\n");
+               return 0;
+       }
+       if (fps > slice_caps->max_slice_frame_rate ||
+           (rc_type != HFI_RC_OFF && rc_type != HFI_RC_CBR_CFR &&
+           rc_type != HFI_RC_CBR_VFR)) {
+               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) ?
+                       slice_caps->max_mb_slice_width : 
slice_caps->max_bytes_slice_width;
+       max_height = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ?
+                       slice_caps->max_mb_slice_height : 
slice_caps->max_bytes_slice_height;
+       min_width = (inst->codec == V4L2_PIX_FMT_HEVC) ?
+                       slice_caps->min_hevc_slice_width : 
slice_caps->min_avc_slice_width;
+       min_height = slice_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, 
slice_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((inst->fw_caps[BITRATE].value / fps) / 8,
+                                                        
slice_caps->max_slices_per_frame);
+               } else {
+                       /*
+                        * No bitrate target exists under RC_OFF, so 
approximate a
+                        * worst-case frame size the same way 
size_bin_bitstream_enc()
+                        * does for buffer allocation, to keep the slice count 
bounded.
+                        */
+                       max_avg_slicesize = DIV_ROUND_UP(output_width * 
output_height * 3,
+                                                        
slice_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 5180d53d3c90..08db80744420 100644
--- a/drivers/media/platform/qcom/iris/iris_ctrls.h
+++ b/drivers/media/platform/qcom/iris/iris_ctrls.h
@@ -49,6 +49,7 @@ int iris_set_layer_count_gen2(struct iris_inst *inst, enum 
platform_inst_fw_cap_
 int iris_set_layer_bitrate(struct iris_inst *inst, enum 
platform_inst_fw_cap_type cap_id);
 int iris_set_req_sync_frame(struct iris_inst *inst, enum 
platform_inst_fw_cap_type cap_id);
 int iris_set_time_delta_based_rc(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 3e752f69e414..79bbd06ef8d2 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c
@@ -13,6 +13,10 @@
 #define VIDEO_ARCH_LX 1
 #define MILOS_BITRATE_MAX                      100000000
 #define BITRATE_MAX                            245000000
+#define MAX_SLICE_MB_SIZE         \
+       (((4096 + 15) >> 4) * ((2160 + 15) >> 4))
+#define MAX_SLICE_MB_SIZE_AR50LT         \
+       (((1920 + 15) >> 4) * ((1088 + 15) >> 4))
 
 static const struct platform_inst_fw_cap inst_fw_cap_milos_dec[] = {
        {
@@ -1782,6 +1786,35 @@ static const struct platform_inst_fw_cap 
inst_fw_cap_sm8550_enc[] = {
                .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED,
                .set = iris_set_req_sync_frame,
        },
+       {
+               .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[] = {
@@ -2814,6 +2847,35 @@ static const struct platform_inst_fw_cap 
inst_fw_cap_gen2_ar50lt_enc[] = {
                .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED,
                .set = iris_set_req_sync_frame,
        },
+       {
+               .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_AR50LT >> 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_AR50LT,
+               .step_or_mask = 1,
+               .value = 1,
+               .hfi_id = HFI_PROP_MULTI_SLICE_MB_COUNT,
+               .flags = CAP_FLAG_OUTPUT_PORT,
+       },
 };
 
 static const u32 iris_hfi_gen2_ar50lt_dec_ip_int_buf_tbl[] = {
@@ -2880,3 +2942,27 @@ const struct iris_firmware_data 
iris_hfi_gen2_ar50lt_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),
 };
+
+const struct platform_inst_slice_caps iris_vpu2_vpu3x_slice_caps = {
+       .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,
+};
+
+const struct platform_inst_slice_caps iris_ar50lt_slice_caps = {
+       .max_slices_per_frame = 128,
+       .max_slice_frame_rate = 60,
+       .max_mb_slice_width = 1920,
+       .max_mb_slice_height = 1088,
+       .max_bytes_slice_width = 1920,
+       .max_bytes_slice_height = 1088,
+       .min_hevc_slice_width = 384,
+       .min_avc_slice_width = 192,
+       .min_slice_height = 128,
+};
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 f43aea10090d..2b8b057d35a9 100644
--- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
+++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
@@ -72,6 +72,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 5593820bbf8a..cddab9a9c375 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_common.h
+++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
@@ -59,6 +59,8 @@ 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_milos_data;
 extern const struct iris_firmware_data iris_hfi_gen2_ar50lt_data;
+extern const struct platform_inst_slice_caps iris_vpu2_vpu3x_slice_caps;
+extern const struct platform_inst_slice_caps iris_ar50lt_slice_caps;
 
 extern const struct iris_platform_data milos_data;
 extern const struct iris_platform_data qcm2290_data;
@@ -98,6 +100,18 @@ struct tz_cp_config {
        u32 cp_nonpixel_size;
 };
 
+struct platform_inst_slice_caps {
+       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;
+};
+
 struct platform_inst_caps {
        u32 min_frame_width;
        u32 max_frame_width;
@@ -194,6 +208,9 @@ enum platform_inst_fw_cap_type {
        LAYER5_BITRATE_HEVC,
        REQUEST_SYNC_FRAME,
        TIME_DELTA_BASED_RC,
+       SLICE_MODE,
+       SLICE_MAX_BYTES,
+       SLICE_MAX_MB,
        INST_FW_CAP_MAX,
 };
 
@@ -325,6 +342,7 @@ struct iris_platform_data {
        const u32 *inst_iris_fmts;
        u32 inst_iris_fmts_size;
        struct platform_inst_caps *inst_caps;
+       const struct platform_inst_slice_caps *slice_caps;
        const struct tz_cp_config *tz_cp_config_data;
        u32 tz_cp_config_data_size;
        u32 num_vpp_pipe;
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c 
b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
index e594c7a25db3..becbe3776544 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c
@@ -127,6 +127,7 @@ const struct iris_platform_data sc7280_data = {
        .inst_iris_fmts = iris_fmts_vpu2_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu2_dec),
        .inst_caps = &platform_inst_cap_vpu2,
+       .slice_caps = &iris_vpu2_vpu3x_slice_caps,
        .tz_cp_config_data = tz_cp_config_vpu2,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu2),
        .num_vpp_pipe = 1,
diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c 
b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
index b8099d7ce556..e963cb116313 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c
@@ -112,6 +112,7 @@ const struct iris_platform_data qcs8300_data = {
        .inst_iris_fmts = iris_fmts_vpu3x_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu3x_dec),
        .inst_caps = &platform_inst_cap_qcs8300,
+       .slice_caps = &iris_vpu2_vpu3x_slice_caps,
        .tz_cp_config_data = tz_cp_config_vpu3,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
        .num_vpp_pipe = 2,
@@ -143,6 +144,7 @@ const struct iris_platform_data sm8550_data = {
        .inst_iris_fmts = iris_fmts_vpu3x_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu3x_dec),
        .inst_caps = &platform_inst_cap_sm8550,
+       .slice_caps = &iris_vpu2_vpu3x_slice_caps,
        .tz_cp_config_data = tz_cp_config_vpu3,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
        .num_vpp_pipe = 4,
@@ -182,6 +184,7 @@ const struct iris_platform_data sm8650_data = {
        .inst_iris_fmts = iris_fmts_vpu3x_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu3x_dec),
        .inst_caps = &platform_inst_cap_sm8550,
+       .slice_caps = &iris_vpu2_vpu3x_slice_caps,
        .tz_cp_config_data = tz_cp_config_vpu3,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
        .num_vpp_pipe = 4,
@@ -213,6 +216,7 @@ const struct iris_platform_data sm8750_data = {
        .inst_iris_fmts = iris_fmts_vpu3x_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu3x_dec),
        .inst_caps = &platform_inst_cap_sm8550,
+       .slice_caps = &iris_vpu2_vpu3x_slice_caps,
        .tz_cp_config_data = tz_cp_config_vpu3,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
        .num_vpp_pipe = 4,
@@ -250,6 +254,7 @@ const struct iris_platform_data x1p42100_data = {
        .inst_iris_fmts = iris_fmts_vpu3x_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu3x_dec),
        .inst_caps = &platform_inst_cap_sm8550,
+       .slice_caps = &iris_vpu2_vpu3x_slice_caps,
        .tz_cp_config_data = tz_cp_config_vpu3,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu3),
        .num_vpp_pipe = 1,
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 99c839a0424f..43460b82ae77 100644
--- a/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
+++ b/drivers/media/platform/qcom/iris/iris_platform_vpu_ar50lt.c
@@ -103,6 +103,7 @@ const struct iris_platform_data qcm2290_data = {
        .inst_iris_fmts = iris_fmts_ar50lt_dec,
        .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_ar50lt_dec),
        .inst_caps = &platform_inst_cap_ar50lt,
+       .slice_caps = &iris_ar50lt_slice_caps,
        .tz_cp_config_data = tz_cp_config_ar50lt,
        .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_ar50lt),
        .num_vpp_pipe = 1,
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to