X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fmedia%2Fplatform%2Fs5p-jpeg%2Fjpeg-core.c;h=4a608cbe0fdb4628975db86730b3ba28f3dae24a;hb=e09b41010ba33a20a87472ee821fa407a5b8da36;hp=bfbf1575677ca93c2d81426daaef885f7675022f;hpb=f93b97fd65072de626c074dbe099a1fff05ce060;p=kvmfornfv.git diff --git a/kernel/drivers/media/platform/s5p-jpeg/jpeg-core.c b/kernel/drivers/media/platform/s5p-jpeg/jpeg-core.c index bfbf15756..4a608cbe0 100644 --- a/kernel/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/kernel/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #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, }, {}, };