diff mbox series

media: imx: vdic: add frame skipping support

Message ID 20190218151304.662-1-gael.portay@collabora.com (mailing list archive)
State New, archived
Headers show
Series media: imx: vdic: add frame skipping support | expand

Commit Message

Gaël PORTAY Feb. 18, 2019, 3:13 p.m. UTC
The VDIC can skip frames, allowing to reduce the frame rate at its
output pad by small fractions.

With this commit, once can specify the frame interval with media-ctl.

media-ctl -V "'ipu1_vdic':2 [fmt: UYVY8_2X8/720x576@1/30 field:interlaced-tb]"

The commit is an adaptation for VDIC of the commit fb30ee795576 ([media]
media: imx: csi: add frame skipping support).

Signed-off-by: Gaël PORTAY <gael.portay@collabora.com>
---
 drivers/gpu/ipu-v3/ipu-common.c            |  28 +++++
 drivers/staging/media/imx/imx-media-vdic.c | 129 +++++++++++++++++++--
 include/video/imx-ipu-v3.h                 |   1 +
 3 files changed, 149 insertions(+), 9 deletions(-)

Comments

Steve Longerbeam Feb. 22, 2019, 1:28 a.m. UTC | #1
Hi Gael,

Some general comments before getting to specifics below.

First, the frame skipping register interface in IPUv3 is very similar 
between CSI/SMFC, VDIC, IC PRPENC, and IC PRPVF. They all support the 
same register frame skipping interface, the only difference being the 
maximum skip set. CSI/SMFC max skip set size is 5 frames, IC PRPENC/VF 
is 4, and VDIC is 11. So It would be preferable to move the frame 
skipping API into imx-media-utils, to make this available to the CSI, 
PRPENC, PRPVF, and VDIC subdevices with less code duplication.

Second, since there is no API change in IPUv3 (only the addition of a 
new exported function), it would be much preferred to split this patch 
up into at least 2 patches, one being pure IPUv3 patch, and the other(s) 
pure imx-media.


On 2/18/19 7:13 AM, Gaël PORTAY wrote:
> The VDIC can skip frames, allowing to reduce the frame rate at its
> output pad by small fractions.
>
> With this commit, once can specify the frame interval with media-ctl.
>
> media-ctl -V "'ipu1_vdic':2 [fmt: UYVY8_2X8/720x576@1/30 field:interlaced-tb]"

The VDIC source pad will only output motion-compensated de-interlaced 
output, so above should be written "field:none".

