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