Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * V4L2 Deinterlacer Subdev for Freescale i.MX5/6 SOC
0004  *
0005  * Copyright (c) 2017 Mentor Graphics Inc.
0006  */
0007 #include <media/v4l2-ctrls.h>
0008 #include <media/v4l2-device.h>
0009 #include <media/v4l2-ioctl.h>
0010 #include <media/v4l2-mc.h>
0011 #include <media/v4l2-subdev.h>
0012 #include <media/imx.h>
0013 #include "imx-media.h"
0014 
0015 /*
0016  * This subdev implements two different video pipelines:
0017  *
0018  * CSI -> VDIC
0019  *
0020  * In this pipeline, the CSI sends a single interlaced field F(n-1)
0021  * directly to the VDIC (and optionally the following field F(n)
0022  * can be sent to memory via IDMAC channel 13). This pipeline only works
0023  * in VDIC's high motion mode, which only requires a single field for
0024  * processing. The other motion modes (low and medium) require three
0025  * fields, so this pipeline does not work in those modes. Also, it is
0026  * not clear how this pipeline can deal with the various field orders
0027  * (sequential BT/TB, interlaced BT/TB).
0028  *
0029  * MEM -> CH8,9,10 -> VDIC
0030  *
0031  * In this pipeline, previous field F(n-1), current field F(n), and next
0032  * field F(n+1) are transferred to the VDIC via IDMAC channels 8,9,10.
0033  * These memory buffers can come from a video output or mem2mem device.
0034  * All motion modes are supported by this pipeline.
0035  *
0036  * The "direct" CSI->VDIC pipeline requires no DMA, but it can only be
0037  * used in high motion mode.
0038  */
0039 
0040 struct vdic_priv;
0041 
0042 struct vdic_pipeline_ops {
0043     int (*setup)(struct vdic_priv *priv);
0044     void (*start)(struct vdic_priv *priv);
0045     void (*stop)(struct vdic_priv *priv);
0046     void (*disable)(struct vdic_priv *priv);
0047 };
0048 
0049 /*
0050  * Min/Max supported width and heights.
0051  */
0052 #define MIN_W        32
0053 #define MIN_H        32
0054 #define MAX_W_VDIC  968
0055 #define MAX_H_VDIC 2048
0056 #define W_ALIGN    4 /* multiple of 16 pixels */
0057 #define H_ALIGN    1 /* multiple of 2 lines */
0058 #define S_ALIGN    1 /* multiple of 2 */
0059 
0060 struct vdic_priv {
0061     struct device *ipu_dev;
0062     struct ipu_soc *ipu;
0063 
0064     struct v4l2_subdev   sd;
0065     struct media_pad pad[VDIC_NUM_PADS];
0066 
0067     /* lock to protect all members below */
0068     struct mutex lock;
0069 
0070     /* IPU units we require */
0071     struct ipu_vdi *vdi;
0072 
0073     int active_input_pad;
0074 
0075     struct ipuv3_channel *vdi_in_ch_p; /* F(n-1) transfer channel */
0076     struct ipuv3_channel *vdi_in_ch;   /* F(n) transfer channel */
0077     struct ipuv3_channel *vdi_in_ch_n; /* F(n+1) transfer channel */
0078 
0079     /* pipeline operations */
0080     struct vdic_pipeline_ops *ops;
0081 
0082     /* current and previous input buffers indirect path */
0083     struct imx_media_buffer *curr_in_buf;
0084     struct imx_media_buffer *prev_in_buf;
0085 
0086     /*
0087      * translated field type, input line stride, and field size
0088      * for indirect path
0089      */
0090     u32 fieldtype;
0091     u32 in_stride;
0092     u32 field_size;
0093 
0094     /* the source (a video device or subdev) */
0095     struct media_entity *src;
0096     /* the sink that will receive the progressive out buffers */
0097     struct v4l2_subdev *sink_sd;
0098 
0099     struct v4l2_mbus_framefmt format_mbus[VDIC_NUM_PADS];
0100     const struct imx_media_pixfmt *cc[VDIC_NUM_PADS];
0101     struct v4l2_fract frame_interval[VDIC_NUM_PADS];
0102 
0103     /* the video device at IDMAC input pad */
0104     struct imx_media_video_dev *vdev;
0105 
0106     bool csi_direct;  /* using direct CSI->VDIC->IC pipeline */
0107 
0108     /* motion select control */
0109     struct v4l2_ctrl_handler ctrl_hdlr;
0110     enum ipu_motion_sel motion;
0111 
0112     int stream_count;
0113 };
0114 
0115 static void vdic_put_ipu_resources(struct vdic_priv *priv)
0116 {
0117     if (priv->vdi_in_ch_p)
0118         ipu_idmac_put(priv->vdi_in_ch_p);
0119     priv->vdi_in_ch_p = NULL;
0120 
0121     if (priv->vdi_in_ch)
0122         ipu_idmac_put(priv->vdi_in_ch);
0123     priv->vdi_in_ch = NULL;
0124 
0125     if (priv->vdi_in_ch_n)
0126         ipu_idmac_put(priv->vdi_in_ch_n);
0127     priv->vdi_in_ch_n = NULL;
0128 
0129     if (!IS_ERR_OR_NULL(priv->vdi))
0130         ipu_vdi_put(priv->vdi);
0131     priv->vdi = NULL;
0132 }
0133 
0134 static int vdic_get_ipu_resources(struct vdic_priv *priv)
0135 {
0136     int ret, err_chan;
0137     struct ipuv3_channel *ch;
0138     struct ipu_vdi *vdi;
0139 
0140     vdi = ipu_vdi_get(priv->ipu);
0141     if (IS_ERR(vdi)) {
0142         v4l2_err(&priv->sd, "failed to get VDIC\n");
0143         ret = PTR_ERR(vdi);
0144         goto out;
0145     }
0146     priv->vdi = vdi;
0147 
0148     if (!priv->csi_direct) {
0149         ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_PREV);
0150         if (IS_ERR(ch)) {
0151             err_chan = IPUV3_CHANNEL_MEM_VDI_PREV;
0152             ret = PTR_ERR(ch);
0153             goto out_err_chan;
0154         }
0155         priv->vdi_in_ch_p = ch;
0156 
0157         ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_CUR);
0158         if (IS_ERR(ch)) {
0159             err_chan = IPUV3_CHANNEL_MEM_VDI_CUR;
0160             ret = PTR_ERR(ch);
0161             goto out_err_chan;
0162         }
0163         priv->vdi_in_ch = ch;
0164 
0165         ch = ipu_idmac_get(priv->ipu, IPUV3_CHANNEL_MEM_VDI_NEXT);
0166         if (IS_ERR(ch)) {
0167             err_chan = IPUV3_CHANNEL_MEM_VDI_NEXT;
0168             ret = PTR_ERR(ch);
0169             goto out_err_chan;
0170         }
0171         priv->vdi_in_ch_n = ch;
0172     }
0173 
0174     return 0;
0175 
0176 out_err_chan:
0177     v4l2_err(&priv->sd, "could not get IDMAC channel %u\n", err_chan);
0178 out:
0179     vdic_put_ipu_resources(priv);
0180     return ret;
0181 }
0182 
0183 /*
0184  * This function is currently unused, but will be called when the
0185  * output/mem2mem device at the IDMAC input pad sends us a new
0186  * buffer. It kicks off the IDMAC read channels to bring in the
0187  * buffer fields from memory and begin the conversions.
0188  */
0189 static void __maybe_unused prepare_vdi_in_buffers(struct vdic_priv *priv,
0190                           struct imx_media_buffer *curr)
0191 {
0192     dma_addr_t prev_phys, curr_phys, next_phys;
0193     struct imx_media_buffer *prev;
0194     struct vb2_buffer *curr_vb, *prev_vb;
0195     u32 fs = priv->field_size;
0196     u32 is = priv->in_stride;
0197 
0198     /* current input buffer is now previous */
0199     priv->prev_in_buf = priv->curr_in_buf;
0200     priv->curr_in_buf = curr;
0201     prev = priv->prev_in_buf ? priv->prev_in_buf : curr;
0202 
0203     prev_vb = &prev->vbuf.vb2_buf;
0204     curr_vb = &curr->vbuf.vb2_buf;
0205 
0206     switch (priv->fieldtype) {
0207     case V4L2_FIELD_SEQ_TB:
0208     case V4L2_FIELD_SEQ_BT:
0209         prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + fs;
0210         curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0);
0211         next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + fs;
0212         break;
0213     case V4L2_FIELD_INTERLACED_TB:
0214     case V4L2_FIELD_INTERLACED_BT:
0215     case V4L2_FIELD_INTERLACED:
0216         prev_phys = vb2_dma_contig_plane_dma_addr(prev_vb, 0) + is;
0217         curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0);
0218         next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is;
0219         break;
0220     default:
0221         /*
0222          * can't get here, priv->fieldtype can only be one of
0223          * the above. This is to quiet smatch errors.
0224          */
0225         return;
0226     }
0227 
0228     ipu_cpmem_set_buffer(priv->vdi_in_ch_p, 0, prev_phys);
0229     ipu_cpmem_set_buffer(priv->vdi_in_ch,   0, curr_phys);
0230     ipu_cpmem_set_buffer(priv->vdi_in_ch_n, 0, next_phys);
0231 
0232     ipu_idmac_select_buffer(priv->vdi_in_ch_p, 0);
0233     ipu_idmac_select_buffer(priv->vdi_in_ch, 0);
0234     ipu_idmac_select_buffer(priv->vdi_in_ch_n, 0);
0235 }
0236 
0237 static int setup_vdi_channel(struct vdic_priv *priv,
0238                  struct ipuv3_channel *channel,
0239                  dma_addr_t phys0, dma_addr_t phys1)
0240 {
0241     struct imx_media_video_dev *vdev = priv->vdev;
0242     unsigned int burst_size;
0243     struct ipu_image image;
0244     int ret;
0245 
0246     ipu_cpmem_zero(channel);
0247 
0248     memset(&image, 0, sizeof(image));
0249     image.pix = vdev->fmt;
0250     image.rect = vdev->compose;
0251     /* one field to VDIC channels */
0252     image.pix.height /= 2;
0253     image.rect.height /= 2;
0254     image.phys0 = phys0;
0255     image.phys1 = phys1;
0256 
0257     ret = ipu_cpmem_set_image(channel, &image);
0258     if (ret)
0259         return ret;
0260 
0261     burst_size = (image.pix.width & 0xf) ? 8 : 16;
0262     ipu_cpmem_set_burstsize(channel, burst_size);
0263 
0264     ipu_cpmem_set_axi_id(channel, 1);
0265 
0266     ipu_idmac_set_double_buffer(channel, false);
0267 
0268     return 0;
0269 }
0270 
0271 static int vdic_setup_direct(struct vdic_priv *priv)
0272 {
0273     /* set VDIC to receive from CSI for direct path */
0274     ipu_fsu_link(priv->ipu, IPUV3_CHANNEL_CSI_DIRECT,
0275              IPUV3_CHANNEL_CSI_VDI_PREV);
0276 
0277     return 0;
0278 }
0279 
0280 static void vdic_start_direct(struct vdic_priv *priv)
0281 {
0282 }
0283 
0284 static void vdic_stop_direct(struct vdic_priv *priv)
0285 {
0286 }
0287 
0288 static void vdic_disable_direct(struct vdic_priv *priv)
0289 {
0290     ipu_fsu_unlink(priv->ipu, IPUV3_CHANNEL_CSI_DIRECT,
0291                IPUV3_CHANNEL_CSI_VDI_PREV);
0292 }
0293 
0294 static int vdic_setup_indirect(struct vdic_priv *priv)
0295 {
0296     struct v4l2_mbus_framefmt *infmt;
0297     const struct imx_media_pixfmt *incc;
0298     int in_size, ret;
0299 
0300     infmt = &priv->format_mbus[VDIC_SINK_PAD_IDMAC];
0301     incc = priv->cc[VDIC_SINK_PAD_IDMAC];
0302 
0303     in_size = (infmt->width * incc->bpp * infmt->height) >> 3;
0304 
0305     /* 1/2 full image size */
0306     priv->field_size = in_size / 2;
0307     priv->in_stride = incc->planar ?
0308         infmt->width : (infmt->width * incc->bpp) >> 3;
0309 
0310     priv->prev_in_buf = NULL;
0311     priv->curr_in_buf = NULL;
0312 
0313     priv->fieldtype = infmt->field;
0314 
0315     /* init the vdi-in channels */
0316     ret = setup_vdi_channel(priv, priv->vdi_in_ch_p, 0, 0);
0317     if (ret)
0318         return ret;
0319     ret = setup_vdi_channel(priv, priv->vdi_in_ch, 0, 0);
0320     if (ret)
0321         return ret;
0322     return setup_vdi_channel(priv, priv->vdi_in_ch_n, 0, 0);
0323 }
0324 
0325 static void vdic_start_indirect(struct vdic_priv *priv)
0326 {
0327     /* enable the channels */
0328     ipu_idmac_enable_channel(priv->vdi_in_ch_p);
0329     ipu_idmac_enable_channel(priv->vdi_in_ch);
0330     ipu_idmac_enable_channel(priv->vdi_in_ch_n);
0331 }
0332 
0333 static void vdic_stop_indirect(struct vdic_priv *priv)
0334 {
0335     /* disable channels */
0336     ipu_idmac_disable_channel(priv->vdi_in_ch_p);
0337     ipu_idmac_disable_channel(priv->vdi_in_ch);
0338     ipu_idmac_disable_channel(priv->vdi_in_ch_n);
0339 }
0340 
0341 static void vdic_disable_indirect(struct vdic_priv *priv)
0342 {
0343 }
0344 
0345 static struct vdic_pipeline_ops direct_ops = {
0346     .setup = vdic_setup_direct,
0347     .start = vdic_start_direct,
0348     .stop = vdic_stop_direct,
0349     .disable = vdic_disable_direct,
0350 };
0351 
0352 static struct vdic_pipeline_ops indirect_ops = {
0353     .setup = vdic_setup_indirect,
0354     .start = vdic_start_indirect,
0355     .stop = vdic_stop_indirect,
0356     .disable = vdic_disable_indirect,
0357 };
0358 
0359 static int vdic_start(struct vdic_priv *priv)
0360 {
0361     struct v4l2_mbus_framefmt *infmt;
0362     int ret;
0363 
0364     infmt = &priv->format_mbus[priv->active_input_pad];
0365 
0366     priv->ops = priv->csi_direct ? &direct_ops : &indirect_ops;
0367 
0368     ret = vdic_get_ipu_resources(priv);
0369     if (ret)
0370         return ret;
0371 
0372     /*
0373      * init the VDIC.
0374      *
0375      * note we don't give infmt->code to ipu_vdi_setup(). The VDIC
0376      * only supports 4:2:2 or 4:2:0, and this subdev will only
0377      * negotiate 4:2:2 at its sink pads.
0378      */
0379     ipu_vdi_setup(priv->vdi, MEDIA_BUS_FMT_UYVY8_2X8,
0380               infmt->width, infmt->height);
0381     ipu_vdi_set_field_order(priv->vdi, V4L2_STD_UNKNOWN, infmt->field);
0382     ipu_vdi_set_motion(priv->vdi, priv->motion);
0383 
0384     ret = priv->ops->setup(priv);
0385     if (ret)
0386         goto out_put_ipu;
0387 
0388     ipu_vdi_enable(priv->vdi);
0389 
0390     priv->ops->start(priv);
0391 
0392     return 0;
0393 
0394 out_put_ipu:
0395     vdic_put_ipu_resources(priv);
0396     return ret;
0397 }
0398 
0399 static void vdic_stop(struct vdic_priv *priv)
0400 {
0401     priv->ops->stop(priv);
0402     ipu_vdi_disable(priv->vdi);
0403     priv->ops->disable(priv);
0404 
0405     vdic_put_ipu_resources(priv);
0406 }
0407 
0408 /*
0409  * V4L2 subdev operations.
0410  */
0411 
0412 static int vdic_s_ctrl(struct v4l2_ctrl *ctrl)
0413 {
0414     struct vdic_priv *priv = container_of(ctrl->handler,
0415                           struct vdic_priv, ctrl_hdlr);
0416     enum ipu_motion_sel motion;
0417     int ret = 0;
0418 
0419     mutex_lock(&priv->lock);
0420 
0421     switch (ctrl->id) {
0422     case V4L2_CID_DEINTERLACING_MODE:
0423         motion = ctrl->val;
0424         if (motion != priv->motion) {
0425             /* can't change motion control mid-streaming */
0426             if (priv->stream_count > 0) {
0427                 ret = -EBUSY;
0428                 goto out;
0429             }
0430             priv->motion = motion;
0431         }
0432         break;
0433     default:
0434         v4l2_err(&priv->sd, "Invalid control\n");
0435         ret = -EINVAL;
0436     }
0437 
0438 out:
0439     mutex_unlock(&priv->lock);
0440     return ret;
0441 }
0442 
0443 static const struct v4l2_ctrl_ops vdic_ctrl_ops = {
0444     .s_ctrl = vdic_s_ctrl,
0445 };
0446 
0447 static const char * const vdic_ctrl_motion_menu[] = {
0448     "No Motion Compensation",
0449     "Low Motion",
0450     "Medium Motion",
0451     "High Motion",
0452 };
0453 
0454 static int vdic_init_controls(struct vdic_priv *priv)
0455 {
0456     struct v4l2_ctrl_handler *hdlr = &priv->ctrl_hdlr;
0457     int ret;
0458 
0459     v4l2_ctrl_handler_init(hdlr, 1);
0460 
0461     v4l2_ctrl_new_std_menu_items(hdlr, &vdic_ctrl_ops,
0462                      V4L2_CID_DEINTERLACING_MODE,
0463                      HIGH_MOTION, 0, HIGH_MOTION,
0464                      vdic_ctrl_motion_menu);
0465 
0466     priv->sd.ctrl_handler = hdlr;
0467 
0468     if (hdlr->error) {
0469         ret = hdlr->error;
0470         goto out_free;
0471     }
0472 
0473     v4l2_ctrl_handler_setup(hdlr);
0474     return 0;
0475 
0476 out_free:
0477     v4l2_ctrl_handler_free(hdlr);
0478     return ret;
0479 }
0480 
0481 static int vdic_s_stream(struct v4l2_subdev *sd, int enable)
0482 {
0483     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0484     struct v4l2_subdev *src_sd = NULL;
0485     int ret = 0;
0486 
0487     mutex_lock(&priv->lock);
0488 
0489     if (!priv->src || !priv->sink_sd) {
0490         ret = -EPIPE;
0491         goto out;
0492     }
0493 
0494     if (priv->csi_direct)
0495         src_sd = media_entity_to_v4l2_subdev(priv->src);
0496 
0497     /*
0498      * enable/disable streaming only if stream_count is
0499      * going from 0 to 1 / 1 to 0.
0500      */
0501     if (priv->stream_count != !enable)
0502         goto update_count;
0503 
0504     dev_dbg(priv->ipu_dev, "%s: stream %s\n", sd->name,
0505         enable ? "ON" : "OFF");
0506 
0507     if (enable)
0508         ret = vdic_start(priv);
0509     else
0510         vdic_stop(priv);
0511     if (ret)
0512         goto out;
0513 
0514     if (src_sd) {
0515         /* start/stop upstream */
0516         ret = v4l2_subdev_call(src_sd, video, s_stream, enable);
0517         ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0;
0518         if (ret) {
0519             if (enable)
0520                 vdic_stop(priv);
0521             goto out;
0522         }
0523     }
0524 
0525 update_count:
0526     priv->stream_count += enable ? 1 : -1;
0527     if (priv->stream_count < 0)
0528         priv->stream_count = 0;
0529 out:
0530     mutex_unlock(&priv->lock);
0531     return ret;
0532 }
0533 
0534 static struct v4l2_mbus_framefmt *
0535 __vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_state *sd_state,
0536            unsigned int pad, enum v4l2_subdev_format_whence which)
0537 {
0538     if (which == V4L2_SUBDEV_FORMAT_TRY)
0539         return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
0540     else
0541         return &priv->format_mbus[pad];
0542 }
0543 
0544 static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
0545                    struct v4l2_subdev_state *sd_state,
0546                    struct v4l2_subdev_mbus_code_enum *code)
0547 {
0548     if (code->pad >= VDIC_NUM_PADS)
0549         return -EINVAL;
0550 
0551     return imx_media_enum_ipu_formats(&code->code, code->index,
0552                       PIXFMT_SEL_YUV);
0553 }
0554 
0555 static int vdic_get_fmt(struct v4l2_subdev *sd,
0556             struct v4l2_subdev_state *sd_state,
0557             struct v4l2_subdev_format *sdformat)
0558 {
0559     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0560     struct v4l2_mbus_framefmt *fmt;
0561     int ret = 0;
0562 
0563     if (sdformat->pad >= VDIC_NUM_PADS)
0564         return -EINVAL;
0565 
0566     mutex_lock(&priv->lock);
0567 
0568     fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
0569     if (!fmt) {
0570         ret = -EINVAL;
0571         goto out;
0572     }
0573 
0574     sdformat->format = *fmt;
0575 out:
0576     mutex_unlock(&priv->lock);
0577     return ret;
0578 }
0579 
0580 static void vdic_try_fmt(struct vdic_priv *priv,
0581              struct v4l2_subdev_state *sd_state,
0582              struct v4l2_subdev_format *sdformat,
0583              const struct imx_media_pixfmt **cc)
0584 {
0585     struct v4l2_mbus_framefmt *infmt;
0586 
0587     *cc = imx_media_find_ipu_format(sdformat->format.code,
0588                     PIXFMT_SEL_YUV);
0589     if (!*cc) {
0590         u32 code;
0591 
0592         imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV);
0593         *cc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV);
0594         sdformat->format.code = (*cc)->codes[0];
0595     }
0596 
0597     infmt = __vdic_get_fmt(priv, sd_state, priv->active_input_pad,
0598                    sdformat->which);
0599 
0600     switch (sdformat->pad) {
0601     case VDIC_SRC_PAD_DIRECT:
0602         sdformat->format = *infmt;
0603         /* output is always progressive! */
0604         sdformat->format.field = V4L2_FIELD_NONE;
0605         break;
0606     case VDIC_SINK_PAD_DIRECT:
0607     case VDIC_SINK_PAD_IDMAC:
0608         v4l_bound_align_image(&sdformat->format.width,
0609                       MIN_W, MAX_W_VDIC, W_ALIGN,
0610                       &sdformat->format.height,
0611                       MIN_H, MAX_H_VDIC, H_ALIGN, S_ALIGN);
0612 
0613         /* input must be interlaced! Choose SEQ_TB if not */
0614         if (!V4L2_FIELD_HAS_BOTH(sdformat->format.field))
0615             sdformat->format.field = V4L2_FIELD_SEQ_TB;
0616         break;
0617     }
0618 
0619     imx_media_try_colorimetry(&sdformat->format, true);
0620 }
0621 
0622 static int vdic_set_fmt(struct v4l2_subdev *sd,
0623             struct v4l2_subdev_state *sd_state,
0624             struct v4l2_subdev_format *sdformat)
0625 {
0626     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0627     const struct imx_media_pixfmt *cc;
0628     struct v4l2_mbus_framefmt *fmt;
0629     int ret = 0;
0630 
0631     if (sdformat->pad >= VDIC_NUM_PADS)
0632         return -EINVAL;
0633 
0634     mutex_lock(&priv->lock);
0635 
0636     if (priv->stream_count > 0) {
0637         ret = -EBUSY;
0638         goto out;
0639     }
0640 
0641     vdic_try_fmt(priv, sd_state, sdformat, &cc);
0642 
0643     fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which);
0644     *fmt = sdformat->format;
0645 
0646     /* propagate format to source pad */
0647     if (sdformat->pad == VDIC_SINK_PAD_DIRECT ||
0648         sdformat->pad == VDIC_SINK_PAD_IDMAC) {
0649         const struct imx_media_pixfmt *outcc;
0650         struct v4l2_mbus_framefmt *outfmt;
0651         struct v4l2_subdev_format format;
0652 
0653         format.pad = VDIC_SRC_PAD_DIRECT;
0654         format.which = sdformat->which;
0655         format.format = sdformat->format;
0656         vdic_try_fmt(priv, sd_state, &format, &outcc);
0657 
0658         outfmt = __vdic_get_fmt(priv, sd_state, VDIC_SRC_PAD_DIRECT,
0659                     sdformat->which);
0660         *outfmt = format.format;
0661         if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
0662             priv->cc[VDIC_SRC_PAD_DIRECT] = outcc;
0663     }
0664 
0665     if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
0666         priv->cc[sdformat->pad] = cc;
0667 out:
0668     mutex_unlock(&priv->lock);
0669     return ret;
0670 }
0671 
0672 static int vdic_link_setup(struct media_entity *entity,
0673                 const struct media_pad *local,
0674                 const struct media_pad *remote, u32 flags)
0675 {
0676     struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
0677     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0678     struct v4l2_subdev *remote_sd;
0679     int ret = 0;
0680 
0681     dev_dbg(priv->ipu_dev, "%s: link setup %s -> %s",
0682         sd->name, remote->entity->name, local->entity->name);
0683 
0684     mutex_lock(&priv->lock);
0685 
0686     if (local->flags & MEDIA_PAD_FL_SOURCE) {
0687         if (!is_media_entity_v4l2_subdev(remote->entity)) {
0688             ret = -EINVAL;
0689             goto out;
0690         }
0691 
0692         remote_sd = media_entity_to_v4l2_subdev(remote->entity);
0693 
0694         if (flags & MEDIA_LNK_FL_ENABLED) {
0695             if (priv->sink_sd) {
0696                 ret = -EBUSY;
0697                 goto out;
0698             }
0699             priv->sink_sd = remote_sd;
0700         } else {
0701             priv->sink_sd = NULL;
0702         }
0703 
0704         goto out;
0705     }
0706 
0707     /* this is a sink pad */
0708 
0709     if (flags & MEDIA_LNK_FL_ENABLED) {
0710         if (priv->src) {
0711             ret = -EBUSY;
0712             goto out;
0713         }
0714     } else {
0715         priv->src = NULL;
0716         goto out;
0717     }
0718 
0719     if (local->index == VDIC_SINK_PAD_IDMAC) {
0720         struct imx_media_video_dev *vdev = priv->vdev;
0721 
0722         if (!is_media_entity_v4l2_video_device(remote->entity)) {
0723             ret = -EINVAL;
0724             goto out;
0725         }
0726         if (!vdev) {
0727             ret = -ENODEV;
0728             goto out;
0729         }
0730 
0731         priv->csi_direct = false;
0732     } else {
0733         if (!is_media_entity_v4l2_subdev(remote->entity)) {
0734             ret = -EINVAL;
0735             goto out;
0736         }
0737 
0738         remote_sd = media_entity_to_v4l2_subdev(remote->entity);
0739 
0740         /* direct pad must connect to a CSI */
0741         if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) ||
0742             remote->index != CSI_SRC_PAD_DIRECT) {
0743             ret = -EINVAL;
0744             goto out;
0745         }
0746 
0747         priv->csi_direct = true;
0748     }
0749 
0750     priv->src = remote->entity;
0751     /* record which input pad is now active */
0752     priv->active_input_pad = local->index;
0753 out:
0754     mutex_unlock(&priv->lock);
0755     return ret;
0756 }
0757 
0758 static int vdic_link_validate(struct v4l2_subdev *sd,
0759                   struct media_link *link,
0760                   struct v4l2_subdev_format *source_fmt,
0761                   struct v4l2_subdev_format *sink_fmt)
0762 {
0763     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0764     int ret;
0765 
0766     ret = v4l2_subdev_link_validate_default(sd, link,
0767                         source_fmt, sink_fmt);
0768     if (ret)
0769         return ret;
0770 
0771     mutex_lock(&priv->lock);
0772 
0773     if (priv->csi_direct && priv->motion != HIGH_MOTION) {
0774         v4l2_err(&priv->sd,
0775              "direct CSI pipeline requires high motion\n");
0776         ret = -EINVAL;
0777     }
0778 
0779     mutex_unlock(&priv->lock);
0780     return ret;
0781 }
0782 
0783 static int vdic_g_frame_interval(struct v4l2_subdev *sd,
0784                 struct v4l2_subdev_frame_interval *fi)
0785 {
0786     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0787 
0788     if (fi->pad >= VDIC_NUM_PADS)
0789         return -EINVAL;
0790 
0791     mutex_lock(&priv->lock);
0792 
0793     fi->interval = priv->frame_interval[fi->pad];
0794 
0795     mutex_unlock(&priv->lock);
0796 
0797     return 0;
0798 }
0799 
0800 static int vdic_s_frame_interval(struct v4l2_subdev *sd,
0801                 struct v4l2_subdev_frame_interval *fi)
0802 {
0803     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0804     struct v4l2_fract *input_fi, *output_fi;
0805     int ret = 0;
0806 
0807     mutex_lock(&priv->lock);
0808 
0809     input_fi = &priv->frame_interval[priv->active_input_pad];
0810     output_fi = &priv->frame_interval[VDIC_SRC_PAD_DIRECT];
0811 
0812     switch (fi->pad) {
0813     case VDIC_SINK_PAD_DIRECT:
0814     case VDIC_SINK_PAD_IDMAC:
0815         /* No limits on valid input frame intervals */
0816         if (fi->interval.numerator == 0 ||
0817             fi->interval.denominator == 0)
0818             fi->interval = priv->frame_interval[fi->pad];
0819         /* Reset output interval */
0820         *output_fi = fi->interval;
0821         if (priv->csi_direct)
0822             output_fi->denominator *= 2;
0823         break;
0824     case VDIC_SRC_PAD_DIRECT:
0825         /*
0826          * frame rate at output pad is double input
0827          * rate when using direct CSI->VDIC pipeline.
0828          *
0829          * TODO: implement VDIC frame skipping
0830          */
0831         fi->interval = *input_fi;
0832         if (priv->csi_direct)
0833             fi->interval.denominator *= 2;
0834         break;
0835     default:
0836         ret = -EINVAL;
0837         goto out;
0838     }
0839 
0840     priv->frame_interval[fi->pad] = fi->interval;
0841 out:
0842     mutex_unlock(&priv->lock);
0843     return ret;
0844 }
0845 
0846 static int vdic_registered(struct v4l2_subdev *sd)
0847 {
0848     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0849     int i, ret;
0850     u32 code;
0851 
0852     for (i = 0; i < VDIC_NUM_PADS; i++) {
0853         code = 0;
0854         if (i != VDIC_SINK_PAD_IDMAC)
0855             imx_media_enum_ipu_formats(&code, 0, PIXFMT_SEL_YUV);
0856 
0857         /* set a default mbus format  */
0858         ret = imx_media_init_mbus_fmt(&priv->format_mbus[i],
0859                           IMX_MEDIA_DEF_PIX_WIDTH,
0860                           IMX_MEDIA_DEF_PIX_HEIGHT, code,
0861                           V4L2_FIELD_NONE, &priv->cc[i]);
0862         if (ret)
0863             return ret;
0864 
0865         /* init default frame interval */
0866         priv->frame_interval[i].numerator = 1;
0867         priv->frame_interval[i].denominator = 30;
0868         if (i == VDIC_SRC_PAD_DIRECT)
0869             priv->frame_interval[i].denominator *= 2;
0870     }
0871 
0872     priv->active_input_pad = VDIC_SINK_PAD_DIRECT;
0873 
0874     return vdic_init_controls(priv);
0875 }
0876 
0877 static void vdic_unregistered(struct v4l2_subdev *sd)
0878 {
0879     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0880 
0881     v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
0882 }
0883 
0884 static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
0885     .init_cfg = imx_media_init_cfg,
0886     .enum_mbus_code = vdic_enum_mbus_code,
0887     .get_fmt = vdic_get_fmt,
0888     .set_fmt = vdic_set_fmt,
0889     .link_validate = vdic_link_validate,
0890 };
0891 
0892 static const struct v4l2_subdev_video_ops vdic_video_ops = {
0893     .g_frame_interval = vdic_g_frame_interval,
0894     .s_frame_interval = vdic_s_frame_interval,
0895     .s_stream = vdic_s_stream,
0896 };
0897 
0898 static const struct media_entity_operations vdic_entity_ops = {
0899     .link_setup = vdic_link_setup,
0900     .link_validate = v4l2_subdev_link_validate,
0901 };
0902 
0903 static const struct v4l2_subdev_ops vdic_subdev_ops = {
0904     .video = &vdic_video_ops,
0905     .pad = &vdic_pad_ops,
0906 };
0907 
0908 static const struct v4l2_subdev_internal_ops vdic_internal_ops = {
0909     .registered = vdic_registered,
0910     .unregistered = vdic_unregistered,
0911 };
0912 
0913 struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev,
0914                         struct device *ipu_dev,
0915                         struct ipu_soc *ipu,
0916                         u32 grp_id)
0917 {
0918     struct vdic_priv *priv;
0919     int i, ret;
0920 
0921     priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL);
0922     if (!priv)
0923         return ERR_PTR(-ENOMEM);
0924 
0925     priv->ipu_dev = ipu_dev;
0926     priv->ipu = ipu;
0927 
0928     v4l2_subdev_init(&priv->sd, &vdic_subdev_ops);
0929     v4l2_set_subdevdata(&priv->sd, priv);
0930     priv->sd.internal_ops = &vdic_internal_ops;
0931     priv->sd.entity.ops = &vdic_entity_ops;
0932     priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
0933     priv->sd.owner = ipu_dev->driver->owner;
0934     priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
0935     priv->sd.grp_id = grp_id;
0936     imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name),
0937                     priv->sd.grp_id, ipu_get_num(ipu));
0938 
0939     mutex_init(&priv->lock);
0940 
0941     for (i = 0; i < VDIC_NUM_PADS; i++)
0942         priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ?
0943             MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
0944 
0945     ret = media_entity_pads_init(&priv->sd.entity, VDIC_NUM_PADS,
0946                      priv->pad);
0947     if (ret)
0948         goto free;
0949 
0950     ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd);
0951     if (ret)
0952         goto free;
0953 
0954     return &priv->sd;
0955 free:
0956     mutex_destroy(&priv->lock);
0957     return ERR_PTR(ret);
0958 }
0959 
0960 int imx_media_vdic_unregister(struct v4l2_subdev *sd)
0961 {
0962     struct vdic_priv *priv = v4l2_get_subdevdata(sd);
0963 
0964     v4l2_info(sd, "Removing\n");
0965 
0966     v4l2_device_unregister_subdev(sd);
0967     mutex_destroy(&priv->lock);
0968     media_entity_cleanup(&sd->entity);
0969 
0970     return 0;
0971 }