These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / media / platform / s5p-jpeg / jpeg-core.c
index bfbf157..4a608cb 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/string.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/v4l2-ioctl.h>
-#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
 #include <media/videobuf2-dma-contig.h>
 
 #include "jpeg-core.h"
@@ -626,6 +626,7 @@ static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
                        return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
                return exynos3250_decoded_subsampling[ctx->subsampling];
        case SJPEG_EXYNOS4:
+       case SJPEG_EXYNOS5433:
                if (ctx->subsampling > 2)
                        return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
                return exynos4x12_decoded_subsampling[ctx->subsampling];
@@ -750,6 +751,208 @@ static void exynos4_jpeg_set_huff_tbl(void __iomem *base)
                                                        ARRAY_SIZE(hactblg0));
 }
 
+static inline int __exynos4_huff_tbl(int class, int id, bool lenval)
+{
+       /*
+        * class: 0 - DC, 1 - AC
+        * id: 0 - Y, 1 - Cb/Cr
+        */
+       if (class) {
+               if (id)
+                       return lenval ? EXYNOS4_HUFF_TBL_HACCL :
+                               EXYNOS4_HUFF_TBL_HACCV;
+               return lenval ? EXYNOS4_HUFF_TBL_HACLL : EXYNOS4_HUFF_TBL_HACLV;
+
+       }
+       /* class == 0 */
+       if (id)
+               return lenval ? EXYNOS4_HUFF_TBL_HDCCL : EXYNOS4_HUFF_TBL_HDCCV;
+
+       return lenval ? EXYNOS4_HUFF_TBL_HDCLL : EXYNOS4_HUFF_TBL_HDCLV;
+}
+
+static inline int exynos4_huff_tbl_len(int class, int id)
+{
+       return __exynos4_huff_tbl(class, id, true);
+}
+
+static inline int exynos4_huff_tbl_val(int class, int id)
+{
+       return __exynos4_huff_tbl(class, id, false);
+}
+
+static int get_byte(struct s5p_jpeg_buffer *buf);
+static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word);
+static void skip(struct s5p_jpeg_buffer *buf, long len);
+
+static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
+{
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       struct s5p_jpeg_buffer jpeg_buffer;
+       unsigned int word;
+       int c, x, components;
+
+       jpeg_buffer.size = 2; /* Ls */
+       jpeg_buffer.data =
+               (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sos + 2;
+       jpeg_buffer.curr = 0;
+
+       word = 0;
+
+       if (get_word_be(&jpeg_buffer, &word))
+               return;
+       jpeg_buffer.size = (long)word - 2;
+       jpeg_buffer.data += 2;
+       jpeg_buffer.curr = 0;
+
+       components = get_byte(&jpeg_buffer);
+       if (components == -1)
+               return;
+       while (components--) {
+               c = get_byte(&jpeg_buffer);
+               if (c == -1)
+                       return;
+               x = get_byte(&jpeg_buffer);
+               if (x == -1)
+                       return;
+               exynos4_jpeg_select_dec_h_tbl(jpeg->regs, c,
+                                       (((x >> 4) & 0x1) << 1) | (x & 0x1));
+       }
+
+}
+
+static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx)
+{
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       struct s5p_jpeg_buffer jpeg_buffer;
+       unsigned int word;
+       int c, i, n, j;
+
+       for (j = 0; j < ctx->out_q.dht.n; ++j) {
+               jpeg_buffer.size = ctx->out_q.dht.len[j];
+               jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
+                                  ctx->out_q.dht.marker[j];
+               jpeg_buffer.curr = 0;
+
+               word = 0;
+               while (jpeg_buffer.curr < jpeg_buffer.size) {
+                       char id, class;
+
+                       c = get_byte(&jpeg_buffer);
+                       if (c == -1)
+                               return;
+                       id = c & 0xf;
+                       class = (c >> 4) & 0xf;
+                       n = 0;
+                       for (i = 0; i < 16; ++i) {
+                               c = get_byte(&jpeg_buffer);
+                               if (c == -1)
+                                       return;
+                               word |= c << ((i % 4) * 8);
+                               if ((i + 1) % 4 == 0) {
+                                       writel(word, jpeg->regs +
+                                       exynos4_huff_tbl_len(class, id) +
+                                       (i / 4) * 4);
+                                       word = 0;
+                               }
+                               n += c;
+                       }
+                       word = 0;
+                       for (i = 0; i < n; ++i) {
+                               c = get_byte(&jpeg_buffer);
+                               if (c == -1)
+                                       return;
+                               word |= c << ((i % 4) * 8);
+                               if ((i + 1) % 4 == 0) {
+                                       writel(word, jpeg->regs +
+                                       exynos4_huff_tbl_val(class, id) +
+                                       (i / 4) * 4);
+                                       word = 0;
+                               }
+                       }
+                       if (i % 4) {
+                               writel(word, jpeg->regs +
+                               exynos4_huff_tbl_val(class, id) + (i / 4) * 4);
+                       }
+                       word = 0;
+               }
+       }
+}
+
+static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx)
+{
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       struct s5p_jpeg_buffer jpeg_buffer;
+       int c, x, components;
+
+       jpeg_buffer.size = ctx->out_q.sof_len;
+       jpeg_buffer.data =
+               (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof;
+       jpeg_buffer.curr = 0;
+
+       skip(&jpeg_buffer, 5); /* P, Y, X */
+       components = get_byte(&jpeg_buffer);
+       if (components == -1)
+               return;
+
+       exynos4_jpeg_set_dec_components(jpeg->regs, components);
+
+       while (components--) {
+               c = get_byte(&jpeg_buffer);
+               if (c == -1)
+                       return;
+               skip(&jpeg_buffer, 1);
+               x = get_byte(&jpeg_buffer);
+               if (x == -1)
+                       return;
+               exynos4_jpeg_select_dec_q_tbl(jpeg->regs, c, x);
+       }
+}
+
+static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx)
+{
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       struct s5p_jpeg_buffer jpeg_buffer;
+       unsigned int word;
+       int c, i, j;
+
+       for (j = 0; j < ctx->out_q.dqt.n; ++j) {
+               jpeg_buffer.size = ctx->out_q.dqt.len[j];
+               jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) +
+                                  ctx->out_q.dqt.marker[j];
+               jpeg_buffer.curr = 0;
+
+               word = 0;
+               while (jpeg_buffer.size - jpeg_buffer.curr >= 65) {
+                       char id;
+
+                       c = get_byte(&jpeg_buffer);
+                       if (c == -1)
+                               return;
+                       id = c & 0xf;
+                       /* nonzero means extended mode - not supported */
+                       if ((c >> 4) & 0xf)
+                               return;
+                       for (i = 0; i < 64; ++i) {
+                               c = get_byte(&jpeg_buffer);
+                               if (c == -1)
+                                       return;
+                               word |= c << ((i % 4) * 8);
+                               if ((i + 1) % 4 == 0) {
+                                       writel(word, jpeg->regs +
+                                       EXYNOS4_QTBL_CONTENT(id) + (i / 4) * 4);
+                                       word = 0;
+                               }
+                       }
+                       word = 0;
+               }
+       }
+}
+
 /*
  * ============================================================================
  * Device file operations
@@ -894,8 +1097,11 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
                               unsigned long buffer, unsigned long size,
                               struct s5p_jpeg_ctx *ctx)
 {
-       int c, components = 0, notfound;
-       unsigned int height, width, word, subsampling = 0;
+       int c, components = 0, notfound, n_dht = 0, n_dqt = 0;
+       unsigned int height, width, word, subsampling = 0, sos = 0, sof = 0,
+                    sof_len = 0;
+       unsigned int dht[S5P_JPEG_MAX_MARKER], dht_len[S5P_JPEG_MAX_MARKER],
+                    dqt[S5P_JPEG_MAX_MARKER], dqt_len[S5P_JPEG_MAX_MARKER];
        long length;
        struct s5p_jpeg_buffer jpeg_buffer;
 
@@ -904,7 +1110,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
        jpeg_buffer.curr = 0;
 
        notfound = 1;
-       while (notfound) {
+       while (notfound || !sos) {
                c = get_byte(&jpeg_buffer);
                if (c == -1)
                        return false;
@@ -923,6 +1129,11 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
                case SOF0:
                        if (get_word_be(&jpeg_buffer, &word))
                                break;
+                       length = (long)word - 2;
+                       if (!length)
+                               return false;
+                       sof = jpeg_buffer.curr; /* after 0xffc0 */
+                       sof_len = length;
                        if (get_byte(&jpeg_buffer) == -1)
                                break;
                        if (get_word_be(&jpeg_buffer, &height))
