]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
Merge branch 'parisc-5.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[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
156         strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver));
157         strscpy(cap->card, vpu->vfd_enc->name, sizeof(cap->card));
158         snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s",
159                  vpu->dev->driver->name);
160         return 0;
161 }
162
163 static int vidioc_enum_framesizes(struct file *file, void *priv,
164                                   struct v4l2_frmsizeenum *fsize)
165 {
166         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
167         const struct rockchip_vpu_fmt *fmt;
168
169         if (fsize->index != 0) {
170                 vpu_debug(0, "invalid frame size index (expected 0, got %d)\n",
171                           fsize->index);
172                 return -EINVAL;
173         }
174
175         fmt = rockchip_vpu_find_format(ctx, fsize->pixel_format);
176         if (!fmt) {
177                 vpu_debug(0, "unsupported bitstream format (%08x)\n",
178                           fsize->pixel_format);
179                 return -EINVAL;
180         }
181
182         /* This only makes sense for coded formats */
183         if (fmt->codec_mode == RK_VPU_MODE_NONE)
184                 return -EINVAL;
185
186         fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
187         fsize->stepwise = fmt->frmsize;
188
189         return 0;
190 }
191
192 static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
193                                           struct v4l2_fmtdesc *f)
194 {
195         struct rockchip_vpu_dev *dev = video_drvdata(file);
196         const struct rockchip_vpu_fmt *fmt;
197         const struct rockchip_vpu_fmt *formats;
198         int num_fmts, i, j = 0;
199
200         formats = dev->variant->enc_fmts;
201         num_fmts = dev->variant->num_enc_fmts;
202         for (i = 0; i < num_fmts; i++) {
203                 /* Skip uncompressed formats */
204                 if (formats[i].codec_mode == RK_VPU_MODE_NONE)
205                         continue;
206                 if (j == f->index) {
207                         fmt = &formats[i];
208                         f->pixelformat = fmt->fourcc;
209                         return 0;
210                 }
211                 ++j;
212         }
213         return -EINVAL;
214 }
215
216 static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
217                                           struct v4l2_fmtdesc *f)
218 {
219         struct rockchip_vpu_dev *dev = video_drvdata(file);
220         const struct rockchip_vpu_fmt *formats;
221         const struct rockchip_vpu_fmt *fmt;
222         int num_fmts, i, j = 0;
223
224         formats = dev->variant->enc_fmts;
225         num_fmts = dev->variant->num_enc_fmts;
226         for (i = 0; i < num_fmts; i++) {
227                 if (formats[i].codec_mode != RK_VPU_MODE_NONE)
228                         continue;
229                 if (j == f->index) {
230                         fmt = &formats[i];
231                         f->pixelformat = fmt->fourcc;
232                         return 0;
233                 }
234                 ++j;
235         }
236         return -EINVAL;
237 }
238
239 static int vidioc_g_fmt_out_mplane(struct file *file, void *priv,
240                                    struct v4l2_format *f)
241 {
242         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
243         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
244
245         vpu_debug(4, "f->type = %d\n", f->type);
246
247         *pix_mp = ctx->src_fmt;
248
249         return 0;
250 }
251
252 static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv,
253                                    struct v4l2_format *f)
254 {
255         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
256         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
257
258         vpu_debug(4, "f->type = %d\n", f->type);
259
260         *pix_mp = ctx->dst_fmt;
261
262         return 0;
263 }
264
265 static int
266 vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
267 {
268         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
269         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
270         const struct rockchip_vpu_fmt *fmt;
271
272         vpu_debug(4, "%c%c%c%c\n",
273                   (pix_mp->pixelformat & 0x7f),
274                   (pix_mp->pixelformat >> 8) & 0x7f,
275                   (pix_mp->pixelformat >> 16) & 0x7f,
276                   (pix_mp->pixelformat >> 24) & 0x7f);
277
278         fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
279         if (!fmt) {
280                 fmt = rockchip_vpu_get_default_fmt(ctx, true);
281                 f->fmt.pix.pixelformat = fmt->fourcc;
282         }
283
284         pix_mp->num_planes = 1;
285         pix_mp->field = V4L2_FIELD_NONE;
286         pix_mp->width = clamp(pix_mp->width,
287                               fmt->frmsize.min_width,
288                               fmt->frmsize.max_width);
289         pix_mp->height = clamp(pix_mp->height,
290                                fmt->frmsize.min_height,
291                                fmt->frmsize.max_height);
292         /* Round up to macroblocks. */
293         pix_mp->width = round_up(pix_mp->width, JPEG_MB_DIM);
294         pix_mp->height = round_up(pix_mp->height, JPEG_MB_DIM);
295
296         /*
297          * For compressed formats the application can specify
298          * sizeimage. If the application passes a zero sizeimage,
299          * let's default to the maximum frame size.
300          */
301         if (!pix_mp->plane_fmt[0].sizeimage)
302                 pix_mp->plane_fmt[0].sizeimage = fmt->header_size +
303                         pix_mp->width * pix_mp->height * fmt->max_depth;
304         memset(pix_mp->plane_fmt[0].reserved, 0,
305                sizeof(pix_mp->plane_fmt[0].reserved));
306         return 0;
307 }
308
309 static int
310 vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
311 {
312         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
313         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
314         const struct rockchip_vpu_fmt *fmt;
315         unsigned int width, height;
316         int i;
317
318         vpu_debug(4, "%c%c%c%c\n",
319                   (pix_mp->pixelformat & 0x7f),
320                   (pix_mp->pixelformat >> 8) & 0x7f,
321                   (pix_mp->pixelformat >> 16) & 0x7f,
322                   (pix_mp->pixelformat >> 24) & 0x7f);
323
324         fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
325         if (!fmt) {
326                 fmt = rockchip_vpu_get_default_fmt(ctx, false);
327                 f->fmt.pix.pixelformat = fmt->fourcc;
328         }
329
330         pix_mp->field = V4L2_FIELD_NONE;
331         width = clamp(pix_mp->width,
332                       ctx->vpu_dst_fmt->frmsize.min_width,
333                       ctx->vpu_dst_fmt->frmsize.max_width);
334         height = clamp(pix_mp->height,
335                        ctx->vpu_dst_fmt->frmsize.min_height,
336                        ctx->vpu_dst_fmt->frmsize.max_height);
337         /* Round up to macroblocks. */
338         width = round_up(width, JPEG_MB_DIM);
339         height = round_up(height, JPEG_MB_DIM);
340
341         /* Fill remaining fields */
342         fill_pixfmt_mp(pix_mp, fmt->fourcc, width, height);
343
344         for (i = 0; i < pix_mp->num_planes; i++) {
345                 memset(pix_mp->plane_fmt[i].reserved, 0,
346                        sizeof(pix_mp->plane_fmt[i].reserved));
347         }
348         return 0;
349 }
350
351 void rockchip_vpu_enc_reset_dst_fmt(struct rockchip_vpu_dev *vpu,
352                                     struct rockchip_vpu_ctx *ctx)
353 {
354         struct v4l2_pix_format_mplane *fmt = &ctx->dst_fmt;
355
356         ctx->vpu_dst_fmt = rockchip_vpu_get_default_fmt(ctx, true);
357
358         memset(fmt, 0, sizeof(*fmt));
359
360         fmt->num_planes = 1;
361         fmt->width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
362                            ctx->vpu_dst_fmt->frmsize.max_width);
363         fmt->height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
364                             ctx->vpu_dst_fmt->frmsize.max_height);
365         fmt->pixelformat = ctx->vpu_dst_fmt->fourcc;
366         fmt->field = V4L2_FIELD_NONE;
367         fmt->colorspace = V4L2_COLORSPACE_JPEG,
368         fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
369         fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
370         fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
371
372         fmt->plane_fmt[0].sizeimage = ctx->vpu_dst_fmt->header_size +
373                 fmt->width * fmt->height * ctx->vpu_dst_fmt->max_depth;
374 }
375
376 void rockchip_vpu_enc_reset_src_fmt(struct rockchip_vpu_dev *vpu,
377                                     struct rockchip_vpu_ctx *ctx)
378 {
379         struct v4l2_pix_format_mplane *fmt = &ctx->src_fmt;
380         unsigned int width, height;
381
382         ctx->vpu_src_fmt = rockchip_vpu_get_default_fmt(ctx, false);
383
384         memset(fmt, 0, sizeof(*fmt));
385
386         width = clamp(fmt->width, ctx->vpu_dst_fmt->frmsize.min_width,
387                       ctx->vpu_dst_fmt->frmsize.max_width);
388         height = clamp(fmt->height, ctx->vpu_dst_fmt->frmsize.min_height,
389                        ctx->vpu_dst_fmt->frmsize.max_height);
390         fmt->field = V4L2_FIELD_NONE;
391         fmt->colorspace = V4L2_COLORSPACE_JPEG,
392         fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
393         fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
394         fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
395
396         fill_pixfmt_mp(fmt, ctx->vpu_src_fmt->fourcc, width, height);
397 }
398
399 static int
400 vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f)
401 {
402         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
403         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
404         struct vb2_queue *vq;
405         int ret;
406
407         /* Change not allowed if queue is streaming. */
408         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
409         if (vb2_is_streaming(vq))
410                 return -EBUSY;
411
412         ret = vidioc_try_fmt_out_mplane(file, priv, f);
413         if (ret)
414                 return ret;
415
416         ctx->vpu_src_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
417         ctx->src_fmt = *pix_mp;
418
419         /* Propagate to the CAPTURE format */
420         ctx->dst_fmt.colorspace = pix_mp->colorspace;
421         ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc;
422         ctx->dst_fmt.xfer_func = pix_mp->xfer_func;
423         ctx->dst_fmt.quantization = pix_mp->quantization;
424         ctx->dst_fmt.width = pix_mp->width;
425         ctx->dst_fmt.height = pix_mp->height;
426
427         vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode);
428         vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
429                   pix_mp->width, pix_mp->height,
430                   JPEG_MB_WIDTH(pix_mp->width),
431                   JPEG_MB_HEIGHT(pix_mp->height));
432         return 0;
433 }
434
435 static int
436 vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f)
437 {
438         struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
439         struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv);
440         struct rockchip_vpu_dev *vpu = ctx->dev;
441         struct vb2_queue *vq, *peer_vq;
442         int ret;
443
444         /* Change not allowed if queue is streaming. */
445         vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
446         if (vb2_is_streaming(vq))
447                 return -EBUSY;
448
449         /*
450          * Since format change on the CAPTURE queue will reset
451          * the OUTPUT queue, we can't allow doing so
452          * when the OUTPUT queue has buffers allocated.
453          */
454         peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
455                                   V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
456         if (vb2_is_busy(peer_vq) &&
457             (pix_mp->pixelformat != ctx->dst_fmt.pixelformat ||
458              pix_mp->height != ctx->dst_fmt.height ||
459              pix_mp->width != ctx->dst_fmt.width))
460                 return -EBUSY;
461
462         ret = vidioc_try_fmt_cap_mplane(file, priv, f);
463         if (ret)
464                 return ret;
465
466         ctx->vpu_dst_fmt = rockchip_vpu_find_format(ctx, pix_mp->pixelformat);
467         ctx->dst_fmt = *pix_mp;
468
469         vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode);
470         vpu_debug(0, "fmt - w: %d, h: %d, mb - w: %d, h: %d\n",
471                   pix_mp->width, pix_mp->height,
472                   JPEG_MB_WIDTH(pix_mp->width),
473                   JPEG_MB_HEIGHT(pix_mp->height));
474
475         /*
476          * Current raw format might have become invalid with newly
477          * selected codec, so reset it to default just to be safe and
478          * keep internal driver state sane. User is mandated to set
479          * the raw format again after we return, so we don't need
480          * anything smarter.
481          */
482         rockchip_vpu_enc_reset_src_fmt(vpu, ctx);
483         return 0;
484 }
485
486 const struct v4l2_ioctl_ops rockchip_vpu_enc_ioctl_ops = {
487         .vidioc_querycap = vidioc_querycap,
488         .vidioc_enum_framesizes = vidioc_enum_framesizes,
489
490         .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane,
491         .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane,
492         .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane,
493         .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane,
494         .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane,
495         .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane,
496         .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
497         .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
498
499         .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
500         .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
501         .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
502         .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
503         .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
504         .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
505         .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
506
507         .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
508         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
509
510         .vidioc_streamon = v4l2_m2m_ioctl_streamon,
511         .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
512 };
513
514 static int
515 rockchip_vpu_queue_setup(struct vb2_queue *vq,
516                          unsigned int *num_buffers,
517                          unsigned int *num_planes,
518                          unsigned int sizes[],
519                          struct device *alloc_devs[])
520 {
521         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
522         struct v4l2_pix_format_mplane *pixfmt;
523         int i;
524
525         switch (vq->type) {
526         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
527                 pixfmt = &ctx->dst_fmt;
528                 break;
529         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
530                 pixfmt = &ctx->src_fmt;
531                 break;
532         default:
533                 vpu_err("invalid queue type: %d\n", vq->type);
534                 return -EINVAL;
535         }
536
537         if (*num_planes) {
538                 if (*num_planes != pixfmt->num_planes)
539                         return -EINVAL;
540                 for (i = 0; i < pixfmt->num_planes; ++i)
541                         if (sizes[i] < pixfmt->plane_fmt[i].sizeimage)
542                                 return -EINVAL;
543                 return 0;
544         }
545
546         *num_planes = pixfmt->num_planes;
547         for (i = 0; i < pixfmt->num_planes; ++i)
548                 sizes[i] = pixfmt->plane_fmt[i].sizeimage;
549         return 0;
550 }
551
552 static int rockchip_vpu_buf_prepare(struct vb2_buffer *vb)
553 {
554         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
555         struct vb2_queue *vq = vb->vb2_queue;
556         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq);
557         struct v4l2_pix_format_mplane *pixfmt;
558         unsigned int sz;
559         int ret = 0;
560         int i;
561
562         switch (vq->type) {
563         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
564                 pixfmt = &ctx->dst_fmt;
565                 break;
566         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
567                 pixfmt = &ctx->src_fmt;
568
569                 if (vbuf->field == V4L2_FIELD_ANY)
570                         vbuf->field = V4L2_FIELD_NONE;
571                 if (vbuf->field != V4L2_FIELD_NONE) {
572                         vpu_debug(4, "field %d not supported\n",
573                                   vbuf->field);
574                         return -EINVAL;
575                 }
576                 break;
577         default:
578                 vpu_err("invalid queue type: %d\n", vq->type);
579                 return -EINVAL;
580         }
581
582         for (i = 0; i < pixfmt->num_planes; ++i) {
583                 sz = pixfmt->plane_fmt[i].sizeimage;
584                 vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n",
585                           i, vb2_plane_size(vb, i), sz);
586                 if (vb2_plane_size(vb, i) < sz) {
587                         vpu_err("plane %d is too small\n", i);
588                         ret = -EINVAL;
589                         break;
590                 }
591         }
592
593         return ret;
594 }
595
596 static void rockchip_vpu_buf_queue(struct vb2_buffer *vb)
597 {
598         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
599         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
600
601         v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
602 }
603
604 static int rockchip_vpu_start_streaming(struct vb2_queue *q, unsigned int count)
605 {
606         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
607         enum rockchip_vpu_codec_mode codec_mode;
608
609         if (V4L2_TYPE_IS_OUTPUT(q->type))
610                 ctx->sequence_out = 0;
611         else
612                 ctx->sequence_cap = 0;
613
614         /* Set codec_ops for the chosen destination format */
615         codec_mode = ctx->vpu_dst_fmt->codec_mode;
616
617         vpu_debug(4, "Codec mode = %d\n", codec_mode);
618         ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode];
619
620         /* A bounce buffer is needed for the JPEG payload */
621         if (!V4L2_TYPE_IS_OUTPUT(q->type)) {
622                 ctx->bounce_size = ctx->dst_fmt.plane_fmt[0].sizeimage -
623                                   ctx->vpu_dst_fmt->header_size;
624                 ctx->bounce_buf = dma_alloc_attrs(ctx->dev->dev,
625                                                   ctx->bounce_size,
626                                                   &ctx->bounce_dma_addr,
627                                                   GFP_KERNEL,
628                                                   DMA_ATTR_ALLOC_SINGLE_PAGES);
629         }
630         return 0;
631 }
632
633 static void rockchip_vpu_stop_streaming(struct vb2_queue *q)
634 {
635         struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q);
636
637         if (!V4L2_TYPE_IS_OUTPUT(q->type))
638                 dma_free_attrs(ctx->dev->dev,
639                                ctx->bounce_size,
640                                ctx->bounce_buf,
641                                ctx->bounce_dma_addr,
642                                DMA_ATTR_ALLOC_SINGLE_PAGES);
643
644         /*
645          * The mem2mem framework calls v4l2_m2m_cancel_job before
646          * .stop_streaming, so there isn't any job running and
647          * it is safe to return all the buffers.
648          */
649         for (;;) {
650                 struct vb2_v4l2_buffer *vbuf;
651
652                 if (V4L2_TYPE_IS_OUTPUT(q->type))
653                         vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
654                 else
655                         vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
656                 if (!vbuf)
657                         break;
658                 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
659         }
660 }
661
662 const struct vb2_ops rockchip_vpu_enc_queue_ops = {
663         .queue_setup = rockchip_vpu_queue_setup,
664         .buf_prepare = rockchip_vpu_buf_prepare,
665         .buf_queue = rockchip_vpu_buf_queue,
666         .start_streaming = rockchip_vpu_start_streaming,
667         .stop_streaming = rockchip_vpu_stop_streaming,
668         .wait_prepare = vb2_ops_wait_prepare,
669         .wait_finish = vb2_ops_wait_finish,
670 };