Message ID | 20241120-qcom-video-iris-v6-14-a8cf6704e992@quicinc.com |
---|---|
State | Superseded |
Headers | show |
Series | Qualcomm iris video decoder driver | expand |
On 20/11/2024 15:46, Dikshita Agarwal wrote: > Initialize ctrl handler by reading platform specific firmware > capabilities. Capabilities are features supported by a specific platform > (SOC). Each capability is defined with min, max, range, default value > and corresponding HFI. Implement s_ctrl and g_volatile_ctrl ctrl ops. > > Co-developed-by: Vedang Nagar <quic_vnagar@quicinc.com> > Signed-off-by: Vedang Nagar <quic_vnagar@quicinc.com> > Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl> Regards, Hans > --- > drivers/media/platform/qcom/iris/Makefile | 1 + > drivers/media/platform/qcom/iris/iris_core.h | 2 + > drivers/media/platform/qcom/iris/iris_ctrls.c | 161 +++++++++++++++++++++ > drivers/media/platform/qcom/iris/iris_ctrls.h | 17 +++ > .../platform/qcom/iris/iris_hfi_gen2_defines.h | 2 + > drivers/media/platform/qcom/iris/iris_instance.h | 4 + > .../platform/qcom/iris/iris_platform_common.h | 29 ++++ > .../platform/qcom/iris/iris_platform_sm8550.c | 47 ++++++ > drivers/media/platform/qcom/iris/iris_probe.c | 3 + > drivers/media/platform/qcom/iris/iris_vdec.c | 9 +- > drivers/media/platform/qcom/iris/iris_vdec.h | 2 +- > drivers/media/platform/qcom/iris/iris_vidc.c | 9 +- > 12 files changed, 283 insertions(+), 3 deletions(-) > > diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile > index 48ab264b7906..f685d76c2f79 100644 > --- a/drivers/media/platform/qcom/iris/Makefile > +++ b/drivers/media/platform/qcom/iris/Makefile > @@ -1,5 +1,6 @@ > iris-objs += iris_buffer.o \ > iris_core.o \ > + iris_ctrls.o \ > iris_firmware.o \ > iris_hfi_common.o \ > iris_hfi_gen1_command.o \ > diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h > index 1ddcb8793172..37fb4919fecc 100644 > --- a/drivers/media/platform/qcom/iris/iris_core.h > +++ b/drivers/media/platform/qcom/iris/iris_core.h > @@ -63,6 +63,7 @@ struct icc_info { > * @intr_status: interrupt status > * @sys_error_handler: a delayed work for handling system fatal error > * @instances: a list_head of all instances > + * @inst_fw_caps: an array of supported instance capabilities > */ > > struct iris_core { > @@ -101,6 +102,7 @@ struct iris_core { > u32 intr_status; > struct delayed_work sys_error_handler; > struct list_head instances; > + struct platform_inst_fw_cap inst_fw_caps[INST_FW_CAP_MAX]; > }; > > int iris_core_init(struct iris_core *core); > diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c > new file mode 100644 > index 000000000000..a204e2e1edf7 > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c > @@ -0,0 +1,161 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#include <media/v4l2-mem2mem.h> > +#include "iris_ctrls.h" > +#include "iris_instance.h" > + > +static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) > +{ > + return cap_id >= 1 && cap_id < INST_FW_CAP_MAX; > +} > + > +static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) > +{ > + switch (id) { > + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: > + return PROFILE; > + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: > + return LEVEL; > + default: > + return INST_FW_CAP_MAX; > + } > +} > + > +static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) > +{ > + if (!iris_valid_cap_id(cap_id)) > + return 0; > + > + switch (cap_id) { > + case PROFILE: > + return V4L2_CID_MPEG_VIDEO_H264_PROFILE; > + case LEVEL: > + return V4L2_CID_MPEG_VIDEO_H264_LEVEL; > + default: > + return 0; > + } > +} > + > +static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) > +{ > + struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); > + enum platform_inst_fw_cap_type cap_id; > + struct platform_inst_fw_cap *cap; > + struct vb2_queue *q; > + > + cap = &inst->fw_caps[0]; > + cap_id = iris_get_cap_id(ctrl->id); > + if (!iris_valid_cap_id(cap_id)) > + return -EINVAL; > + > + q = v4l2_m2m_get_src_vq(inst->m2m_ctx); > + if (vb2_is_streaming(q) && > + (!(inst->fw_caps[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED))) > + return -EINVAL; > + > + cap[cap_id].flags |= CAP_FLAG_CLIENT_SET; > + > + inst->fw_caps[cap_id].value = ctrl->val; > + > + return 0; > +} > + > +static const struct v4l2_ctrl_ops iris_ctrl_ops = { > + .s_ctrl = iris_vdec_op_s_ctrl, > +}; > + > +int iris_ctrls_init(struct iris_inst *inst) > +{ > + struct platform_inst_fw_cap *cap = &inst->fw_caps[0]; > + u32 num_ctrls = 0, ctrl_idx = 0, idx = 0; > + u32 v4l2_id; > + int ret; > + > + for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { > + if (iris_get_v4l2_id(cap[idx].cap_id)) > + num_ctrls++; > + } > + if (!num_ctrls) > + return -EINVAL; > + > + /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ > + > + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls + 1); > + if (ret) > + return ret; > + > + for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { > + struct v4l2_ctrl *ctrl; > + > + v4l2_id = iris_get_v4l2_id(cap[idx].cap_id); > + if (!v4l2_id) > + continue; > + > + if (ctrl_idx >= num_ctrls) { > + ret = -EINVAL; > + goto error; > + } > + > + if (cap[idx].flags & CAP_FLAG_MENU) { > + ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, > + &iris_ctrl_ops, > + v4l2_id, > + cap[idx].max, > + ~(cap[idx].step_or_mask), > + cap[idx].value); > + } else { > + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, > + &iris_ctrl_ops, > + v4l2_id, > + cap[idx].min, > + cap[idx].max, > + cap[idx].step_or_mask, > + cap[idx].value); > + } > + if (!ctrl) { > + ret = -EINVAL; > + goto error; > + } > + > + ctrl_idx++; > + } > + > + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, > + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); > + > + ret = inst->ctrl_handler.error; > + if (ret) > + goto error; > + > + return 0; > +error: > + v4l2_ctrl_handler_free(&inst->ctrl_handler); > + > + return ret; > +} > + > +void iris_session_init_caps(struct iris_core *core) > +{ > + struct platform_inst_fw_cap *caps; > + u32 i, num_cap, cap_id; > + > + caps = core->iris_platform_data->inst_fw_caps; > + num_cap = core->iris_platform_data->inst_fw_caps_size; > + > + for (i = 0; i < num_cap; i++) { > + cap_id = caps[i].cap_id; > + if (!iris_valid_cap_id(cap_id)) > + continue; > + > + core->inst_fw_caps[cap_id].cap_id = caps[i].cap_id; > + core->inst_fw_caps[cap_id].min = caps[i].min; > + core->inst_fw_caps[cap_id].max = caps[i].max; > + core->inst_fw_caps[cap_id].step_or_mask = caps[i].step_or_mask; > + core->inst_fw_caps[cap_id].value = caps[i].value; > + core->inst_fw_caps[cap_id].flags = caps[i].flags; > + core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; > + } > +} > diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h > new file mode 100644 > index 000000000000..fe65a772e6dd > --- /dev/null > +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h > @@ -0,0 +1,17 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. > + */ > + > +#ifndef __IRIS_CTRLS_H__ > +#define __IRIS_CTRLS_H__ > + > +#include "iris_platform_common.h" > + > +struct iris_core; > +struct iris_inst; > + > +int iris_ctrls_init(struct iris_inst *inst); > +void iris_session_init_caps(struct iris_core *core); > + > +#endif > 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 b95a34379ea1..6be8a6ff7924 100644 > --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h > @@ -28,6 +28,8 @@ > #define HFI_PROP_UBWC_BANK_SWZL_LEVEL3 0x03000008 > #define HFI_PROP_UBWC_BANK_SPREADING 0x03000009 > #define HFI_PROP_CODEC 0x03000100 > +#define HFI_PROP_PROFILE 0x03000107 > +#define HFI_PROP_LEVEL 0x03000108 > #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 > #define HFI_PROP_END 0x03FFFFFF > > diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h > index ef4515d2086c..16b463cec4f4 100644 > --- a/drivers/media/platform/qcom/iris/iris_instance.h > +++ b/drivers/media/platform/qcom/iris/iris_instance.h > @@ -23,8 +23,10 @@ > * @fh: reference of v4l2 file handler > * @fmt_src: structure of v4l2_format for source > * @fmt_dst: structure of v4l2_format for destination > + * @ctrl_handler: reference of v4l2 ctrl handler > * @crop: structure of crop info > * @completions: structure of signal completions > + * @fw_caps: array of supported instance firmware capabilities > * @buffers: array of different iris buffers > * @fw_min_count: minimnum count of buffers needed by fw > * @once_per_session_set: boolean to set once per session property > @@ -42,8 +44,10 @@ struct iris_inst { > struct v4l2_fh fh; > struct v4l2_format *fmt_src; > struct v4l2_format *fmt_dst; > + struct v4l2_ctrl_handler ctrl_handler; > struct iris_hfi_rect_desc crop; > struct completion completion; > + struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; > struct iris_buffers buffers[BUF_TYPE_MAX]; > u32 fw_min_count; > bool once_per_session_set; > diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h > index 75d4932df910..a96475535aeb 100644 > --- a/drivers/media/platform/qcom/iris/iris_platform_common.h > +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h > @@ -49,6 +49,33 @@ struct platform_inst_caps { > u32 max_frame_height; > u32 max_mbpf; > }; > + > +enum platform_inst_fw_cap_type { > + PROFILE = 1, > + LEVEL, > + INST_FW_CAP_MAX, > +}; > + > +enum platform_inst_fw_cap_flags { > + CAP_FLAG_DYNAMIC_ALLOWED = BIT(0), > + CAP_FLAG_MENU = BIT(1), > + CAP_FLAG_INPUT_PORT = BIT(2), > + CAP_FLAG_OUTPUT_PORT = BIT(3), > + CAP_FLAG_CLIENT_SET = BIT(4), > + CAP_FLAG_BITMASK = BIT(5), > + CAP_FLAG_VOLATILE = BIT(6), > +}; > + > +struct platform_inst_fw_cap { > + enum platform_inst_fw_cap_type cap_id; > + s64 min; > + s64 max; > + s64 step_or_mask; > + s64 value; > + u32 hfi_id; > + enum platform_inst_fw_cap_flags flags; > +}; > + > struct iris_core_power { > u64 clk_freq; > u64 icc_bw; > @@ -79,6 +106,8 @@ struct iris_platform_data { > const char *fwname; > u32 pas_id; > struct platform_inst_caps *inst_caps; > + struct platform_inst_fw_cap *inst_fw_caps; > + u32 inst_fw_caps_size; > struct tz_cp_config *tz_cp_config_data; > u32 core_arch; > u32 hw_response_timeout; > diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > index 37c0130d7059..7e3703adb5b3 100644 > --- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c > @@ -5,11 +5,56 @@ > > #include "iris_core.h" > #include "iris_hfi_gen2.h" > +#include "iris_hfi_gen2_defines.h" > #include "iris_platform_common.h" > #include "iris_vpu_common.h" > > #define VIDEO_ARCH_LX 1 > > +static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { > + { > + .cap_id = PROFILE, > + .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, > + }, > + { > + .cap_id = LEVEL, > + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, > + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_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) | > + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | > + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | > + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | > + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | > + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | > + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), > + .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, > + .hfi_id = HFI_PROP_LEVEL, > + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, > + }, > +}; > + > static struct platform_inst_caps platform_inst_cap_sm8550 = { > .min_frame_width = 96, > .max_frame_width = 8192, > @@ -77,6 +122,8 @@ struct iris_platform_data sm8550_data = { > .fwname = "qcom/vpu/vpu30_p4.mbn", > .pas_id = IRIS_PAS_ID, > .inst_caps = &platform_inst_cap_sm8550, > + .inst_fw_caps = inst_fw_cap_sm8550, > + .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), > .tz_cp_config_data = &tz_cp_config_sm8550, > .core_arch = VIDEO_ARCH_LX, > .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, > diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c > index a9162be5f9f6..954cc7c0cc97 100644 > --- a/drivers/media/platform/qcom/iris/iris_probe.c > +++ b/drivers/media/platform/qcom/iris/iris_probe.c > @@ -12,6 +12,7 @@ > #include <linux/reset.h> > > #include "iris_core.h" > +#include "iris_ctrls.h" > #include "iris_vidc.h" > > static int iris_init_icc(struct iris_core *core) > @@ -236,6 +237,8 @@ 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_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c > index 9afeb681b7a7..5571c24a7417 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.c > +++ b/drivers/media/platform/qcom/iris/iris_vdec.c > @@ -7,6 +7,7 @@ > #include <media/v4l2-mem2mem.h> > > #include "iris_buffer.h" > +#include "iris_ctrls.h" > #include "iris_instance.h" > #include "iris_vdec.h" > #include "iris_vpu_buffer.h" > @@ -15,8 +16,9 @@ > #define DEFAULT_HEIGHT 240 > #define DEFAULT_CODEC_ALIGNMENT 16 > > -void iris_vdec_inst_init(struct iris_inst *inst) > +int iris_vdec_inst_init(struct iris_inst *inst) > { > + struct iris_core *core = inst->core; > struct v4l2_format *f; > > inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); > @@ -51,6 +53,11 @@ void iris_vdec_inst_init(struct iris_inst *inst) > f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; > inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); > inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; > + > + memcpy(&inst->fw_caps[0], &core->inst_fw_caps[0], > + INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); > + > + return iris_ctrls_init(inst); > } > > void iris_vdec_inst_deinit(struct iris_inst *inst) > diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h > index f64ce3234e6a..9f08a13cb6bb 100644 > --- a/drivers/media/platform/qcom/iris/iris_vdec.h > +++ b/drivers/media/platform/qcom/iris/iris_vdec.h > @@ -8,7 +8,7 @@ > > struct iris_inst; > > -void iris_vdec_inst_init(struct iris_inst *inst); > +int iris_vdec_inst_init(struct iris_inst *inst); > void iris_vdec_inst_deinit(struct iris_inst *inst); > int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); > int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); > diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c > index 3a138172e674..820d98da3190 100644 > --- a/drivers/media/platform/qcom/iris/iris_vidc.c > +++ b/drivers/media/platform/qcom/iris/iris_vidc.c > @@ -23,12 +23,14 @@ > static void iris_v4l2_fh_init(struct iris_inst *inst) > { > v4l2_fh_init(&inst->fh, inst->core->vdev_dec); > + inst->fh.ctrl_handler = &inst->ctrl_handler; > v4l2_fh_add(&inst->fh); > } > > static void iris_v4l2_fh_deinit(struct iris_inst *inst) > { > v4l2_fh_del(&inst->fh); > + inst->fh.ctrl_handler = NULL; > v4l2_fh_exit(&inst->fh); > } > > @@ -162,7 +164,9 @@ int iris_open(struct file *filp) > goto fail_m2m_release; > } > > - iris_vdec_inst_init(inst); > + ret = iris_vdec_inst_init(inst); > + if (ret) > + goto fail_m2m_ctx_release; > > iris_add_session(inst); > > @@ -171,6 +175,8 @@ int iris_open(struct file *filp) > > return 0; > > +fail_m2m_ctx_release: > + v4l2_m2m_ctx_release(inst->m2m_ctx); > fail_m2m_release: > v4l2_m2m_release(inst->m2m_dev); > fail_v4l2_fh_deinit: > @@ -202,6 +208,7 @@ int iris_close(struct file *filp) > { > struct iris_inst *inst = iris_get_inst(filp, NULL); > > + v4l2_ctrl_handler_free(&inst->ctrl_handler); > v4l2_m2m_ctx_release(inst->m2m_ctx); > v4l2_m2m_release(inst->m2m_dev); > mutex_lock(&inst->lock); >
diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index 48ab264b7906..f685d76c2f79 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -1,5 +1,6 @@ iris-objs += iris_buffer.o \ iris_core.o \ + iris_ctrls.o \ iris_firmware.o \ iris_hfi_common.o \ iris_hfi_gen1_command.o \ diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 1ddcb8793172..37fb4919fecc 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -63,6 +63,7 @@ struct icc_info { * @intr_status: interrupt status * @sys_error_handler: a delayed work for handling system fatal error * @instances: a list_head of all instances + * @inst_fw_caps: an array of supported instance capabilities */ struct iris_core { @@ -101,6 +102,7 @@ struct iris_core { u32 intr_status; struct delayed_work sys_error_handler; struct list_head instances; + struct platform_inst_fw_cap inst_fw_caps[INST_FW_CAP_MAX]; }; int iris_core_init(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c new file mode 100644 index 000000000000..a204e2e1edf7 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <media/v4l2-mem2mem.h> +#include "iris_ctrls.h" +#include "iris_instance.h" + +static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) +{ + return cap_id >= 1 && cap_id < INST_FW_CAP_MAX; +} + +static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) +{ + switch (id) { + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + return PROFILE; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + return LEVEL; + default: + return INST_FW_CAP_MAX; + } +} + +static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) +{ + if (!iris_valid_cap_id(cap_id)) + return 0; + + switch (cap_id) { + case PROFILE: + return V4L2_CID_MPEG_VIDEO_H264_PROFILE; + case LEVEL: + return V4L2_CID_MPEG_VIDEO_H264_LEVEL; + default: + return 0; + } +} + +static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); + enum platform_inst_fw_cap_type cap_id; + struct platform_inst_fw_cap *cap; + struct vb2_queue *q; + + cap = &inst->fw_caps[0]; + cap_id = iris_get_cap_id(ctrl->id); + if (!iris_valid_cap_id(cap_id)) + return -EINVAL; + + q = v4l2_m2m_get_src_vq(inst->m2m_ctx); + if (vb2_is_streaming(q) && + (!(inst->fw_caps[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED))) + return -EINVAL; + + cap[cap_id].flags |= CAP_FLAG_CLIENT_SET; + + inst->fw_caps[cap_id].value = ctrl->val; + + return 0; +} + +static const struct v4l2_ctrl_ops iris_ctrl_ops = { + .s_ctrl = iris_vdec_op_s_ctrl, +}; + +int iris_ctrls_init(struct iris_inst *inst) +{ + struct platform_inst_fw_cap *cap = &inst->fw_caps[0]; + u32 num_ctrls = 0, ctrl_idx = 0, idx = 0; + u32 v4l2_id; + int ret; + + for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { + if (iris_get_v4l2_id(cap[idx].cap_id)) + num_ctrls++; + } + if (!num_ctrls) + return -EINVAL; + + /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ + + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls + 1); + if (ret) + return ret; + + for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { + struct v4l2_ctrl *ctrl; + + v4l2_id = iris_get_v4l2_id(cap[idx].cap_id); + if (!v4l2_id) + continue; + + if (ctrl_idx >= num_ctrls) { + ret = -EINVAL; + goto error; + } + + if (cap[idx].flags & CAP_FLAG_MENU) { + ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, + &iris_ctrl_ops, + v4l2_id, + cap[idx].max, + ~(cap[idx].step_or_mask), + cap[idx].value); + } else { + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, + &iris_ctrl_ops, + v4l2_id, + cap[idx].min, + cap[idx].max, + cap[idx].step_or_mask, + cap[idx].value); + } + if (!ctrl) { + ret = -EINVAL; + goto error; + } + + ctrl_idx++; + } + + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); + + ret = inst->ctrl_handler.error; + if (ret) + goto error; + + return 0; +error: + v4l2_ctrl_handler_free(&inst->ctrl_handler); + + return ret; +} + +void iris_session_init_caps(struct iris_core *core) +{ + struct platform_inst_fw_cap *caps; + u32 i, num_cap, cap_id; + + caps = core->iris_platform_data->inst_fw_caps; + num_cap = core->iris_platform_data->inst_fw_caps_size; + + for (i = 0; i < num_cap; i++) { + cap_id = caps[i].cap_id; + if (!iris_valid_cap_id(cap_id)) + continue; + + core->inst_fw_caps[cap_id].cap_id = caps[i].cap_id; + core->inst_fw_caps[cap_id].min = caps[i].min; + core->inst_fw_caps[cap_id].max = caps[i].max; + core->inst_fw_caps[cap_id].step_or_mask = caps[i].step_or_mask; + core->inst_fw_caps[cap_id].value = caps[i].value; + core->inst_fw_caps[cap_id].flags = caps[i].flags; + core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; + } +} diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h new file mode 100644 index 000000000000..fe65a772e6dd --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_CTRLS_H__ +#define __IRIS_CTRLS_H__ + +#include "iris_platform_common.h" + +struct iris_core; +struct iris_inst; + +int iris_ctrls_init(struct iris_inst *inst); +void iris_session_init_caps(struct iris_core *core); + +#endif 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 b95a34379ea1..6be8a6ff7924 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -28,6 +28,8 @@ #define HFI_PROP_UBWC_BANK_SWZL_LEVEL3 0x03000008 #define HFI_PROP_UBWC_BANK_SPREADING 0x03000009 #define HFI_PROP_CODEC 0x03000100 +#define HFI_PROP_PROFILE 0x03000107 +#define HFI_PROP_LEVEL 0x03000108 #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 #define HFI_PROP_END 0x03FFFFFF diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index ef4515d2086c..16b463cec4f4 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -23,8 +23,10 @@ * @fh: reference of v4l2 file handler * @fmt_src: structure of v4l2_format for source * @fmt_dst: structure of v4l2_format for destination + * @ctrl_handler: reference of v4l2 ctrl handler * @crop: structure of crop info * @completions: structure of signal completions + * @fw_caps: array of supported instance firmware capabilities * @buffers: array of different iris buffers * @fw_min_count: minimnum count of buffers needed by fw * @once_per_session_set: boolean to set once per session property @@ -42,8 +44,10 @@ struct iris_inst { struct v4l2_fh fh; struct v4l2_format *fmt_src; struct v4l2_format *fmt_dst; + struct v4l2_ctrl_handler ctrl_handler; struct iris_hfi_rect_desc crop; struct completion completion; + struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; struct iris_buffers buffers[BUF_TYPE_MAX]; u32 fw_min_count; bool once_per_session_set; diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index 75d4932df910..a96475535aeb 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -49,6 +49,33 @@ struct platform_inst_caps { u32 max_frame_height; u32 max_mbpf; }; + +enum platform_inst_fw_cap_type { + PROFILE = 1, + LEVEL, + INST_FW_CAP_MAX, +}; + +enum platform_inst_fw_cap_flags { + CAP_FLAG_DYNAMIC_ALLOWED = BIT(0), + CAP_FLAG_MENU = BIT(1), + CAP_FLAG_INPUT_PORT = BIT(2), + CAP_FLAG_OUTPUT_PORT = BIT(3), + CAP_FLAG_CLIENT_SET = BIT(4), + CAP_FLAG_BITMASK = BIT(5), + CAP_FLAG_VOLATILE = BIT(6), +}; + +struct platform_inst_fw_cap { + enum platform_inst_fw_cap_type cap_id; + s64 min; + s64 max; + s64 step_or_mask; + s64 value; + u32 hfi_id; + enum platform_inst_fw_cap_flags flags; +}; + struct iris_core_power { u64 clk_freq; u64 icc_bw; @@ -79,6 +106,8 @@ struct iris_platform_data { const char *fwname; u32 pas_id; struct platform_inst_caps *inst_caps; + struct platform_inst_fw_cap *inst_fw_caps; + u32 inst_fw_caps_size; struct tz_cp_config *tz_cp_config_data; u32 core_arch; u32 hw_response_timeout; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c index 37c0130d7059..7e3703adb5b3 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8550.c @@ -5,11 +5,56 @@ #include "iris_core.h" #include "iris_hfi_gen2.h" +#include "iris_hfi_gen2_defines.h" #include "iris_platform_common.h" #include "iris_vpu_common.h" #define VIDEO_ARCH_LX 1 +static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { + { + .cap_id = PROFILE, + .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, + }, + { + .cap_id = LEVEL, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_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) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, +}; + static struct platform_inst_caps platform_inst_cap_sm8550 = { .min_frame_width = 96, .max_frame_width = 8192, @@ -77,6 +122,8 @@ struct iris_platform_data sm8550_data = { .fwname = "qcom/vpu/vpu30_p4.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_sm8550, + .inst_fw_caps = inst_fw_cap_sm8550, + .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index a9162be5f9f6..954cc7c0cc97 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -12,6 +12,7 @@ #include <linux/reset.h> #include "iris_core.h" +#include "iris_ctrls.h" #include "iris_vidc.h" static int iris_init_icc(struct iris_core *core) @@ -236,6 +237,8 @@ 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_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c index 9afeb681b7a7..5571c24a7417 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/iris/iris_vdec.c @@ -7,6 +7,7 @@ #include <media/v4l2-mem2mem.h> #include "iris_buffer.h" +#include "iris_ctrls.h" #include "iris_instance.h" #include "iris_vdec.h" #include "iris_vpu_buffer.h" @@ -15,8 +16,9 @@ #define DEFAULT_HEIGHT 240 #define DEFAULT_CODEC_ALIGNMENT 16 -void iris_vdec_inst_init(struct iris_inst *inst) +int iris_vdec_inst_init(struct iris_inst *inst) { + struct iris_core *core = inst->core; struct v4l2_format *f; inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); @@ -51,6 +53,11 @@ void iris_vdec_inst_init(struct iris_inst *inst) f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + memcpy(&inst->fw_caps[0], &core->inst_fw_caps[0], + INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); + + return iris_ctrls_init(inst); } void iris_vdec_inst_deinit(struct iris_inst *inst) diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h index f64ce3234e6a..9f08a13cb6bb 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.h +++ b/drivers/media/platform/qcom/iris/iris_vdec.h @@ -8,7 +8,7 @@ struct iris_inst; -void iris_vdec_inst_init(struct iris_inst *inst); +int iris_vdec_inst_init(struct iris_inst *inst); void iris_vdec_inst_deinit(struct iris_inst *inst); int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 3a138172e674..820d98da3190 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -23,12 +23,14 @@ static void iris_v4l2_fh_init(struct iris_inst *inst) { v4l2_fh_init(&inst->fh, inst->core->vdev_dec); + inst->fh.ctrl_handler = &inst->ctrl_handler; v4l2_fh_add(&inst->fh); } static void iris_v4l2_fh_deinit(struct iris_inst *inst) { v4l2_fh_del(&inst->fh); + inst->fh.ctrl_handler = NULL; v4l2_fh_exit(&inst->fh); } @@ -162,7 +164,9 @@ int iris_open(struct file *filp) goto fail_m2m_release; } - iris_vdec_inst_init(inst); + ret = iris_vdec_inst_init(inst); + if (ret) + goto fail_m2m_ctx_release; iris_add_session(inst); @@ -171,6 +175,8 @@ int iris_open(struct file *filp) return 0; +fail_m2m_ctx_release: + v4l2_m2m_ctx_release(inst->m2m_ctx); fail_m2m_release: v4l2_m2m_release(inst->m2m_dev); fail_v4l2_fh_deinit: @@ -202,6 +208,7 @@ int iris_close(struct file *filp) { struct iris_inst *inst = iris_get_inst(filp, NULL); + v4l2_ctrl_handler_free(&inst->ctrl_handler); v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); mutex_lock(&inst->lock);