diff mbox series

[v4,04/11] media: s5p-mfc: Add YV12 and I420 multiplanar format support

Message ID 20231025102216.50480-5-aakarsh.jain@samsung.com
State Superseded
Headers show
Series Add MFC V12 support | expand

Commit Message

Aakarsh Jain Oct. 25, 2023, 10:22 a.m. UTC
YV12 and I420 format (3-plane) support is added. Stride information is
added to all formats and planes since it is necessary for YV12/I420
which are different from width.

Cc: linux-fsd@tesla.com
Signed-off-by: Smitha T Murthy <smithatmurthy@gmail.com>
Signed-off-by: Aakarsh Jain <aakarsh.jain@samsung.com>
---
 .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   2 +
 .../platform/samsung/s5p-mfc/regs-mfc-v7.h    |   1 +
 .../platform/samsung/s5p-mfc/regs-mfc-v8.h    |   3 +
 .../platform/samsung/s5p-mfc/s5p_mfc_common.h |   4 +
 .../platform/samsung/s5p-mfc/s5p_mfc_dec.c    |  45 ++++-
 .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    |  86 +++++++--
 .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   6 +-
 .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c |  12 +-
 .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 168 +++++++++++++++---
 9 files changed, 281 insertions(+), 46 deletions(-)

Comments

Hans Verkuil Nov. 22, 2023, 3:40 p.m. UTC | #1
On 25/10/2023 12:22, Aakarsh Jain wrote:
> YV12 and I420 format (3-plane) support is added. Stride information is
> added to all formats and planes since it is necessary for YV12/I420
> which are different from width.
> 
> Cc: linux-fsd@tesla.com
> Signed-off-by: Smitha T Murthy <smithatmurthy@gmail.com>
> Signed-off-by: Aakarsh Jain <aakarsh.jain@samsung.com>
> ---
>  .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   2 +
>  .../platform/samsung/s5p-mfc/regs-mfc-v7.h    |   1 +
>  .../platform/samsung/s5p-mfc/regs-mfc-v8.h    |   3 +
>  .../platform/samsung/s5p-mfc/s5p_mfc_common.h |   4 +
>  .../platform/samsung/s5p-mfc/s5p_mfc_dec.c    |  45 ++++-
>  .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    |  86 +++++++--
>  .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   6 +-
>  .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c |  12 +-
>  .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 168 +++++++++++++++---
>  9 files changed, 281 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> index 6c68a45082d0..70464f47c1f9 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> @@ -26,6 +26,8 @@
>  #define MFC_VERSION_V12			0xC0
>  #define MFC_NUM_PORTS_V12		1
>  #define S5P_FIMV_CODEC_VP9_ENC		27
> +#define MFC_CHROMA_PAD_BYTES_V12        256
> +#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V12 256
>  
>  /* Encoder buffer size for MFCv12 */
>  #define ENC_V120_BASE_SIZE(x, y) \
> diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> index 4a7adfdaa359..50f9bf0603c1 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> @@ -24,6 +24,7 @@
>  
>  #define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7		0xfa70
>  #define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7	0xfa74
> +#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7		0xfa78
>  
>  #define S5P_FIMV_E_VP8_OPTIONS_V7			0xfdb0
>  #define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7		0xfdb4
> diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> index 162e3c7e920f..0ef9eb2dff22 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> @@ -17,13 +17,16 @@
>  #define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8	0xf108
>  #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8	0xf144
>  #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8	0xf148
> +#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8	0xf14C
>  #define S5P_FIMV_D_MV_BUFFER_SIZE_V8		0xf150
>  
>  #define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8	0xf138
>  #define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8	0xf13c
> +#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8	0xf140
>  
>  #define S5P_FIMV_D_FIRST_PLANE_DPB_V8		0xf160
>  #define S5P_FIMV_D_SECOND_PLANE_DPB_V8		0xf260
> +#define S5P_FIMV_D_THIRD_PLANE_DPB_V8		0xf360
>  #define S5P_FIMV_D_MV_BUFFER_V8			0xf460
>  
>  #define S5P_FIMV_D_NUM_MV_V8			0xf134
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> index dd2e9f7704ab..9a39cccfe002 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> @@ -56,6 +56,7 @@
>  #define MFC_NO_INSTANCE_SET	-1
>  #define MFC_ENC_CAP_PLANE_COUNT	1
>  #define MFC_ENC_OUT_PLANE_COUNT	2
> +#define VB2_MAX_PLANE_COUNT	3
>  #define STUFF_BYTE		4
>  #define MFC_MAX_CTRLS		128
>  
> @@ -181,6 +182,7 @@ struct s5p_mfc_buf {
>  		struct {
>  			size_t luma;
>  			size_t chroma;
> +			size_t chroma_1;
>  		} raw;
>  		size_t stream;
>  	} cookie;
> @@ -657,6 +659,7 @@ struct s5p_mfc_ctx {
>  
>  	int luma_size;
>  	int chroma_size;
> +	int chroma_size_1;
>  	int mv_size;
>  
>  	unsigned long consumed_stream;
> @@ -722,6 +725,7 @@ struct s5p_mfc_ctx {
>  	size_t scratch_buf_size;
>  	int is_10bit;
>  	int is_422;
> +	int stride[VB2_MAX_PLANE_COUNT];
>  };
>  
>  /*
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> index e219cbcd86d5..317f796fffa1 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> @@ -56,6 +56,20 @@ static struct s5p_mfc_fmt formats[] = {
>  		.num_planes	= 2,
>  		.versions	= MFC_V6PLUS_BITS,
>  	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT,
> +	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT
> +	},
>  	{
>  		.fourcc		= V4L2_PIX_FMT_H264,
>  		.codec_mode	= S5P_MFC_CODEC_H264_DEC,
> @@ -359,10 +373,15 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  		/* Set pixelformat to the format in which MFC
>  		   outputs the decoded frame */
>  		pix_mp->pixelformat = ctx->dst_fmt->fourcc;
> -		pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> +		pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
>  		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> -		pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> +		pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
>  		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> +			pix_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
> +		}
>  	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
>  		/* This is run on OUTPUT
>  		   The buffer contains compressed image
> @@ -937,6 +956,9 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
>  		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
>  		/* Output plane count is 2 - one for Y and one for CbCr */
>  		*plane_count = 2;
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)

These misalignments produce a lot of checkpatch warnings.

Make sure you run your patch series through 'checkpatch.pl --strict'!

Regards,

	Hans

