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
iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id)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
iris_get_cap_id(u32 id)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
iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id)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
iris_vdec_op_s_ctrl(struct v4l2_ctrl * ctrl)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
iris_ctrls_init(struct iris_inst * inst)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
iris_session_init_caps(struct iris_core * core)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
iris_get_port_info(struct iris_inst * inst,enum platform_inst_fw_cap_type cap_id)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
iris_set_u32_enum(struct iris_inst * inst,enum platform_inst_fw_cap_type cap_id)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
iris_set_u32(struct iris_inst * inst,enum platform_inst_fw_cap_type cap_id)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
iris_set_stage(struct iris_inst * inst,enum platform_inst_fw_cap_type cap_id)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
iris_set_pipe(struct iris_inst * inst,enum platform_inst_fw_cap_type cap_id)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
iris_set_properties(struct iris_inst * inst,u32 plane)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