]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
[media] s5p-jpeg: add support for 5433
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Fri, 18 Sep 2015 14:20:58 +0000 (11:20 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 1 Oct 2015 11:40:04 +0000 (08:40 -0300)
JPEG IP found in Exynos5433 is similar to what is in Exynos4, but
there are some subtle differences which this patch takes into account.

The most important difference is in what is processed by the JPEG IP and
what has to be provided to it. In case of 5433 the IP does not parse
Huffman and quantisation tables, so this has to be performed with the CPU
and the majority of the code in this patch does that.

A small but important difference is in what address is passed to the JPEG
IP. In case of 5433 it is the SOS (start of scan) position, which is
natural, because the headers must be parsed elsewhere.

There is also a difference in how the hardware is put to work in
device_run.

Data structures are extended as appropriate to accommodate the above
changes.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Reviewed-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-jpeg/jpeg-core.h
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h
drivers/media/platform/s5p-jpeg/jpeg-regs.h

index 4ef45636ebdedd538bef484a94705b720aceda66..38941db23dd2435e97f085633cfeb298cf6a030f 100644 (file)
@@ -4,7 +4,8 @@ Required properties:
 
 - compatible   : should be one of:
                  "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg",
-                 "samsung,exynos3250-jpeg", "samsung,exynos5420-jpeg";
+                 "samsung,exynos3250-jpeg", "samsung,exynos5420-jpeg",
+                 "samsung,exynos5433-jpeg";
 - reg          : address and length of the JPEG codec IP register set;
 - interrupts   : specifies the JPEG codec IP interrupt;
 - clock-names   : should contain:
index b17091b9dfeb76f8c2587ae91ef9ef68e4df27d7..8b81ff63923db6ea90266790ba48e8b050d910f6 100644 (file)
@@ -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,211 @@ 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;
+       unsigned int word;
+       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;
+
+       word = 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 +1100,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 +1113,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 +1132,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 +1146,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 +1154,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 +1208,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 +1240,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 +1484,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 +1607,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 +2146,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 +2183,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 +2204,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)
@@ -2187,6 +2500,17 @@ 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;
@@ -2373,7 +2697,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;
@@ -2725,6 +3050,7 @@ static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
        .htbl_reinit    = 1,
        .clk_names      = {"jpeg"},
        .num_clocks     = 1,
+       .hw_ex4_compat  = 1,
 };
 
 static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
@@ -2738,6 +3064,17 @@ static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = {
        .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[] = {
        {
                .compatible = "samsung,s5pv210-jpeg",
@@ -2754,6 +3091,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,
        },
        {},
 };
index d0076fe2843d48d9f9f05546ad469dbfabf8a97c..9b1db09349094c784aea79d36460cf474b578854 100644 (file)
 /* a selection of JPEG markers */
 #define TEM                            0x01
 #define SOF0                           0xc0
+#define DHT                            0xc4
 #define RST                            0xd0
 #define SOI                            0xd8
 #define EOI                            0xd9
+#define        SOS                             0xda
+#define DQT                            0xdb
 #define DHP                            0xde
 
 /* Flags that indicate a format can be used for capture/output */
 #define SJPEG_SUBSAMPLING_422  0x21
 #define SJPEG_SUBSAMPLING_420  0x22
 
+#define S5P_JPEG_MAX_MARKER    4
+
 /* Version numbers */
 enum sjpeg_version {
        SJPEG_S5P,
        SJPEG_EXYNOS3250,
        SJPEG_EXYNOS4,
        SJPEG_EXYNOS5420,
+       SJPEG_EXYNOS5433,
 };
 
 enum exynos4_jpeg_result {
@@ -134,6 +140,7 @@ struct s5p_jpeg_variant {
        unsigned int            fmt_ver_flag;
        unsigned int            hw3250_compat:1;
        unsigned int            htbl_reinit:1;
+       unsigned int            hw_ex4_compat:1;
        struct v4l2_m2m_ops     *m2m_ops;
        irqreturn_t             (*jpeg_irq)(int irq, void *priv);
        const char              *clk_names[JPEG_MAX_CLOCKS];
@@ -162,17 +169,41 @@ struct s5p_jpeg_fmt {
        u32     flags;
 };
 
+/**
+ * s5p_jpeg_marker - collection of markers from jpeg header
+ * @marker:    markers' positions relative to the buffer beginning
+ * @len:       markers' payload lengths (without length field)
+ * @n:         number of markers in collection
+ */
+struct s5p_jpeg_marker {
+       u32     marker[S5P_JPEG_MAX_MARKER];
+       u32     len[S5P_JPEG_MAX_MARKER];
+       u32     n;
+};
+
 /**
  * s5p_jpeg_q_data - parameters of one queue
  * @fmt:       driver-specific format of this queue
  * @w:         image width
  * @h:         image height
+ * @sos:       SOS marker's position relative to the buffer beginning
+ * @dht:       DHT markers' positions relative to the buffer beginning
+ * @dqt:       DQT markers' positions relative to the buffer beginning
+ * @sof:       SOF0 marker's postition relative to the buffer beginning
+ * @sof_len:   SOF0 marker's payload length (without length field itself)
+ * @components:        number of image components
  * @size:      image buffer size in bytes
  */
 struct s5p_jpeg_q_data {
        struct s5p_jpeg_fmt     *fmt;
        u32                     w;
        u32                     h;
+       u32                     sos;
+       struct s5p_jpeg_marker  dht;
+       struct s5p_jpeg_marker  dqt;
+       u32                     sof;
+       u32                     sof_len;
+       u32                     components;
        u32                     size;
 };
 
index ab6d6f43c96f1a81361a98b7acc6faa160e368d1..0912d0a892e2cd9e90bfd1a465b58439a12a9416 100644 (file)
@@ -45,9 +45,20 @@ void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode)
        }
 }
 
