linux/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015-2016 MediaTek Inc.
   4 * Author: Houlong Wei <houlong.wei@mediatek.com>
   5 *         Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/errno.h>
  10#include <linux/kernel.h>
  11#include <linux/pm_runtime.h>
  12#include <linux/slab.h>
  13#include <linux/workqueue.h>
  14#include <media/v4l2-event.h>
  15#include <media/v4l2-ioctl.h>
  16
  17#include "mtk_mdp_core.h"
  18#include "mtk_mdp_m2m.h"
  19#include "mtk_mdp_regs.h"
  20#include "mtk_vpu.h"
  21
  22
  23/**
  24 *  struct mtk_mdp_pix_limit - image pixel size limits
  25 *  @org_w: source pixel width
  26 *  @org_h: source pixel height
  27 *  @target_rot_dis_w: pixel dst scaled width with the rotator is off
  28 *  @target_rot_dis_h: pixel dst scaled height with the rotator is off
  29 *  @target_rot_en_w: pixel dst scaled width with the rotator is on
  30 *  @target_rot_en_h: pixel dst scaled height with the rotator is on
  31 */
  32struct mtk_mdp_pix_limit {
  33        u16 org_w;
  34        u16 org_h;
  35        u16 target_rot_dis_w;
  36        u16 target_rot_dis_h;
  37        u16 target_rot_en_w;
  38        u16 target_rot_en_h;
  39};
  40
  41static struct mtk_mdp_pix_align mtk_mdp_size_align = {
  42        .org_w                  = 16,
  43        .org_h                  = 16,
  44        .target_w               = 2,
  45        .target_h               = 2,
  46};
  47
  48static const struct mtk_mdp_fmt mtk_mdp_formats[] = {
  49        {
  50                .pixelformat    = V4L2_PIX_FMT_MT21C,
  51                .depth          = { 8, 4 },
  52                .row_depth      = { 8, 8 },
  53                .num_planes     = 2,
  54                .num_comp       = 2,
  55                .align          = &mtk_mdp_size_align,
  56                .flags          = MTK_MDP_FMT_FLAG_OUTPUT,
  57        }, {
  58                .pixelformat    = V4L2_PIX_FMT_NV12M,
  59                .depth          = { 8, 4 },
  60                .row_depth      = { 8, 8 },
  61                .num_planes     = 2,
  62                .num_comp       = 2,
  63                .flags          = MTK_MDP_FMT_FLAG_OUTPUT |
  64                                  MTK_MDP_FMT_FLAG_CAPTURE,
  65        }, {
  66                .pixelformat    = V4L2_PIX_FMT_YUV420M,
  67                .depth          = { 8, 2, 2 },
  68                .row_depth      = { 8, 4, 4 },
  69                .num_planes     = 3,
  70                .num_comp       = 3,
  71                .flags          = MTK_MDP_FMT_FLAG_OUTPUT |
  72                                  MTK_MDP_FMT_FLAG_CAPTURE,
  73        }, {
  74                .pixelformat    = V4L2_PIX_FMT_YVU420,
  75                .depth          = { 12 },
  76                .row_depth      = { 8 },
  77                .num_planes     = 1,
  78                .num_comp       = 3,
  79                .flags          = MTK_MDP_FMT_FLAG_OUTPUT |
  80                                  MTK_MDP_FMT_FLAG_CAPTURE,
  81        }
  82};
  83
  84static struct mtk_mdp_pix_limit mtk_mdp_size_max = {
  85        .target_rot_dis_w       = 4096,
  86        .target_rot_dis_h       = 4096,
  87        .target_rot_en_w        = 4096,
  88        .target_rot_en_h        = 4096,
  89};
  90
  91static struct mtk_mdp_pix_limit mtk_mdp_size_min = {
  92        .org_w                  = 16,
  93        .org_h                  = 16,
  94        .target_rot_dis_w       = 16,
  95        .target_rot_dis_h       = 16,
  96        .target_rot_en_w        = 16,
  97        .target_rot_en_h        = 16,
  98};
  99
 100/* align size for normal raster scan pixel format */
 101static struct mtk_mdp_pix_align mtk_mdp_rs_align = {
 102        .org_w                  = 2,
 103        .org_h                  = 2,
 104        .target_w               = 2,
 105        .target_h               = 2,
 106};
 107
 108static struct mtk_mdp_variant mtk_mdp_default_variant = {
 109        .pix_max                = &mtk_mdp_size_max,
 110        .pix_min                = &mtk_mdp_size_min,
 111        .pix_align              = &mtk_mdp_rs_align,
 112        .h_scale_up_max         = 32,
 113        .v_scale_up_max         = 32,
 114        .h_scale_down_max       = 32,
 115        .v_scale_down_max       = 128,
 116};
 117
 118static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type)
 119{
 120        u32 i, flag;
 121
 122        flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
 123                                           MTK_MDP_FMT_FLAG_CAPTURE;
 124
 125        for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
 126                if (!(mtk_mdp_formats[i].flags & flag))
 127                        continue;
 128                if (mtk_mdp_formats[i].pixelformat == pixelformat)
 129                        return &mtk_mdp_formats[i];
 130        }
 131        return NULL;
 132}
 133
 134static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type)
 135{
 136        u32 i, flag, num = 0;
 137
 138        flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT :
 139                                           MTK_MDP_FMT_FLAG_CAPTURE;
 140
 141        for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) {
 142                if (!(mtk_mdp_formats[i].flags & flag))
 143                        continue;
 144                if (index == num)
 145                        return &mtk_mdp_formats[i];
 146                num++;
 147        }
 148        return NULL;
 149}
 150
 151static void mtk_mdp_bound_align_image(u32 *w, unsigned int wmin,
 152                                      unsigned int wmax, unsigned int align_w,
 153                                      u32 *h, unsigned int hmin,
 154                                      unsigned int hmax, unsigned int align_h)
 155{
 156        int org_w, org_h, step_w, step_h;
 157        int walign, halign;
 158
 159        org_w = *w;
 160        org_h = *h;
 161        walign = ffs(align_w) - 1;
 162        halign = ffs(align_h) - 1;
 163        v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
 164
 165        step_w = 1 << walign;
 166        step_h = 1 << halign;
 167        if (*w < org_w && (*w + step_w) <= wmax)
 168                *w += step_w;
 169        if (*h < org_h && (*h + step_h) <= hmax)
 170                *h += step_h;
 171}
 172
 173static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx,
 174                                                        struct v4l2_format *f)
 175{
 176        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
 177        struct mtk_mdp_variant *variant = mdp->variant;
 178        struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
 179        const struct mtk_mdp_fmt *fmt;
 180        u32 max_w, max_h, align_w, align_h;
 181        u32 min_w, min_h, org_w, org_h;
 182        int i;
 183
 184        fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type);
 185        if (!fmt)
 186                fmt = mtk_mdp_find_fmt_by_index(0, f->type);
 187        if (!fmt) {
 188                dev_dbg(&ctx->mdp_dev->pdev->dev,
 189                        "pixelformat format 0x%X invalid\n",
 190                        pix_mp->pixelformat);
 191                return NULL;
 192        }
 193
 194        pix_mp->field = V4L2_FIELD_NONE;
 195        pix_mp->pixelformat = fmt->pixelformat;
 196        if (V4L2_TYPE_IS_CAPTURE(f->type)) {
 197                pix_mp->colorspace = ctx->colorspace;
 198                pix_mp->xfer_func = ctx->xfer_func;
 199                pix_mp->ycbcr_enc = ctx->ycbcr_enc;
 200                pix_mp->quantization = ctx->quant;
 201        }
 202        memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
 203
 204        max_w = variant->pix_max->target_rot_dis_w;
 205        max_h = variant->pix_max->target_rot_dis_h;
 206
 207        if (fmt->align == NULL) {
 208                /* use default alignment */
 209                align_w = variant->pix_align->org_w;
 210                align_h = variant->pix_align->org_h;
 211        } else {
 212                align_w = fmt->align->org_w;
 213                align_h = fmt->align->org_h;
 214        }
 215
 216        if (V4L2_TYPE_IS_OUTPUT(f->type)) {
 217                min_w = variant->pix_min->org_w;
 218                min_h = variant->pix_min->org_h;
 219        } else {
 220                min_w = variant->pix_min->target_rot_dis_w;
 221                min_h = variant->pix_min->target_rot_dis_h;
 222        }
 223
 224        mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u",
 225                    ctx->id, f->type, pix_mp->width, pix_mp->height,
 226                    align_w, align_h, max_w, max_h);
 227        /*
 228         * To check if image size is modified to adjust parameter against
 229         * hardware abilities
 230         */
 231        org_w = pix_mp->width;
 232        org_h = pix_mp->height;
 233
 234        mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w,
 235                                  &pix_mp->height, min_h, max_h, align_h);
 236
 237        if (org_w != pix_mp->width || org_h != pix_mp->height)
 238                mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id,
 239                            org_w, org_h, pix_mp->width, pix_mp->height);
 240        pix_mp->num_planes = fmt->num_planes;
 241
 242        for (i = 0; i < pix_mp->num_planes; ++i) {
 243                int bpl = (pix_mp->width * fmt->row_depth[i]) / 8;
 244                int sizeimage = (pix_mp->width * pix_mp->height *
 245                        fmt->depth[i]) / 8;
 246
 247                pix_mp->plane_fmt[i].bytesperline = bpl;
 248                if (pix_mp->plane_fmt[i].sizeimage < sizeimage)
 249                        pix_mp->plane_fmt[i].sizeimage = sizeimage;
 250                memset(pix_mp->plane_fmt[i].reserved, 0,
 251                       sizeof(pix_mp->plane_fmt[i].reserved));
 252                mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id,
 253                            i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage);
 254        }
 255
 256        return fmt;
 257}
 258
 259static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx,
 260                                            enum v4l2_buf_type type)
 261{
 262        if (V4L2_TYPE_IS_OUTPUT(type))
 263                return &ctx->s_frame;
 264        return &ctx->d_frame;
 265}
 266
 267static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h)
 268{
 269        if (new_w != *w || new_h != *h) {
 270                mtk_mdp_dbg(1, "size change:%dx%d to %dx%d",
 271                            *w, *h, new_w, new_h);
 272
 273                *w = new_w;
 274                *h = new_h;
 275        }
 276}
 277
 278static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type,
 279                            struct v4l2_rect *r)
 280{
 281        struct mtk_mdp_frame *frame;
 282        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
 283        struct mtk_mdp_variant *variant = mdp->variant;
 284        u32 align_w, align_h, new_w, new_h;
 285        u32 min_w, min_h, max_w, max_h;
 286
 287        if (r->top < 0 || r->left < 0) {
 288                dev_err(&ctx->mdp_dev->pdev->dev,
 289                        "doesn't support negative values for top & left\n");
 290                return -EINVAL;
 291        }
 292
 293        mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, type,
 294                    r->width, r->height);
 295
 296        frame = mtk_mdp_ctx_get_frame(ctx, type);
 297        max_w = frame->width;
 298        max_h = frame->height;
 299        new_w = r->width;
 300        new_h = r->height;
 301
 302        if (V4L2_TYPE_IS_OUTPUT(type)) {
 303                align_w = 1;
 304                align_h = 1;
 305                min_w = 64;
 306                min_h = 32;
 307        } else {
 308                align_w = variant->pix_align->target_w;
 309                align_h = variant->pix_align->target_h;
 310                if (ctx->ctrls.rotate->val == 90 ||
 311                    ctx->ctrls.rotate->val == 270) {
 312                        max_w = frame->height;
 313                        max_h = frame->width;
 314                        min_w = variant->pix_min->target_rot_en_w;
 315                        min_h = variant->pix_min->target_rot_en_h;
 316                        new_w = r->height;
 317                        new_h = r->width;
 318                } else {
 319                        min_w = variant->pix_min->target_rot_dis_w;
 320                        min_h = variant->pix_min->target_rot_dis_h;
 321                }
 322        }
 323
 324        mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id,
 325                    align_w, align_h, min_w, min_h, new_w, new_h);
 326
 327        mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w,
 328                                  &new_h, min_h, max_h, align_h);
 329
 330        if (V4L2_TYPE_IS_CAPTURE(type) &&
 331            (ctx->ctrls.rotate->val == 90 || ctx->ctrls.rotate->val == 270))
 332                mtk_mdp_check_crop_change(new_h, new_w,
 333                                          &r->width, &r->height);
 334        else
 335                mtk_mdp_check_crop_change(new_w, new_h,
 336                                          &r->width, &r->height);
 337
 338        /* adjust left/top if cropping rectangle is out of bounds */
 339        /* Need to add code to algin left value with 2's multiple */
 340        if (r->left + new_w > max_w)
 341                r->left = max_w - new_w;
 342        if (r->top + new_h > max_h)
 343                r->top = max_h - new_h;
 344
 345        if (r->left & 1)
 346                r->left -= 1;
 347
 348        mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id,
 349                    r->left, r->top, r->width,
 350                    r->height, max_w, max_h);
 351        return 0;
 352}
 353
 354static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh)
 355{
 356        return container_of(fh, struct mtk_mdp_ctx, fh);
 357}
 358
 359static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
 360{
 361        return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler);
 362}
 363
 364void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state)
 365{
 366        mutex_lock(&ctx->slock);
 367        ctx->state |= state;
 368        mutex_unlock(&ctx->slock);
 369}
 370
 371static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask)
 372{
 373        bool ret;
 374
 375        mutex_lock(&ctx->slock);
 376        ret = (ctx->state & mask) == mask;
 377        mutex_unlock(&ctx->slock);
 378        return ret;
 379}
 380
 381static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width,
 382                                   int height)
 383{
 384        frame->width = width;
 385        frame->height = height;
 386        frame->crop.width = width;
 387        frame->crop.height = height;
 388        frame->crop.left = 0;
 389        frame->crop.top = 0;
 390}
 391
 392static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
 393{
 394        struct mtk_mdp_ctx *ctx = q->drv_priv;
 395        int ret;
 396
 397        ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev);
 398        if (ret < 0)
 399                mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d",
 400                            ctx->id, ret);
 401
 402        return 0;
 403}
 404
 405static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx,
 406                                    enum v4l2_buf_type type)
 407{
 408        if (V4L2_TYPE_IS_OUTPUT(type))
 409                return v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
 410        else
 411                return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 412}
 413
 414static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q)
 415{
 416        struct mtk_mdp_ctx *ctx = q->drv_priv;
 417        struct vb2_buffer *vb;
 418
 419        vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
 420        while (vb != NULL) {
 421                v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
 422                vb = mtk_mdp_m2m_buf_remove(ctx, q->type);
 423        }
 424
 425        pm_runtime_put(&ctx->mdp_dev->pdev->dev);
 426}
 427
 428/* The color format (num_planes) must be already configured. */
 429static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx,
 430                                 struct vb2_buffer *vb,
 431                                 struct mtk_mdp_frame *frame,
 432                                 struct mtk_mdp_addr *addr)
 433{
 434        u32 pix_size, planes, i;
 435
 436        pix_size = frame->width * frame->height;
 437        planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr));
 438        for (i = 0; i < planes; i++)
 439                addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
 440
 441        if (planes == 1) {
 442                if (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) {
 443                        addr->addr[1] = (dma_addr_t)(addr->addr[0] + pix_size);
 444                        addr->addr[2] = (dma_addr_t)(addr->addr[1] +
 445                                        (pix_size >> 2));
 446                } else {
 447                        dev_err(&ctx->mdp_dev->pdev->dev,
 448                                "Invalid pixelformat:0x%x\n",
 449                                frame->fmt->pixelformat);
 450                }
 451        }
 452        mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p",
 453                    ctx->id, planes, pix_size, (void *)addr->addr[0],
 454                    (void *)addr->addr[1], (void *)addr->addr[2]);
 455}
 456
 457static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx)
 458{
 459        struct mtk_mdp_frame *s_frame, *d_frame;
 460        struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
 461
 462        s_frame = &ctx->s_frame;
 463        d_frame = &ctx->d_frame;
 464
 465        src_vbuf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
 466        mtk_mdp_prepare_addr(ctx, &src_vbuf->vb2_buf, s_frame, &s_frame->addr);
 467
 468        dst_vbuf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
 469        mtk_mdp_prepare_addr(ctx, &dst_vbuf->vb2_buf, d_frame, &d_frame->addr);
 470
 471        dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
 472}
 473
 474static void mtk_mdp_process_done(void *priv, int vb_state)
 475{
 476        struct mtk_mdp_dev *mdp = priv;
 477        struct mtk_mdp_ctx *ctx;
 478        struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
 479
 480        ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev);
 481        if (!ctx)
 482                return;
 483
 484        src_vbuf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
 485        dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
 486
 487        dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp;
 488        dst_vbuf->timecode = src_vbuf->timecode;
 489        dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
 490        dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
 491
 492        v4l2_m2m_buf_done(src_vbuf, vb_state);
 493        v4l2_m2m_buf_done(dst_vbuf, vb_state);
 494        v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
 495}
 496
 497static void mtk_mdp_m2m_worker(struct work_struct *work)
 498{
 499        struct mtk_mdp_ctx *ctx =
 500                                container_of(work, struct mtk_mdp_ctx, work);
 501        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
 502        enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
 503        int ret;
 504
 505        if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) {
 506                dev_err(&mdp->pdev->dev, "ctx is in error state");
 507                goto worker_end;
 508        }
 509
 510        mtk_mdp_m2m_get_bufs(ctx);
 511
 512        mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr);
 513        mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr);
 514
 515        mtk_mdp_hw_set_in_size(ctx);
 516        mtk_mdp_hw_set_in_image_format(ctx);
 517
 518        mtk_mdp_hw_set_out_size(ctx);
 519        mtk_mdp_hw_set_out_image_format(ctx);
 520
 521        mtk_mdp_hw_set_rotation(ctx);
 522        mtk_mdp_hw_set_global_alpha(ctx);
 523
 524        ret = mtk_mdp_vpu_process(&ctx->vpu);
 525        if (ret) {
 526                dev_err(&mdp->pdev->dev, "processing failed: %d", ret);
 527                goto worker_end;
 528        }
 529
 530        buf_state = VB2_BUF_STATE_DONE;
 531
 532worker_end:
 533        mtk_mdp_process_done(mdp, buf_state);
 534}
 535
 536static void mtk_mdp_m2m_device_run(void *priv)
 537{
 538        struct mtk_mdp_ctx *ctx = priv;
 539
 540        queue_work(ctx->mdp_dev->job_wq, &ctx->work);
 541}
 542
 543static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq,
 544                        unsigned int *num_buffers, unsigned int *num_planes,
 545                        unsigned int sizes[], struct device *alloc_devs[])
 546{
 547        struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq);
 548        struct mtk_mdp_frame *frame;
 549        int i;
 550
 551        frame = mtk_mdp_ctx_get_frame(ctx, vq->type);
 552        *num_planes = frame->fmt->num_planes;
 553        for (i = 0; i < frame->fmt->num_planes; i++)
 554                sizes[i] = frame->payload[i];
 555        mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u",
 556                    ctx->id, vq->type, *num_planes, *num_buffers,
 557                    sizes[0], sizes[1]);
 558        return 0;
 559}
 560
 561static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb)
 562{
 563        struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 564        struct mtk_mdp_frame *frame;
 565        int i;
 566
 567        frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type);
 568
 569        if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
 570                for (i = 0; i < frame->fmt->num_planes; i++)
 571                        vb2_set_plane_payload(vb, i, frame->payload[i]);
 572        }
 573
 574        return 0;
 575}
 576
 577static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb)
 578{
 579        struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 580
 581        v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
 582}
 583
 584static const struct vb2_ops mtk_mdp_m2m_qops = {
 585        .queue_setup     = mtk_mdp_m2m_queue_setup,
 586        .buf_prepare     = mtk_mdp_m2m_buf_prepare,
 587        .buf_queue       = mtk_mdp_m2m_buf_queue,
 588        .stop_streaming  = mtk_mdp_m2m_stop_streaming,
 589        .start_streaming = mtk_mdp_m2m_start_streaming,
 590        .wait_prepare    = vb2_ops_wait_prepare,
 591        .wait_finish     = vb2_ops_wait_finish,
 592};
 593
 594static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
 595                                struct v4l2_capability *cap)
 596{
 597        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 598        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
 599
 600        strscpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver));
 601        strscpy(cap->card, mdp->pdev->name, sizeof(cap->card));
 602        strscpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info));
 603
 604        return 0;
 605}
 606
 607static int mtk_mdp_enum_fmt(struct v4l2_fmtdesc *f, u32 type)
 608{
 609        const struct mtk_mdp_fmt *fmt;
 610
 611        fmt = mtk_mdp_find_fmt_by_index(f->index, type);
 612        if (!fmt)
 613                return -EINVAL;
 614
 615        f->pixelformat = fmt->pixelformat;
 616
 617        return 0;
 618}
 619
 620static int mtk_mdp_m2m_enum_fmt_vid_cap(struct file *file, void *priv,
 621                                        struct v4l2_fmtdesc *f)
 622{
 623        return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
 624}
 625
 626static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv,
 627                                        struct v4l2_fmtdesc *f)
 628{
 629        return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 630}
 631
 632static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
 633                                    struct v4l2_format *f)
 634{
 635        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 636        struct mtk_mdp_frame *frame;
 637        struct v4l2_pix_format_mplane *pix_mp;
 638        int i;
 639
 640        mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
 641
 642        frame = mtk_mdp_ctx_get_frame(ctx, f->type);
 643        pix_mp = &f->fmt.pix_mp;
 644
 645        pix_mp->width = frame->width;
 646        pix_mp->height = frame->height;
 647        pix_mp->field = V4L2_FIELD_NONE;
 648        pix_mp->pixelformat = frame->fmt->pixelformat;
 649        pix_mp->num_planes = frame->fmt->num_planes;
 650        pix_mp->colorspace = ctx->colorspace;
 651        pix_mp->xfer_func = ctx->xfer_func;
 652        pix_mp->ycbcr_enc = ctx->ycbcr_enc;
 653        pix_mp->quantization = ctx->quant;
 654        mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id,
 655                    pix_mp->width, pix_mp->height);
 656
 657        for (i = 0; i < pix_mp->num_planes; ++i) {
 658                pix_mp->plane_fmt[i].bytesperline = (frame->width *
 659                        frame->fmt->row_depth[i]) / 8;
 660                pix_mp->plane_fmt[i].sizeimage = (frame->width *
 661                        frame->height * frame->fmt->depth[i]) / 8;
 662
 663                mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i,
 664                            pix_mp->plane_fmt[i].bytesperline,
 665                            pix_mp->plane_fmt[i].sizeimage);
 666        }
 667
 668        return 0;
 669}
 670
 671static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
 672                                      struct v4l2_format *f)
 673{
 674        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 675
 676        if (!mtk_mdp_try_fmt_mplane(ctx, f))
 677                return -EINVAL;
 678        return 0;
 679}
 680
 681static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
 682                                    struct v4l2_format *f)
 683{
 684        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 685        struct vb2_queue *vq;
 686        struct mtk_mdp_frame *frame;
 687        struct v4l2_pix_format_mplane *pix_mp;
 688        const struct mtk_mdp_fmt *fmt;
 689        int i;
 690
 691        mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type);
 692
 693        frame = mtk_mdp_ctx_get_frame(ctx, f->type);
 694        fmt = mtk_mdp_try_fmt_mplane(ctx, f);
 695        if (!fmt) {
 696                mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type);
 697                return -EINVAL;
 698        }
 699        frame->fmt = fmt;
 700
 701        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 702        if (vb2_is_streaming(vq)) {
 703                dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type);
 704                return -EBUSY;
 705        }
 706
 707        pix_mp = &f->fmt.pix_mp;
 708        for (i = 0; i < frame->fmt->num_planes; i++) {
 709                frame->payload[i] = pix_mp->plane_fmt[i].sizeimage;
 710                frame->pitch[i] = pix_mp->plane_fmt[i].bytesperline;
 711        }
 712
 713        mtk_mdp_set_frame_size(frame, pix_mp->width, pix_mp->height);
 714        if (V4L2_TYPE_IS_OUTPUT(f->type)) {
 715                ctx->colorspace = pix_mp->colorspace;
 716                ctx->xfer_func = pix_mp->xfer_func;
 717                ctx->ycbcr_enc = pix_mp->ycbcr_enc;
 718                ctx->quant = pix_mp->quantization;
 719        }
 720
 721        mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type,
 722                    frame->width, frame->height);
 723
 724        return 0;
 725}
 726
 727static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh,
 728                               struct v4l2_requestbuffers *reqbufs)
 729{
 730        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 731
 732        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 733}
 734
 735static int mtk_mdp_m2m_streamon(struct file *file, void *fh,
 736                                enum v4l2_buf_type type)
 737{
 738        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 739        int ret;
 740
 741        if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) {
 742                ret = mtk_mdp_vpu_init(&ctx->vpu);
 743                if (ret < 0) {
 744                        dev_err(&ctx->mdp_dev->pdev->dev,
 745                                "vpu init failed %d\n",
 746                                ret);
 747                        return -EINVAL;
 748                }
 749                mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_VPU_INIT);
 750        }
 751
 752        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 753}
 754
 755static inline bool mtk_mdp_is_target_compose(u32 target)
 756{
 757        if (target == V4L2_SEL_TGT_COMPOSE_DEFAULT
 758            || target == V4L2_SEL_TGT_COMPOSE_BOUNDS
 759            || target == V4L2_SEL_TGT_COMPOSE)
 760                return true;
 761        return false;
 762}
 763
 764static inline bool mtk_mdp_is_target_crop(u32 target)
 765{
 766        if (target == V4L2_SEL_TGT_CROP_DEFAULT
 767            || target == V4L2_SEL_TGT_CROP_BOUNDS
 768            || target == V4L2_SEL_TGT_CROP)
 769                return true;
 770        return false;
 771}
 772
 773static int mtk_mdp_m2m_g_selection(struct file *file, void *fh,
 774                                       struct v4l2_selection *s)
 775{
 776        struct mtk_mdp_frame *frame;
 777        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 778        bool valid = false;
 779
 780        if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 781                if (mtk_mdp_is_target_compose(s->target))
 782                        valid = true;
 783        } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
 784                if (mtk_mdp_is_target_crop(s->target))
 785                        valid = true;
 786        }
 787        if (!valid) {
 788                mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx->id, s->type,
 789                            s->target);
 790                return -EINVAL;
 791        }
 792
 793        frame = mtk_mdp_ctx_get_frame(ctx, s->type);
 794
 795        switch (s->target) {
 796        case V4L2_SEL_TGT_COMPOSE_DEFAULT:
 797        case V4L2_SEL_TGT_COMPOSE_BOUNDS:
 798        case V4L2_SEL_TGT_CROP_BOUNDS:
 799        case V4L2_SEL_TGT_CROP_DEFAULT:
 800                s->r.left = 0;
 801                s->r.top = 0;
 802                s->r.width = frame->width;
 803                s->r.height = frame->height;
 804                return 0;
 805
 806        case V4L2_SEL_TGT_COMPOSE:
 807        case V4L2_SEL_TGT_CROP:
 808                s->r.left = frame->crop.left;
 809                s->r.top = frame->crop.top;
 810                s->r.width = frame->crop.width;
 811                s->r.height = frame->crop.height;
 812                return 0;
 813        }
 814
 815        return -EINVAL;
 816}
 817
 818static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w,
 819                                      int src_h, int dst_w, int dst_h, int rot)
 820{
 821        int tmp_w, tmp_h;
 822
 823        if (rot == 90 || rot == 270) {
 824                tmp_w = dst_h;
 825                tmp_h = dst_w;
 826        } else {
 827                tmp_w = dst_w;
 828                tmp_h = dst_h;
 829        }
 830
 831        if ((src_w / tmp_w) > var->h_scale_down_max ||
 832            (src_h / tmp_h) > var->v_scale_down_max ||
 833            (tmp_w / src_w) > var->h_scale_up_max ||
 834            (tmp_h / src_h) > var->v_scale_up_max)
 835                return -EINVAL;
 836
 837        return 0;
 838}
 839
 840static int mtk_mdp_m2m_s_selection(struct file *file, void *fh,
 841                                   struct v4l2_selection *s)
 842{
 843        struct mtk_mdp_frame *frame;
 844        struct mtk_mdp_ctx *ctx = fh_to_ctx(fh);
 845        struct v4l2_rect new_r;
 846        struct mtk_mdp_variant *variant = ctx->mdp_dev->variant;
 847        int ret;
 848        bool valid = false;
 849
 850        if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 851                if (s->target == V4L2_SEL_TGT_COMPOSE)
 852                        valid = true;
 853        } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
 854                if (s->target == V4L2_SEL_TGT_CROP)
 855                        valid = true;
 856        }
 857        if (!valid) {
 858                mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx->id, s->type,
 859                            s->target);
 860                return -EINVAL;
 861        }
 862
 863        new_r = s->r;
 864        ret = mtk_mdp_try_crop(ctx, s->type, &new_r);
 865        if (ret)
 866                return ret;
 867
 868        if (mtk_mdp_is_target_crop(s->target))
 869                frame = &ctx->s_frame;
 870        else
 871                frame = &ctx->d_frame;
 872
 873        /* Check to see if scaling ratio is within supported range */
 874        if (V4L2_TYPE_IS_OUTPUT(s->type))
 875                ret = mtk_mdp_check_scaler_ratio(variant, new_r.width,
 876                        new_r.height, ctx->d_frame.crop.width,
 877                        ctx->d_frame.crop.height,
 878                        ctx->ctrls.rotate->val);
 879        else
 880                ret = mtk_mdp_check_scaler_ratio(variant,
 881                        ctx->s_frame.crop.width,
 882                        ctx->s_frame.crop.height, new_r.width,
 883                        new_r.height, ctx->ctrls.rotate->val);
 884
 885        if (ret) {
 886                dev_info(&ctx->mdp_dev->pdev->dev,
 887                        "Out of scaler range");
 888                return -EINVAL;
 889        }
 890
 891        s->r = new_r;
 892        frame->crop = new_r;
 893
 894        return 0;
 895}
 896
 897static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = {
 898        .vidioc_querycap                = mtk_mdp_m2m_querycap,
 899        .vidioc_enum_fmt_vid_cap        = mtk_mdp_m2m_enum_fmt_vid_cap,
 900        .vidioc_enum_fmt_vid_out        = mtk_mdp_m2m_enum_fmt_vid_out,
 901        .vidioc_g_fmt_vid_cap_mplane    = mtk_mdp_m2m_g_fmt_mplane,
 902        .vidioc_g_fmt_vid_out_mplane    = mtk_mdp_m2m_g_fmt_mplane,
 903        .vidioc_try_fmt_vid_cap_mplane  = mtk_mdp_m2m_try_fmt_mplane,
 904        .vidioc_try_fmt_vid_out_mplane  = mtk_mdp_m2m_try_fmt_mplane,
 905        .vidioc_s_fmt_vid_cap_mplane    = mtk_mdp_m2m_s_fmt_mplane,
 906        .vidioc_s_fmt_vid_out_mplane    = mtk_mdp_m2m_s_fmt_mplane,
 907        .vidioc_reqbufs                 = mtk_mdp_m2m_reqbufs,
 908        .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
 909        .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
 910        .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
 911        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 912        .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
 913        .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
 914        .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
 915        .vidioc_streamon                = mtk_mdp_m2m_streamon,
 916        .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
 917        .vidioc_g_selection             = mtk_mdp_m2m_g_selection,
 918        .vidioc_s_selection             = mtk_mdp_m2m_s_selection
 919};
 920
 921static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
 922                                  struct vb2_queue *dst_vq)
 923{
 924        struct mtk_mdp_ctx *ctx = priv;
 925        int ret;
 926
 927        memset(src_vq, 0, sizeof(*src_vq));
 928        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 929        src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 930        src_vq->drv_priv = ctx;
 931        src_vq->ops = &mtk_mdp_m2m_qops;
 932        src_vq->mem_ops = &vb2_dma_contig_memops;
 933        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 934        src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 935        src_vq->dev = &ctx->mdp_dev->pdev->dev;
 936        src_vq->lock = &ctx->mdp_dev->lock;
 937
 938        ret = vb2_queue_init(src_vq);
 939        if (ret)
 940                return ret;
 941
 942        memset(dst_vq, 0, sizeof(*dst_vq));
 943        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 944        dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
 945        dst_vq->drv_priv = ctx;
 946        dst_vq->ops = &mtk_mdp_m2m_qops;
 947        dst_vq->mem_ops = &vb2_dma_contig_memops;
 948        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 949        dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 950        dst_vq->dev = &ctx->mdp_dev->pdev->dev;
 951        dst_vq->lock = &ctx->mdp_dev->lock;
 952
 953        return vb2_queue_init(dst_vq);
 954}
 955
 956static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl)
 957{
 958        struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl);
 959        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
 960        struct mtk_mdp_variant *variant = mdp->variant;
 961        int ret = 0;
 962
 963        if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
 964                return 0;
 965
 966        switch (ctrl->id) {
 967        case V4L2_CID_HFLIP:
 968                ctx->hflip = ctrl->val;
 969                break;
 970        case V4L2_CID_VFLIP:
 971                ctx->vflip = ctrl->val;
 972                break;
 973        case V4L2_CID_ROTATE:
 974                ret = mtk_mdp_check_scaler_ratio(variant,
 975                                ctx->s_frame.crop.width,
 976                                ctx->s_frame.crop.height,
 977                                ctx->d_frame.crop.width,
 978                                ctx->d_frame.crop.height,
 979                                ctx->ctrls.rotate->val);
 980
 981                if (ret)
 982                        return -EINVAL;
 983
 984                ctx->rotation = ctrl->val;
 985                break;
 986        case V4L2_CID_ALPHA_COMPONENT:
 987                ctx->d_frame.alpha = ctrl->val;
 988                break;
 989        }
 990
 991        return 0;
 992}
 993
 994static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = {
 995        .s_ctrl = mtk_mdp_s_ctrl,
 996};
 997
 998static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx)
 999{
1000        v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM);
1001
1002        ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
1003                        &mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
1004        ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
1005                                             &mtk_mdp_ctrl_ops,
1006                                             V4L2_CID_HFLIP,
1007                                             0, 1, 1, 0);
1008        ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
1009                                             &mtk_mdp_ctrl_ops,
1010                                             V4L2_CID_VFLIP,
1011                                             0, 1, 1, 0);
1012        ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
1013                                                    &mtk_mdp_ctrl_ops,
1014                                                    V4L2_CID_ALPHA_COMPONENT,
1015                                                    0, 255, 1, 0);
1016        ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
1017
1018        if (ctx->ctrl_handler.error) {
1019                int err = ctx->ctrl_handler.error;
1020
1021                v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1022                dev_err(&ctx->mdp_dev->pdev->dev,
1023                        "Failed to create control handlers\n");
1024                return err;
1025        }
1026
1027        return 0;
1028}
1029
1030static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx)
1031{
1032        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
1033        struct mtk_mdp_frame *frame;
1034
1035        frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
1036        frame->fmt = mtk_mdp_find_fmt_by_index(0,
1037                                        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
1038        frame->width = mdp->variant->pix_min->org_w;
1039        frame->height = mdp->variant->pix_min->org_h;
1040        frame->payload[0] = frame->width * frame->height;
1041        frame->payload[1] = frame->payload[0] / 2;
1042
1043        frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
1044        frame->fmt = mtk_mdp_find_fmt_by_index(0,
1045                                        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
1046        frame->width = mdp->variant->pix_min->target_rot_dis_w;
1047        frame->height = mdp->variant->pix_min->target_rot_dis_h;
1048        frame->payload[0] = frame->width * frame->height;
1049        frame->payload[1] = frame->payload[0] / 2;
1050
1051}
1052
1053static int mtk_mdp_m2m_open(struct file *file)
1054{
1055        struct mtk_mdp_dev *mdp = video_drvdata(file);
1056        struct video_device *vfd = video_devdata(file);
1057        struct mtk_mdp_ctx *ctx = NULL;
1058        int ret;
1059        struct v4l2_format default_format;
1060
1061        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1062        if (!ctx)
1063                return -ENOMEM;
1064
1065        if (mutex_lock_interruptible(&mdp->lock)) {
1066                ret = -ERESTARTSYS;
1067                goto err_lock;
1068        }
1069
1070        mutex_init(&ctx->slock);
1071        ctx->id = mdp->id_counter++;
1072        v4l2_fh_init(&ctx->fh, vfd);
1073        file->private_data = &ctx->fh;
1074        ret = mtk_mdp_ctrls_create(ctx);
1075        if (ret)
1076                goto error_ctrls;
1077
1078        /* Use separate control handler per file handle */
1079        ctx->fh.ctrl_handler = &ctx->ctrl_handler;
1080        v4l2_fh_add(&ctx->fh);
1081        INIT_LIST_HEAD(&ctx->list);
1082
1083        ctx->mdp_dev = mdp;
1084        mtk_mdp_set_default_params(ctx);
1085
1086        INIT_WORK(&ctx->work, mtk_mdp_m2m_worker);
1087        ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx,
1088                                         mtk_mdp_m2m_queue_init);
1089        if (IS_ERR(ctx->m2m_ctx)) {
1090                dev_err(&mdp->pdev->dev, "Failed to initialize m2m context");
1091                ret = PTR_ERR(ctx->m2m_ctx);
1092                goto error_m2m_ctx;
1093        }
1094        ctx->fh.m2m_ctx = ctx->m2m_ctx;
1095        if (mdp->ctx_num++ == 0) {
1096                ret = vpu_load_firmware(mdp->vpu_dev);
1097                if (ret < 0) {
1098                        dev_err(&mdp->pdev->dev,
1099                                "vpu_load_firmware failed %d\n", ret);
1100                        goto err_load_vpu;
1101                }
1102
1103                ret = mtk_mdp_vpu_register(mdp->pdev);
1104                if (ret < 0) {
1105                        dev_err(&mdp->pdev->dev,
1106                                "mdp_vpu register failed %d\n", ret);
1107                        goto err_load_vpu;
1108                }
1109        }
1110
1111        list_add(&ctx->list, &mdp->ctx_list);
1112        mutex_unlock(&mdp->lock);
1113
1114        /* Default format */
1115        memset(&default_format, 0, sizeof(default_format));
1116        default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1117        default_format.fmt.pix_mp.width = 32;
1118        default_format.fmt.pix_mp.height = 32;
1119        default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
1120        mtk_mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
1121        default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1122        mtk_mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
1123
1124        mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
1125
1126        return 0;
1127
1128err_load_vpu:
1129        mdp->ctx_num--;
1130        v4l2_m2m_ctx_release(ctx->m2m_ctx);
1131error_m2m_ctx:
1132        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1133error_ctrls:
1134        v4l2_fh_del(&ctx->fh);
1135        v4l2_fh_exit(&ctx->fh);
1136        mutex_unlock(&mdp->lock);
1137err_lock:
1138        kfree(ctx);
1139
1140        return ret;
1141}
1142
1143static int mtk_mdp_m2m_release(struct file *file)
1144{
1145        struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data);
1146        struct mtk_mdp_dev *mdp = ctx->mdp_dev;
1147
1148        flush_workqueue(mdp->job_wq);
1149        mutex_lock(&mdp->lock);
1150        v4l2_m2m_ctx_release(ctx->m2m_ctx);
1151        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
1152        v4l2_fh_del(&ctx->fh);
1153        v4l2_fh_exit(&ctx->fh);
1154        mtk_mdp_vpu_deinit(&ctx->vpu);
1155        mdp->ctx_num--;
1156        list_del_init(&ctx->list);
1157
1158        mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id);
1159
1160        mutex_unlock(&mdp->lock);
1161        kfree(ctx);
1162
1163        return 0;
1164}
1165
1166static const struct v4l2_file_operations mtk_mdp_m2m_fops = {
1167        .owner          = THIS_MODULE,
1168        .open           = mtk_mdp_m2m_open,
1169        .release        = mtk_mdp_m2m_release,
1170        .poll           = v4l2_m2m_fop_poll,
1171        .unlocked_ioctl = video_ioctl2,
1172        .mmap           = v4l2_m2m_fop_mmap,
1173};
1174
1175static const struct v4l2_m2m_ops mtk_mdp_m2m_ops = {
1176        .device_run     = mtk_mdp_m2m_device_run,
1177};
1178
1179int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
1180{
1181        struct device *dev = &mdp->pdev->dev;
1182        int ret;
1183
1184        mdp->variant = &mtk_mdp_default_variant;
1185        mdp->vdev = video_device_alloc();
1186        if (!mdp->vdev) {
1187                dev_err(dev, "failed to allocate video device\n");
1188                ret = -ENOMEM;
1189                goto err_video_alloc;
1190        }
1191        mdp->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
1192        mdp->vdev->fops = &mtk_mdp_m2m_fops;
1193        mdp->vdev->ioctl_ops = &mtk_mdp_m2m_ioctl_ops;
1194        mdp->vdev->release = video_device_release;
1195        mdp->vdev->lock = &mdp->lock;
1196        mdp->vdev->vfl_dir = VFL_DIR_M2M;
1197        mdp->vdev->v4l2_dev = &mdp->v4l2_dev;
1198        snprintf(mdp->vdev->name, sizeof(mdp->vdev->name), "%s:m2m",
1199                 MTK_MDP_MODULE_NAME);
1200        video_set_drvdata(mdp->vdev, mdp);
1201
1202        mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops);
1203        if (IS_ERR(mdp->m2m_dev)) {
1204                dev_err(dev, "failed to initialize v4l2-m2m device\n");
1205                ret = PTR_ERR(mdp->m2m_dev);
1206                goto err_m2m_init;
1207        }
1208
1209        ret = video_register_device(mdp->vdev, VFL_TYPE_VIDEO, 2);
1210        if (ret) {
1211                dev_err(dev, "failed to register video device\n");
1212                goto err_vdev_register;
1213        }
1214
1215        v4l2_info(&mdp->v4l2_dev, "driver registered as /dev/video%d",
1216                  mdp->vdev->num);
1217        return 0;
1218
1219err_vdev_register:
1220        v4l2_m2m_release(mdp->m2m_dev);
1221err_m2m_init:
1222        video_device_release(mdp->vdev);
1223err_video_alloc:
1224
1225        return ret;
1226}
1227
1228void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp)
1229{
1230        video_unregister_device(mdp->vdev);
1231        v4l2_m2m_release(mdp->m2m_dev);
1232}
1233