linux/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c
<<
>>
Prefs
   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 */
  44struct 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
  55static const struct v4l2_format_info *
  56v4l2_format_info(u32 format)
  57{
  58        static const struct 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
  75static void
  76fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
  77               int pixelformat, int width, int height)
  78{
  79        const struct v4l2_format_info *info;
  80        struct v4l2_plane_pix_format *plane;
  81        int i;
  82
  83        info = 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
 120static const struct rockchip_vpu_fmt *
 121rockchip_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
 135static const struct rockchip_vpu_fmt *
 136rockchip_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
 151static 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
 163static 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
 192static 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
 216static 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
 239static 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
 252static 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
 265static int
 266vidioc_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
 309static int
 310vidioc_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
 351void 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
 376void 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
 399static int
 400vidioc_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
 435static int
 436vidioc_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
 486const 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
 514static int
 515rockchip_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
 552static 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
 596static 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
 604static 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
 633static 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
 662const 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};
 671