linux/drivers/staging/media/imx/imx-ic-prpencvf.c
<<
>>
Prefs
   1/*
   2 * V4L2 Capture IC Preprocess Subdev for Freescale i.MX5/6 SOC
   3 *
   4 * This subdevice handles capture of video frames from the CSI or VDIC,
   5 * which are routed directly to the Image Converter preprocess tasks,
   6 * for resizing, colorspace conversion, and rotation.
   7 *
   8 * Copyright (c) 2012-2017 Mentor Graphics Inc.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 */
  15#include <linux/delay.h>
  16#include <linux/interrupt.h>
  17#include <linux/module.h>
  18#include <linux/sched.h>
  19#include <linux/slab.h>
  20#include <linux/spinlock.h>
  21#include <linux/timer.h>
  22#include <media/v4l2-ctrls.h>
  23#include <media/v4l2-device.h>
  24#include <media/v4l2-ioctl.h>
  25#include <media/v4l2-mc.h>
  26#include <media/v4l2-subdev.h>
  27#include <media/imx.h>
  28#include "imx-media.h"
  29#include "imx-ic.h"
  30
  31/*
  32 * Min/Max supported width and heights.
  33 *
  34 * We allow planar output, so we have to align width at the source pad
  35 * by 16 pixels to meet IDMAC alignment requirements for possible planar
  36 * output.
  37 *
  38 * TODO: move this into pad format negotiation, if capture device
  39 * has not requested a planar format, we should allow 8 pixel
  40 * alignment at the source pad.
  41 */
  42#define MIN_W_SINK  176
  43#define MIN_H_SINK  144
  44#define MAX_W_SINK 4096
  45#define MAX_H_SINK 4096
  46#define W_ALIGN_SINK  3 /* multiple of 8 pixels */
  47#define H_ALIGN_SINK  1 /* multiple of 2 lines */
  48
  49#define MAX_W_SRC  1024
  50#define MAX_H_SRC  1024
  51#define W_ALIGN_SRC   4 /* multiple of 16 pixels */
  52#define H_ALIGN_SRC   1 /* multiple of 2 lines */
  53
  54#define S_ALIGN       1 /* multiple of 2 */
  55
  56struct prp_priv {
  57        struct imx_media_dev *md;
  58        struct imx_ic_priv *ic_priv;
  59        struct media_pad pad[PRPENCVF_NUM_PADS];
  60        /* the video device at output pad */
  61        struct imx_media_video_dev *vdev;
  62
  63        /* lock to protect all members below */
  64        struct mutex lock;
  65
  66        /* IPU units we require */
  67        struct ipu_soc *ipu;
  68        struct ipu_ic *ic;
  69        struct ipuv3_channel *out_ch;
  70        struct ipuv3_channel *rot_in_ch;
  71        struct ipuv3_channel *rot_out_ch;
  72
  73        /* active vb2 buffers to send to video dev sink */
  74        struct imx_media_buffer *active_vb2_buf[2];
  75        struct imx_media_dma_buf underrun_buf;
  76
  77        int ipu_buf_num;  /* ipu double buffer index: 0-1 */
  78
  79        /* the sink for the captured frames */
  80        struct media_entity *sink;
  81        /* the source subdev */
  82        struct v4l2_subdev *src_sd;
  83
  84        struct v4l2_mbus_framefmt format_mbus[PRPENCVF_NUM_PADS];
  85        const struct imx_media_pixfmt *cc[PRPENCVF_NUM_PADS];
  86        struct v4l2_fract frame_interval;
  87
  88        struct imx_media_dma_buf rot_buf[2];
  89
  90        /* controls */
  91        struct v4l2_ctrl_handler ctrl_hdlr;
  92        int  rotation; /* degrees */
  93        bool hflip;
  94        bool vflip;
  95
  96        /* derived from rotation, hflip, vflip controls */
  97        enum ipu_rotate_mode rot_mode;
  98
  99        spinlock_t irqlock; /* protect eof_irq handler */
 100
 101        struct timer_list eof_timeout_timer;
 102        int eof_irq;
 103        int nfb4eof_irq;
 104
 105        int stream_count;
 106        bool last_eof;  /* waiting for last EOF at stream off */
 107        bool nfb4eof;    /* NFB4EOF encountered during streaming */
 108        struct completion last_eof_comp;
 109};
 110
 111static const struct prp_channels {
 112        u32 out_ch;
 113        u32 rot_in_ch;
 114        u32 rot_out_ch;
 115} prp_channel[] = {
 116        [IC_TASK_ENCODER] = {
 117                .out_ch = IPUV3_CHANNEL_IC_PRP_ENC_MEM,
 118                .rot_in_ch = IPUV3_CHANNEL_MEM_ROT_ENC,
 119                .rot_out_ch = IPUV3_CHANNEL_ROT_ENC_MEM,
 120        },
 121        [IC_TASK_VIEWFINDER] = {
 122                .out_ch = IPUV3_CHANNEL_IC_PRP_VF_MEM,
 123                .rot_in_ch = IPUV3_CHANNEL_MEM_ROT_VF,
 124                .rot_out_ch = IPUV3_CHANNEL_ROT_VF_MEM,
 125        },
 126};
 127
 128static inline struct prp_priv *sd_to_priv(struct v4l2_subdev *sd)
 129{
 130        struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
 131
 132        return ic_priv->task_priv;
 133}
 134
 135static void prp_put_ipu_resources(struct prp_priv *priv)
 136{
 137        if (priv->ic)
 138                ipu_ic_put(priv->ic);
 139        priv->ic = NULL;
 140
 141        if (priv->out_ch)
 142                ipu_idmac_put(priv->out_ch);
 143        priv->out_ch = NULL;
 144
 145        if (priv->rot_in_ch)
 146                ipu_idmac_put(priv->rot_in_ch);
 147        priv->rot_in_ch = NULL;
 148
 149        if (priv->rot_out_ch)
 150                ipu_idmac_put(priv->rot_out_ch);
 151        priv->rot_out_ch = NULL;
 152}
 153
 154static int prp_get_ipu_resources(struct prp_priv *priv)
 155{
 156        struct imx_ic_priv *ic_priv = priv->ic_priv;
 157        struct ipu_ic *ic;
 158        struct ipuv3_channel *out_ch, *rot_in_ch, *rot_out_ch;
 159        int ret, task = ic_priv->task_id;
 160
 161        priv->ipu = priv->md->ipu[ic_priv->ipu_id];
 162
 163        ic = ipu_ic_get(priv->ipu, task);
 164        if (IS_ERR(ic)) {
 165                v4l2_err(&ic_priv->sd, "failed to get IC\n");
 166                ret = PTR_ERR(ic);
 167                goto out;
 168        }
 169        priv->ic = ic;
 170
 171        out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].out_ch);
 172        if (IS_ERR(out_ch)) {
 173                v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
 174                         prp_channel[task].out_ch);
 175                ret = PTR_ERR(out_ch);
 176                goto out;
 177        }
 178        priv->out_ch = out_ch;
 179
 180        rot_in_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_in_ch);
 181        if (IS_ERR(rot_in_ch)) {
 182                v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
 183                         prp_channel[task].rot_in_ch);
 184                ret = PTR_ERR(rot_in_ch);
 185                goto out;
 186        }
 187        priv->rot_in_ch = rot_in_ch;
 188
 189        rot_out_ch = ipu_idmac_get(priv->ipu, prp_channel[task].rot_out_ch);
 190        if (IS_ERR(rot_out_ch)) {
 191                v4l2_err(&ic_priv->sd, "could not get IDMAC channel %u\n",
 192                         prp_channel[task].rot_out_ch);
 193                ret = PTR_ERR(rot_out_ch);
 194                goto out;
 195        }
 196        priv->rot_out_ch = rot_out_ch;
 197
 198        return 0;
 199out:
 200        prp_put_ipu_resources(priv);
 201        return ret;
 202}
 203
 204static void prp_vb2_buf_done(struct prp_priv *priv, struct ipuv3_channel *ch)
 205{
 206        struct imx_media_video_dev *vdev = priv->vdev;
 207        struct imx_media_buffer *done, *next;
 208        struct vb2_buffer *vb;
 209        dma_addr_t phys;
 210
 211        done = priv->active_vb2_buf[priv->ipu_buf_num];
 212        if (done) {
 213                vb = &done->vbuf.vb2_buf;
 214                vb->timestamp = ktime_get_ns();
 215                vb2_buffer_done(vb, priv->nfb4eof ?
 216                                VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
 217        }
 218
 219        priv->nfb4eof = false;
 220
 221        /* get next queued buffer */
 222        next = imx_media_capture_device_next_buf(vdev);
 223        if (next) {
 224                phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
 225                priv->active_vb2_buf[priv->ipu_buf_num] = next;
 226        } else {
 227                phys = priv->underrun_buf.phys;
 228                priv->active_vb2_buf[priv->ipu_buf_num] = NULL;
 229        }
 230
 231        if (ipu_idmac_buffer_is_ready(ch, priv->ipu_buf_num))
 232                ipu_idmac_clear_buffer(ch, priv->ipu_buf_num);
 233
 234        ipu_cpmem_set_buffer(ch, priv->ipu_buf_num, phys);
 235}
 236
 237static irqreturn_t prp_eof_interrupt(int irq, void *dev_id)
 238{
 239        struct prp_priv *priv = dev_id;
 240        struct ipuv3_channel *channel;
 241
 242        spin_lock(&priv->irqlock);
 243
 244        if (priv->last_eof) {
 245                complete(&priv->last_eof_comp);
 246                priv->last_eof = false;
 247                goto unlock;
 248        }
 249
 250        channel = (ipu_rot_mode_is_irt(priv->rot_mode)) ?
 251                priv->rot_out_ch : priv->out_ch;
 252
 253        prp_vb2_buf_done(priv, channel);
 254
 255        /* select new IPU buf */
 256        ipu_idmac_select_buffer(channel, priv->ipu_buf_num);
 257        /* toggle IPU double-buffer index */
 258        priv->ipu_buf_num ^= 1;
 259
 260        /* bump the EOF timeout timer */
 261        mod_timer(&priv->eof_timeout_timer,
 262                  jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
 263
 264unlock:
 265        spin_unlock(&priv->irqlock);
 266        return IRQ_HANDLED;
 267}
 268
 269static irqreturn_t prp_nfb4eof_interrupt(int irq, void *dev_id)
 270{
 271        struct prp_priv *priv = dev_id;
 272        struct imx_ic_priv *ic_priv = priv->ic_priv;
 273
 274        spin_lock(&priv->irqlock);
 275
 276        /*
 277         * this is not an unrecoverable error, just mark
 278         * the next captured frame with vb2 error flag.
 279         */
 280        priv->nfb4eof = true;
 281
 282        v4l2_err(&ic_priv->sd, "NFB4EOF\n");
 283
 284        spin_unlock(&priv->irqlock);
 285
 286        return IRQ_HANDLED;
 287}
 288
 289/*
 290 * EOF timeout timer function.
 291 */
 292/*
 293 * EOF timeout timer function. This is an unrecoverable condition
 294 * without a stream restart.
 295 */
 296static void prp_eof_timeout(struct timer_list *t)
 297{
 298        struct prp_priv *priv = from_timer(priv, t, eof_timeout_timer);
 299        struct imx_media_video_dev *vdev = priv->vdev;
 300        struct imx_ic_priv *ic_priv = priv->ic_priv;
 301
 302        v4l2_err(&ic_priv->sd, "EOF timeout\n");
 303
 304        /* signal a fatal error to capture device */
 305        imx_media_capture_device_error(vdev);
 306}
 307
 308static void prp_setup_vb2_buf(struct prp_priv *priv, dma_addr_t *phys)
 309{
 310        struct imx_media_video_dev *vdev = priv->vdev;
 311        struct imx_media_buffer *buf;
 312        int i;
 313
 314        for (i = 0; i < 2; i++) {
 315                buf = imx_media_capture_device_next_buf(vdev);
 316                if (buf) {
 317                        priv->active_vb2_buf[i] = buf;
 318                        phys[i] = vb2_dma_contig_plane_dma_addr(
 319                                &buf->vbuf.vb2_buf, 0);
 320                } else {
 321                        priv->active_vb2_buf[i] = NULL;
 322                        phys[i] = priv->underrun_buf.phys;
 323                }
 324        }
 325}
 326
 327static void prp_unsetup_vb2_buf(struct prp_priv *priv,
 328                                enum vb2_buffer_state return_status)
 329{
 330        struct imx_media_buffer *buf;
 331        int i;
 332
 333        /* return any remaining active frames with return_status */
 334        for (i = 0; i < 2; i++) {
 335                buf = priv->active_vb2_buf[i];
 336                if (buf) {
 337                        struct vb2_buffer *vb = &buf->vbuf.vb2_buf;
 338
 339                        vb->timestamp = ktime_get_ns();
 340                        vb2_buffer_done(vb, return_status);
 341                }
 342        }
 343}
 344
 345static int prp_setup_channel(struct prp_priv *priv,
 346                             struct ipuv3_channel *channel,
 347                             enum ipu_rotate_mode rot_mode,
 348                             dma_addr_t addr0, dma_addr_t addr1,
 349                             bool rot_swap_width_height)
 350{
 351        struct imx_media_video_dev *vdev = priv->vdev;
 352        const struct imx_media_pixfmt *outcc;
 353        struct v4l2_mbus_framefmt *infmt;
 354        unsigned int burst_size;
 355        struct ipu_image image;
 356        int ret;
 357
 358        infmt = &priv->format_mbus[PRPENCVF_SINK_PAD];
 359        outcc = vdev->cc;
 360
 361        ipu_cpmem_zero(channel);
 362
 363        memset(&image, 0, sizeof(image));
 364        image.pix = vdev->fmt.fmt.pix;
 365        image.rect.width = image.pix.width;
 366        image.rect.height = image.pix.height;
 367
 368        if (rot_swap_width_height) {
 369                swap(image.pix.width, image.pix.height);
 370                swap(image.rect.width, image.rect.height);
 371                /* recalc stride using swapped width */
 372                image.pix.bytesperline = outcc->planar ?
 373                        image.pix.width :
 374                        (image.pix.width * outcc->bpp) >> 3;
 375        }
 376
 377        image.phys0 = addr0;
 378        image.phys1 = addr1;
 379
 380        if (channel == priv->out_ch || channel == priv->rot_out_ch) {
 381                switch (image.pix.pixelformat) {
 382                case V4L2_PIX_FMT_YUV420:
 383                case V4L2_PIX_FMT_YVU420:
 384                case V4L2_PIX_FMT_NV12:
 385                        /* Skip writing U and V components to odd rows */
 386                        ipu_cpmem_skip_odd_chroma_rows(channel);
 387                        break;
 388                }
 389        }
 390
 391        ret = ipu_cpmem_set_image(channel, &image);
 392        if (ret)
 393                return ret;
 394
 395        if (channel == priv->rot_in_ch ||
 396            channel == priv->rot_out_ch) {
 397                burst_size = 8;
 398                ipu_cpmem_set_block_mode(channel);
 399        } else {
 400                burst_size = (image.pix.width & 0xf) ? 8 : 16;
 401        }
 402
 403        ipu_cpmem_set_burstsize(channel, burst_size);
 404
 405        if (rot_mode)
 406                ipu_cpmem_set_rotation(channel, rot_mode);
 407
 408        if (image.pix.field == V4L2_FIELD_NONE &&
 409            V4L2_FIELD_HAS_BOTH(infmt->field) &&
 410            channel == priv->out_ch)
 411                ipu_cpmem_interlaced_scan(channel, image.pix.bytesperline);
 412
 413        ret = ipu_ic_task_idma_init(priv->ic, channel,
 414                                    image.pix.width, image.pix.height,
 415                                    burst_size, rot_mode);
 416        if (ret)
 417                return ret;
 418
 419        ipu_cpmem_set_axi_id(channel, 1);
 420
 421        ipu_idmac_set_double_buffer(channel, true);
 422
 423        return 0;
 424}
 425
 426static int prp_setup_rotation(struct prp_priv *priv)
 427{
 428        struct imx_media_video_dev *vdev = priv->vdev;
 429        struct imx_ic_priv *ic_priv = priv->ic_priv;
 430        const struct imx_media_pixfmt *outcc, *incc;
 431        struct v4l2_mbus_framefmt *infmt;
 432        struct v4l2_pix_format *outfmt;
 433        dma_addr_t phys[2];
 434        int ret;
 435
 436        infmt = &priv->format_mbus[PRPENCVF_SINK_PAD];
 437        outfmt = &vdev->fmt.fmt.pix;
 438        incc = priv->cc[PRPENCVF_SINK_PAD];
 439        outcc = vdev->cc;
 440
 441        ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[0],
 442                                      outfmt->sizeimage);
 443        if (ret) {
 444                v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[0], %d\n", ret);
 445                return ret;
 446        }
 447        ret = imx_media_alloc_dma_buf(priv->md, &priv->rot_buf[1],
 448                                      outfmt->sizeimage);
 449        if (ret) {
 450                v4l2_err(&ic_priv->sd, "failed to alloc rot_buf[1], %d\n", ret);
 451                goto free_rot0;
 452        }
 453
 454        ret = ipu_ic_task_init(priv->ic,
 455                               infmt->width, infmt->height,
 456                               outfmt->height, outfmt->width,
 457                               incc->cs, outcc->cs);
 458        if (ret) {
 459                v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret);
 460                goto free_rot1;
 461        }
 462
 463        /* init the IC-PRP-->MEM IDMAC channel */
 464        ret = prp_setup_channel(priv, priv->out_ch, IPU_ROTATE_NONE,
 465                                priv->rot_buf[0].phys, priv->rot_buf[1].phys,
 466                                true);
 467        if (ret) {
 468                v4l2_err(&ic_priv->sd,
 469                         "prp_setup_channel(out_ch) failed, %d\n", ret);
 470                goto free_rot1;
 471        }
 472
 473        /* init the MEM-->IC-PRP ROT IDMAC channel */
 474        ret = prp_setup_channel(priv, priv->rot_in_ch, priv->rot_mode,
 475                                priv->rot_buf[0].phys, priv->rot_buf[1].phys,
 476                                true);
 477        if (ret) {
 478                v4l2_err(&ic_priv->sd,
 479                         "prp_setup_channel(rot_in_ch) failed, %d\n", ret);
 480                goto free_rot1;
 481        }
 482
 483        prp_setup_vb2_buf(priv, phys);
 484
 485        /* init the destination IC-PRP ROT-->MEM IDMAC channel */
 486        ret = prp_setup_channel(priv, priv->rot_out_ch, IPU_ROTATE_NONE,
 487                                phys[0], phys[1],
 488                                false);
 489        if (ret) {
 490                v4l2_err(&ic_priv->sd,
 491                         "prp_setup_channel(rot_out_ch) failed, %d\n", ret);
 492                goto unsetup_vb2;
 493        }
 494
 495        /* now link IC-PRP-->MEM to MEM-->IC-PRP ROT */
 496        ipu_idmac_link(priv->out_ch, priv->rot_in_ch);
 497
 498        /* enable the IC */
 499        ipu_ic_enable(priv->ic);
 500
 501        /* set buffers ready */
 502        ipu_idmac_select_buffer(priv->out_ch, 0);
 503        ipu_idmac_select_buffer(priv->out_ch, 1);
 504        ipu_idmac_select_buffer(priv->rot_out_ch, 0);
 505        ipu_idmac_select_buffer(priv->rot_out_ch, 1);
 506
 507        /* enable the channels */
 508        ipu_idmac_enable_channel(priv->out_ch);
 509        ipu_idmac_enable_channel(priv->rot_in_ch);
 510        ipu_idmac_enable_channel(priv->rot_out_ch);
 511
 512        /* and finally enable the IC PRP task */
 513        ipu_ic_task_enable(priv->ic);
 514
 515        return 0;
 516
 517unsetup_vb2:
 518        prp_unsetup_vb2_buf(priv, VB2_BUF_STATE_QUEUED);
 519free_rot1:
 520        imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]);
 521free_rot0:
 522        imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]);
 523        return ret;
 524}
 525
 526static void prp_unsetup_rotation(struct prp_priv *priv)
 527{
 528        ipu_ic_task_disable(priv->ic);
 529
 530        ipu_idmac_disable_channel(priv->out_ch);
 531        ipu_idmac_disable_channel(priv->rot_in_ch);
 532        ipu_idmac_disable_channel(priv->rot_out_ch);
 533
 534        ipu_idmac_unlink(priv->out_ch, priv->rot_in_ch);
 535
 536        ipu_ic_disable(priv->ic);
 537
 538        imx_media_free_dma_buf(priv->md, &priv->rot_buf[0]);
 539        imx_media_free_dma_buf(priv->md, &priv->rot_buf[1]);
 540}
 541
 542static int prp_setup_norotation(struct prp_priv *priv)
 543{
 544        struct imx_media_video_dev *vdev = priv->vdev;
 545        struct imx_ic_priv *ic_priv = priv->ic_priv;
 546        const struct imx_media_pixfmt *outcc, *incc;
 547        struct v4l2_mbus_framefmt *infmt;
 548        struct v4l2_pix_format *outfmt;
 549        dma_addr_t phys[2];
 550        int ret;
 551
 552        infmt = &priv->format_mbus[PRPENCVF_SINK_PAD];
 553        outfmt = &vdev->fmt.fmt.pix;
 554        incc = priv->cc[PRPENCVF_SINK_PAD];
 555        outcc = vdev->cc;
 556
 557        ret = ipu_ic_task_init(priv->ic,
 558                               infmt->width, infmt->height,
 559                               outfmt->width, outfmt->height,
 560                               incc->cs, outcc->cs);
 561        if (ret) {
 562                v4l2_err(&ic_priv->sd, "ipu_ic_task_init failed, %d\n", ret);
 563                return ret;
 564        }
 565
 566        prp_setup_vb2_buf(priv, phys);
 567
 568        /* init the IC PRP-->MEM IDMAC channel */
 569        ret = prp_setup_channel(priv, priv->out_ch, priv->rot_mode,
 570                                phys[0], phys[1], false);
 571        if (ret) {
 572                v4l2_err(&ic_priv->sd,
 573                         "prp_setup_channel(out_ch) failed, %d\n", ret);
 574                goto unsetup_vb2;
 575        }
 576
 577        ipu_cpmem_dump(priv->out_ch);
 578        ipu_ic_dump(priv->ic);
 579        ipu_dump(priv->ipu);
 580
 581        ipu_ic_enable(priv->ic);
 582
 583        /* set buffers ready */
 584        ipu_idmac_select_buffer(priv->out_ch, 0);
 585        ipu_idmac_select_buffer(priv->out_ch, 1);
 586
 587        /* enable the channels */
 588        ipu_idmac_enable_channel(priv->out_ch);
 589
 590        /* enable the IC task */
 591        ipu_ic_task_enable(priv->ic);
 592
 593        return 0;
 594
 595unsetup_vb2:
 596        prp_unsetup_vb2_buf(priv, VB2_BUF_STATE_QUEUED);
 597        return ret;
 598}
 599
 600static void prp_unsetup_norotation(struct prp_priv *priv)
 601{
 602        ipu_ic_task_disable(priv->ic);
 603        ipu_idmac_disable_channel(priv->out_ch);
 604        ipu_ic_disable(priv->ic);
 605}
 606
 607static void prp_unsetup(struct prp_priv *priv,
 608                        enum vb2_buffer_state state)
 609{
 610        if (ipu_rot_mode_is_irt(priv->rot_mode))
 611                prp_unsetup_rotation(priv);
 612        else
 613                prp_unsetup_norotation(priv);
 614
 615        prp_unsetup_vb2_buf(priv, state);
 616}
 617
 618static int prp_start(struct prp_priv *priv)
 619{
 620        struct imx_ic_priv *ic_priv = priv->ic_priv;
 621        struct imx_media_video_dev *vdev = priv->vdev;
 622        struct v4l2_pix_format *outfmt;
 623        int ret;
 624
 625        ret = prp_get_ipu_resources(priv);
 626        if (ret)
 627                return ret;
 628
 629        outfmt = &vdev->fmt.fmt.pix;
 630
 631        ret = imx_media_alloc_dma_buf(priv->md, &priv->underrun_buf,
 632                                      outfmt->sizeimage);
 633        if (ret)
 634                goto out_put_ipu;
 635
 636        priv->ipu_buf_num = 0;
 637
 638        /* init EOF completion waitq */
 639        init_completion(&priv->last_eof_comp);
 640        priv->last_eof = false;
 641        priv->nfb4eof = false;
 642
 643        if (ipu_rot_mode_is_irt(priv->rot_mode))
 644                ret = prp_setup_rotation(priv);
 645        else
 646                ret = prp_setup_norotation(priv);
 647        if (ret)
 648                goto out_free_underrun;
 649
 650        priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu,
 651                                                  priv->out_ch,
 652                                                  IPU_IRQ_NFB4EOF);
 653        ret = devm_request_irq(ic_priv->dev, priv->nfb4eof_irq,
 654                               prp_nfb4eof_interrupt, 0,
 655                               "imx-ic-prp-nfb4eof", priv);
 656        if (ret) {
 657                v4l2_err(&ic_priv->sd,
 658                         "Error registering NFB4EOF irq: %d\n", ret);
 659                goto out_unsetup;
 660        }
 661
 662        if (ipu_rot_mode_is_irt(priv->rot_mode))
 663                priv->eof_irq = ipu_idmac_channel_irq(
 664                        priv->ipu, priv->rot_out_ch, IPU_IRQ_EOF);
 665        else
 666                priv->eof_irq = ipu_idmac_channel_irq(
 667                        priv->ipu, priv->out_ch, IPU_IRQ_EOF);
 668
 669        ret = devm_request_irq(ic_priv->dev, priv->eof_irq,
 670                               prp_eof_interrupt, 0,
 671                               "imx-ic-prp-eof", priv);
 672        if (ret) {
 673                v4l2_err(&ic_priv->sd,
 674                         "Error registering eof irq: %d\n", ret);
 675                goto out_free_nfb4eof_irq;
 676        }
 677
 678        /* start the EOF timeout timer */
 679        mod_timer(&priv->eof_timeout_timer,
 680                  jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
 681
 682        return 0;
 683
 684out_free_nfb4eof_irq:
 685        devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
 686out_unsetup:
 687        prp_unsetup(priv, VB2_BUF_STATE_QUEUED);
 688out_free_underrun:
 689        imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
 690out_put_ipu:
 691        prp_put_ipu_resources(priv);
 692        return ret;
 693}
 694
 695static void prp_stop(struct prp_priv *priv)
 696{
 697        struct imx_ic_priv *ic_priv = priv->ic_priv;
 698        unsigned long flags;
 699        int ret;
 700
 701        /* mark next EOF interrupt as the last before stream off */
 702        spin_lock_irqsave(&priv->irqlock, flags);
 703        priv->last_eof = true;
 704        spin_unlock_irqrestore(&priv->irqlock, flags);
 705
 706        /*
 707         * and then wait for interrupt handler to mark completion.
 708         */
 709        ret = wait_for_completion_timeout(
 710                &priv->last_eof_comp,
 711                msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
 712        if (ret == 0)
 713                v4l2_warn(&ic_priv->sd, "wait last EOF timeout\n");
 714
 715        devm_free_irq(ic_priv->dev, priv->eof_irq, priv);
 716        devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv);
 717
 718        prp_unsetup(priv, VB2_BUF_STATE_ERROR);
 719
 720        imx_media_free_dma_buf(priv->md, &priv->underrun_buf);
 721
 722        /* cancel the EOF timeout timer */
 723        del_timer_sync(&priv->eof_timeout_timer);
 724
 725        prp_put_ipu_resources(priv);
 726}
 727
 728static struct v4l2_mbus_framefmt *
 729__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg,
 730              unsigned int pad, enum v4l2_subdev_format_whence which)
 731{
 732        struct imx_ic_priv *ic_priv = priv->ic_priv;
 733
 734        if (which == V4L2_SUBDEV_FORMAT_TRY)
 735                return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad);
 736        else
 737                return &priv->format_mbus[pad];
 738}
 739
 740/*
 741 * Applies IC resizer and IDMAC alignment restrictions to output
 742 * rectangle given the input rectangle, and depending on given
 743 * rotation mode.
 744 *
 745 * The IC resizer cannot downsize more than 4:1. Note also that
 746 * for 90 or 270 rotation, _both_ output width and height must
 747 * be aligned by W_ALIGN_SRC, because the intermediate rotation
 748 * buffer swaps output width/height, and the final output buffer
 749 * does not.
 750 *
 751 * Returns true if the output rectangle was modified.
 752 */
 753static bool prp_bound_align_output(struct v4l2_mbus_framefmt *outfmt,
 754                                   struct v4l2_mbus_framefmt *infmt,
 755                                   enum ipu_rotate_mode rot_mode)
 756{
 757        u32 orig_width = outfmt->width;
 758        u32 orig_height = outfmt->height;
 759
 760        if (ipu_rot_mode_is_irt(rot_mode))
 761                v4l_bound_align_image(&outfmt->width,
 762                                      infmt->height / 4, MAX_H_SRC,
 763                                      W_ALIGN_SRC,
 764                                      &outfmt->height,
 765                                      infmt->width / 4, MAX_W_SRC,
 766                                      W_ALIGN_SRC, S_ALIGN);
 767        else
 768                v4l_bound_align_image(&outfmt->width,
 769                                      infmt->width / 4, MAX_W_SRC,
 770                                      W_ALIGN_SRC,
 771                                      &outfmt->height,
 772                                      infmt->height / 4, MAX_H_SRC,
 773                                      H_ALIGN_SRC, S_ALIGN);
 774
 775        return outfmt->width != orig_width || outfmt->height != orig_height;
 776}
 777
 778/*
 779 * V4L2 subdev operations.
 780 */
 781
 782static int prp_enum_mbus_code(struct v4l2_subdev *sd,
 783                              struct v4l2_subdev_pad_config *cfg,
 784                              struct v4l2_subdev_mbus_code_enum *code)
 785{
 786        if (code->pad >= PRPENCVF_NUM_PADS)
 787                return -EINVAL;
 788
 789        return imx_media_enum_ipu_format(&code->code, code->index, CS_SEL_ANY);
 790}
 791
 792static int prp_get_fmt(struct v4l2_subdev *sd,
 793                       struct v4l2_subdev_pad_config *cfg,
 794                       struct v4l2_subdev_format *sdformat)
 795{
 796        struct prp_priv *priv = sd_to_priv(sd);
 797        struct v4l2_mbus_framefmt *fmt;
 798        int ret = 0;
 799
 800        if (sdformat->pad >= PRPENCVF_NUM_PADS)
 801                return -EINVAL;
 802
 803        mutex_lock(&priv->lock);
 804
 805        fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
 806        if (!fmt) {
 807                ret = -EINVAL;
 808                goto out;
 809        }
 810
 811        sdformat->format = *fmt;
 812out:
 813        mutex_unlock(&priv->lock);
 814        return ret;
 815}
 816
 817static void prp_try_fmt(struct prp_priv *priv,
 818                        struct v4l2_subdev_pad_config *cfg,
 819                        struct v4l2_subdev_format *sdformat,
 820                        const struct imx_media_pixfmt **cc)
 821{
 822        struct v4l2_mbus_framefmt *infmt;
 823
 824        *cc = imx_media_find_ipu_format(sdformat->format.code, CS_SEL_ANY);
 825        if (!*cc) {
 826                u32 code;
 827
 828                imx_media_enum_ipu_format(&code, 0, CS_SEL_ANY);
 829                *cc = imx_media_find_ipu_format(code, CS_SEL_ANY);
 830                sdformat->format.code = (*cc)->codes[0];
 831        }
 832
 833        infmt = __prp_get_fmt(priv, cfg, PRPENCVF_SINK_PAD, sdformat->which);
 834
 835        if (sdformat->pad == PRPENCVF_SRC_PAD) {
 836                if (sdformat->format.field != V4L2_FIELD_NONE)
 837                        sdformat->format.field = infmt->field;
 838
 839                prp_bound_align_output(&sdformat->format, infmt,
 840                                       priv->rot_mode);
 841
 842                /* propagate colorimetry from sink */
 843                sdformat->format.colorspace = infmt->colorspace;
 844                sdformat->format.xfer_func = infmt->xfer_func;
 845                sdformat->format.quantization = infmt->quantization;
 846                sdformat->format.ycbcr_enc = infmt->ycbcr_enc;
 847        } else {
 848                v4l_bound_align_image(&sdformat->format.width,
 849                                      MIN_W_SINK, MAX_W_SINK, W_ALIGN_SINK,
 850                                      &sdformat->format.height,
 851                                      MIN_H_SINK, MAX_H_SINK, H_ALIGN_SINK,
 852                                      S_ALIGN);
 853
 854                imx_media_fill_default_mbus_fields(&sdformat->format, infmt,
 855                                                   true);
 856        }
 857}
 858
 859static int prp_set_fmt(struct v4l2_subdev *sd,
 860                       struct v4l2_subdev_pad_config *cfg,
 861                       struct v4l2_subdev_format *sdformat)
 862{
 863        struct prp_priv *priv = sd_to_priv(sd);
 864        struct imx_media_video_dev *vdev = priv->vdev;
 865        const struct imx_media_pixfmt *cc;
 866        struct v4l2_pix_format vdev_fmt;
 867        struct v4l2_mbus_framefmt *fmt;
 868        int ret = 0;
 869
 870        if (sdformat->pad >= PRPENCVF_NUM_PADS)
 871                return -EINVAL;
 872
 873        mutex_lock(&priv->lock);
 874
 875        if (priv->stream_count > 0) {
 876                ret = -EBUSY;
 877                goto out;
 878        }
 879
 880        prp_try_fmt(priv, cfg, sdformat, &cc);
 881
 882        fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
 883        *fmt = sdformat->format;
 884
 885        /* propagate a default format to source pad */
 886        if (sdformat->pad == PRPENCVF_SINK_PAD) {
 887                const struct imx_media_pixfmt *outcc;
 888                struct v4l2_mbus_framefmt *outfmt;
 889                struct v4l2_subdev_format format;
 890
 891                format.pad = PRPENCVF_SRC_PAD;
 892                format.which = sdformat->which;
 893                format.format = sdformat->format;
 894                prp_try_fmt(priv, cfg, &format, &outcc);
 895
 896                outfmt = __prp_get_fmt(priv, cfg, PRPENCVF_SRC_PAD,
 897                                       sdformat->which);
 898                *outfmt = format.format;
 899                if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 900                        priv->cc[PRPENCVF_SRC_PAD] = outcc;
 901        }
 902
 903        if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
 904                goto out;
 905
 906        priv->cc[sdformat->pad] = cc;
 907
 908        /* propagate output pad format to capture device */
 909        imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt,
 910                                      &priv->format_mbus[PRPENCVF_SRC_PAD],
 911                                      priv->cc[PRPENCVF_SRC_PAD]);
 912        mutex_unlock(&priv->lock);
 913        imx_media_capture_device_set_format(vdev, &vdev_fmt);
 914
 915        return 0;
 916out:
 917        mutex_unlock(&priv->lock);
 918        return ret;
 919}
 920
 921static int prp_enum_frame_size(struct v4l2_subdev *sd,
 922                               struct v4l2_subdev_pad_config *cfg,
 923                               struct v4l2_subdev_frame_size_enum *fse)
 924{
 925        struct prp_priv *priv = sd_to_priv(sd);
 926        struct v4l2_subdev_format format = {};
 927        const struct imx_media_pixfmt *cc;
 928        int ret = 0;
 929
 930        if (fse->pad >= PRPENCVF_NUM_PADS || fse->index != 0)
 931                return -EINVAL;
 932
 933        mutex_lock(&priv->lock);
 934
 935        format.pad = fse->pad;
 936        format.which = fse->which;
 937        format.format.code = fse->code;
 938        format.format.width = 1;
 939        format.format.height = 1;
 940        prp_try_fmt(priv, cfg, &format, &cc);
 941        fse->min_width = format.format.width;
 942        fse->min_height = format.format.height;
 943
 944        if (format.format.code != fse->code) {
 945                ret = -EINVAL;
 946                goto out;
 947        }
 948
 949        format.format.code = fse->code;
 950        format.format.width = -1;
 951        format.format.height = -1;
 952        prp_try_fmt(priv, cfg, &format, &cc);
 953        fse->max_width = format.format.width;
 954        fse->max_height = format.format.height;
 955out:
 956        mutex_unlock(&priv->lock);
 957        return ret;
 958}
 959
 960static int prp_link_setup(struct media_entity *entity,
 961                          const struct media_pad *local,
 962                          const struct media_pad *remote, u32 flags)
 963{
 964        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
 965        struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
 966        struct prp_priv *priv = ic_priv->task_priv;
 967        struct v4l2_subdev *remote_sd;
 968        int ret = 0;
 969
 970        dev_dbg(ic_priv->dev, "link setup %s -> %s", remote->entity->name,
 971                local->entity->name);
 972
 973        mutex_lock(&priv->lock);
 974
 975        if (local->flags & MEDIA_PAD_FL_SINK) {
 976                if (!is_media_entity_v4l2_subdev(remote->entity)) {
 977                        ret = -EINVAL;
 978                        goto out;
 979                }
 980
 981                remote_sd = media_entity_to_v4l2_subdev(remote->entity);
 982
 983                if (flags & MEDIA_LNK_FL_ENABLED) {
 984                        if (priv->src_sd) {
 985                                ret = -EBUSY;
 986                                goto out;
 987                        }
 988                        priv->src_sd = remote_sd;
 989                } else {
 990                        priv->src_sd = NULL;
 991                }
 992
 993                goto out;
 994        }
 995
 996        /* this is the source pad */
 997
 998        /* the remote must be the device node */
 999        if (!is_media_entity_v4l2_video_device(remote->entity)) {
1000                ret = -EINVAL;
1001                goto out;
1002        }
1003
1004        if (flags & MEDIA_LNK_FL_ENABLED) {
1005                if (priv->sink) {
1006                        ret = -EBUSY;
1007                        goto out;
1008                }
1009        } else {
1010                priv->sink = NULL;
1011                goto out;
1012        }
1013
1014        priv->sink = remote->entity;
1015out:
1016        mutex_unlock(&priv->lock);
1017        return ret;
1018}
1019
1020static int prp_s_ctrl(struct v4l2_ctrl *ctrl)
1021{
1022        struct prp_priv *priv = container_of(ctrl->handler,
1023                                               struct prp_priv, ctrl_hdlr);
1024        struct imx_ic_priv *ic_priv = priv->ic_priv;
1025        enum ipu_rotate_mode rot_mode;
1026        int rotation, ret = 0;
1027        bool hflip, vflip;
1028
1029        mutex_lock(&priv->lock);
1030
1031        rotation = priv->rotation;
1032        hflip = priv->hflip;
1033        vflip = priv->vflip;
1034
1035        switch (ctrl->id) {
1036        case V4L2_CID_HFLIP:
1037                hflip = (ctrl->val == 1);
1038                break;
1039        case V4L2_CID_VFLIP:
1040                vflip = (ctrl->val == 1);
1041                break;
1042        case V4L2_CID_ROTATE:
1043                rotation = ctrl->val;
1044                break;
1045        default:
1046                v4l2_err(&ic_priv->sd, "Invalid control\n");
1047                ret = -EINVAL;
1048                goto out;
1049        }
1050
1051        ret = ipu_degrees_to_rot_mode(&rot_mode, rotation, hflip, vflip);
1052        if (ret)
1053                goto out;
1054
1055        if (rot_mode != priv->rot_mode) {
1056                struct v4l2_mbus_framefmt outfmt, infmt;
1057
1058                /* can't change rotation mid-streaming */
1059                if (priv->stream_count > 0) {
1060                        ret = -EBUSY;
1061                        goto out;
1062                }
1063
1064                outfmt = priv->format_mbus[PRPENCVF_SRC_PAD];
1065                infmt = priv->format_mbus[PRPENCVF_SINK_PAD];
1066
1067                if (prp_bound_align_output(&outfmt, &infmt, rot_mode)) {
1068                        ret = -EINVAL;
1069                        goto out;
1070                }
1071
1072                priv->rot_mode = rot_mode;
1073                priv->rotation = rotation;
1074                priv->hflip = hflip;
1075                priv->vflip = vflip;
1076        }
1077
1078out:
1079        mutex_unlock(&priv->lock);
1080        return ret;
1081}
1082
1083static const struct v4l2_ctrl_ops prp_ctrl_ops = {
1084        .s_ctrl = prp_s_ctrl,
1085};
1086
1087static int prp_init_controls(struct prp_priv *priv)
1088{
1089        struct imx_ic_priv *ic_priv = priv->ic_priv;
1090        struct v4l2_ctrl_handler *hdlr = &priv->ctrl_hdlr;
1091        int ret;
1092
1093        v4l2_ctrl_handler_init(hdlr, 3);
1094
1095        v4l2_ctrl_new_std(hdlr, &prp_ctrl_ops, V4L2_CID_HFLIP,
1096                          0, 1, 1, 0);
1097        v4l2_ctrl_new_std(hdlr, &prp_ctrl_ops, V4L2_CID_VFLIP,
1098                          0, 1, 1, 0);
1099        v4l2_ctrl_new_std(hdlr, &prp_ctrl_ops, V4L2_CID_ROTATE,
1100                          0, 270, 90, 0);
1101
1102        ic_priv->sd.ctrl_handler = hdlr;
1103
1104        if (hdlr->error) {
1105                ret = hdlr->error;
1106                goto out_free;
1107        }
1108
1109        v4l2_ctrl_handler_setup(hdlr);
1110        return 0;
1111
1112out_free:
1113        v4l2_ctrl_handler_free(hdlr);
1114        return ret;
1115}
1116
1117static int prp_s_stream(struct v4l2_subdev *sd, int enable)
1118{
1119        struct imx_ic_priv *ic_priv = v4l2_get_subdevdata(sd);
1120        struct prp_priv *priv = ic_priv->task_priv;
1121        int ret = 0;
1122
1123        mutex_lock(&priv->lock);
1124
1125        if (!priv->src_sd || !priv->sink) {
1126                ret = -EPIPE;
1127                goto out;
1128        }
1129
1130        /*
1131         * enable/disable streaming only if stream_count is
1132         * going from 0 to 1 / 1 to 0.
1133         */
1134        if (priv->stream_count != !enable)
1135                goto update_count;
1136
1137        dev_dbg(ic_priv->dev, "stream %s\n", enable ? "ON" : "OFF");
1138
1139        if (enable)
1140                ret = prp_start(priv);
1141        else
1142                prp_stop(priv);
1143        if (ret)
1144                goto out;
1145
1146        /* start/stop upstream */
1147        ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable);
1148        ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
1149        if (ret) {
1150                if (enable)
1151                        prp_stop(priv);
1152                goto out;
1153        }
1154
1155update_count:
1156        priv->stream_count += enable ? 1 : -1;
1157        if (priv->stream_count < 0)
1158                priv->stream_count = 0;
1159out:
1160        mutex_unlock(&priv->lock);
1161        return ret;
1162}
1163
1164static int prp_g_frame_interval(struct v4l2_subdev *sd,
1165                                struct v4l2_subdev_frame_interval *fi)
1166{
1167        struct prp_priv *priv = sd_to_priv(sd);
1168
1169        if (fi->pad >= PRPENCVF_NUM_PADS)
1170                return -EINVAL;
1171
1172        mutex_lock(&priv->lock);
1173        fi->interval = priv->frame_interval;
1174        mutex_unlock(&priv->lock);
1175
1176        return 0;
1177}
1178
1179static int prp_s_frame_interval(struct v4l2_subdev *sd,
1180                                struct v4l2_subdev_frame_interval *fi)
1181{
1182        struct prp_priv *priv = sd_to_priv(sd);
1183
1184        if (fi->pad >= PRPENCVF_NUM_PADS)
1185                return -EINVAL;
1186
1187        /* No limits on frame interval */
1188        mutex_lock(&priv->lock);
1189        priv->frame_interval = fi->interval;
1190        mutex_unlock(&priv->lock);
1191
1192        return 0;
1193}
1194
1195/*
1196 * retrieve our pads parsed from the OF graph by the media device
1197 */
1198static int prp_registered(struct v4l2_subdev *sd)
1199{
1200        struct prp_priv *priv = sd_to_priv(sd);
1201        int i, ret;
1202        u32 code;
1203
1204        /* get media device */
1205        priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
1206
1207        for (i = 0; i < PRPENCVF_NUM_PADS; i++) {
1208                priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ?
1209                        MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
1210
1211                /* set a default mbus format  */
1212                imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV);
1213                ret = imx_media_init_mbus_fmt(&priv->format_mbus[i],
1214                                              640, 480, code, V4L2_FIELD_NONE,
1215                                              &priv->cc[i]);
1216                if (ret)
1217                        return ret;
1218        }
1219
1220        /* init default frame interval */
1221        priv->frame_interval.numerator = 1;
1222        priv->frame_interval.denominator = 30;
1223
1224        ret = media_entity_pads_init(&sd->entity, PRPENCVF_NUM_PADS,
1225                                     priv->pad);
1226        if (ret)
1227                return ret;
1228
1229        ret = imx_media_capture_device_register(priv->vdev);
1230        if (ret)
1231                return ret;
1232
1233        ret = imx_media_add_video_device(priv->md, priv->vdev);
1234        if (ret)
1235                goto unreg;
1236
1237        ret = prp_init_controls(priv);
1238        if (ret)
1239                goto unreg;
1240
1241        return 0;
1242unreg:
1243        imx_media_capture_device_unregister(priv->vdev);
1244        return ret;
1245}
1246
1247static void prp_unregistered(struct v4l2_subdev *sd)
1248{
1249        struct prp_priv *priv = sd_to_priv(sd);
1250
1251        imx_media_capture_device_unregister(priv->vdev);
1252        v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
1253}
1254
1255static const struct v4l2_subdev_pad_ops prp_pad_ops = {
1256        .init_cfg = imx_media_init_cfg,
1257        .enum_mbus_code = prp_enum_mbus_code,
1258        .enum_frame_size = prp_enum_frame_size,
1259        .get_fmt = prp_get_fmt,
1260        .set_fmt = prp_set_fmt,
1261};
1262
1263static const struct v4l2_subdev_video_ops prp_video_ops = {
1264        .g_frame_interval = prp_g_frame_interval,
1265        .s_frame_interval = prp_s_frame_interval,
1266        .s_stream = prp_s_stream,
1267};
1268
1269static const struct media_entity_operations prp_entity_ops = {
1270        .link_setup = prp_link_setup,
1271        .link_validate = v4l2_subdev_link_validate,
1272};
1273
1274static const struct v4l2_subdev_ops prp_subdev_ops = {
1275        .video = &prp_video_ops,
1276        .pad = &prp_pad_ops,
1277};
1278
1279static const struct v4l2_subdev_internal_ops prp_internal_ops = {
1280        .registered = prp_registered,
1281        .unregistered = prp_unregistered,
1282};
1283
1284static int prp_init(struct imx_ic_priv *ic_priv)
1285{
1286        struct prp_priv *priv;
1287
1288        priv = devm_kzalloc(ic_priv->dev, sizeof(*priv), GFP_KERNEL);
1289        if (!priv)
1290                return -ENOMEM;
1291
1292        ic_priv->task_priv = priv;
1293        priv->ic_priv = ic_priv;
1294
1295        spin_lock_init(&priv->irqlock);
1296        timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0);
1297
1298        priv->vdev = imx_media_capture_device_init(&ic_priv->sd,
1299                                                   PRPENCVF_SRC_PAD);
1300        if (IS_ERR(priv->vdev))
1301                return PTR_ERR(priv->vdev);
1302
1303        mutex_init(&priv->lock);
1304
1305        return 0;
1306}
1307
1308static void prp_remove(struct imx_ic_priv *ic_priv)
1309{
1310        struct prp_priv *priv = ic_priv->task_priv;
1311
1312        mutex_destroy(&priv->lock);
1313        imx_media_capture_device_remove(priv->vdev);
1314}
1315
1316struct imx_ic_ops imx_ic_prpencvf_ops = {
1317        .subdev_ops = &prp_subdev_ops,
1318        .internal_ops = &prp_internal_ops,
1319        .entity_ops = &prp_entity_ops,
1320        .init = prp_init,
1321        .remove = prp_remove,
1322};
1323