> +			*plane_count = 3;
>  		/* Setup buffer count */
>  		if (*buf_count < ctx->pb_count)
>  			*buf_count = ctx->pb_count;
> @@ -955,12 +977,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
>  	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
>  		psize[0] = ctx->luma_size;
>  		psize[1] = ctx->chroma_size;
> -
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			psize[2] = ctx->chroma_size_1;
>  		if (IS_MFCV6_PLUS(dev))
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
>  		else
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
>  		alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
>  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
>  		   ctx->state == MFCINST_INIT) {
>  		psize[0] = ctx->dec_src_buf_size;
> @@ -994,12 +1021,24 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
>  			mfc_err("Plane buffer (CAPTURE) is too small\n");
>  			return -EINVAL;
>  		}
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
> +				mfc_err("Plane buffer (CAPTURE) is too small\n");
> +				return -EINVAL;
> +			}
> +		}
>  		i = vb->index;
>  		ctx->dst_bufs[i].b = vbuf;
>  		ctx->dst_bufs[i].cookie.raw.luma =
>  					vb2_dma_contig_plane_dma_addr(vb, 0);
>  		ctx->dst_bufs[i].cookie.raw.chroma =
>  					vb2_dma_contig_plane_dma_addr(vb, 1);
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			ctx->dst_bufs[i].cookie.raw.chroma_1 =
> +					vb2_dma_contig_plane_dma_addr(vb, 2);
> +		}
>  		ctx->dst_bufs_cnt++;
>  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
>  		if (IS_ERR_OR_NULL(ERR_PTR(
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> index e4d6e7c117b5..0eec04eb3ef3 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> @@ -59,6 +59,20 @@ static struct s5p_mfc_fmt formats[] = {
>  		.num_planes	= 2,
>  		.versions	= MFC_V6PLUS_BITS,
>  	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT,
> +	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT,
> +	},
>  	{
>  		.fourcc		= V4L2_PIX_FMT_H264,
>  		.codec_mode	= S5P_MFC_CODEC_H264_ENC,
> @@ -1193,14 +1207,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	struct s5p_mfc_buf *dst_mb;
>  	struct s5p_mfc_buf *src_mb;
> -	unsigned long src_y_addr, src_c_addr, dst_addr;
> +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
>  	unsigned int dst_size;
>  
>  	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
>  	src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
>  	src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
> +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		src_c_1_addr =
> +			vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 2);
> +	else
> +		src_c_1_addr = 0;
>  	s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
> -							src_y_addr, src_c_addr);
> +					src_y_addr, src_c_addr, src_c_1_addr);
>  
>  	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
>  	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
> @@ -1215,8 +1235,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	struct s5p_mfc_buf *mb_entry;
> -	unsigned long enc_y_addr = 0, enc_c_addr = 0;
> -	unsigned long mb_y_addr, mb_c_addr;
> +	unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0;
> +	unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr;
>  	int slice_type;
>  	unsigned int strm_size;
>  	bool src_ready;
> @@ -1229,14 +1249,21 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
>  		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
>  	if (slice_type >= 0) {
>  		s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
> -				&enc_y_addr, &enc_c_addr);
> +				&enc_y_addr, &enc_c_addr, &enc_c_1_addr);
>  		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
>  			mb_y_addr = vb2_dma_contig_plane_dma_addr(
>  					&mb_entry->b->vb2_buf, 0);
>  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
>  					&mb_entry->b->vb2_buf, 1);
> -			if ((enc_y_addr == mb_y_addr) &&
> -						(enc_c_addr == mb_c_addr)) {
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				mb_c_1_addr = vb2_dma_contig_plane_dma_addr
> +						(&mb_entry->b->vb2_buf, 2);
> +			else
> +				mb_c_1_addr = 0;
> +			if ((enc_y_addr == mb_y_addr)
> +					&& (enc_c_addr == mb_c_addr)
> +					&& (enc_c_1_addr == mb_c_1_addr)) {
>  				list_del(&mb_entry->list);
>  				ctx->src_queue_cnt--;
>  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> @@ -1249,8 +1276,15 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
>  					&mb_entry->b->vb2_buf, 0);
>  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
>  					&mb_entry->b->vb2_buf, 1);
> -			if ((enc_y_addr == mb_y_addr) &&
> -						(enc_c_addr == mb_c_addr)) {
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				mb_c_1_addr = vb2_dma_contig_plane_dma_addr(
> +						&mb_entry->b->vb2_buf, 2);
> +			else
> +				mb_c_1_addr = 0;
> +			if ((enc_y_addr == mb_y_addr)
> +					&& (enc_c_addr == mb_c_addr)
> +					&& (enc_c_1_addr == mb_c_1_addr)) {
>  				list_del(&mb_entry->list);
>  				ctx->ref_queue_cnt--;
>  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> @@ -1381,10 +1415,15 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  		pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
>  		pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
>  
> -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
>  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
>  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
> +		}
>  	} else {
>  		mfc_err("invalid buf type\n");
>  		return -EINVAL;
> @@ -1468,9 +1507,14 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  
>  		s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
>  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
>  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
> +		}
>  
>  		ctx->src_bufs_cnt = 0;
>  		ctx->output_state = QUEUE_FREE;
> @@ -2414,10 +2458,16 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
>  
>  		psize[0] = ctx->luma_size;
>  		psize[1] = ctx->chroma_size;
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			psize[2] = ctx->chroma_size_1;
>  
>  		if (IS_MFCV6_PLUS(dev)) {
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
>  			alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
>  		} else {
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
>  			alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
> @@ -2456,6 +2506,10 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
>  					vb2_dma_contig_plane_dma_addr(vb, 0);
>  		ctx->src_bufs[i].cookie.raw.chroma =
>  					vb2_dma_contig_plane_dma_addr(vb, 1);
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			ctx->src_bufs[i].cookie.raw.chroma_1 =
> +					vb2_dma_contig_plane_dma_addr(vb, 2);
>  		ctx->src_bufs_cnt++;
>  	} else {
>  		mfc_err("invalid queue type: %d\n", vq->type);
> @@ -2493,6 +2547,12 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
>  			mfc_err("plane size is too small for output\n");
>  			return -EINVAL;
>  		}
> +		if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +		     ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) &&
> +		    (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) {
> +			mfc_err("plane size is too small for output\n");
> +			return -EINVAL;
> +		}
>  	} else {
>  		mfc_err("invalid queue type: %d\n", vq->type);
>  		return -EINVAL;
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> index 87ac56756a16..7c5e851c8191 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> @@ -293,9 +293,11 @@ struct s5p_mfc_hw_ops {
>  	int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
>  			unsigned long addr, unsigned int size);
>  	void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> -			unsigned long y_addr, unsigned long c_addr);
> +			unsigned long y_addr, unsigned long c_addr,
> +			unsigned long c_1_addr);
>  	void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> -			unsigned long *y_addr, unsigned long *c_addr);
> +			unsigned long *y_addr, unsigned long *c_addr,
> +			unsigned long *c_1_addr);
>  	void (*try_run)(struct s5p_mfc_dev *dev);
>  	void (*clear_int_flags)(struct s5p_mfc_dev *dev);
>  	int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev);
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> index 28a06dc343fd..fcfaf125a5a1 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> @@ -516,7 +516,8 @@ static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
>  }
>  
>  static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> -		unsigned long y_addr, unsigned long c_addr)
> +		unsigned long y_addr, unsigned long c_addr,
> +		unsigned long c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  
> @@ -525,7 +526,8 @@ static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
>  }
>  
>  static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> -		unsigned long *y_addr, unsigned long *c_addr)
> +		unsigned long *y_addr, unsigned long *c_addr,
> +		unsigned long *c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  
> @@ -1210,7 +1212,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  	if (list_empty(&ctx->src_queue)) {
>  		/* send null frame */
>  		s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX],
> -						dev->dma_base[BANK_R_CTX]);
> +						dev->dma_base[BANK_R_CTX], 0);
>  		src_mb = NULL;
>  	} else {
>  		src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
> @@ -1220,7 +1222,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  			/* send null frame */
>  			s5p_mfc_set_enc_frame_buffer_v5(ctx,
>  						dev->dma_base[BANK_R_CTX],
> -						dev->dma_base[BANK_R_CTX]);
> +						dev->dma_base[BANK_R_CTX], 0);
>  			ctx->state = MFCINST_FINISHING;
>  		} else {
>  			src_y_addr = vb2_dma_contig_plane_dma_addr(
> @@ -1228,7 +1230,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  			src_c_addr = vb2_dma_contig_plane_dma_addr(
>  					&src_mb->b->vb2_buf, 1);
>  			s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr,
> -								src_c_addr);
> +								src_c_addr, 0);
>  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
>  				ctx->state = MFCINST_FINISHING;
>  		}
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> index fb3f0718821d..e579c765e902 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> @@ -494,16 +494,43 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
>  	ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6);
> +	ctx->chroma_size_1 = 0;
>  	mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
>  			"buffer dimensions: %dx%d\n", ctx->img_width,
>  			ctx->img_height, ctx->buf_width, ctx->buf_height);
>  
> -	ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
> -	ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
> +	switch (ctx->dst_fmt->fourcc) {
> +	case V4L2_PIX_FMT_NV12M:
> +	case V4L2_PIX_FMT_NV21M:
> +		ctx->stride[0] = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->stride[1] = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> +		ctx->chroma_size = calc_plane(ctx->stride[1],
> +					(ctx->img_height / 2));
> +		break;
> +	case V4L2_PIX_FMT_YUV420M:
> +	case V4L2_PIX_FMT_YVU420M:
> +		ctx->stride[0] = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->stride[1] = ALIGN(ctx->img_width / 2,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->stride[2] = ALIGN(ctx->img_width / 2,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> +		ctx->chroma_size = calc_plane(ctx->stride[1],
> +					(ctx->img_height / 2));
> +		ctx->chroma_size_1 = calc_plane(ctx->stride[2],
> +					(ctx->img_height / 2));
> +		break;
> +	}
> +
>  	if (IS_MFCV8_PLUS(ctx->dev)) {
>  		/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
>  		ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
>  		ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> +		ctx->chroma_size_1 += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
>  	}
>  
>  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
> @@ -534,15 +561,53 @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
>  	mb_width = MB_WIDTH(ctx->img_width);
>  	mb_height = MB_HEIGHT(ctx->img_height);
>  
> -	ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
> -	ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
> -	ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
> -
> -	/* MFCv7 needs pad bytes for Luma and Chroma */
> -	if (IS_MFCV7_PLUS(ctx->dev)) {
> +	if (IS_MFCV12(ctx->dev)) {
> +		switch (ctx->src_fmt->fourcc) {
> +		case V4L2_PIX_FMT_NV12M:
> +		case V4L2_PIX_FMT_NV21M:
> +			ctx->stride[0] = ALIGN(ctx->img_width,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->stride[1] = ALIGN(ctx->img_width,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->luma_size = ctx->stride[0] *
> +						ALIGN(ctx->img_height, 16);
> +			ctx->chroma_size =  ctx->stride[0] *
> +						ALIGN(ctx->img_height / 2, 16);
> +			break;
> +		case V4L2_PIX_FMT_YUV420M:
> +		case V4L2_PIX_FMT_YVU420M:
> +			ctx->stride[0] = ALIGN(ctx->img_width,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->stride[1] = ALIGN(ctx->img_width / 2,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->stride[2] = ALIGN(ctx->img_width / 2,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->luma_size = ctx->stride[0] *
> +						ALIGN(ctx->img_height, 16);
> +			ctx->chroma_size =  ctx->stride[1] *
> +						ALIGN(ctx->img_height / 2, 16);
> +			ctx->chroma_size_1 =  ctx->stride[2] *
> +						ALIGN(ctx->img_height / 2, 16);
> +			break;
> +		}
>  		ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> -		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
> +		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V12;
> +		ctx->chroma_size_1 += MFC_CHROMA_PAD_BYTES_V12;
> +	} else {
> +		ctx->buf_width = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12M_HALIGN_V6);
> +		ctx->stride[0] = ctx->buf_width;
> +		ctx->stride[1] = ctx->buf_width;
> +		ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
> +		ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
> +		ctx->chroma_size_1 = 0;
> +		/* MFCv7 needs pad bytes for Luma and Chroma */
> +		if (IS_MFCV7_PLUS(ctx->dev)) {
> +			ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> +			ctx->chroma_size += MFC_LUMA_PAD_BYTES_V7;
> +		}
>  	}
> +
>  }
>  
>  /* Set registers for decoding stream buffer */
> @@ -588,15 +653,21 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
>  	writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
>  	writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
>  	writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
> -
> +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +			ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		writel(ctx->chroma_size_1, mfc_regs->d_third_plane_dpb_size);
>  	writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
>  	writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
>  
>  	if (IS_MFCV8_PLUS(dev)) {
> -		writel(ctx->img_width,
> +		writel(ctx->stride[0],
>  			mfc_regs->d_first_plane_dpb_stride_size);
> -		writel(ctx->img_width,
> +		writel(ctx->stride[1],
>  			mfc_regs->d_second_plane_dpb_stride_size);
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			writel(ctx->stride[2],
> +				mfc_regs->d_third_plane_dpb_stride_size);
>  	}
>  
>  	buf_addr1 += ctx->scratch_buf_size;
> @@ -625,6 +696,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
>  					ctx->dst_bufs[i].cookie.raw.chroma);
>  		writel(ctx->dst_bufs[i].cookie.raw.chroma,
>  				mfc_regs->d_second_plane_dpb + i * 4);
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			mfc_debug(2, "\tChroma_1 %d: %zx\n", i,
> +					ctx->dst_bufs[i].cookie.raw.chroma_1);
> +			writel(ctx->dst_bufs[i].cookie.raw.chroma_1,
> +					mfc_regs->d_third_plane_dpb + i * 4);
> +		}
>  	}
>  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
>  			ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC ||
> @@ -683,20 +761,24 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
>  }
>  
>  static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> -		unsigned long y_addr, unsigned long c_addr)
> +		unsigned long y_addr, unsigned long c_addr,
> +		unsigned long c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
>  
>  	writel(y_addr, mfc_regs->e_source_first_plane_addr);
>  	writel(c_addr, mfc_regs->e_source_second_plane_addr);
> +	writel(c_1_addr, mfc_regs->e_source_third_plane_addr);
>  
>  	mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
>  	mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
> +	mfc_debug(2, "enc src cr buf addr: 0x%08lx\n", c_1_addr);
>  }
>  
>  static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> -		unsigned long *y_addr, unsigned long *c_addr)
> +		unsigned long *y_addr, unsigned long *c_addr,
> +		unsigned long *c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
> @@ -704,12 +786,17 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
>  
>  	*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
>  	*c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
> +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		*c_1_addr = readl(mfc_regs->e_encoded_source_third_plane_addr);
> +	else
> +		*c_1_addr = 0;
>  
>  	enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
>  	enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
>  
>  	mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n", enc_recon_y_addr, *y_addr);
> -	mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
> +	mfc_debug(2, "recon c addr: 0x%08lx c_addr: 0x%08lx\n", enc_recon_c_addr, *c_addr);
>  }
>  
>  /* Set encoding ref & codec buffer */
> @@ -886,6 +973,20 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
>  		writel(reg, mfc_regs->e_enc_options);
>  		/* 0: NV12(CbCr), 1: NV21(CrCb) */
>  		writel(0x0, mfc_regs->pixel_format);
> +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +		/* 0: Linear, 1: 2D tiled*/
> +		reg = readl(mfc_regs->e_enc_options);
> +		reg &= ~(0x1 << 7);
> +		writel(reg, mfc_regs->e_enc_options);
> +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> +		writel(0x2, mfc_regs->pixel_format);
> +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M) {
> +		/* 0: Linear, 1: 2D tiled*/
> +		reg = readl(mfc_regs->e_enc_options);
> +		reg &= ~(0x1 << 7);
> +		writel(reg, mfc_regs->e_enc_options);
> +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> +		writel(0x3, mfc_regs->pixel_format);
>  	}
>  
>  	/* memory structure recon. frame */
> @@ -1696,8 +1797,12 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
>  	else
>  		writel(reg, mfc_regs->d_dec_options);
>  
> -	/* 0: NV12(CbCr), 1: NV21(CrCb) */
> -	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
> +	/* 0: NV12(CbCr), 1: NV21(CrCb), 2: YV12(CrCb), 3: I420(CbCr) */
> +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M)
> +		writel(0x3, mfc_regs->pixel_format);
> +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		writel(0x2, mfc_regs->pixel_format);
> +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
>  		writel(0x1, mfc_regs->pixel_format);
>  	else
>  		writel(0x0, mfc_regs->pixel_format);
> @@ -1781,8 +1886,12 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
>  
>  	/* Set stride lengths for v7 & above */
>  	if (IS_MFCV7_PLUS(dev)) {
> -		writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
> -		writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
> +		writel(ctx->stride[0], mfc_regs->e_source_first_plane_stride);
> +		writel(ctx->stride[1], mfc_regs->e_source_second_plane_stride);
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			writel(ctx->stride[2],
> +					mfc_regs->e_source_third_plane_stride);
>  	}
>  
>  	writel(ctx->inst_no, mfc_regs->instance_id);
> @@ -1891,7 +2000,7 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	struct s5p_mfc_buf *dst_mb;
>  	struct s5p_mfc_buf *src_mb;
> -	unsigned long src_y_addr, src_c_addr, dst_addr;
> +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
>  	/*
>  	unsigned int src_y_size, src_c_size;
>  	*/
> @@ -1909,22 +2018,29 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  
>  	if (list_empty(&ctx->src_queue)) {
>  		/* send null frame */
> -		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> +		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
>  		src_mb = NULL;
>  	} else {
>  		src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
>  		src_mb->flags |= MFC_BUF_FLAG_USED;
>  		if (src_mb->b->vb2_buf.planes[0].bytesused == 0) {
> -			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> +			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
>  			ctx->state = MFCINST_FINISHING;
>  		} else {
>  			src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
>  			src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				src_c_1_addr = vb2_dma_contig_plane_dma_addr
> +						(&src_mb->b->vb2_buf, 2);
> +			else
> +				src_c_1_addr = 0;
>  
>  			mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr);
>  			mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr);
>  
> -			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr);
> +			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
> +						src_c_addr, src_c_1_addr);
>  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
>  				ctx->state = MFCINST_FINISHING;
>  		}
> @@ -2450,6 +2566,8 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
>  			S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
>  	R(e_encoded_source_second_plane_addr,
>  			S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
> +	R(e_encoded_source_third_plane_addr,
> +			S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7);
>  	R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
>  
>  	if (!IS_MFCV8_PLUS(dev))
> @@ -2464,16 +2582,20 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
>  	R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
>  	R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
>  	R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
> +	R(d_third_plane_dpb_size, S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8);
>  	R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
>  	R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
>  	R(d_first_plane_dpb_stride_size,
>  			S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
>  	R(d_second_plane_dpb_stride_size,
>  			S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
> +	R(d_third_plane_dpb_stride_size,
> +			S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8);
>  	R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
>  	R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
>  	R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
>  	R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
> +	R(d_third_plane_dpb, S5P_FIMV_D_THIRD_PLANE_DPB_V8);
>  	R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
>  	R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
>  	R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);
Nicolas Dufresne Nov. 23, 2023, 5:25 p.m. UTC | #2
Le mercredi 25 octobre 2023 à 15:52 +0530, Aakarsh Jain a écrit :
> YV12 and I420 format (3-plane) support is added. Stride information is
> added to all formats and planes since it is necessary for YV12/I420
> which are different from width.
> 
> Cc: linux-fsd@tesla.com
> Signed-off-by: Smitha T Murthy <smithatmurthy@gmail.com>
> Signed-off-by: Aakarsh Jain <aakarsh.jain@samsung.com>
> ---
>  .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   2 +
>  .../platform/samsung/s5p-mfc/regs-mfc-v7.h    |   1 +
>  .../platform/samsung/s5p-mfc/regs-mfc-v8.h    |   3 +
>  .../platform/samsung/s5p-mfc/s5p_mfc_common.h |   4 +
>  .../platform/samsung/s5p-mfc/s5p_mfc_dec.c    |  45 ++++-
>  .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    |  86 +++++++--
>  .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   6 +-
>  .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c |  12 +-
>  .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 168 +++++++++++++++---
>  9 files changed, 281 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> index 6c68a45082d0..70464f47c1f9 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> @@ -26,6 +26,8 @@
>  #define MFC_VERSION_V12			0xC0
>  #define MFC_NUM_PORTS_V12		1
>  #define S5P_FIMV_CODEC_VP9_ENC		27
> +#define MFC_CHROMA_PAD_BYTES_V12        256
> +#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V12 256
>  
>  /* Encoder buffer size for MFCv12 */
>  #define ENC_V120_BASE_SIZE(x, y) \
> diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> index 4a7adfdaa359..50f9bf0603c1 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> @@ -24,6 +24,7 @@
>  
>  #define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7		0xfa70
>  #define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7	0xfa74
> +#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7		0xfa78
>  
>  #define S5P_FIMV_E_VP8_OPTIONS_V7			0xfdb0
>  #define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7		0xfdb4
> diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> index 162e3c7e920f..0ef9eb2dff22 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> @@ -17,13 +17,16 @@
>  #define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8	0xf108
>  #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8	0xf144
>  #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8	0xf148
> +#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8	0xf14C
>  #define S5P_FIMV_D_MV_BUFFER_SIZE_V8		0xf150
>  
>  #define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8	0xf138
>  #define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8	0xf13c
> +#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8	0xf140
>  
>  #define S5P_FIMV_D_FIRST_PLANE_DPB_V8		0xf160
>  #define S5P_FIMV_D_SECOND_PLANE_DPB_V8		0xf260
> +#define S5P_FIMV_D_THIRD_PLANE_DPB_V8		0xf360
>  #define S5P_FIMV_D_MV_BUFFER_V8			0xf460
>  
>  #define S5P_FIMV_D_NUM_MV_V8			0xf134
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> index dd2e9f7704ab..9a39cccfe002 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> @@ -56,6 +56,7 @@
>  #define MFC_NO_INSTANCE_SET	-1
>  #define MFC_ENC_CAP_PLANE_COUNT	1
>  #define MFC_ENC_OUT_PLANE_COUNT	2
> +#define VB2_MAX_PLANE_COUNT	3
>  #define STUFF_BYTE		4
>  #define MFC_MAX_CTRLS		128
>  
> @@ -181,6 +182,7 @@ struct s5p_mfc_buf {
>  		struct {
>  			size_t luma;
>  			size_t chroma;
> +			size_t chroma_1;
>  		} raw;
>  		size_t stream;
>  	} cookie;
> @@ -657,6 +659,7 @@ struct s5p_mfc_ctx {
>  
>  	int luma_size;
>  	int chroma_size;
> +	int chroma_size_1;
>  	int mv_size;
>  
>  	unsigned long consumed_stream;
> @@ -722,6 +725,7 @@ struct s5p_mfc_ctx {
>  	size_t scratch_buf_size;
>  	int is_10bit;
>  	int is_422;
> +	int stride[VB2_MAX_PLANE_COUNT];
>  };
>  
>  /*
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> index e219cbcd86d5..317f796fffa1 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> @@ -56,6 +56,20 @@ static struct s5p_mfc_fmt formats[] = {
>  		.num_planes	= 2,
>  		.versions	= MFC_V6PLUS_BITS,
>  	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT,
> +	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT
> +	},
>  	{
>  		.fourcc		= V4L2_PIX_FMT_H264,
>  		.codec_mode	= S5P_MFC_CODEC_H264_DEC,
> @@ -359,10 +373,15 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  		/* Set pixelformat to the format in which MFC
>  		   outputs the decoded frame */
>  		pix_mp->pixelformat = ctx->dst_fmt->fourcc;
> -		pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> +		pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
>  		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> -		pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> +		pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
>  		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> +			pix_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
> +		}
>  	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
>  		/* This is run on OUTPUT
>  		   The buffer contains compressed image
> @@ -937,6 +956,9 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
>  		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
>  		/* Output plane count is 2 - one for Y and one for CbCr */
>  		*plane_count = 2;
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			*plane_count = 3;

I don't usually interfere, this is your driver to maintain, but this becomes
horribly messy. Have you consider de-hardcoding a little and encapsulate per HW
format details into a C structure ? Drivers these days try to make sure of v4l2-
common library, which as a matter of fact knows that YUV420M and YVU420M have 3
places, so that you don't have to duplicate it in your driver.

regards,
Nicolas

>  		/* Setup buffer count */
>  		if (*buf_count < ctx->pb_count)
>  			*buf_count = ctx->pb_count;
> @@ -955,12 +977,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
>  	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
>  		psize[0] = ctx->luma_size;
>  		psize[1] = ctx->chroma_size;
> -
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			psize[2] = ctx->chroma_size_1;
>  		if (IS_MFCV6_PLUS(dev))
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
>  		else
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
>  		alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
>  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
>  		   ctx->state == MFCINST_INIT) {
>  		psize[0] = ctx->dec_src_buf_size;
> @@ -994,12 +1021,24 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
>  			mfc_err("Plane buffer (CAPTURE) is too small\n");
>  			return -EINVAL;
>  		}
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
> +				mfc_err("Plane buffer (CAPTURE) is too small\n");
> +				return -EINVAL;
> +			}
> +		}
>  		i = vb->index;
>  		ctx->dst_bufs[i].b = vbuf;
>  		ctx->dst_bufs[i].cookie.raw.luma =
>  					vb2_dma_contig_plane_dma_addr(vb, 0);
>  		ctx->dst_bufs[i].cookie.raw.chroma =
>  					vb2_dma_contig_plane_dma_addr(vb, 1);
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			ctx->dst_bufs[i].cookie.raw.chroma_1 =
> +					vb2_dma_contig_plane_dma_addr(vb, 2);
> +		}
>  		ctx->dst_bufs_cnt++;
>  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
>  		if (IS_ERR_OR_NULL(ERR_PTR(
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> index e4d6e7c117b5..0eec04eb3ef3 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> @@ -59,6 +59,20 @@ static struct s5p_mfc_fmt formats[] = {
>  		.num_planes	= 2,
>  		.versions	= MFC_V6PLUS_BITS,
>  	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT,
> +	},
> +	{
> +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> +		.codec_mode     = S5P_MFC_CODEC_NONE,
> +		.type           = MFC_FMT_RAW,
> +		.num_planes     = 3,
> +		.versions       = MFC_V12_BIT,
> +	},
>  	{
>  		.fourcc		= V4L2_PIX_FMT_H264,
>  		.codec_mode	= S5P_MFC_CODEC_H264_ENC,
> @@ -1193,14 +1207,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	struct s5p_mfc_buf *dst_mb;
>  	struct s5p_mfc_buf *src_mb;
> -	unsigned long src_y_addr, src_c_addr, dst_addr;
> +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
>  	unsigned int dst_size;
>  
>  	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
>  	src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
>  	src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
> +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		src_c_1_addr =
> +			vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 2);
> +	else
> +		src_c_1_addr = 0;
>  	s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
> -							src_y_addr, src_c_addr);
> +					src_y_addr, src_c_addr, src_c_1_addr);
>  
>  	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
>  	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
> @@ -1215,8 +1235,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	struct s5p_mfc_buf *mb_entry;
> -	unsigned long enc_y_addr = 0, enc_c_addr = 0;
> -	unsigned long mb_y_addr, mb_c_addr;
> +	unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0;
> +	unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr;
>  	int slice_type;
>  	unsigned int strm_size;
>  	bool src_ready;
> @@ -1229,14 +1249,21 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
>  		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
>  	if (slice_type >= 0) {
>  		s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
> -				&enc_y_addr, &enc_c_addr);
> +				&enc_y_addr, &enc_c_addr, &enc_c_1_addr);
>  		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
>  			mb_y_addr = vb2_dma_contig_plane_dma_addr(
>  					&mb_entry->b->vb2_buf, 0);
>  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
>  					&mb_entry->b->vb2_buf, 1);
> -			if ((enc_y_addr == mb_y_addr) &&
> -						(enc_c_addr == mb_c_addr)) {
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				mb_c_1_addr = vb2_dma_contig_plane_dma_addr
> +						(&mb_entry->b->vb2_buf, 2);
> +			else
> +				mb_c_1_addr = 0;
> +			if ((enc_y_addr == mb_y_addr)
> +					&& (enc_c_addr == mb_c_addr)
> +					&& (enc_c_1_addr == mb_c_1_addr)) {
>  				list_del(&mb_entry->list);
>  				ctx->src_queue_cnt--;
>  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> @@ -1249,8 +1276,15 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
>  					&mb_entry->b->vb2_buf, 0);
>  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
>  					&mb_entry->b->vb2_buf, 1);
> -			if ((enc_y_addr == mb_y_addr) &&
> -						(enc_c_addr == mb_c_addr)) {
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				mb_c_1_addr = vb2_dma_contig_plane_dma_addr(
> +						&mb_entry->b->vb2_buf, 2);
> +			else
> +				mb_c_1_addr = 0;
> +			if ((enc_y_addr == mb_y_addr)
> +					&& (enc_c_addr == mb_c_addr)
> +					&& (enc_c_1_addr == mb_c_1_addr)) {
>  				list_del(&mb_entry->list);
>  				ctx->ref_queue_cnt--;
>  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> @@ -1381,10 +1415,15 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  		pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
>  		pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
>  
> -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
>  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
>  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
> +		}
>  	} else {
>  		mfc_err("invalid buf type\n");
>  		return -EINVAL;
> @@ -1468,9 +1507,14 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
>  
>  		s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
>  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
>  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
> +		}
>  
>  		ctx->src_bufs_cnt = 0;
>  		ctx->output_state = QUEUE_FREE;
> @@ -2414,10 +2458,16 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
>  
>  		psize[0] = ctx->luma_size;
>  		psize[1] = ctx->chroma_size;
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			psize[2] = ctx->chroma_size_1;
>  
>  		if (IS_MFCV6_PLUS(dev)) {
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
>  			alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
>  		} else {
>  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
>  			alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
> @@ -2456,6 +2506,10 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
>  					vb2_dma_contig_plane_dma_addr(vb, 0);
>  		ctx->src_bufs[i].cookie.raw.chroma =
>  					vb2_dma_contig_plane_dma_addr(vb, 1);
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			ctx->src_bufs[i].cookie.raw.chroma_1 =
> +					vb2_dma_contig_plane_dma_addr(vb, 2);
>  		ctx->src_bufs_cnt++;
>  	} else {
>  		mfc_err("invalid queue type: %d\n", vq->type);
> @@ -2493,6 +2547,12 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
>  			mfc_err("plane size is too small for output\n");
>  			return -EINVAL;
>  		}
> +		if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +		     ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) &&
> +		    (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) {
> +			mfc_err("plane size is too small for output\n");
> +			return -EINVAL;
> +		}
>  	} else {
>  		mfc_err("invalid queue type: %d\n", vq->type);
>  		return -EINVAL;
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> index 87ac56756a16..7c5e851c8191 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> @@ -293,9 +293,11 @@ struct s5p_mfc_hw_ops {
>  	int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
>  			unsigned long addr, unsigned int size);
>  	void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> -			unsigned long y_addr, unsigned long c_addr);
> +			unsigned long y_addr, unsigned long c_addr,
> +			unsigned long c_1_addr);
>  	void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> -			unsigned long *y_addr, unsigned long *c_addr);
> +			unsigned long *y_addr, unsigned long *c_addr,
> +			unsigned long *c_1_addr);
>  	void (*try_run)(struct s5p_mfc_dev *dev);
>  	void (*clear_int_flags)(struct s5p_mfc_dev *dev);
>  	int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev);
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> index 28a06dc343fd..fcfaf125a5a1 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> @@ -516,7 +516,8 @@ static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
>  }
>  
>  static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> -		unsigned long y_addr, unsigned long c_addr)
> +		unsigned long y_addr, unsigned long c_addr,
> +		unsigned long c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  
> @@ -525,7 +526,8 @@ static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
>  }
>  
>  static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> -		unsigned long *y_addr, unsigned long *c_addr)
> +		unsigned long *y_addr, unsigned long *c_addr,
> +		unsigned long *c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  
> @@ -1210,7 +1212,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  	if (list_empty(&ctx->src_queue)) {
>  		/* send null frame */
>  		s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX],
> -						dev->dma_base[BANK_R_CTX]);
> +						dev->dma_base[BANK_R_CTX], 0);
>  		src_mb = NULL;
>  	} else {
>  		src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
> @@ -1220,7 +1222,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  			/* send null frame */
>  			s5p_mfc_set_enc_frame_buffer_v5(ctx,
>  						dev->dma_base[BANK_R_CTX],
> -						dev->dma_base[BANK_R_CTX]);
> +						dev->dma_base[BANK_R_CTX], 0);
>  			ctx->state = MFCINST_FINISHING;
>  		} else {
>  			src_y_addr = vb2_dma_contig_plane_dma_addr(
> @@ -1228,7 +1230,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  			src_c_addr = vb2_dma_contig_plane_dma_addr(
>  					&src_mb->b->vb2_buf, 1);
>  			s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr,
> -								src_c_addr);
> +								src_c_addr, 0);
>  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
>  				ctx->state = MFCINST_FINISHING;
>  		}
> diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> index fb3f0718821d..e579c765e902 100644
> --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> @@ -494,16 +494,43 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
>  	ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6);
> +	ctx->chroma_size_1 = 0;
>  	mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
>  			"buffer dimensions: %dx%d\n", ctx->img_width,
>  			ctx->img_height, ctx->buf_width, ctx->buf_height);
>  
> -	ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
> -	ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
> +	switch (ctx->dst_fmt->fourcc) {
> +	case V4L2_PIX_FMT_NV12M:
> +	case V4L2_PIX_FMT_NV21M:
> +		ctx->stride[0] = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->stride[1] = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> +		ctx->chroma_size = calc_plane(ctx->stride[1],
> +					(ctx->img_height / 2));
> +		break;
> +	case V4L2_PIX_FMT_YUV420M:
> +	case V4L2_PIX_FMT_YVU420M:
> +		ctx->stride[0] = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->stride[1] = ALIGN(ctx->img_width / 2,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->stride[2] = ALIGN(ctx->img_width / 2,
> +					S5P_FIMV_NV12MT_HALIGN_V6);
> +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> +		ctx->chroma_size = calc_plane(ctx->stride[1],
> +					(ctx->img_height / 2));
> +		ctx->chroma_size_1 = calc_plane(ctx->stride[2],
> +					(ctx->img_height / 2));
> +		break;
> +	}
> +
>  	if (IS_MFCV8_PLUS(ctx->dev)) {
>  		/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
>  		ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
>  		ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> +		ctx->chroma_size_1 += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
>  	}
>  
>  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
> @@ -534,15 +561,53 @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
>  	mb_width = MB_WIDTH(ctx->img_width);
>  	mb_height = MB_HEIGHT(ctx->img_height);
>  
> -	ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
> -	ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
> -	ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
> -
> -	/* MFCv7 needs pad bytes for Luma and Chroma */
> -	if (IS_MFCV7_PLUS(ctx->dev)) {
> +	if (IS_MFCV12(ctx->dev)) {
> +		switch (ctx->src_fmt->fourcc) {
> +		case V4L2_PIX_FMT_NV12M:
> +		case V4L2_PIX_FMT_NV21M:
> +			ctx->stride[0] = ALIGN(ctx->img_width,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->stride[1] = ALIGN(ctx->img_width,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->luma_size = ctx->stride[0] *
> +						ALIGN(ctx->img_height, 16);
> +			ctx->chroma_size =  ctx->stride[0] *
> +						ALIGN(ctx->img_height / 2, 16);
> +			break;
> +		case V4L2_PIX_FMT_YUV420M:
> +		case V4L2_PIX_FMT_YVU420M:
> +			ctx->stride[0] = ALIGN(ctx->img_width,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->stride[1] = ALIGN(ctx->img_width / 2,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->stride[2] = ALIGN(ctx->img_width / 2,
> +						S5P_FIMV_NV12M_HALIGN_V6);
> +			ctx->luma_size = ctx->stride[0] *
> +						ALIGN(ctx->img_height, 16);
> +			ctx->chroma_size =  ctx->stride[1] *
> +						ALIGN(ctx->img_height / 2, 16);
> +			ctx->chroma_size_1 =  ctx->stride[2] *
> +						ALIGN(ctx->img_height / 2, 16);
> +			break;
> +		}
>  		ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> -		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
> +		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V12;
> +		ctx->chroma_size_1 += MFC_CHROMA_PAD_BYTES_V12;
> +	} else {
> +		ctx->buf_width = ALIGN(ctx->img_width,
> +					S5P_FIMV_NV12M_HALIGN_V6);
> +		ctx->stride[0] = ctx->buf_width;
> +		ctx->stride[1] = ctx->buf_width;
> +		ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
> +		ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
> +		ctx->chroma_size_1 = 0;
> +		/* MFCv7 needs pad bytes for Luma and Chroma */
> +		if (IS_MFCV7_PLUS(ctx->dev)) {
> +			ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> +			ctx->chroma_size += MFC_LUMA_PAD_BYTES_V7;
> +		}
>  	}
> +
>  }
>  
>  /* Set registers for decoding stream buffer */
> @@ -588,15 +653,21 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
>  	writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
>  	writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
>  	writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
> -
> +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +			ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		writel(ctx->chroma_size_1, mfc_regs->d_third_plane_dpb_size);
>  	writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
>  	writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
>  
>  	if (IS_MFCV8_PLUS(dev)) {
> -		writel(ctx->img_width,
> +		writel(ctx->stride[0],
>  			mfc_regs->d_first_plane_dpb_stride_size);
> -		writel(ctx->img_width,
> +		writel(ctx->stride[1],
>  			mfc_regs->d_second_plane_dpb_stride_size);
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			writel(ctx->stride[2],
> +				mfc_regs->d_third_plane_dpb_stride_size);
>  	}
>  
>  	buf_addr1 += ctx->scratch_buf_size;
> @@ -625,6 +696,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
>  					ctx->dst_bufs[i].cookie.raw.chroma);
>  		writel(ctx->dst_bufs[i].cookie.raw.chroma,
>  				mfc_regs->d_second_plane_dpb + i * 4);
> +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +			mfc_debug(2, "\tChroma_1 %d: %zx\n", i,
> +					ctx->dst_bufs[i].cookie.raw.chroma_1);
> +			writel(ctx->dst_bufs[i].cookie.raw.chroma_1,
> +					mfc_regs->d_third_plane_dpb + i * 4);
> +		}
>  	}
>  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
>  			ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC ||
> @@ -683,20 +761,24 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
>  }
>  
>  static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> -		unsigned long y_addr, unsigned long c_addr)
> +		unsigned long y_addr, unsigned long c_addr,
> +		unsigned long c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
>  
>  	writel(y_addr, mfc_regs->e_source_first_plane_addr);
>  	writel(c_addr, mfc_regs->e_source_second_plane_addr);
> +	writel(c_1_addr, mfc_regs->e_source_third_plane_addr);
>  
>  	mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
>  	mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
> +	mfc_debug(2, "enc src cr buf addr: 0x%08lx\n", c_1_addr);
>  }
>  
>  static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> -		unsigned long *y_addr, unsigned long *c_addr)
> +		unsigned long *y_addr, unsigned long *c_addr,
> +		unsigned long *c_1_addr)
>  {
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
> @@ -704,12 +786,17 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
>  
>  	*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
>  	*c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
> +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		*c_1_addr = readl(mfc_regs->e_encoded_source_third_plane_addr);
> +	else
> +		*c_1_addr = 0;
>  
>  	enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
>  	enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
>  
>  	mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n", enc_recon_y_addr, *y_addr);
> -	mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
> +	mfc_debug(2, "recon c addr: 0x%08lx c_addr: 0x%08lx\n", enc_recon_c_addr, *c_addr);
>  }
>  
>  /* Set encoding ref & codec buffer */
> @@ -886,6 +973,20 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
>  		writel(reg, mfc_regs->e_enc_options);
>  		/* 0: NV12(CbCr), 1: NV21(CrCb) */
>  		writel(0x0, mfc_regs->pixel_format);
> +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> +		/* 0: Linear, 1: 2D tiled*/
> +		reg = readl(mfc_regs->e_enc_options);
> +		reg &= ~(0x1 << 7);
> +		writel(reg, mfc_regs->e_enc_options);
> +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> +		writel(0x2, mfc_regs->pixel_format);
> +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M) {
> +		/* 0: Linear, 1: 2D tiled*/
> +		reg = readl(mfc_regs->e_enc_options);
> +		reg &= ~(0x1 << 7);
> +		writel(reg, mfc_regs->e_enc_options);
> +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> +		writel(0x3, mfc_regs->pixel_format);
>  	}
>  
>  	/* memory structure recon. frame */
> @@ -1696,8 +1797,12 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
>  	else
>  		writel(reg, mfc_regs->d_dec_options);
>  
> -	/* 0: NV12(CbCr), 1: NV21(CrCb) */
> -	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
> +	/* 0: NV12(CbCr), 1: NV21(CrCb), 2: YV12(CrCb), 3: I420(CbCr) */
> +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M)
> +		writel(0x3, mfc_regs->pixel_format);
> +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +		writel(0x2, mfc_regs->pixel_format);
> +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
>  		writel(0x1, mfc_regs->pixel_format);
>  	else
>  		writel(0x0, mfc_regs->pixel_format);
> @@ -1781,8 +1886,12 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
>  
>  	/* Set stride lengths for v7 & above */
>  	if (IS_MFCV7_PLUS(dev)) {
> -		writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
> -		writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
> +		writel(ctx->stride[0], mfc_regs->e_source_first_plane_stride);
> +		writel(ctx->stride[1], mfc_regs->e_source_second_plane_stride);
> +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +			writel(ctx->stride[2],
> +					mfc_regs->e_source_third_plane_stride);
>  	}
>  
>  	writel(ctx->inst_no, mfc_regs->instance_id);
> @@ -1891,7 +2000,7 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  	struct s5p_mfc_dev *dev = ctx->dev;
>  	struct s5p_mfc_buf *dst_mb;
>  	struct s5p_mfc_buf *src_mb;
> -	unsigned long src_y_addr, src_c_addr, dst_addr;
> +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
>  	/*
>  	unsigned int src_y_size, src_c_size;
>  	*/
> @@ -1909,22 +2018,29 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
>  
>  	if (list_empty(&ctx->src_queue)) {
>  		/* send null frame */
> -		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> +		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
>  		src_mb = NULL;
>  	} else {
>  		src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
>  		src_mb->flags |= MFC_BUF_FLAG_USED;
>  		if (src_mb->b->vb2_buf.planes[0].bytesused == 0) {
> -			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> +			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
>  			ctx->state = MFCINST_FINISHING;
>  		} else {
>  			src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
>  			src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
> +			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> +				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> +				src_c_1_addr = vb2_dma_contig_plane_dma_addr
> +						(&src_mb->b->vb2_buf, 2);
> +			else
> +				src_c_1_addr = 0;
>  
>  			mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr);
>  			mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr);
>  
> -			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr);
> +			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
> +						src_c_addr, src_c_1_addr);
>  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
>  				ctx->state = MFCINST_FINISHING;
>  		}
> @@ -2450,6 +2566,8 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
>  			S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
>  	R(e_encoded_source_second_plane_addr,
>  			S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
> +	R(e_encoded_source_third_plane_addr,
> +			S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7);
>  	R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
>  
>  	if (!IS_MFCV8_PLUS(dev))
> @@ -2464,16 +2582,20 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
>  	R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
>  	R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
>  	R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
> +	R(d_third_plane_dpb_size, S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8);
>  	R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
>  	R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
>  	R(d_first_plane_dpb_stride_size,
>  			S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
>  	R(d_second_plane_dpb_stride_size,
>  			S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
> +	R(d_third_plane_dpb_stride_size,
> +			S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8);
>  	R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
>  	R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
>  	R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
>  	R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
> +	R(d_third_plane_dpb, S5P_FIMV_D_THIRD_PLANE_DPB_V8);
>  	R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
>  	R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
>  	R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);
Aakarsh Jain Nov. 27, 2023, 7 a.m. UTC | #3
Hi Nicolas,

> -----Original Message-----
> From: Nicolas Dufresne <nicolas@ndufresne.ca>
> Sent: 23 November 2023 22:56
> To: Aakarsh Jain <aakarsh.jain@samsung.com>; linux-arm-
> kernel@lists.infradead.org; linux-media@vger.kernel.org; linux-
> kernel@vger.kernel.org; devicetree@vger.kernel.org
> Cc: m.szyprowski@samsung.com; andrzej.hajda@intel.com;
> mchehab@kernel.org; hverkuil-cisco@xs4all.nl;
> krzysztof.kozlowski+dt@linaro.org; dillon.minfei@gmail.com;
> david.plowman@raspberrypi.com; mark.rutland@arm.com;
> robh+dt@kernel.org; conor+dt@kernel.org; linux-samsung-
> soc@vger.kernel.org; andi@etezian.org; gost.dev@samsung.com;
> alim.akhtar@samsung.com; aswani.reddy@samsung.com;
> pankaj.dubey@samsung.com; ajaykumar.rs@samsung.com; linux-
> fsd@tesla.com; Smitha T Murthy <smithatmurthy@gmail.com>
> Subject: Re: [Patch v4 04/11] media: s5p-mfc: Add YV12 and I420 multiplanar
> format support
> 
> Le mercredi 25 octobre 2023 à 15:52 +0530, Aakarsh Jain a écrit :
> > YV12 and I420 format (3-plane) support is added. Stride information is
> > added to all formats and planes since it is necessary for YV12/I420
> > which are different from width.
> >
> > Cc: linux-fsd@tesla.com
> > Signed-off-by: Smitha T Murthy <smithatmurthy@gmail.com>
> > Signed-off-by: Aakarsh Jain <aakarsh.jain@samsung.com>
> > ---
> >  .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   2 +
> >  .../platform/samsung/s5p-mfc/regs-mfc-v7.h    |   1 +
> >  .../platform/samsung/s5p-mfc/regs-mfc-v8.h    |   3 +
> >  .../platform/samsung/s5p-mfc/s5p_mfc_common.h |   4 +
> >  .../platform/samsung/s5p-mfc/s5p_mfc_dec.c    |  45 ++++-
> >  .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    |  86 +++++++--
> >  .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   6 +-
> >  .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c |  12 +-
> > .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 168
> +++++++++++++++---
> >  9 files changed, 281 insertions(+), 46 deletions(-)
> >
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > index 6c68a45082d0..70464f47c1f9 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > @@ -26,6 +26,8 @@
> >  #define MFC_VERSION_V12			0xC0
> >  #define MFC_NUM_PORTS_V12		1
> >  #define S5P_FIMV_CODEC_VP9_ENC		27
> > +#define MFC_CHROMA_PAD_BYTES_V12        256
> > +#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V12 256
> >
> >  /* Encoder buffer size for MFCv12 */
> >  #define ENC_V120_BASE_SIZE(x, y) \
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > index 4a7adfdaa359..50f9bf0603c1 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > @@ -24,6 +24,7 @@
> >
> >  #define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7
> 	0xfa70
> >  #define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7
> 	0xfa74
> > +#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7
> 	0xfa78
> >
> >  #define S5P_FIMV_E_VP8_OPTIONS_V7			0xfdb0
> >  #define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7		0xfdb4
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > index 162e3c7e920f..0ef9eb2dff22 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > @@ -17,13 +17,16 @@
> >  #define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8	0xf108
> >  #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8	0xf144
> >  #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8	0xf148
> > +#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8	0xf14C
> >  #define S5P_FIMV_D_MV_BUFFER_SIZE_V8		0xf150
> >
> >  #define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8	0xf138
> >  #define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8
> 	0xf13c
> > +#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8
> 	0xf140
> >
> >  #define S5P_FIMV_D_FIRST_PLANE_DPB_V8		0xf160
> >  #define S5P_FIMV_D_SECOND_PLANE_DPB_V8		0xf260
> > +#define S5P_FIMV_D_THIRD_PLANE_DPB_V8		0xf360
> >  #define S5P_FIMV_D_MV_BUFFER_V8			0xf460
> >
> >  #define S5P_FIMV_D_NUM_MV_V8			0xf134
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > index dd2e9f7704ab..9a39cccfe002 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > @@ -56,6 +56,7 @@
> >  #define MFC_NO_INSTANCE_SET	-1
> >  #define MFC_ENC_CAP_PLANE_COUNT	1
> >  #define MFC_ENC_OUT_PLANE_COUNT	2
> > +#define VB2_MAX_PLANE_COUNT	3
> >  #define STUFF_BYTE		4
> >  #define MFC_MAX_CTRLS		128
> >
> > @@ -181,6 +182,7 @@ struct s5p_mfc_buf {
> >  		struct {
> >  			size_t luma;
> >  			size_t chroma;
> > +			size_t chroma_1;
> >  		} raw;
> >  		size_t stream;
> >  	} cookie;
> > @@ -657,6 +659,7 @@ struct s5p_mfc_ctx {
> >
> >  	int luma_size;
> >  	int chroma_size;
> > +	int chroma_size_1;
> >  	int mv_size;
> >
> >  	unsigned long consumed_stream;
> > @@ -722,6 +725,7 @@ struct s5p_mfc_ctx {
> >  	size_t scratch_buf_size;
> >  	int is_10bit;
> >  	int is_422;
> > +	int stride[VB2_MAX_PLANE_COUNT];
> >  };
> >
> >  /*
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > index e219cbcd86d5..317f796fffa1 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > @@ -56,6 +56,20 @@ static struct s5p_mfc_fmt formats[] = {
> >  		.num_planes	= 2,
> >  		.versions	= MFC_V6PLUS_BITS,
> >  	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT,
> > +	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT
> > +	},
> >  	{
> >  		.fourcc		= V4L2_PIX_FMT_H264,
> >  		.codec_mode	= S5P_MFC_CODEC_H264_DEC,
> > @@ -359,10 +373,15 @@ static int vidioc_g_fmt(struct file *file, void *priv,
> struct v4l2_format *f)
> >  		/* Set pixelformat to the format in which MFC
> >  		   outputs the decoded frame */
> >  		pix_mp->pixelformat = ctx->dst_fmt->fourcc;
> > -		pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> > +		pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
> >  		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> > -		pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> > +		pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> >  		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> > +			pix_mp->plane_fmt[2].sizeimage = ctx-
> >chroma_size_1;
> > +		}
> >  	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> >  		/* This is run on OUTPUT
> >  		   The buffer contains compressed image @@ -937,6 +956,9
> @@ static
> > int s5p_mfc_queue_setup(struct vb2_queue *vq,
> >  		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> >  		/* Output plane count is 2 - one for Y and one for CbCr */
> >  		*plane_count = 2;
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			*plane_count = 3;
> 
> I don't usually interfere, this is your driver to maintain, but this becomes
> horribly messy. Have you consider de-hardcoding a little and encapsulate per
> HW format details into a C structure ? Drivers these days try to make sure of
> v4l2- common library, which as a matter of fact knows that YUV420M and
> YVU420M have 3 places, so that you don't have to duplicate it in your driver.
> 
> regards,
> Nicolas

Thanks for pointing out.
We could have done it in this way ' *plane_count = ctx->dst_fmt->num_planes' also.
Anyway, will make use of ' v4l2- common library ' for getting the planes count here in next series.

Thanks for the review.
> 
> >  		/* Setup buffer count */
> >  		if (*buf_count < ctx->pb_count)
> >  			*buf_count = ctx->pb_count;
> > @@ -955,12 +977,17 @@ static int s5p_mfc_queue_setup(struct
> vb2_queue *vq,
> >  	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> >  		psize[0] = ctx->luma_size;
> >  		psize[1] = ctx->chroma_size;
> > -
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			psize[2] = ctx->chroma_size_1;
> >  		if (IS_MFCV6_PLUS(dev))
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
> >  		else
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
> >  		alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
> >  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
> >  		   ctx->state == MFCINST_INIT) {
> >  		psize[0] = ctx->dec_src_buf_size;
> > @@ -994,12 +1021,24 @@ static int s5p_mfc_buf_init(struct vb2_buffer
> *vb)
> >  			mfc_err("Plane buffer (CAPTURE) is too small\n");
> >  			return -EINVAL;
> >  		}
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
> > +				mfc_err("Plane buffer (CAPTURE) is too
> small\n");
> > +				return -EINVAL;
> > +			}
> > +		}
> >  		i = vb->index;
> >  		ctx->dst_bufs[i].b = vbuf;
> >  		ctx->dst_bufs[i].cookie.raw.luma =
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 0);
> >  		ctx->dst_bufs[i].cookie.raw.chroma =
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 1);
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			ctx->dst_bufs[i].cookie.raw.chroma_1 =
> > +
> 	vb2_dma_contig_plane_dma_addr(vb, 2);
> > +		}
> >  		ctx->dst_bufs_cnt++;
> >  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> >  		if (IS_ERR_OR_NULL(ERR_PTR(
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > index e4d6e7c117b5..0eec04eb3ef3 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > @@ -59,6 +59,20 @@ static struct s5p_mfc_fmt formats[] = {
> >  		.num_planes	= 2,
> >  		.versions	= MFC_V6PLUS_BITS,
> >  	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT,
> > +	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT,
> > +	},
> >  	{
> >  		.fourcc		= V4L2_PIX_FMT_H264,
> >  		.codec_mode	= S5P_MFC_CODEC_H264_ENC,
> > @@ -1193,14 +1207,20 @@ static int enc_pre_frame_start(struct
> s5p_mfc_ctx *ctx)
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	struct s5p_mfc_buf *dst_mb;
> >  	struct s5p_mfc_buf *src_mb;
> > -	unsigned long src_y_addr, src_c_addr, dst_addr;
> > +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
> >  	unsigned int dst_size;
> >
> >  	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
> >  	src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b-
> >vb2_buf, 0);
> >  	src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b-
> >vb2_buf, 1);
> > +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		src_c_1_addr =
> > +			vb2_dma_contig_plane_dma_addr(&src_mb->b-
> >vb2_buf, 2);
> > +	else
> > +		src_c_1_addr = 0;
> >  	s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
> > -							src_y_addr,
> src_c_addr);
> > +					src_y_addr, src_c_addr,
> src_c_1_addr);
> >
> >  	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
> >  	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b-
> >vb2_buf, 0); @@
> > -1215,8 +1235,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx
> > *ctx)  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	struct s5p_mfc_buf *mb_entry;
> > -	unsigned long enc_y_addr = 0, enc_c_addr = 0;
> > -	unsigned long mb_y_addr, mb_c_addr;
> > +	unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0;
> > +	unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr;
> >  	int slice_type;
> >  	unsigned int strm_size;
> >  	bool src_ready;
> > @@ -1229,14 +1249,21 @@ static int enc_post_frame_start(struct
> s5p_mfc_ctx *ctx)
> >  		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
> >  	if (slice_type >= 0) {
> >  		s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer,
> ctx,
> > -				&enc_y_addr, &enc_c_addr);
> > +				&enc_y_addr, &enc_c_addr,
> &enc_c_1_addr);
> >  		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
> >  			mb_y_addr = vb2_dma_contig_plane_dma_addr(
> >  					&mb_entry->b->vb2_buf, 0);
> >  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
> >  					&mb_entry->b->vb2_buf, 1);
> > -			if ((enc_y_addr == mb_y_addr) &&
> > -						(enc_c_addr == mb_c_addr))
> {
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				mb_c_1_addr =
> vb2_dma_contig_plane_dma_addr
> > +						(&mb_entry->b->vb2_buf,
> 2);
> > +			else
> > +				mb_c_1_addr = 0;
> > +			if ((enc_y_addr == mb_y_addr)
> > +					&& (enc_c_addr == mb_c_addr)
> > +					&& (enc_c_1_addr ==
> mb_c_1_addr)) {
> >  				list_del(&mb_entry->list);
> >  				ctx->src_queue_cnt--;
> >  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> > @@ -1249,8 +1276,15 @@ static int enc_post_frame_start(struct
> s5p_mfc_ctx *ctx)
> >  					&mb_entry->b->vb2_buf, 0);
> >  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
> >  					&mb_entry->b->vb2_buf, 1);
> > -			if ((enc_y_addr == mb_y_addr) &&
> > -						(enc_c_addr == mb_c_addr))
> {
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				mb_c_1_addr =
> vb2_dma_contig_plane_dma_addr(
> > +						&mb_entry->b->vb2_buf, 2);
> > +			else
> > +				mb_c_1_addr = 0;
> > +			if ((enc_y_addr == mb_y_addr)
> > +					&& (enc_c_addr == mb_c_addr)
> > +					&& (enc_c_1_addr ==
> mb_c_1_addr)) {
> >  				list_del(&mb_entry->list);
> >  				ctx->ref_queue_cnt--;
> >  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> > @@ -1381,10 +1415,15 @@ static int vidioc_g_fmt(struct file *file, void
> *priv, struct v4l2_format *f)
> >  		pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
> >  		pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
> >
> > -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
> >  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> > -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> >  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx-
> >stride[2];
> > +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx-
> >chroma_size_1;
> > +		}
> >  	} else {
> >  		mfc_err("invalid buf type\n");
> >  		return -EINVAL;
> > @@ -1468,9 +1507,14 @@ static int vidioc_s_fmt(struct file *file, void
> > *priv, struct v4l2_format *f)
> >
> >  		s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
> >  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> > -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
> >  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> > -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx-
> >stride[2];
> > +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx-
> >chroma_size_1;
> > +		}
> >
> >  		ctx->src_bufs_cnt = 0;
> >  		ctx->output_state = QUEUE_FREE;
> > @@ -2414,10 +2458,16 @@ static int s5p_mfc_queue_setup(struct
> > vb2_queue *vq,
> >
> >  		psize[0] = ctx->luma_size;
> >  		psize[1] = ctx->chroma_size;
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			psize[2] = ctx->chroma_size_1;
> >
> >  		if (IS_MFCV6_PLUS(dev)) {
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
> >  			alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				alloc_devs[2] = ctx->dev-
> >mem_dev[BANK_L_CTX];
> >  		} else {
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
> >  			alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
> @@ -2456,6 +2506,10
> > @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 0);
> >  		ctx->src_bufs[i].cookie.raw.chroma =
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 1);
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			ctx->src_bufs[i].cookie.raw.chroma_1 =
> > +
> 	vb2_dma_contig_plane_dma_addr(vb, 2);
> >  		ctx->src_bufs_cnt++;
> >  	} else {
> >  		mfc_err("invalid queue type: %d\n", vq->type); @@ -2493,6
> +2547,12
> > @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
> >  			mfc_err("plane size is too small for output\n");
> >  			return -EINVAL;
> >  		}
> > +		if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +		     ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) &&
> > +		    (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) {
> > +			mfc_err("plane size is too small for output\n");
> > +			return -EINVAL;
> > +		}
> >  	} else {
> >  		mfc_err("invalid queue type: %d\n", vq->type);
> >  		return -EINVAL;
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > index 87ac56756a16..7c5e851c8191 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > @@ -293,9 +293,11 @@ struct s5p_mfc_hw_ops {
> >  	int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
> >  			unsigned long addr, unsigned int size);
> >  	void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> > -			unsigned long y_addr, unsigned long c_addr);
> > +			unsigned long y_addr, unsigned long c_addr,
> > +			unsigned long c_1_addr);
> >  	void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> > -			unsigned long *y_addr, unsigned long *c_addr);
> > +			unsigned long *y_addr, unsigned long *c_addr,
> > +			unsigned long *c_1_addr);
> >  	void (*try_run)(struct s5p_mfc_dev *dev);
> >  	void (*clear_int_flags)(struct s5p_mfc_dev *dev);
> >  	int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); diff --git
> > a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > index 28a06dc343fd..fcfaf125a5a1 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > @@ -516,7 +516,8 @@ static int
> s5p_mfc_set_enc_stream_buffer_v5(struct
> > s5p_mfc_ctx *ctx,  }
> >
> >  static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> > -		unsigned long y_addr, unsigned long c_addr)
> > +		unsigned long y_addr, unsigned long c_addr,
> > +		unsigned long c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >
> > @@ -525,7 +526,8 @@ static void
> s5p_mfc_set_enc_frame_buffer_v5(struct
> > s5p_mfc_ctx *ctx,  }
> >
> >  static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> > -		unsigned long *y_addr, unsigned long *c_addr)
> > +		unsigned long *y_addr, unsigned long *c_addr,
> > +		unsigned long *c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >
> > @@ -1210,7 +1212,7 @@ static int s5p_mfc_run_enc_frame(struct
> s5p_mfc_ctx *ctx)
> >  	if (list_empty(&ctx->src_queue)) {
> >  		/* send null frame */
> >  		s5p_mfc_set_enc_frame_buffer_v5(ctx, dev-
> >dma_base[BANK_R_CTX],
> > -						dev-
> >dma_base[BANK_R_CTX]);
> > +						dev-
> >dma_base[BANK_R_CTX], 0);
> >  		src_mb = NULL;
> >  	} else {
> >  		src_mb = list_entry(ctx->src_queue.next, struct
> s5p_mfc_buf, @@
> > -1220,7 +1222,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx
> *ctx)
> >  			/* send null frame */
> >  			s5p_mfc_set_enc_frame_buffer_v5(ctx,
> >  						dev-
> >dma_base[BANK_R_CTX],
> > -						dev-
> >dma_base[BANK_R_CTX]);
> > +						dev-
> >dma_base[BANK_R_CTX], 0);
> >  			ctx->state = MFCINST_FINISHING;
> >  		} else {
> >  			src_y_addr = vb2_dma_contig_plane_dma_addr(
> @@ -1228,7 +1230,7 @@
> > static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
> >  			src_c_addr = vb2_dma_contig_plane_dma_addr(
> >  					&src_mb->b->vb2_buf, 1);
> >  			s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr,
> > -								src_c_addr);
> > +								src_c_addr,
> 0);
> >  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
> >  				ctx->state = MFCINST_FINISHING;
> >  		}
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > index fb3f0718821d..e579c765e902 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > @@ -494,16 +494,43 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct
> s5p_mfc_ctx *ctx)
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	ctx->buf_width = ALIGN(ctx->img_width,
> S5P_FIMV_NV12MT_HALIGN_V6);
> >  	ctx->buf_height = ALIGN(ctx->img_height,
> S5P_FIMV_NV12MT_VALIGN_V6);
> > +	ctx->chroma_size_1 = 0;
> >  	mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
> >  			"buffer dimensions: %dx%d\n", ctx->img_width,
> >  			ctx->img_height, ctx->buf_width, ctx->buf_height);
> >
> > -	ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
> > -	ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >>
> 1));
> > +	switch (ctx->dst_fmt->fourcc) {
> > +	case V4L2_PIX_FMT_NV12M:
> > +	case V4L2_PIX_FMT_NV21M:
> > +		ctx->stride[0] = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->stride[1] = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> > +		ctx->chroma_size = calc_plane(ctx->stride[1],
> > +					(ctx->img_height / 2));
> > +		break;
> > +	case V4L2_PIX_FMT_YUV420M:
> > +	case V4L2_PIX_FMT_YVU420M:
> > +		ctx->stride[0] = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->stride[1] = ALIGN(ctx->img_width / 2,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->stride[2] = ALIGN(ctx->img_width / 2,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> > +		ctx->chroma_size = calc_plane(ctx->stride[1],
> > +					(ctx->img_height / 2));
> > +		ctx->chroma_size_1 = calc_plane(ctx->stride[2],
> > +					(ctx->img_height / 2));
> > +		break;
> > +	}
> > +
> >  	if (IS_MFCV8_PLUS(ctx->dev)) {
> >  		/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
> >  		ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> >  		ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> > +		ctx->chroma_size_1 +=
> S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> >  	}
> >
> >  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || @@ -534,15
> +561,53
> > @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
> >  	mb_width = MB_WIDTH(ctx->img_width);
> >  	mb_height = MB_HEIGHT(ctx->img_height);
> >
> > -	ctx->buf_width = ALIGN(ctx->img_width,
> S5P_FIMV_NV12M_HALIGN_V6);
> > -	ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
> > -	ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
> > -
> > -	/* MFCv7 needs pad bytes for Luma and Chroma */
> > -	if (IS_MFCV7_PLUS(ctx->dev)) {
> > +	if (IS_MFCV12(ctx->dev)) {
> > +		switch (ctx->src_fmt->fourcc) {
> > +		case V4L2_PIX_FMT_NV12M:
> > +		case V4L2_PIX_FMT_NV21M:
> > +			ctx->stride[0] = ALIGN(ctx->img_width,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->stride[1] = ALIGN(ctx->img_width,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->luma_size = ctx->stride[0] *
> > +						ALIGN(ctx->img_height, 16);
> > +			ctx->chroma_size =  ctx->stride[0] *
> > +						ALIGN(ctx->img_height / 2,
> 16);
> > +			break;
> > +		case V4L2_PIX_FMT_YUV420M:
> > +		case V4L2_PIX_FMT_YVU420M:
> > +			ctx->stride[0] = ALIGN(ctx->img_width,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->stride[1] = ALIGN(ctx->img_width / 2,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->stride[2] = ALIGN(ctx->img_width / 2,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->luma_size = ctx->stride[0] *
> > +						ALIGN(ctx->img_height, 16);
> > +			ctx->chroma_size =  ctx->stride[1] *
> > +						ALIGN(ctx->img_height / 2,
> 16);
> > +			ctx->chroma_size_1 =  ctx->stride[2] *
> > +						ALIGN(ctx->img_height / 2,
> 16);
> > +			break;
> > +		}
> >  		ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> > -		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
> > +		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V12;
> > +		ctx->chroma_size_1 += MFC_CHROMA_PAD_BYTES_V12;
> > +	} else {
> > +		ctx->buf_width = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12M_HALIGN_V6);
> > +		ctx->stride[0] = ctx->buf_width;
> > +		ctx->stride[1] = ctx->buf_width;
> > +		ctx->luma_size = ALIGN((mb_width * mb_height) * 256,
> 256);
> > +		ctx->chroma_size = ALIGN((mb_width * mb_height) * 128,
> 256);
> > +		ctx->chroma_size_1 = 0;
> > +		/* MFCv7 needs pad bytes for Luma and Chroma */
> > +		if (IS_MFCV7_PLUS(ctx->dev)) {
> > +			ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> > +			ctx->chroma_size += MFC_LUMA_PAD_BYTES_V7;
> > +		}
> >  	}
> > +
> >  }
> >
> >  /* Set registers for decoding stream buffer */ @@ -588,15 +653,21 @@
> > static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
> >  	writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
> >  	writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
> >  	writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
> > -
> > +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +			ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		writel(ctx->chroma_size_1, mfc_regs-
> >d_third_plane_dpb_size);
> >  	writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
> >  	writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
> >
> >  	if (IS_MFCV8_PLUS(dev)) {
> > -		writel(ctx->img_width,
> > +		writel(ctx->stride[0],
> >  			mfc_regs->d_first_plane_dpb_stride_size);
> > -		writel(ctx->img_width,
> > +		writel(ctx->stride[1],
> >  			mfc_regs->d_second_plane_dpb_stride_size);
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			writel(ctx->stride[2],
> > +				mfc_regs->d_third_plane_dpb_stride_size);
> >  	}
> >
> >  	buf_addr1 += ctx->scratch_buf_size;
> > @@ -625,6 +696,13 @@ static int
> s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
> >  					ctx->dst_bufs[i].cookie.raw.chroma);
> >  		writel(ctx->dst_bufs[i].cookie.raw.chroma,
> >  				mfc_regs->d_second_plane_dpb + i * 4);
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			mfc_debug(2, "\tChroma_1 %d: %zx\n", i,
> > +					ctx-
> >dst_bufs[i].cookie.raw.chroma_1);
> > +			writel(ctx->dst_bufs[i].cookie.raw.chroma_1,
> > +					mfc_regs->d_third_plane_dpb + i *
> 4);
> > +		}
> >  	}
> >  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
> >  			ctx->codec_mode ==
> S5P_MFC_CODEC_H264_MVC_DEC || @@ -683,20
> > +761,24 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct
> > s5p_mfc_ctx *ctx,  }
> >
> >  static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> > -		unsigned long y_addr, unsigned long c_addr)
> > +		unsigned long y_addr, unsigned long c_addr,
> > +		unsigned long c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
> >
> >  	writel(y_addr, mfc_regs->e_source_first_plane_addr);
> >  	writel(c_addr, mfc_regs->e_source_second_plane_addr);
> > +	writel(c_1_addr, mfc_regs->e_source_third_plane_addr);
> >
> >  	mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
> >  	mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
> > +	mfc_debug(2, "enc src cr buf addr: 0x%08lx\n", c_1_addr);
> >  }
> >
> >  static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> > -		unsigned long *y_addr, unsigned long *c_addr)
> > +		unsigned long *y_addr, unsigned long *c_addr,
> > +		unsigned long *c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; @@ -704,12
> > +786,17 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct
> > s5p_mfc_ctx *ctx,
> >
> >  	*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
> >  	*c_addr = readl(mfc_regs-
> >e_encoded_source_second_plane_addr);
> > +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		*c_1_addr = readl(mfc_regs-
> >e_encoded_source_third_plane_addr);
> > +	else
> > +		*c_1_addr = 0;
> >
> >  	enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
> >  	enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
> >
> >  	mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n",
> enc_recon_y_addr, *y_addr);
> > -	mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
> > +	mfc_debug(2, "recon c addr: 0x%08lx c_addr: 0x%08lx\n",
> > +enc_recon_c_addr, *c_addr);
> >  }
> >
> >  /* Set encoding ref & codec buffer */ @@ -886,6 +973,20 @@ static int
> > s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
> >  		writel(reg, mfc_regs->e_enc_options);
> >  		/* 0: NV12(CbCr), 1: NV21(CrCb) */
> >  		writel(0x0, mfc_regs->pixel_format);
> > +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> > +		/* 0: Linear, 1: 2D tiled*/
> > +		reg = readl(mfc_regs->e_enc_options);
> > +		reg &= ~(0x1 << 7);
> > +		writel(reg, mfc_regs->e_enc_options);
> > +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> > +		writel(0x2, mfc_regs->pixel_format);
> > +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M) {
> > +		/* 0: Linear, 1: 2D tiled*/
> > +		reg = readl(mfc_regs->e_enc_options);
> > +		reg &= ~(0x1 << 7);
> > +		writel(reg, mfc_regs->e_enc_options);
> > +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> > +		writel(0x3, mfc_regs->pixel_format);
> >  	}
> >
> >  	/* memory structure recon. frame */
> > @@ -1696,8 +1797,12 @@ static int s5p_mfc_init_decode_v6(struct
> s5p_mfc_ctx *ctx)
> >  	else
> >  		writel(reg, mfc_regs->d_dec_options);
> >
> > -	/* 0: NV12(CbCr), 1: NV21(CrCb) */
> > -	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
> > +	/* 0: NV12(CbCr), 1: NV21(CrCb), 2: YV12(CrCb), 3: I420(CbCr) */
> > +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M)
> > +		writel(0x3, mfc_regs->pixel_format);
> > +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		writel(0x2, mfc_regs->pixel_format);
> > +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
> >  		writel(0x1, mfc_regs->pixel_format);
> >  	else
> >  		writel(0x0, mfc_regs->pixel_format); @@ -1781,8 +1886,12
> @@ static
> > int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
> >
> >  	/* Set stride lengths for v7 & above */
> >  	if (IS_MFCV7_PLUS(dev)) {
> > -		writel(ctx->img_width, mfc_regs-
> >e_source_first_plane_stride);
> > -		writel(ctx->img_width, mfc_regs-
> >e_source_second_plane_stride);
> > +		writel(ctx->stride[0], mfc_regs-
> >e_source_first_plane_stride);
> > +		writel(ctx->stride[1], mfc_regs-
> >e_source_second_plane_stride);
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			writel(ctx->stride[2],
> > +					mfc_regs-
> >e_source_third_plane_stride);
> >  	}
> >
> >  	writel(ctx->inst_no, mfc_regs->instance_id); @@ -1891,7 +2000,7
> @@
> > static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	struct s5p_mfc_buf *dst_mb;
> >  	struct s5p_mfc_buf *src_mb;
> > -	unsigned long src_y_addr, src_c_addr, dst_addr;
> > +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
> >  	/*
> >  	unsigned int src_y_size, src_c_size;
> >  	*/
> > @@ -1909,22 +2018,29 @@ static inline int s5p_mfc_run_enc_frame(struct
> > s5p_mfc_ctx *ctx)
> >
> >  	if (list_empty(&ctx->src_queue)) {
> >  		/* send null frame */
> > -		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> > +		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
> >  		src_mb = NULL;
> >  	} else {
> >  		src_mb = list_entry(ctx->src_queue.next, struct
> s5p_mfc_buf, list);
> >  		src_mb->flags |= MFC_BUF_FLAG_USED;
> >  		if (src_mb->b->vb2_buf.planes[0].bytesused == 0) {
> > -			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> > +			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
> >  			ctx->state = MFCINST_FINISHING;
> >  		} else {
> >  			src_y_addr =
> vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
> >  			src_c_addr =
> vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf,
> > 1);
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				src_c_1_addr =
> vb2_dma_contig_plane_dma_addr
> > +						(&src_mb->b->vb2_buf, 2);
> > +			else
> > +				src_c_1_addr = 0;
> >
> >  			mfc_debug(2, "enc src y addr: 0x%08lx\n",
> src_y_addr);
> >  			mfc_debug(2, "enc src c addr: 0x%08lx\n",
> src_c_addr);
> >
> > -			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
> src_c_addr);
> > +			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
> > +						src_c_addr, src_c_1_addr);
> >  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
> >  				ctx->state = MFCINST_FINISHING;
> >  		}
> > @@ -2450,6 +2566,8 @@ const struct s5p_mfc_regs
> *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
> >  			S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
> >  	R(e_encoded_source_second_plane_addr,
> >
> 	S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
> > +	R(e_encoded_source_third_plane_addr,
> > +			S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7);
> >  	R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
> >
> >  	if (!IS_MFCV8_PLUS(dev))
> > @@ -2464,16 +2582,20 @@ const struct s5p_mfc_regs
> *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
> >  	R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
> >  	R(d_first_plane_dpb_size,
> S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
> >  	R(d_second_plane_dpb_size,
> S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
> > +	R(d_third_plane_dpb_size,
> S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8);
> >  	R(d_scratch_buffer_addr,
> S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
> >  	R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
> >  	R(d_first_plane_dpb_stride_size,
> >  			S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
> >  	R(d_second_plane_dpb_stride_size,
> >
> 	S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
> > +	R(d_third_plane_dpb_stride_size,
> > +			S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8);
> >  	R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
> >  	R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
> >  	R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
> >  	R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
> > +	R(d_third_plane_dpb, S5P_FIMV_D_THIRD_PLANE_DPB_V8);
> >  	R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
> >  	R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
> >  	R(d_available_dpb_flag_lower,
> > S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);
Aakarsh Jain Nov. 27, 2023, 7:01 a.m. UTC | #4
Hi Hans,

> -----Original Message-----
> From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> Sent: 22 November 2023 21:11
> To: Aakarsh Jain <aakarsh.jain@samsung.com>; linux-arm-
> kernel@lists.infradead.org; linux-media@vger.kernel.org; linux-
> kernel@vger.kernel.org; devicetree@vger.kernel.org
> Cc: m.szyprowski@samsung.com; andrzej.hajda@intel.com;
> mchehab@kernel.org; krzysztof.kozlowski+dt@linaro.org;
> dillon.minfei@gmail.com; david.plowman@raspberrypi.com;
> mark.rutland@arm.com; robh+dt@kernel.org; conor+dt@kernel.org; linux-
> samsung-soc@vger.kernel.org; andi@etezian.org; gost.dev@samsung.com;
> alim.akhtar@samsung.com; aswani.reddy@samsung.com;
> pankaj.dubey@samsung.com; ajaykumar.rs@samsung.com; linux-
> fsd@tesla.com; Smitha T Murthy <smithatmurthy@gmail.com>
> Subject: Re: [Patch v4 04/11] media: s5p-mfc: Add YV12 and I420 multiplanar
> format support
> 
> On 25/10/2023 12:22, Aakarsh Jain wrote:
> > YV12 and I420 format (3-plane) support is added. Stride information is
> > added to all formats and planes since it is necessary for YV12/I420
> > which are different from width.
> >
> > Cc: linux-fsd@tesla.com
> > Signed-off-by: Smitha T Murthy <smithatmurthy@gmail.com>
> > Signed-off-by: Aakarsh Jain <aakarsh.jain@samsung.com>
> > ---
> >  .../platform/samsung/s5p-mfc/regs-mfc-v12.h   |   2 +
> >  .../platform/samsung/s5p-mfc/regs-mfc-v7.h    |   1 +
> >  .../platform/samsung/s5p-mfc/regs-mfc-v8.h    |   3 +
> >  .../platform/samsung/s5p-mfc/s5p_mfc_common.h |   4 +
> >  .../platform/samsung/s5p-mfc/s5p_mfc_dec.c    |  45 ++++-
> >  .../platform/samsung/s5p-mfc/s5p_mfc_enc.c    |  86 +++++++--
> >  .../platform/samsung/s5p-mfc/s5p_mfc_opr.h    |   6 +-
> >  .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c |  12 +-
> > .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 168
> +++++++++++++++---
> >  9 files changed, 281 insertions(+), 46 deletions(-)
> >
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > index 6c68a45082d0..70464f47c1f9 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
> > @@ -26,6 +26,8 @@
> >  #define MFC_VERSION_V12			0xC0
> >  #define MFC_NUM_PORTS_V12		1
> >  #define S5P_FIMV_CODEC_VP9_ENC		27
> > +#define MFC_CHROMA_PAD_BYTES_V12        256
> > +#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V12 256
> >
> >  /* Encoder buffer size for MFCv12 */
> >  #define ENC_V120_BASE_SIZE(x, y) \
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > index 4a7adfdaa359..50f9bf0603c1 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
> > @@ -24,6 +24,7 @@
> >
> >  #define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7
> 	0xfa70
> >  #define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7
> 	0xfa74
> > +#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7
> 	0xfa78
> >
> >  #define S5P_FIMV_E_VP8_OPTIONS_V7			0xfdb0
> >  #define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7		0xfdb4
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > index 162e3c7e920f..0ef9eb2dff22 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
> > @@ -17,13 +17,16 @@
> >  #define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8	0xf108
> >  #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8	0xf144
> >  #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8	0xf148
> > +#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8	0xf14C
> >  #define S5P_FIMV_D_MV_BUFFER_SIZE_V8		0xf150
> >
> >  #define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8	0xf138
> >  #define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8
> 	0xf13c
> > +#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8
> 	0xf140
> >
> >  #define S5P_FIMV_D_FIRST_PLANE_DPB_V8		0xf160
> >  #define S5P_FIMV_D_SECOND_PLANE_DPB_V8		0xf260
> > +#define S5P_FIMV_D_THIRD_PLANE_DPB_V8		0xf360
> >  #define S5P_FIMV_D_MV_BUFFER_V8			0xf460
> >
> >  #define S5P_FIMV_D_NUM_MV_V8			0xf134
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > index dd2e9f7704ab..9a39cccfe002 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
> > @@ -56,6 +56,7 @@
> >  #define MFC_NO_INSTANCE_SET	-1
> >  #define MFC_ENC_CAP_PLANE_COUNT	1
> >  #define MFC_ENC_OUT_PLANE_COUNT	2
> > +#define VB2_MAX_PLANE_COUNT	3
> >  #define STUFF_BYTE		4
> >  #define MFC_MAX_CTRLS		128
> >
> > @@ -181,6 +182,7 @@ struct s5p_mfc_buf {
> >  		struct {
> >  			size_t luma;
> >  			size_t chroma;
> > +			size_t chroma_1;
> >  		} raw;
> >  		size_t stream;
> >  	} cookie;
> > @@ -657,6 +659,7 @@ struct s5p_mfc_ctx {
> >
> >  	int luma_size;
> >  	int chroma_size;
> > +	int chroma_size_1;
> >  	int mv_size;
> >
> >  	unsigned long consumed_stream;
> > @@ -722,6 +725,7 @@ struct s5p_mfc_ctx {
> >  	size_t scratch_buf_size;
> >  	int is_10bit;
> >  	int is_422;
> > +	int stride[VB2_MAX_PLANE_COUNT];
> >  };
> >
> >  /*
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > index e219cbcd86d5..317f796fffa1 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
> > @@ -56,6 +56,20 @@ static struct s5p_mfc_fmt formats[] = {
> >  		.num_planes	= 2,
> >  		.versions	= MFC_V6PLUS_BITS,
> >  	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT,
> > +	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT
> > +	},
> >  	{
> >  		.fourcc		= V4L2_PIX_FMT_H264,
> >  		.codec_mode	= S5P_MFC_CODEC_H264_DEC,
> > @@ -359,10 +373,15 @@ static int vidioc_g_fmt(struct file *file, void *priv,
> struct v4l2_format *f)
> >  		/* Set pixelformat to the format in which MFC
> >  		   outputs the decoded frame */
> >  		pix_mp->pixelformat = ctx->dst_fmt->fourcc;
> > -		pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> > +		pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
> >  		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> > -		pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> > +		pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> >  		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
> > +			pix_mp->plane_fmt[2].sizeimage = ctx-
> >chroma_size_1;
> > +		}
> >  	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> >  		/* This is run on OUTPUT
> >  		   The buffer contains compressed image @@ -937,6 +956,9
> @@ static
> > int s5p_mfc_queue_setup(struct vb2_queue *vq,
> >  		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> >  		/* Output plane count is 2 - one for Y and one for CbCr */
> >  		*plane_count = 2;
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> 
> These misalignments produce a lot of checkpatch warnings.
> 
> Make sure you run your patch series through 'checkpatch.pl --strict'!
> 
> Regards,
> 
> 	Hans
> 
Thanks for pointing out. Will fix it in next series.

Thanks for the review.
> > +			*plane_count = 3;
> >  		/* Setup buffer count */
> >  		if (*buf_count < ctx->pb_count)
> >  			*buf_count = ctx->pb_count;
> > @@ -955,12 +977,17 @@ static int s5p_mfc_queue_setup(struct
> vb2_queue *vq,
> >  	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> >  		psize[0] = ctx->luma_size;
> >  		psize[1] = ctx->chroma_size;
> > -
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			psize[2] = ctx->chroma_size_1;
> >  		if (IS_MFCV6_PLUS(dev))
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
> >  		else
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
> >  		alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
> >  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
> >  		   ctx->state == MFCINST_INIT) {
> >  		psize[0] = ctx->dec_src_buf_size;
> > @@ -994,12 +1021,24 @@ static int s5p_mfc_buf_init(struct vb2_buffer
> *vb)
> >  			mfc_err("Plane buffer (CAPTURE) is too small\n");
> >  			return -EINVAL;
> >  		}
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
> > +				mfc_err("Plane buffer (CAPTURE) is too
> small\n");
> > +				return -EINVAL;
> > +			}
> > +		}
> >  		i = vb->index;
> >  		ctx->dst_bufs[i].b = vbuf;
> >  		ctx->dst_bufs[i].cookie.raw.luma =
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 0);
> >  		ctx->dst_bufs[i].cookie.raw.chroma =
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 1);
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			ctx->dst_bufs[i].cookie.raw.chroma_1 =
> > +
> 	vb2_dma_contig_plane_dma_addr(vb, 2);
> > +		}
> >  		ctx->dst_bufs_cnt++;
> >  	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
> >  		if (IS_ERR_OR_NULL(ERR_PTR(
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > index e4d6e7c117b5..0eec04eb3ef3 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
> > @@ -59,6 +59,20 @@ static struct s5p_mfc_fmt formats[] = {
> >  		.num_planes	= 2,
> >  		.versions	= MFC_V6PLUS_BITS,
> >  	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YUV420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT,
> > +	},
> > +	{
> > +		.fourcc         = V4L2_PIX_FMT_YVU420M,
> > +		.codec_mode     = S5P_MFC_CODEC_NONE,
> > +		.type           = MFC_FMT_RAW,
> > +		.num_planes     = 3,
> > +		.versions       = MFC_V12_BIT,
> > +	},
> >  	{
> >  		.fourcc		= V4L2_PIX_FMT_H264,
> >  		.codec_mode	= S5P_MFC_CODEC_H264_ENC,
> > @@ -1193,14 +1207,20 @@ static int enc_pre_frame_start(struct
> s5p_mfc_ctx *ctx)
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	struct s5p_mfc_buf *dst_mb;
> >  	struct s5p_mfc_buf *src_mb;
> > -	unsigned long src_y_addr, src_c_addr, dst_addr;
> > +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
> >  	unsigned int dst_size;
> >
> >  	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
> >  	src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b-
> >vb2_buf, 0);
> >  	src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b-
> >vb2_buf, 1);
> > +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		src_c_1_addr =
> > +			vb2_dma_contig_plane_dma_addr(&src_mb->b-
> >vb2_buf, 2);
> > +	else
> > +		src_c_1_addr = 0;
> >  	s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
> > -							src_y_addr,
> src_c_addr);
> > +					src_y_addr, src_c_addr,
> src_c_1_addr);
> >
> >  	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
> >  	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b-
> >vb2_buf, 0); @@
> > -1215,8 +1235,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx
> > *ctx)  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	struct s5p_mfc_buf *mb_entry;
> > -	unsigned long enc_y_addr = 0, enc_c_addr = 0;
> > -	unsigned long mb_y_addr, mb_c_addr;
> > +	unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0;
> > +	unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr;
> >  	int slice_type;
> >  	unsigned int strm_size;
> >  	bool src_ready;
> > @@ -1229,14 +1249,21 @@ static int enc_post_frame_start(struct
> s5p_mfc_ctx *ctx)
> >  		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
> >  	if (slice_type >= 0) {
> >  		s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer,
> ctx,
> > -				&enc_y_addr, &enc_c_addr);
> > +				&enc_y_addr, &enc_c_addr,
> &enc_c_1_addr);
> >  		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
> >  			mb_y_addr = vb2_dma_contig_plane_dma_addr(
> >  					&mb_entry->b->vb2_buf, 0);
> >  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
> >  					&mb_entry->b->vb2_buf, 1);
> > -			if ((enc_y_addr == mb_y_addr) &&
> > -						(enc_c_addr == mb_c_addr))
> {
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				mb_c_1_addr =
> vb2_dma_contig_plane_dma_addr
> > +						(&mb_entry->b->vb2_buf,
> 2);
> > +			else
> > +				mb_c_1_addr = 0;
> > +			if ((enc_y_addr == mb_y_addr)
> > +					&& (enc_c_addr == mb_c_addr)
> > +					&& (enc_c_1_addr ==
> mb_c_1_addr)) {
> >  				list_del(&mb_entry->list);
> >  				ctx->src_queue_cnt--;
> >  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> > @@ -1249,8 +1276,15 @@ static int enc_post_frame_start(struct
> s5p_mfc_ctx *ctx)
> >  					&mb_entry->b->vb2_buf, 0);
> >  			mb_c_addr = vb2_dma_contig_plane_dma_addr(
> >  					&mb_entry->b->vb2_buf, 1);
> > -			if ((enc_y_addr == mb_y_addr) &&
> > -						(enc_c_addr == mb_c_addr))
> {
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				mb_c_1_addr =
> vb2_dma_contig_plane_dma_addr(
> > +						&mb_entry->b->vb2_buf, 2);
> > +			else
> > +				mb_c_1_addr = 0;
> > +			if ((enc_y_addr == mb_y_addr)
> > +					&& (enc_c_addr == mb_c_addr)
> > +					&& (enc_c_1_addr ==
> mb_c_1_addr)) {
> >  				list_del(&mb_entry->list);
> >  				ctx->ref_queue_cnt--;
> >  				vb2_buffer_done(&mb_entry->b->vb2_buf,
> > @@ -1381,10 +1415,15 @@ static int vidioc_g_fmt(struct file *file, void
> *priv, struct v4l2_format *f)
> >  		pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
> >  		pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
> >
> > -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
> >  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> > -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> >  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx-
> >stride[2];
> > +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx-
> >chroma_size_1;
> > +		}
> >  	} else {
> >  		mfc_err("invalid buf type\n");
> >  		return -EINVAL;
> > @@ -1468,9 +1507,14 @@ static int vidioc_s_fmt(struct file *file, void
> > *priv, struct v4l2_format *f)
> >
> >  		s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
> >  		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
> > -		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
> >  		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
> > -		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
> > +		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			pix_fmt_mp->plane_fmt[2].bytesperline = ctx-
> >stride[2];
> > +			pix_fmt_mp->plane_fmt[2].sizeimage = ctx-
> >chroma_size_1;
> > +		}
> >
> >  		ctx->src_bufs_cnt = 0;
> >  		ctx->output_state = QUEUE_FREE;
> > @@ -2414,10 +2458,16 @@ static int s5p_mfc_queue_setup(struct
> > vb2_queue *vq,
> >
> >  		psize[0] = ctx->luma_size;
> >  		psize[1] = ctx->chroma_size;
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			psize[2] = ctx->chroma_size_1;
> >
> >  		if (IS_MFCV6_PLUS(dev)) {
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
> >  			alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				alloc_devs[2] = ctx->dev-
> >mem_dev[BANK_L_CTX];
> >  		} else {
> >  			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
> >  			alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
> @@ -2456,6 +2506,10
> > @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 0);
> >  		ctx->src_bufs[i].cookie.raw.chroma =
> >
> 	vb2_dma_contig_plane_dma_addr(vb, 1);
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			ctx->src_bufs[i].cookie.raw.chroma_1 =
> > +
> 	vb2_dma_contig_plane_dma_addr(vb, 2);
> >  		ctx->src_bufs_cnt++;
> >  	} else {
> >  		mfc_err("invalid queue type: %d\n", vq->type); @@ -2493,6
> +2547,12
> > @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
> >  			mfc_err("plane size is too small for output\n");
> >  			return -EINVAL;
> >  		}
> > +		if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +		     ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) &&
> > +		    (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) {
> > +			mfc_err("plane size is too small for output\n");
> > +			return -EINVAL;
> > +		}
> >  	} else {
> >  		mfc_err("invalid queue type: %d\n", vq->type);
> >  		return -EINVAL;
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > index 87ac56756a16..7c5e851c8191 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
> > @@ -293,9 +293,11 @@ struct s5p_mfc_hw_ops {
> >  	int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
> >  			unsigned long addr, unsigned int size);
> >  	void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> > -			unsigned long y_addr, unsigned long c_addr);
> > +			unsigned long y_addr, unsigned long c_addr,
> > +			unsigned long c_1_addr);
> >  	void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
> > -			unsigned long *y_addr, unsigned long *c_addr);
> > +			unsigned long *y_addr, unsigned long *c_addr,
> > +			unsigned long *c_1_addr);
> >  	void (*try_run)(struct s5p_mfc_dev *dev);
> >  	void (*clear_int_flags)(struct s5p_mfc_dev *dev);
> >  	int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); diff --git
> > a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > index 28a06dc343fd..fcfaf125a5a1 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
> > @@ -516,7 +516,8 @@ static int
> s5p_mfc_set_enc_stream_buffer_v5(struct
> > s5p_mfc_ctx *ctx,  }
> >
> >  static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> > -		unsigned long y_addr, unsigned long c_addr)
> > +		unsigned long y_addr, unsigned long c_addr,
> > +		unsigned long c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >
> > @@ -525,7 +526,8 @@ static void
> s5p_mfc_set_enc_frame_buffer_v5(struct
> > s5p_mfc_ctx *ctx,  }
> >
> >  static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
> > -		unsigned long *y_addr, unsigned long *c_addr)
> > +		unsigned long *y_addr, unsigned long *c_addr,
> > +		unsigned long *c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >
> > @@ -1210,7 +1212,7 @@ static int s5p_mfc_run_enc_frame(struct
> s5p_mfc_ctx *ctx)
> >  	if (list_empty(&ctx->src_queue)) {
> >  		/* send null frame */
> >  		s5p_mfc_set_enc_frame_buffer_v5(ctx, dev-
> >dma_base[BANK_R_CTX],
> > -						dev-
> >dma_base[BANK_R_CTX]);
> > +						dev-
> >dma_base[BANK_R_CTX], 0);
> >  		src_mb = NULL;
> >  	} else {
> >  		src_mb = list_entry(ctx->src_queue.next, struct
> s5p_mfc_buf, @@
> > -1220,7 +1222,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx
> *ctx)
> >  			/* send null frame */
> >  			s5p_mfc_set_enc_frame_buffer_v5(ctx,
> >  						dev-
> >dma_base[BANK_R_CTX],
> > -						dev-
> >dma_base[BANK_R_CTX]);
> > +						dev-
> >dma_base[BANK_R_CTX], 0);
> >  			ctx->state = MFCINST_FINISHING;
> >  		} else {
> >  			src_y_addr = vb2_dma_contig_plane_dma_addr(
> @@ -1228,7 +1230,7 @@
> > static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
> >  			src_c_addr = vb2_dma_contig_plane_dma_addr(
> >  					&src_mb->b->vb2_buf, 1);
> >  			s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr,
> > -								src_c_addr);
> > +								src_c_addr,
> 0);
> >  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
> >  				ctx->state = MFCINST_FINISHING;
> >  		}
> > diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > index fb3f0718821d..e579c765e902 100644
> > --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
> > @@ -494,16 +494,43 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct
> s5p_mfc_ctx *ctx)
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	ctx->buf_width = ALIGN(ctx->img_width,
> S5P_FIMV_NV12MT_HALIGN_V6);
> >  	ctx->buf_height = ALIGN(ctx->img_height,
> S5P_FIMV_NV12MT_VALIGN_V6);
> > +	ctx->chroma_size_1 = 0;
> >  	mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
> >  			"buffer dimensions: %dx%d\n", ctx->img_width,
> >  			ctx->img_height, ctx->buf_width, ctx->buf_height);
> >
> > -	ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
> > -	ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >>
> 1));
> > +	switch (ctx->dst_fmt->fourcc) {
> > +	case V4L2_PIX_FMT_NV12M:
> > +	case V4L2_PIX_FMT_NV21M:
> > +		ctx->stride[0] = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->stride[1] = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> > +		ctx->chroma_size = calc_plane(ctx->stride[1],
> > +					(ctx->img_height / 2));
> > +		break;
> > +	case V4L2_PIX_FMT_YUV420M:
> > +	case V4L2_PIX_FMT_YVU420M:
> > +		ctx->stride[0] = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->stride[1] = ALIGN(ctx->img_width / 2,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->stride[2] = ALIGN(ctx->img_width / 2,
> > +					S5P_FIMV_NV12MT_HALIGN_V6);
> > +		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
> > +		ctx->chroma_size = calc_plane(ctx->stride[1],
> > +					(ctx->img_height / 2));
> > +		ctx->chroma_size_1 = calc_plane(ctx->stride[2],
> > +					(ctx->img_height / 2));
> > +		break;
> > +	}
> > +
> >  	if (IS_MFCV8_PLUS(ctx->dev)) {
> >  		/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
> >  		ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> >  		ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> > +		ctx->chroma_size_1 +=
> S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
> >  	}
> >
> >  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || @@ -534,15
> +561,53
> > @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
> >  	mb_width = MB_WIDTH(ctx->img_width);
> >  	mb_height = MB_HEIGHT(ctx->img_height);
> >
> > -	ctx->buf_width = ALIGN(ctx->img_width,
> S5P_FIMV_NV12M_HALIGN_V6);
> > -	ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
> > -	ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
> > -
> > -	/* MFCv7 needs pad bytes for Luma and Chroma */
> > -	if (IS_MFCV7_PLUS(ctx->dev)) {
> > +	if (IS_MFCV12(ctx->dev)) {
> > +		switch (ctx->src_fmt->fourcc) {
> > +		case V4L2_PIX_FMT_NV12M:
> > +		case V4L2_PIX_FMT_NV21M:
> > +			ctx->stride[0] = ALIGN(ctx->img_width,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->stride[1] = ALIGN(ctx->img_width,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->luma_size = ctx->stride[0] *
> > +						ALIGN(ctx->img_height, 16);
> > +			ctx->chroma_size =  ctx->stride[0] *
> > +						ALIGN(ctx->img_height / 2,
> 16);
> > +			break;
> > +		case V4L2_PIX_FMT_YUV420M:
> > +		case V4L2_PIX_FMT_YVU420M:
> > +			ctx->stride[0] = ALIGN(ctx->img_width,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->stride[1] = ALIGN(ctx->img_width / 2,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->stride[2] = ALIGN(ctx->img_width / 2,
> > +
> 	S5P_FIMV_NV12M_HALIGN_V6);
> > +			ctx->luma_size = ctx->stride[0] *
> > +						ALIGN(ctx->img_height, 16);
> > +			ctx->chroma_size =  ctx->stride[1] *
> > +						ALIGN(ctx->img_height / 2,
> 16);
> > +			ctx->chroma_size_1 =  ctx->stride[2] *
> > +						ALIGN(ctx->img_height / 2,
> 16);
> > +			break;
> > +		}
> >  		ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> > -		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
> > +		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V12;
> > +		ctx->chroma_size_1 += MFC_CHROMA_PAD_BYTES_V12;
> > +	} else {
> > +		ctx->buf_width = ALIGN(ctx->img_width,
> > +					S5P_FIMV_NV12M_HALIGN_V6);
> > +		ctx->stride[0] = ctx->buf_width;
> > +		ctx->stride[1] = ctx->buf_width;
> > +		ctx->luma_size = ALIGN((mb_width * mb_height) * 256,
> 256);
> > +		ctx->chroma_size = ALIGN((mb_width * mb_height) * 128,
> 256);
> > +		ctx->chroma_size_1 = 0;
> > +		/* MFCv7 needs pad bytes for Luma and Chroma */
> > +		if (IS_MFCV7_PLUS(ctx->dev)) {
> > +			ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
> > +			ctx->chroma_size += MFC_LUMA_PAD_BYTES_V7;
> > +		}
> >  	}
> > +
> >  }
> >
> >  /* Set registers for decoding stream buffer */ @@ -588,15 +653,21 @@
> > static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
> >  	writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
> >  	writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
> >  	writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
> > -
> > +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +			ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		writel(ctx->chroma_size_1, mfc_regs-
> >d_third_plane_dpb_size);
> >  	writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
> >  	writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
> >
> >  	if (IS_MFCV8_PLUS(dev)) {
> > -		writel(ctx->img_width,
> > +		writel(ctx->stride[0],
> >  			mfc_regs->d_first_plane_dpb_stride_size);
> > -		writel(ctx->img_width,
> > +		writel(ctx->stride[1],
> >  			mfc_regs->d_second_plane_dpb_stride_size);
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			writel(ctx->stride[2],
> > +				mfc_regs->d_third_plane_dpb_stride_size);
> >  	}
> >
> >  	buf_addr1 += ctx->scratch_buf_size;
> > @@ -625,6 +696,13 @@ static int
> s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
> >  					ctx->dst_bufs[i].cookie.raw.chroma);
> >  		writel(ctx->dst_bufs[i].cookie.raw.chroma,
> >  				mfc_regs->d_second_plane_dpb + i * 4);
> > +		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->dst_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M) {
> > +			mfc_debug(2, "\tChroma_1 %d: %zx\n", i,
> > +					ctx-
> >dst_bufs[i].cookie.raw.chroma_1);
> > +			writel(ctx->dst_bufs[i].cookie.raw.chroma_1,
> > +					mfc_regs->d_third_plane_dpb + i *
> 4);
> > +		}
> >  	}
> >  	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
> >  			ctx->codec_mode ==
> S5P_MFC_CODEC_H264_MVC_DEC || @@ -683,20
> > +761,24 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct
> > s5p_mfc_ctx *ctx,  }
> >
> >  static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> > -		unsigned long y_addr, unsigned long c_addr)
> > +		unsigned long y_addr, unsigned long c_addr,
> > +		unsigned long c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
> >
> >  	writel(y_addr, mfc_regs->e_source_first_plane_addr);
> >  	writel(c_addr, mfc_regs->e_source_second_plane_addr);
> > +	writel(c_1_addr, mfc_regs->e_source_third_plane_addr);
> >
> >  	mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
> >  	mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
> > +	mfc_debug(2, "enc src cr buf addr: 0x%08lx\n", c_1_addr);
> >  }
> >
> >  static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
> > -		unsigned long *y_addr, unsigned long *c_addr)
> > +		unsigned long *y_addr, unsigned long *c_addr,
> > +		unsigned long *c_1_addr)
> >  {
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; @@ -704,12
> > +786,17 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct
> > s5p_mfc_ctx *ctx,
> >
> >  	*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
> >  	*c_addr = readl(mfc_regs-
> >e_encoded_source_second_plane_addr);
> > +	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		*c_1_addr = readl(mfc_regs-
> >e_encoded_source_third_plane_addr);
> > +	else
> > +		*c_1_addr = 0;
> >
> >  	enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
> >  	enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
> >
> >  	mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n",
> enc_recon_y_addr, *y_addr);
> > -	mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
> > +	mfc_debug(2, "recon c addr: 0x%08lx c_addr: 0x%08lx\n",
> > +enc_recon_c_addr, *c_addr);
> >  }
> >
> >  /* Set encoding ref & codec buffer */ @@ -886,6 +973,20 @@ static int
> > s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
> >  		writel(reg, mfc_regs->e_enc_options);
> >  		/* 0: NV12(CbCr), 1: NV21(CrCb) */
> >  		writel(0x0, mfc_regs->pixel_format);
> > +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
> > +		/* 0: Linear, 1: 2D tiled*/
> > +		reg = readl(mfc_regs->e_enc_options);
> > +		reg &= ~(0x1 << 7);
> > +		writel(reg, mfc_regs->e_enc_options);
> > +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> > +		writel(0x2, mfc_regs->pixel_format);
> > +	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M) {
> > +		/* 0: Linear, 1: 2D tiled*/
> > +		reg = readl(mfc_regs->e_enc_options);
> > +		reg &= ~(0x1 << 7);
> > +		writel(reg, mfc_regs->e_enc_options);
> > +		/* 2: YV12(CrCb), 3: I420(CrCb) */
> > +		writel(0x3, mfc_regs->pixel_format);
> >  	}
> >
> >  	/* memory structure recon. frame */
> > @@ -1696,8 +1797,12 @@ static int s5p_mfc_init_decode_v6(struct
> s5p_mfc_ctx *ctx)
> >  	else
> >  		writel(reg, mfc_regs->d_dec_options);
> >
> > -	/* 0: NV12(CbCr), 1: NV21(CrCb) */
> > -	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
> > +	/* 0: NV12(CbCr), 1: NV21(CrCb), 2: YV12(CrCb), 3: I420(CbCr) */
> > +	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M)
> > +		writel(0x3, mfc_regs->pixel_format);
> > +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
> > +		writel(0x2, mfc_regs->pixel_format);
> > +	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
> >  		writel(0x1, mfc_regs->pixel_format);
> >  	else
> >  		writel(0x0, mfc_regs->pixel_format); @@ -1781,8 +1886,12
> @@ static
> > int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
> >
> >  	/* Set stride lengths for v7 & above */
> >  	if (IS_MFCV7_PLUS(dev)) {
> > -		writel(ctx->img_width, mfc_regs-
> >e_source_first_plane_stride);
> > -		writel(ctx->img_width, mfc_regs-
> >e_source_second_plane_stride);
> > +		writel(ctx->stride[0], mfc_regs-
> >e_source_first_plane_stride);
> > +		writel(ctx->stride[1], mfc_regs-
> >e_source_second_plane_stride);
> > +		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +			writel(ctx->stride[2],
> > +					mfc_regs-
> >e_source_third_plane_stride);
> >  	}
> >
> >  	writel(ctx->inst_no, mfc_regs->instance_id); @@ -1891,7 +2000,7
> @@
> > static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
> >  	struct s5p_mfc_dev *dev = ctx->dev;
> >  	struct s5p_mfc_buf *dst_mb;
> >  	struct s5p_mfc_buf *src_mb;
> > -	unsigned long src_y_addr, src_c_addr, dst_addr;
> > +	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
> >  	/*
> >  	unsigned int src_y_size, src_c_size;
> >  	*/
> > @@ -1909,22 +2018,29 @@ static inline int s5p_mfc_run_enc_frame(struct
> > s5p_mfc_ctx *ctx)
> >
> >  	if (list_empty(&ctx->src_queue)) {
> >  		/* send null frame */
> > -		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> > +		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
> >  		src_mb = NULL;
> >  	} else {
> >  		src_mb = list_entry(ctx->src_queue.next, struct
> s5p_mfc_buf, list);
> >  		src_mb->flags |= MFC_BUF_FLAG_USED;
> >  		if (src_mb->b->vb2_buf.planes[0].bytesused == 0) {
> > -			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
> > +			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
> >  			ctx->state = MFCINST_FINISHING;
> >  		} else {
> >  			src_y_addr =
> vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
> >  			src_c_addr =
> vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf,
> > 1);
> > +			if (ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YUV420M ||
> > +				ctx->src_fmt->fourcc ==
> V4L2_PIX_FMT_YVU420M)
> > +				src_c_1_addr =
> vb2_dma_contig_plane_dma_addr
> > +						(&src_mb->b->vb2_buf, 2);
> > +			else
> > +				src_c_1_addr = 0;
> >
> >  			mfc_debug(2, "enc src y addr: 0x%08lx\n",
> src_y_addr);
> >  			mfc_debug(2, "enc src c addr: 0x%08lx\n",
> src_c_addr);
> >
> > -			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
> src_c_addr);
> > +			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
> > +						src_c_addr, src_c_1_addr);
> >  			if (src_mb->flags & MFC_BUF_FLAG_EOS)
> >  				ctx->state = MFCINST_FINISHING;
> >  		}
> > @@ -2450,6 +2566,8 @@ const struct s5p_mfc_regs
> *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
> >  			S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
> >  	R(e_encoded_source_second_plane_addr,
> >
> 	S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
> > +	R(e_encoded_source_third_plane_addr,
> > +			S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7);
> >  	R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
> >
> >  	if (!IS_MFCV8_PLUS(dev))
> > @@ -2464,16 +2582,20 @@ const struct s5p_mfc_regs
> *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
> >  	R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
> >  	R(d_first_plane_dpb_size,
> S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
> >  	R(d_second_plane_dpb_size,
> S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
> > +	R(d_third_plane_dpb_size,
> S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8);
> >  	R(d_scratch_buffer_addr,
> S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
> >  	R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
> >  	R(d_first_plane_dpb_stride_size,
> >  			S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
> >  	R(d_second_plane_dpb_stride_size,
> >
> 	S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
> > +	R(d_third_plane_dpb_stride_size,
> > +			S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8);
> >  	R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
> >  	R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
> >  	R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
> >  	R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
> > +	R(d_third_plane_dpb, S5P_FIMV_D_THIRD_PLANE_DPB_V8);
> >  	R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
> >  	R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
> >  	R(d_available_dpb_flag_lower,
> > S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);
diff mbox series

Patch

diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
index 6c68a45082d0..70464f47c1f9 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
@@ -26,6 +26,8 @@ 
 #define MFC_VERSION_V12			0xC0
 #define MFC_NUM_PORTS_V12		1
 #define S5P_FIMV_CODEC_VP9_ENC		27
+#define MFC_CHROMA_PAD_BYTES_V12        256
+#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V12 256
 
 /* Encoder buffer size for MFCv12 */
 #define ENC_V120_BASE_SIZE(x, y) \
diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
index 4a7adfdaa359..50f9bf0603c1 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
@@ -24,6 +24,7 @@ 
 
 #define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7		0xfa70
 #define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7	0xfa74
+#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7		0xfa78
 
 #define S5P_FIMV_E_VP8_OPTIONS_V7			0xfdb0
 #define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7		0xfdb4
diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
index 162e3c7e920f..0ef9eb2dff22 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
@@ -17,13 +17,16 @@ 
 #define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8	0xf108
 #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8	0xf144
 #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8	0xf148
+#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8	0xf14C
 #define S5P_FIMV_D_MV_BUFFER_SIZE_V8		0xf150
 
 #define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8	0xf138
 #define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8	0xf13c
+#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8	0xf140
 
 #define S5P_FIMV_D_FIRST_PLANE_DPB_V8		0xf160
 #define S5P_FIMV_D_SECOND_PLANE_DPB_V8		0xf260
+#define S5P_FIMV_D_THIRD_PLANE_DPB_V8		0xf360
 #define S5P_FIMV_D_MV_BUFFER_V8			0xf460
 
 #define S5P_FIMV_D_NUM_MV_V8			0xf134
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
index dd2e9f7704ab..9a39cccfe002 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
@@ -56,6 +56,7 @@ 
 #define MFC_NO_INSTANCE_SET	-1
 #define MFC_ENC_CAP_PLANE_COUNT	1
 #define MFC_ENC_OUT_PLANE_COUNT	2
+#define VB2_MAX_PLANE_COUNT	3
 #define STUFF_BYTE		4
 #define MFC_MAX_CTRLS		128
 
@@ -181,6 +182,7 @@  struct s5p_mfc_buf {
 		struct {
 			size_t luma;
 			size_t chroma;
+			size_t chroma_1;
 		} raw;
 		size_t stream;
 	} cookie;
@@ -657,6 +659,7 @@  struct s5p_mfc_ctx {
 
 	int luma_size;
 	int chroma_size;
+	int chroma_size_1;
 	int mv_size;
 
 	unsigned long consumed_stream;
@@ -722,6 +725,7 @@  struct s5p_mfc_ctx {
 	size_t scratch_buf_size;
 	int is_10bit;
 	int is_422;
+	int stride[VB2_MAX_PLANE_COUNT];
 };
 
 /*
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
index e219cbcd86d5..317f796fffa1 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
@@ -56,6 +56,20 @@  static struct s5p_mfc_fmt formats[] = {
 		.num_planes	= 2,
 		.versions	= MFC_V6PLUS_BITS,
 	},
+	{
+		.fourcc         = V4L2_PIX_FMT_YUV420M,
+		.codec_mode     = S5P_MFC_CODEC_NONE,
+		.type           = MFC_FMT_RAW,
+		.num_planes     = 3,
+		.versions       = MFC_V12_BIT,
+	},
+	{
+		.fourcc         = V4L2_PIX_FMT_YVU420M,
+		.codec_mode     = S5P_MFC_CODEC_NONE,
+		.type           = MFC_FMT_RAW,
+		.num_planes     = 3,
+		.versions       = MFC_V12_BIT
+	},
 	{
 		.fourcc		= V4L2_PIX_FMT_H264,
 		.codec_mode	= S5P_MFC_CODEC_H264_DEC,
@@ -359,10 +373,15 @@  static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 		/* Set pixelformat to the format in which MFC
 		   outputs the decoded frame */
 		pix_mp->pixelformat = ctx->dst_fmt->fourcc;
-		pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+		pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
 		pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
-		pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+		pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
 		pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+			pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
+			pix_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
+		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		/* This is run on OUTPUT
 		   The buffer contains compressed image
@@ -937,6 +956,9 @@  static int s5p_mfc_queue_setup(struct vb2_queue *vq,
 		   vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		/* Output plane count is 2 - one for Y and one for CbCr */
 		*plane_count = 2;
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			*plane_count = 3;
 		/* Setup buffer count */
 		if (*buf_count < ctx->pb_count)
 			*buf_count = ctx->pb_count;
@@ -955,12 +977,17 @@  static int s5p_mfc_queue_setup(struct vb2_queue *vq,
 	    vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		psize[0] = ctx->luma_size;
 		psize[1] = ctx->chroma_size;
-
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			psize[2] = ctx->chroma_size_1;
 		if (IS_MFCV6_PLUS(dev))
 			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
 		else
 			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
 		alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
 	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
 		   ctx->state == MFCINST_INIT) {
 		psize[0] = ctx->dec_src_buf_size;
@@ -994,12 +1021,24 @@  static int s5p_mfc_buf_init(struct vb2_buffer *vb)
 			mfc_err("Plane buffer (CAPTURE) is too small\n");
 			return -EINVAL;
 		}
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+			if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
+				mfc_err("Plane buffer (CAPTURE) is too small\n");
+				return -EINVAL;
+			}
+		}
 		i = vb->index;
 		ctx->dst_bufs[i].b = vbuf;
 		ctx->dst_bufs[i].cookie.raw.luma =
 					vb2_dma_contig_plane_dma_addr(vb, 0);
 		ctx->dst_bufs[i].cookie.raw.chroma =
 					vb2_dma_contig_plane_dma_addr(vb, 1);
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+			ctx->dst_bufs[i].cookie.raw.chroma_1 =
+					vb2_dma_contig_plane_dma_addr(vb, 2);
+		}
 		ctx->dst_bufs_cnt++;
 	} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
 		if (IS_ERR_OR_NULL(ERR_PTR(
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
index e4d6e7c117b5..0eec04eb3ef3 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
@@ -59,6 +59,20 @@  static struct s5p_mfc_fmt formats[] = {
 		.num_planes	= 2,
 		.versions	= MFC_V6PLUS_BITS,
 	},
+	{
+		.fourcc         = V4L2_PIX_FMT_YUV420M,
+		.codec_mode     = S5P_MFC_CODEC_NONE,
+		.type           = MFC_FMT_RAW,
+		.num_planes     = 3,
+		.versions       = MFC_V12_BIT,
+	},
+	{
+		.fourcc         = V4L2_PIX_FMT_YVU420M,
+		.codec_mode     = S5P_MFC_CODEC_NONE,
+		.type           = MFC_FMT_RAW,
+		.num_planes     = 3,
+		.versions       = MFC_V12_BIT,
+	},
 	{
 		.fourcc		= V4L2_PIX_FMT_H264,
 		.codec_mode	= S5P_MFC_CODEC_H264_ENC,
@@ -1193,14 +1207,20 @@  static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
 	struct s5p_mfc_dev *dev = ctx->dev;
 	struct s5p_mfc_buf *dst_mb;
 	struct s5p_mfc_buf *src_mb;
-	unsigned long src_y_addr, src_c_addr, dst_addr;
+	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
 	unsigned int dst_size;
 
 	src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
 	src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
 	src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
+	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+		src_c_1_addr =
+			vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 2);
+	else
+		src_c_1_addr = 0;
 	s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
-							src_y_addr, src_c_addr);
+					src_y_addr, src_c_addr, src_c_1_addr);
 
 	dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
 	dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
@@ -1215,8 +1235,8 @@  static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
 	struct s5p_mfc_buf *mb_entry;
-	unsigned long enc_y_addr = 0, enc_c_addr = 0;
-	unsigned long mb_y_addr, mb_c_addr;
+	unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0;
+	unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr;
 	int slice_type;
 	unsigned int strm_size;
 	bool src_ready;
@@ -1229,14 +1249,21 @@  static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
 		  mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
 	if (slice_type >= 0) {
 		s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
-				&enc_y_addr, &enc_c_addr);
+				&enc_y_addr, &enc_c_addr, &enc_c_1_addr);
 		list_for_each_entry(mb_entry, &ctx->src_queue, list) {
 			mb_y_addr = vb2_dma_contig_plane_dma_addr(
 					&mb_entry->b->vb2_buf, 0);
 			mb_c_addr = vb2_dma_contig_plane_dma_addr(
 					&mb_entry->b->vb2_buf, 1);
-			if ((enc_y_addr == mb_y_addr) &&
-						(enc_c_addr == mb_c_addr)) {
+			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+				mb_c_1_addr = vb2_dma_contig_plane_dma_addr
+						(&mb_entry->b->vb2_buf, 2);
+			else
+				mb_c_1_addr = 0;
+			if ((enc_y_addr == mb_y_addr)
+					&& (enc_c_addr == mb_c_addr)
+					&& (enc_c_1_addr == mb_c_1_addr)) {
 				list_del(&mb_entry->list);
 				ctx->src_queue_cnt--;
 				vb2_buffer_done(&mb_entry->b->vb2_buf,
@@ -1249,8 +1276,15 @@  static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
 					&mb_entry->b->vb2_buf, 0);
 			mb_c_addr = vb2_dma_contig_plane_dma_addr(
 					&mb_entry->b->vb2_buf, 1);
-			if ((enc_y_addr == mb_y_addr) &&
-						(enc_c_addr == mb_c_addr)) {
+			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+				mb_c_1_addr = vb2_dma_contig_plane_dma_addr(
+						&mb_entry->b->vb2_buf, 2);
+			else
+				mb_c_1_addr = 0;
+			if ((enc_y_addr == mb_y_addr)
+					&& (enc_c_addr == mb_c_addr)
+					&& (enc_c_1_addr == mb_c_1_addr)) {
 				list_del(&mb_entry->list);
 				ctx->ref_queue_cnt--;
 				vb2_buffer_done(&mb_entry->b->vb2_buf,
@@ -1381,10 +1415,15 @@  static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 		pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
 		pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
 
-		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
 		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
-		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
 		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+			pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
+			pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
+		}
 	} else {
 		mfc_err("invalid buf type\n");
 		return -EINVAL;
@@ -1468,9 +1507,14 @@  static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 
 		s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
 		pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
-		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+		pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
 		pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
-		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+		pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
+		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+			pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
+			pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
+		}
 
 		ctx->src_bufs_cnt = 0;
 		ctx->output_state = QUEUE_FREE;
@@ -2414,10 +2458,16 @@  static int s5p_mfc_queue_setup(struct vb2_queue *vq,
 
 		psize[0] = ctx->luma_size;
 		psize[1] = ctx->chroma_size;
+		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			psize[2] = ctx->chroma_size_1;
 
 		if (IS_MFCV6_PLUS(dev)) {
 			alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
 			alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
+			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+				alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
 		} else {
 			alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
 			alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
@@ -2456,6 +2506,10 @@  static int s5p_mfc_buf_init(struct vb2_buffer *vb)
 					vb2_dma_contig_plane_dma_addr(vb, 0);
 		ctx->src_bufs[i].cookie.raw.chroma =
 					vb2_dma_contig_plane_dma_addr(vb, 1);
+		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			ctx->src_bufs[i].cookie.raw.chroma_1 =
+					vb2_dma_contig_plane_dma_addr(vb, 2);
 		ctx->src_bufs_cnt++;
 	} else {
 		mfc_err("invalid queue type: %d\n", vq->type);
@@ -2493,6 +2547,12 @@  static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
 			mfc_err("plane size is too small for output\n");
 			return -EINVAL;
 		}
+		if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+		     ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) &&
+		    (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) {
+			mfc_err("plane size is too small for output\n");
+			return -EINVAL;
+		}
 	} else {
 		mfc_err("invalid queue type: %d\n", vq->type);
 		return -EINVAL;
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
index 87ac56756a16..7c5e851c8191 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
@@ -293,9 +293,11 @@  struct s5p_mfc_hw_ops {
 	int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
 			unsigned long addr, unsigned int size);
 	void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
-			unsigned long y_addr, unsigned long c_addr);
+			unsigned long y_addr, unsigned long c_addr,
+			unsigned long c_1_addr);
 	void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
-			unsigned long *y_addr, unsigned long *c_addr);
+			unsigned long *y_addr, unsigned long *c_addr,
+			unsigned long *c_1_addr);
 	void (*try_run)(struct s5p_mfc_dev *dev);
 	void (*clear_int_flags)(struct s5p_mfc_dev *dev);
 	int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev);
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
index 28a06dc343fd..fcfaf125a5a1 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
@@ -516,7 +516,8 @@  static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
 }
 
 static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
-		unsigned long y_addr, unsigned long c_addr)
+		unsigned long y_addr, unsigned long c_addr,
+		unsigned long c_1_addr)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
 
