diff --git a/drivers/media/platform/imx8/mxc-jpeg.c b/drivers/media/platform/imx8/mxc-jpeg.c
index 58ac99c86d5f7861c416d828dbe9e8b7c3566a2f..cddf227950cb4e15529028f70c8e0ee3639bd44f 100644
--- a/drivers/media/platform/imx8/mxc-jpeg.c
+++ b/drivers/media/platform/imx8/mxc-jpeg.c
@@ -395,11 +395,8 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
 	desc->buf_base0 = vb2_dma_contig_plane_dma_addr(b_base0_buf, 0);
 	desc->buf_base1 = 0;
 	if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) {
-		u32 h = desc->imgsize & 0xFFFF;
-		u32 w = (desc->imgsize >> 16) & 0xFFFF;
-		u32 luma_plane_size =  w * h;
-
-		desc->buf_base1 = desc->buf_base0 + luma_plane_size;
+		WARN_ON(b_base0_buf->num_planes < 2);
+		desc->buf_base1 = vb2_dma_contig_plane_dma_addr(b_base0_buf, 1);
 	}
 	desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(bufbase_buf, 0) +
 		offset;
@@ -426,6 +423,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
 	u32 dec_ret;
 	unsigned long payload_size;
 	struct mxc_jpeg_q_data *q_data;
+	enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	int slot = 0; /* TODO remove hardcoded slot 0 */
 
 	spin_lock(&jpeg->hw_lock);
@@ -479,11 +477,17 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
 		dev_dbg(dev, "Encoding finished, payload_size: %ld\n",
 			payload_size);
 	} else {
-		q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		q_data = mxc_jpeg_get_q_data(ctx, cap_type);
 		payload_size = q_data->sizeimage[0];
 		vb2_set_plane_payload(dst_buf, 0, payload_size);
-		dev_dbg(dev, "Decoding finished, payload_size: %ld\n",
-			payload_size);
+		vb2_set_plane_payload(dst_buf, 1, 0);
+		if (q_data->fmt->colplanes == 2) {
+			payload_size = q_data->sizeimage[1];
+			vb2_set_plane_payload(dst_buf, 1, payload_size);
+		}
+		dev_dbg(dev, "Decoding finished, payload_size: %ld + %ld\n",
+			vb2_get_plane_payload(dst_buf, 0),
+			vb2_get_plane_payload(dst_buf, 1));
 	}
 
 	/* short preview of the results */
@@ -714,18 +718,21 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
 {
 	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
 	struct mxc_jpeg_q_data *q_data = NULL;
+	int i;
 
 	q_data = mxc_jpeg_get_q_data(ctx, q->type);
 	if (!q_data)
 		return -EINVAL;
-	*num_planes = 1;
 
-	/* assuming worst case jpeg compression: 6 x raw file size */
-	sizes[0] = q_data->w * q_data->h * 6;
+	*num_planes = q_data->fmt->colplanes;
 
-	if (q_data->sizeimage[0] > 0)
-		sizes[0] = q_data->sizeimage[0];
+	for (i = 0; i < *num_planes; i++) {
+		/* assuming worst case jpeg compression: 6 x raw file size */
+		sizes[i] = q_data->w * q_data->h * 6;
 
+		if (q_data->sizeimage[i] > 0)
+			sizes[i] = q_data->sizeimage[i];
+	}
 	return 0;
 }
 static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
@@ -901,6 +908,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 {
 	struct device *dev = ctx->mxc_jpeg->dev;
 	struct mxc_jpeg_q_data *q_data_out, *q_data_cap;
+	enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	struct mxc_jpeg_stream stream;
 	bool notfound = true;
 	struct mxc_jpeg_sof sof;
@@ -936,7 +944,8 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 			notfound = true;
 		}
 	}
