]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: iris: Add support for G/S_PARM for encoder video device
authorDikshita Agarwal <quic_dikshita@quicinc.com>
Wed, 3 Sep 2025 10:05:40 +0000 (15:35 +0530)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Wed, 10 Sep 2025 07:02:38 +0000 (09:02 +0200)
Add supports for the G/S_PARM V4L2 ioctls for encoder video device with
necessary hooks. This allows userspace to query the current streaming
parameters such as frame intervals and set desired streaming parameters
primarily the frame rate.

Tested-by: Vikash Garodia <quic_vgarodia@quicinc.com> # X1E80100
Reviewed-by: Vikash Garodia <quic_vgarodia@quicinc.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-HDK
Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # x1e80100-crd
Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/platform/qcom/iris/iris_instance.h
drivers/media/platform/qcom/iris/iris_platform_common.h
drivers/media/platform/qcom/iris/iris_platform_gen2.c
drivers/media/platform/qcom/iris/iris_platform_qcs8300.h
drivers/media/platform/qcom/iris/iris_platform_sm8250.c
drivers/media/platform/qcom/iris/iris_utils.c
drivers/media/platform/qcom/iris/iris_utils.h
drivers/media/platform/qcom/iris/iris_vb2.c
drivers/media/platform/qcom/iris/iris_venc.c
drivers/media/platform/qcom/iris/iris_venc.h
drivers/media/platform/qcom/iris/iris_vidc.c

index 55cf9702111829ef24189986ba5245c7684bfe11..b75549718df3c87cd85aecfc74c873c60cd4bde5 100644 (file)
@@ -61,6 +61,9 @@ struct iris_fmt {
  * @metadata_idx: index for metadata buffer
  * @codec: codec type
  * @last_buffer_dequeued: a flag to indicate that last buffer is sent by driver
+ * @frame_rate: frame rate of current instance
+ * @operating_rate: operating rate of current instance
+
  */
 
 struct iris_inst {
@@ -96,6 +99,8 @@ struct iris_inst {
        u32                             metadata_idx;
        u32                             codec;
        bool                            last_buffer_dequeued;
+       u32                             frame_rate;
+       u32                             operating_rate;
 };
 
 #endif
index b555542c870f372f72609e7fda3f368d08ac7500..064ce659bc72d353c0d755a7d12b1d1e26d7bc66 100644 (file)
@@ -83,6 +83,8 @@ struct platform_inst_caps {
        u32 mb_cycles_fw;
        u32 mb_cycles_fw_vpp;
        u32 num_comv;
+       u32 max_frame_rate;
+       u32 max_operating_rate;
 };
 
 enum platform_inst_fw_cap_type {
index 39c46c8b972f7bc87d9a9e3db8833df3efb8fcea..f575ce139e16e78f5c677161e5839773194d1316 100644 (file)
@@ -211,6 +211,8 @@ static struct platform_inst_caps platform_inst_cap_sm8550 = {
        .mb_cycles_fw = 489583,
        .mb_cycles_fw_vpp = 66234,
        .num_comv = 0,
+       .max_frame_rate = MAXIMUM_FPS,
+       .max_operating_rate = MAXIMUM_FPS,
 };
 
 static void iris_set_sm8550_preset_registers(struct iris_core *core)
index a8d66ed388a34e6bb45d4a089d981bb7d135fb50..64331b705fca541e0547afc01ec108759529c9d8 100644 (file)
@@ -197,4 +197,6 @@ static struct platform_inst_caps platform_inst_cap_qcs8300 = {
        .mb_cycles_fw = 326389,
        .mb_cycles_fw_vpp = 44156,
        .num_comv = 0,
+       .max_frame_rate = MAXIMUM_FPS,
+       .max_operating_rate = MAXIMUM_FPS,
 };
index 2a3cbe1f2d4b27d3cce9e9cdad1525801d71a041..4ff72109c6001cc47d746d366f458c0ff0a8924a 100644 (file)
@@ -40,6 +40,8 @@ static struct platform_inst_caps platform_inst_cap_sm8250 = {
        .max_mbpf = 138240,
        .mb_cycles_vsp = 25,
        .mb_cycles_vpp = 200,
+       .max_frame_rate = MAXIMUM_FPS,
+       .max_operating_rate = MAXIMUM_FPS,
 };
 
 static void iris_set_sm8250_preset_registers(struct iris_core *core)
index 83c70d6a2d9092615dcf1b7d0fc85110f0df1aa0..85c70a62b1fd2c409fc18b28f64771cb0097a7fd 100644 (file)
@@ -88,3 +88,39 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id)
        mutex_unlock(&core->lock);
        return NULL;
 }
+
+int iris_check_core_mbpf(struct iris_inst *inst)
+{
+       struct iris_core *core = inst->core;
+       struct iris_inst *instance;
+       u32 total_mbpf = 0;
+
+       mutex_lock(&core->lock);
+       list_for_each_entry(instance, &core->instances, list)
+               total_mbpf += iris_get_mbpf(instance);
+       mutex_unlock(&core->lock);
+
+       if (total_mbpf > core->iris_platform_data->max_core_mbpf)
+               return -ENOMEM;
+
+       return 0;
+}
+
+int iris_check_core_mbps(struct iris_inst *inst)
+{
+       struct iris_core *core = inst->core;
+       struct iris_inst *instance;
+       u32 total_mbps = 0, fps = 0;
+
+       mutex_lock(&core->lock);
+       list_for_each_entry(instance, &core->instances, list) {
+               fps = max(instance->frame_rate, instance->operating_rate);
+               total_mbps += iris_get_mbpf(instance) * fps;
+       }
+       mutex_unlock(&core->lock);
+
+       if (total_mbps > core->iris_platform_data->max_core_mbps)
+               return -ENOMEM;
+
+       return 0;
+}
index 49869cf7a376880a026f44ff3883a6b13c6fcfbb..75740181122f5bdf93d64d3f43b3a26a9fe97919 100644 (file)
@@ -49,5 +49,7 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id);
 void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type,
                              enum vb2_buffer_state state);
 int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush);
