1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Cedrus VPU driver
4 *
5 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
6 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
7 * Copyright (C) 2018 Bootlin
8 *
9 * Based on the vim2m driver, that is:
10 *
11 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
12 * Pawel Osciak, <pawel@osciak.com>
13 * Marek Szyprowski, <m.szyprowski@samsung.com>
14 */
15
16 #include <linux/pm_runtime.h>
17
18 #include <media/videobuf2-dma-contig.h>
19 #include <media/v4l2-device.h>
20 #include <media/v4l2-ioctl.h>
21 #include <media/v4l2-event.h>
22 #include <media/v4l2-mem2mem.h>
23
24 #include "cedrus.h"
25 #include "cedrus_video.h"
26 #include "cedrus_dec.h"
27 #include "cedrus_hw.h"
28
29 #define CEDRUS_DECODE_SRC BIT(0)
30 #define CEDRUS_DECODE_DST BIT(1)
31
32 #define CEDRUS_MIN_WIDTH 16U
33 #define CEDRUS_MIN_HEIGHT 16U
34 #define CEDRUS_MAX_WIDTH 4096U
35 #define CEDRUS_MAX_HEIGHT 2304U
36
37 static struct cedrus_format cedrus_formats[] = {
38 {
39 .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE,
40 .directions = CEDRUS_DECODE_SRC,
41 .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC,
42 },
43 {
44 .pixelformat = V4L2_PIX_FMT_H264_SLICE,
45 .directions = CEDRUS_DECODE_SRC,
46 .capabilities = CEDRUS_CAPABILITY_H264_DEC,
47 },
48 {
49 .pixelformat = V4L2_PIX_FMT_HEVC_SLICE,
50 .directions = CEDRUS_DECODE_SRC,
51 .capabilities = CEDRUS_CAPABILITY_H265_DEC,
52 },
53 {
54 .pixelformat = V4L2_PIX_FMT_VP8_FRAME,
55 .directions = CEDRUS_DECODE_SRC,
56 .capabilities = CEDRUS_CAPABILITY_VP8_DEC,
57 },
58 {
59 .pixelformat = V4L2_PIX_FMT_NV12,
60 .directions = CEDRUS_DECODE_DST,
61 .capabilities = CEDRUS_CAPABILITY_UNTILED,
62 },
63 {
64 .pixelformat = V4L2_PIX_FMT_NV12_32L32,
65 .directions = CEDRUS_DECODE_DST,
66 },
67 };
68
69 #define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats)
70
cedrus_file2ctx(struct file * file)71 static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
72 {
73 return container_of(file->private_data, struct cedrus_ctx, fh);
74 }
75
cedrus_find_format(struct cedrus_ctx * ctx,u32 pixelformat,u32 directions)76 static struct cedrus_format *cedrus_find_format(struct cedrus_ctx *ctx,
77 u32 pixelformat, u32 directions)
78 {
79 struct cedrus_format *first_valid_fmt = NULL;
80 struct cedrus_format *fmt;
81 unsigned int i;
82
83 for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
84 fmt = &cedrus_formats[i];
85
86 if (!cedrus_is_capable(ctx, fmt->capabilities) ||
87 !(fmt->directions & directions))
88 continue;
89
90 if (fmt->pixelformat == pixelformat)
91 break;
92
93 if (!first_valid_fmt)
94 first_valid_fmt = fmt;
95 }
96
97 if (i == CEDRUS_FORMATS_COUNT)
98 return first_valid_fmt;
99
100 return &cedrus_formats[i];
101 }
102
cedrus_prepare_format(struct v4l2_pix_format * pix_fmt)103 void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
104 {
105 unsigned int width = pix_fmt->width;
106 unsigned int height = pix_fmt->height;
107 unsigned int sizeimage = pix_fmt->sizeimage;
108 unsigned int bytesperline = pix_fmt->bytesperline;
109
110 pix_fmt->field = V4L2_FIELD_NONE;
111
112 /* Limit to hardware min/max. */
113 width = clamp(width, CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
114 height = clamp(height, CEDRUS_MIN_HEIGHT, CEDRUS_MAX_HEIGHT);
115
116 switch (pix_fmt->pixelformat) {
117 case V4L2_PIX_FMT_MPEG2_SLICE:
118 case V4L2_PIX_FMT_H264_SLICE:
119 case V4L2_PIX_FMT_HEVC_SLICE:
120 case V4L2_PIX_FMT_VP8_FRAME:
121 /* Zero bytes per line for encoded source. */
122 bytesperline = 0;
123 /* Choose some minimum size since this can't be 0 */
124 sizeimage = max_t(u32, SZ_1K, sizeimage);
125 break;
126
127 case V4L2_PIX_FMT_NV12_32L32:
128 /* 32-aligned stride. */
129 bytesperline = ALIGN(width, 32);
130
131 /* 32-aligned height. */
132 height = ALIGN(height, 32);
133
134 /* Luma plane size. */
135 sizeimage = bytesperline * height;
136
137 /* Chroma plane size. */
138 sizeimage += bytesperline * ALIGN(height, 64) / 2;
139
140 break;
141
142 case V4L2_PIX_FMT_NV12:
143 /* 16-aligned stride. */
144 bytesperline = ALIGN(width, 16);
145
146 /* 16-aligned height. */
147 height = ALIGN(height, 16);
148
149 /* Luma plane size. */
150 sizeimage = bytesperline * height;
151
152 /* Chroma plane size. */
153 sizeimage += bytesperline * height / 2;
154
155 break;
156 }
157
158 pix_fmt->width = width;
159 pix_fmt->height = height;
160
161 pix_fmt->bytesperline = bytesperline;
162 pix_fmt->sizeimage = sizeimage;
163 }
164
cedrus_querycap(struct file * file,void * priv,struct v4l2_capability * cap)165 static int cedrus_querycap(struct file *file, void *priv,
166 struct v4l2_capability *cap)
167 {
168 strscpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver));
169 strscpy(cap->card, CEDRUS_NAME, sizeof(cap->card));
170 snprintf(cap->bus_info, sizeof(cap->bus_info),
171 "platform:%s", CEDRUS_NAME);
172
173 return 0;
174 }
175
cedrus_enum_fmt(struct file * file,struct v4l2_fmtdesc * f,u32 direction)176 static int cedrus_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
177 u32 direction)
178 {
179 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
180 unsigned int i, index;
181
182 /* Index among formats that match the requested direction. */
183 index = 0;
184
185 for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) {
186 if (!cedrus_is_capable(ctx, cedrus_formats[i].capabilities))
187 continue;
188
189 if (!(cedrus_formats[i].directions & direction))
190 continue;
191
192 if (index == f->index)
193 break;
194
195 index++;
196 }
197
198 /* Matched format. */
199 if (i < CEDRUS_FORMATS_COUNT) {
200 f->pixelformat = cedrus_formats[i].pixelformat;
201
202 return 0;
203 }
204
205 return -EINVAL;
206 }
207
cedrus_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)208 static int cedrus_enum_fmt_vid_cap(struct file *file, void *priv,
209 struct v4l2_fmtdesc *f)
210 {
211 return cedrus_enum_fmt(file, f, CEDRUS_DECODE_DST);
212 }
213
cedrus_enum_fmt_vid_out(struct file * file,void * priv,struct v4l2_fmtdesc * f)214 static int cedrus_enum_fmt_vid_out(struct file *file, void *priv,
215 struct v4l2_fmtdesc *f)
216 {
217 return cedrus_enum_fmt(file, f, CEDRUS_DECODE_SRC);
218 }
219
cedrus_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)220 static int cedrus_g_fmt_vid_cap(struct file *file, void *priv,
221 struct v4l2_format *f)
222 {
223 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
224
225 f->fmt.pix = ctx->dst_fmt;
226 return 0;
227 }
228
cedrus_g_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)229 static int cedrus_g_fmt_vid_out(struct file *file, void *priv,
230 struct v4l2_format *f)
231 {
232 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
233
234 f->fmt.pix = ctx->src_fmt;
235 return 0;
236 }
237
cedrus_try_fmt_vid_cap_p(struct cedrus_ctx * ctx,struct v4l2_pix_format * pix_fmt)238 static int cedrus_try_fmt_vid_cap_p(struct cedrus_ctx *ctx,
239 struct v4l2_pix_format *pix_fmt)
240 {
241 struct cedrus_format *fmt =
242 cedrus_find_format(ctx, pix_fmt->pixelformat,
243 CEDRUS_DECODE_DST);
244
245 if (!fmt)
246 return -EINVAL;
247
248 pix_fmt->pixelformat = fmt->pixelformat;
249 pix_fmt->width = ctx->src_fmt.width;
250 pix_fmt->height = ctx->src_fmt.height;
251 cedrus_prepare_format(pix_fmt);
252
253 if (ctx->current_codec->extra_cap_size)
254 pix_fmt->sizeimage +=
255 ctx->current_codec->extra_cap_size(ctx, pix_fmt);
256
257 return 0;
258 }
259
cedrus_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)260 static int cedrus_try_fmt_vid_cap(struct file *file, void *priv,
261 struct v4l2_format *f)
262 {
263 return cedrus_try_fmt_vid_cap_p(cedrus_file2ctx(file), &f->fmt.pix);
264 }
265
cedrus_try_fmt_vid_out_p(struct cedrus_ctx * ctx,struct v4l2_pix_format * pix_fmt)266 static int cedrus_try_fmt_vid_out_p(struct cedrus_ctx *ctx,
267 struct v4l2_pix_format *pix_fmt)
268 {
269 struct cedrus_format *fmt =
270 cedrus_find_format(ctx, pix_fmt->pixelformat,
271 CEDRUS_DECODE_SRC);
272
273 if (!fmt)
274 return -EINVAL;
275
276 pix_fmt->pixelformat = fmt->pixelformat;
277 cedrus_prepare_format(pix_fmt);
278
279 return 0;
280 }
281
cedrus_try_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)282 static int cedrus_try_fmt_vid_out(struct file *file, void *priv,
283 struct v4l2_format *f)
284 {
285 return cedrus_try_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
286 }
287
cedrus_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)288 static int cedrus_s_fmt_vid_cap(struct file *file, void *priv,
289 struct v4l2_format *f)
290 {
291 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
292 struct vb2_queue *vq;
293 int ret;
294
295 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
296 if (vb2_is_busy(vq))
297 return -EBUSY;
298
299 ret = cedrus_try_fmt_vid_cap(file, priv, f);
300 if (ret)
301 return ret;
302
303 ctx->dst_fmt = f->fmt.pix;
304
305 return 0;
306 }
307
cedrus_reset_cap_format(struct cedrus_ctx * ctx)308 void cedrus_reset_cap_format(struct cedrus_ctx *ctx)
309 {
310 ctx->dst_fmt.pixelformat = 0;
311 cedrus_try_fmt_vid_cap_p(ctx, &ctx->dst_fmt);
312 }
313
cedrus_s_fmt_vid_out_p(struct cedrus_ctx * ctx,struct v4l2_pix_format * pix_fmt)314 static int cedrus_s_fmt_vid_out_p(struct cedrus_ctx *ctx,
315 struct v4l2_pix_format *pix_fmt)
316 {
317 struct vb2_queue *vq;
318 int ret;
319
320 ret = cedrus_try_fmt_vid_out_p(ctx, pix_fmt);
321 if (ret)
322 return ret;
323
324 ctx->src_fmt = *pix_fmt;
325
326 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
327
328 switch (ctx->src_fmt.pixelformat) {
329 case V4L2_PIX_FMT_H264_SLICE:
330 case V4L2_PIX_FMT_HEVC_SLICE:
331 vq->subsystem_flags |=
332 VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
333 break;
334 default:
335 vq->subsystem_flags &=
336 ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
337 break;
338 }
339
340 switch (ctx->src_fmt.pixelformat) {
341 case V4L2_PIX_FMT_MPEG2_SLICE:
342 ctx->current_codec = &cedrus_dec_ops_mpeg2;
343 break;
344 case V4L2_PIX_FMT_H264_SLICE:
345 ctx->current_codec = &cedrus_dec_ops_h264;
346 break;
347 case V4L2_PIX_FMT_HEVC_SLICE:
348 ctx->current_codec = &cedrus_dec_ops_h265;
349 break;
350 case V4L2_PIX_FMT_VP8_FRAME:
351 ctx->current_codec = &cedrus_dec_ops_vp8;
352 break;
353 }
354
355 /* Propagate format information to capture. */
356 ctx->dst_fmt.colorspace = pix_fmt->colorspace;
357 ctx->dst_fmt.xfer_func = pix_fmt->xfer_func;
358 ctx->dst_fmt.ycbcr_enc = pix_fmt->ycbcr_enc;
359 ctx->dst_fmt.quantization = pix_fmt->quantization;
360 cedrus_reset_cap_format(ctx);
361
362 return 0;
363 }
364
cedrus_reset_out_format(struct cedrus_ctx * ctx)365 void cedrus_reset_out_format(struct cedrus_ctx *ctx)
366 {
367 ctx->src_fmt.pixelformat = 0;
368 cedrus_s_fmt_vid_out_p(ctx, &ctx->src_fmt);
369 }
370
cedrus_s_fmt_vid_out(struct file * file,void * priv,struct v4l2_format * f)371 static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
372 struct v4l2_format *f)
373 {
374 struct cedrus_ctx *ctx = cedrus_file2ctx(file);
375 struct vb2_queue *vq;
376 struct vb2_queue *peer_vq;
377
378 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
379 /*
380 * In order to support dynamic resolution change,
381 * the decoder admits a resolution change, as long
382 * as the pixelformat remains. Can't be done if streaming.
383 */
384 if (vb2_is_streaming(vq) || (vb2_is_busy(vq) &&
385 f->fmt.pix.pixelformat != ctx->src_fmt.pixelformat))
386 return -EBUSY;
387 /*
388 * Since format change on the OUTPUT queue will reset
389 * the CAPTURE queue, we can't allow doing so
390 * when the CAPTURE queue has buffers allocated.
391 */
392 peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
393 V4L2_BUF_TYPE_VIDEO_CAPTURE);
394 if (vb2_is_busy(peer_vq))
395 return -EBUSY;
396
397 return cedrus_s_fmt_vid_out_p(cedrus_file2ctx(file), &f->fmt.pix);
398 }
399
400 const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
401 .vidioc_querycap = cedrus_querycap,
402
403 .vidioc_enum_fmt_vid_cap = cedrus_enum_fmt_vid_cap,
404 .vidioc_g_fmt_vid_cap = cedrus_g_fmt_vid_cap,
405 .vidioc_try_fmt_vid_cap = cedrus_try_fmt_vid_cap,
406 .vidioc_s_fmt_vid_cap = cedrus_s_fmt_vid_cap,
407
408 .vidioc_enum_fmt_vid_out = cedrus_enum_fmt_vid_out,
409 .vidioc_g_fmt_vid_out = cedrus_g_fmt_vid_out,
410 .vidioc_try_fmt_vid_out = cedrus_try_fmt_vid_out,
411 .vidioc_s_fmt_vid_out = cedrus_s_fmt_vid_out,
412
413 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
414 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
415 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
416 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
417 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
418 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
419 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
420
421 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
422 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
423
424 .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd,
425 .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd,
426
427 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
428 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
429 };
430
cedrus_queue_setup(struct vb2_queue * vq,unsigned int * nbufs,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])431 static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
432 unsigned int *nplanes, unsigned int sizes[],
433 struct device *alloc_devs[])
434 {
435 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
436 struct v4l2_pix_format *pix_fmt;
437
438 if (V4L2_TYPE_IS_OUTPUT(vq->type))
439 pix_fmt = &ctx->src_fmt;
440 else
441 pix_fmt = &ctx->dst_fmt;
442
443 if (*nplanes) {
444 if (sizes[0] < pix_fmt->sizeimage)
445 return -EINVAL;
446 } else {
447 sizes[0] = pix_fmt->sizeimage;
448 *nplanes = 1;
449 }
450
451 return 0;
452 }
453
cedrus_queue_cleanup(struct vb2_queue * vq,u32 state)454 static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state)
455 {
456 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
457 struct vb2_v4l2_buffer *vbuf;
458
459 for (;;) {
460 if (V4L2_TYPE_IS_OUTPUT(vq->type))
461 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
462 else
463 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
464
465 if (!vbuf)
466 return;
467
468 v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
469 &ctx->hdl);
470 v4l2_m2m_buf_done(vbuf, state);
471 }
472 }
473
cedrus_buf_out_validate(struct vb2_buffer * vb)474 static int cedrus_buf_out_validate(struct vb2_buffer *vb)
475 {
476 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
477
478 vbuf->field = V4L2_FIELD_NONE;
479 return 0;
480 }
481
cedrus_buf_prepare(struct vb2_buffer * vb)482 static int cedrus_buf_prepare(struct vb2_buffer *vb)
483 {
484 struct vb2_queue *vq = vb->vb2_queue;
485 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
486 struct v4l2_pix_format *pix_fmt;
487
488 if (V4L2_TYPE_IS_OUTPUT(vq->type))
489 pix_fmt = &ctx->src_fmt;
490 else
491 pix_fmt = &ctx->dst_fmt;
492
493 if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
494 return -EINVAL;
495
496 /*
497 * Buffer's bytesused must be written by driver for CAPTURE buffers.
498 * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets
499 * it to buffer length).
500 */
501 if (V4L2_TYPE_IS_CAPTURE(vq->type))
502 vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
503
504 return 0;
505 }
506
cedrus_start_streaming(struct vb2_queue * vq,unsigned int count)507 static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
508 {
509 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
510 struct cedrus_dev *dev = ctx->dev;
511 int ret = 0;
512
513 if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
514 ret = pm_runtime_resume_and_get(dev->dev);
515 if (ret < 0)
516 goto err_cleanup;
517
518 if (ctx->current_codec->start) {
519 ret = ctx->current_codec->start(ctx);
520 if (ret)
521 goto err_pm;
522 }
523 }
524
525 return 0;
526
527 err_pm:
528 pm_runtime_put(dev->dev);
529 err_cleanup:
530 cedrus_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
531
532 return ret;
533 }
534
cedrus_stop_streaming(struct vb2_queue * vq)535 static void cedrus_stop_streaming(struct vb2_queue *vq)
536 {
537 struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
538 struct cedrus_dev *dev = ctx->dev;
539
540 if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
541 if (ctx->current_codec->stop)
542 ctx->current_codec->stop(ctx);
543
544 pm_runtime_put(dev->dev);
545 }
546
547 cedrus_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
548 }
549
cedrus_buf_queue(struct vb2_buffer * vb)550 static void cedrus_buf_queue(struct vb2_buffer *vb)
551 {
552 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
553 struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
554
555 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
556 }
557
cedrus_buf_request_complete(struct vb2_buffer * vb)558 static void cedrus_buf_request_complete(struct vb2_buffer *vb)
559 {
560 struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
561
562 v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
563 }
564
565 static const struct vb2_ops cedrus_qops = {
566 .queue_setup = cedrus_queue_setup,
567 .buf_prepare = cedrus_buf_prepare,
568 .buf_queue = cedrus_buf_queue,
569 .buf_out_validate = cedrus_buf_out_validate,
570 .buf_request_complete = cedrus_buf_request_complete,
571 .start_streaming = cedrus_start_streaming,
572 .stop_streaming = cedrus_stop_streaming,
573 .wait_prepare = vb2_ops_wait_prepare,
574 .wait_finish = vb2_ops_wait_finish,
575 };
576
cedrus_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)577 int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
578 struct vb2_queue *dst_vq)
579 {
580 struct cedrus_ctx *ctx = priv;
581 int ret;
582
583 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
584 src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
585 src_vq->drv_priv = ctx;
586 src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
587 src_vq->ops = &cedrus_qops;
588 src_vq->mem_ops = &vb2_dma_contig_memops;
589 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
590 src_vq->lock = &ctx->dev->dev_mutex;
591 src_vq->dev = ctx->dev->dev;
592 src_vq->supports_requests = true;
593 src_vq->requires_requests = true;
594
595 ret = vb2_queue_init(src_vq);
596 if (ret)
597 return ret;
598
599 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
600 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
601 dst_vq->drv_priv = ctx;
602 dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
603 dst_vq->ops = &cedrus_qops;
604 dst_vq->mem_ops = &vb2_dma_contig_memops;
605 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
606 dst_vq->lock = &ctx->dev->dev_mutex;
607 dst_vq->dev = ctx->dev->dev;
608
609 return vb2_queue_init(dst_vq);
610 }
611