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