@@ -932,7 +1143,6 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
                        components = get_byte(&jpeg_buffer);
                        if (components == -1)
                                break;
-                       notfound = 0;
 
                        if (components == 1) {
                                subsampling = 0x33;
@@ -941,8 +1151,40 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
                                subsampling = get_byte(&jpeg_buffer);
                                skip(&jpeg_buffer, 1);
                        }
-
+                       if (components > 3)
+                               return false;
                        skip(&jpeg_buffer, components * 2);
+                       notfound = 0;
+                       break;
+
+               case DQT:
+                       if (get_word_be(&jpeg_buffer, &word))
+                               break;
+                       length = (long)word - 2;
+                       if (!length)
+                               return false;
+                       if (n_dqt >= S5P_JPEG_MAX_MARKER)
+                               return false;
+                       dqt[n_dqt] = jpeg_buffer.curr; /* after 0xffdb */
+                       dqt_len[n_dqt++] = length;
+                       skip(&jpeg_buffer, length);
+                       break;
+
+               case DHT:
+                       if (get_word_be(&jpeg_buffer, &word))
+                               break;
+                       length = (long)word - 2;
+                       if (!length)
+                               return false;
+                       if (n_dht >= S5P_JPEG_MAX_MARKER)
+                               return false;
+                       dht[n_dht] = jpeg_buffer.curr; /* after 0xffc4 */
+                       dht_len[n_dht++] = length;
+                       skip(&jpeg_buffer, length);
+                       break;
+
+               case SOS:
+                       sos = jpeg_buffer.curr - 2; /* 0xffda */
                        break;
 
                /* skip payload-less markers */