+int iris_check_core_mbpf(struct iris_inst *inst);
+int iris_check_core_mbps(struct iris_inst *inst);
 
 #endif
index e62ed7a57df2debf0a930ad8307e6d945f589922..e32f7e1f007228a3b2b51cd76cd193d852f16080 100644 (file)
 #include "iris_vdec.h"
 #include "iris_power.h"
 
-static int iris_check_core_mbpf(struct iris_inst *inst)
-{
-       struct iris_core *core = inst->core;
-       struct iris_inst *instance;
-       u32 total_mbpf = 0;
-
-       mutex_lock(&core->lock);
-       list_for_each_entry(instance, &core->instances, list)
-               total_mbpf += iris_get_mbpf(instance);
-       mutex_unlock(&core->lock);
-
-       if (total_mbpf > core->iris_platform_data->max_core_mbpf)
-               return -ENOMEM;
-
-       return 0;
-}
-
 static int iris_check_inst_mbpf(struct iris_inst *inst)
 {
        struct platform_inst_caps *caps;
index 71960a0e903d114be7a9e797089c3dee2fab2545..967db02ed27f31498e0f5c3245a37473022f4be5 100644 (file)
@@ -61,6 +61,9 @@ int iris_venc_inst_init(struct iris_inst *inst)
        inst->crop.width = f->fmt.pix_mp.width;
        inst->crop.height = f->fmt.pix_mp.height;
 
+       inst->operating_rate = DEFAULT_FPS;
+       inst->frame_rate = DEFAULT_FPS;
+
        return 0;
 }
 
@@ -326,3 +329,94 @@ int iris_venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s)
                return -EINVAL;
        }
 }
