diff --git a/drivers/media/platform/imx8/mxc-jpeg.c b/drivers/media/platform/imx8/mxc-jpeg.c
index a1d515a95eab4fd4acf8818df4cc4de695905fa4..5334df40c71f903db2416aaa34af0a8f3e5f0c64 100644
--- a/drivers/media/platform/imx8/mxc-jpeg.c
+++ b/drivers/media/platform/imx8/mxc-jpeg.c
@@ -367,6 +367,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
 	void __iomem *reg = jpeg->base_reg;
 	struct device *dev = jpeg->dev;
 	struct vb2_buffer *src_buf, *dst_buf;
+	enum vb2_buffer_state buf_state;
 	u32 dec_ret;
 	unsigned long payload_size;
 	struct mxc_jpeg_q_data *q_data;
@@ -380,28 +381,35 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
 			 "Instance released before the end of transaction.\n");
 		goto job_unlock;
 	}
+
+	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
 	if (ctx->aborting) {
 		dev_warn(dev, "Aborting current job\n");
 		mxc_jpeg_sw_reset(reg);
-		goto job_finish;
+		buf_state = VB2_BUF_STATE_ERROR;
+		goto buffers_done;
 	}
 
 	dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
 	writel(dec_ret, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); /* w1c */
+
+	if (dec_ret & SLOTa_STATUS_ENC_CONFIG_ERR) {
+		u32 ret = readl(reg + CAST_STATUS12);
+
+		dev_err(dev, "Encoder/decoder error, status=0x%08x", ret);
+		mxc_jpeg_sw_reset(reg);
+		buf_state = VB2_BUF_STATE_ERROR;
+		goto buffers_done;
+	}
+
 	if (!(dec_ret & SLOTa_STATUS_FRMDONE))
 		goto job_unlock;
 
-	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
-	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
-
 	if (ctx->mode == MXC_JPEG_ENCODE
 	    && ctx->enc_state == MXC_JPEG_ENC_CONF) {
 		ctx->enc_state = MXC_JPEG_ENC_DONE;
-		if (dec_ret & SLOTa_STATUS_ENC_CONFIG_ERR) {
-			dev_err(dev, "Encoder config finished with errors.\n");
-			goto job_finish;
-		}
-
 		dev_dbg(dev, "Encoder config finished. Start encoding...\n");
 		goto job_unlock;
 	}
@@ -423,12 +431,13 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
 	print_buf(dev, src_buf);
 	dev_dbg(dev, "dst_buf preview: ");
 	print_buf(dev, dst_buf);
+	buf_state = VB2_BUF_STATE_DONE;
 
+buffers_done:
 	v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
 	v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), VB2_BUF_STATE_DONE);
-	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_DONE);
-job_finish:
+	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
+	v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
 	v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
 job_unlock:
 	spin_unlock(&jpeg->hw_lock);
@@ -584,6 +593,27 @@ end:
 	spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
 }
 
+static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
+			      struct v4l2_decoder_cmd *cmd)
+{
+	struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(file->private_data);
+	struct device *dev = ctx->mxc_jpeg->dev;
+
+	switch (cmd->cmd) {
+	case V4L2_DEC_CMD_STOP:
+		dev_dbg(dev, "Received V4L2_DEC_CMD_STOP");
+		/*
+		 * TODO, provide actual implementation if needed,
+		 * for now, just silence vb2_warn_zero_bytesused
+		 * because allow_zero_bytesused flag is set
+		 */
+		return 0;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int mxc_jpeg_job_ready(void *priv)
 {
 	struct mxc_jpeg_ctx *ctx = priv;
@@ -637,16 +667,31 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
 	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
 	int ret;
 
-	dev_dbg(ctx->mxc_jpeg->dev, "Start streaming\n");
+	dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx);
 	ret = pm_runtime_get_sync(ctx->mxc_jpeg->dev);
 	return ret > 0 ? 0 : ret;
 }
 
+static void release_active_buffers(struct vb2_queue *q, enum vb2_buffer_state s)
+{
+	struct vb2_buffer *vb;
+
+	if (!list_empty(&q->queued_list))
+		list_for_each_entry(vb, &q->queued_list, queued_entry) {
+			if (vb->state == VB2_BUF_STATE_ACTIVE)
+				vb2_buffer_done(vb, s);
+		}
+}
+
 static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
 {
 	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
 
-	dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming\n");
+	dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming ctx=%p", ctx);
+
+	/* Release all active buffers */
+	release_active_buffers(q, VB2_BUF_STATE_ERROR);
+
 	pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev);
 }
 struct mxc_jpeg_stream {
@@ -789,7 +834,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 	struct mxc_jpeg_desc *desc, u8 *src_addr, u32 size)
 {
 	struct device *dev = ctx->mxc_jpeg->dev;
-	struct mxc_jpeg_q_data *q_data;
+	struct mxc_jpeg_q_data *q_data_out, *q_data_cap;
 	struct mxc_jpeg_stream stream;
 	bool notfound = true;
 	struct mxc_jpeg_sof sof;
@@ -825,11 +870,11 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 			notfound = true;
 		}
 	}