-void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt)
+void __exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt,
+                               unsigned int version)
 {
        unsigned int reg;
+       unsigned int exynos4_swap_chroma_cbcr;
+       unsigned int exynos4_swap_chroma_crcb;
+
+       if (version == SJPEG_EXYNOS4) {
+               exynos4_swap_chroma_cbcr = EXYNOS4_SWAP_CHROMA_CBCR;
+               exynos4_swap_chroma_crcb = EXYNOS4_SWAP_CHROMA_CRCB;
+       } else {
+               exynos4_swap_chroma_cbcr = EXYNOS5433_SWAP_CHROMA_CBCR;
+               exynos4_swap_chroma_crcb = EXYNOS5433_SWAP_CHROMA_CRCB;
+       }
 
        reg = readl(base + EXYNOS4_IMG_FMT_REG) &
                        EXYNOS4_ENC_IN_FMT_MASK; /* clear except enc format */
@@ -67,48 +78,48 @@ void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt)
        case V4L2_PIX_FMT_NV24:
                reg = reg | EXYNOS4_ENC_YUV_444_IMG |
                                EXYNOS4_YUV_444_IP_YUV_444_2P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CBCR;
+                               exynos4_swap_chroma_cbcr;
                break;
        case V4L2_PIX_FMT_NV42:
                reg = reg | EXYNOS4_ENC_YUV_444_IMG |
                                EXYNOS4_YUV_444_IP_YUV_444_2P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CRCB;
+                               exynos4_swap_chroma_crcb;
                break;
        case V4L2_PIX_FMT_YUYV:
                reg = reg | EXYNOS4_DEC_YUV_422_IMG |
                                EXYNOS4_YUV_422_IP_YUV_422_1P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CBCR;
+                               exynos4_swap_chroma_cbcr;
                break;
 
        case V4L2_PIX_FMT_YVYU:
                reg = reg | EXYNOS4_DEC_YUV_422_IMG |
                                EXYNOS4_YUV_422_IP_YUV_422_1P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CRCB;
+                               exynos4_swap_chroma_crcb;
                break;
        case V4L2_PIX_FMT_NV16:
                reg = reg | EXYNOS4_DEC_YUV_422_IMG |
                                EXYNOS4_YUV_422_IP_YUV_422_2P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CBCR;
+                               exynos4_swap_chroma_cbcr;
                break;
        case V4L2_PIX_FMT_NV61:
                reg = reg | EXYNOS4_DEC_YUV_422_IMG |
                                EXYNOS4_YUV_422_IP_YUV_422_2P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CRCB;