@@ -525,7 +526,8 @@  static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
 }
 
 static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
-		unsigned long *y_addr, unsigned long *c_addr)
+		unsigned long *y_addr, unsigned long *c_addr,
+		unsigned long *c_1_addr)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
 
@@ -1210,7 +1212,7 @@  static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 	if (list_empty(&ctx->src_queue)) {
 		/* send null frame */
 		s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX],
-						dev->dma_base[BANK_R_CTX]);
+						dev->dma_base[BANK_R_CTX], 0);
 		src_mb = NULL;
 	} else {
 		src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
@@ -1220,7 +1222,7 @@  static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 			/* send null frame */
 			s5p_mfc_set_enc_frame_buffer_v5(ctx,
 						dev->dma_base[BANK_R_CTX],
-						dev->dma_base[BANK_R_CTX]);
+						dev->dma_base[BANK_R_CTX], 0);
 			ctx->state = MFCINST_FINISHING;
 		} else {
 			src_y_addr = vb2_dma_contig_plane_dma_addr(
@@ -1228,7 +1230,7 @@  static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 			src_c_addr = vb2_dma_contig_plane_dma_addr(
 					&src_mb->b->vb2_buf, 1);
 			s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr,
-								src_c_addr);
+								src_c_addr, 0);
 			if (src_mb->flags & MFC_BUF_FLAG_EOS)
 				ctx->state = MFCINST_FINISHING;
 		}
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
index fb3f0718821d..e579c765e902 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
@@ -494,16 +494,43 @@  static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
 	struct s5p_mfc_dev *dev = ctx->dev;
 	ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
 	ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6);