@@ -963,7 +1205,20 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
        }
        result->w = width;
        result->h = height;
-       result->size = components;
+       result->sos = sos;
+       result->dht.n = n_dht;
+       while (n_dht--) {
+               result->dht.marker[n_dht] = dht[n_dht];
+               result->dht.len[n_dht] = dht_len[n_dht];
+       }
+       result->dqt.n = n_dqt;
+       while (n_dqt--) {
+               result->dqt.marker[n_dqt] = dqt[n_dqt];
+               result->dqt.len[n_dqt] = dqt_len[n_dqt];
+       }
+       result->sof = sof;
+       result->sof_len = sof_len;
+       result->size = result->components = components;
 
        switch (subsampling) {
        case 0x11:
@@ -982,7 +1237,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
                return false;
        }
 
-       return !notfound;
+       return !notfound && sos;
 }
 
 static int s5p_jpeg_querycap(struct file *file, void *priv,
@@ -1226,8 +1481,7 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
                return -EINVAL;
        }
 
-       if ((ctx->jpeg->variant->version != SJPEG_EXYNOS4) ||
-           (ctx->mode != S5P_JPEG_DECODE))
+       if (!ctx->jpeg->variant->hw_ex4_compat || ctx->mode != S5P_JPEG_DECODE)
                goto exit;
 
        /*
@@ -1350,7 +1604,7 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
                 * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
                 * page fault calculate proper buffer size in such a case.
                 */
