1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 */ 5 6 #include <linux/types.h> 7 #include <media/v4l2-mem2mem.h> 8 9 #include "iris_ctrls.h" 10 #include "iris_instance.h" 11 12 static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) 13 { 14 return cap_id >= 1 && cap_id < INST_FW_CAP_MAX; 15 } 16 17 static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) 18 { 19 switch (id) { 20 case V4L2_CID_MPEG_VIDEO_H264_PROFILE: 21 return PROFILE_H264; 22 case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: 23 return PROFILE_HEVC; 24 case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: 25 return PROFILE_VP9; 26 case V4L2_CID_MPEG_VIDEO_H264_LEVEL: 27 return LEVEL_H264; 28 case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: 29 return LEVEL_HEVC; 30 case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: 31 return LEVEL_VP9; 32 case V4L2_CID_MPEG_VIDEO_HEVC_TIER: 33 return TIER; 34 default: 35 return INST_FW_CAP_MAX; 36 } 37 } 38 39 static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) 40 { 41 if (!iris_valid_cap_id(cap_id)) 42 return 0; 43 44 switch (cap_id) { 45 case PROFILE_H264: 46 return V4L2_CID_MPEG_VIDEO_H264_PROFILE; 47 case PROFILE_HEVC: 48 return V4L2_CID_MPEG_VIDEO_HEVC_PROFILE; 49 case PROFILE_VP9: 50 return V4L2_CID_MPEG_VIDEO_VP9_PROFILE; 51 case LEVEL_H264: 52 return V4L2_CID_MPEG_VIDEO_H264_LEVEL; 53 case LEVEL_HEVC: 54 return V4L2_CID_MPEG_VIDEO_HEVC_LEVEL; 55 case LEVEL_VP9: 56 return V4L2_CID_MPEG_VIDEO_VP9_LEVEL; 57 case TIER: 58 return V4L2_CID_MPEG_VIDEO_HEVC_TIER; 59 default: 60 return 0; 61 } 62 } 63 64 static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) 65 { 66 struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); 67 enum platform_inst_fw_cap_type cap_id; 68 struct platform_inst_fw_cap *cap; 69 struct vb2_queue *q; 70 71 cap = &inst->fw_caps[0]; 72 cap_id = iris_get_cap_id(ctrl->id); 73 if (!iris_valid_cap_id(cap_id)) 74 return -EINVAL; 75 76 q = v4l2_m2m_get_src_vq(inst->m2m_ctx); 77 if (vb2_is_streaming(q) && 78 (!(inst->fw_caps[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED))) 79 return -EINVAL; 80 81 cap[cap_id].flags |= CAP_FLAG_CLIENT_SET; 82 83 inst->fw_caps[cap_id].value = ctrl->val; 84 85 return 0; 86 } 87 88 static const struct v4l2_ctrl_ops iris_ctrl_ops = { 89 .s_ctrl = iris_vdec_op_s_ctrl, 90 }; 91 92 int iris_ctrls_init(struct iris_inst *inst) 93 { 94 struct platform_inst_fw_cap *cap = &inst->fw_caps[0]; 95 u32 num_ctrls = 0, ctrl_idx = 0, idx = 0; 96 u32 v4l2_id; 97 int ret; 98 99 for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { 100 if (iris_get_v4l2_id(cap[idx].cap_id)) 101 num_ctrls++; 102 } 103 104 /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ 105 106 ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls + 1); 107 if (ret) 108 return ret; 109 110 for (idx = 1; idx < INST_FW_CAP_MAX; idx++) { 111 struct v4l2_ctrl *ctrl; 112 113 v4l2_id = iris_get_v4l2_id(cap[idx].cap_id); 114 if (!v4l2_id) 115 continue; 116 117 if (ctrl_idx >= num_ctrls) { 118 ret = -EINVAL; 119 goto error; 120 } 121 122 if (cap[idx].flags & CAP_FLAG_MENU) { 123 ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, 124 &iris_ctrl_ops, 125 v4l2_id, 126 cap[idx].max, 127 ~(cap[idx].step_or_mask), 128 cap[idx].value); 129 } else { 130 ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, 131 &iris_ctrl_ops, 132 v4l2_id, 133 cap[idx].min, 134 cap[idx].max, 135 cap[idx].step_or_mask, 136 cap[idx].value); 137 } 138 if (!ctrl) { 139 ret = -EINVAL; 140 goto error; 141 } 142 143 ctrl_idx++; 144 } 145 146 v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, 147 V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); 148 149 ret = inst->ctrl_handler.error; 150 if (ret) 151 goto error; 152 153 return 0; 154 error: 155 v4l2_ctrl_handler_free(&inst->ctrl_handler); 156 157 return ret; 158 } 159 160 void iris_session_init_caps(struct iris_core *core) 161 { 162 struct platform_inst_fw_cap *caps; 163 u32 i, num_cap, cap_id; 164 165 caps = core->iris_platform_data->inst_fw_caps; 166 num_cap = core->iris_platform_data->inst_fw_caps_size; 167 168 for (i = 0; i < num_cap; i++) { 169 cap_id = caps[i].cap_id; 170 if (!iris_valid_cap_id(cap_id)) 171 continue; 172 173 core->inst_fw_caps[cap_id].cap_id = caps[i].cap_id; 174 core->inst_fw_caps[cap_id].min = caps[i].min; 175 core->inst_fw_caps[cap_id].max = caps[i].max; 176 core->inst_fw_caps[cap_id].step_or_mask = caps[i].step_or_mask; 177 core->inst_fw_caps[cap_id].value = caps[i].value; 178 core->inst_fw_caps[cap_id].flags = caps[i].flags; 179 core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; 180 core->inst_fw_caps[cap_id].set = caps[i].set; 181 } 182 } 183 184 static u32 iris_get_port_info(struct iris_inst *inst, 185 enum platform_inst_fw_cap_type cap_id) 186 { 187 if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) 188 return HFI_PORT_BITSTREAM; 189 else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) 190 return HFI_PORT_RAW; 191 192 return HFI_PORT_NONE; 193 } 194 195 int iris_set_u32_enum(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) 196 { 197 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 198 u32 hfi_value = inst->fw_caps[cap_id].value; 199 u32 hfi_id = inst->fw_caps[cap_id].hfi_id; 200 201 return hfi_ops->session_set_property(inst, hfi_id, 202 HFI_HOST_FLAGS_NONE, 203 iris_get_port_info(inst, cap_id), 204 HFI_PAYLOAD_U32_ENUM, 205 &hfi_value, sizeof(u32)); 206 } 207 208 int iris_set_u32(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) 209 { 210 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 211 u32 hfi_value = inst->fw_caps[cap_id].value; 212 u32 hfi_id = inst->fw_caps[cap_id].hfi_id; 213 214 return hfi_ops->session_set_property(inst, hfi_id, 215 HFI_HOST_FLAGS_NONE, 216 iris_get_port_info(inst, cap_id), 217 HFI_PAYLOAD_U32, 218 &hfi_value, sizeof(u32)); 219 } 220 221 int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) 222 { 223 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 224 struct v4l2_format *inp_f = inst->fmt_src; 225 u32 hfi_id = inst->fw_caps[cap_id].hfi_id; 226 u32 height = inp_f->fmt.pix_mp.height; 227 u32 width = inp_f->fmt.pix_mp.width; 228 u32 work_mode = STAGE_2; 229 230 if (iris_res_is_less_than(width, height, 1280, 720)) 231 work_mode = STAGE_1; 232 233 return hfi_ops->session_set_property(inst, hfi_id, 234 HFI_HOST_FLAGS_NONE, 235 iris_get_port_info(inst, cap_id), 236 HFI_PAYLOAD_U32, 237 &work_mode, sizeof(u32)); 238 } 239 240 int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) 241 { 242 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 243 u32 work_route = inst->fw_caps[PIPE].value; 244 u32 hfi_id = inst->fw_caps[cap_id].hfi_id; 245 246 return hfi_ops->session_set_property(inst, hfi_id, 247 HFI_HOST_FLAGS_NONE, 248 iris_get_port_info(inst, cap_id), 249 HFI_PAYLOAD_U32, 250 &work_route, sizeof(u32)); 251 } 252 253 int iris_set_properties(struct iris_inst *inst, u32 plane) 254 { 255 const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; 256 struct platform_inst_fw_cap *cap; 257 int ret; 258 u32 i; 259 260 ret = hfi_ops->session_set_config_params(inst, plane); 261 if (ret) 262 return ret; 263 264 for (i = 1; i < INST_FW_CAP_MAX; i++) { 265 cap = &inst->fw_caps[i]; 266 if (!iris_valid_cap_id(cap->cap_id)) 267 continue; 268 269 if (cap->cap_id && cap->set) 270 cap->set(inst, i); 271 } 272 273 return 0; 274 } 275