+	ctx->chroma_size_1 = 0;
 	mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
 			"buffer dimensions: %dx%d\n", ctx->img_width,
 			ctx->img_height, ctx->buf_width, ctx->buf_height);
 
-	ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
-	ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
+	switch (ctx->dst_fmt->fourcc) {
+	case V4L2_PIX_FMT_NV12M:
+	case V4L2_PIX_FMT_NV21M:
+		ctx->stride[0] = ALIGN(ctx->img_width,
+					S5P_FIMV_NV12MT_HALIGN_V6);
+		ctx->stride[1] = ALIGN(ctx->img_width,
+					S5P_FIMV_NV12MT_HALIGN_V6);
+		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
+		ctx->chroma_size = calc_plane(ctx->stride[1],
+					(ctx->img_height / 2));
+		break;
+	case V4L2_PIX_FMT_YUV420M:
+	case V4L2_PIX_FMT_YVU420M:
+		ctx->stride[0] = ALIGN(ctx->img_width,
+					S5P_FIMV_NV12MT_HALIGN_V6);
+		ctx->stride[1] = ALIGN(ctx->img_width / 2,
+					S5P_FIMV_NV12MT_HALIGN_V6);
+		ctx->stride[2] = ALIGN(ctx->img_width / 2,
+					S5P_FIMV_NV12MT_HALIGN_V6);
+		ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
+		ctx->chroma_size = calc_plane(ctx->stride[1],
+					(ctx->img_height / 2));
+		ctx->chroma_size_1 = calc_plane(ctx->stride[2],
+					(ctx->img_height / 2));
+		break;
+	}
+
 	if (IS_MFCV8_PLUS(ctx->dev)) {
 		/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
 		ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
 		ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
+		ctx->chroma_size_1 += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
 	}
 
 	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