+                               exynos4_swap_chroma_crcb;
                break;
        case V4L2_PIX_FMT_NV12:
                reg = reg | EXYNOS4_DEC_YUV_420_IMG |
                                EXYNOS4_YUV_420_IP_YUV_420_2P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CBCR;
+                               exynos4_swap_chroma_cbcr;
                break;
        case V4L2_PIX_FMT_NV21:
                reg = reg | EXYNOS4_DEC_YUV_420_IMG |
                                EXYNOS4_YUV_420_IP_YUV_420_2P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CRCB;
+                               exynos4_swap_chroma_crcb;
                break;
        case V4L2_PIX_FMT_YUV420:
                reg = reg | EXYNOS4_DEC_YUV_420_IMG |
                                EXYNOS4_YUV_420_IP_YUV_420_3P_IMG |
-                               EXYNOS4_SWAP_CHROMA_CBCR;
+                               exynos4_swap_chroma_cbcr;
                break;
        default:
                break;
@@ -118,12 +129,14 @@ void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt)
        writel(reg, base + EXYNOS4_IMG_FMT_REG);
 }
 
-void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt)
+void __exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt,
+                                   unsigned int version)
 {
        unsigned int reg;
 
        reg = readl(base + EXYNOS4_IMG_FMT_REG) &
-                       ~EXYNOS4_ENC_FMT_MASK; /* clear enc format */
+                       ~(version == SJPEG_EXYNOS4 ? EXYNOS4_ENC_FMT_MASK :
+                         EXYNOS5433_ENC_FMT_MASK); /* clear enc format */
 
        switch (out_fmt) {
        case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
@@ -149,9 +162,18 @@ void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt)
        writel(reg, base + EXYNOS4_IMG_FMT_REG);
 }
 
-void exynos4_jpeg_set_interrupt(void __iomem *base)
+void exynos4_jpeg_set_interrupt(void __iomem *base, unsigned int version)
 {
-       writel(EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
+       unsigned int reg;
+
+       if (version == SJPEG_EXYNOS4) {
+               reg = readl(base + EXYNOS4_INT_EN_REG) & ~EXYNOS4_INT_EN_MASK;
+               writel(reg | EXYNOS4_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
+       } else {
+               reg = readl(base + EXYNOS4_INT_EN_REG) &
+                                                       ~EXYNOS5433_INT_EN_MASK;
+               writel(reg | EXYNOS5433_INT_EN_ALL, base + EXYNOS4_INT_EN_REG);
+       }
 }
 
 unsigned int exynos4_jpeg_get_int_status(void __iomem *base)
@@ -234,6 +256,36 @@ void exynos4_jpeg_set_encode_tbl_select(void __iomem *base,
        writel(reg, base + EXYNOS4_TBL_SEL_REG);
 }
 
+void exynos4_jpeg_set_dec_components(void __iomem *base, int n)
+{
+       unsigned int    reg;
+
+       reg = readl(base + EXYNOS4_TBL_SEL_REG);
+
+       reg |= EXYNOS4_NF(n);
+       writel(reg, base + EXYNOS4_TBL_SEL_REG);
+}
+
+void exynos4_jpeg_select_dec_q_tbl(void __iomem *base, char c, char x)
+{
+       unsigned int    reg;
+
+       reg = readl(base + EXYNOS4_TBL_SEL_REG);
+
+       reg |= EXYNOS4_Q_TBL_COMP(c, x);
+       writel(reg, base + EXYNOS4_TBL_SEL_REG);
+}
+
+void exynos4_jpeg_select_dec_h_tbl(void __iomem *base, char c, char x)
+{
+       unsigned int    reg;
+
+       reg = readl(base + EXYNOS4_TBL_SEL_REG);
+
+       reg |= EXYNOS4_HUFF_TBL_COMP(c, x);
+       writel(reg, base + EXYNOS4_TBL_SEL_REG);
+}
+
 void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt)
 {
        if (fmt == V4L2_PIX_FMT_GREY)
index c228d28a4bc7c3ee5be085f4e9e741b064b7e077..cf6ec055d63a1d2e58998c80ab30fef9cd87b9e0 100644 (file)
 
 void exynos4_jpeg_sw_reset(void __iomem *base);
 void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode);
-void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt);
-void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt);
+void __exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt,
+                               unsigned int version);
+void __exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt,
+                                   unsigned int version);
 void exynos4_jpeg_set_enc_tbl(void __iomem *base);