-               if (ct->jpeg->variant->version == SJPEG_EXYNOS4 &&
+               if (ct->jpeg->variant->hw_ex4_compat &&
                    f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
                        q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
                                                        f,
@@ -1889,9 +2143,36 @@ static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
                vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 
        jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+       if (jpeg->variant->version == SJPEG_EXYNOS5433 &&
+           ctx->mode == S5P_JPEG_DECODE)
+               jpeg_addr += ctx->out_q.sos;
        exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
 }
 
+static inline void exynos4_jpeg_set_img_fmt(void __iomem *base,
+                                           unsigned int img_fmt)
+{
+       __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS4);
+}
+
+static inline void exynos5433_jpeg_set_img_fmt(void __iomem *base,
+                                              unsigned int img_fmt)
+{
+       __exynos4_jpeg_set_img_fmt(base, img_fmt, SJPEG_EXYNOS5433);
+}
+
+static inline void exynos4_jpeg_set_enc_out_fmt(void __iomem *base,
+                                               unsigned int out_fmt)
+{
+       __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS4);
+}
+
+static inline void exynos5433_jpeg_set_enc_out_fmt(void __iomem *base,
+                                                  unsigned int out_fmt)
+{
+       __exynos4_jpeg_set_enc_out_fmt(base, out_fmt, SJPEG_EXYNOS5433);
+}
+
 static void exynos4_jpeg_device_run(void *priv)
 {
        struct s5p_jpeg_ctx *ctx = priv;
@@ -1899,11 +2180,11 @@ static void exynos4_jpeg_device_run(void *priv)
        unsigned int bitstream_size;
        unsigned long flags;
 
-       spin_lock_irqsave(&ctx->jpeg->slock, flags);
+       spin_lock_irqsave(&jpeg->slock, flags);
 
        if (ctx->mode == S5P_JPEG_ENCODE) {
                exynos4_jpeg_sw_reset(jpeg->regs);
-               exynos4_jpeg_set_interrupt(jpeg->regs);
+               exynos4_jpeg_set_interrupt(jpeg->regs, jpeg->variant->version);
                exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
 
                exynos4_jpeg_set_huff_tbl(jpeg->regs);
@@ -1920,27 +2201,56 @@ static void exynos4_jpeg_device_run(void *priv)
                exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
                                                        ctx->cap_q.h);
 
-               exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
-               exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
+               if (ctx->jpeg->variant->version == SJPEG_EXYNOS4) {
+                       exynos4_jpeg_set_enc_out_fmt(jpeg->regs,
+                                                    ctx->subsampling);
+                       exynos4_jpeg_set_img_fmt(jpeg->regs,
+                                                ctx->out_q.fmt->fourcc);
+               } else {
+                       exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
+                                                       ctx->subsampling);
+                       exynos5433_jpeg_set_img_fmt(jpeg->regs,
+                                                   ctx->out_q.fmt->fourcc);
+               }
                exynos4_jpeg_set_img_addr(ctx);
                exynos4_jpeg_set_jpeg_addr(ctx);
                exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
                                                        ctx->out_q.fmt->fourcc);
        } else {
                exynos4_jpeg_sw_reset(jpeg->regs);
-               exynos4_jpeg_set_interrupt(jpeg->regs);
+               exynos4_jpeg_set_interrupt(jpeg->regs,
+                                          jpeg->variant->version);
                exynos4_jpeg_set_img_addr(ctx);
                exynos4_jpeg_set_jpeg_addr(ctx);
-               exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
 
-               bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
+               if (jpeg->variant->version == SJPEG_EXYNOS5433) {
+                       exynos4_jpeg_parse_huff_tbl(ctx);
+                       exynos4_jpeg_parse_decode_h_tbl(ctx);
+
+                       exynos4_jpeg_parse_q_tbl(ctx);
+                       exynos4_jpeg_parse_decode_q_tbl(ctx);
+
+                       exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
+
+                       exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
+                                       ctx->cap_q.h);
+                       exynos5433_jpeg_set_enc_out_fmt(jpeg->regs,
+                                                       ctx->subsampling);
+                       exynos5433_jpeg_set_img_fmt(jpeg->regs,
+                                                   ctx->cap_q.fmt->fourcc);
+                       bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 16);
+               } else {
+                       exynos4_jpeg_set_img_fmt(jpeg->regs,
+                                                ctx->cap_q.fmt->fourcc);
+                       bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
+               }
 
                exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
        }
 
        exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
 
