0001
0002
0003
0004
0005
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
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
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
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
0057 #define H_ALIGN 1
0058 #define S_ALIGN 1
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
0068 struct mutex lock;
0069
0070
0071 struct ipu_vdi *vdi;
0072
0073 int active_input_pad;
0074
0075 struct ipuv3_channel *vdi_in_ch_p;
0076 struct ipuv3_channel *vdi_in_ch;
0077 struct ipuv3_channel *vdi_in_ch_n;
0078
0079
0080 struct vdic_pipeline_ops *ops;
0081
0082
0083 struct imx_media_buffer *curr_in_buf;
0084 struct imx_media_buffer *prev_in_buf;
0085
0086
0087
0088
0089
0090 u32 fieldtype;
0091 u32 in_stride;
0092 u32 field_size;
0093
0094
0095 struct media_entity *src;
0096
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
0104 struct imx_media_video_dev *vdev;
0105
0106 bool csi_direct;
0107
0108
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
0185
0186
0187
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
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
0223
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
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
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
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
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
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
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
0374
0375
0376
0377
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
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
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
0499
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
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
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
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
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
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
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
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
0816 if (fi->interval.numerator == 0 ||
0817 fi->interval.denominator == 0)
0818 fi->interval = priv->frame_interval[fi->pad];
0819
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
0827
0828
0829
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
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
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 }