-	q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	q_data_out = mxc_jpeg_get_q_data(ctx,
+					 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
 	if (sof.width != q_data_out->w || sof.height != q_data_out->h) {
 		dev_err(dev,
 			"Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
@@ -973,7 +982,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 		return -EINVAL;
 	}
 
-	q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type);
 	if (q_data_cap->w == 0 && q_data_cap->h == 0) {
 		dev_dbg(dev, "capture queue format is not set-up yet, using output queue settings");
 		q_data_cap->w = q_data_out->w;
@@ -997,6 +1006,11 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 	q_data_cap->stride = desc->line_pitch;
 	q_data_cap->sizeimage[0] = q_data_cap->w * q_data_cap->h *
 					q_data_cap->fmt->depth / 8;
+	q_data_cap->sizeimage[1] = 0;
+	if (q_data_cap->fmt->fourcc == V4L2_PIX_FMT_NV12) {
+		q_data_cap->sizeimage[0] = q_data_cap->sizeimage[0] * 2 / 3;
+		q_data_cap->sizeimage[1] = q_data_cap->sizeimage[0] / 2;
+	}
 
 	return 0;
 }
@@ -1008,10 +1022,10 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
 	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	int slot = 0; /* TODO get slot*/
 
-	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
 		goto end;
 
-	/* for V4L2_BUF_TYPE_VIDEO_OUTPUT */
+	/* for V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE */
 	if (ctx->mode != MXC_JPEG_DECODE)
 		goto end;
 	ret = mxc_jpeg_parse(ctx,
@@ -1044,18 +1058,22 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
 {
 	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	struct mxc_jpeg_q_data *q_data = NULL;
+	struct device *dev = ctx->mxc_jpeg->dev;
 	unsigned long sizeimage;
+	int i;
 
 	q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type);
 	if (!q_data)
 		return -EINVAL;
-	sizeimage = q_data->sizeimage[0];
-	if (vb2_plane_size(vb, 0) < sizeimage) {
-		dev_err(ctx->mxc_jpeg->dev, "buffer too small (%lu < %lu)",
-			 vb2_plane_size(vb, 0), sizeimage);
-		return -EINVAL;
+	for (i = 0; i < q_data->fmt->colplanes; i++) {
+		sizeimage = q_data->sizeimage[i];
+		if (vb2_plane_size(vb, i) < sizeimage) {
+			dev_err(dev, "plane %d too small (%lu < %lu)",
+				i, vb2_plane_size(vb, i), sizeimage);
+			return -EINVAL;
+		}
+		vb2_set_plane_payload(vb, i, sizeimage);
 	}
-	vb2_set_plane_payload(vb, 0, sizeimage);
 	return 0;
 }
 
@@ -1080,7 +1098,7 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
 	struct mxc_jpeg_ctx *ctx = priv;
 	int ret;
 
-	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 	src_vq->drv_priv = ctx;
 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
@@ -1095,7 +1113,7 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
 	if (ret)
 		return ret;
 
-	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
 	dst_vq->drv_priv = ctx;
 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
@@ -1246,7 +1264,7 @@ static int mxc_jpeg_querycap(struct file *file, void *priv,
 	strlcpy(cap->card, MXC_JPEG_NAME " decoder", sizeof(cap->card));
 	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
 		 dev_name(mxc_jpeg->dev));
-	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
+	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
 	return 0;
@@ -1301,10 +1319,12 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
 			    struct mxc_jpeg_ctx *ctx, int q_type)
 {
 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
-	struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
+	struct v4l2_plane_pix_format *pfmt;
 	u32 w = pix_mp->width;
 	u32 h = pix_mp->height;
 	unsigned int mode = ctx->mode;
+	int i;
+	bool is_nv12 = (fmt->fourcc == V4L2_PIX_FMT_NV12);
 
 	memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
 	pix_mp->field = V4L2_FIELD_NONE;
@@ -1319,25 +1339,39 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
 					MXC_JPEG_MAX_HEIGHT,
 					MXC_JPEG_H_ALIGN);
 
-	memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
-
-	/* TODO try_fmt should not modify the state, move to s_fmt */
-	if (q_type == MXC_JPEG_FMT_TYPE_ENC && mode == MXC_JPEG_DECODE) {
-		pfmt->bytesperline = 0;
-		/* Source size must be aligned to 128 */
-		pfmt->sizeimage = mxc_jpeg_align(pfmt->sizeimage, 128);
-		if (pfmt->sizeimage == 0)
-			pfmt->sizeimage = MXC_JPEG_DEFAULT_SIZEIMAGE;
-	} else if (q_type == MXC_JPEG_FMT_TYPE_RAW && mode == MXC_JPEG_DECODE) {
-		pfmt->bytesperline = w * (fmt->depth / 8);
-		pfmt->sizeimage = w * h * fmt->depth / 8;
-	} else if (q_type == MXC_JPEG_FMT_TYPE_ENC && mode == MXC_JPEG_ENCODE) {
-		pfmt->bytesperline = 0;
-		/* assuming worst jpeg compression */
-		pfmt->sizeimage = w * h * 6;
-	} else { /* MXC_JPEG_FMT_TYPE_RAW && MXC_JPEG_ENCODE */
-		pfmt->bytesperline = w * (fmt->depth / 8);
-		pfmt->sizeimage = w * h * fmt->depth / 8;
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		pfmt = &pix_mp->plane_fmt[i];
+		memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+
+		/* TODO try_fmt should not modify the state, move to s_fmt */
+		if (q_type == MXC_JPEG_FMT_TYPE_ENC &&
+		    mode == MXC_JPEG_DECODE) {
+			pfmt->bytesperline = 0;
+			/* Source size must be aligned to 128 */
+			pfmt->sizeimage = mxc_jpeg_align(pfmt->sizeimage, 128);
+			if (pfmt->sizeimage == 0)
+				pfmt->sizeimage = MXC_JPEG_DEFAULT_SIZEIMAGE;
+		} else if (q_type == MXC_JPEG_FMT_TYPE_RAW &&
+		    mode == MXC_JPEG_DECODE) {
+			pfmt->bytesperline = w * (fmt->depth / 8);
+			pfmt->sizeimage = w * h * fmt->depth / 8;
+			if (is_nv12 && i == 0) /* luma plane */
+				pfmt->sizeimage = pfmt->sizeimage * 2 / 3;
+			else if (is_nv12 && i == 1) /* chroma plane */
+				pfmt->sizeimage = pfmt->sizeimage * 1 / 3;
+		} else if (q_type == MXC_JPEG_FMT_TYPE_ENC &&
+		    mode == MXC_JPEG_ENCODE) {
+			pfmt->bytesperline = 0;
+			/* assuming worst jpeg compression */
+			pfmt->sizeimage = w * h * 6;
+		} else { /* MXC_JPEG_FMT_TYPE_RAW && MXC_JPEG_ENCODE */
+			pfmt->bytesperline = w * (fmt->depth / 8);
+			pfmt->sizeimage = w * h * fmt->depth / 8;
+			if (is_nv12 && i == 0) /* luma plane */
+				pfmt->sizeimage = pfmt->sizeimage * 2 / 3;
+			else if (is_nv12 && i == 1) /* chroma plane */
+				pfmt->sizeimage = pfmt->sizeimage * 1 / 3;
+		}
 	}
 
 	return 0;
@@ -1395,6 +1429,7 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
 	struct mxc_jpeg_q_data *q_data = NULL;
 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
 	struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+	int i;
 
 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
 	if (!vq)
@@ -1410,9 +1445,10 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
 	q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat);
 	q_data->w = pix_mp->width;
 	q_data->h = pix_mp->height;