-	q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	if (sof.width != q_data->w || sof.height != q_data->h) {
+	q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+	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)",
-			sof.width, sof.height, q_data->w, q_data->h);
+			sof.width, sof.height, q_data_out->w, q_data_out->h);
 		return -EINVAL;
 	}
 	if (sof.width % 8 != 0 || sof.height % 8 != 0) {
@@ -862,9 +907,16 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 		return -EINVAL;
 	}
 
-	if (fourcc != q_data->fmt->fourcc) {
+	q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	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;
+		q_data_cap->h = q_data_out->h;
+		q_data_cap->fmt = mxc_jpeg_find_format(ctx, fourcc);
+	}
+	if (fourcc != q_data_cap->fmt->fourcc) {
 		char *jpeg_format_name = fourcc_to_str(fourcc);
-		char *user_format_name = fourcc_to_str(q_data->fmt->fourcc);
+		char *user_format_name = fourcc_to_str(q_data_cap->fmt->fourcc);
 
 		dev_warn(dev,
 			 "Pixel format mismatch: jpeg(%s) versus user (%s)",
@@ -872,12 +924,13 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
 		dev_warn(dev, "Keeping user settings\n");
 		kfree(jpeg_format_name);
 		kfree(user_format_name);
-		img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
+		img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data_cap->fmt->fourcc);
 	}
 	desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt);
 	desc->line_pitch = mxc_jpeg_get_line_pitch(dev, &sof, img_fmt);
-	q_data->stride = desc->line_pitch;
-	q_data->sizeimage[0] = sof.width * sof.height;
+	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;
 
 	return 0;
 }
@@ -888,12 +941,11 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 	int slot = 0; /* TODO get slot*/
-	struct mxc_jpeg_q_data *q_data;
-	int decoded_jpeg_size;
 
-	if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+	if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		goto end;
 
+	/* for V4L2_BUF_TYPE_VIDEO_OUTPUT */
 	if (ctx->mode != MXC_JPEG_DECODE)
 		goto end;
 	ret = mxc_jpeg_parse(ctx,
@@ -907,10 +959,6 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
 		return;
 	}
 
-	q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-	decoded_jpeg_size = q_data->w * q_data->h * q_data->fmt->depth / 8;
-	if (q_data->sizeimage[0] != decoded_jpeg_size)
-		q_data->sizeimage[0] = decoded_jpeg_size;
 
 	if (ctx->state == MXC_JPEG_INIT) {
 		struct vb2_queue *dst_vq = v4l2_m2m_get_vq(
@@ -933,12 +981,18 @@ 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;
+	unsigned long sizeimage;
 
 	q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type);
 	if (!q_data)
 		return -EINVAL;
-
-	vb2_set_plane_payload(vb, 0, q_data->sizeimage[0]);
+	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;
+	}
+	vb2_set_plane_payload(vb, 0, sizeimage);
 	return 0;
 }
 
@@ -972,6 +1026,7 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	src_vq->lock = &ctx->mxc_jpeg->lock;
 	src_vq->dev = ctx->mxc_jpeg->dev;
+	src_vq->allow_zero_bytesused = 1; /* keep old userspace apps working */
 
 	ret = vb2_queue_init(src_vq);
 	if (ret)
@@ -1201,7 +1256,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
 					MXC_JPEG_MIN_HEIGHT,
 					MXC_JPEG_MAX_HEIGHT,
 					MXC_JPEG_H_ALIGN))
-		dev_warn(dev, "Image was aligned to %dx%d", w, h);
+		dev_dbg(dev, "Image was aligned to %dx%d", w, h);
 
 	memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
 
@@ -1324,6 +1379,18 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
 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 mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type);
+
+	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->bytesperline[0];
+	pix->sizeimage = q_data->sizeimage[0];
+
 	return 0;
 }
 static int mxc_jpeg_g_fmt_vid_out(struct file *file, void *priv,
@@ -1332,6 +1399,19 @@ static int mxc_jpeg_g_fmt_vid_out(struct file *file, void *priv,
 	return 0;
 }
 
+static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh,
+		const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	case V4L2_EVENT_SOURCE_CHANGE:
+		return v4l2_src_change_event_subscribe(fh, sub);
+	default:
+		return -EINVAL;
+	}
+}
+
 static int mxc_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 {
 	struct v4l2_fh *fh = file->private_data;
@@ -1367,6 +1447,9 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
 	.vidioc_g_fmt_vid_cap		= mxc_jpeg_g_fmt_vid_cap,
 	.vidioc_g_fmt_vid_out		= mxc_jpeg_g_fmt_vid_out,
 
+	.vidioc_subscribe_event		= mxc_jpeg_subscribe_event,
+	.vidioc_decoder_cmd		= mxc_jpeg_decoder_cmd,
+
 	.vidioc_qbuf			= mxc_jpeg_qbuf,
 
 	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,