linux/drivers/media/platform/mx2_emmaprp.c
<<
>>
Prefs
   1/*
   2 * Support eMMa-PrP through mem2mem framework.
   3 *
   4 * eMMa-PrP is a piece of HW that allows fetching buffers
   5 * from one memory location and do several operations on
   6 * them such as scaling or format conversion giving, as a result
   7 * a new processed buffer in another memory location.
   8 *
   9 * Based on mem2mem_testdev.c by Pawel Osciak.
  10 *
  11 * Copyright (c) 2011 Vista Silicon S.L.
  12 * Javier Martin <javier.martin@vista-silicon.com>
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by the
  16 * Free Software Foundation; either version 2 of the
  17 * License, or (at your option) any later version
  18 */
  19#include <linux/module.h>
  20#include <linux/clk.h>
  21#include <linux/slab.h>
  22#include <linux/interrupt.h>
  23#include <linux/io.h>
  24
  25#include <linux/platform_device.h>
  26#include <media/v4l2-mem2mem.h>
  27#include <media/v4l2-device.h>
  28#include <media/v4l2-ioctl.h>
  29#include <media/videobuf2-dma-contig.h>
  30#include <asm/sizes.h>
  31
  32#define EMMAPRP_MODULE_NAME "mem2mem-emmaprp"
  33
  34MODULE_DESCRIPTION("Mem-to-mem device which supports eMMa-PrP present in mx2 SoCs");
  35MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
  36MODULE_LICENSE("GPL");
  37MODULE_VERSION("0.0.1");
  38
  39static bool debug;
  40module_param(debug, bool, 0644);
  41
  42#define MIN_W 32
  43#define MIN_H 32
  44#define MAX_W 2040
  45#define MAX_H 2046
  46
  47#define S_ALIGN         1 /* multiple of 2 */
  48#define W_ALIGN_YUV420  3 /* multiple of 8 */
  49#define W_ALIGN_OTHERS  2 /* multiple of 4 */
  50#define H_ALIGN         1 /* multiple of 2 */
  51
  52/* Flags that indicate a format can be used for capture/output */
  53#define MEM2MEM_CAPTURE (1 << 0)
  54#define MEM2MEM_OUTPUT  (1 << 1)
  55
  56#define MEM2MEM_NAME            "m2m-emmaprp"
  57
  58/* In bytes, per queue */
  59#define MEM2MEM_VID_MEM_LIMIT   SZ_16M
  60
  61#define dprintk(dev, fmt, arg...) \
  62        v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
  63
  64/* EMMA PrP */
  65#define PRP_CNTL                        0x00
  66#define PRP_INTR_CNTL                   0x04
  67#define PRP_INTRSTATUS                  0x08
  68#define PRP_SOURCE_Y_PTR                0x0c
  69#define PRP_SOURCE_CB_PTR               0x10
  70#define PRP_SOURCE_CR_PTR               0x14
  71#define PRP_DEST_RGB1_PTR               0x18
  72#define PRP_DEST_RGB2_PTR               0x1c
  73#define PRP_DEST_Y_PTR                  0x20
  74#define PRP_DEST_CB_PTR                 0x24
  75#define PRP_DEST_CR_PTR                 0x28
  76#define PRP_SRC_FRAME_SIZE              0x2c
  77#define PRP_DEST_CH1_LINE_STRIDE        0x30
  78#define PRP_SRC_PIXEL_FORMAT_CNTL       0x34
  79#define PRP_CH1_PIXEL_FORMAT_CNTL       0x38
  80#define PRP_CH1_OUT_IMAGE_SIZE          0x3c
  81#define PRP_CH2_OUT_IMAGE_SIZE          0x40
  82#define PRP_SRC_LINE_STRIDE             0x44
  83#define PRP_CSC_COEF_012                0x48
  84#define PRP_CSC_COEF_345                0x4c
  85#define PRP_CSC_COEF_678                0x50
  86#define PRP_CH1_RZ_HORI_COEF1           0x54
  87#define PRP_CH1_RZ_HORI_COEF2           0x58
  88#define PRP_CH1_RZ_HORI_VALID           0x5c
  89#define PRP_CH1_RZ_VERT_COEF1           0x60
  90#define PRP_CH1_RZ_VERT_COEF2           0x64
  91#define PRP_CH1_RZ_VERT_VALID           0x68
  92#define PRP_CH2_RZ_HORI_COEF1           0x6c
  93#define PRP_CH2_RZ_HORI_COEF2           0x70
  94#define PRP_CH2_RZ_HORI_VALID           0x74
  95#define PRP_CH2_RZ_VERT_COEF1           0x78
  96#define PRP_CH2_RZ_VERT_COEF2           0x7c
  97#define PRP_CH2_RZ_VERT_VALID           0x80
  98
  99#define PRP_CNTL_CH1EN          (1 << 0)
 100#define PRP_CNTL_CH2EN          (1 << 1)
 101#define PRP_CNTL_CSIEN          (1 << 2)
 102#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
 103#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
 104#define PRP_CNTL_DATA_IN_RGB16  (2 << 3)
 105#define PRP_CNTL_DATA_IN_RGB32  (3 << 3)
 106#define PRP_CNTL_CH1_OUT_RGB8   (0 << 5)
 107#define PRP_CNTL_CH1_OUT_RGB16  (1 << 5)
 108#define PRP_CNTL_CH1_OUT_RGB32  (2 << 5)
 109#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
 110#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
 111#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
 112#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
 113#define PRP_CNTL_CH1_LEN        (1 << 9)
 114#define PRP_CNTL_CH2_LEN        (1 << 10)
 115#define PRP_CNTL_SKIP_FRAME     (1 << 11)
 116#define PRP_CNTL_SWRST          (1 << 12)
 117#define PRP_CNTL_CLKEN          (1 << 13)
 118#define PRP_CNTL_WEN            (1 << 14)
 119#define PRP_CNTL_CH1BYP         (1 << 15)
 120#define PRP_CNTL_IN_TSKIP(x)    ((x) << 16)
 121#define PRP_CNTL_CH1_TSKIP(x)   ((x) << 19)
 122#define PRP_CNTL_CH2_TSKIP(x)   ((x) << 22)
 123#define PRP_CNTL_INPUT_FIFO_LEVEL(x)    ((x) << 25)
 124#define PRP_CNTL_RZ_FIFO_LEVEL(x)       ((x) << 27)
 125#define PRP_CNTL_CH2B1EN        (1 << 29)
 126#define PRP_CNTL_CH2B2EN        (1 << 30)
 127#define PRP_CNTL_CH2FEN         (1 << 31)
 128
 129#define PRP_SIZE_HEIGHT(x)      (x)
 130#define PRP_SIZE_WIDTH(x)       ((x) << 16)
 131
 132/* IRQ Enable and status register */
 133#define PRP_INTR_RDERR          (1 << 0)
 134#define PRP_INTR_CH1WERR        (1 << 1)
 135#define PRP_INTR_CH2WERR        (1 << 2)
 136#define PRP_INTR_CH1FC          (1 << 3)
 137#define PRP_INTR_CH2FC          (1 << 5)
 138#define PRP_INTR_LBOVF          (1 << 7)
 139#define PRP_INTR_CH2OVF         (1 << 8)
 140
 141#define PRP_INTR_ST_RDERR       (1 << 0)
 142#define PRP_INTR_ST_CH1WERR     (1 << 1)
 143#define PRP_INTR_ST_CH2WERR     (1 << 2)
 144#define PRP_INTR_ST_CH2B2CI     (1 << 3)
 145#define PRP_INTR_ST_CH2B1CI     (1 << 4)
 146#define PRP_INTR_ST_CH1B2CI     (1 << 5)
 147#define PRP_INTR_ST_CH1B1CI     (1 << 6)
 148#define PRP_INTR_ST_LBOVF       (1 << 7)
 149#define PRP_INTR_ST_CH2OVF      (1 << 8)
 150
 151struct emmaprp_fmt {
 152        char    *name;
 153        u32     fourcc;
 154        /* Types the format can be used for */
 155        u32     types;
 156};
 157
 158static struct emmaprp_fmt formats[] = {
 159        {
 160                .name   = "YUV 4:2:0 Planar",
 161                .fourcc = V4L2_PIX_FMT_YUV420,
 162                .types  = MEM2MEM_CAPTURE,
 163        },
 164        {
 165                .name   = "4:2:2, packed, YUYV",
 166                .fourcc = V4L2_PIX_FMT_YUYV,
 167                .types  = MEM2MEM_OUTPUT,
 168        },
 169};
 170
 171/* Per-queue, driver-specific private data */
 172struct emmaprp_q_data {
 173        unsigned int            width;
 174        unsigned int            height;
 175        unsigned int            sizeimage;
 176        struct emmaprp_fmt      *fmt;
 177};
 178
 179enum {
 180        V4L2_M2M_SRC = 0,
 181        V4L2_M2M_DST = 1,
 182};
 183
 184#define NUM_FORMATS ARRAY_SIZE(formats)
 185
 186static struct emmaprp_fmt *find_format(struct v4l2_format *f)
 187{
 188        struct emmaprp_fmt *fmt;
 189        unsigned int k;
 190
 191        for (k = 0; k < NUM_FORMATS; k++) {
 192                fmt = &formats[k];
 193                if (fmt->fourcc == f->fmt.pix.pixelformat)
 194                        break;
 195        }
 196
 197        if (k == NUM_FORMATS)
 198                return NULL;
 199
 200        return &formats[k];
 201}
 202
 203struct emmaprp_dev {
 204        struct v4l2_device      v4l2_dev;
 205        struct video_device     *vfd;
 206
 207        struct mutex            dev_mutex;
 208        spinlock_t              irqlock;
 209
 210        int                     irq_emma;
 211        void __iomem            *base_emma;
 212        struct clk              *clk_emma_ahb, *clk_emma_ipg;
 213        struct resource         *res_emma;
 214
 215        struct v4l2_m2m_dev     *m2m_dev;
 216        struct vb2_alloc_ctx    *alloc_ctx;
 217};
 218
 219struct emmaprp_ctx {
 220        struct emmaprp_dev      *dev;
 221        /* Abort requested by m2m */
 222        int                     aborting;
 223        struct emmaprp_q_data   q_data[2];
 224        struct v4l2_m2m_ctx     *m2m_ctx;
 225};
 226
 227static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
 228                                         enum v4l2_buf_type type)
 229{
 230        switch (type) {
 231        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 232                return &(ctx->q_data[V4L2_M2M_SRC]);
 233        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 234                return &(ctx->q_data[V4L2_M2M_DST]);
 235        default:
 236                BUG();
 237        }
 238        return NULL;
 239}
 240
 241/*
 242 * mem2mem callbacks
 243 */
 244static void emmaprp_job_abort(void *priv)
 245{
 246        struct emmaprp_ctx *ctx = priv;
 247        struct emmaprp_dev *pcdev = ctx->dev;
 248
 249        ctx->aborting = 1;
 250
 251        dprintk(pcdev, "Aborting task\n");
 252
 253        v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
 254}
 255
 256static void emmaprp_lock(void *priv)
 257{
 258        struct emmaprp_ctx *ctx = priv;
 259        struct emmaprp_dev *pcdev = ctx->dev;
 260        mutex_lock(&pcdev->dev_mutex);
 261}
 262
 263static void emmaprp_unlock(void *priv)
 264{
 265        struct emmaprp_ctx *ctx = priv;
 266        struct emmaprp_dev *pcdev = ctx->dev;
 267        mutex_unlock(&pcdev->dev_mutex);
 268}
 269
 270static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
 271{
 272        dprintk(pcdev,
 273                "eMMa-PrP Registers:\n"
 274                "  SOURCE_Y_PTR = 0x%08X\n"
 275                "  SRC_FRAME_SIZE = 0x%08X\n"
 276                "  DEST_Y_PTR = 0x%08X\n"
 277                "  DEST_CR_PTR = 0x%08X\n"
 278                "  DEST_CB_PTR = 0x%08X\n"
 279                "  CH2_OUT_IMAGE_SIZE = 0x%08X\n"
 280                "  CNTL = 0x%08X\n",
 281                readl(pcdev->base_emma + PRP_SOURCE_Y_PTR),
 282                readl(pcdev->base_emma + PRP_SRC_FRAME_SIZE),
 283                readl(pcdev->base_emma + PRP_DEST_Y_PTR),
 284                readl(pcdev->base_emma + PRP_DEST_CR_PTR),
 285                readl(pcdev->base_emma + PRP_DEST_CB_PTR),
 286                readl(pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE),
 287                readl(pcdev->base_emma + PRP_CNTL));
 288}
 289
 290static void emmaprp_device_run(void *priv)
 291{
 292        struct emmaprp_ctx *ctx = priv;
 293        struct emmaprp_q_data *s_q_data, *d_q_data;
 294        struct vb2_buffer *src_buf, *dst_buf;
 295        struct emmaprp_dev *pcdev = ctx->dev;
 296        unsigned int s_width, s_height;
 297        unsigned int d_width, d_height;
 298        unsigned int d_size;
 299        dma_addr_t p_in, p_out;
 300        u32 tmp;
 301
 302        src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
 303        dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
 304
 305        s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
 306        s_width = s_q_data->width;
 307        s_height = s_q_data->height;
 308
 309        d_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
 310        d_width = d_q_data->width;
 311        d_height = d_q_data->height;
 312        d_size = d_width * d_height;
 313
 314        p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0);
 315        p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
 316        if (!p_in || !p_out) {
 317                v4l2_err(&pcdev->v4l2_dev,
 318                         "Acquiring kernel pointers to buffers failed\n");
 319                return;
 320        }
 321
 322        /* Input frame parameters */
 323        writel(p_in, pcdev->base_emma + PRP_SOURCE_Y_PTR);
 324        writel(PRP_SIZE_WIDTH(s_width) | PRP_SIZE_HEIGHT(s_height),
 325               pcdev->base_emma + PRP_SRC_FRAME_SIZE);
 326
 327        /* Output frame parameters */
 328        writel(p_out, pcdev->base_emma + PRP_DEST_Y_PTR);
 329        writel(p_out + d_size, pcdev->base_emma + PRP_DEST_CB_PTR);
 330        writel(p_out + d_size + (d_size >> 2),
 331               pcdev->base_emma + PRP_DEST_CR_PTR);
 332        writel(PRP_SIZE_WIDTH(d_width) | PRP_SIZE_HEIGHT(d_height),
 333               pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE);
 334
 335        /* IRQ configuration */
 336        tmp = readl(pcdev->base_emma + PRP_INTR_CNTL);
 337        writel(tmp | PRP_INTR_RDERR |
 338                PRP_INTR_CH2WERR |
 339                PRP_INTR_CH2FC,
 340                pcdev->base_emma + PRP_INTR_CNTL);
 341
 342        emmaprp_dump_regs(pcdev);
 343
 344        /* Enable transfer */
 345        tmp = readl(pcdev->base_emma + PRP_CNTL);
 346        writel(tmp | PRP_CNTL_CH2_OUT_YUV420 |
 347                PRP_CNTL_DATA_IN_YUV422 |
 348                PRP_CNTL_CH2EN,
 349                pcdev->base_emma + PRP_CNTL);
 350}
 351
 352static irqreturn_t emmaprp_irq(int irq_emma, void *data)
 353{
 354        struct emmaprp_dev *pcdev = data;
 355        struct emmaprp_ctx *curr_ctx;
 356        struct vb2_buffer *src_vb, *dst_vb;
 357        unsigned long flags;
 358        u32 irqst;
 359
 360        /* Check irq flags and clear irq */
 361        irqst = readl(pcdev->base_emma + PRP_INTRSTATUS);
 362        writel(irqst, pcdev->base_emma + PRP_INTRSTATUS);
 363        dprintk(pcdev, "irqst = 0x%08x\n", irqst);
 364
 365        curr_ctx = v4l2_m2m_get_curr_priv(pcdev->m2m_dev);
 366        if (curr_ctx == NULL) {
 367                pr_err("Instance released before the end of transaction\n");
 368                return IRQ_HANDLED;
 369        }
 370
 371        if (!curr_ctx->aborting) {
 372                if ((irqst & PRP_INTR_ST_RDERR) ||
 373                (irqst & PRP_INTR_ST_CH2WERR)) {
 374                        pr_err("PrP bus error occurred, this transfer is probably corrupted\n");
 375                        writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
 376                } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
 377                        src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
 378                        dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
 379
 380                        src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
 381                        src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
 382
 383                        spin_lock_irqsave(&pcdev->irqlock, flags);
 384                        v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
 385                        v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
 386                        spin_unlock_irqrestore(&pcdev->irqlock, flags);
 387                }
 388        }
 389
 390        v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
 391        return IRQ_HANDLED;
 392}
 393
 394/*
 395 * video ioctls
 396 */
 397static int vidioc_querycap(struct file *file, void *priv,
 398                           struct v4l2_capability *cap)
 399{
 400        strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
 401        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
 402        /*
 403         * This is only a mem-to-mem video device. The capture and output
 404         * device capability flags are left only for backward compatibility
 405         * and are scheduled for removal.
 406         */
 407        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
 408                            V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
 409        return 0;
 410}
 411
 412static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
 413{
 414        int i, num;
 415        struct emmaprp_fmt *fmt;
 416
 417        num = 0;
 418
 419        for (i = 0; i < NUM_FORMATS; ++i) {
 420                if (formats[i].types & type) {
 421                        /* index-th format of type type found ? */
 422                        if (num == f->index)
 423                                break;
 424                        /* Correct type but haven't reached our index yet,
 425                         * just increment per-type index */
 426                        ++num;
 427                }
 428        }
 429
 430        if (i < NUM_FORMATS) {
 431                /* Format found */
 432                fmt = &formats[i];
 433                strlcpy(f->description, fmt->name, sizeof(f->description) - 1);
 434                f->pixelformat = fmt->fourcc;
 435                return 0;
 436        }
 437
 438        /* Format not found */
 439        return -EINVAL;
 440}
 441
 442static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 443                                   struct v4l2_fmtdesc *f)
 444{
 445        return enum_fmt(f, MEM2MEM_CAPTURE);
 446}
 447
 448static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
 449                                   struct v4l2_fmtdesc *f)
 450{
 451        return enum_fmt(f, MEM2MEM_OUTPUT);
 452}
 453
 454static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
 455{
 456        struct vb2_queue *vq;
 457        struct emmaprp_q_data *q_data;
 458
 459        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 460        if (!vq)
 461                return -EINVAL;
 462
 463        q_data = get_q_data(ctx, f->type);
 464
 465        f->fmt.pix.width        = q_data->width;
 466        f->fmt.pix.height       = q_data->height;
 467        f->fmt.pix.field        = V4L2_FIELD_NONE;
 468        f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
 469        if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
 470                f->fmt.pix.bytesperline = q_data->width * 3 / 2;
 471        else /* YUYV */
 472                f->fmt.pix.bytesperline = q_data->width * 2;
 473        f->fmt.pix.sizeimage    = q_data->sizeimage;
 474
 475        return 0;
 476}
 477
 478static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
 479                                struct v4l2_format *f)
 480{
 481        return vidioc_g_fmt(priv, f);
 482}
 483
 484static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 485                                struct v4l2_format *f)
 486{
 487        return vidioc_g_fmt(priv, f);
 488}
 489
 490static int vidioc_try_fmt(struct v4l2_format *f)
 491{
 492        enum v4l2_field field;
 493
 494
 495        if (!find_format(f))
 496                return -EINVAL;
 497
 498        field = f->fmt.pix.field;
 499        if (field == V4L2_FIELD_ANY)
 500                field = V4L2_FIELD_NONE;
 501        else if (V4L2_FIELD_NONE != field)
 502                return -EINVAL;
 503
 504        /* V4L2 specification suggests the driver corrects the format struct
 505         * if any of the dimensions is unsupported */
 506        f->fmt.pix.field = field;
 507
 508        if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
 509                v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
 510                                      W_ALIGN_YUV420, &f->fmt.pix.height,
 511                                      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
 512                f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
 513        } else {
 514                v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
 515                                      W_ALIGN_OTHERS, &f->fmt.pix.height,
 516                                      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
 517                f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
 518        }
 519        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
 520
 521        return 0;
 522}
 523
 524static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 525                                  struct v4l2_format *f)
 526{
 527        struct emmaprp_fmt *fmt;
 528        struct emmaprp_ctx *ctx = priv;
 529
 530        fmt = find_format(f);
 531        if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
 532                v4l2_err(&ctx->dev->v4l2_dev,
 533                         "Fourcc format (0x%08x) invalid.\n",
 534                         f->fmt.pix.pixelformat);
 535                return -EINVAL;
 536        }
 537
 538        return vidioc_try_fmt(f);
 539}
 540
 541static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
 542                                  struct v4l2_format *f)
 543{
 544        struct emmaprp_fmt *fmt;
 545        struct emmaprp_ctx *ctx = priv;
 546
 547        fmt = find_format(f);
 548        if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
 549                v4l2_err(&ctx->dev->v4l2_dev,
 550                         "Fourcc format (0x%08x) invalid.\n",
 551                         f->fmt.pix.pixelformat);
 552                return -EINVAL;
 553        }
 554
 555        return vidioc_try_fmt(f);
 556}
 557
 558static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
 559{
 560        struct emmaprp_q_data *q_data;
 561        struct vb2_queue *vq;
 562        int ret;
 563
 564        vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
 565        if (!vq)
 566                return -EINVAL;
 567
 568        q_data = get_q_data(ctx, f->type);
 569        if (!q_data)
 570                return -EINVAL;
 571
 572        if (vb2_is_busy(vq)) {
 573                v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
 574                return -EBUSY;
 575        }
 576
 577        ret = vidioc_try_fmt(f);
 578        if (ret)
 579                return ret;
 580
 581        q_data->fmt             = find_format(f);
 582        q_data->width           = f->fmt.pix.width;
 583        q_data->height          = f->fmt.pix.height;
 584        if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
 585                q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
 586        else /* YUYV */
 587                q_data->sizeimage = q_data->width * q_data->height * 2;
 588
 589        dprintk(ctx->dev,
 590                "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
 591                f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
 592
 593        return 0;
 594}
 595
 596static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 597                                struct v4l2_format *f)
 598{
 599        int ret;
 600
 601        ret = vidioc_try_fmt_vid_cap(file, priv, f);
 602        if (ret)
 603                return ret;
 604
 605        return vidioc_s_fmt(priv, f);
 606}
 607
 608static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
 609                                struct v4l2_format *f)
 610{
 611        int ret;
 612
 613        ret = vidioc_try_fmt_vid_out(file, priv, f);
 614        if (ret)
 615                return ret;
 616
 617        return vidioc_s_fmt(priv, f);
 618}
 619
 620static int vidioc_reqbufs(struct file *file, void *priv,
 621                          struct v4l2_requestbuffers *reqbufs)
 622{
 623        struct emmaprp_ctx *ctx = priv;
 624
 625        return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
 626}
 627
 628static int vidioc_querybuf(struct file *file, void *priv,
 629                           struct v4l2_buffer *buf)
 630{
 631        struct emmaprp_ctx *ctx = priv;
 632
 633        return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
 634}
 635
 636static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 637{
 638        struct emmaprp_ctx *ctx = priv;
 639
 640        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 641}
 642
 643static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 644{
 645        struct emmaprp_ctx *ctx = priv;
 646
 647        return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
 648}
 649
 650static int vidioc_streamon(struct file *file, void *priv,
 651                           enum v4l2_buf_type type)
 652{
 653        struct emmaprp_ctx *ctx = priv;
 654
 655        return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
 656}
 657
 658static int vidioc_streamoff(struct file *file, void *priv,
 659                            enum v4l2_buf_type type)
 660{
 661        struct emmaprp_ctx *ctx = priv;
 662
 663        return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
 664}
 665
 666static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
 667        .vidioc_querycap        = vidioc_querycap,
 668
 669        .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
 670        .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
 671        .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
 672        .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
 673
 674        .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
 675        .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
 676        .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
 677        .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
 678
 679        .vidioc_reqbufs         = vidioc_reqbufs,
 680        .vidioc_querybuf        = vidioc_querybuf,
 681
 682        .vidioc_qbuf            = vidioc_qbuf,
 683        .vidioc_dqbuf           = vidioc_dqbuf,
 684
 685        .vidioc_streamon        = vidioc_streamon,
 686        .vidioc_streamoff       = vidioc_streamoff,
 687};
 688
 689
 690/*
 691 * Queue operations
 692 */
 693static int emmaprp_queue_setup(struct vb2_queue *vq,
 694                                const struct v4l2_format *fmt,
 695                                unsigned int *nbuffers, unsigned int *nplanes,
 696                                unsigned int sizes[], void *alloc_ctxs[])
 697{
 698        struct emmaprp_ctx *ctx = vb2_get_drv_priv(vq);
 699        struct emmaprp_q_data *q_data;
 700        unsigned int size, count = *nbuffers;
 701
 702        q_data = get_q_data(ctx, vq->type);
 703
 704        if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420)
 705                size = q_data->width * q_data->height * 3 / 2;
 706        else
 707                size = q_data->width * q_data->height * 2;
 708
 709        while (size * count > MEM2MEM_VID_MEM_LIMIT)
 710                (count)--;
 711
 712        *nplanes = 1;
 713        *nbuffers = count;
 714        sizes[0] = size;
 715
 716        alloc_ctxs[0] = ctx->dev->alloc_ctx;
 717
 718        dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
 719
 720        return 0;
 721}
 722
 723static int emmaprp_buf_prepare(struct vb2_buffer *vb)
 724{
 725        struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 726        struct emmaprp_q_data *q_data;
 727
 728        dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
 729
 730        q_data = get_q_data(ctx, vb->vb2_queue->type);
 731
 732        if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
 733                dprintk(ctx->dev, "%s data will not fit into plane"
 734                                  "(%lu < %lu)\n", __func__,
 735                                  vb2_plane_size(vb, 0),
 736                                  (long)q_data->sizeimage);
 737                return -EINVAL;
 738        }
 739
 740        vb2_set_plane_payload(vb, 0, q_data->sizeimage);
 741
 742        return 0;
 743}
 744
 745static void emmaprp_buf_queue(struct vb2_buffer *vb)
 746{
 747        struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 748        v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
 749}
 750
 751static struct vb2_ops emmaprp_qops = {
 752        .queue_setup     = emmaprp_queue_setup,
 753        .buf_prepare     = emmaprp_buf_prepare,
 754        .buf_queue       = emmaprp_buf_queue,
 755};
 756
 757static int queue_init(void *priv, struct vb2_queue *src_vq,
 758                      struct vb2_queue *dst_vq)
 759{
 760        struct emmaprp_ctx *ctx = priv;
 761        int ret;
 762
 763        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
 764        src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 765        src_vq->drv_priv = ctx;
 766        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 767        src_vq->ops = &emmaprp_qops;
 768        src_vq->mem_ops = &vb2_dma_contig_memops;
 769        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 770
 771        ret = vb2_queue_init(src_vq);
 772        if (ret)
 773                return ret;
 774
 775        dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 776        dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 777        dst_vq->drv_priv = ctx;
 778        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
 779        dst_vq->ops = &emmaprp_qops;
 780        dst_vq->mem_ops = &vb2_dma_contig_memops;
 781        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 782
 783        return vb2_queue_init(dst_vq);
 784}
 785
 786/*
 787 * File operations
 788 */
 789static int emmaprp_open(struct file *file)
 790{
 791        struct emmaprp_dev *pcdev = video_drvdata(file);
 792        struct emmaprp_ctx *ctx;
 793
 794        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
 795        if (!ctx)
 796                return -ENOMEM;
 797
 798        file->private_data = ctx;
 799        ctx->dev = pcdev;
 800
 801        if (mutex_lock_interruptible(&pcdev->dev_mutex)) {
 802                kfree(ctx);
 803                return -ERESTARTSYS;
 804        }
 805
 806        ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
 807
 808        if (IS_ERR(ctx->m2m_ctx)) {
 809                int ret = PTR_ERR(ctx->m2m_ctx);
 810
 811                mutex_unlock(&pcdev->dev_mutex);
 812                kfree(ctx);
 813                return ret;
 814        }
 815
 816        clk_prepare_enable(pcdev->clk_emma_ipg);
 817        clk_prepare_enable(pcdev->clk_emma_ahb);
 818        ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
 819        ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
 820        mutex_unlock(&pcdev->dev_mutex);
 821
 822        dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
 823
 824        return 0;
 825}
 826
 827static int emmaprp_release(struct file *file)
 828{
 829        struct emmaprp_dev *pcdev = video_drvdata(file);
 830        struct emmaprp_ctx *ctx = file->private_data;
 831
 832        dprintk(pcdev, "Releasing instance %p\n", ctx);
 833
 834        mutex_lock(&pcdev->dev_mutex);
 835        clk_disable_unprepare(pcdev->clk_emma_ahb);
 836        clk_disable_unprepare(pcdev->clk_emma_ipg);
 837        v4l2_m2m_ctx_release(ctx->m2m_ctx);
 838        mutex_unlock(&pcdev->dev_mutex);
 839        kfree(ctx);
 840
 841        return 0;
 842}
 843
 844static unsigned int emmaprp_poll(struct file *file,
 845                                 struct poll_table_struct *wait)
 846{
 847        struct emmaprp_dev *pcdev = video_drvdata(file);
 848        struct emmaprp_ctx *ctx = file->private_data;
 849        unsigned int res;
 850
 851        mutex_lock(&pcdev->dev_mutex);
 852        res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
 853        mutex_unlock(&pcdev->dev_mutex);
 854        return res;
 855}
 856
 857static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
 858{
 859        struct emmaprp_dev *pcdev = video_drvdata(file);
 860        struct emmaprp_ctx *ctx = file->private_data;
 861        int ret;
 862
 863        if (mutex_lock_interruptible(&pcdev->dev_mutex))
 864                return -ERESTARTSYS;
 865        ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
 866        mutex_unlock(&pcdev->dev_mutex);
 867        return ret;
 868}
 869
 870static const struct v4l2_file_operations emmaprp_fops = {
 871        .owner          = THIS_MODULE,
 872        .open           = emmaprp_open,
 873        .release        = emmaprp_release,
 874        .poll           = emmaprp_poll,
 875        .unlocked_ioctl = video_ioctl2,
 876        .mmap           = emmaprp_mmap,
 877};
 878
 879static struct video_device emmaprp_videodev = {
 880        .name           = MEM2MEM_NAME,
 881        .fops           = &emmaprp_fops,
 882        .ioctl_ops      = &emmaprp_ioctl_ops,
 883        .minor          = -1,
 884        .release        = video_device_release,
 885        .vfl_dir        = VFL_DIR_M2M,
 886};
 887
 888static struct v4l2_m2m_ops m2m_ops = {
 889        .device_run     = emmaprp_device_run,
 890        .job_abort      = emmaprp_job_abort,
 891        .lock           = emmaprp_lock,
 892        .unlock         = emmaprp_unlock,
 893};
 894
 895static int emmaprp_probe(struct platform_device *pdev)
 896{
 897        struct emmaprp_dev *pcdev;
 898        struct video_device *vfd;
 899        struct resource *res_emma;
 900        int irq_emma;
 901        int ret;
 902
 903        pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
 904        if (!pcdev)
 905                return -ENOMEM;
 906
 907        spin_lock_init(&pcdev->irqlock);
 908
 909        pcdev->clk_emma_ipg = devm_clk_get(&pdev->dev, "ipg");
 910        if (IS_ERR(pcdev->clk_emma_ipg)) {
 911                return PTR_ERR(pcdev->clk_emma_ipg);
 912        }
 913
 914        pcdev->clk_emma_ahb = devm_clk_get(&pdev->dev, "ahb");
 915        if (IS_ERR(pcdev->clk_emma_ahb))
 916                return PTR_ERR(pcdev->clk_emma_ahb);
 917
 918        irq_emma = platform_get_irq(pdev, 0);
 919        res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 920        if (irq_emma < 0 || res_emma == NULL) {
 921                dev_err(&pdev->dev, "Missing platform resources data\n");
 922                return -ENODEV;
 923        }
 924
 925        ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
 926        if (ret)
 927                return ret;
 928
 929        mutex_init(&pcdev->dev_mutex);
 930
 931        vfd = video_device_alloc();
 932        if (!vfd) {
 933                v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
 934                ret = -ENOMEM;
 935                goto unreg_dev;
 936        }
 937
 938        *vfd = emmaprp_videodev;
 939        vfd->lock = &pcdev->dev_mutex;
 940
 941        video_set_drvdata(vfd, pcdev);
 942        snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name);
 943        pcdev->vfd = vfd;
 944        v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME
 945                        " Device registered as /dev/video%d\n", vfd->num);
 946
 947        platform_set_drvdata(pdev, pcdev);
 948
 949        pcdev->base_emma = devm_ioremap_resource(&pdev->dev, res_emma);
 950        if (IS_ERR(pcdev->base_emma)) {
 951                ret = PTR_ERR(pcdev->base_emma);
 952                goto rel_vdev;
 953        }
 954
 955        pcdev->irq_emma = irq_emma;
 956        pcdev->res_emma = res_emma;
 957
 958        if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
 959                             0, MEM2MEM_NAME, pcdev) < 0) {
 960                ret = -ENODEV;
 961                goto rel_vdev;
 962        }
 963
 964        pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
 965        if (IS_ERR(pcdev->alloc_ctx)) {
 966                v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
 967                ret = PTR_ERR(pcdev->alloc_ctx);
 968                goto rel_vdev;
 969        }
 970
 971        pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
 972        if (IS_ERR(pcdev->m2m_dev)) {
 973                v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
 974                ret = PTR_ERR(pcdev->m2m_dev);
 975                goto rel_ctx;
 976        }
 977
 978        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
 979        if (ret) {
 980                v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
 981                goto rel_m2m;
 982        }
 983
 984        return 0;
 985
 986
 987rel_m2m:
 988        v4l2_m2m_release(pcdev->m2m_dev);
 989rel_ctx:
 990        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
 991rel_vdev:
 992        video_device_release(vfd);
 993unreg_dev:
 994        v4l2_device_unregister(&pcdev->v4l2_dev);
 995
 996        return ret;
 997}
 998
 999static int emmaprp_remove(struct platform_device *pdev)
1000{
1001        struct emmaprp_dev *pcdev = platform_get_drvdata(pdev);
1002
1003        v4l2_info(&pcdev->v4l2_dev, "Removing " EMMAPRP_MODULE_NAME);
1004
1005        video_unregister_device(pcdev->vfd);
1006        v4l2_m2m_release(pcdev->m2m_dev);
1007        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
1008        v4l2_device_unregister(&pcdev->v4l2_dev);
1009
1010        return 0;
1011}
1012
1013static struct platform_driver emmaprp_pdrv = {
1014        .probe          = emmaprp_probe,
1015        .remove         = emmaprp_remove,
1016        .driver         = {
1017                .name   = MEM2MEM_NAME,
1018                .owner  = THIS_MODULE,
1019        },
1020};
1021module_platform_driver(emmaprp_pdrv);
1022