@@ -534,15 +561,53 @@  static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
 	mb_width = MB_WIDTH(ctx->img_width);
 	mb_height = MB_HEIGHT(ctx->img_height);
 
-	ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
-	ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
-	ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
-
-	/* MFCv7 needs pad bytes for Luma and Chroma */
-	if (IS_MFCV7_PLUS(ctx->dev)) {
+	if (IS_MFCV12(ctx->dev)) {
+		switch (ctx->src_fmt->fourcc) {
+		case V4L2_PIX_FMT_NV12M:
+		case V4L2_PIX_FMT_NV21M:
+			ctx->stride[0] = ALIGN(ctx->img_width,
+						S5P_FIMV_NV12M_HALIGN_V6);
+			ctx->stride[1] = ALIGN(ctx->img_width,
+						S5P_FIMV_NV12M_HALIGN_V6);
+			ctx->luma_size = ctx->stride[0] *
+						ALIGN(ctx->img_height, 16);
+			ctx->chroma_size =  ctx->stride[0] *
+						ALIGN(ctx->img_height / 2, 16);
+			break;
+		case V4L2_PIX_FMT_YUV420M:
+		case V4L2_PIX_FMT_YVU420M:
+			ctx->stride[0] = ALIGN(ctx->img_width,
+						S5P_FIMV_NV12M_HALIGN_V6);
+			ctx->stride[1] = ALIGN(ctx->img_width / 2,
+						S5P_FIMV_NV12M_HALIGN_V6);
+			ctx->stride[2] = ALIGN(ctx->img_width / 2,
+						S5P_FIMV_NV12M_HALIGN_V6);
+			ctx->luma_size = ctx->stride[0] *
+						ALIGN(ctx->img_height, 16);
+			ctx->chroma_size =  ctx->stride[1] *
+						ALIGN(ctx->img_height / 2, 16);
+			ctx->chroma_size_1 =  ctx->stride[2] *
+						ALIGN(ctx->img_height / 2, 16);
+			break;
+		}
 		ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
-		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
+		ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V12;
+		ctx->chroma_size_1 += MFC_CHROMA_PAD_BYTES_V12;
+	} else {
+		ctx->buf_width = ALIGN(ctx->img_width,
+					S5P_FIMV_NV12M_HALIGN_V6);
+		ctx->stride[0] = ctx->buf_width;
+		ctx->stride[1] = ctx->buf_width;
+		ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
+		ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
+		ctx->chroma_size_1 = 0;
+		/* MFCv7 needs pad bytes for Luma and Chroma */
+		if (IS_MFCV7_PLUS(ctx->dev)) {
+			ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
+			ctx->chroma_size += MFC_LUMA_PAD_BYTES_V7;
+		}
 	}
+
 }
 
 /* Set registers for decoding stream buffer */