-       spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+       spin_unlock_irqrestore(&jpeg->slock, flags);
 }
 
 static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
@@ -2120,7 +2430,7 @@ static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
  */
 
 static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
-                          const struct v4l2_format *fmt,
+                          const void *parg,
                           unsigned int *nbuffers, unsigned int *nplanes,
                           unsigned int sizes[], void *alloc_ctxs[])
 {
@@ -2170,6 +2480,7 @@ static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb)
 
 static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
 {
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
 
        if (ctx->mode == S5P_JPEG_DECODE &&
@@ -2187,13 +2498,24 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
                q_data = &ctx->out_q;
                q_data->w = tmp.w;
                q_data->h = tmp.h;
+               q_data->sos = tmp.sos;
+               memcpy(q_data->dht.marker, tmp.dht.marker,
+                      sizeof(tmp.dht.marker));
+               memcpy(q_data->dht.len, tmp.dht.len, sizeof(tmp.dht.len));
+               q_data->dht.n = tmp.dht.n;
+               memcpy(q_data->dqt.marker, tmp.dqt.marker,
+                      sizeof(tmp.dqt.marker));
+               memcpy(q_data->dqt.len, tmp.dqt.len, sizeof(tmp.dqt.len));
+               q_data->dqt.n = tmp.dqt.n;
+               q_data->sof = tmp.sof;
+               q_data->sof_len = tmp.sof_len;
 
                q_data = &ctx->cap_q;
                q_data->w = tmp.w;
                q_data->h = tmp.h;
        }
 
-       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
 }
 
 static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
@@ -2264,7 +2586,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
 {
        struct s5p_jpeg *jpeg = dev_id;
        struct s5p_jpeg_ctx *curr_ctx;
-       struct vb2_buffer *src_buf, *dst_buf;
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
        unsigned long payload_size = 0;
        enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
        bool enc_jpeg_too_large = false;
@@ -2298,15 +2620,15 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
                payload_size = s5p_jpeg_compressed_size(jpeg->regs);
        }
 
-       dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
-       dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
-       dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-       dst_buf->v4l2_buf.flags |=
-               src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+       dst_buf->timecode = src_buf->timecode;
+       dst_buf->timestamp = src_buf->timestamp;
+       dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+       dst_buf->flags |=
+               src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
 
        v4l2_m2m_buf_done(src_buf, state);
        if (curr_ctx->mode == S5P_JPEG_ENCODE)
-               vb2_set_plane_payload(dst_buf, 0, payload_size);
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
        v4l2_m2m_buf_done(dst_buf, state);
        v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
 
