linux/drivers/media/platform/exynos4-is/fimc-m2m.c
<<
>>
Prefs
   1/*
   2 * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
   3 *
   4 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
   5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published
   9 * by the Free Software Foundation, either version 2 of the License,
  10 * or (at your option) any later version.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/types.h>
  16#include <linux/errno.h>
  17#include <linux/bug.h>
  18#include <linux/interrupt.h>
  19#include <linux/device.h>
  20#include <linux/platform_device.h>
  21#include <linux/pm_runtime.h>
  22#include <linux/list.h>
  23#include <linux/io.h>
  24#include <linux/slab.h>
  25#include <linux/clk.h>
  26#include <media/v4l2-ioctl.h>
  27#include <media/videobuf2-core.h>
  28#include <media/videobuf2-dma-contig.h>
  29
  30#include "common.h"
  31#include "fimc-core.h"
  32#include "fimc-reg.h"
  33#include "media-dev.h"
  34
  35static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
  36{
  37        if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
  38                return FMT_FLAGS_M2M_IN;
  39        else
  40                return FMT_FLAGS_M2M_OUT;
  41}
  42
  43void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
  44{
  45        struct vb2_buffer *src_vb, *dst_vb;
  46
  47        if (!ctx || !ctx->m2m_ctx)
  48                return;
  49
  50        src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
  51        dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
  52
  53        if (src_vb && dst_vb) {
  54                v4l2_m2m_buf_done(src_vb, vb_state);
  55                v4l2_m2m_buf_done(dst_vb, vb_state);
  56                v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
  57                                    ctx->m2m_ctx);
  58        }
  59}
  60
  61/* Complete the transaction which has been scheduled for execution. */
  62static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
  63{
  64        struct fimc_dev *fimc = ctx->fimc_dev;
  65        int ret;
  66
  67        if (!fimc_m2m_pending(fimc))
  68                return 0;
  69
  70        fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
  71
  72        ret = wait_event_timeout(fimc->irq_queue,
  73                           !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
  74                           FIMC_SHUTDOWN_TIMEOUT);
  75
  76        return ret == 0 ? -ETIMEDOUT : ret;
  77}
  78
  79static int start_streaming(struct vb2_queue *q, unsigned int count)
  80{
  81        struct fimc_ctx *ctx = q->drv_priv;
  82        int ret;
  83
  84        ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
  85        return ret > 0 ? 0 : ret;
  86}
  87
  88static int stop_streaming(struct vb2_queue *q)
  89{
  90        struct fimc_ctx *ctx = q->drv_priv;
  91        int ret;
  92
  93        ret = fimc_m2m_shutdown(ctx);
  94        if (ret == -ETIMEDOUT)
  95                fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
  96
  97        pm_runtime_put(&ctx->fimc_dev->pdev->dev);
  98        return 0;
  99}
 100
 101static void fimc_device_run(void *priv)
 102{
 103        struct vb2_buffer *src_vb, *dst_vb;
 104        struct fimc_ctx *ctx = priv;
 105        struct fimc_frame *sf, *df;
 106        struct fimc_dev *fimc;
 107        unsigned long flags;
 108        int ret;
 109
 110        if (WARN(!ctx, "Null context\n"))
 111                return;
 112
 113        fimc = ctx->fimc_dev;
 114        spin_lock_irqsave(&fimc->slock, flags);
 115
 116        set_bit(ST_M2M_PEND, &fimc->state);
 117        sf = &ctx->s_frame;
 118        df = &ctx->d_frame;
 119
 120        if (ctx->state & FIMC_PARAMS) {
 121                /* Prepare the DMA offsets for scaler */
 122                fimc_prepare_dma_offset(ctx, sf);
 123                fimc_prepare_dma_offset(ctx, df);
 124        }
 125
 126        src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
 127        ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr);
 128        if (ret)
 129                goto dma_unlock;
 130
 131        dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
 132        ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr);
 133        if (ret)
 134                goto dma_unlock;
 135
 136        dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
 137
 138        /* Reconfigure hardware if the context has changed. */
 139        if (fimc->m2m.ctx != ctx) {
 140                ctx->state |= FIMC_PARAMS;
 141                fimc->m2m.ctx = ctx;
 142        }
 143
 144        if (ctx->state & FIMC_PARAMS) {
 145                fimc_set_yuv_order(ctx);
 146                fimc_hw_set_input_path(ctx);
 147                fimc_hw_set_in_dma(ctx);
 148                ret = fimc_set_scaler_info(ctx);
 149                if (ret)
 150                        goto dma_unlock;
 151                fimc_hw_set_prescaler(ctx);
 152                fimc_hw_set_mainscaler(ctx);
 153                fimc_hw_set_target_format(ctx);
 154                fimc_hw_set_rotation(ctx);
 155                fimc_hw_set_effect(ctx);
 156                fimc_hw_set_out_dma(ctx);
 157                if (fimc->drv_data->alpha_color)
 158                        fimc_hw_set_rgb_alpha(ctx);
 159                fimc_hw_set_output_path(ctx);
 160        }
 161        fimc_hw_set_input_addr(fimc, &sf->paddr);
 162        fimc_hw_set_output_addr(fimc, &df->paddr, -1);
 163
 164        fimc_activate_capture(ctx);
 165        ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
 166        fimc_hw_activate_input_dma(fimc, true);
 167
 168dma_unlock:
 169        spin_unlock_irqrestore(&fimc->slock, flags);
 170}
 171
 172static void fimc_job_abort(void *priv)
 173{
 174        fimc_m2m_shutdown(priv);
 175}
 176
 177static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
 178                            unsigned int *num_buffers, unsigned int *num_planes,
 179                            unsigned int sizes[], void *allocators[])
 180{
 181        struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
 182        struct fimc_frame *f;
 183        int i;
 184
 185        f = ctx_get_frame(ctx, vq->type);
 186        if (IS_ERR(f))
 187                return PTR_ERR(f);
 188        /*
 189         * Return number of non-contigous planes (plane buffers)
 190         * depending on the configured color format.
 191         */
 192        if (!f->fmt)
 193                return -EINVAL;
 194
 195        *num_planes = f->fmt->memplanes;
 196        for (i = 0; i < f->fmt->memplanes; i++) {
 197                sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
 198                allocators[i] = ctx->fimc_dev->alloc_ctx;
 199        }
 200        return 0;
 201}
 202
 203static int fimc_buf_prepare(struct vb2_buffer *vb)
 204{
 205        struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 206        struct fimc_frame *frame;
 207        int i;
 208
 209        frame = ctx_get_frame(ctx, vb->vb2_queue->type);
 210        if (IS_ERR(frame))
 211                return PTR_ERR(frame);
 212
 213        for (i = 0; i < frame->fmt->memplanes; i++)
 214                vb2_set_plane_payload(vb, i, frame->payload[i]);
 215
 216        return 0;
 217}
 218
 219static void fimc_buf_queue(struct vb2_buffer *vb)
 220{
 221        struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 222
 223        dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
 224
 225        if (ctx->m2m_ctx)
 226                v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
 227}
 228
 229static void fimc_lock(struct vb2_queue *vq)
 230{
 231        struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
 232        mutex_lock(&ctx->fimc_dev->lock);
 233}
 234
 235static void fimc_unlock(struct vb2_queue *vq)
 236{
 237        struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
 238        mutex_unlock(&ctx->fimc_dev->lock);
 239}
 240
 241static struct vb2_ops fimc_qops = {
 242        .queue_setup     = fimc_queue_setup,
 243        .buf_prepare     = fimc_buf_prepare,
 244        .buf_queue       = fimc_buf_queue,
 245        .wait_prepare    = fimc_unlock,
 246        .wait_finish     = fimc_lock,
 247        .stop_streaming  = stop_streaming,
 248        .start_streaming = start_streaming,
 249};
 250
 251/*
 252 * V4L2 ioctl handlers
 253 */
 254static int fimc_m2m_querycap(struct file *file, void *fh,
 255                                     struct v4l2_capability *cap)
 256{
 257        struct fimc_dev *fimc = video_drvdata(file);
 258        unsigned int caps;
 259
 260        /*
 261         * This is only a mem-to-mem video device. The capture and output
 262         * device capability flags are left only for backward compatibility
 263         * and are scheduled for removal.
 264         */
 265        caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
 266                V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
 267
 268        __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps);
 269        return 0;
 270}
 271
 272static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
 273                                    struct v4l2_fmtdesc *f)
 274{
 275        struct fimc_fmt *fmt;
 276
 277        fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
 278                               f->index);
 279        if (!fmt)
 280                return -EINVAL;
 281
 282        strncpy(f->description, fmt->name, sizeof(f->description) - 1);
 283        f->pixelformat = fmt->fourcc;
 284        return 0;
 285}
 286
 287static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
 288                                 struct v4l2_format *f)
 289{
 290        struct fimc_ctx *ctx = fh_to_ctx(fh);
 291        struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
 292
 293        if (IS_ERR(frame))
 294                return PTR_ERR(frame);
 295
 296        __fimc_get_format(frame, f);
 297        return 0;
 298}
 299
 300static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
 301{
 302        struct fimc_dev *fimc = ctx->fimc_dev;
 303        const struct fimc_variant *variant = fimc->variant;
 304        struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
 305        struct fimc_fmt *fmt;
 306        u32 max_w, mod_x, mod_y;
 307
 308        if (!IS_M2M(f->type))
 309                return -EINVAL;
 310
 311        fmt = fimc_find_format(&pix->pixelformat, NULL,
 312                               get_m2m_fmt_flags(f->type), 0);
 313        if (WARN(fmt == NULL, "Pixel format lookup failed"))
 314                return -EINVAL;
 315
 316        if (pix->field == V4L2_FIELD_ANY)
 317                pix->field = V4L2_FIELD_NONE;
 318        else if (pix->field != V4L2_FIELD_NONE)
 319                return -EINVAL;
 320
 321        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 322                max_w = variant->pix_limit->scaler_dis_w;
 323                mod_x = ffs(variant->min_inp_pixsize) - 1;
 324        } else {
 325                max_w = variant->pix_limit->out_rot_dis_w;
 326                mod_x = ffs(variant->min_out_pixsize) - 1;
 327        }
 328
 329        if (tiled_fmt(fmt)) {
 330                mod_x = 6; /* 64 x 32 pixels tile */
 331                mod_y = 5;
 332        } else {
 333                if (variant->min_vsize_align == 1)
 334                        mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
 335                else
 336                        mod_y = ffs(variant->min_vsize_align) - 1;
 337        }
 338
 339        v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
 340                &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
 341
 342        fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
 343        return 0;
 344}
 345
 346static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
 347                                   struct v4l2_format *f)
 348{
 349        struct fimc_ctx *ctx = fh_to_ctx(fh);
 350        return fimc_try_fmt_mplane(ctx, f);
 351}
 352
 353static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt,
 354                               struct v4l2_pix_format_mplane *pixm)
 355{
 356        int i;
 357
 358        for (i = 0; i < fmt->colplanes; i++) {
 359                frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline;
 360                frame->payload[i] = pixm->plane_fmt[i].sizeimage;
 361        }
 362
 363        frame->f_width = pixm->width;
 364        frame->f_height = pixm->height;
 365        frame->o_width = pixm->width;
 366        frame->o_height = pixm->height;
 367        frame->width = pixm->width;
 368        frame->height = pixm->height;
 369        frame->offs_h = 0;
 370        frame->offs_v = 0;
 371        frame->fmt = fmt;
 372}
 373
 374static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
 375                                 struct v4l2_format *f)
 376{
 377        struct fimc_ctx *ctx = fh_to_ctx(fh);
 378        struct fimc_dev *fimc = ctx->fimc_dev;
 379        struct fimc_fmt *fmt;
 380        struct vb2_queue *vq;
 381        struct fimc_frame *frame;
 382        int ret;
 383
 384        ret = fimc_try_fmt_mplane(ctx, f);
 385        if (ret)
 386                return ret;
 387
 388        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 389
 390        if (vb2_is_busy(vq)) {
 391                v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
 392                return -EBUSY;
 393        }
 394
 395        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 396                frame = &ctx->s_frame;
 397        else
 398                frame = &ctx->d_frame;
 399
 400        fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL,
 401                               get_m2m_fmt_flags(f->type), 0);
 402        if (!fmt)
 403                return -EINVAL;
 404
 405        __set_frame_format(frame, fmt, &f->fmt.pix_mp);
 406
 407        /* Update RGB Alpha control state and value range */
 408        fimc_alpha_ctrl_update(ctx);
 409
 410        return 0;
 411}
 412
 413static int fimc_m2m_reqbufs(struct file *file, void *fh,
 414                            struct v4l2_requestbuffers *reqbufs)
 415{
 416        struct fimc_ctx *ctx = fh_to_ctx(fh);
 417        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 418}
 419
 420static int fimc_m2m_querybuf(struct file *file, void *fh,
 421                             struct v4l2_buffer *buf)
 422{
 423        struct fimc_ctx *ctx = fh_to_ctx(fh);
 424        return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 425}
 426
 427static int fimc_m2m_qbuf(struct file *file, void *fh,
 428                         struct v4l2_buffer *buf)
 429{
 430        struct fimc_ctx *ctx = fh_to_ctx(fh);
 431        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 432}
 433
 434static int fimc_m2m_dqbuf(struct file *file, void *fh,
 435                          struct v4l2_buffer *buf)
 436{
 437        struct fimc_ctx *ctx = fh_to_ctx(fh);
 438        return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 439}
 440
 441static int fimc_m2m_expbuf(struct file *file, void *fh,
 442                            struct v4l2_exportbuffer *eb)
 443{
 444        struct fimc_ctx *ctx = fh_to_ctx(fh);
 445        return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
 446}
 447
 448
 449static int fimc_m2m_streamon(struct file *file, void *fh,
 450                             enum v4l2_buf_type type)
 451{
 452        struct fimc_ctx *ctx = fh_to_ctx(fh);
 453        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 454}
 455
 456static int fimc_m2m_streamoff(struct file *file, void *fh,
 457                            enum v4l2_buf_type type)
 458{
 459        struct fimc_ctx *ctx = fh_to_ctx(fh);
 460        return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 461}
 462
 463static int fimc_m2m_cropcap(struct file *file, void *fh,
 464                            struct v4l2_cropcap *cr)
 465{
 466        struct fimc_ctx *ctx = fh_to_ctx(fh);
 467        struct fimc_frame *frame;
 468
 469        frame = ctx_get_frame(ctx, cr->type);
 470        if (IS_ERR(frame))
 471                return PTR_ERR(frame);
 472
 473        cr->bounds.left = 0;
 474        cr->bounds.top = 0;
 475        cr->bounds.width = frame->o_width;
 476        cr->bounds.height = frame->o_height;
 477        cr->defrect = cr->bounds;
 478
 479        return 0;
 480}
 481
 482static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
 483{
 484        struct fimc_ctx *ctx = fh_to_ctx(fh);
 485        struct fimc_frame *frame;
 486
 487        frame = ctx_get_frame(ctx, cr->type);
 488        if (IS_ERR(frame))
 489                return PTR_ERR(frame);
 490
 491        cr->c.left = frame->offs_h;
 492        cr->c.top = frame->offs_v;
 493        cr->c.width = frame->width;
 494        cr->c.height = frame->height;
 495
 496        return 0;
 497}
 498
 499static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
 500{
 501        struct fimc_dev *fimc = ctx->fimc_dev;
 502        struct fimc_frame *f;
 503        u32 min_size, halign, depth = 0;
 504        int i;
 505
 506        if (cr->c.top < 0 || cr->c.left < 0) {
 507                v4l2_err(&fimc->m2m.vfd,
 508                        "doesn't support negative values for top & left\n");
 509                return -EINVAL;
 510        }
 511        if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 512                f = &ctx->d_frame;
 513        else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
 514                f = &ctx->s_frame;
 515        else
 516                return -EINVAL;
 517
 518        min_size = (f == &ctx->s_frame) ?
 519                fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
 520
 521        /* Get pixel alignment constraints. */
 522        if (fimc->variant->min_vsize_align == 1)
 523                halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
 524        else
 525                halign = ffs(fimc->variant->min_vsize_align) - 1;
 526
 527        for (i = 0; i < f->fmt->colplanes; i++)
 528                depth += f->fmt->depth[i];
 529
 530        v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
 531                              ffs(min_size) - 1,
 532                              &cr->c.height, min_size, f->o_height,
 533                              halign, 64/(ALIGN(depth, 8)));
 534
 535        /* adjust left/top if cropping rectangle is out of bounds */
 536        if (cr->c.left + cr->c.width > f->o_width)
 537                cr->c.left = f->o_width - cr->c.width;
 538        if (cr->c.top + cr->c.height > f->o_height)
 539                cr->c.top = f->o_height - cr->c.height;
 540
 541        cr->c.left = round_down(cr->c.left, min_size);
 542        cr->c.top  = round_down(cr->c.top, fimc->variant->hor_offs_align);
 543
 544        dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
 545            cr->c.left, cr->c.top, cr->c.width, cr->c.height,
 546            f->f_width, f->f_height);
 547
 548        return 0;
 549}
 550
 551static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
 552{
 553        struct fimc_ctx *ctx = fh_to_ctx(fh);
 554        struct fimc_dev *fimc = ctx->fimc_dev;
 555        struct v4l2_crop cr = *crop;
 556        struct fimc_frame *f;
 557        int ret;
 558
 559        ret = fimc_m2m_try_crop(ctx, &cr);
 560        if (ret)
 561                return ret;
 562
 563        f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
 564                &ctx->s_frame : &ctx->d_frame;
 565
 566        /* Check to see if scaling ratio is within supported range */
 567        if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 568                ret = fimc_check_scaler_ratio(ctx, cr.c.width,
 569                                cr.c.height, ctx->d_frame.width,
 570                                ctx->d_frame.height, ctx->rotation);
 571        } else {
 572                ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
 573                                ctx->s_frame.height, cr.c.width,
 574                                cr.c.height, ctx->rotation);
 575        }
 576        if (ret) {
 577                v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
 578                return -EINVAL;
 579        }
 580
 581        f->offs_h = cr.c.left;
 582        f->offs_v = cr.c.top;
 583        f->width  = cr.c.width;
 584        f->height = cr.c.height;
 585
 586        fimc_ctx_state_set(FIMC_PARAMS, ctx);
 587
 588        return 0;
 589}
 590
 591static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
 592        .vidioc_querycap                = fimc_m2m_querycap,
 593        .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane,
 594        .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane,
 595        .vidioc_g_fmt_vid_cap_mplane    = fimc_m2m_g_fmt_mplane,
 596        .vidioc_g_fmt_vid_out_mplane    = fimc_m2m_g_fmt_mplane,
 597        .vidioc_try_fmt_vid_cap_mplane  = fimc_m2m_try_fmt_mplane,
 598        .vidioc_try_fmt_vid_out_mplane  = fimc_m2m_try_fmt_mplane,
 599        .vidioc_s_fmt_vid_cap_mplane    = fimc_m2m_s_fmt_mplane,
 600        .vidioc_s_fmt_vid_out_mplane    = fimc_m2m_s_fmt_mplane,
 601        .vidioc_reqbufs                 = fimc_m2m_reqbufs,
 602        .vidioc_querybuf                = fimc_m2m_querybuf,
 603        .vidioc_qbuf                    = fimc_m2m_qbuf,
 604        .vidioc_dqbuf                   = fimc_m2m_dqbuf,
 605        .vidioc_expbuf                  = fimc_m2m_expbuf,
 606        .vidioc_streamon                = fimc_m2m_streamon,
 607        .vidioc_streamoff               = fimc_m2m_streamoff,
 608        .vidioc_g_crop                  = fimc_m2m_g_crop,
 609        .vidioc_s_crop                  = fimc_m2m_s_crop,
 610        .vidioc_cropcap                 = fimc_m2m_cropcap
 611
 612};
 613
 614static int queue_init(void *priv, struct vb2_queue *src_vq,
 615                      struct vb2_queue *dst_vq)
 616{
 617        struct fimc_ctx *ctx = priv;
 618        int ret;
 619
 620        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 621        src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
 622        src_vq->drv_priv = ctx;
 623        src_vq->ops = &fimc_qops;
 624        src_vq->mem_ops = &vb2_dma_contig_memops;
 625        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 626        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 627
 628        ret = vb2_queue_init(src_vq);
 629        if (ret)
 630                return ret;
 631
 632        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 633        dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
 634        dst_vq->drv_priv = ctx;
 635        dst_vq->ops = &fimc_qops;
 636        dst_vq->mem_ops = &vb2_dma_contig_memops;
 637        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 638        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 639
 640        return vb2_queue_init(dst_vq);
 641}
 642
 643static int fimc_m2m_set_default_format(struct fimc_ctx *ctx)
 644{
 645        struct v4l2_pix_format_mplane pixm = {
 646                .pixelformat    = V4L2_PIX_FMT_RGB32,
 647                .width          = 800,
 648                .height         = 600,
 649                .plane_fmt[0]   = {
 650                        .bytesperline = 800 * 4,
 651                        .sizeimage = 800 * 4 * 600,
 652                },
 653        };
 654        struct fimc_fmt *fmt;
 655
 656        fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0);
 657        if (!fmt)
 658                return -EINVAL;
 659
 660        __set_frame_format(&ctx->s_frame, fmt, &pixm);
 661        __set_frame_format(&ctx->d_frame, fmt, &pixm);
 662
 663        return 0;
 664}
 665
 666static int fimc_m2m_open(struct file *file)
 667{
 668        struct fimc_dev *fimc = video_drvdata(file);
 669        struct fimc_ctx *ctx;
 670        int ret = -EBUSY;
 671
 672        pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state);
 673
 674        if (mutex_lock_interruptible(&fimc->lock))
 675                return -ERESTARTSYS;
 676        /*
 677         * Don't allow simultaneous open() of the mem-to-mem and the
 678         * capture video node that belong to same FIMC IP instance.
 679         */
 680        if (test_bit(ST_CAPT_BUSY, &fimc->state))
 681                goto unlock;
 682
 683        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 684        if (!ctx) {
 685                ret = -ENOMEM;
 686                goto unlock;
 687        }
 688        v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd);
 689        ctx->fimc_dev = fimc;
 690
 691        /* Default color format */
 692        ctx->s_frame.fmt = fimc_get_format(0);
 693        ctx->d_frame.fmt = fimc_get_format(0);
 694
 695        ret = fimc_ctrls_create(ctx);
 696        if (ret)
 697                goto error_fh;
 698
 699        /* Use separate control handler per file handle */
 700        ctx->fh.ctrl_handler = &ctx->ctrls.handler;
 701        file->private_data = &ctx->fh;
 702        v4l2_fh_add(&ctx->fh);
 703
 704        /* Setup the device context for memory-to-memory mode */
 705        ctx->state = FIMC_CTX_M2M;
 706        ctx->flags = 0;
 707        ctx->in_path = FIMC_IO_DMA;
 708        ctx->out_path = FIMC_IO_DMA;
 709        ctx->scaler.enabled = 1;
 710
 711        ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
 712        if (IS_ERR(ctx->m2m_ctx)) {
 713                ret = PTR_ERR(ctx->m2m_ctx);
 714                goto error_c;
 715        }
 716
 717        if (fimc->m2m.refcnt++ == 0)
 718                set_bit(ST_M2M_RUN, &fimc->state);
 719
 720        ret = fimc_m2m_set_default_format(ctx);
 721        if (ret < 0)
 722                goto error_m2m_ctx;
 723
 724        mutex_unlock(&fimc->lock);
 725        return 0;
 726
 727error_m2m_ctx:
 728        v4l2_m2m_ctx_release(ctx->m2m_ctx);
 729error_c:
 730        fimc_ctrls_delete(ctx);
 731error_fh:
 732        v4l2_fh_del(&ctx->fh);
 733        v4l2_fh_exit(&ctx->fh);
 734        kfree(ctx);
 735unlock:
 736        mutex_unlock(&fimc->lock);
 737        return ret;
 738}
 739
 740static int fimc_m2m_release(struct file *file)
 741{
 742        struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
 743        struct fimc_dev *fimc = ctx->fimc_dev;
 744
 745        dbg("pid: %d, state: 0x%lx, refcnt= %d",
 746                task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
 747
 748        mutex_lock(&fimc->lock);
 749
 750        v4l2_m2m_ctx_release(ctx->m2m_ctx);
 751        fimc_ctrls_delete(ctx);
 752        v4l2_fh_del(&ctx->fh);
 753        v4l2_fh_exit(&ctx->fh);
 754
 755        if (--fimc->m2m.refcnt <= 0)
 756                clear_bit(ST_M2M_RUN, &fimc->state);
 757        kfree(ctx);
 758
 759        mutex_unlock(&fimc->lock);
 760        return 0;
 761}
 762
 763static unsigned int fimc_m2m_poll(struct file *file,
 764                                  struct poll_table_struct *wait)
 765{
 766        struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
 767        struct fimc_dev *fimc = ctx->fimc_dev;
 768        int ret;
 769
 770        if (mutex_lock_interruptible(&fimc->lock))
 771                return -ERESTARTSYS;
 772
 773        ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 774        mutex_unlock(&fimc->lock);
 775
 776        return ret;
 777}
 778
 779
 780static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
 781{
 782        struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
 783        struct fimc_dev *fimc = ctx->fimc_dev;
 784        int ret;
 785
 786        if (mutex_lock_interruptible(&fimc->lock))
 787                return -ERESTARTSYS;
 788
 789        ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 790        mutex_unlock(&fimc->lock);
 791
 792        return ret;
 793}
 794
 795static const struct v4l2_file_operations fimc_m2m_fops = {
 796        .owner          = THIS_MODULE,
 797        .open           = fimc_m2m_open,
 798        .release        = fimc_m2m_release,
 799        .poll           = fimc_m2m_poll,
 800        .unlocked_ioctl = video_ioctl2,
 801        .mmap           = fimc_m2m_mmap,
 802};
 803
 804static struct v4l2_m2m_ops m2m_ops = {
 805        .device_run     = fimc_device_run,
 806        .job_abort      = fimc_job_abort,
 807};
 808
 809int fimc_register_m2m_device(struct fimc_dev *fimc,
 810                             struct v4l2_device *v4l2_dev)
 811{
 812        struct video_device *vfd = &fimc->m2m.vfd;
 813        int ret;
 814
 815        fimc->v4l2_dev = v4l2_dev;
 816
 817        memset(vfd, 0, sizeof(*vfd));
 818        vfd->fops = &fimc_m2m_fops;
 819        vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
 820        vfd->v4l2_dev = v4l2_dev;
 821        vfd->minor = -1;
 822        vfd->release = video_device_release_empty;
 823        vfd->lock = &fimc->lock;
 824        vfd->vfl_dir = VFL_DIR_M2M;
 825
 826        snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
 827        video_set_drvdata(vfd, fimc);
 828
 829        fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
 830        if (IS_ERR(fimc->m2m.m2m_dev)) {
 831                v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
 832                return PTR_ERR(fimc->m2m.m2m_dev);
 833        }
 834
 835        ret = media_entity_init(&vfd->entity, 0, NULL, 0);
 836        if (ret)
 837                goto err_me;
 838
 839        ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
 840        if (ret)
 841                goto err_vd;
 842
 843        v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
 844                  vfd->name, video_device_node_name(vfd));
 845        return 0;
 846
 847err_vd:
 848        media_entity_cleanup(&vfd->entity);
 849err_me:
 850        v4l2_m2m_release(fimc->m2m.m2m_dev);
 851        return ret;
 852}
 853
 854void fimc_unregister_m2m_device(struct fimc_dev *fimc)
 855{
 856        if (!fimc)
 857                return;
 858
 859        if (fimc->m2m.m2m_dev)
 860                v4l2_m2m_release(fimc->m2m.m2m_dev);
 861
 862        if (video_is_registered(&fimc->m2m.vfd)) {
 863                video_unregister_device(&fimc->m2m.vfd);
 864                media_entity_cleanup(&fimc->m2m.vfd.entity);
 865        }
 866}
 867