@@ -588,15 +653,21 @@  static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
 	writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
 	writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
 	writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
-
+	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+			ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+		writel(ctx->chroma_size_1, mfc_regs->d_third_plane_dpb_size);
 	writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
 	writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
 
 	if (IS_MFCV8_PLUS(dev)) {
-		writel(ctx->img_width,
+		writel(ctx->stride[0],
 			mfc_regs->d_first_plane_dpb_stride_size);
-		writel(ctx->img_width,
+		writel(ctx->stride[1],
 			mfc_regs->d_second_plane_dpb_stride_size);
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			writel(ctx->stride[2],
+				mfc_regs->d_third_plane_dpb_stride_size);
 	}
 
 	buf_addr1 += ctx->scratch_buf_size;
@@ -625,6 +696,13 @@  static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
 					ctx->dst_bufs[i].cookie.raw.chroma);
 		writel(ctx->dst_bufs[i].cookie.raw.chroma,
 				mfc_regs->d_second_plane_dpb + i * 4);
+		if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+			mfc_debug(2, "\tChroma_1 %d: %zx\n", i,
+					ctx->dst_bufs[i].cookie.raw.chroma_1);
+			writel(ctx->dst_bufs[i].cookie.raw.chroma_1,
+					mfc_regs->d_third_plane_dpb + i * 4);
+		}
 	}
 	if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
 			ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC ||