>
> The commit is an adaptation for VDIC of the commit fb30ee795576 ([media]
> media: imx: csi: add frame skipping support).
>
> Signed-off-by: Gaël PORTAY <gael.portay@collabora.com>
> ---
>   drivers/gpu/ipu-v3/ipu-common.c            |  28 +++++
>   drivers/staging/media/imx/imx-media-vdic.c | 129 +++++++++++++++++++--
>   include/video/imx-ipu-v3.h                 |   1 +
>   3 files changed, 149 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
> index 474b00e19697..19e1e50dc469 100644
> --- a/drivers/gpu/ipu-v3/ipu-common.c
> +++ b/drivers/gpu/ipu-v3/ipu-common.c
> @@ -35,6 +35,12 @@
>   #include <video/imx-ipu-v3.h>
>   #include "ipu-prv.h"
>   
> +/* IPU Register Fields */
> +#define VDI_MAX_RATIO_SKIP_MASK			0x000f0000
> +#define VDI_MAX_RATIO_SKIP_SHIFT		16
> +#define VDI_SKIP_MASK_MASK			0xfff00000
> +#define VDI_SKIP_SHIFT_SHIFT			20
> +
>   static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
>   {
>   	return readl(ipu->cm_reg + offset);
> @@ -267,6 +273,28 @@ int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
>   }
>   EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
>   
> +int ipu_set_skip_vdi(struct ipu_soc *ipu, u32 skip, u32 max_ratio)
> +{
> +	unsigned long flags;
> +	u32 temp;
> +
> +	if (max_ratio > 15)
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&ipu->lock, flags);
> +
> +	temp = ipu_cm_read(ipu, IPU_SKIP);
> +	temp &= ~(VDI_MAX_RATIO_SKIP_MASK | VDI_SKIP_MASK_MASK);
> +	temp |= (max_ratio << VDI_MAX_RATIO_SKIP_SHIFT) |
> +		(skip << VDI_SKIP_SHIFT_SHIFT);
> +	ipu_cm_write(ipu, temp, IPU_SKIP);
> +
> +	spin_unlock_irqrestore(&ipu->lock, flags);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_set_skip_vdi);
> +
>   struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
>   {
>   	struct ipuv3_channel *channel;
> diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
> index 2808662e2597..a12ac4dd5afd 100644
> --- a/drivers/staging/media/imx/imx-media-vdic.c
> +++ b/drivers/staging/media/imx/imx-media-vdic.c
> @@ -9,6 +9,7 @@
>    * (at your option) any later version.
>    */
>   #include <linux/delay.h>
> +#include <linux/gcd.h>
>   #include <linux/interrupt.h>
>   #include <linux/module.h>
>   #include <linux/platform_device.h>
> @@ -68,6 +69,18 @@ struct vdic_pipeline_ops {
>   #define H_ALIGN    1 /* multiple of 2 lines */
>   #define S_ALIGN    1 /* multiple of 2 */
>   
> +/*
> + * struct vdic_skip_desc - VDIC frame skipping descriptor
> + * @keep - number of frames kept per max_ratio frames
> + * @max_ratio - width of skip, written to MAX_RATIO bitfield
> + * @skip - skip pattern written to the SKIP bitfield
> + */
> +struct vdic_skip_desc {
> +	u8 keep;
> +	u8 max_ratio;
> +	u8 skip;
> +};
> +
>   struct vdic_priv {
>   	struct device        *dev;
>   	struct ipu_soc       *ipu;
> @@ -111,6 +124,7 @@ struct vdic_priv {
>   	struct v4l2_mbus_framefmt format_mbus[VDIC_NUM_PADS];
>   	const struct imx_media_pixfmt *cc[VDIC_NUM_PADS];
>   	struct v4l2_fract frame_interval[VDIC_NUM_PADS];
> +	const struct vdic_skip_desc *skip;
>   
>   	/* the video device at IDMAC input pad */
>   	struct imx_media_video_dev *vdev;
> @@ -388,6 +402,7 @@ static int vdic_start(struct vdic_priv *priv)
>   		      infmt->width, infmt->height);
>   	ipu_vdi_set_field_order(priv->vdi, V4L2_STD_UNKNOWN, infmt->field);
>   	ipu_vdi_set_motion(priv->vdi, priv->motion);
> +	ipu_set_skip_vdi(priv->ipu, priv->skip->skip, priv->skip->max_ratio - 1);
>   
>   	ret = priv->ops->setup(priv);
>   	if (ret)
> @@ -558,6 +573,63 @@ static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
>   	return imx_media_enum_ipu_format(&code->code, code->index, CS_SEL_YUV);
>   }
>   
> +static const struct vdic_skip_desc vdic_skip[12] = {
> +	{ 1, 1, 0x00 }, /* Keep all frames */
> +	{ 5, 6, 0x10 }, /* Skip every sixth frame */
> +	{ 4, 5, 0x08 }, /* Skip every fifth frame */
> +	{ 3, 4, 0x04 }, /* Skip every fourth frame */
> +	{ 2, 3, 0x02 }, /* Skip every third frame */
> +	{ 3, 5, 0x0a }, /* Skip frames 1 and 3 of every 5 */
> +	{ 1, 2, 0x01 }, /* Skip every second frame */
> +	{ 2, 5, 0x0b }, /* Keep frames 1 and 4 of every 5 */
> +	{ 1, 3, 0x03 }, /* Keep one in three frames */
> +	{ 1, 4, 0x07 }, /* Keep one in four frames */
> +	{ 1, 5, 0x0f }, /* Keep one in five frames */
> +	{ 1, 6, 0x1f }, /* Keep one in six frames */
> +};
> +
> +static void vdic_apply_skip_interval(const struct vdic_skip_desc *skip,
> +				     struct v4l2_fract *interval)
> +{
> +	unsigned int div;
> +
> +	interval->numerator *= skip->max_ratio;
> +	interval->denominator *= skip->keep;
> +
> +	/* Reduce fraction to lowest terms */
> +	div = gcd(interval->numerator, interval->denominator);
> +	if (div > 1) {
> +		interval->numerator /= div;
> +		interval->denominator /= div;
> +	}
> +}
> +
> +static int vdic_enum_frame_interval(struct v4l2_subdev *sd,
> +				    struct v4l2_subdev_pad_config *cfg,
> +				    struct v4l2_subdev_frame_interval_enum *fie)
> +{
> +	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
> +	struct v4l2_fract *input_fi;
> +	int ret = 0;
> +
> +	if (fie->pad >= VDIC_NUM_PADS ||
> +	    fie->index >= (fie->pad != VDIC_SRC_PAD_DIRECT ?
> +			   1 : ARRAY_SIZE(vdic_skip)))
> +		return -EINVAL;
> +
> +	mutex_lock(&priv->lock);
> +
> +	input_fi = &priv->frame_interval[CSI_SINK_PAD];
> +	fie->interval = *input_fi;
> +
> +	if (fie->pad == VDIC_SRC_PAD_DIRECT)
> +		vdic_apply_skip_interval(&vdic_skip[fie->index],
> +					 &fie->interval);
> +
> +	mutex_unlock(&priv->lock);
> +	return ret;
> +}
> +
>   static int vdic_get_fmt(struct v4l2_subdev *sd,
>   			struct v4l2_subdev_pad_config *cfg,
>   			struct v4l2_subdev_format *sdformat)
> @@ -786,6 +858,48 @@ static int vdic_link_validate(struct v4l2_subdev *sd,
>   	return ret;
>   }
>   
> +/*
> + * Find the skip pattern to produce the output frame interval closest to the
> + * requested one, for the given input frame interval. Updates the output frame
> + * interval to the exact value.
> + */
> +static const struct vdic_skip_desc *vdic_find_best_skip(struct v4l2_fract *in,
> +							struct v4l2_fract *out)
> +{
> +	const struct vdic_skip_desc *skip = &vdic_skip[0], *best_skip = skip;
> +	u32 min_err = UINT_MAX;
> +	u64 want_us;
> +	int i;
> +
> +	/* Default to 1:1 ratio */
> +	if (out->numerator == 0 || out->denominator == 0 ||
> +	    in->numerator == 0 || in->denominator == 0) {
> +		*out = *in;
> +		return best_skip;
> +	}
> +
> +	want_us = div_u64((u64)USEC_PER_SEC * out->numerator, out->denominator);
> +
> +	/* Find the reduction closest to the requested time per frame */
> +	for (i = 0; i < ARRAY_SIZE(vdic_skip); i++, skip++) {
> +		u64 tmp, err;
> +
> +		tmp = div_u64((u64)USEC_PER_SEC * in->numerator *
> +			      skip->max_ratio, in->denominator * skip->keep);
> +
> +		err = abs((s64)tmp - want_us);
> +		if (err < min_err) {
> +			min_err = err;
> +			best_skip = skip;
> +		}
> +	}
> +
> +	*out = *in;
> +	vdic_apply_skip_interval(best_skip, out);
> +
> +	return best_skip;
> +}
> +
>   static int vdic_g_frame_interval(struct v4l2_subdev *sd,
>   				struct v4l2_subdev_frame_interval *fi)
>   {
> @@ -826,17 +940,10 @@ static int vdic_s_frame_interval(struct v4l2_subdev *sd,
>   		*output_fi = fi->interval;
>   		if (priv->csi_direct)
>   			output_fi->denominator *= 2;
> +		priv->skip = &vdic_skip[0];
>   		break;
>   	case VDIC_SRC_PAD_DIRECT:
> -		/*
> -		 * frame rate at output pad is double input
> -		 * rate when using direct CSI->VDIC pipeline.
> -		 *
> -		 * TODO: implement VDIC frame skipping
> -		 */
> -		fi->interval = *input_fi;
> -		if (priv->csi_direct)
> -			fi->interval.denominator *= 2;
> +		priv->skip = vdic_find_best_skip(output_fi, &fi->interval);

According to the i.MX6 reference manual, "Skipping is relevant only if 
the source to the VDIC is coming from the CSI". So VDIC frame skipping 
should only be allowed if priv->csi_direct is true.

Steve

>   		break;
>   	default:
>   		ret = -EINVAL;
> @@ -883,6 +990,9 @@ static int vdic_registered(struct v4l2_subdev *sd)
>   			priv->frame_interval[i].denominator *= 2;
>   	}
>   
> +	/* disable frame skipping */
> +	priv->skip = &vdic_skip[0];
> +
>   	priv->active_input_pad = VDIC_SINK_PAD_DIRECT;
>   
>   	ret = vdic_init_controls(priv);
> @@ -906,6 +1016,7 @@ static void vdic_unregistered(struct v4l2_subdev *sd)
>   static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
>   	.init_cfg = imx_media_init_cfg,
>   	.enum_mbus_code = vdic_enum_mbus_code,
> +	.enum_frame_interval = vdic_enum_frame_interval,
>   	.get_fmt = vdic_get_fmt,
>   	.set_fmt = vdic_set_fmt,
>   	.link_validate = vdic_link_validate,
> diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
> index c887f4bee5f8..026c4340a8da 100644
> --- a/include/video/imx-ipu-v3.h
> +++ b/include/video/imx-ipu-v3.h
> @@ -203,6 +203,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
>    * IPU Common functions
>    */
>   int ipu_get_num(struct ipu_soc *ipu);
> +int ipu_set_skip_vdi(struct ipu_soc *csi, u32 skip, u32 max_ratio);
>   void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
>   void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
>   void ipu_dump(struct ipu_soc *ipu);
diff mbox series

Patch

diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index 474b00e19697..19e1e50dc469 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -35,6 +35,12 @@ 
 #include <video/imx-ipu-v3.h>
 #include "ipu-prv.h"
 
+/* IPU Register Fields */
+#define VDI_MAX_RATIO_SKIP_MASK			0x000f0000
+#define VDI_MAX_RATIO_SKIP_SHIFT		16
+#define VDI_SKIP_MASK_MASK			0xfff00000
+#define VDI_SKIP_SHIFT_SHIFT			20
+
 static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
 {
 	return readl(ipu->cm_reg + offset);
@@ -267,6 +273,28 @@  int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
 }
 EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
 
+int ipu_set_skip_vdi(struct ipu_soc *ipu, u32 skip, u32 max_ratio)
+{
+	unsigned long flags;
+	u32 temp;
+
+	if (max_ratio > 15)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	temp = ipu_cm_read(ipu, IPU_SKIP);
+	temp &= ~(VDI_MAX_RATIO_SKIP_MASK | VDI_SKIP_MASK_MASK);
+	temp |= (max_ratio << VDI_MAX_RATIO_SKIP_SHIFT) |
+		(skip << VDI_SKIP_SHIFT_SHIFT);
+	ipu_cm_write(ipu, temp, IPU_SKIP);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_set_skip_vdi);
+
 struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
 {
 	struct ipuv3_channel *channel;
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index 2808662e2597..a12ac4dd5afd 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -9,6 +9,7 @@ 
  * (at your option) any later version.
  */
 #include <linux/delay.h>
+#include <linux/gcd.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -68,6 +69,18 @@  struct vdic_pipeline_ops {
 #define H_ALIGN    1 /* multiple of 2 lines */
 #define S_ALIGN    1 /* multiple of 2 */
 
+/*
+ * struct vdic_skip_desc - VDIC frame skipping descriptor
+ * @keep - number of frames kept per max_ratio frames
+ * @max_ratio - width of skip, written to MAX_RATIO bitfield
+ * @skip - skip pattern written to the SKIP bitfield
+ */
+struct vdic_skip_desc {
+	u8 keep;
+	u8 max_ratio;
+	u8 skip;
+};
+
 struct vdic_priv {
 	struct device        *dev;
 	struct ipu_soc       *ipu;
@@ -111,6 +124,7 @@  struct vdic_priv {
 	struct v4l2_mbus_framefmt format_mbus[VDIC_NUM_PADS];
 	const struct imx_media_pixfmt *cc[VDIC_NUM_PADS];
 	struct v4l2_fract frame_interval[VDIC_NUM_PADS];
+	const struct vdic_skip_desc *skip;
 
 	/* the video device at IDMAC input pad */
 	struct imx_media_video_dev *vdev;
@@ -388,6 +402,7 @@  static int vdic_start(struct vdic_priv *priv)
 		      infmt->width, infmt->height);
 	ipu_vdi_set_field_order(priv->vdi, V4L2_STD_UNKNOWN, infmt->field);
 	ipu_vdi_set_motion(priv->vdi, priv->motion);
+	ipu_set_skip_vdi(priv->ipu, priv->skip->skip, priv->skip->max_ratio - 1);
 
 	ret = priv->ops->setup(priv);
 	if (ret)
@@ -558,6 +573,63 @@  static int vdic_enum_mbus_code(struct v4l2_subdev *sd,
 	return imx_media_enum_ipu_format(&code->code, code->index, CS_SEL_YUV);
 }
 
+static const struct vdic_skip_desc vdic_skip[12] = {
+	{ 1, 1, 0x00 }, /* Keep all frames */
+	{ 5, 6, 0x10 }, /* Skip every sixth frame */
+	{ 4, 5, 0x08 }, /* Skip every fifth frame */
+	{ 3, 4, 0x04 }, /* Skip every fourth frame */
+	{ 2, 3, 0x02 }, /* Skip every third frame */
+	{ 3, 5, 0x0a }, /* Skip frames 1 and 3 of every 5 */
+	{ 1, 2, 0x01 }, /* Skip every second frame */
+	{ 2, 5, 0x0b }, /* Keep frames 1 and 4 of every 5 */
+	{ 1, 3, 0x03 }, /* Keep one in three frames */
+	{ 1, 4, 0x07 }, /* Keep one in four frames */
+	{ 1, 5, 0x0f }, /* Keep one in five frames */
+	{ 1, 6, 0x1f }, /* Keep one in six frames */
+};
+
+static void vdic_apply_skip_interval(const struct vdic_skip_desc *skip,
+				     struct v4l2_fract *interval)
+{
+	unsigned int div;
+
+	interval->numerator *= skip->max_ratio;
+	interval->denominator *= skip->keep;
+
+	/* Reduce fraction to lowest terms */
+	div = gcd(interval->numerator, interval->denominator);
+	if (div > 1) {
+		interval->numerator /= div;
+		interval->denominator /= div;
+	}
+}
+
+static int vdic_enum_frame_interval(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_frame_interval_enum *fie)
+{
+	struct vdic_priv *priv = v4l2_get_subdevdata(sd);
+	struct v4l2_fract *input_fi;
+	int ret = 0;
+
+	if (fie->pad >= VDIC_NUM_PADS ||
+	    fie->index >= (fie->pad != VDIC_SRC_PAD_DIRECT ?
+			   1 : ARRAY_SIZE(vdic_skip)))
+		return -EINVAL;
+
+	mutex_lock(&priv->lock);
+
+	input_fi = &priv->frame_interval[CSI_SINK_PAD];
+	fie->interval = *input_fi;
+
+	if (fie->pad == VDIC_SRC_PAD_DIRECT)
+		vdic_apply_skip_interval(&vdic_skip[fie->index],
+					 &fie->interval);
+
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
 static int vdic_get_fmt(struct v4l2_subdev *sd,
 			struct v4l2_subdev_pad_config *cfg,
 			struct v4l2_subdev_format *sdformat)
@@ -786,6 +858,48 @@  static int vdic_link_validate(struct v4l2_subdev *sd,
 	return ret;
 }
 
+/*
+ * Find the skip pattern to produce the output frame interval closest to the
+ * requested one, for the given input frame interval. Updates the output frame
+ * interval to the exact value.
+ */
+static const struct vdic_skip_desc *vdic_find_best_skip(struct v4l2_fract *in,
+							struct v4l2_fract *out)
+{
+	const struct vdic_skip_desc *skip = &vdic_skip[0], *best_skip = skip;
+	u32 min_err = UINT_MAX;
+	u64 want_us;
+	int i;
+
+	/* Default to 1:1 ratio */
+	if (out->numerator == 0 || out->denominator == 0 ||
+	    in->numerator == 0 || in->denominator == 0) {
+		*out = *in;
+		return best_skip;
+	}
+
+	want_us = div_u64((u64)USEC_PER_SEC * out->numerator, out->denominator);
+
+	/* Find the reduction closest to the requested time per frame */
+	for (i = 0; i < ARRAY_SIZE(vdic_skip); i++, skip++) {
+		u64 tmp, err;
+
+		tmp = div_u64((u64)USEC_PER_SEC * in->numerator *
+			      skip->max_ratio, in->denominator * skip->keep);
+
+		err = abs((s64)tmp - want_us);
+		if (err < min_err) {
+			min_err = err;
+			best_skip = skip;
+		}
+	}
+
+	*out = *in;
+	vdic_apply_skip_interval(best_skip, out);
+
+	return best_skip;
+}
+
 static int vdic_g_frame_interval(struct v4l2_subdev *sd,
 				struct v4l2_subdev_frame_interval *fi)
 {
@@ -826,17 +940,10 @@  static int vdic_s_frame_interval(struct v4l2_subdev *sd,
 		*output_fi = fi->interval;
 		if (priv->csi_direct)
 			output_fi->denominator *= 2;
+		priv->skip = &vdic_skip[0];
 		break;
 	case VDIC_SRC_PAD_DIRECT:
-		/*
-		 * frame rate at output pad is double input
-		 * rate when using direct CSI->VDIC pipeline.
-		 *
-		 * TODO: implement VDIC frame skipping
-		 */
-		fi->interval = *input_fi;
-		if (priv->csi_direct)
-			fi->interval.denominator *= 2;
+		priv->skip = vdic_find_best_skip(output_fi, &fi->interval);
 		break;
 	default:
 		ret = -EINVAL;
@@ -883,6 +990,9 @@  static int vdic_registered(struct v4l2_subdev *sd)
 			priv->frame_interval[i].denominator *= 2;
 	}
 
+	/* disable frame skipping */
+	priv->skip = &vdic_skip[0];
+
 	priv->active_input_pad = VDIC_SINK_PAD_DIRECT;
 
 	ret = vdic_init_controls(priv);
@@ -906,6 +1016,7 @@  static void vdic_unregistered(struct v4l2_subdev *sd)
 static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
 	.init_cfg = imx_media_init_cfg,
 	.enum_mbus_code = vdic_enum_mbus_code,
+	.enum_frame_interval = vdic_enum_frame_interval,
 	.get_fmt = vdic_get_fmt,
 	.set_fmt = vdic_set_fmt,
 	.link_validate = vdic_link_validate,
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index c887f4bee5f8..026c4340a8da 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -203,6 +203,7 @@  int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
  * IPU Common functions
  */
 int ipu_get_num(struct ipu_soc *ipu);
+int ipu_set_skip_vdi(struct ipu_soc *csi, u32 skip, u32 max_ratio);
 void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
 void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
 void ipu_dump(struct ipu_soc *ipu);