@@ -2321,7 +2643,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
 static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
 {
        unsigned int int_status;
-       struct vb2_buffer *src_vb, *dst_vb;
+       struct vb2_v4l2_buffer *src_vb, *dst_vb;
        struct s5p_jpeg *jpeg = priv;
        struct s5p_jpeg_ctx *curr_ctx;
        unsigned long payload_size = 0;
@@ -2363,7 +2685,8 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
        if (jpeg->irq_ret == OK_ENC_OR_DEC) {
                if (curr_ctx->mode == S5P_JPEG_ENCODE) {
                        payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
-                       vb2_set_plane_payload(dst_vb, 0, payload_size);
+                       vb2_set_plane_payload(&dst_vb->vb2_buf,
+                                       0, payload_size);
                }
                v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
                v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
@@ -2373,7 +2696,8 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
        }
 
        v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
-       curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
+       if (jpeg->variant->version == SJPEG_EXYNOS4)
+               curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
 
        spin_unlock(&jpeg->slock);
        return IRQ_HANDLED;
@@ -2383,7 +2707,7 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
 {
        struct s5p_jpeg *jpeg = dev_id;
        struct s5p_jpeg_ctx *curr_ctx;
-       struct vb2_buffer *src_buf, *dst_buf;
+       struct vb2_v4l2_buffer *src_buf, *dst_buf;
        unsigned long payload_size = 0;
        enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
        bool interrupt_timeout = false;
@@ -2427,12 +2751,12 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
        src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
        dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
 
-       dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
-       dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+       dst_buf->timecode = src_buf->timecode;
+       dst_buf->timestamp = src_buf->timestamp;
 
        v4l2_m2m_buf_done(src_buf, state);
        if (curr_ctx->mode == S5P_JPEG_ENCODE)
-               vb2_set_plane_payload(dst_buf, 0, payload_size);
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload_size);
        v4l2_m2m_buf_done(dst_buf, state);
        v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
 
@@ -2455,7 +2779,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 {
        struct s5p_jpeg *jpeg;
        struct resource *res;
-       int ret;
+       int i, ret;
 
        /* JPEG IP abstraction struct */
        jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
@@ -2490,23 +2814,21 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        }
 
        /* clocks */
-       jpeg->clk = clk_get(&pdev->dev, "jpeg");
-       if (IS_ERR(jpeg->clk)) {
-               dev_err(&pdev->dev, "cannot get clock\n");
-               ret = PTR_ERR(jpeg->clk);
-               return ret;
+       for (i = 0; i < jpeg->variant->num_clocks; i++) {
+               jpeg->clocks[i] = devm_clk_get(&pdev->dev,
+                                             jpeg->variant->clk_names[i]);
+               if (IS_ERR(jpeg->clocks[i])) {
+                       dev_err(&pdev->dev, "failed to get clock: %s\n",
+                               jpeg->variant->clk_names[i]);
+                       return PTR_ERR(jpeg->clocks[i]);
+               }
        }
-       dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
-
-       jpeg->sclk = clk_get(&pdev->dev, "sclk");
-       if (IS_ERR(jpeg->sclk))
-               dev_info(&pdev->dev, "sclk clock not available\n");
 
        /* v4l2 device */
        ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to register v4l2 device\n");
-               goto clk_get_rollback;
+               return ret;
        }
 
        /* mem2mem device */
@@ -2544,7 +2866,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
        if (ret) {
                v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
-               goto enc_vdev_alloc_rollback;
+               video_device_release(jpeg->vfd_encoder);
+               goto vb2_allocator_rollback;
        }
 
        video_set_drvdata(jpeg->vfd_encoder, jpeg);
@@ -2572,7 +2895,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
        if (ret) {
                v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
-               goto dec_vdev_alloc_rollback;
+               video_device_release(jpeg->vfd_decoder);
+               goto enc_vdev_register_rollback;
        }
 
        video_set_drvdata(jpeg->vfd_decoder, jpeg);
@@ -2589,15 +2913,9 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 
        return 0;
 
-dec_vdev_alloc_rollback:
-       video_device_release(jpeg->vfd_decoder);
-
 enc_vdev_register_rollback:
        video_unregister_device(jpeg->vfd_encoder);
 
-enc_vdev_alloc_rollback:
-       video_device_release(jpeg->vfd_encoder);
-
 vb2_allocator_rollback:
        vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
 
@@ -2607,38 +2925,27 @@ m2m_init_rollback:
 device_register_rollback:
        v4l2_device_unregister(&jpeg->v4l2_dev);
 
-clk_get_rollback:
-       clk_put(jpeg->clk);
-       if (!IS_ERR(jpeg->sclk))
-               clk_put(jpeg->sclk);
-
        return ret;
 }
 
 static int s5p_jpeg_remove(struct platform_device *pdev)
 {
        struct s5p_jpeg *jpeg = platform_get_drvdata(pdev);
+       int i;
 
        pm_runtime_disable(jpeg->dev);
 
        video_unregister_device(jpeg->vfd_decoder);
-       video_device_release(jpeg->vfd_decoder);
        video_unregister_device(jpeg->vfd_encoder);
-       video_device_release(jpeg->vfd_encoder);
        vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx);
        v4l2_m2m_release(jpeg->m2m_dev);
        v4l2_device_unregister(&jpeg->v4l2_dev);
 
        if (!pm_runtime_status_suspended(&pdev->dev)) {
-               clk_disable_unprepare(jpeg->clk);
-               if (!IS_ERR(jpeg->sclk))
-                       clk_disable_unprepare(jpeg->sclk);
+               for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
+                       clk_disable_unprepare(jpeg->clocks[i]);
        }
 