@@ -683,20 +761,24 @@  static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
 }
 
 static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
-		unsigned long y_addr, unsigned long c_addr)
+		unsigned long y_addr, unsigned long c_addr,
+		unsigned long c_1_addr)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
 
 	writel(y_addr, mfc_regs->e_source_first_plane_addr);
 	writel(c_addr, mfc_regs->e_source_second_plane_addr);
+	writel(c_1_addr, mfc_regs->e_source_third_plane_addr);
 
 	mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
 	mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
+	mfc_debug(2, "enc src cr buf addr: 0x%08lx\n", c_1_addr);
 }
 
 static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
-		unsigned long *y_addr, unsigned long *c_addr)
+		unsigned long *y_addr, unsigned long *c_addr,
+		unsigned long *c_1_addr)
 {
 	struct s5p_mfc_dev *dev = ctx->dev;
 	const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
@@ -704,12 +786,17 @@  static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
 
 	*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
 	*c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
+	if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+			ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+		*c_1_addr = readl(mfc_regs->e_encoded_source_third_plane_addr);
+	else
+		*c_1_addr = 0;
 
 	enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
 	enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
 
 	mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n", enc_recon_y_addr, *y_addr);
-	mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
+	mfc_debug(2, "recon c addr: 0x%08lx c_addr: 0x%08lx\n", enc_recon_c_addr, *c_addr);
 }
 
 /* Set encoding ref & codec buffer */