-	q_data->bytesperline[0] = pix_mp->plane_fmt[0].bytesperline;
-	q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
-
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
+		q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+	}
 	return 0;
 }
 static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
@@ -1441,16 +1477,20 @@ static int mxc_jpeg_g_fmt_vid_cap(struct file *file, void *priv,
 				struct v4l2_format *f)
 {
 	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
-	struct v4l2_pix_format   *pix = &f->fmt.pix;
+	struct v4l2_pix_format_mplane   *pix_mp = &f->fmt.pix_mp;
 	struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type);
+	int i;
 
-	pix->pixelformat = q_data->fmt->fourcc;
-	pix->width = q_data->w;
-	pix->height = q_data->h;
-	pix->field = V4L2_FIELD_NONE;
-	pix->colorspace = V4L2_COLORSPACE_REC709;
-	pix->bytesperline = q_data->stride;
-	pix->sizeimage = q_data->sizeimage[0];
+	pix_mp->pixelformat = q_data->fmt->fourcc;
+	pix_mp->width = q_data->w;
+	pix_mp->height = q_data->h;
+	pix_mp->field = V4L2_FIELD_NONE;
+	pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+	pix_mp->num_planes = q_data->fmt->colplanes;
+	for (i = 0; i < pix_mp->num_planes; i++) {
+		pix_mp->plane_fmt[i].bytesperline = q_data->stride;
+		pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+	}
 
 	return 0;
 }