-       clk_put(jpeg->clk);
-       if (!IS_ERR(jpeg->sclk))
-               clk_put(jpeg->sclk);
-
        return 0;
 }
 
@@ -2646,10 +2953,10 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
 static int s5p_jpeg_runtime_suspend(struct device *dev)
 {
        struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+       int i;
 
-       clk_disable_unprepare(jpeg->clk);
-       if (!IS_ERR(jpeg->sclk))
-               clk_disable_unprepare(jpeg->sclk);
+       for (i = jpeg->variant->num_clocks - 1; i >= 0; i--)
+               clk_disable_unprepare(jpeg->clocks[i]);
 
        return 0;
 }
@@ -2658,16 +2965,15 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
 {
        struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
        unsigned long flags;
-       int ret;
+       int i, ret;
 
-       ret = clk_prepare_enable(jpeg->clk);
-       if (ret < 0)
-               return ret;
-
-       if (!IS_ERR(jpeg->sclk)) {
-               ret = clk_prepare_enable(jpeg->sclk);
-               if (ret < 0)
+       for (i = 0; i < jpeg->variant->num_clocks; i++) {
+               ret = clk_prepare_enable(jpeg->clocks[i]);
+               if (ret) {
+                       while (--i > 0)
+                               clk_disable_unprepare(jpeg->clocks[i]);
                        return ret;
+               }
        }
 
        spin_lock_irqsave(&jpeg->slock, flags);
@@ -2721,6 +3027,8 @@ static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
        .jpeg_irq       = s5p_jpeg_irq,
        .m2m_ops        = &s5p_jpeg_m2m_ops,
        .fmt_ver_flag   = SJPEG_FMT_FLAG_S5P,
+       .clk_names      = {"jpeg"},
+       .num_clocks     = 1,
 };
 
 static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
@@ -2729,6 +3037,8 @@ static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
        .m2m_ops        = &exynos3250_jpeg_m2m_ops,
        .fmt_ver_flag   = SJPEG_FMT_FLAG_EXYNOS3250,
        .hw3250_compat  = 1,
+       .clk_names      = {"jpeg", "sclk"},
+       .num_clocks     = 2,
 };
 
 static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
@@ -2737,6 +3047,9 @@ static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
        .m2m_ops        = &exynos4_jpeg_m2m_ops,
        .fmt_ver_flag   = SJPEG_FMT_FLAG_EXYNOS4,
        .htbl_reinit    = 1,
+       .clk_names      = {"jpeg"},
+       .num_clocks     = 1,
+       .hw_ex4_compat  = 1,
 };
 
 static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
@@ -2746,6 +3059,19 @@ static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
        .fmt_ver_flag   = SJPEG_FMT_FLAG_EXYNOS3250,    /* intentionally 3250 */
        .hw3250_compat  = 1,
        .htbl_reinit    = 1,
+       .clk_names      = {"jpeg"},
+       .num_clocks     = 1,
+};
+
+static struct s5p_jpeg_variant exynos5433_jpeg_drvdata = {
+       .version        = SJPEG_EXYNOS5433,
+       .jpeg_irq       = exynos4_jpeg_irq,
+       .m2m_ops        = &exynos4_jpeg_m2m_ops,
+       .fmt_ver_flag   = SJPEG_FMT_FLAG_EXYNOS4,
+       .htbl_reinit    = 1,
+       .clk_names      = {"pclk", "aclk", "aclk_xiu", "sclk"},
+       .num_clocks     = 4,
+       .hw_ex4_compat  = 1,
 };
 
 static const struct of_device_id samsung_jpeg_match[] = {
@@ -2764,6 +3090,9 @@ static const struct of_device_id samsung_jpeg_match[] = {
        }, {
                .compatible = "samsung,exynos5420-jpeg",
                .data = &exynos5420_jpeg_drvdata,
+       }, {
+               .compatible = "samsung,exynos5433-jpeg",
+               .data = &exynos5433_jpeg_drvdata,
        },
        {},
 };