@@ -886,6 +973,20 @@  static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
 		writel(reg, mfc_regs->e_enc_options);
 		/* 0: NV12(CbCr), 1: NV21(CrCb) */
 		writel(0x0, mfc_regs->pixel_format);
+	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+		/* 0: Linear, 1: 2D tiled*/
+		reg = readl(mfc_regs->e_enc_options);
+		reg &= ~(0x1 << 7);
+		writel(reg, mfc_regs->e_enc_options);
+		/* 2: YV12(CrCb), 3: I420(CrCb) */
+		writel(0x2, mfc_regs->pixel_format);
+	} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M) {
+		/* 0: Linear, 1: 2D tiled*/
+		reg = readl(mfc_regs->e_enc_options);
+		reg &= ~(0x1 << 7);
+		writel(reg, mfc_regs->e_enc_options);
+		/* 2: YV12(CrCb), 3: I420(CrCb) */
+		writel(0x3, mfc_regs->pixel_format);
 	}
 
 	/* memory structure recon. frame */
@@ -1696,8 +1797,12 @@  static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
 	else
 		writel(reg, mfc_regs->d_dec_options);
 
-	/* 0: NV12(CbCr), 1: NV21(CrCb) */
-	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
+	/* 0: NV12(CbCr), 1: NV21(CrCb), 2: YV12(CrCb), 3: I420(CbCr) */
+	if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M)
+		writel(0x3, mfc_regs->pixel_format);
+	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+		writel(0x2, mfc_regs->pixel_format);
+	else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
 		writel(0x1, mfc_regs->pixel_format);
 	else
 		writel(0x0, mfc_regs->pixel_format);
@@ -1781,8 +1886,12 @@  static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
 
 	/* Set stride lengths for v7 & above */
 	if (IS_MFCV7_PLUS(dev)) {
-		writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
-		writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
+		writel(ctx->stride[0], mfc_regs->e_source_first_plane_stride);
+		writel(ctx->stride[1], mfc_regs->e_source_second_plane_stride);
+		if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+			writel(ctx->stride[2],
+					mfc_regs->e_source_third_plane_stride);
 	}
 
 	writel(ctx->inst_no, mfc_regs->instance_id);
@@ -1891,7 +2000,7 @@  static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 	struct s5p_mfc_dev *dev = ctx->dev;
 	struct s5p_mfc_buf *dst_mb;
 	struct s5p_mfc_buf *src_mb;
-	unsigned long src_y_addr, src_c_addr, dst_addr;
+	unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
 	/*
 	unsigned int src_y_size, src_c_size;
 	*/
@@ -1909,22 +2018,29 @@  static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
 
 	if (list_empty(&ctx->src_queue)) {
 		/* send null frame */
-		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
+		s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
 		src_mb = NULL;
 	} else {
 		src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
 		src_mb->flags |= MFC_BUF_FLAG_USED;
 		if (src_mb->b->vb2_buf.planes[0].bytesused == 0) {
-			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
+			s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
 			ctx->state = MFCINST_FINISHING;
 		} else {
 			src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
 			src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
+			if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+				ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+				src_c_1_addr = vb2_dma_contig_plane_dma_addr
+						(&src_mb->b->vb2_buf, 2);
+			else
+				src_c_1_addr = 0;
 
 			mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr);
 			mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr);
 
-			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr);
+			s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr,
+						src_c_addr, src_c_1_addr);
 			if (src_mb->flags & MFC_BUF_FLAG_EOS)
 				ctx->state = MFCINST_FINISHING;
 		}
@@ -2450,6 +2566,8 @@  const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
 			S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
 	R(e_encoded_source_second_plane_addr,
 			S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
+	R(e_encoded_source_third_plane_addr,
+			S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7);
 	R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
 
 	if (!IS_MFCV8_PLUS(dev))
@@ -2464,16 +2582,20 @@  const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
 	R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
 	R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
 	R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
+	R(d_third_plane_dpb_size, S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8);
 	R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
 	R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
 	R(d_first_plane_dpb_stride_size,
 			S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
 	R(d_second_plane_dpb_stride_size,
 			S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
+	R(d_third_plane_dpb_stride_size,
+			S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8);
 	R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
 	R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
 	R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
 	R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
+	R(d_third_plane_dpb, S5P_FIMV_D_THIRD_PLANE_DPB_V8);
 	R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
 	R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
 	R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);