aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/s5p-jpeg/jpeg-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/s5p-jpeg/jpeg-core.c')
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c475
1 files changed, 405 insertions, 70 deletions
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 9690f9dcb0ca..4a608cbe0fdb 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -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 */
@@ -2603,17 +2925,13 @@ 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);
@@ -2624,15 +2942,10 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
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;
}
@@ -2640,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;
}
@@ -2652,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);
@@ -2715,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 = {
@@ -2723,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 = {
@@ -2731,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 = {
@@ -2740,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[] = {
@@ -2758,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,
},
{},
};