+
+int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm)
+{
+       struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps;
+       struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx);
+       struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx);
+       struct v4l2_fract *timeperframe = NULL;
+       u32 default_rate = DEFAULT_FPS;
+       bool is_frame_rate = false;
+       u64 us_per_frame, fps;
+       u32 max_rate;
+
+       int ret = 0;
+
+       if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               timeperframe = &s_parm->parm.output.timeperframe;
+               max_rate = caps->max_operating_rate;
+               s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       } else {
+               timeperframe = &s_parm->parm.capture.timeperframe;
+               is_frame_rate = true;
+               max_rate = caps->max_frame_rate;
+               s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       }
+
+       if (!timeperframe->denominator || !timeperframe->numerator) {
+               if (!timeperframe->numerator)
+                       timeperframe->numerator = 1;
+               if (!timeperframe->denominator)
+                       timeperframe->denominator = default_rate;
+       }
+
+       us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC;
+       do_div(us_per_frame, timeperframe->denominator);
+
+       if (!us_per_frame)
+               return -EINVAL;
+
+       fps = (u64)USEC_PER_SEC;
+       do_div(fps, us_per_frame);
+       if (fps > max_rate) {
+               ret = -ENOMEM;
+               goto reset_rate;
+       }
+
+       if (is_frame_rate)
+               inst->frame_rate = (u32)fps;
+       else
+               inst->operating_rate = (u32)fps;
+
+       if ((s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && vb2_is_streaming(src_q)) ||
+           (s_parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && vb2_is_streaming(dst_q))) {
+               ret = iris_check_core_mbpf(inst);
+               if (ret)
+                       goto reset_rate;
+               ret = iris_check_core_mbps(inst);
+               if (ret)
+                       goto reset_rate;
+       }
+
+       return 0;
+
+reset_rate:
+       if (ret) {
+               if (is_frame_rate)
+                       inst->frame_rate = default_rate;
+               else
+                       inst->operating_rate = default_rate;
+       }
+
+       return ret;
+}
+
+int iris_venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm)
+{
+       struct v4l2_fract *timeperframe = NULL;
+
+       if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               timeperframe = &s_parm->parm.output.timeperframe;
+               timeperframe->numerator = 1;
+               timeperframe->denominator = inst->operating_rate;
+               s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       } else {
+               timeperframe = &s_parm->parm.capture.timeperframe;
+               timeperframe->numerator = 1;
+               timeperframe->denominator = inst->frame_rate;
+               s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       }
+
+       return 0;
+}
index 72c6e25d87113baa6d2219ae478b7d7df1aed7bf..0d566b7fc89b96b8fbc62a35b2ba795ca0bcf460 100644 (file)
@@ -16,5 +16,7 @@ int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f);
 int iris_venc_validate_format(struct iris_inst *inst, u32 pixelformat);
 int iris_venc_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub);
 int iris_venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s);
+int iris_venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm);
+int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm);
 
 #endif
index b134ae710d9e1d02bc52db2e9356fdc4f668a387..1fd0c87e20758593f0f6ec607d8aa369c7bd6490 100644 (file)
@@ -530,6 +530,34 @@ static int iris_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs
        return -EINVAL;
 }
 
+static int iris_s_parm(struct file *filp, void *fh, struct v4l2_streamparm *a)
+{
+       struct iris_inst *inst = iris_get_inst(filp);
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return -EINVAL;
+
+       if (inst->domain == ENCODER)
+               return iris_venc_s_param(inst, a);
+       else
+               return -EINVAL;
+}
+
+static int iris_g_parm(struct file *filp, void *fh, struct v4l2_streamparm *a)
+{
+       struct iris_inst *inst = iris_get_inst(filp);
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return -EINVAL;
+
+       if (inst->domain == ENCODER)
+               return iris_venc_g_param(inst, a);
+       else
+               return -EINVAL;
+}
+
 static int iris_dec_cmd(struct file *filp, void *fh,
                        struct v4l2_decoder_cmd *dec)
 {
@@ -626,6 +654,8 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_enc = {
        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
        .vidioc_g_selection             = iris_g_selection,
        .vidioc_s_selection             = iris_s_selection,
+       .vidioc_s_parm                  = iris_s_parm,
+       .vidioc_g_parm                  = iris_g_parm,
 };
 
 void iris_init_ops(struct iris_core *core)