@@ -1513,17 +1553,17 @@ static int mxc_jpeg_dqbuf(struct file *file, void *priv,
 }
 static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
 	.vidioc_querycap		= mxc_jpeg_querycap,
-	.vidioc_enum_fmt_vid_cap	= mxc_jpeg_enum_fmt_vid_cap,
-	.vidioc_enum_fmt_vid_out	= mxc_jpeg_enum_fmt_vid_out,
+	.vidioc_enum_fmt_vid_cap_mplane	= mxc_jpeg_enum_fmt_vid_cap,
+	.vidioc_enum_fmt_vid_out_mplane	= mxc_jpeg_enum_fmt_vid_out,
 
-	.vidioc_try_fmt_vid_cap		= mxc_jpeg_try_fmt_vid_cap,
-	.vidioc_try_fmt_vid_out		= mxc_jpeg_try_fmt_vid_out,
+	.vidioc_try_fmt_vid_cap_mplane		= mxc_jpeg_try_fmt_vid_cap,
+	.vidioc_try_fmt_vid_out_mplane		= mxc_jpeg_try_fmt_vid_out,
 
-	.vidioc_s_fmt_vid_cap		= mxc_jpeg_s_fmt_vid_cap,
-	.vidioc_s_fmt_vid_out		= mxc_jpeg_s_fmt_vid_out,
+	.vidioc_s_fmt_vid_cap_mplane		= mxc_jpeg_s_fmt_vid_cap,
+	.vidioc_s_fmt_vid_out_mplane		= mxc_jpeg_s_fmt_vid_out,
 
-	.vidioc_g_fmt_vid_cap		= mxc_jpeg_g_fmt_vid_cap,
-	.vidioc_g_fmt_vid_out		= mxc_jpeg_g_fmt_vid_out,
+	.vidioc_g_fmt_vid_cap_mplane		= mxc_jpeg_g_fmt_vid_cap,
+	.vidioc_g_fmt_vid_out_mplane		= mxc_jpeg_g_fmt_vid_out,
 
 	.vidioc_subscribe_event		= mxc_jpeg_subscribe_event,
 	.vidioc_decoder_cmd		= mxc_jpeg_decoder_cmd,
@@ -1666,7 +1706,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
 	jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
 	jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
 	jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
-					V4L2_CAP_VIDEO_M2M;
+					V4L2_CAP_VIDEO_M2M_MPLANE;
 
 	ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, -1);
 	if (ret) {
diff --git a/drivers/media/platform/imx8/mxc-jpeg.h b/drivers/media/platform/imx8/mxc-jpeg.h
index d1e12948412785b8ce335fdea15760091439061c..9f039264b093007098446651d5809f84f9a29426 100644
--- a/drivers/media/platform/imx8/mxc-jpeg.h
+++ b/drivers/media/platform/imx8/mxc-jpeg.h
@@ -37,6 +37,7 @@
 #define SOF0				0xC0
 #define SOF2				0xC2
 #define MXC_JPEG_ENC_CONF_DONE		1
+#define MXC_JPEG_MAX_PLANES		2
 
 
 /**
@@ -73,8 +74,8 @@ struct mxc_jpeg_desc {
 
 struct mxc_jpeg_q_data {
 	struct mxc_jpeg_fmt	*fmt;
-	u32			sizeimage[1];
-	u32			bytesperline[2];
+	u32			sizeimage[MXC_JPEG_MAX_PLANES];
+	u32			bytesperline[MXC_JPEG_MAX_PLANES];
 	int w;
 	int h;
 	u32			stride;