linux/drivers/staging/media/imx/imx-media-vdic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * V4L2 Deinterlacer Subdev for Freescale i.MX5/6 SOC
   4 *
   5 * Copyright (c) 2017 Mentor Graphics Inc.
   6 */
   7#include <linux/delay.h>
   8#include <linux/interrupt.h>
   9#include <linux/module.h>
  10#include <linux/platform_device.h>
  11#include <linux/sched.h>
  12#include <linux/slab.h>
  13#include <linux/timer.h>
  14#include <media/v4l2-ctrls.h>
  15#include <media/v4l2-device.h>
  16#include <media/v4l2-ioctl.h>
  17#include <media/v4l2-mc.h>
  18#include <media/v4l2-subdev.h>
  19#include <media/imx.h>
  20#include "imx-media.h"
  21
  22/*
  23 * This subdev implements two different video pipelines:
  24 *
  25 * CSI -> VDIC
  26 *
  27 * In this pipeline, the CSI sends a single interlaced field F(n-1)
  28 * directly to the VDIC (and optionally the following field F(n)
  29 * can be sent to memory via IDMAC channel 13). This pipeline only works
  30 * in VDIC's high motion mode, which only requires a single field for
  31 * processing. The other motion modes (low and medium) require three
  32 * fields, so this pipeline does not work in those modes. Also, it is
  33 * not clear how this pipeline can deal with the various field orders
  34 * (sequential BT/TB, interlaced BT/TB).
  35 *
  36 * MEM -> CH8,9,10 -> VDIC
  37 *
  38 * In this pipeline, previous field F(n-1), current field F(n), and next
  39 * field F(n+1) are transferred to the VDIC via IDMAC channels 8,9,10.
  40 * These memory buffers can come from a video output or mem2mem device.
  41 * All motion modes are supported by this pipeline.
  42 *
  43 * The "direct" CSI->VDIC pipeline requires no DMA, but it can only be
  44 * used in high motion mode.
  45 */
  46
  47struct vdic_priv;
  48
  49struct vdic_pipeline_ops {
  50        int (*setup)(struct vdic_priv *priv);
  51        void (*start)(struct vdic_priv *priv);
  52        void (*stop)(struct vdic_priv *priv);
  53        void (*disable)(struct vdic_priv *priv);
  54};
  55
  56/*
  57 * Min/Max supported width and heights.
  58 */
  59#define MIN_W       176
  60#define MIN_H       144
  61#define MAX_W_VDIC  968
  62#define MAX_H_VDIC 2048
  63#define W_ALIGN    4 /* multiple of 16 pixels */
  64#define H_ALIGN    1 /* multiple of 2 lines */
  65#define S_ALIGN    1 /* multiple of 2 */
  66
  67struct vdic_priv {
  68        struct device        *dev;
  69        struct ipu_soc       *ipu;
  70        struct imx_media_dev *md;
  71        struct v4l2_subdev   sd;
  72        struct media_pad pad[VDIC_NUM_PADS];
  73        int ipu_id;
  74
  75        /* lock to protect all members below */
  76        struct mutex lock;
  77
  78        /* IPU units we require */
  79        struct ipu_vdi *vdi;
  80
  81        int active_input_pad;
  82
  83        struct ipuv3_channel *vdi_in_ch_p; /* F(n-1) transfer channel */
  84        struct ipuv3_channel *vdi_in_ch;   /* F(n) transfer channel */
  85        struct ipuv3_channel *vdi_in_ch_n; /* F(n+1) transfer channel */
  86
  87        /* pipeline operations */
  88        struct vdic_pipeline_ops *ops;
  89
  90        /* current and previous input buffers indirect path */
  91        struct imx_media_buffer *curr_in_buf;
  92        struct imx_media_buffer *prev_in_buf;
  93
  94        /*
  95         * translated field type, input line stride, and field size
  96         * for indirect path
  97         */
  98        u32 fieldtype;
  99        u32 in_stride;
 100        u32 field_size;
 101
 102        /* the source (a video device or subdev) */
 103        struct media_entity *src;
 104        /* the sink that will receive the progressive out buffers */
 105        struct v4l2_subdev *sink_sd;
 106
 107        struct v4l2_mbus_framefmt format_mbus[VDIC_NUM_PADS];
 108        const struct imx_media_pixfmt *cc[VDIC_NUM_PADS];
 109        struct v4l2_fract frame_interval[VDIC_NUM_PADS];
 110
 111        /* the video device at IDMAC input pad */
 112        struct imx_media_video_dev *vdev;
 113
 114        bool csi_direct;  /* using direct CSI->VDIC->IC pipeline */
 115
 116        /* motion select control */
 117        struct v4l2_ctrl_handler ctrl_hdlr;
 118        enum ipu_motion_sel motion;
 119
 120        int stream_count;
 121};
 122
 123static void vdic_put_ipu_resources(struct vdic_priv *priv)
 124{
 125        if (priv->vdi_in_ch_p)
 126                ipu_idmac_put(priv->vdi_in_ch_p);
 127        priv->vdi_in_ch_p = NULL;
 128
 129        if (priv->vdi_in_ch)
 130                ipu_idmac_put(priv->vdi_in_ch);
 131        priv->vdi_in_ch = NULL;
 132
 133        if (priv->vdi_in_ch_n)
 134                ipu_idmac_put(priv->vdi_in_ch_n);
 135        priv->vdi_in_ch_n = NULL;
 136
 137        if (!IS_ERR_OR_NULL(priv->vdi))
 138                ipu_vdi_put(priv->vdi);
 139        priv->vdi = NULL;
 140}
 141
 142static int vdic_get_ipu_resources(struct vdic_priv *priv)
 143{
 144        int ret, err_chan;
 145        struct ipuv3_channel *ch;
 146        struct ipu_vdi *vdi;
 147
 148        priv->ipu = priv->md->ipu[priv->ipu_id];
 149
 150        vdi = ipu_vdi_get(priv->ipu);
 151        if (IS_ERR(vdi)) {
 152                v4l2_err(&priv->sd, "failed to get VDIC\n");
 153                ret = PTR_ERR(vdi);
 154                goto out;
 155        }
 156        priv->vdi = vdi;
 157
 158        if (!priv->csi_direct) {
 159                ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_PREV);
 160                if (IS_ERR(ch)) {
 161                        err_chan = IPUV3_CHANNEL_MEM_VDI_PREV;
 162                        ret = PTR_ERR(ch);
 163                        goto out_err_chan;
 164                }
 165                priv->vdi_in_ch_p = ch;
 166
 167                ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_CUR);
 168                if (IS_ERR(ch)) {
 169                        err_chan = IPUV3_CHANNEL_MEM_VDI_CUR;
 170                        ret = PTR_ERR(ch);
 171                        goto out_err_chan;
 172                }
 173                priv->vdi_in_ch = ch;
 174
 175                ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_NEXT);
 176                if (IS_ERR(ch)) {
 177                        err_chan = IPUV3_CHANNEL_MEM_VDI_NEXT;
 178                        ret = PTR_ERR(ch);
 179                        goto out_err_chan;
 180                }
 181                priv->vdi_in_ch_n = ch;
 182        }
 183
 184        return 0;
 185
 186out_err_chan:
 187        v4l2_err(&priv->sd, "could not get IDMAC channel %u\n", err_chan);
 188out:
 189        vdic_put_ipu_resources(priv);
 190        return ret;
 191}
 192
 193/*
 194 * This function is currently unused, but will be called when the
 195 * output/mem2mem device at the IDMAC input pad sends us a new
 196 * buffer. It kicks off the IDMAC read channels to bring in the
 197 * buffer fields from memory and begin the conversions.
 198 */
 199static void __maybe_unused prepare_vdi_in_buffers(struct vdic_priv *priv,
 200                                                  struct imx_media_buffer *curr)
 201{
 202        dma_addr_t prev_phys, curr_phys, next_phys;
 203        struct imx_media_buffer *prev;
 204        struct vb2_buffer *curr_vb, *prev_vb;
 205        u32 fs = priv->field_size;
 206        u32 is = priv->in_stride;
 207
 208        /* current input buffer is now previous */
 209        priv->prev_in_buf = priv->curr_in_buf;
 210        priv->curr_in_buf = curr;
 211        prev = priv->prev_in_buf ? priv->prev_in_buf : curr;
 212
 213        prev_vb = &prev->vbuf.vb2_buf;
 214        curr_vb = &curr->vbuf.vb2_buf;
 215
 216        switch (priv->fieldtype) {
 217        case V4L2_FIELD_SEQ_TB:
 218        case V4L2_FIELD_SEQ_BT:
 219                prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + fs;
 220                curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0);
 221                next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + fs;
 222                break;
 223        case V4L2_FIELD_INTERLACED_TB:
 224        case V4L2_FIELD_INTERLACED_BT:
 225        case V4L2_FIELD_INTERLACED:
 226                prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + is;
 227                curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0);
 228                next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is;
 229                break;
 230        default:
 231                /*
 232                 * can't get here, priv->fieldtype can only be one of
 233                 * the above. This is to quiet smatch errors.
 234                 */
 235                return;
 236        }
 237
 238        ipu_cpmem_set_buffer(priv->vdi_in_ch_p, 0, prev_phys);
 239        ipu_cpmem_set_buffer(priv->vdi_in_ch,   0, curr_phys);
 240        ipu_cpmem_set_buffer(priv->vdi_in_ch_n, 0, next_phys);
 241
 242        ipu_idmac_select_buffer(priv->vdi_in_ch_p, 0);
 243        ipu_idmac_select_buffer(priv->vdi_in_ch, 0);
 244        ipu_idmac_select_buffer(priv->vdi_in_ch_n, 0);
 245}
 246
 247static int setup_vdi_channel(struct vdic_priv *priv,
 248                             struct ipuv3_channel *channel,
 249                             dma_addr_t phys0, dma_addr_t phys1)
 250{
 251        struct imx_media_video_dev *vdev = priv->vdev;
 252        unsigned int burst_size;
 253        struct ipu_image image;
 254        int ret;
 255
 256        ipu_cpmem_zero(channel);
 257
 258        memset(&image, 0, sizeof(image));
 259        image.pix = vdev->fmt.fmt.pix;
 260        image.rect = vdev->compose;
 261        /* one field to VDIC channels */
 262        image.pix.height /= 2;
 263        image.rect.height /= 2;
 264        image.phys0 = phys0;
 265        image.phys1 = phys1;
 266
 267        ret = ipu_cpmem_set_image(channel, &image);
 268        if (ret)
 269                return ret;
 270
 271        burst_size = (image.pix.width & 0xf) ? 8 : 16;
 272        ipu_cpmem_set_burstsize(channel, burst_size);
 273
 274        ipu_cpmem_set_axi_id(channel, 1);
 275
 276        ipu_idmac_set_double_buffer(channel, false);
 277
 278        return 0;
 279}
 280
 281static int vdic_setup_direct(struct vdic_priv *priv)
 282{
 283        /* set VDIC to receive from CSI for direct path */
 284        ipu_fsu_link(priv->ipu, IPUV3_CHANNEL_CSI_DIRECT,
 285                     IPUV3_CHANNEL_CSI_VDI_PREV);
 286
 287        return 0;
 288}
 289
 290static void vdic_start_direct(struct vdic_priv *priv)
 291{
 292}
 293
 294static void vdic_stop_direct(struct vdic_priv *priv)
 295{
 296}
 297
 298static void vdic_disable_direct(struct vdic_priv *priv)
 299{
 300        ipu_fsu_unlink(priv->ipu, IPUV3_CHANNEL_CSI_DIRECT,
 301                       IPUV3_CHANNEL_CSI_VDI_PREV);
 302}
 303
 304static int vdic_setup_indirect(struct vdic_priv *priv)
 305{
 306        struct v4l2_mbus_framefmt *infmt;
 307        const struct imx_media_pixfmt *incc;
 308        int in_size, ret;
 309
 310        infmt = &priv->format_mbus[VDIC_SINK_PAD_IDMAC];
 311        incc = priv->cc[VDIC_SINK_PAD_IDMAC];
 312
 313        in_size = (infmt->width * incc->bpp * infmt->height) >> 3;
 314
 315        /* 1/2 full image size */
 316        priv->field_size = in_size / 2;
 317        priv->in_stride = incc->planar ?
 318                infmt->width : (infmt->width * incc->bpp) >> 3;
 319
 320        priv->prev_in_buf = NULL;
 321        priv->curr_in_buf = NULL;
 322
 323        priv->fieldtype = infmt->field;
 324
 325        /* init the vdi-in channels */
 326        ret = setup_vdi_channel(priv, priv->vdi_in_ch_p, 0, 0);
 327        if (ret)
 328                return ret;
 329        ret = setup_vdi_channel(priv, priv->vdi_in_ch, 0, 0);
 330        if (ret)
 331                return ret;
 332        return setup_vdi_channel(priv, priv->vdi_in_ch_n, 0, 0);
 333}
 334
 335static void vdic_start_indirect(struct vdic_priv *priv)
 336{
 337        /* enable the channels */
 338        ipu_idmac_enable_channel(priv->vdi_in_ch_p);
 339        ipu_idmac_enable_channel(priv->vdi_in_ch);
 340        ipu_idmac_enable_channel(priv->vdi_in_ch_n);
 341}
 342
 343static void vdic_stop_indirect(struct vdic_priv *priv)
 344{
 345        /* disable channels */
 346        ipu_idmac_disable_channel(priv->vdi_in_ch_p);
 347        ipu_idmac_disable_channel(priv->vdi_in_ch);
 348        ipu_idmac_disable_channel(priv->vdi_in_ch_n);
 349}
 350
 351static void vdic_disable_indirect(struct vdic_priv *priv)
 352{
 353}
 354
 355static struct vdic_pipeline_ops direct_ops = {
 356        .setup = vdic_setup_direct,
 357        .start = vdic_start_direct,
 358        .stop = vdic_stop_direct,
 359        .disable = vdic_disable_direct,
 360};
 361
 362static struct vdic_pipeline_ops indirect_ops = {
 363        .setup = vdic_setup_indirect,
 364        .start = vdic_start_indirect,
 365        .stop = vdic_stop_indirect,
 366        .disable = vdic_disable_indirect,
 367};
 368
 369static int vdic_start(struct vdic_priv *priv)
 370{
 371        struct v4l2_mbus_framefmt *infmt;
 372        int ret;
 373
 374        infmt = &priv->format_mbus[priv->active_input_pad];
 375
 376        priv->ops = priv->csi_direct ? &direct_ops : &indirect_ops;
 377
 378        ret = vdic_get_ipu_resources(priv);
 379        if (ret)
 380                return ret;
 381
 382        /*
 383         * init the VDIC.
 384         *
 385         * note we don't give infmt->code to ipu_vdi_setup(). The VDIC
 386         * only supports 4:2:2 or 4:2:0, and this subdev will only
 387         * negotiate 4:2:2 at its sink pads.
 388         */
 389        ipu_vdi_setup(priv->vdi, MEDIA_BUS_FMT_UYVY8_2X8,
 390                      infmt->width, infmt->height);
 391        ipu_vdi_set_field_order(priv->vdi, V4L2_STD_UNKNOWN, infmt->field);
 392        ipu_vdi_set_motion(priv->vdi, priv->motion);
 393
 394        ret = priv->ops->setup(priv);
 395        if (ret)
 396                goto out_put_ipu;
 397
 398        ipu_vdi_enable(priv->vdi);
 399
 400        priv->ops->start(priv);
 401
 402        return 0;
 403
 404out_put_ipu:
 405        vdic_put_ipu_resources(priv);
 406        return ret;
 407}
 408
 409static void vdic_stop(struct vdic_priv *priv)
 410{
 411        priv->ops->stop(priv);
 412        ipu_vdi_disable(priv->vdi);
 413        priv->ops->disable(priv);
 414
 415        vdic_put_ipu_resources(priv);
 416}
 417
 418/*
 419 * V4L2 subdev operations.
 420 */
 421
 422static int vdic_s_ctrl(struct v4l2_ctrl *ctrl)
 423{
 424        struct vdic_priv *priv = container_of(ctrl->handler,
 425                                              struct vdic_priv, ctrl_hdlr);
 426        enum ipu_motion_sel motion;
 427        int ret = 0;
 428
 429        mutex_lock(&priv->lock);
 430
 431        switch (ctrl->id) {
 432        case V4L2_CID_DEINTERLACING_MODE:
 433                motion = ctrl->val;
 434                if (motion != priv->motion) {
 435                        /* can't change motion control mid-streaming */
 436                        if (priv->stream_count > 0) {
 437                                ret = -EBUSY;
 438                                goto out;
 439                        }
 440                        priv->motion = motion;
 441                }
 442                break;
 443        default:
 444                v4l2_err(&priv->sd, "Invalid control\n");
 445                ret = -EINVAL;
 446        }
 447
 448out:
 449        mutex_unlock(&priv->lock);
 450        return ret;
 451}
 452
 453static const struct v4l2_ctrl_ops vdic_ctrl_ops = {
 454        .s_ctrl = vdic_s_ctrl,
 455};
 456
 457static const char * const vdic_ctrl_motion_menu[] = {
 458        "No Motion Compensation",
 459        "Low Motion",
 460        "Medium Motion",
 461        "High Motion",
 462};
 463
 464static int vdic_init_controls(struct vdic_priv *priv)
 465{
 466        struct v4l2_ctrl_handler *hdlr = &priv->ctrl_hdlr;
 467        int ret;
 468
 469        v4l2_ctrl_handler_init(hdlr, 1);
 470
 471        v4l2_ctrl_new_std_menu_items(hdlr, &vdic_ctrl_ops,
 472                                     V4L2_CID_DEINTERLACING_MODE,
 473                                     HIGH_MOTION, 0, HIGH_MOTION,
 474                                     vdic_ctrl_motion_menu);
 475
 476        priv->sd.ctrl_handler = hdlr;
 477
 478        if (hdlr->error) {
 479                ret = hdlr->error;
 480                goto out_free;
 481        }
 482
 483        v4l2_ctrl_handler_setup(hdlr);
 484        return 0;
 485
 486out_free:
 487        v4l2_ctrl_handler_free(hdlr);
 488        return ret;
 489}
 490
 491static int vdic_s_stream(struct v4l2_subdev *sd, int enable)
 492{
 493        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 494        struct v4l2_subdev *src_sd = NULL;
 495        int ret = 0;
 496
 497        mutex_lock(&priv->lock);
 498
 499        if (!priv->src || !priv->sink_sd) {
 500                ret = -EPIPE;
 501                goto out;
 502        }
 503
 504        if (priv->csi_direct)
 505                src_sd = media_entity_to_v4l2_subdev(priv->src);
 506
 507        /*
 508         * enable/disable streaming only if stream_count is
 509         * going from 0 to 1 / 1 to 0.
 510         */
 511        if (priv->stream_count != !enable)
 512                goto update_count;
 513
 514        dev_dbg(priv->dev, "stream %s\n", enable ? "ON" : "OFF");
 515
 516        if (enable)
 517                ret = vdic_start(priv);
 518        else
 519                vdic_stop(priv);
 520        if (ret)
 521                goto out;
 522
 523        if (src_sd) {
 524                /* start/stop upstream */
 525                ret = v4l2_subdev_call(src_sd, video, s_stream, enable);
 526                ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
 527                if (ret) {
 528                        if (enable)
 529                                vdic_stop(priv);
 530                        goto out;
 531                }
 532        }
 533
 534update_count:
 535        priv->stream_count += enable ? 1 : -1;
 536        if (priv->stream_count < 0)
 537                priv->stream_count = 0;
 538out:
 539        mutex_unlock(&priv->lock);
 540        return ret;
 541}
 542
 543static struct v4l2_mbus_framefmt *
 544__vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_pad_config *cfg,
 545               unsigned int pad, enum v4l2_subdev_format_whence which)
 546{
 547        if (which == V4L2_SUBDEV_FORMAT_TRY)
 548                return v4l2_subdev_get_try_format(&priv->sd, cfg, pad);
 549        else
 550                return &priv->format_mbus[pad];
 551}
 552
 553static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
 554                               struct v4l2_subdev_pad_config *cfg,
 555                               struct v4l2_subdev_mbus_code_enum *code)
 556{
 557        if (code->pad >= VDIC_NUM_PADS)
 558                return -EINVAL;
 559
 560        return imx_media_enum_ipu_format(&code->code, code->index, CS_SEL_YUV);
 561}
 562
 563static int vdic_get_fmt(struct v4l2_subdev *sd,
 564                        struct v4l2_subdev_pad_config *cfg,
 565                        struct v4l2_subdev_format *sdformat)
 566{
 567        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 568        struct v4l2_mbus_framefmt *fmt;
 569        int ret = 0;
 570
 571        if (sdformat->pad >= VDIC_NUM_PADS)
 572                return -EINVAL;
 573
 574        mutex_lock(&priv->lock);
 575
 576        fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
 577        if (!fmt) {
 578                ret = -EINVAL;
 579                goto out;
 580        }
 581
 582        sdformat->format = *fmt;
 583out:
 584        mutex_unlock(&priv->lock);
 585        return ret;
 586}
 587
 588static void vdic_try_fmt(struct vdic_priv *priv,
 589                         struct v4l2_subdev_pad_config *cfg,
 590                         struct v4l2_subdev_format *sdformat,
 591                         const struct imx_media_pixfmt **cc)
 592{
 593        struct v4l2_mbus_framefmt *infmt;
 594
 595        *cc = imx_media_find_ipu_format(sdformat->format.code, CS_SEL_YUV);
 596        if (!*cc) {
 597                u32 code;
 598
 599                imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV);
 600                *cc = imx_media_find_ipu_format(code, CS_SEL_YUV);
 601                sdformat->format.code = (*cc)->codes[0];
 602        }
 603
 604        infmt = __vdic_get_fmt(priv, cfg, priv->active_input_pad,
 605                               sdformat->which);
 606
 607        switch (sdformat->pad) {
 608        case VDIC_SRC_PAD_DIRECT:
 609                sdformat->format = *infmt;
 610                /* output is always progressive! */
 611                sdformat->format.field = V4L2_FIELD_NONE;
 612                break;
 613        case VDIC_SINK_PAD_DIRECT:
 614        case VDIC_SINK_PAD_IDMAC:
 615                v4l_bound_align_image(&sdformat->format.width,
 616                                      MIN_W, MAX_W_VDIC, W_ALIGN,
 617                                      &sdformat->format.height,
 618                                      MIN_H, MAX_H_VDIC, H_ALIGN, S_ALIGN);
 619
 620                imx_media_fill_default_mbus_fields(&sdformat->format, infmt,
 621                                                   true);
 622
 623                /* input must be interlaced! Choose SEQ_TB if not */
 624                if (!V4L2_FIELD_HAS_BOTH(sdformat->format.field))
 625                        sdformat->format.field = V4L2_FIELD_SEQ_TB;
 626                break;
 627        }
 628}
 629
 630static int vdic_set_fmt(struct v4l2_subdev *sd,
 631                        struct v4l2_subdev_pad_config *cfg,
 632                        struct v4l2_subdev_format *sdformat)
 633{
 634        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 635        const struct imx_media_pixfmt *cc;
 636        struct v4l2_mbus_framefmt *fmt;
 637        int ret = 0;
 638
 639        if (sdformat->pad >= VDIC_NUM_PADS)
 640                return -EINVAL;
 641
 642        mutex_lock(&priv->lock);
 643
 644        if (priv->stream_count > 0) {
 645                ret = -EBUSY;
 646                goto out;
 647        }
 648
 649        vdic_try_fmt(priv, cfg, sdformat, &cc);
 650
 651        fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which);
 652        *fmt = sdformat->format;
 653
 654        /* propagate format to source pad */
 655        if (sdformat->pad == VDIC_SINK_PAD_DIRECT ||
 656            sdformat->pad == VDIC_SINK_PAD_IDMAC) {
 657                const struct imx_media_pixfmt *outcc;
 658                struct v4l2_mbus_framefmt *outfmt;
 659                struct v4l2_subdev_format format;
 660
 661                format.pad = VDIC_SRC_PAD_DIRECT;
 662                format.which = sdformat->which;
 663                format.format = sdformat->format;
 664                vdic_try_fmt(priv, cfg, &format, &outcc);
 665
 666                outfmt = __vdic_get_fmt(priv, cfg, VDIC_SRC_PAD_DIRECT,
 667                                        sdformat->which);
 668                *outfmt = format.format;
 669                if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 670                        priv->cc[VDIC_SRC_PAD_DIRECT] = outcc;
 671        }
 672
 673        if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 674                priv->cc[sdformat->pad] = cc;
 675out:
 676        mutex_unlock(&priv->lock);
 677        return ret;
 678}
 679
 680static int vdic_link_setup(struct media_entity *entity,
 681                            const struct media_pad *local,
 682                            const struct media_pad *remote, u32 flags)
 683{
 684        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
 685        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 686        struct v4l2_subdev *remote_sd;
 687        int ret = 0;
 688
 689        dev_dbg(priv->dev, "link setup %s -> %s", remote->entity->name,
 690                local->entity->name);
 691
 692        mutex_lock(&priv->lock);
 693
 694        if (local->flags & MEDIA_PAD_FL_SOURCE) {
 695                if (!is_media_entity_v4l2_subdev(remote->entity)) {
 696                        ret = -EINVAL;
 697                        goto out;
 698                }
 699
 700                remote_sd = media_entity_to_v4l2_subdev(remote->entity);
 701
 702                if (flags & MEDIA_LNK_FL_ENABLED) {
 703                        if (priv->sink_sd) {
 704                                ret = -EBUSY;
 705                                goto out;
 706                        }
 707                        priv->sink_sd = remote_sd;
 708                } else {
 709                        priv->sink_sd = NULL;
 710                }
 711
 712                goto out;
 713        }
 714
 715        /* this is a sink pad */
 716
 717        if (flags & MEDIA_LNK_FL_ENABLED) {
 718                if (priv->src) {
 719                        ret = -EBUSY;
 720                        goto out;
 721                }
 722        } else {
 723                priv->src = NULL;
 724                goto out;
 725        }
 726
 727        if (local->index == VDIC_SINK_PAD_IDMAC) {
 728                struct imx_media_video_dev *vdev = priv->vdev;
 729
 730                if (!is_media_entity_v4l2_video_device(remote->entity)) {
 731                        ret = -EINVAL;
 732                        goto out;
 733                }
 734                if (!vdev) {
 735                        ret = -ENODEV;
 736                        goto out;
 737                }
 738
 739                priv->csi_direct = false;
 740        } else {
 741                if (!is_media_entity_v4l2_subdev(remote->entity)) {
 742                        ret = -EINVAL;
 743                        goto out;
 744                }
 745
 746                remote_sd = media_entity_to_v4l2_subdev(remote->entity);
 747
 748                /* direct pad must connect to a CSI */
 749                if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) ||
 750                    remote->index != CSI_SRC_PAD_DIRECT) {
 751                        ret = -EINVAL;
 752                        goto out;
 753                }
 754
 755                priv->csi_direct = true;
 756        }
 757
 758        priv->src = remote->entity;
 759        /* record which input pad is now active */
 760        priv->active_input_pad = local->index;
 761out:
 762        mutex_unlock(&priv->lock);
 763        return ret;
 764}
 765
 766static int vdic_link_validate(struct v4l2_subdev *sd,
 767                              struct media_link *link,
 768                              struct v4l2_subdev_format *source_fmt,
 769                              struct v4l2_subdev_format *sink_fmt)
 770{
 771        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 772        int ret;
 773
 774        ret = v4l2_subdev_link_validate_default(sd, link,
 775                                                source_fmt, sink_fmt);
 776        if (ret)
 777                return ret;
 778
 779        mutex_lock(&priv->lock);
 780
 781        if (priv->csi_direct && priv->motion != HIGH_MOTION) {
 782                v4l2_err(&priv->sd,
 783                         "direct CSI pipeline requires high motion\n");
 784                ret = -EINVAL;
 785        }
 786
 787        mutex_unlock(&priv->lock);
 788        return ret;
 789}
 790
 791static int vdic_g_frame_interval(struct v4l2_subdev *sd,
 792                                struct v4l2_subdev_frame_interval *fi)
 793{
 794        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 795
 796        if (fi->pad >= VDIC_NUM_PADS)
 797                return -EINVAL;
 798
 799        mutex_lock(&priv->lock);
 800
 801        fi->interval = priv->frame_interval[fi->pad];
 802
 803        mutex_unlock(&priv->lock);
 804
 805        return 0;
 806}
 807
 808static int vdic_s_frame_interval(struct v4l2_subdev *sd,
 809                                struct v4l2_subdev_frame_interval *fi)
 810{
 811        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 812        struct v4l2_fract *input_fi, *output_fi;
 813        int ret = 0;
 814
 815        mutex_lock(&priv->lock);
 816
 817        input_fi = &priv->frame_interval[priv->active_input_pad];
 818        output_fi = &priv->frame_interval[VDIC_SRC_PAD_DIRECT];
 819
 820        switch (fi->pad) {
 821        case VDIC_SINK_PAD_DIRECT:
 822        case VDIC_SINK_PAD_IDMAC:
 823                /* No limits on valid input frame intervals */
 824                if (fi->interval.numerator == 0 ||
 825                    fi->interval.denominator == 0)
 826                        fi->interval = priv->frame_interval[fi->pad];
 827                /* Reset output interval */
 828                *output_fi = fi->interval;
 829                if (priv->csi_direct)
 830                        output_fi->denominator *= 2;
 831                break;
 832        case VDIC_SRC_PAD_DIRECT:
 833                /*
 834                 * frame rate at output pad is double input
 835                 * rate when using direct CSI->VDIC pipeline.
 836                 *
 837                 * TODO: implement VDIC frame skipping
 838                 */
 839                fi->interval = *input_fi;
 840                if (priv->csi_direct)
 841                        fi->interval.denominator *= 2;
 842                break;
 843        default:
 844                ret = -EINVAL;
 845                goto out;
 846        }
 847
 848        priv->frame_interval[fi->pad] = fi->interval;
 849out:
 850        mutex_unlock(&priv->lock);
 851        return ret;
 852}
 853
 854/*
 855 * retrieve our pads parsed from the OF graph by the media device
 856 */
 857static int vdic_registered(struct v4l2_subdev *sd)
 858{
 859        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 860        int i, ret;
 861        u32 code;
 862
 863        /* get media device */
 864        priv->md = dev_get_drvdata(sd->v4l2_dev->dev);
 865
 866        for (i = 0; i < VDIC_NUM_PADS; i++) {
 867                priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ?
 868                        MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
 869
 870                code = 0;
 871                if (i != VDIC_SINK_PAD_IDMAC)
 872                        imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV);
 873
 874                /* set a default mbus format  */
 875                ret = imx_media_init_mbus_fmt(&priv->format_mbus[i],
 876                                              640, 480, code, V4L2_FIELD_NONE,
 877                                              &priv->cc[i]);
 878                if (ret)
 879                        return ret;
 880
 881                /* init default frame interval */
 882                priv->frame_interval[i].numerator = 1;
 883                priv->frame_interval[i].denominator = 30;
 884                if (i == VDIC_SRC_PAD_DIRECT)
 885                        priv->frame_interval[i].denominator *= 2;
 886        }
 887
 888        priv->active_input_pad = VDIC_SINK_PAD_DIRECT;
 889
 890        ret = vdic_init_controls(priv);
 891        if (ret)
 892                return ret;
 893
 894        ret = media_entity_pads_init(&sd->entity, VDIC_NUM_PADS, priv->pad);
 895        if (ret)
 896                v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
 897
 898        return ret;
 899}
 900
 901static void vdic_unregistered(struct v4l2_subdev *sd)
 902{
 903        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 904
 905        v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
 906}
 907
 908static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
 909        .init_cfg = imx_media_init_cfg,
 910        .enum_mbus_code = vdic_enum_mbus_code,
 911        .get_fmt = vdic_get_fmt,
 912        .set_fmt = vdic_set_fmt,
 913        .link_validate = vdic_link_validate,
 914};
 915
 916static const struct v4l2_subdev_video_ops vdic_video_ops = {
 917        .g_frame_interval = vdic_g_frame_interval,
 918        .s_frame_interval = vdic_s_frame_interval,
 919        .s_stream = vdic_s_stream,
 920};
 921
 922static const struct media_entity_operations vdic_entity_ops = {
 923        .link_setup = vdic_link_setup,
 924        .link_validate = v4l2_subdev_link_validate,
 925};
 926
 927static const struct v4l2_subdev_ops vdic_subdev_ops = {
 928        .video = &vdic_video_ops,
 929        .pad = &vdic_pad_ops,
 930};
 931
 932static const struct v4l2_subdev_internal_ops vdic_internal_ops = {
 933        .registered = vdic_registered,
 934        .unregistered = vdic_unregistered,
 935};
 936
 937static int imx_vdic_probe(struct platform_device *pdev)
 938{
 939        struct imx_media_ipu_internal_sd_pdata *pdata;
 940        struct vdic_priv *priv;
 941        int ret;
 942
 943        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 944        if (!priv)
 945                return -ENOMEM;
 946
 947        platform_set_drvdata(pdev, &priv->sd);
 948        priv->dev = &pdev->dev;
 949
 950        pdata = priv->dev->platform_data;
 951        priv->ipu_id = pdata->ipu_id;
 952
 953        v4l2_subdev_init(&priv->sd, &vdic_subdev_ops);
 954        v4l2_set_subdevdata(&priv->sd, priv);
 955        priv->sd.internal_ops = &vdic_internal_ops;
 956        priv->sd.entity.ops = &vdic_entity_ops;
 957        priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
 958        priv->sd.dev = &pdev->dev;
 959        priv->sd.owner = THIS_MODULE;
 960        priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
 961        /* get our group id */
 962        priv->sd.grp_id = pdata->grp_id;
 963        strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name));
 964
 965        mutex_init(&priv->lock);
 966
 967        ret = v4l2_async_register_subdev(&priv->sd);
 968        if (ret)
 969                goto free;
 970
 971        return 0;
 972free:
 973        mutex_destroy(&priv->lock);
 974        return ret;
 975}
 976
 977static int imx_vdic_remove(struct platform_device *pdev)
 978{
 979        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
 980        struct vdic_priv *priv = v4l2_get_subdevdata(sd);
 981
 982        v4l2_info(sd, "Removing\n");
 983
 984        v4l2_async_unregister_subdev(sd);
 985        mutex_destroy(&priv->lock);
 986        media_entity_cleanup(&sd->entity);
 987
 988        return 0;
 989}
 990
 991static const struct platform_device_id imx_vdic_ids[] = {
 992        { .name = "imx-ipuv3-vdic" },
 993        { },
 994};
 995MODULE_DEVICE_TABLE(platform, imx_vdic_ids);
 996
 997static struct platform_driver imx_vdic_driver = {
 998        .probe = imx_vdic_probe,
 999        .remove = imx_vdic_remove,
1000        .id_table = imx_vdic_ids,
1001        .driver = {
1002                .name = "imx-ipuv3-vdic",
1003        },
1004};
1005module_platform_driver(imx_vdic_driver);
1006
1007MODULE_DESCRIPTION("i.MX VDIC subdev driver");
1008MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
1009MODULE_LICENSE("GPL");
1010MODULE_ALIAS("platform:imx-ipuv3-vdic");
1011