-void exynos4_jpeg_set_interrupt(void __iomem *base);
+void exynos4_jpeg_set_interrupt(void __iomem *base, unsigned int version);
 unsigned int exynos4_jpeg_get_int_status(void __iomem *base);
 void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value);
 void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value);
@@ -30,6 +32,9 @@ void exynos4_jpeg_set_frame_buf_address(void __iomem *base,
                                struct s5p_jpeg_addr *jpeg_addr);
 void exynos4_jpeg_set_encode_tbl_select(void __iomem *base,
                enum exynos4_jpeg_img_quality_level level);
+void exynos4_jpeg_set_dec_components(void __iomem *base, int n);
+void exynos4_jpeg_select_dec_q_tbl(void __iomem *base, char c, char x);
+void exynos4_jpeg_select_dec_h_tbl(void __iomem *base, char c, char x);
 void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt);
 void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size);
 unsigned int exynos4_jpeg_get_stream_size(void __iomem *base);
index 050fc440248fb81229a17807cc90437d3b39bfe2..1870400468b2061e885a28c6b49fbf1688d31cca 100644 (file)
 
 /* JPEG INT Register bit */
 #define EXYNOS4_INT_EN_MASK            (0x1f << 0)
+#define EXYNOS5433_INT_EN_MASK         (0x1ff << 0)
 #define EXYNOS4_PROT_ERR_INT_EN                (1 << 0)
 #define EXYNOS4_IMG_COMPLETION_INT_EN  (1 << 1)
 #define EXYNOS4_DEC_INVALID_FORMAT_EN  (1 << 2)
 #define EXYNOS4_MULTI_SCAN_ERROR_EN    (1 << 3)
 #define EXYNOS4_FRAME_ERR_EN           (1 << 4)
 #define EXYNOS4_INT_EN_ALL             (0x1f << 0)
+#define EXYNOS5433_INT_EN_ALL          (0x1b6 << 0)
 
 #define EXYNOS4_MOD_REG_PROC_ENC       (0 << 3)
 #define EXYNOS4_MOD_REG_PROC_DEC       (1 << 3)
 
 #define EXYNOS4_ENC_FMT_SHIFT                  24
 #define EXYNOS4_ENC_FMT_MASK                   (3 << EXYNOS4_ENC_FMT_SHIFT)
+#define EXYNOS5433_ENC_FMT_MASK                        (7 << EXYNOS4_ENC_FMT_SHIFT)
+
 #define EXYNOS4_ENC_FMT_GRAY                   (0 << EXYNOS4_ENC_FMT_SHIFT)
 #define EXYNOS4_ENC_FMT_YUV_444                        (1 << EXYNOS4_ENC_FMT_SHIFT)
 #define EXYNOS4_ENC_FMT_YUV_422                        (2 << EXYNOS4_ENC_FMT_SHIFT)
 
 #define EXYNOS4_SWAP_CHROMA_CRCB               (1 << 26)
 #define EXYNOS4_SWAP_CHROMA_CBCR               (0 << 26)
+#define EXYNOS5433_SWAP_CHROMA_CRCB            (1 << 27)
+#define EXYNOS5433_SWAP_CHROMA_CBCR            (0 << 27)
 
 /* JPEG HUFF count Register bit */
 #define EXYNOS4_HUFF_COUNT_MASK                        0xffff
 #define EXYNOS4_DECODED_IMG_FMT_MASK           0x3
 
 /* JPEG TBL SEL Register bit */
