Files
linux/drivers/media/platform/qcom/iris/iris_ctrls.c
Dikshita Agarwal c314a28cda media: iris: Fix missing function pointer initialization
The function pointers responsible for setting firmware properties were
never initialized in the instance capability structure, causing it to
remain NULL. As a result, the firmware properties were not being set
correctly.

Fix this by properly assigning the function pointers from the core
capability to the instance capability, ensuring that the properties are
correctly applied to the firmware.

Cc: stable@vger.kernel.org
Fixes: 3a19d7b9e0 ("media: iris: implement set properties to firmware during streamon")
Acked-by: Vikash Garodia <quic_vgarodia@quicinc.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-HDK
Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Tested-by: Vikash Garodia <quic_vgarodia@quicinc.com> # on sa8775p-ride
Signed-off-by: Bryan O'Donoghue <bod@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
2025-07-03 11:02:44 +02:00

255 lines
6.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/types.h>
#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++;
}
/* 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;
core->inst_fw_caps[cap_id].set = caps[i].set;
}
}
static u32 iris_get_port_info(struct iris_inst *inst,
enum platform_inst_fw_cap_type cap_id)
{
if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT)
return HFI_PORT_BITSTREAM;
else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT)
return HFI_PORT_RAW;
return HFI_PORT_NONE;
}
int iris_set_u32_enum(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
u32 hfi_value = inst->fw_caps[cap_id].value;
u32 hfi_id = inst->fw_caps[cap_id].hfi_id;
return hfi_ops->session_set_property(inst, hfi_id,
HFI_HOST_FLAGS_NONE,
iris_get_port_info(inst, cap_id),
HFI_PAYLOAD_U32_ENUM,
&hfi_value, sizeof(u32));
}
int iris_set_u32(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
u32 hfi_value = inst->fw_caps[cap_id].value;
u32 hfi_id = inst->fw_caps[cap_id].hfi_id;
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_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
struct v4l2_format *inp_f = inst->fmt_src;
u32 hfi_id = inst->fw_caps[cap_id].hfi_id;
u32 height = inp_f->fmt.pix_mp.height;
u32 width = inp_f->fmt.pix_mp.width;
u32 work_mode = STAGE_2;
if (iris_res_is_less_than(width, height, 1280, 720))
work_mode = STAGE_1;
return hfi_ops->session_set_property(inst, hfi_id,
HFI_HOST_FLAGS_NONE,
iris_get_port_info(inst, cap_id),
HFI_PAYLOAD_U32,
&work_mode, sizeof(u32));
}
int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
u32 work_route = inst->fw_caps[PIPE].value;
u32 hfi_id = inst->fw_caps[cap_id].hfi_id;
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));
}
int iris_set_properties(struct iris_inst *inst, u32 plane)
{
const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
struct platform_inst_fw_cap *cap;
int ret;
u32 i;
ret = hfi_ops->session_set_config_params(inst, plane);
if (ret)
return ret;
for (i = 1; i < INST_FW_CAP_MAX; i++) {
cap = &inst->fw_caps[i];
if (!iris_valid_cap_id(cap->cap_id))
continue;
if (cap->cap_id && cap->set)
cap->set(inst, i);
}
return 0;
}