]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
Merge tag 'linux-kselftest-5.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / staging / media / rockchip / vpu / rockchip_vpu_enc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockchip VPU codec driver
4  *
5  * Copyright (C) 2018 Collabora, Ltd.
6  * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
7  *      Alpha Lin <Alpha.Lin@rock-chips.com>
8  *      Jeffy Chen <jeffy.chen@rock-chips.com>
9  *
10  * Copyright 2018 Google LLC.
11  *      Tomasz Figa <tfiga@chromium.org>
12  *
13  * Based on s5p-mfc driver by Samsung Electronics Co., Ltd.
14  * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
15  */
16
17 #include <linux/interrupt.h>
18 #include <linux/io.h>
19 #include <linux/module.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/videodev2.h>
22 #include <linux/workqueue.h>
23 #include <media/v4l2-ctrls.h>
24 #include <media/v4l2-event.h>
25 #include <media/v4l2-mem2mem.h>
26 #include <media/videobuf2-core.h>
27 #include <media/videobuf2-dma-sg.h>
28
29 #include "rockchip_vpu.h"
30 #include "rockchip_vpu_hw.h"
31 #include "rockchip_vpu_common.h"
32
33 /**
34  * struct v4l2_format_info - information about a V4L2 format
35  * @format: 4CC format identifier (V4L2_PIX_FMT_*)
36  * @header_size: Size of header, optional and used by compressed formats
37  * @num_planes: Number of planes (1 to 3)
38  * @cpp: Number of bytes per pixel (per plane)
39  * @hsub: Horizontal chroma subsampling factor
40  * @vsub: Vertical chroma subsampling factor
41  * @is_compressed: Is it a compressed format?
42  * @multiplanar: Is it a multiplanar variant format? (e.g. NV12M)
43  */
44 struct rockchip_vpu_v4l2_format_info {
45         u32 format;
46         u32 header_size;
47         u8 num_planes;
48         u8 cpp[3];
49         u8 hsub;
50         u8 vsub;
51         u8 is_compressed;
52         u8 multiplanar;
53 };
54
55 static const struct rockchip_vpu_v4l2_format_info *
56 rockchip_vpu_v4l2_format_info(u32 format)
57 {
58         static const struct rockchip_vpu_v4l2_format_info formats[] = {
59                 { .format = V4L2_PIX_FMT_YUV420M,       .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .multiplanar = 1 },
60                 { .format = V4L2_PIX_FMT_NV12M,         .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .multiplanar = 1 },
61                 { .format = V4L2_PIX_FMT_YUYV,          .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
62                 { .format = V4L2_PIX_FMT_UYVY,          .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 },
63         };
64         unsigned int i;
65
66         for (i = 0; i < ARRAY_SIZE(formats); ++i) {
67                 if (formats[i].format == format)
68                         return &formats[i];
69         }
70
71         vpu_err("Unsupported V4L 4CC format (%08x)\n", format);
72         return NULL;
73 }
74
75 static void
76 fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
77                int pixelformat, int width, int height)
78 {
79         const struct rockchip_vpu_v4l2_format_info *info;
80         struct v4l2_plane_pix_format *plane;
81         int i;
82
83         info = rockchip_vpu_v4l2_format_info(pixelformat);
84         if (!info)
85                 return;
86
87         pixfmt->width = width;
88         pixfmt->height = height;
89         pixfmt->pixelformat = pixelformat;
90
91         if (!info->multiplanar) {
92                 pixfmt->num_planes = 1;
93                 plane = &pixfmt->plane_fmt[0];
94                 plane->bytesperline = info->is_compressed ?
95                                         0 : width * info->cpp[0];
96                 plane->sizeimage = info->header_size;
97                 for (i = 0; i < info->num_planes; i++) {
98                         unsigned int hsub = (i == 0) ? 1 : info->hsub;
99                         unsigned int vsub = (i == 0) ? 1 : info->vsub;
100
101                         plane->sizeimage += info->cpp[i] *
102                                 DIV_ROUND_UP(width, hsub) *
103                                 DIV_ROUND_UP(height, vsub);
104                 }
105         } else {
106                 pixfmt->num_planes = info->num_planes;
107                 for (i = 0; i < info->num_planes; i++) {
108                         unsigned int hsub = (i == 0) ? 1 : info->hsub;
109                         unsigned int vsub = (i == 0) ? 1 : info->vsub;
110
111                         plane = &pixfmt->plane_fmt[i];
112                         plane->bytesperline =
113                                 info->cpp[i] * DIV_ROUND_UP(width, hsub);
114                         plane->sizeimage =
115                                 plane->bytesperline * DIV_ROUND_UP(height, vsub);
116                 }
117         }
118 }
119
120 static const struct rockchip_vpu_fmt *
121 rockchip_vpu_find_format(struct rockchip_vpu_ctx *ctx, u32 fourcc)
122 {
123         struct rockchip_vpu_dev *dev = ctx->dev;
124         const struct rockchip_vpu_fmt *formats;
125         unsigned int num_fmts, i;
126
127         formats = dev->variant->enc_fmts;
128         num_fmts = dev->variant->num_enc_fmts;
129         for (i = 0; i < num_fmts; i++)
130                 if (formats[i].fourcc == fourcc)
131                         return &formats[i];
132         return NULL;
133 }
134
135 static const struct rockchip_vpu_fmt *
136 rockchip_vpu_get_default_fmt(struct rockchip_vpu_ctx *ctx, bool bitstream)
137 {
138         struct rockchip_vpu_dev *dev = ctx->dev;
139         const struct rockchip_vpu_fmt *formats;
140         unsigned int num_fmts, i;
141
142         formats = dev->variant->enc_fmts;
143         num_fmts = dev->variant->num_enc_fmts;
144         for (i = 0; i < num_fmts; i++) {
145                 if (bitstream == (formats[i].codec_mode != RK_VPU_MODE_NONE))
146                         return &formats[i];
147         }
148         return NULL;
149 }
150
151 static int vidioc_querycap(struct file *file, void *priv,
152                            struct v4l2_capability *cap)
153 {
154         struct rockchip_vpu_dev *vpu = video_drvdata(file);
155         struct video_device *vdev = video_devdata(file);
156
157         strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
158         strscpy(cap->card, vdev->name, sizeof(cap->card));
159         snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
160                  vpu->dev->driver->name);
161         return 0;
162 }
163
164 static int vidioc_enum_framesizes(struct file *file, void *priv,
165                                   struct v4l2_frmsizeenum *fsize)
166 {
167         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
168         const struct rockchip_vpu_fmt *fmt;
169
170         if (fsize->index != 0) {
171                 vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
172                           fsize->index);
173                 return -EINVAL;
174         }
175
176         fmt = rockchip_vpu_find_format(ctx, fsize->pixel_format);
177         if (!fmt) {
178                 vpu_debug(0, "unsupported bitstream format (%08x)\n",
179                           fsize->pixel_format);
180                 return -EINVAL;
181         }
182
183         /* This only makes sense for coded formats */
184         if (fmt->codec_mode == RK_VPU_MODE_NONE)
185                 return -EINVAL;
186
187         fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
188         fsize->stepwise = fmt->frmsize;
189
190         return 0;
191 }
192
193 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
194                                           struct v4l2_fmtdesc *f)
195 {
196         struct rockchip_vpu_dev *dev = video_drvdata(file);
197         const struct rockchip_vpu_fmt *fmt;
198         const struct rockchip_vpu_fmt *formats;
199         int num_fmts, i, j = 0;
200
201         formats = dev->variant->enc_fmts;
202         num_fmts = dev->variant->num_enc_fmts;
203         for (i = 0; i < num_fmts; i++) {
204                 /* Skip uncompressed formats */
205                 if (formats[i].codec_mode == RK_VPU_MODE_NONE)
206                         continue;
207                 if (j == f->index) {
208                         fmt = &formats[i];
209                         f->pixelformat = fmt->fourcc;
210                         return 0;
211                 }
212                 ++j;
213         }
214         return -EINVAL;
215 }
216
217 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
218                                           struct v4l2_fmtdesc *f)
219 {
220         struct rockchip_vpu_dev *dev = video_drvdata(file);
221         const struct rockchip_vpu_fmt *formats;
222         const struct rockchip_vpu_fmt *fmt;
223         int num_fmts, i, j = 0;
224
225         formats = dev->variant->enc_fmts;
226         num_fmts = dev->variant->num_enc_fmts;
227         for (i = 0; i < num_fmts; i++) {
228                 if (formats[i].codec_mode != RK_VPU_MODE_NONE)
229                         continue;
230                 if (j == f->index) {
231                         fmt = &formats[i];
232                         f->pixelformat = fmt->fourcc;
233                         return 0;
234                 }
235                 ++j;
236         }
237         return -EINVAL;
238 }
239
240 static int vidioc_g_fmt_out_mplane(struct file *file, void *priv,
241                                    struct v4l2_format *f)
242 {
243         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
244         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
245
246         vpu_debug(4, "f->type = %d\n", f->type);
247
248         *pix_mp = ctx->src_fmt;
249
250         return 0;
251 }
252
253 static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv,
254                                    struct v4l2_format *f)
255 {
256         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
257         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
258
259         vpu_debug(4, "f->type = %d\n", f->type);
260
261         *pix_mp = ctx->dst_fmt;
262
263         return 0;
264 }
265
266 static int
267 vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
268 {
269         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
270         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
271         const struct rockchip_vpu_fmt *fmt;
272
273         vpu_debug(4, "%c%c%c%c\n",
274                   (pix_mp->pixelformat & 0x7f),
275                   (pix_mp->pixelformat >> 8) & 0x7f,
276                   (pix_mp->pixelformat >> 16) & 0x7f,
277                   (pix_mp->pixelformat >> 24) & 0x7f);
278
279         fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
280         if (!fmt) {
281                 fmt = rockchip_vpu_get_default_fmt(ctx, true);
282                 f->fmt.pix.pixelformat = fmt->fourcc;
283         }
284
285         pix_mp->num_planes = 1;
286         pix_mp->field = V4L2_FIELD_NONE;
287         pix_mp->width = clamp(pix_mp->width,
288                               fmt->frmsize.min_width,
289                               fmt->frmsize.max_width);
290         pix_mp->height = clamp(pix_mp->height,
291                                fmt->frmsize.min_height,
292                                fmt->frmsize.max_height);
293         /* Round up to macroblocks. */
294         pix_mp->width = round_up(pix_mp->width, JPEG_MB_DIM);
295         pix_mp->height = round_up(pix_mp->height, JPEG_MB_DIM);
296
297         /*
298          * For compressed formats the application can specify
299          * sizeimage. If the application passes a zero sizeimage,
300          * let's default to the maximum frame size.
301          */
302         if (!pix_mp->plane_fmt[0].sizeimage)
303                 pix_mp->plane_fmt[0].sizeimage = fmt->header_size +
304                         pix_mp->width * pix_mp->height * fmt->max_depth;
305         memset(pix_mp->plane_fmt[0].reserved, 0,
306                sizeof(pix_mp->plane_fmt[0].reserved));
307         return 0;
308 }
309
310 static int
311 vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
312 {
313         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
314         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
315         const struct rockchip_vpu_fmt *fmt;
316         unsigned int width, height;
317         int i;
318
319         vpu_debug(4, "%c%c%c%c\n",
320                   (pix_mp->pixelformat & 0x7f),
321                   (pix_mp->pixelformat >> 8) & 0x7f,
322                   (pix_mp->pixelformat >> 16) & 0x7f,
323                   (pix_mp->pixelformat >> 24) & 0x7f);
324
325         fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
326         if (!fmt) {
327                 fmt = rockchip_vpu_get_default_fmt(ctx, false);
328                 f->fmt.pix.pixelformat = fmt->fourcc;
329         }
330
331         pix_mp->field = V4L2_FIELD_NONE;
332         width = clamp(pix_mp->width,
333                       ctx->vpu_dst_fmt->frmsize.min_width,
334                       ctx->vpu_dst_fmt->frmsize.max_width);
335         height = clamp(pix_mp->height,
336                        ctx->vpu_dst_fmt->frmsize.min_height,
337                        ctx->vpu_dst_fmt->frmsize.max_height);
338         /* Round up to macroblocks. */
339         width = round_up(width, JPEG_MB_DIM);
340         height = round_up(height, JPEG_MB_DIM);
341
342         /* Fill remaining fields */
343         fill_pixfmt_mp(pix_mp, fmt->fourcc, width, height);
344
345         for (i = 0; i < pix_mp->num_planes; i++) {
346                 memset(pix_mp->plane_fmt[i].reserved, 0,
347                        sizeof(pix_mp->plane_fmt[i].reserved));
348         }
349         return 0;
350 }
351
352 void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu,
353                                     struct rockchip_vpu_ctx *ctx)
354 {
355         struct v4l2_pix_format_mplane *fmt = &ctx->dst_fmt;
356
357         ctx->vpu_dst_fmt = rockchip_vpu_get_default_fmt(ctx, true);
358
359         memset(fmt, 0, sizeof(*fmt));
360
361         fmt->num_planes = 1;
362         fmt->width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
363                            ctx->vpu_dst_fmt->frmsize.max_width);
364         fmt->height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
365                             ctx->vpu_dst_fmt->frmsize.max_height);
366         fmt->pixelformat = ctx->vpu_dst_fmt->fourcc;
367         fmt->field = V4L2_FIELD_NONE;
368         fmt->colorspace = V4L2_COLORSPACE_JPEG,
369         fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
370         fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
371         fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
372
373         fmt->plane_fmt[0].sizeimage = ctx->vpu_dst_fmt->header_size +
374                 fmt->width * fmt->height * ctx->vpu_dst_fmt->max_depth;
375 }
376
377 void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu,
378                                     struct rockchip_vpu_ctx *ctx)
379 {
380         struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt;
381         unsigned int width, height;
382
383         ctx->vpu_src_fmt = rockchip_vpu_get_default_fmt(ctx, false);
384
385         memset(fmt, 0, sizeof(*fmt));
386
387         width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
388                       ctx->vpu_dst_fmt->frmsize.max_width);
389         height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
390                        ctx->vpu_dst_fmt->frmsize.max_height);
391         fmt->field = V4L2_FIELD_NONE;
392         fmt->colorspace = V4L2_COLORSPACE_JPEG,
393         fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
394         fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
395         fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
396
397         fill_pixfmt_mp(fmt, ctx->vpu_src_fmt->fourcc, width, height);
398 }
399
400 static int
401 vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
402 {
403         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
404         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
405         struct vb2_queue *vq;
406         int ret;
407
408         /* Change not allowed if queue is streaming. */
409         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
410         if (vb2_is_streaming(vq))
411                 return -EBUSY;
412
413         ret = vidioc_try_fmt_out_mplane(file, priv, f);
414         if (ret)
415                 return ret;
416
417         ctx->vpu_src_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
418         ctx->src_fmt = *pix_mp;
419
420         /* Propagate to the CAPTURE format */
421         ctx->dst_fmt.colorspace = pix_mp->colorspace;
422         ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc;
423         ctx->dst_fmt.xfer_func = pix_mp->xfer_func;
424         ctx->dst_fmt.quantization = pix_mp->quantization;
425         ctx->dst_fmt.width = pix_mp->width;
426         ctx->dst_fmt.height = pix_mp->height;
427
428         vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode);
429         vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
430                   pix_mp->width, pix_mp->height,
431                   JPEG_MB_WIDTH(pix_mp->width),
432                   JPEG_MB_HEIGHT(pix_mp->height));
433         return 0;
434 }
435
436 static int
437 vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
438 {
439         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
440         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
441         struct rockchip_vpu_dev *vpu = ctx->dev;
442         struct vb2_queue *vq, *peer_vq;
443         int ret;
444
445         /* Change not allowed if queue is streaming. */
446         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
447         if (vb2_is_streaming(vq))
448                 return -EBUSY;
449
450         /*
451          * Since format change on the CAPTURE queue will reset
452          * the OUTPUT queue, we can't allow doing so
453          * when the OUTPUT queue has buffers allocated.
454          */
455         peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
456                                   V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
457         if (vb2_is_busy(peer_vq) &&
458             (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
459              pix_mp->height != ctx->dst_fmt.height ||
460              pix_mp->width != ctx->dst_fmt.width))
461                 return -EBUSY;
462
463         ret = vidioc_try_fmt_cap_mplane(file, priv, f);
464         if (ret)
465                 return ret;
466
467         ctx->vpu_dst_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
468         ctx->dst_fmt = *pix_mp;
469
470         vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode);
471         vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
472                   pix_mp->width, pix_mp->height,
473                   JPEG_MB_WIDTH(pix_mp->width),
474                   JPEG_MB_HEIGHT(pix_mp->height));
475
476         /*
477          * Current raw format might have become invalid with newly
478          * selected codec, so reset it to default just to be safe and
479          * keep internal driver state sane. User is mandated to set
480          * the raw format again after we return, so we don't need
481          * anything smarter.
482          */
483         rockchip_vpu_enc_reset_src_fmt(vpu, ctx);
484         return 0;
485 }
486
487 const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops = {
488         .vidioc_querycap = vidioc_querycap,
489         .vidioc_enum_framesizes = vidioc_enum_framesizes,
490
491         .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane,
492         .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane,
493         .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane,
494         .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane,
495         .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane,
496         .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane,
497         .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
498         .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
499
500         .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
501         .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
502         .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
503         .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
504         .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
505         .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
506         .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
507
508         .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
509         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
510
511         .vidioc_streamon = v4l2_m2m_ioctl_streamon,
512         .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
513 };
514
515 static int
516 rockchip_vpu_queue_setup(struct vb2_queue *vq,
517                          unsigned int *num_buffers,
518                          unsigned int *num_planes,
519                          unsigned int sizes[],
520                          struct device *alloc_devs[])
521 {
522         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
523         struct v4l2_pix_format_mplane *pixfmt;
524         int i;
525
526         switch (vq->type) {
527         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
528                 pixfmt = &ctx->dst_fmt;
529                 break;
530         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
531                 pixfmt = &ctx->src_fmt;
532                 break;
533         default:
534                 vpu_err("invalid queue type: %d\n", vq->type);
535                 return -EINVAL;
536         }
537
538         if (*num_planes) {
539                 if (*num_planes != pixfmt->num_planes)
540                         return -EINVAL;
541                 for (i = 0; i < pixfmt->num_planes; ++i)
542                         if (sizes[i] < pixfmt->plane_fmt[i].sizeimage)
543                                 return -EINVAL;
544                 return 0;
545         }
546
547         *num_planes = pixfmt->num_planes;
548         for (i = 0; i < pixfmt->num_planes; ++i)
549                 sizes[i] = pixfmt->plane_fmt[i].sizeimage;
550         return 0;
551 }
552
553 static int rockchip_vpu_buf_prepare(struct vb2_buffer *vb)
554 {
555         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
556         struct vb2_queue *vq = vb->vb2_queue;
557         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
558         struct v4l2_pix_format_mplane *pixfmt;
559         unsigned int sz;
560         int ret = 0;
561         int i;
562
563         switch (vq->type) {
564         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
565                 pixfmt = &ctx->dst_fmt;
566                 break;
567         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
568                 pixfmt = &ctx->src_fmt;
569
570                 if (vbuf->field == V4L2_FIELD_ANY)
571                         vbuf->field = V4L2_FIELD_NONE;
572                 if (vbuf->field != V4L2_FIELD_NONE) {
573                         vpu_debug(4, "field %d not supported\n",
574                                   vbuf->field);
575                         return -EINVAL;
576                 }
577                 break;
578         default:
579                 vpu_err("invalid queue type: %d\n", vq->type);
580                 return -EINVAL;
581         }
582
583         for (i = 0; i < pixfmt->num_planes; ++i) {
584                 sz = pixfmt->plane_fmt[i].sizeimage;
585                 vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n",
586                           i, vb2_plane_size(vb, i), sz);
587                 if (vb2_plane_size(vb, i) < sz) {
588                         vpu_err("plane %d is too small\n", i);
589                         ret = -EINVAL;
590                         break;
591                 }
592         }
593
594         return ret;
595 }
596
597 static void rockchip_vpu_buf_queue(struct vb2_buffer *vb)
598 {
599         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
600         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
601
602         v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
603 }
604
605 static int rockchip_vpu_start_streaming(struct vb2_queue *q, unsigned int count)
606 {
607         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
608         enum rockchip_vpu_codec_mode codec_mode;
609
610         if (V4L2_TYPE_IS_OUTPUT(q->type))
611                 ctx->sequence_out = 0;
612         else
613                 ctx->sequence_cap = 0;
614
615         /* Set codec_ops for the chosen destination format */
616         codec_mode = ctx->vpu_dst_fmt->codec_mode;
617
618         vpu_debug(4, "Codec mode = %d\n", codec_mode);
619         ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode];
620
621         /* A bounce buffer is needed for the JPEG payload */
622         if (!V4L2_TYPE_IS_OUTPUT(q->type)) {
623                 ctx->bounce_size = ctx->dst_fmt.plane_fmt[0].sizeimage -
624                                   ctx->vpu_dst_fmt->header_size;
625                 ctx->bounce_buf = dma_alloc_attrs(ctx->dev->dev,
626                                                   ctx->bounce_size,
627                                                   &ctx->bounce_dma_addr,
628                                                   GFP_KERNEL,
629                                                   DMA_ATTR_ALLOC_SINGLE_PAGES);
630         }
631         return 0;
632 }
633
634 static void rockchip_vpu_stop_streaming(struct vb2_queue *q)
635 {
636         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
637
638         if (!V4L2_TYPE_IS_OUTPUT(q->type))
639                 dma_free_attrs(ctx->dev->dev,
640                                ctx->bounce_size,
641                                ctx->bounce_buf,
642                                ctx->bounce_dma_addr,
643                                DMA_ATTR_ALLOC_SINGLE_PAGES);
644
645         /*
646          * The mem2mem framework calls v4l2_m2m_cancel_job before
647          * .stop_streaming, so there isn't any job running and
648          * it is safe to return all the buffers.
649          */
650         for (;;) {
651                 struct vb2_v4l2_buffer *vbuf;
652
653                 if (V4L2_TYPE_IS_OUTPUT(q->type))
654                         vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
655                 else
656                         vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
657                 if (!vbuf)
658                         break;
659                 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
660         }
661 }
662
663 const struct vb2_ops rockchip_vpu_enc_queue_ops = {
664         .queue_setup = rockchip_vpu_queue_setup,
665         .buf_prepare = rockchip_vpu_buf_prepare,
666         .buf_queue = rockchip_vpu_buf_queue,
667         .start_streaming = rockchip_vpu_start_streaming,
668         .stop_streaming = rockchip_vpu_stop_streaming,
669         .wait_prepare = vb2_ops_wait_prepare,
670         .wait_finish = vb2_ops_wait_finish,
671 };