-#define EXYNOS4_Q_TBL_COMP1_0          (0 << 0)
-#define EXYNOS4_Q_TBL_COMP1_1          (1 << 0)
-#define EXYNOS4_Q_TBL_COMP1_2          (2 << 0)
-#define EXYNOS4_Q_TBL_COMP1_3          (3 << 0)
-
-#define EXYNOS4_Q_TBL_COMP2_0          (0 << 2)
-#define EXYNOS4_Q_TBL_COMP2_1          (1 << 2)
-#define EXYNOS4_Q_TBL_COMP2_2          (2 << 2)
-#define EXYNOS4_Q_TBL_COMP2_3          (3 << 2)
-
-#define EXYNOS4_Q_TBL_COMP3_0          (0 << 4)
-#define EXYNOS4_Q_TBL_COMP3_1          (1 << 4)
-#define EXYNOS4_Q_TBL_COMP3_2          (2 << 4)
-#define EXYNOS4_Q_TBL_COMP3_3          (3 << 4)
-
-#define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_0       (0 << 6)
-#define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1       (1 << 6)
-#define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_0       (2 << 6)
-#define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_1       (3 << 6)
-
-#define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0       (0 << 8)
-#define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_1       (1 << 8)
-#define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_0       (2 << 8)
-#define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_1       (3 << 8)
-
-#define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_0       (0 << 10)
-#define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_1       (1 << 10)
-#define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_0       (2 << 10)
-#define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1       (3 << 10)
+#define EXYNOS4_Q_TBL_COMP(c, n)       ((n) << (((c) - 1) << 1))
+
+#define EXYNOS4_Q_TBL_COMP1_0          EXYNOS4_Q_TBL_COMP(1, 0)
+#define EXYNOS4_Q_TBL_COMP1_1          EXYNOS4_Q_TBL_COMP(1, 1)
+#define EXYNOS4_Q_TBL_COMP1_2          EXYNOS4_Q_TBL_COMP(1, 2)
+#define EXYNOS4_Q_TBL_COMP1_3          EXYNOS4_Q_TBL_COMP(1, 3)
+
+#define EXYNOS4_Q_TBL_COMP2_0          EXYNOS4_Q_TBL_COMP(2, 0)
+#define EXYNOS4_Q_TBL_COMP2_1          EXYNOS4_Q_TBL_COMP(2, 1)
+#define EXYNOS4_Q_TBL_COMP2_2          EXYNOS4_Q_TBL_COMP(2, 2)
+#define EXYNOS4_Q_TBL_COMP2_3          EXYNOS4_Q_TBL_COMP(2, 3)
+
+#define EXYNOS4_Q_TBL_COMP3_0          EXYNOS4_Q_TBL_COMP(3, 0)
+#define EXYNOS4_Q_TBL_COMP3_1          EXYNOS4_Q_TBL_COMP(3, 1)
+#define EXYNOS4_Q_TBL_COMP3_2          EXYNOS4_Q_TBL_COMP(3, 2)
+#define EXYNOS4_Q_TBL_COMP3_3          EXYNOS4_Q_TBL_COMP(3, 3)
+
+#define EXYNOS4_HUFF_TBL_COMP(c, n)    ((n) << ((((c) - 1) << 1) + 6))
+
+#define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_0       \
+       EXYNOS4_HUFF_TBL_COMP(1, 0)
+#define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1       \
+       EXYNOS4_HUFF_TBL_COMP(1, 1)
+#define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_0       \
+       EXYNOS4_HUFF_TBL_COMP(1, 2)
+#define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_1       \
+       EXYNOS4_HUFF_TBL_COMP(1, 3)
+
+#define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0       \
+       EXYNOS4_HUFF_TBL_COMP(2, 0)
+#define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_1       \
+       EXYNOS4_HUFF_TBL_COMP(2, 1)
+#define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_0       \
+       EXYNOS4_HUFF_TBL_COMP(2, 2)
+#define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_1       \
+       EXYNOS4_HUFF_TBL_COMP(2, 3)
+
+#define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_0       \
+       EXYNOS4_HUFF_TBL_COMP(3, 0)
+#define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_1       \
+       EXYNOS4_HUFF_TBL_COMP(3, 1)
+#define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_0       \
+       EXYNOS4_HUFF_TBL_COMP(3, 2)
+#define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1       \
+       EXYNOS4_HUFF_TBL_COMP(3, 3)
+
+#define EXYNOS4_NF_SHIFT                       16
+#define EXYNOS4_NF_MASK                                0xff
+#define EXYNOS4_NF(x)                          \
+       (((x) << EXYNOS4_NF_SHIFT) & EXYNOS4_NF_MASK)
 
 /* JPEG quantizer table register */
 #define EXYNOS4_QTBL_CONTENT(n)        (0x100 + (n) * 0x40)