Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 <media/videobuf2-dma-contig.h>
7#include <media/v4l2-event.h>
8#include <media/v4l2-mem2mem.h>
9
10#include "iris_common.h"
11#include "iris_instance.h"
12#include "iris_vb2.h"
13#include "iris_vdec.h"
14#include "iris_venc.h"
15#include "iris_power.h"
16
17static int iris_check_inst_mbpf(struct iris_inst *inst)
18{
19 struct platform_inst_caps *caps;
20 u32 mbpf, max_mbpf;
21
22 caps = inst->core->iris_platform_data->inst_caps;
23 max_mbpf = caps->max_mbpf;
24 mbpf = iris_get_mbpf(inst);
25 if (mbpf > max_mbpf)
26 return -ENOMEM;
27
28 return 0;
29}
30
31static int iris_check_resolution_supported(struct iris_inst *inst)
32{
33 u32 width, height, min_width, min_height, max_width, max_height;
34 struct platform_inst_caps *caps;
35
36 caps = inst->core->iris_platform_data->inst_caps;
37 width = inst->fmt_src->fmt.pix_mp.width;
38 height = inst->fmt_src->fmt.pix_mp.height;
39
40 min_width = caps->min_frame_width;
41 max_width = caps->max_frame_width;
42 min_height = caps->min_frame_height;
43 max_height = caps->max_frame_height;
44
45 if (!(min_width <= width && width <= max_width) ||
46 !(min_height <= height && height <= max_height))
47 return -EINVAL;
48
49 return 0;
50}
51
52static int iris_check_session_supported(struct iris_inst *inst)
53{
54 struct iris_core *core = inst->core;
55 struct iris_inst *instance = NULL;
56 bool found = false;
57 int ret;
58
59 list_for_each_entry(instance, &core->instances, list) {
60 if (instance == inst)
61 found = true;
62 }
63
64 if (!found) {
65 ret = -EINVAL;
66 goto exit;
67 }
68
69 ret = iris_check_core_mbpf(inst);
70 if (ret)
71 goto exit;
72
73 ret = iris_check_inst_mbpf(inst);
74 if (ret)
75 goto exit;
76
77 ret = iris_check_resolution_supported(inst);
78 if (ret)
79 goto exit;
80
81 return 0;
82exit:
83 dev_err(inst->core->dev, "current session not supported(%d)\n", ret);
84
85 return ret;
86}
87
88int iris_vb2_buf_init(struct vb2_buffer *vb2)
89{
90 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
91 struct iris_buffer *buf = to_iris_buffer(vbuf);
92
93 buf->device_addr = vb2_dma_contig_plane_dma_addr(vb2, 0);
94
95 return 0;
96}
97
98int iris_vb2_queue_setup(struct vb2_queue *q,
99 unsigned int *num_buffers, unsigned int *num_planes,
100 unsigned int sizes[], struct device *alloc_devs[])
101{
102 struct iris_inst *inst;
103 struct iris_core *core;
104 struct v4l2_format *f;
105 int ret = 0;
106
107 inst = vb2_get_drv_priv(q);
108
109 mutex_lock(&inst->lock);
110 if (inst->state == IRIS_INST_ERROR) {
111 ret = -EBUSY;
112 goto unlock;
113 }
114
115 core = inst->core;
116 f = V4L2_TYPE_IS_OUTPUT(q->type) ? inst->fmt_src : inst->fmt_dst;
117
118 if (*num_planes) {
119 if (*num_planes != f->fmt.pix_mp.num_planes ||
120 sizes[0] < f->fmt.pix_mp.plane_fmt[0].sizeimage)
121 ret = -EINVAL;
122 goto unlock;
123 }
124
125 ret = iris_check_session_supported(inst);
126 if (ret)
127 goto unlock;
128
129 if (!inst->once_per_session_set) {
130 inst->once_per_session_set = true;
131
132 ret = core->hfi_ops->session_open(inst);
133 if (ret) {
134 ret = -EINVAL;
135 dev_err(core->dev, "session open failed\n");
136 goto unlock;
137 }
138
139 ret = iris_inst_change_state(inst, IRIS_INST_INIT);
140 if (ret)
141 goto unlock;
142 }
143
144 *num_planes = 1;
145 sizes[0] = f->fmt.pix_mp.plane_fmt[0].sizeimage;
146
147unlock:
148 mutex_unlock(&inst->lock);
149
150 return ret;
151}
152
153int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
154{
155 enum iris_buffer_type buf_type;
156 struct iris_inst *inst;
157 int ret = 0;
158
159 inst = vb2_get_drv_priv(q);
160
161 mutex_lock(&inst->lock);
162 if (inst->state == IRIS_INST_ERROR) {
163 ret = -EBUSY;
164 goto error;
165 }
166
167 if (!V4L2_TYPE_IS_OUTPUT(q->type) &&
168 !V4L2_TYPE_IS_CAPTURE(q->type)) {
169 ret = -EINVAL;
170 goto error;
171 }
172
173 iris_scale_power(inst);
174
175 ret = iris_check_session_supported(inst);
176 if (ret)
177 goto error;
178
179 if (V4L2_TYPE_IS_OUTPUT(q->type)) {
180 if (inst->domain == DECODER)
181 ret = iris_vdec_streamon_input(inst);
182 else
183 ret = iris_venc_streamon_input(inst);
184 } else if (V4L2_TYPE_IS_CAPTURE(q->type)) {
185 if (inst->domain == DECODER)
186 ret = iris_vdec_streamon_output(inst);
187 else
188 ret = iris_venc_streamon_output(inst);
189 }
190 if (ret)
191 goto error;
192
193 buf_type = iris_v4l2_type_to_driver(q->type);
194
195 if (inst->domain == DECODER) {
196 if (inst->state == IRIS_INST_STREAMING)
197 ret = iris_queue_internal_deferred_buffers(inst, BUF_DPB);
198 if (!ret)
199 ret = iris_queue_deferred_buffers(inst, buf_type);
200 } else {
201 if (inst->state == IRIS_INST_STREAMING) {
202 ret = iris_queue_deferred_buffers(inst, BUF_INPUT);
203 if (!ret)
204 ret = iris_queue_deferred_buffers(inst, BUF_OUTPUT);
205 }
206 }
207
208 if (ret)
209 goto error;
210
211 mutex_unlock(&inst->lock);
212
213 return ret;
214
215error:
216 iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED);
217 iris_inst_change_state(inst, IRIS_INST_ERROR);
218 mutex_unlock(&inst->lock);
219
220 return ret;
221}
222
223void iris_vb2_stop_streaming(struct vb2_queue *q)
224{
225 struct iris_inst *inst;
226 int ret = 0;
227
228 inst = vb2_get_drv_priv(q);
229
230 if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT)
231 return;
232
233 mutex_lock(&inst->lock);
234 if (inst->state == IRIS_INST_ERROR)
235 goto exit;
236
237 if (!V4L2_TYPE_IS_OUTPUT(q->type) &&
238 !V4L2_TYPE_IS_CAPTURE(q->type))
239 goto exit;
240
241 ret = iris_session_streamoff(inst, q->type);
242 if (ret)
243 goto exit;
244
245exit:
246 if (ret) {
247 iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR);
248 iris_inst_change_state(inst, IRIS_INST_ERROR);
249 }
250 mutex_unlock(&inst->lock);
251}
252
253int iris_vb2_buf_prepare(struct vb2_buffer *vb)
254{
255 struct iris_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
256 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
257
258 if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
259 if (vbuf->field == V4L2_FIELD_ANY)
260 vbuf->field = V4L2_FIELD_NONE;
261 if (vbuf->field != V4L2_FIELD_NONE)
262 return -EINVAL;
263 }
264
265 if (!(inst->sub_state & IRIS_INST_SUB_DRC)) {
266 if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
267 vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT))
268 return -EINVAL;
269 if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
270 vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT))
271 return -EINVAL;
272 }
273 return 0;
274}
275
276int iris_vb2_buf_out_validate(struct vb2_buffer *vb)
277{
278 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
279
280 v4l2_buf->field = V4L2_FIELD_NONE;
281
282 return 0;
283}
284
285void iris_vb2_buf_queue(struct vb2_buffer *vb2)
286{
287 static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS };
288 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
289 struct v4l2_m2m_ctx *m2m_ctx;
290 struct iris_inst *inst;
291 int ret = 0;
292
293 inst = vb2_get_drv_priv(vb2->vb2_queue);
294
295 mutex_lock(&inst->lock);
296 if (inst->state == IRIS_INST_ERROR) {
297 ret = -EBUSY;
298 goto exit;
299 }
300
301 if (vbuf->field == V4L2_FIELD_ANY)
302 vbuf->field = V4L2_FIELD_NONE;
303
304 m2m_ctx = inst->m2m_ctx;
305
306 if (!vb2->planes[0].bytesused && V4L2_TYPE_IS_OUTPUT(vb2->type)) {
307 ret = -EINVAL;
308 goto exit;
309 }
310
311 if (!inst->last_buffer_dequeued && V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) {
312 if ((inst->sub_state & IRIS_INST_SUB_DRC &&
313 inst->sub_state & IRIS_INST_SUB_DRC_LAST) ||
314 (inst->sub_state & IRIS_INST_SUB_DRAIN &&
315 inst->sub_state & IRIS_INST_SUB_DRAIN_LAST)) {
316 vbuf->flags |= V4L2_BUF_FLAG_LAST;
317 vbuf->sequence = inst->sequence_cap++;
318 vbuf->field = V4L2_FIELD_NONE;
319 vb2_set_plane_payload(vb2, 0, 0);
320 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
321 if (!v4l2_m2m_has_stopped(m2m_ctx)) {
322 v4l2_event_queue_fh(&inst->fh, &eos);
323 v4l2_m2m_mark_stopped(m2m_ctx);
324 }
325 inst->last_buffer_dequeued = true;
326 goto exit;
327 }
328 }
329
330 v4l2_m2m_buf_queue(m2m_ctx, vbuf);
331
332 if (inst->domain == DECODER)
333 ret = iris_vdec_qbuf(inst, vbuf);
334 else
335 ret = iris_venc_qbuf(inst, vbuf);
336
337exit:
338 if (ret) {
339 iris_inst_change_state(inst, IRIS_INST_ERROR);
340 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
341 }
342 mutex_unlock(&inst->lock);
343}