linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver
@ 2013-11-19 14:26 Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 01/16] s5p-jpeg: Reorder quantization tables Jacek Anaszewski
                   ` (15 more replies)
  0 siblings, 16 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

The main aim of this series is to add support for Exynos4x12 SoC
for the s5p-jpeg driver. Nonetheless, a room for couple of fixes
and improvements has been found during development, which
is reflected in the corresponding patches.

Thanks,
Jacek Anaszewski

Jacek Anaszewski (16):
  s5p-jpeg: Reorder quantization tables
  s5p-jpeg: Fix output YUV 4:2:0 fourcc for decoder
  s5p-jpeg: Fix erroneous condition while validating bytesperline value
  s5p-jpeg: Remove superfluous call to the jpeg_bound_align_image
    function
  s5p-jpeg: Rename functions specific to the S5PC210 SoC accordingly
  s5p-jpeg: Fix clock resource management
  s5p-jpeg: Fix lack of spin_lock protection
  s5p-jpeg: Synchronize cached controls with V4L2 core
  s5p-jpeg: Split jpeg-hw.h to jpeg-hw-s5p.c and jpeg-hw-s5p.c
  s5p-jpeg: Add hardware API for the exynos4x12 JPEG codec.
  s5p-jpeg: Retrieve "YCbCr subsampling" field from the jpeg header
  s5p-jpeg: Ensure correct capture format for Exynos4x12
  s5p-jpeg: Allow for wider JPEG subsampling scope for Exynos4x12
    encoder
  s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value
  s5p-jpeg: Ensure setting correct value of the chroma subsampling
    control
  s5p-jpeg: Adjust g_volatile_ctrl callback to Exynos4x12 needs

 drivers/media/platform/s5p-jpeg/Makefile           |    2 +-
 drivers/media/platform/s5p-jpeg/jpeg-core.c        | 1049 ++++++++++++++++----
 drivers/media/platform/s5p-jpeg/jpeg-core.h        |   75 +-
 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c   |  293 ++++++
 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h   |   44 +
 .../platform/s5p-jpeg/{jpeg-hw.h => jpeg-hw-s5p.c} |   82 +-
 drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h      |   63 ++
 drivers/media/platform/s5p-jpeg/jpeg-regs.h        |  215 +++-
 8 files changed, 1564 insertions(+), 259 deletions(-)
 create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c
 create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h
 rename drivers/media/platform/s5p-jpeg/{jpeg-hw.h => jpeg-hw-s5p.c} (71%)
 create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 01/16] s5p-jpeg: Reorder quantization tables
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 02/16] s5p-jpeg: Fix output YUV 4:2:0 fourcc for decoder Jacek Anaszewski
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Reorder quantization tables so that their elements
are arranged in the manner reflecting compression
quality level that is in accordance with V4L2 documentation,
i.e. the larger value of the V4L2_CID_JPEG_COMPRESSION_QUALITY
control the better image quality, and thus lower compression
quality. The modification allows also to get rid of
reverse logic in the s_ctrl callback while assigning
user space value to the ctx->compr_quality variable.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |  116 +++++++++++++--------------
 1 file changed, 58 insertions(+), 58 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 47934db..2234944 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -84,15 +84,25 @@ static struct s5p_jpeg_fmt formats_dec[] = {
 #define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
 
 static const unsigned char qtbl_luminance[4][64] = {
-	{/* level 1 - high quality */
-		 8,  6,  6,  8, 12, 14, 16, 17,
-		 6,  6,  6,  8, 10, 13, 12, 15,
-		 6,  6,  7,  8, 13, 14, 18, 24,
-		 8,  8,  8, 14, 13, 19, 24, 35,
-		12, 10, 13, 13, 20, 26, 34, 39,
-		14, 13, 14, 19, 26, 34, 39, 39,
-		16, 12, 18, 24, 34, 39, 39, 39,
-		17, 15, 24, 35, 39, 39, 39, 39
+	{/*level 0 - high compression quality */
+		20, 16, 25, 39, 50, 46, 62, 68,
+		16, 18, 23, 38, 38, 53, 65, 68,
+		25, 23, 31, 38, 53, 65, 68, 68,
+		39, 38, 38, 53, 65, 68, 68, 68,
+		50, 38, 53, 65, 68, 68, 68, 68,
+		46, 53, 65, 68, 68, 68, 68, 68,
+		62, 65, 68, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68
+	},
+	{/* level 1 */
+		16, 11, 11, 16, 23, 27, 31, 30,
+		11, 12, 12, 15, 20, 23, 23, 30,
+		11, 12, 13, 16, 23, 26, 35, 47,
+		16, 15, 16, 23, 26, 37, 47, 64,
+		23, 20, 23, 26, 39, 51, 64, 64,
+		27, 23, 26, 37, 51, 64, 64, 64,
+		31, 23, 35, 47, 64, 64, 64, 64,
+		30, 30, 47, 64, 64, 64, 64, 64
 	},
 	{/* level 2 */
 		12,  8,  8, 12, 17, 21, 24, 23,
@@ -104,38 +114,38 @@ static const unsigned char qtbl_luminance[4][64] = {
 		24, 18, 27, 36, 51, 59, 59, 59,
 		23, 23, 36, 53, 59, 59, 59, 59
 	},
-	{/* level 3 */
-		16, 11, 11, 16, 23, 27, 31, 30,
-		11, 12, 12, 15, 20, 23, 23, 30,
-		11, 12, 13, 16, 23, 26, 35, 47,
-		16, 15, 16, 23, 26, 37, 47, 64,
-		23, 20, 23, 26, 39, 51, 64, 64,
-		27, 23, 26, 37, 51, 64, 64, 64,
-		31, 23, 35, 47, 64, 64, 64, 64,
-		30, 30, 47, 64, 64, 64, 64, 64
-	},
-	{/*level 4 - low quality */
-		20, 16, 25, 39, 50, 46, 62, 68,
-		16, 18, 23, 38, 38, 53, 65, 68,
-		25, 23, 31, 38, 53, 65, 68, 68,
-		39, 38, 38, 53, 65, 68, 68, 68,
-		50, 38, 53, 65, 68, 68, 68, 68,
-		46, 53, 65, 68, 68, 68, 68, 68,
-		62, 65, 68, 68, 68, 68, 68, 68,
-		68, 68, 68, 68, 68, 68, 68, 68
+	{/* level 3 - low compression quality */
+		 8,  6,  6,  8, 12, 14, 16, 17,
+		 6,  6,  6,  8, 10, 13, 12, 15,
+		 6,  6,  7,  8, 13, 14, 18, 24,
+		 8,  8,  8, 14, 13, 19, 24, 35,
+		12, 10, 13, 13, 20, 26, 34, 39,
+		14, 13, 14, 19, 26, 34, 39, 39,
+		16, 12, 18, 24, 34, 39, 39, 39,
+		17, 15, 24, 35, 39, 39, 39, 39
 	}
 };
 
 static const unsigned char qtbl_chrominance[4][64] = {
-	{/* level 1 - high quality */
-		 9,  8,  9, 11, 14, 17, 19, 24,
-		 8, 10,  9, 11, 14, 13, 17, 22,
-		 9,  9, 13, 14, 13, 15, 23, 26,
-		11, 11, 14, 14, 15, 20, 26, 33,
-		14, 14, 13, 15, 20, 24, 33, 39,
-		17, 13, 15, 20, 24, 32, 39, 39,
-		19, 17, 23, 26, 33, 39, 39, 39,
-		24, 22, 26, 33, 39, 39, 39, 39
+	{/*level 0 - high compression quality */
+		21, 25, 32, 38, 54, 68, 68, 68,
+		25, 28, 24, 38, 54, 68, 68, 68,
+		32, 24, 32, 43, 66, 68, 68, 68,
+		38, 38, 43, 53, 68, 68, 68, 68,
+		54, 54, 66, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68,
+		68, 68, 68, 68, 68, 68, 68, 68
+	},
+	{/* level 1 */
+		17, 15, 17, 21, 20, 26, 38, 48,
+		15, 19, 18, 17, 20, 26, 35, 43,
+		17, 18, 20, 22, 26, 30, 46, 53,
+		21, 17, 22, 28, 30, 39, 53, 64,
+		20, 20, 26, 30, 39, 48, 64, 64,
+		26, 26, 30, 39, 48, 63, 64, 64,
+		38, 35, 46, 53, 64, 64, 64, 64,
+		48, 43, 53, 64, 64, 64, 64, 64
 	},
 	{/* level 2 */
 		13, 11, 13, 16, 20, 20, 29, 37,
@@ -147,25 +157,15 @@ static const unsigned char qtbl_chrominance[4][64] = {
 		29, 26, 35, 40, 50, 59, 59, 59,
 		37, 32, 40, 50, 59, 59, 59, 59
 	},
-	{/* level 3 */
-		17, 15, 17, 21, 20, 26, 38, 48,
-		15, 19, 18, 17, 20, 26, 35, 43,
-		17, 18, 20, 22, 26, 30, 46, 53,
-		21, 17, 22, 28, 30, 39, 53, 64,
-		20, 20, 26, 30, 39, 48, 64, 64,
-		26, 26, 30, 39, 48, 63, 64, 64,
-		38, 35, 46, 53, 64, 64, 64, 64,
-		48, 43, 53, 64, 64, 64, 64, 64
-	},
-	{/*level 4 - low quality */
-		21, 25, 32, 38, 54, 68, 68, 68,
-		25, 28, 24, 38, 54, 68, 68, 68,
-		32, 24, 32, 43, 66, 68, 68, 68,
-		38, 38, 43, 53, 68, 68, 68, 68,
-		54, 54, 66, 68, 68, 68, 68, 68,
-		68, 68, 68, 68, 68, 68, 68, 68,
-		68, 68, 68, 68, 68, 68, 68, 68,
-		68, 68, 68, 68, 68, 68, 68, 68
+	{/* level 3 - low compression quality */
+		 9,  8,  9, 11, 14, 17, 19, 24,
+		 8, 10,  9, 11, 14, 13, 17, 22,
+		 9,  9, 13, 14, 13, 15, 23, 26,
+		11, 11, 14, 14, 15, 20, 26, 33,
+		14, 14, 13, 15, 20, 24, 33, 39,
+		17, 13, 15, 20, 24, 32, 39, 39,
+		19, 17, 23, 26, 33, 39, 39, 39,
+		24, 22, 26, 33, 39, 39, 39, 39
 	}
 };
 
@@ -834,7 +834,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 
 	switch (ctrl->id) {
 	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
-		ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+		ctx->compr_quality = ctrl->val;
 		break;
 	case V4L2_CID_JPEG_RESTART_INTERVAL:
 		ctx->restart_interval = ctrl->val;
@@ -863,7 +863,7 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
 	if (ctx->mode == S5P_JPEG_ENCODE) {
 		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
 				  V4L2_CID_JPEG_COMPRESSION_QUALITY,
-				  0, 3, 1, 3);
+				  0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
 
 		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
 				  V4L2_CID_JPEG_RESTART_INTERVAL,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 02/16] s5p-jpeg: Fix output YUV 4:2:0 fourcc for decoder
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 01/16] s5p-jpeg: Reorder quantization tables Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 03/16] s5p-jpeg: Fix erroneous condition while validating bytesperline value Jacek Anaszewski
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Output samples during decoding phase for the YUV 4:2:0 format
are arranged in the manner compatible with 2-planar NV12,
not 3-planar YUV420 fourcc.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 2234944..0f567c5 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -58,7 +58,7 @@ static struct s5p_jpeg_fmt formats_enc[] = {
 static struct s5p_jpeg_fmt formats_dec[] = {
 	{
 		.name		= "YUV 4:2:0 planar, YCbCr",
-		.fourcc		= V4L2_PIX_FMT_YUV420,
+		.fourcc		= V4L2_PIX_FMT_NV12,
 		.depth		= 12,
 		.colplanes	= 3,
 		.h_align	= 4,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 03/16] s5p-jpeg: Fix erroneous condition while validating bytesperline value
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 01/16] s5p-jpeg: Reorder quantization tables Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 02/16] s5p-jpeg: Fix output YUV 4:2:0 fourcc for decoder Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 04/16] s5p-jpeg: Remove superfluous call to the jpeg_bound_align_image function Jacek Anaszewski
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

The aim of the condition is ensuring that the bytesperline
value set by the user space application is proper for the
given format and adjusting it if isn't. As the depth value
of the format description entry is expressed in bits then
the bytesperline value needs to be divided, not multiplied,
by that value to get the number of bytes required to store
single line of image samples.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 0f567c5..a1366f0 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -670,7 +670,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
 			bpl = pix->width; /* planar */
 
 		if (fmt->colplanes == 1 && /* packed */
-		    (bpl << 3) * fmt->depth < pix->width)
+		    (bpl << 3) / fmt->depth < pix->width)
 			bpl = (pix->width * fmt->depth) >> 3;
 
 		pix->bytesperline = bpl;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 04/16] s5p-jpeg: Remove superfluous call to the jpeg_bound_align_image function
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (2 preceding siblings ...)
  2013-11-19 14:26 ` [PATCH 03/16] s5p-jpeg: Fix erroneous condition while validating bytesperline value Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 05/16] s5p-jpeg: Rename functions specific to the S5PC210 SoC accordingly Jacek Anaszewski
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Aligning capture queue image dimensions while enqueuing output
queue doesn't make a sense as the S_FMT ioctl might have not
been called for the capture queue until that moment, whereas
it is required to know capture format as the type of alignment
heavily depends on it.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |    7 -------
 1 file changed, 7 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index a1366f0..a6ec8c6 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1089,13 +1089,6 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
 		q_data = &ctx->cap_q;
 		q_data->w = tmp.w;
 		q_data->h = tmp.h;
-
-		jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
-				       S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
-				       &q_data->h, S5P_JPEG_MIN_HEIGHT,
-				       S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
-				      );
-		q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
 	}
 
 	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 05/16] s5p-jpeg: Rename functions specific to the S5PC210 SoC accordingly
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (3 preceding siblings ...)
  2013-11-19 14:26 ` [PATCH 04/16] s5p-jpeg: Remove superfluous call to the jpeg_bound_align_image function Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 06/16] s5p-jpeg: Fix clock resource management Jacek Anaszewski
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   58 ++++++++++++++++-----------
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index a6ec8c6..32033e7 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -213,8 +213,9 @@ static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
 	return container_of(fh, struct s5p_jpeg_ctx, fh);
 }
 
-static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
-		   unsigned long tab, int len)
+static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
+				     const unsigned char *qtbl,
+				     unsigned long tab, int len)
 {
 	int i;
 
@@ -222,22 +223,25 @@ static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
 		writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
 }
 
-static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
 {
 	/* this driver fills quantisation table 0 with data for luma */
-	jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
-		      ARRAY_SIZE(qtbl_luminance[quality]));
+	s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
+			  S5P_JPG_QTBL_CONTENT(0),
+			  ARRAY_SIZE(qtbl_luminance[quality]));
 }
 
-static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
 {
 	/* this driver fills quantisation table 1 with data for chroma */
-	jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
-		      ARRAY_SIZE(qtbl_chrominance[quality]));
+	s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
+			  S5P_JPG_QTBL_CONTENT(1),
+			  ARRAY_SIZE(qtbl_chrominance[quality]));
 }
 
-static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
-		   unsigned long tab, int len)
+static inline void s5p_jpeg_set_htbl(void __iomem *regs,
+				     const unsigned char *htbl,
+				     unsigned long tab, int len)
 {
 	int i;
 
@@ -245,28 +249,32 @@ static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
 		writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
 }
 
-static inline void jpeg_set_hdctbl(void __iomem *regs)
+static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
 {
 	/* this driver fills table 0 for this component */
-	jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
+	s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
+						ARRAY_SIZE(hdctbl0));
 }
 
-static inline void jpeg_set_hdctblg(void __iomem *regs)
+static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
 {
 	/* this driver fills table 0 for this component */
-	jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
+	s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
+						ARRAY_SIZE(hdctblg0));
 }
 
-static inline void jpeg_set_hactbl(void __iomem *regs)
+static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
 {
 	/* this driver fills table 0 for this component */
-	jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+	s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
+						ARRAY_SIZE(hactbl0));
 }
 
-static inline void jpeg_set_hactblg(void __iomem *regs)
+static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
 {
 	/* this driver fills table 0 for this component */
-	jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
+	s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
+						ARRAY_SIZE(hactblg0));
 }
 
 /*
@@ -962,8 +970,8 @@ static void s5p_jpeg_device_run(void *priv)
 		 * JPEG IP allows storing 4 quantization tables
 		 * We fill table 0 for luma and table 1 for chroma
 		 */
-		jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
-		jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+		s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+		s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
 		/* use table 0 for Y */
 		jpeg_qtbl(jpeg->regs, 1, 0);
 		/* use table 1 for Cb and Cr*/
@@ -1406,14 +1414,16 @@ static int s5p_jpeg_runtime_suspend(struct device *dev)
 static int s5p_jpeg_runtime_resume(struct device *dev)
 {
 	struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+
 	/*
 	 * JPEG IP allows storing two Huffman tables for each component
 	 * We fill table 0 for each component
 	 */
-	jpeg_set_hdctbl(jpeg->regs);
-	jpeg_set_hdctblg(jpeg->regs);
-	jpeg_set_hactbl(jpeg->regs);
-	jpeg_set_hactblg(jpeg->regs);
+	s5p_jpeg_set_hdctbl(jpeg->regs);
+	s5p_jpeg_set_hdctblg(jpeg->regs);
+	s5p_jpeg_set_hactbl(jpeg->regs);
+	s5p_jpeg_set_hactblg(jpeg->regs);
+
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 06/16] s5p-jpeg: Fix clock resource management
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (4 preceding siblings ...)
  2013-11-19 14:26 ` [PATCH 05/16] s5p-jpeg: Rename functions specific to the S5PC210 SoC accordingly Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:26 ` [PATCH 07/16] s5p-jpeg: Fix lack of spin_lock protection Jacek Anaszewski
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski,
	Marek Szyprowski

Standard suspend/resume path is called after runtime resume
of the given device, so suspend/resume callbacks must do all
clock management done also by runtime pm to allow for proper
power domain shutdown. Moreover, JPEG clock is enabled from
probe function but is is not necessary. This patch also moves
control of jpeg clock to runtime_pm callbacks.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   52 ++++++++++++++++++---------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 32033e7..328bb8b 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1250,29 +1250,28 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 	if (IS_ERR(jpeg->regs))
 		return PTR_ERR(jpeg->regs);
 
+	/* 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;
+	}
+	dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
+
 	/* interrupt service routine registration */
 	jpeg->irq = ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "cannot find IRQ\n");
-		return ret;
+		goto clk_get_rollback;
 	}
 
 	ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
 			dev_name(&pdev->dev), jpeg);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
-		return ret;
-	}
-
-	/* 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;
+		goto clk_get_rollback;
 	}
-	dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
-	clk_prepare_enable(jpeg->clk);
 
 	/* v4l2 device */
 	ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
@@ -1380,7 +1379,6 @@ device_register_rollback:
 	v4l2_device_unregister(&jpeg->v4l2_dev);
 
 clk_get_rollback:
-	clk_disable_unprepare(jpeg->clk);
 	clk_put(jpeg->clk);
 
 	return ret;
@@ -1400,7 +1398,9 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
 	v4l2_m2m_release(jpeg->m2m_dev);
 	v4l2_device_unregister(&jpeg->v4l2_dev);
 
-	clk_disable_unprepare(jpeg->clk);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		clk_disable_unprepare(jpeg->clk);
+
 	clk_put(jpeg->clk);
 
 	return 0;
@@ -1408,6 +1408,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);
+
+	clk_disable_unprepare(jpeg->clk);
+
 	return 0;
 }
 
@@ -1415,6 +1419,8 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
 {
 	struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
 
+	clk_prepare_enable(jpeg->clk);
+
 	/*
 	 * JPEG IP allows storing two Huffman tables for each component
 	 * We fill table 0 for each component
@@ -1427,9 +1433,23 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
 	return 0;
 }
 
+static int s5p_jpeg_suspend(struct device *dev)
+{
+	s5p_jpeg_runtime_suspend(dev);
+
+	return 0;
+}
+
+static int s5p_jpeg_resume(struct device *dev)
+{
+	s5p_jpeg_runtime_resume(dev);
+
+	return 0;
+}
+
 static const struct dev_pm_ops s5p_jpeg_pm_ops = {
-	.runtime_suspend = s5p_jpeg_runtime_suspend,
-	.runtime_resume	 = s5p_jpeg_runtime_resume,
+	SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
+	SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
 };
 
 #ifdef CONFIG_OF
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 07/16] s5p-jpeg: Fix lack of spin_lock protection
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (5 preceding siblings ...)
  2013-11-19 14:26 ` [PATCH 06/16] s5p-jpeg: Fix clock resource management Jacek Anaszewski
@ 2013-11-19 14:26 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 08/16] s5p-jpeg: Synchronize cached controls with V4L2 core Jacek Anaszewski
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:26 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

s5p_jpeg_device_run and s5p_jpeg_runtime_resume callbacks should
have spin_lock protection as they alter device registers.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 328bb8b..650c4d3 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -930,7 +930,9 @@ static void s5p_jpeg_device_run(void *priv)
 	struct s5p_jpeg_ctx *ctx = priv;
 	struct s5p_jpeg *jpeg = ctx->jpeg;
 	struct vb2_buffer *src_buf, *dst_buf;
-	unsigned long src_addr, dst_addr;
+	unsigned long src_addr, dst_addr, flags;
+
+	spin_lock_irqsave(&ctx->jpeg->slock, flags);
 
 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -998,6 +1000,8 @@ static void s5p_jpeg_device_run(void *priv)
 	}
 
 	jpeg_start(jpeg->regs);
+
+	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
 }
 
 static int s5p_jpeg_job_ready(void *priv)
@@ -1418,9 +1422,12 @@ static int s5p_jpeg_runtime_suspend(struct device *dev)
 static int s5p_jpeg_runtime_resume(struct device *dev)
 {
 	struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+	unsigned long flags;
 
 	clk_prepare_enable(jpeg->clk);
 
+	spin_lock_irqsave(&jpeg->slock, flags);
+
 	/*
 	 * JPEG IP allows storing two Huffman tables for each component
 	 * We fill table 0 for each component
@@ -1430,6 +1437,8 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
 	s5p_jpeg_set_hactbl(jpeg->regs);
 	s5p_jpeg_set_hactblg(jpeg->regs);
 
+	spin_unlock_irqrestore(&jpeg->slock, flags);
+
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 08/16] s5p-jpeg: Synchronize cached controls with V4L2 core
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (6 preceding siblings ...)
  2013-11-19 14:26 ` [PATCH 07/16] s5p-jpeg: Fix lack of spin_lock protection Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 09/16] s5p-jpeg: Split jpeg-hw.h to jpeg-hw-s5p.c and jpeg-hw-s5p.c Jacek Anaszewski
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

This patch adds proper initialization of the in-driver
cached state of JPEG controls with V4L2 core.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 650c4d3..b82e3fa 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -890,6 +890,9 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
 	if (ctx->mode == S5P_JPEG_DECODE)
 		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
 			V4L2_CTRL_FLAG_READ_ONLY;
+
+	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 09/16] s5p-jpeg: Split jpeg-hw.h to jpeg-hw-s5p.c and jpeg-hw-s5p.c
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (7 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 08/16] s5p-jpeg: Synchronize cached controls with V4L2 core Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 10/16] s5p-jpeg: Add hardware API for the exynos4x12 JPEG codec Jacek Anaszewski
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Move function definitions from jpeg-hw.h to jpeg-hw-s5p.c
and put function declarations in the jpeg-hw-s5p.h.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/Makefile           |    2 +-
 drivers/media/platform/s5p-jpeg/jpeg-core.c        |    2 +-
 drivers/media/platform/s5p-jpeg/jpeg-core.h        |    5 ++
 .../platform/s5p-jpeg/{jpeg-hw.h => jpeg-hw-s5p.c} |   82 ++++++++------------
 drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h      |   63 +++++++++++++++
 5 files changed, 104 insertions(+), 50 deletions(-)
 rename drivers/media/platform/s5p-jpeg/{jpeg-hw.h => jpeg-hw-s5p.c} (71%)
 create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h

diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile
index d18cb5e..faf6398 100644
--- a/drivers/media/platform/s5p-jpeg/Makefile
+++ b/drivers/media/platform/s5p-jpeg/Makefile
@@ -1,2 +1,2 @@
-s5p-jpeg-objs := jpeg-core.o
+s5p-jpeg-objs := jpeg-core.o jpeg-hw-s5p.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index b82e3fa..4e874ad 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -29,7 +29,7 @@
 #include <media/videobuf2-dma-contig.h>
 
 #include "jpeg-core.h"
-#include "jpeg-hw.h"
+#include "jpeg-hw-s5p.h"
 
 static struct s5p_jpeg_fmt formats_enc[] = {
 	{
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 4a4776b..7baadf3 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -42,10 +42,15 @@
 #define EOI				0xd9
 #define DHP				0xde
 
+#define S5P_JPEG_ENCODE		0
+#define S5P_JPEG_DECODE		1
+
 /* Flags that indicate a format can be used for capture/output */
 #define MEM2MEM_CAPTURE			(1 << 0)
 #define MEM2MEM_OUTPUT			(1 << 1)
 
+
+
 /**
  * struct s5p_jpeg - JPEG IP abstraction
  * @lock:		the mutex protecting this structure
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
similarity index 71%
rename from drivers/media/platform/s5p-jpeg/jpeg-hw.h
rename to drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
index b47e887..6a1164c 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-hw.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
@@ -9,27 +9,15 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#ifndef JPEG_HW_H_
-#define JPEG_HW_H_
 
 #include <linux/io.h>
 #include <linux/videodev2.h>
 
-#include "jpeg-hw.h"
+#include "jpeg-core.h"
 #include "jpeg-regs.h"
+#include "jpeg-hw-s5p.h"
 
-#define S5P_JPEG_MIN_WIDTH		32
-#define S5P_JPEG_MIN_HEIGHT		32
-#define S5P_JPEG_MAX_WIDTH		8192
-#define S5P_JPEG_MAX_HEIGHT		8192
-#define S5P_JPEG_ENCODE			0
-#define S5P_JPEG_DECODE			1
-#define S5P_JPEG_RAW_IN_565		0
-#define S5P_JPEG_RAW_IN_422		1
-#define S5P_JPEG_RAW_OUT_422		0
-#define S5P_JPEG_RAW_OUT_420		1
-
-static inline void jpeg_reset(void __iomem *regs)
+void jpeg_reset(void __iomem *regs)
 {
 	unsigned long reg;
 
@@ -42,12 +30,12 @@ static inline void jpeg_reset(void __iomem *regs)
 	}
 }
 
-static inline void jpeg_poweron(void __iomem *regs)
+void jpeg_poweron(void __iomem *regs)
 {
 	writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
 }
 
-static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
+void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
 {
 	unsigned long reg, m;
 
@@ -63,7 +51,7 @@ static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
 	writel(reg, regs + S5P_JPGCMOD);
 }
 
-static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
+void jpeg_input_raw_y16(void __iomem *regs, bool y16)
 {
 	unsigned long reg;
 
@@ -75,7 +63,7 @@ static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
 	writel(reg, regs + S5P_JPGCMOD);
 }
 
-static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
+void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
 {
 	unsigned long reg, m;
 
@@ -90,7 +78,7 @@ static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
 	writel(reg, regs + S5P_JPGMOD);
 }
 
-static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
+void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
 {
 	unsigned long reg, m;
 
@@ -105,12 +93,12 @@ static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
 	writel(reg, regs + S5P_JPGMOD);
 }
 
-static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
 {
 	return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
 }
 
-static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
+void jpeg_dri(void __iomem *regs, unsigned int dri)
 {
 	unsigned long reg;
 
@@ -125,7 +113,7 @@ static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
 	writel(reg, regs + S5P_JPGDRI_L);
 }
 
-static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
 {
 	unsigned long reg;
 
@@ -135,7 +123,7 @@ static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
 	writel(reg, regs + S5P_JPG_QTBL);
 }
 
-static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
 {
 	unsigned long reg;
 
@@ -146,7 +134,7 @@ static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
 	writel(reg, regs + S5P_JPG_HTBL);
 }
 
-static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
 {
 	unsigned long reg;
 
@@ -157,7 +145,7 @@ static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
 	writel(reg, regs + S5P_JPG_HTBL);
 }
 
-static inline void jpeg_y(void __iomem *regs, unsigned int y)
+void jpeg_y(void __iomem *regs, unsigned int y)
 {
 	unsigned long reg;
 
@@ -172,7 +160,7 @@ static inline void jpeg_y(void __iomem *regs, unsigned int y)
 	writel(reg, regs + S5P_JPGY_L);
 }
 
-static inline void jpeg_x(void __iomem *regs, unsigned int x)
+void jpeg_x(void __iomem *regs, unsigned int x)
 {
 	unsigned long reg;
 
@@ -187,7 +175,7 @@ static inline void jpeg_x(void __iomem *regs, unsigned int x)
 	writel(reg, regs + S5P_JPGX_L);
 }
 
-static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
+void jpeg_rst_int_enable(void __iomem *regs, bool enable)
 {
 	unsigned long reg;
 
@@ -198,7 +186,7 @@ static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
 	writel(reg, regs + S5P_JPGINTSE);
 }
 
-static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
+void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
 {
 	unsigned long reg;
 
@@ -209,7 +197,7 @@ static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
 	writel(reg, regs + S5P_JPGINTSE);
 }
 
-static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
+void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
 {
 	unsigned long reg;
 
@@ -220,7 +208,7 @@ static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
 	writel(reg, regs + S5P_JPGINTSE);
 }
 
-static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
+void jpeg_timer_enable(void __iomem *regs, unsigned long val)
 {
 	unsigned long reg;
 
@@ -231,7 +219,7 @@ static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
 	writel(reg, regs + S5P_JPG_TIMER_SE);
 }
 
-static inline void jpeg_timer_disable(void __iomem *regs)
+void jpeg_timer_disable(void __iomem *regs)
 {
 	unsigned long reg;
 
@@ -240,13 +228,13 @@ static inline void jpeg_timer_disable(void __iomem *regs)
 	writel(reg, regs + S5P_JPG_TIMER_SE);
 }
 
-static inline int jpeg_timer_stat(void __iomem *regs)
+int jpeg_timer_stat(void __iomem *regs)
 {
 	return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
 		     >> S5P_TIMER_INT_STAT_SHIFT);
 }
 
-static inline void jpeg_clear_timer_stat(void __iomem *regs)
+void jpeg_clear_timer_stat(void __iomem *regs)
 {
 	unsigned long reg;
 
@@ -255,7 +243,7 @@ static inline void jpeg_clear_timer_stat(void __iomem *regs)
 	writel(reg, regs + S5P_JPG_TIMER_SE);
 }
 
-static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
+void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
 {
 	unsigned long reg;
 
@@ -266,13 +254,13 @@ static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
 	writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
 }
 
-static inline int jpeg_enc_stream_stat(void __iomem *regs)
+int jpeg_enc_stream_stat(void __iomem *regs)
 {
 	return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
 		     S5P_ENC_STREAM_INT_STAT_MASK);
 }
 
-static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
+void jpeg_clear_enc_stream_stat(void __iomem *regs)
 {
 	unsigned long reg;
 
@@ -281,7 +269,7 @@ static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
 	writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
 }
 
-static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
+void jpeg_outform_raw(void __iomem *regs, unsigned long format)
 {
 	unsigned long reg, f;
 
@@ -296,17 +284,17 @@ static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
 	writel(reg, regs + S5P_JPG_OUTFORM);
 }
 
-static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
+void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
 {
 	writel(addr, regs + S5P_JPG_JPGADR);
 }
 
-static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
+void jpeg_imgadr(void __iomem *regs, unsigned long addr)
 {
 	writel(addr, regs + S5P_JPG_IMGADR);
 }
 
-static inline void jpeg_coef(void __iomem *regs, unsigned int i,
+void jpeg_coef(void __iomem *regs, unsigned int i,
 			     unsigned int j, unsigned int coef)
 {
 	unsigned long reg;
@@ -317,24 +305,24 @@ static inline void jpeg_coef(void __iomem *regs, unsigned int i,
 	writel(reg, regs + S5P_JPG_COEF(i));
 }
 
-static inline void jpeg_start(void __iomem *regs)
+void jpeg_start(void __iomem *regs)
 {
 	writel(1, regs + S5P_JSTART);
 }
 
-static inline int jpeg_result_stat_ok(void __iomem *regs)
+int jpeg_result_stat_ok(void __iomem *regs)
 {
 	return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
 		     >> S5P_RESULT_STAT_SHIFT);
 }
 
-static inline int jpeg_stream_stat_ok(void __iomem *regs)
+int jpeg_stream_stat_ok(void __iomem *regs)
 {
 	return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
 		      >> S5P_STREAM_STAT_SHIFT);
 }
 
-static inline void jpeg_clear_int(void __iomem *regs)
+void jpeg_clear_int(void __iomem *regs)
 {
 	unsigned long reg;
 
@@ -343,7 +331,7 @@ static inline void jpeg_clear_int(void __iomem *regs)
 	reg = readl(regs + S5P_JPGOPR);
 }
 
-static inline unsigned int jpeg_compressed_size(void __iomem *regs)
+unsigned int jpeg_compressed_size(void __iomem *regs)
 {
 	unsigned long jpeg_size = 0;
 
@@ -353,5 +341,3 @@ static inline unsigned int jpeg_compressed_size(void __iomem *regs)
 
 	return (unsigned int)jpeg_size;
 }
-
-#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
new file mode 100644
index 0000000..ff6f5f0
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
@@ -0,0 +1,63 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef JPEG_HW_S5P_H_
+#define JPEG_HW_S5P_H_
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+
+#include "jpeg-regs.h"
+
+#define S5P_JPEG_MIN_WIDTH		32
+#define S5P_JPEG_MIN_HEIGHT		32
+#define S5P_JPEG_MAX_WIDTH		8192
+#define S5P_JPEG_MAX_HEIGHT		8192
+#define S5P_JPEG_RAW_IN_565		0
+#define S5P_JPEG_RAW_IN_422		1
+#define S5P_JPEG_RAW_OUT_422		0
+#define S5P_JPEG_RAW_OUT_420		1
+
+void jpeg_reset(void __iomem *regs);
+void jpeg_poweron(void __iomem *regs);
+void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode);
+void jpeg_input_raw_y16(void __iomem *regs, bool y16);
+void jpeg_proc_mode(void __iomem *regs, unsigned long mode);
+void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode);
+unsigned int jpeg_get_subsampling_mode(void __iomem *regs);
+void jpeg_dri(void __iomem *regs, unsigned int dri);
+void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n);
+void jpeg_htbl_ac(void __iomem *regs, unsigned int t);
+void jpeg_htbl_dc(void __iomem *regs, unsigned int t);
+void jpeg_y(void __iomem *regs, unsigned int y);
+void jpeg_x(void __iomem *regs, unsigned int x);
+void jpeg_rst_int_enable(void __iomem *regs, bool enable);
+void jpeg_data_num_int_enable(void __iomem *regs, bool enable);
+void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl);
+void jpeg_timer_enable(void __iomem *regs, unsigned long val);
+void jpeg_timer_disable(void __iomem *regs);
+int jpeg_timer_stat(void __iomem *regs);
+void jpeg_clear_timer_stat(void __iomem *regs);
+void jpeg_enc_stream_int(void __iomem *regs, unsigned long size);
+int jpeg_enc_stream_stat(void __iomem *regs);
+void jpeg_clear_enc_stream_stat(void __iomem *regs);
+void jpeg_outform_raw(void __iomem *regs, unsigned long format);
+void jpeg_jpgadr(void __iomem *regs, unsigned long addr);
+void jpeg_imgadr(void __iomem *regs, unsigned long addr);
+void jpeg_coef(void __iomem *regs, unsigned int i,
+			     unsigned int j, unsigned int coef);
+void jpeg_start(void __iomem *regs);
+int jpeg_result_stat_ok(void __iomem *regs);
+int jpeg_stream_stat_ok(void __iomem *regs);
+void jpeg_clear_int(void __iomem *regs);
+unsigned int jpeg_compressed_size(void __iomem *regs);
+
+#endif /* JPEG_HW_S5P_H_ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 10/16] s5p-jpeg: Add hardware API for the exynos4x12 JPEG codec.
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (8 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 09/16] s5p-jpeg: Split jpeg-hw.h to jpeg-hw-s5p.c and jpeg-hw-s5p.c Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 11/16] s5p-jpeg: Retrieve "YCbCr subsampling" field from the jpeg header Jacek Anaszewski
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/Makefile         |    2 +-
 drivers/media/platform/s5p-jpeg/jpeg-core.c      |  620 +++++++++++++++++++---
 drivers/media/platform/s5p-jpeg/jpeg-core.h      |   72 ++-
 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c |  293 ++++++++++
 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h |   44 ++
 drivers/media/platform/s5p-jpeg/jpeg-regs.h      |  215 +++++++-
 6 files changed, 1152 insertions(+), 94 deletions(-)
 create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c
 create mode 100644 drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h

diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile
index faf6398..f981dff 100644
--- a/drivers/media/platform/s5p-jpeg/Makefile
+++ b/drivers/media/platform/s5p-jpeg/Makefile
@@ -1,2 +1,2 @@
-s5p-jpeg-objs := jpeg-core.o jpeg-hw-s5p.o
+s5p-jpeg-objs := jpeg-core.o jpeg-hw-exynos.o jpeg-hw-s5p.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 4e874ad..68a82cc 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1,9 +1,10 @@
 /* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -30,58 +31,212 @@
 
 #include "jpeg-core.h"
 #include "jpeg-hw-s5p.h"
+#include "jpeg-hw-exynos.h"
+#include "jpeg-regs.h"
 
-static struct s5p_jpeg_fmt formats_enc[] = {
+static struct s5p_jpeg_fmt sjpeg_formats[] = {
 	{
 		.name		= "JPEG JFIF",
 		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.flags		= SJPEG_FMT_FLAG_ENC_CAPTURE |
+				  SJPEG_FMT_FLAG_DEC_OUTPUT |
+				  SJPEG_FMT_FLAG_S5P |
+				  SJPEG_FMT_FLAG_EXYNOS,
+	},
+	{
+		.name		= "YUV 4:2:2 packed, YCbYCr",
+		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.depth		= 16,
 		.colplanes	= 1,
-		.types		= MEM2MEM_CAPTURE,
+		.h_align	= 4,
+		.v_align	= 3,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_S5P |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_422,
 	},
 	{
 		.name		= "YUV 4:2:2 packed, YCbYCr",
 		.fourcc		= V4L2_PIX_FMT_YUYV,
 		.depth		= 16,
 		.colplanes	= 1,
-		.types		= MEM2MEM_OUTPUT,
+		.h_align	= 1,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+	},
+	{
+		.name		= "YUV 4:2:2 packed, YCrYCb",
+		.fourcc		= V4L2_PIX_FMT_YVYU,
+		.depth		= 16,
+		.colplanes	= 1,
+		.h_align	= 1,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_422,
 	},
 	{
 		.name		= "RGB565",
 		.fourcc		= V4L2_PIX_FMT_RGB565,
 		.depth		= 16,
 		.colplanes	= 1,
-		.types		= MEM2MEM_OUTPUT,
+		.h_align	= 0,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+	},
+	{
+		.name		= "RGB565",
+		.fourcc		= V4L2_PIX_FMT_RGB565,
+		.depth		= 16,
+		.colplanes	= 1,
+		.h_align	= 0,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_S5P |
+				  SJPEG_FMT_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+	},
+	{
+		.name		= "ARGB8888, 32 bpp",
+		.fourcc		= V4L2_PIX_FMT_RGB32,
+		.depth		= 32,
+		.colplanes	= 1,
+		.h_align	= 0,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+	},
+	{
+		.name		= "YUV 4:4:4 planar, Y/CbCr",
+		.fourcc		= V4L2_PIX_FMT_NV24,
+		.depth		= 24,
+		.colplanes	= 2,
+		.h_align	= 0,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+	},
+	{
+		.name		= "YUV 4:4:4 planar, Y/CrCb",
+		.fourcc		= V4L2_PIX_FMT_NV42,
+		.depth		= 24,
+		.colplanes	= 2,
+		.h_align	= 0,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+	},
+	{
+		.name		= "YUV 4:2:2 planar, Y/CrCb",
+		.fourcc		= V4L2_PIX_FMT_NV61,
+		.depth		= 16,
+		.colplanes	= 2,
+		.h_align	= 1,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_422,
 	},
-};
-#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
-
-static struct s5p_jpeg_fmt formats_dec[] = {
 	{
-		.name		= "YUV 4:2:0 planar, YCbCr",
+		.name		= "YUV 4:2:2 planar, Y/CbCr",
+		.fourcc		= V4L2_PIX_FMT_NV16,
+		.depth		= 16,
+		.colplanes	= 2,
+		.h_align	= 1,
+		.v_align	= 0,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+	},
+	{
+		.name		= "YUV 4:2:0 planar, Y/CbCr",
 		.fourcc		= V4L2_PIX_FMT_NV12,
-		.depth		= 12,
-		.colplanes	= 3,
-		.h_align	= 4,
-		.v_align	= 4,
-		.types		= MEM2MEM_CAPTURE,
+		.depth		= 16,
+		.colplanes	= 2,
+		.h_align	= 1,
+		.v_align	= 1,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_420,
 	},
 	{
-		.name		= "YUV 4:2:2 packed, YCbYCr",
-		.fourcc		= V4L2_PIX_FMT_YUYV,
+		.name		= "YUV 4:2:0 planar, Y/CbCr",
+		.fourcc		= V4L2_PIX_FMT_NV12,
 		.depth		= 16,
-		.colplanes	= 1,
+		.colplanes	= 4,
 		.h_align	= 4,
-		.v_align	= 3,
-		.types		= MEM2MEM_CAPTURE,
+		.v_align	= 1,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_S5P |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_420,
 	},
 	{
-		.name		= "JPEG JFIF",
-		.fourcc		= V4L2_PIX_FMT_JPEG,
+		.name		= "YUV 4:2:0 planar, Y/CrCb",
+		.fourcc		= V4L2_PIX_FMT_NV21,
+		.depth		= 12,
+		.colplanes	= 2,
+		.h_align	= 1,
+		.v_align	= 1,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+	},
+	{
+		.name		= "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
+		.fourcc		= V4L2_PIX_FMT_YUV420,
+		.depth		= 12,
+		.colplanes	= 3,
+		.h_align	= 1,
+		.v_align	= 1,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+	},
+	{
+		.name		= "Gray",
+		.fourcc		= V4L2_PIX_FMT_GREY,
+		.depth		= 8,
 		.colplanes	= 1,
-		.types		= MEM2MEM_OUTPUT,
+		.flags		= SJPEG_FMT_FLAG_ENC_OUTPUT |
+				  SJPEG_FMT_FLAG_DEC_CAPTURE |
+				  SJPEG_FMT_FLAG_EXYNOS |
+				  SJPEG_FMT_NON_RGB,
+		.subsampling	= V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
 	},
 };
-#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
+#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
 
 static const unsigned char qtbl_luminance[4][64] = {
 	{/*level 0 - high compression quality */
@@ -277,6 +432,58 @@ static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
 						ARRAY_SIZE(hactblg0));
 }
 
+static inline void exynos_jpeg_set_tbl(void __iomem *regs,
+				      const unsigned char *tbl,
+				      unsigned long tab, int len)
+{
+	int i;
+	unsigned int dword;
+
+	for (i = 0; i < len; i += 4) {
+		dword = tbl[i] |
+			(tbl[i + 1] << 8) |
+			(tbl[i + 2] << 16) |
+			(tbl[i + 3] << 24);
+		writel(dword, regs + tab + i);
+	}
+}
+
+static inline void exynos_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+{
+	/* this driver fills quantisation table 0 with data for luma */
+	exynos_jpeg_set_tbl(regs, qtbl_luminance[quality],
+			     EXYNOS_QTBL_CONTENT(0),
+			     ARRAY_SIZE(qtbl_luminance[quality]));
+}
+
+static inline void exynos_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+{
+	/* this driver fills quantisation table 1 with data for chroma */
+	exynos_jpeg_set_tbl(regs, qtbl_chrominance[quality],
+			     EXYNOS_QTBL_CONTENT(1),
+			     ARRAY_SIZE(qtbl_chrominance[quality]));
+}
+
+void exynos_jpeg_set_huff_tbl(void __iomem *base)
+{
+	exynos_jpeg_set_tbl(base, hdctbl0, EXYNOS_HUFF_TBL_HDCLL,
+							ARRAY_SIZE(hdctbl0));
+	exynos_jpeg_set_tbl(base, hdctbl0, EXYNOS_HUFF_TBL_HDCCL,
+							ARRAY_SIZE(hdctbl0));
+	exynos_jpeg_set_tbl(base, hdctblg0, EXYNOS_HUFF_TBL_HDCLV,
+							ARRAY_SIZE(hdctblg0));
+	exynos_jpeg_set_tbl(base, hdctblg0, EXYNOS_HUFF_TBL_HDCCV,
+							ARRAY_SIZE(hdctblg0));
+	exynos_jpeg_set_tbl(base, hactbl0, EXYNOS_HUFF_TBL_HACLL,
+							ARRAY_SIZE(hactbl0));
+	exynos_jpeg_set_tbl(base, hactbl0, EXYNOS_HUFF_TBL_HACCL,
+							ARRAY_SIZE(hactbl0));
+	exynos_jpeg_set_tbl(base, hactblg0, EXYNOS_HUFF_TBL_HACLV,
+							ARRAY_SIZE(hactblg0));
+	exynos_jpeg_set_tbl(base, hactblg0, EXYNOS_HUFF_TBL_HACCV,
+							ARRAY_SIZE(hactblg0));
+}
+
 /*
  * ============================================================================
  * Device file operations
@@ -285,8 +492,8 @@ static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
 
 static int queue_init(void *priv, struct vb2_queue *src_vq,
 		      struct vb2_queue *dst_vq);
-static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
-						 __u32 pixelformat);
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
+				__u32 pixelformat, unsigned int fmt_type);
 static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
 
 static int s5p_jpeg_open(struct file *file)
@@ -294,7 +501,7 @@ static int s5p_jpeg_open(struct file *file)
 	struct s5p_jpeg *jpeg = video_drvdata(file);
 	struct video_device *vfd = video_devdata(file);
 	struct s5p_jpeg_ctx *ctx;
-	struct s5p_jpeg_fmt *out_fmt;
+	struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
 	int ret = 0;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -315,16 +522,18 @@ static int s5p_jpeg_open(struct file *file)
 	ctx->jpeg = jpeg;
 	if (vfd == jpeg->vfd_encoder) {
 		ctx->mode = S5P_JPEG_ENCODE;
-		out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
+		out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
+							FMT_TYPE_OUTPUT);
+		cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+							FMT_TYPE_CAPTURE);
 	} else {
 		ctx->mode = S5P_JPEG_DECODE;
-		out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
+		out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+							FMT_TYPE_OUTPUT);
+		cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
+							FMT_TYPE_CAPTURE);
 	}
 
-	ret = s5p_jpeg_controls_create(ctx);
-	if (ret < 0)
-		goto error;
-
 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
 	if (IS_ERR(ctx->fh.m2m_ctx)) {
 		ret = PTR_ERR(ctx->fh.m2m_ctx);
@@ -332,7 +541,12 @@ static int s5p_jpeg_open(struct file *file)
 	}
 
 	ctx->out_q.fmt = out_fmt;
-	ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
+	ctx->cap_q.fmt = cap_fmt;
+
+	ret = s5p_jpeg_controls_create(ctx);
+	if (ret < 0)
+		goto error;
+
 	mutex_unlock(&jpeg->lock);
 	return 0;
 
@@ -352,11 +566,11 @@ static int s5p_jpeg_release(struct file *file)
 
 	mutex_lock(&jpeg->lock);
 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
-	mutex_unlock(&jpeg->lock);
 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 	v4l2_fh_del(&ctx->fh);
 	v4l2_fh_exit(&ctx->fh);
 	kfree(ctx);
+	mutex_unlock(&jpeg->lock);
 
 	return 0;
 }
@@ -504,13 +718,13 @@ static int s5p_jpeg_querycap(struct file *file, void *priv,
 	return 0;
 }
 
-static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
+static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
 		    struct v4l2_fmtdesc *f, u32 type)
 {
 	int i, num = 0;
 
 	for (i = 0; i < n; ++i) {
-		if (formats[i].types & type) {
+		if (sjpeg_formats[i].flags & type) {
 			/* index-th format of type type found ? */
 			if (num == f->index)
 				break;
@@ -524,8 +738,8 @@ static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
 	if (i >= n)
 		return -EINVAL;
 
-	strlcpy(f->description, formats[i].name, sizeof(f->description));
-	f->pixelformat = formats[i].fourcc;
+	strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
+	f->pixelformat = sjpeg_formats[i].fourcc;
 
 	return 0;
 }
@@ -536,10 +750,11 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
-		return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
-				MEM2MEM_CAPTURE);
+		return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+				SJPEG_FMT_FLAG_ENC_CAPTURE);
 
-	return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
+	return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+					SJPEG_FMT_FLAG_DEC_CAPTURE);
 }
 
 static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
@@ -548,10 +763,11 @@ static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (ctx->mode == S5P_JPEG_ENCODE)
-		return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
-				MEM2MEM_OUTPUT);
+		return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+				SJPEG_FMT_FLAG_ENC_OUTPUT);
 
-	return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
+	return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+					SJPEG_FMT_FLAG_DEC_OUTPUT);
 }
 
 static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
@@ -598,29 +814,35 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 	return 0;
 }
 
-static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
-						 u32 pixelformat)
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
+				u32 pixelformat, unsigned int fmt_type)
 {
-	unsigned int k;
-	struct s5p_jpeg_fmt *formats;
-	int n;
+	unsigned int k, fmt_flag, ver_flag;
 
-	if (mode == S5P_JPEG_ENCODE) {
-		formats = formats_enc;
-		n = NUM_FORMATS_ENC;
-	} else {
-		formats = formats_dec;
-		n = NUM_FORMATS_DEC;
-	}
+	if (ctx->mode == S5P_JPEG_ENCODE)
+		fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
+				SJPEG_FMT_FLAG_ENC_OUTPUT :
+				SJPEG_FMT_FLAG_ENC_CAPTURE;
+	else
+		fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
+				SJPEG_FMT_FLAG_DEC_OUTPUT :
+				SJPEG_FMT_FLAG_DEC_CAPTURE;
 
-	for (k = 0; k < n; k++) {
-		struct s5p_jpeg_fmt *fmt = &formats[k];
-		if (fmt->fourcc == pixelformat)
+	if (ctx->jpeg->variant->version == SJPEG_S5P)
+		ver_flag = SJPEG_FMT_FLAG_S5P;
+	else
+		ver_flag = SJPEG_FMT_FLAG_EXYNOS;
+
+	for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
+		struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
+		if (fmt->fourcc == pixelformat &&
+		    fmt->flags & fmt_flag &&
+		    fmt->flags & ver_flag) {
 			return fmt;
+		}
 	}
 
 	return NULL;
-
 }
 
 static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
@@ -656,7 +878,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
 
 	/* V4L2 specification suggests the driver corrects the format struct
 	 * if any of the dimensions is unsupported */
-	if (q_type == MEM2MEM_OUTPUT)
+	if (q_type == FMT_TYPE_OUTPUT)
 		jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
 				       S5P_JPEG_MAX_WIDTH, 0,
 				       &pix->height, S5P_JPEG_MIN_HEIGHT,
@@ -694,15 +916,16 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_jpeg_fmt *fmt;
 
-	fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
-	if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+	fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
+						FMT_TYPE_CAPTURE);
+	if (!fmt) {
 		v4l2_err(&ctx->jpeg->v4l2_dev,
 			 "Fourcc format (0x%08x) invalid.\n",
 			 f->fmt.pix.pixelformat);
 		return -EINVAL;
 	}
 
-	return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
+	return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
 }
 
 static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
@@ -711,15 +934,16 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_jpeg_fmt *fmt;
 
-	fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
-	if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+	fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
+						FMT_TYPE_OUTPUT);
+	if (!fmt) {
 		v4l2_err(&ctx->jpeg->v4l2_dev,
 			 "Fourcc format (0x%08x) invalid.\n",
 			 f->fmt.pix.pixelformat);
 		return -EINVAL;
 	}
 
-	return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
+	return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
 }
 
 static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
@@ -727,6 +951,7 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
 	struct vb2_queue *vq;
 	struct s5p_jpeg_q_data *q_data = NULL;
 	struct v4l2_pix_format *pix = &f->fmt.pix;
+	unsigned int f_type;
 
 	vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
 	if (!vq)
@@ -740,7 +965,10 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
 		return -EBUSY;
 	}
 
-	q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
+	f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
+			FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
+
+	q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
 	q_data->w = pix->width;
 	q_data->h = pix->height;
 	if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
@@ -781,7 +1009,8 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv,
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
 	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-	    s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+	    s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    ctx->jpeg->variant->version != SJPEG_S5P)
 		return -EINVAL;
 
 	/* For JPEG blob active == default == bounds */
@@ -1007,6 +1236,106 @@ static void s5p_jpeg_device_run(void *priv)
 	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
 }
 
+static void exynos_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
+{
+	struct s5p_jpeg *jpeg = ctx->jpeg;
+	struct s5p_jpeg_fmt *fmt;
+	struct vb2_buffer *vb;
+	struct s5p_jpeg_addr jpeg_addr;
+	u32 pix_size, padding_bytes = 0;
+
+	pix_size = ctx->cap_q.w * ctx->cap_q.h;
+
+	if (ctx->mode == S5P_JPEG_ENCODE) {
+		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+		fmt = ctx->out_q.fmt;
+		if (ctx->out_q.w % 2 && fmt->h_align > 0)
+			padding_bytes = ctx->out_q.h;
+	} else {
+		fmt = ctx->cap_q.fmt;
+		vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	}
+
+	jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+	if (fmt->colplanes == 2) {
+		jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
+	} else if (fmt->colplanes == 3) {
+		jpeg_addr.cb = jpeg_addr.y + pix_size;
+		if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
+			jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
+		else
+			jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
+	}
+
+	jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
+}
+
+static void exynos_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
+{
+	struct s5p_jpeg *jpeg = ctx->jpeg;
+	struct vb2_buffer *vb;
+	unsigned int jpeg_addr = 0;
+
+	if (ctx->mode == S5P_JPEG_ENCODE)
+		vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	else
+		vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+	jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+	jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
+}
+
+static void exynos_jpeg_device_run(void *priv)
+{
+	struct s5p_jpeg_ctx *ctx = priv;
+	struct s5p_jpeg *jpeg = ctx->jpeg;
+	unsigned int bitstream_size;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+	if (ctx->mode == S5P_JPEG_ENCODE) {
+		jpeg_sw_reset(jpeg->regs);
+		jpeg_set_interrupt(jpeg->regs);
+		jpeg_set_huf_table_enable(jpeg->regs, 1);
+
+		exynos_jpeg_set_huff_tbl(jpeg->regs);
+
+		/*
+		 * JPEG IP allows storing 4 quantization tables
+		 * We fill table 0 for luma and table 1 for chroma
+		 */
+		exynos_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+		exynos_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+
+		jpeg_set_encode_tbl_select(jpeg->regs, ctx->compr_quality);
+		jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w, ctx->cap_q.h);
+
+		jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
+		jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
+		exynos_jpeg_set_img_addr(ctx);
+		exynos_jpeg_set_jpeg_addr(ctx);
+		jpeg_set_encode_hoff_cnt(jpeg->regs, ctx->out_q.fmt->fourcc);
+		jpeg_set_timer_count(jpeg->regs,
+				     ctx->cap_q.w * ctx->cap_q.h * 32 + 0xff);
+	} else {
+		jpeg_sw_reset(jpeg->regs);
+		jpeg_set_interrupt(jpeg->regs);
+		exynos_jpeg_set_img_addr(ctx);
+		exynos_jpeg_set_jpeg_addr(ctx);
+		jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
+
+		bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
+
+		jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
+	}
+
+	jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
+
+	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+}
+
 static int s5p_jpeg_job_ready(void *priv)
 {
 	struct s5p_jpeg_ctx *ctx = priv;
@@ -1024,6 +1353,12 @@ static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
 	.device_run	= s5p_jpeg_device_run,
 	.job_ready	= s5p_jpeg_job_ready,
 	.job_abort	= s5p_jpeg_job_abort,
+}
+;
+static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
+	.device_run	= exynos_jpeg_device_run,
+	.job_ready	= s5p_jpeg_job_ready,
+	.job_abort	= s5p_jpeg_job_abort,
 };
 
 /*
@@ -1229,6 +1564,69 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t exynos_jpeg_irq(int irq, void *priv)
+{
+	unsigned int int_status;
+	struct vb2_buffer *src_vb, *dst_vb;
+	struct s5p_jpeg *jpeg = priv;
+	struct s5p_jpeg_ctx *curr_ctx;
+	unsigned long payload_size = 0;
+
+	spin_lock(&jpeg->slock);
+
+	curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+
+	src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+	dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+
+	int_status = jpeg_get_int_status(jpeg->regs);
+
+	if (int_status) {
+		switch (int_status & 0x1f) {
+		case 0x1:
+			jpeg->irq_ret = ERR_PROT;
+			break;
+		case 0x2:
+			jpeg->irq_ret = OK_ENC_OR_DEC;
+			break;
+		case 0x4:
+			jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
+			break;
+		case 0x8:
+			jpeg->irq_ret = ERR_MULTI_SCAN;
+			break;
+		case 0x10:
+			jpeg->irq_ret = ERR_FRAME;
+			break;
+		default:
+			jpeg->irq_ret = ERR_UNKNOWN;
+			break;
+		}
+	} else {
+		jpeg->irq_ret = ERR_UNKNOWN;
+	}
+
+	if (jpeg->irq_ret == OK_ENC_OR_DEC) {
+		if (curr_ctx->mode == S5P_JPEG_ENCODE) {
+			payload_size = jpeg_get_stream_size(jpeg->regs);
+			vb2_set_plane_payload(dst_vb, 0, payload_size);
+		}
+		v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+		v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+	} else {
+		v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+		v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+	}
+
+	v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
+	curr_ctx->subsampling = jpeg_get_frame_fmt(jpeg->regs);
+
+	spin_unlock(&jpeg->slock);
+	return IRQ_HANDLED;
+}
+
+static void *jpeg_get_drv_data(struct platform_device *pdev);
+
 /*
  * ============================================================================
  * Driver basic infrastructure
@@ -1239,13 +1637,19 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 {
 	struct s5p_jpeg *jpeg;
 	struct resource *res;
+	struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
 	int ret;
 
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
 	/* JPEG IP abstraction struct */
 	jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
 	if (!jpeg)
 		return -ENOMEM;
 
+	jpeg->variant = jpeg_get_drv_data(pdev);
+
 	mutex_init(&jpeg->lock);
 	spin_lock_init(&jpeg->slock);
 	jpeg->dev = &pdev->dev;
@@ -1273,8 +1677,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 		goto clk_get_rollback;
 	}
 
-	ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
-			dev_name(&pdev->dev), jpeg);
+	ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
+				0, dev_name(&pdev->dev), jpeg);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
 		goto clk_get_rollback;
@@ -1287,8 +1691,13 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 		goto clk_get_rollback;
 	}
 
+	if (jpeg->variant->version == SJPEG_S5P)
+		samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
+	else
+		samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
+
 	/* mem2mem device */
-	jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
+	jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
 	if (IS_ERR(jpeg->m2m_dev)) {
 		v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
 		ret = PTR_ERR(jpeg->m2m_dev);
@@ -1433,12 +1842,16 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
 
 	/*
 	 * JPEG IP allows storing two Huffman tables for each component
-	 * We fill table 0 for each component
+	 * We fill table 0 for each component and do this here only
+	 * for S5PC210 device as Exynos4x12 requires programming its
+	 * Huffman tables each time the encoding process is initialized.
 	 */
-	s5p_jpeg_set_hdctbl(jpeg->regs);
-	s5p_jpeg_set_hdctblg(jpeg->regs);
-	s5p_jpeg_set_hactbl(jpeg->regs);
-	s5p_jpeg_set_hactblg(jpeg->regs);
+	if (jpeg->variant->version == SJPEG_S5P) {
+		s5p_jpeg_set_hdctbl(jpeg->regs);
+		s5p_jpeg_set_hdctblg(jpeg->regs);
+		s5p_jpeg_set_hactbl(jpeg->regs);
+		s5p_jpeg_set_hactblg(jpeg->regs);
+	}
 
 	spin_unlock_irqrestore(&jpeg->slock, flags);
 
@@ -1465,27 +1878,60 @@ static const struct dev_pm_ops s5p_jpeg_pm_ops = {
 };
 
 #ifdef CONFIG_OF
-static const struct of_device_id s5p_jpeg_of_match[] = {
-	{ .compatible = "samsung,s5pv210-jpeg" },
-	{ .compatible = "samsung,exynos4210-jpeg" },
-	{ /* sentinel */ },
+static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
+	.version	= SJPEG_S5P,
+	.jpeg_irq	= s5p_jpeg_irq,
 };
-MODULE_DEVICE_TABLE(of, s5p_jpeg_of_match);
+
+static struct s5p_jpeg_variant exynos_jpeg_drvdata = {
+	.version	= SJPEG_EXYNOS,
+	.jpeg_irq	= exynos_jpeg_irq,
+};
+
+static const struct of_device_id samsung_jpeg_match[] = {
+	{
+		.compatible = "samsung,s5pv210-jpeg",
+		.data = &s5p_jpeg_drvdata,
+	}, {
+		.compatible = "samsung,exynos4210-jpeg",
+		.data = &s5p_jpeg_drvdata,
+	}, {
+		.compatible = "samsung,exynos4212-jpeg",
+		.data = &exynos_jpeg_drvdata,
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
+
+static void *jpeg_get_drv_data(struct platform_device *pdev)
+{
+	struct s5p_jpeg_variant *driver_data = NULL;
+	const struct of_device_id *match;
+
+	match = of_match_node(of_match_ptr(samsung_jpeg_match),
+					 pdev->dev.of_node);
+	if (match)
+		driver_data = (struct s5p_jpeg_variant *)match->data;
+
+	return driver_data;
+}
 #endif
 
 static struct platform_driver s5p_jpeg_driver = {
 	.probe = s5p_jpeg_probe,
 	.remove = s5p_jpeg_remove,
 	.driver = {
-		.of_match_table = of_match_ptr(s5p_jpeg_of_match),
-		.owner = THIS_MODULE,
-		.name = S5P_JPEG_M2M_NAME,
-		.pm = &s5p_jpeg_pm_ops,
+		.of_match_table	= of_match_ptr(samsung_jpeg_match),
+		.owner		= THIS_MODULE,
+		.name		= S5P_JPEG_M2M_NAME,
+		.pm		= &s5p_jpeg_pm_ops,
 	},
 };
 
 module_platform_driver(s5p_jpeg_driver);
 
 MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
 MODULE_DESCRIPTION("Samsung JPEG codec driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 7baadf3..749bc61 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -13,6 +13,7 @@
 #ifndef JPEG_CORE_H_
 #define JPEG_CORE_H_
 
+#include <linux/interrupt.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ctrls.h>
@@ -42,12 +43,52 @@
 #define EOI				0xd9
 #define DHP				0xde
 
+/* Flags that indicate a format can be used for capture/output */
+#define SJPEG_FMT_FLAG_ENC_CAPTURE	(1 << 0)
+#define SJPEG_FMT_FLAG_ENC_OUTPUT	(1 << 1)
+#define SJPEG_FMT_FLAG_DEC_CAPTURE	(1 << 2)
+#define SJPEG_FMT_FLAG_DEC_OUTPUT	(1 << 3)
+#define SJPEG_FMT_FLAG_S5P		(1 << 4)
+#define SJPEG_FMT_FLAG_EXYNOS		(1 << 5)
+#define SJPEG_FMT_RGB			(1 << 6)
+#define SJPEG_FMT_NON_RGB		(1 << 7)
+
 #define S5P_JPEG_ENCODE		0
 #define S5P_JPEG_DECODE		1
 
-/* Flags that indicate a format can be used for capture/output */
-#define MEM2MEM_CAPTURE			(1 << 0)
-#define MEM2MEM_OUTPUT			(1 << 1)
+#define FMT_TYPE_OUTPUT		0
+#define FMT_TYPE_CAPTURE	1
+
+#define SJPEG_SUBSAMPLING_444	0x11
+#define SJPEG_SUBSAMPLING_422	0x21
+#define SJPEG_SUBSAMPLING_420	0x22
+
+/* Version numbers */
+
+#define SJPEG_S5P	1
+#define SJPEG_EXYNOS	2
+
+enum exynos_jpeg_result {
+	OK_ENC_OR_DEC,
+	ERR_PROT,
+	ERR_DEC_INVALID_FORMAT,
+	ERR_MULTI_SCAN,
+	ERR_FRAME,
+	ERR_UNKNOWN,
+};
+
+enum  exynos_jpeg_img_quality_level {
+	QUALITY_LEVEL_1 = 0,	/* high */
+	QUALITY_LEVEL_2,
+	QUALITY_LEVEL_3,
+	QUALITY_LEVEL_4,	/* low */
+};
+
+enum exynos_jpeg_scale_value {
+	JPEG_SCALE_NORMAL,
+	JPEG_SCALE_2,
+	JPEG_SCALE_4,
+};
 
 
 
@@ -76,9 +117,16 @@ struct s5p_jpeg {
 
 	void __iomem		*regs;
 	unsigned int		irq;
+	enum exynos_jpeg_result	irq_ret;
 	struct clk		*clk;
 	struct device		*dev;
 	void			*alloc_ctx;
+	struct s5p_jpeg_variant *variant;
+};
+
+struct s5p_jpeg_variant {
+	unsigned int	version;
+	irqreturn_t	(*jpeg_irq)(int irq, void *priv);
 };
 
 /**
@@ -89,16 +137,18 @@ struct s5p_jpeg {
  * @colplanes:	number of color planes (1 for packed formats)
  * @h_align:	horizontal alignment order (align to 2^h_align)
  * @v_align:	vertical alignment order (align to 2^v_align)
- * @types:	types of queue this format is applicable to
+ * @flags:	flags describing format applicability
  */
 struct s5p_jpeg_fmt {
 	char	*name;
 	u32	fourcc;
 	int	depth;
 	int	colplanes;
+	int	memplanes;
 	int	h_align;
 	int	v_align;
-	u32	types;
+	int	subsampling;
+	u32	flags;
 };
 
 /**
@@ -150,4 +200,16 @@ struct s5p_jpeg_buffer {
 	unsigned long data;
 };
 
+/**
+ * struct s5p_jpeg_addr - JPEG converter physical address set for DMA
+ * @y:   luminance plane physical address
+ * @cb:  Cb plane physical address
+ * @cr:  Cr plane physical address
+ */
+struct s5p_jpeg_addr {
+	u32     y;
+	u32     cb;
+	u32     cr;
+};
+
 #endif /* JPEG_CORE_H */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c
new file mode 100644
index 0000000..fb57adc
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.c
@@ -0,0 +1,293 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * Register interface file for JPEG driver on Exynos4x12.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw-exynos.h"
+#include "jpeg-regs.h"
+
+void jpeg_sw_reset(void __iomem *base)
+{
+	unsigned int reg;
+
+	reg = readl(base + EXYNOS_JPEG_CNTL_REG);
+	writel(reg & ~EXYNOS_SOFT_RESET_HI, base + EXYNOS_JPEG_CNTL_REG);
+
+	ndelay(100000);
+
+	writel(reg | EXYNOS_SOFT_RESET_HI, base + EXYNOS_JPEG_CNTL_REG);
+}
+
+void jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode)
+{
+	unsigned int reg;
+
+	reg = readl(base + EXYNOS_JPEG_CNTL_REG);
+	/* set jpeg mod register */
+	if (mode == S5P_JPEG_DECODE) {
+		writel((reg & EXYNOS_ENC_DEC_MODE_MASK) |
+					EXYNOS_DEC_MODE,
+			base + EXYNOS_JPEG_CNTL_REG);
+	} else {/* encode */
+		writel((reg & EXYNOS_ENC_DEC_MODE_MASK) |
+					EXYNOS_ENC_MODE,
+			base + EXYNOS_JPEG_CNTL_REG);
+	}
+}
+
+void jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt)
+{
+	unsigned int reg;
+
+	reg = readl(base + EXYNOS_IMG_FMT_REG) &
+			EXYNOS_ENC_IN_FMT_MASK; /* clear except enc format */
+
+	switch (img_fmt) {
+	case V4L2_PIX_FMT_GREY:
+		reg = reg | EXYNOS_ENC_GRAY_IMG | EXYNOS_GRAY_IMG_IP;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		reg = reg | EXYNOS_ENC_RGB_IMG |
+				EXYNOS_RGB_IP_RGB_32BIT_IMG;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		reg = reg | EXYNOS_ENC_RGB_IMG |
+				EXYNOS_RGB_IP_RGB_16BIT_IMG;
+		break;
+	case V4L2_PIX_FMT_NV24:
+		reg = reg | EXYNOS_ENC_YUV_444_IMG |
+				EXYNOS_YUV_444_IP_YUV_444_2P_IMG |
+				EXYNOS_SWAP_CHROMA_CBCR;
+		break;
+	case V4L2_PIX_FMT_NV42:
+		reg = reg | EXYNOS_ENC_YUV_444_IMG |
+				EXYNOS_YUV_444_IP_YUV_444_2P_IMG |
+				EXYNOS_SWAP_CHROMA_CRCB;
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		reg = reg | EXYNOS_DEC_YUV_422_IMG |
+				EXYNOS_YUV_422_IP_YUV_422_1P_IMG |
+				EXYNOS_SWAP_CHROMA_CBCR;
+		break;
+
+	case V4L2_PIX_FMT_YVYU:
+		reg = reg | EXYNOS_DEC_YUV_422_IMG |
+				EXYNOS_YUV_422_IP_YUV_422_1P_IMG |
+				EXYNOS_SWAP_CHROMA_CRCB;
+		break;
+	case V4L2_PIX_FMT_NV16:
+		reg = reg | EXYNOS_DEC_YUV_422_IMG |
+				EXYNOS_YUV_422_IP_YUV_422_2P_IMG |
+				EXYNOS_SWAP_CHROMA_CBCR;
+		break;
+	case V4L2_PIX_FMT_NV61:
+		reg = reg | EXYNOS_DEC_YUV_422_IMG |
+				EXYNOS_YUV_422_IP_YUV_422_2P_IMG |
+				EXYNOS_SWAP_CHROMA_CRCB;
+		break;
+	case V4L2_PIX_FMT_NV12:
+		reg = reg | EXYNOS_DEC_YUV_420_IMG |
+				EXYNOS_YUV_420_IP_YUV_420_2P_IMG |
+				EXYNOS_SWAP_CHROMA_CBCR;
+		break;
+	case V4L2_PIX_FMT_NV21:
+		reg = reg | EXYNOS_DEC_YUV_420_IMG |
+				EXYNOS_YUV_420_IP_YUV_420_2P_IMG |
+				EXYNOS_SWAP_CHROMA_CRCB;
+		break;
+	case V4L2_PIX_FMT_YUV420:
+		reg = reg | EXYNOS_DEC_YUV_420_IMG |
+				EXYNOS_YUV_420_IP_YUV_420_3P_IMG |
+				EXYNOS_SWAP_CHROMA_CBCR;
+		break;
+	default:
+		break;
+
+	}
+
+	writel(reg, base + EXYNOS_IMG_FMT_REG);
+}
+
+void jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt)
+{
+	unsigned int reg;
+
+	reg = readl(base + EXYNOS_IMG_FMT_REG) &
+			~EXYNOS_ENC_FMT_MASK; /* clear enc format */
+
+	switch (out_fmt) {
+	case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+		reg = reg | EXYNOS_ENC_FMT_GRAY;
+		break;
+
+	case V4L2_JPEG_CHROMA_SUBSAMPLING_444:
+		reg = reg | EXYNOS_ENC_FMT_YUV_444;
+		break;
+
+	case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+		reg = reg | EXYNOS_ENC_FMT_YUV_422;
+		break;
+
+	case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+		reg = reg | EXYNOS_ENC_FMT_YUV_420;
+		break;
+
+	default:
+		break;
+	}
+
+	writel(reg, base + EXYNOS_IMG_FMT_REG);
+}
+
+void jpeg_set_interrupt(void __iomem *base)
+{
+	unsigned int reg;
+
+	reg = readl(base + EXYNOS_INT_EN_REG) & ~EXYNOS_INT_EN_MASK;
+	writel(EXYNOS_INT_EN_ALL, base + EXYNOS_INT_EN_REG);
+}
+
+unsigned int jpeg_get_int_status(void __iomem *base)
+{
+	unsigned int	int_status;
+
+	int_status = readl(base + EXYNOS_INT_STATUS_REG);
+
+	return int_status;
+}
+
+unsigned int jpeg_get_fifo_status(void __iomem *base)
+{
+	unsigned int fifo_status;
+
+	fifo_status = readl(base + EXYNOS_FIFO_STATUS_REG);
+
+	return fifo_status;
+}
+
+void jpeg_set_huf_table_enable(void __iomem *base, int value)
+{
+	unsigned int	reg;
+
+	reg = readl(base + EXYNOS_JPEG_CNTL_REG) & ~EXYNOS_HUF_TBL_EN;
+
+	if (value == 1)
+		writel(reg | EXYNOS_HUF_TBL_EN,
+					base + EXYNOS_JPEG_CNTL_REG);
+	else
+		writel(reg | ~EXYNOS_HUF_TBL_EN,
+					base + EXYNOS_JPEG_CNTL_REG);
+}
+
+void jpeg_set_dec_scaling(void __iomem *base,
+			  enum exynos_jpeg_scale_value x_value,
+			  enum exynos_jpeg_scale_value y_value)
+{
+	unsigned int	reg;
+
+	reg = readl(base + EXYNOS_JPEG_CNTL_REG) &
+			~(EXYNOS_HOR_SCALING_MASK |
+				EXYNOS_VER_SCALING_MASK);
+
+	writel(reg | EXYNOS_HOR_SCALING(x_value) |
+			EXYNOS_VER_SCALING(y_value),
+				base + EXYNOS_JPEG_CNTL_REG);
+}
+
+void jpeg_set_sys_int_enable(void __iomem *base, int value)
+{
+	unsigned int	reg;
+
+	reg = readl(base + EXYNOS_JPEG_CNTL_REG) & ~(EXYNOS_SYS_INT_EN);
+
+	if (value == 1)
+		writel(EXYNOS_SYS_INT_EN, base + EXYNOS_JPEG_CNTL_REG);
+	else
+		writel(~EXYNOS_SYS_INT_EN, base + EXYNOS_JPEG_CNTL_REG);
+}
+
+void jpeg_set_stream_buf_address(void __iomem *base, unsigned int address)
+{
+	writel(address, base + EXYNOS_OUT_MEM_BASE_REG);
+}
+
+void jpeg_set_stream_size(void __iomem *base,
+		unsigned int x_value, unsigned int y_value)
+{
+	writel(0x0, base + EXYNOS_JPEG_IMG_SIZE_REG); /* clear */
+	writel(EXYNOS_X_SIZE(x_value) | EXYNOS_Y_SIZE(y_value),
+			base + EXYNOS_JPEG_IMG_SIZE_REG);
+}
+
+void jpeg_set_frame_buf_address(void __iomem *base,
+				struct s5p_jpeg_addr *jpeg_addr)
+{
+	writel(jpeg_addr->y, base + EXYNOS_IMG_BA_PLANE_1_REG);
+	writel(jpeg_addr->cb, base + EXYNOS_IMG_BA_PLANE_2_REG);
+	writel(jpeg_addr->cr, base + EXYNOS_IMG_BA_PLANE_3_REG);
+}
+
+void jpeg_set_encode_tbl_select(void __iomem *base,
+		enum exynos_jpeg_img_quality_level level)
+{
+	unsigned int	reg;
+
+	reg = EXYNOS_Q_TBL_COMP1_0 | EXYNOS_Q_TBL_COMP2_1 |
+		EXYNOS_Q_TBL_COMP3_1 |
+		EXYNOS_HUFF_TBL_COMP1_AC_0_DC_1 |
+		EXYNOS_HUFF_TBL_COMP2_AC_0_DC_0 |
+		EXYNOS_HUFF_TBL_COMP3_AC_1_DC_1;
+
+	writel(reg, base + EXYNOS_TBL_SEL_REG);
+}
+
+void jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt)
+{
+	if (fmt == V4L2_PIX_FMT_GREY)
+		writel(0xd2, base + EXYNOS_HUFF_CNT_REG);
+	else
+		writel(0x1a2, base + EXYNOS_HUFF_CNT_REG);
+}
+
+unsigned int jpeg_get_stream_size(void __iomem *base)
+{
+	unsigned int size;
+
+	size = readl(base + EXYNOS_BITSTREAM_SIZE_REG);
+	return size;
+}
+
+void jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size)
+{
+	writel(size, base + EXYNOS_BITSTREAM_SIZE_REG);
+}
+
+void jpeg_get_frame_size(void __iomem *base,
+			unsigned int *width, unsigned int *height)
+{
+	*width = (readl(base + EXYNOS_DECODE_XY_SIZE_REG) &
+				EXYNOS_DECODED_SIZE_MASK);
+	*height = (readl(base + EXYNOS_DECODE_XY_SIZE_REG) >> 16) &
+				EXYNOS_DECODED_SIZE_MASK;
+}
+
+unsigned int jpeg_get_frame_fmt(void __iomem *base)
+{
+	return readl(base + EXYNOS_DECODE_IMG_FMT_REG) &
+				EXYNOS_JPEG_DECODED_IMG_FMT_MASK;
+}
+
+void jpeg_set_timer_count(void __iomem *base, unsigned int size)
+{
+	writel(size, base + EXYNOS_INT_TIMER_COUNT_REG);
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h
new file mode 100644
index 0000000..1ceb593
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * Header file of the register interface for JPEG driver on Exynos4x12.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef JPEG_HW_EXYNOS_H_
+#define JPEG_HW_EXYNOS_H_
+
+void jpeg_sw_reset(void __iomem *base);
+void jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode);
+void jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt);
+void jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt);
+void jpeg_set_enc_tbl(void __iomem *base);
+void jpeg_set_interrupt(void __iomem *base);
+unsigned int jpeg_get_int_status(void __iomem *base);
+void jpeg_set_huf_table_enable(void __iomem *base, int value);
+void jpeg_set_dec_scaling(void __iomem *base,
+		enum exynos_jpeg_scale_value x_value,
+		enum exynos_jpeg_scale_value y_value);
+void jpeg_set_sys_int_enable(void __iomem *base, int value);
+void jpeg_set_stream_buf_address(void __iomem *base, unsigned int address);
+void jpeg_set_stream_size(void __iomem *base,
+		unsigned int x_value, unsigned int y_value);
+void jpeg_set_frame_buf_address(void __iomem *base,
+				struct s5p_jpeg_addr *jpeg_addr);
+void jpeg_set_encode_tbl_select(void __iomem *base,
+		enum exynos_jpeg_img_quality_level level);
+void jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt);
+void jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size);
+unsigned int jpeg_get_stream_size(void __iomem *base);
+void jpeg_get_frame_size(void __iomem *base,
+			unsigned int *width, unsigned int *height);
+unsigned int jpeg_get_frame_fmt(void __iomem *base);
+unsigned int jpeg_get_fifo_status(void __iomem *base);
+void jpeg_set_timer_count(void __iomem *base, unsigned int size);
+
+#endif /* JPEG_HW_EXYNOS_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
index 38e5081..0bda8b0 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
@@ -2,10 +2,11 @@
  *
  * Register definition file for Samsung JPEG codec driver
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
  *
  * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +16,8 @@
 #ifndef JPEG_REGS_H_
 #define JPEG_REGS_H_
 
+/* Register and bit definitions for S5PC210 */
+
 /* JPEG mode register */
 #define S5P_JPGMOD			0x00
 #define S5P_PROC_MODE_MASK		(0x1 << 3)
@@ -166,5 +169,215 @@
 /* JPEG AC Huffman table register */
 #define S5P_JPG_HACTBLG(n)		(0x8c0 + (n) * 0x400)
 
+
+/* Register and bit definitions for Exynos 4x12 */
+
+/* JPEG Codec Control Registers */
+#define EXYNOS_JPEG_CNTL_REG		0x00
+#define EXYNOS_INT_EN_REG		0x04
+#define EXYNOS_INT_TIMER_COUNT_REG	0x08
+#define EXYNOS_INT_STATUS_REG		0x0c
+#define EXYNOS_OUT_MEM_BASE_REG		0x10
+#define EXYNOS_JPEG_IMG_SIZE_REG	0x14
+#define EXYNOS_IMG_BA_PLANE_1_REG	0x18
+#define EXYNOS_IMG_SO_PLANE_1_REG	0x1c
+#define EXYNOS_IMG_PO_PLANE_1_REG	0x20
+#define EXYNOS_IMG_BA_PLANE_2_REG	0x24
+#define EXYNOS_IMG_SO_PLANE_2_REG	0x28
+#define EXYNOS_IMG_PO_PLANE_2_REG	0x2c
+#define EXYNOS_IMG_BA_PLANE_3_REG	0x30
+#define EXYNOS_IMG_SO_PLANE_3_REG	0x34
+#define EXYNOS_IMG_PO_PLANE_3_REG	0x38
+
+#define EXYNOS_TBL_SEL_REG		0x3c
+
+#define EXYNOS_IMG_FMT_REG		0x40
+
+#define EXYNOS_BITSTREAM_SIZE_REG	0x44
+#define EXYNOS_PADDING_REG		0x48
+#define EXYNOS_HUFF_CNT_REG		0x4c
+#define EXYNOS_FIFO_STATUS_REG	0x50
+#define EXYNOS_DECODE_XY_SIZE_REG	0x54
+#define EXYNOS_DECODE_IMG_FMT_REG	0x58
+
+#define EXYNOS_QUAN_TBL_ENTRY_REG	0x100
+#define EXYNOS_HUFF_TBL_ENTRY_REG	0x200
+
+
+/****************************************************************/
+/* Bit definition part						*/
+/****************************************************************/
+
+/* JPEG CNTL Register bit */
+#define EXYNOS_ENC_DEC_MODE_MASK	(0xfffffffc << 0)
+#define EXYNOS_DEC_MODE			(1 << 0)
+#define EXYNOS_ENC_MODE			(1 << 1)
+#define EXYNOS_AUTO_RST_MARKER		(1 << 2)
+#define EXYNOS_RST_INTERVAL_SHIFT	3
+#define EXYNOS_RST_INTERVAL(x)		(((x) & 0xffff) \
+						<< EXYNOS_RST_INTERVAL_SHIFT)
+#define EXYNOS_HUF_TBL_EN		(1 << 19)
+#define EXYNOS_HOR_SCALING_SHIFT	20
+#define EXYNOS_HOR_SCALING_MASK		(3 << EXYNOS_HOR_SCALING_SHIFT)
+#define EXYNOS_HOR_SCALING(x)		(((x) & 0x3) \
+						<< EXYNOS_HOR_SCALING_SHIFT)
+#define EXYNOS_VER_SCALING_SHIFT	22
+#define EXYNOS_VER_SCALING_MASK		(3 << EXYNOS_VER_SCALING_SHIFT)
+#define EXYNOS_VER_SCALING(x)		(((x) & 0x3) \
+						<< EXYNOS_VER_SCALING_SHIFT)
+#define EXYNOS_PADDING			(1 << 27)
+#define EXYNOS_SYS_INT_EN		(1 << 28)
+#define EXYNOS_SOFT_RESET_HI		(1 << 29)
+
+/* JPEG INT Register bit */
+#define EXYNOS_INT_EN_MASK		(0x1f << 0)
+#define EXYNOS_PROT_ERR_INT_EN		(1 << 0)
+#define EXYNOS_IMG_COMPLETION_INT_EN	(1 << 1)
+#define EXYNOS_DEC_INVALID_FORMAT_EN	(1 << 2)
+#define EXYNOS_MULTI_SCAN_ERROR_EN	(1 << 3)
+#define EXYNOS_FRAME_ERR_EN		(1 << 4)
+#define EXYNOS_INT_EN_ALL		(0x1f << 0)
+
+#define EXYNOS_MOD_REG_PROC_ENC		(0 << 3)
+#define EXYNOS_MOD_REG_PROC_DEC		(1 << 3)
+
+#define EXYNOS_MOD_REG_SUBSAMPLE_444	(0 << 0)
+#define EXYNOS_MOD_REG_SUBSAMPLE_422	(1 << 0)
+#define EXYNOS_MOD_REG_SUBSAMPLE_420	(2 << 0)
+#define EXYNOS_MOD_REG_SUBSAMPLE_GRAY	(3 << 0)
+
+
+/* JPEG IMAGE SIZE Register bit */
+#define EXYNOS_X_SIZE_SHIFT		0
+#define EXYNOS_X_SIZE_MASK		(0xffff << EXYNOS_X_SIZE_SHIFT)
+#define EXYNOS_X_SIZE(x)		(((x) & 0xffff) << EXYNOS_X_SIZE_SHIFT)
+#define EXYNOS_Y_SIZE_SHIFT		16
+#define EXYNOS_Y_SIZE_MASK		(0xffff << EXYNOS_Y_SIZE_SHIFT)
+#define EXYNOS_Y_SIZE(x)		(((x) & 0xffff) << EXYNOS_Y_SIZE_SHIFT)
+
+/* JPEG IMAGE FORMAT Register bit */
+#define EXYNOS_ENC_IN_FMT_MASK		0xffff0000
+#define EXYNOS_ENC_GRAY_IMG		(0 << 0)
+#define EXYNOS_ENC_RGB_IMG		(1 << 0)
+#define EXYNOS_ENC_YUV_444_IMG		(2 << 0)
+#define EXYNOS_ENC_YUV_422_IMG		(3 << 0)
+#define EXYNOS_ENC_YUV_440_IMG		(4 << 0)
+
+#define EXYNOS_DEC_GRAY_IMG		(0 << 0)
+#define EXYNOS_DEC_RGB_IMG		(1 << 0)
+#define EXYNOS_DEC_YUV_444_IMG		(2 << 0)
+#define EXYNOS_DEC_YUV_422_IMG		(3 << 0)
+#define EXYNOS_DEC_YUV_420_IMG		(4 << 0)
+
+#define EXYNOS_GRAY_IMG_IP_SHIFT	3
+#define EXYNOS_GRAY_IMG_IP_MASK		(7 << EXYNOS_GRAY_IMG_IP_SHIFT)
+#define EXYNOS_GRAY_IMG_IP		(4 << EXYNOS_GRAY_IMG_IP_SHIFT)
+
+#define EXYNOS_RGB_IP_SHIFT		6
+#define EXYNOS_RGB_IP_MASK		(7 << EXYNOS_RGB_IP_SHIFT)
+#define EXYNOS_RGB_IP_RGB_16BIT_IMG	(4 << EXYNOS_RGB_IP_SHIFT)
+#define EXYNOS_RGB_IP_RGB_32BIT_IMG	(5 << EXYNOS_RGB_IP_SHIFT)
+
+#define EXYNOS_YUV_444_IP_SHIFT			9
+#define EXYNOS_YUV_444_IP_MASK			(7 << EXYNOS_YUV_444_IP_SHIFT)
+#define EXYNOS_YUV_444_IP_YUV_444_2P_IMG	(4 << EXYNOS_YUV_444_IP_SHIFT)
+#define EXYNOS_YUV_444_IP_YUV_444_3P_IMG	(5 << EXYNOS_YUV_444_IP_SHIFT)
+
+#define EXYNOS_YUV_422_IP_SHIFT			12
+#define EXYNOS_YUV_422_IP_MASK			(7 << EXYNOS_YUV_422_IP_SHIFT)
+#define EXYNOS_YUV_422_IP_YUV_422_1P_IMG	(4 << EXYNOS_YUV_422_IP_SHIFT)
+#define EXYNOS_YUV_422_IP_YUV_422_2P_IMG	(5 << EXYNOS_YUV_422_IP_SHIFT)
+#define EXYNOS_YUV_422_IP_YUV_422_3P_IMG	(6 << EXYNOS_YUV_422_IP_SHIFT)
+
+#define EXYNOS_YUV_420_IP_SHIFT			15
+#define EXYNOS_YUV_420_IP_MASK			(7 << EXYNOS_YUV_420_IP_SHIFT)
+#define EXYNOS_YUV_420_IP_YUV_420_2P_IMG	(4 << EXYNOS_YUV_420_IP_SHIFT)
+#define EXYNOS_YUV_420_IP_YUV_420_3P_IMG	(5 << EXYNOS_YUV_420_IP_SHIFT)
+
+#define EXYNOS_ENC_FMT_SHIFT			24
+#define EXYNOS_ENC_FMT_MASK			(3 << EXYNOS_ENC_FMT_SHIFT)
+#define EXYNOS_ENC_FMT_GRAY			(0 << EXYNOS_ENC_FMT_SHIFT)
+#define EXYNOS_ENC_FMT_YUV_444			(1 << EXYNOS_ENC_FMT_SHIFT)
+#define EXYNOS_ENC_FMT_YUV_422			(2 << EXYNOS_ENC_FMT_SHIFT)
+#define EXYNOS_ENC_FMT_YUV_420			(3 << EXYNOS_ENC_FMT_SHIFT)
+
+#define EXYNOS_JPEG_DECODED_IMG_FMT_MASK	0x03
+
+#define EXYNOS_SWAP_CHROMA_CRCB			(1 << 26)
+#define EXYNOS_SWAP_CHROMA_CBCR			(0 << 26)
+
+/* JPEG HUFF count Register bit */
+#define EXYNOS_HUFF_COUNT_MASK			0xffff
+
+/* JPEG Decoded_img_x_y_size Register bit */
+#define EXYNOS_DECODED_SIZE_MASK		0x0000ffff
+
+/* JPEG Decoded image format Register bit */
+#define EXYNOS_DECODED_IMG_FMT_MASK		0x3
+
+/* JPEG TBL SEL Register bit */
+#define EXYNOS_Q_TBL_COMP1_SHIFT	0
+#define EXYNOS_Q_TBL_COMP1_0		(0 << EXYNOS_Q_TBL_COMP1_SHIFT)
+#define EXYNOS_Q_TBL_COMP1_1		(1 << EXYNOS_Q_TBL_COMP1_SHIFT)
+#define EXYNOS_Q_TBL_COMP1_2		(2 << EXYNOS_Q_TBL_COMP1_SHIFT)
+#define EXYNOS_Q_TBL_COMP1_3		(3 << EXYNOS_Q_TBL_COMP1_SHIFT)
+
+#define EXYNOS_Q_TBL_COMP2_SHIFT	2
+#define EXYNOS_Q_TBL_COMP2_0		(0 << EXYNOS_Q_TBL_COMP2_SHIFT)
+#define EXYNOS_Q_TBL_COMP2_1		(1 << EXYNOS_Q_TBL_COMP2_SHIFT)
+#define EXYNOS_Q_TBL_COMP2_2		(2 << EXYNOS_Q_TBL_COMP2_SHIFT)
+#define EXYNOS_Q_TBL_COMP2_3		(3 << EXYNOS_Q_TBL_COMP2_SHIFT)
+
+#define EXYNOS_Q_TBL_COMP3_SHIFT	4
+#define EXYNOS_Q_TBL_COMP3_0		(0 << EXYNOS_Q_TBL_COMP3_SHIFT)
+#define EXYNOS_Q_TBL_COMP3_1		(1 << EXYNOS_Q_TBL_COMP2_SHIFT)
+#define EXYNOS_Q_TBL_COMP3_2		(2 << EXYNOS_Q_TBL_COMP2_SHIFT)
+#define EXYNOS_Q_TBL_COMP3_3		(3 << EXYNOS_Q_TBL_COMP2_SHIFT)
+
+#define EXYNOS_HUFF_TBL_COMP1_SHIFT	6
+#define EXYNOS_HUFF_TBL_COMP1_AC_0_DC_0	(0 << EXYNOS_HUFF_TBL_COMP1_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP1_AC_0_DC_1	(1 << EXYNOS_HUFF_TBL_COMP1_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP1_AC_1_DC_0	(2 << EXYNOS_HUFF_TBL_COMP1_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP1_AC_1_DC_1	(3 << EXYNOS_HUFF_TBL_COMP1_SHIFT)
+
+#define EXYNOS_HUFF_TBL_COMP2_SHIFT	8
+#define EXYNOS_HUFF_TBL_COMP2_AC_0_DC_0	(0 << EXYNOS_HUFF_TBL_COMP2_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP2_AC_0_DC_1	(1 << EXYNOS_HUFF_TBL_COMP2_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP2_AC_1_DC_0	(2 << EXYNOS_HUFF_TBL_COMP2_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP2_AC_1_DC_1	(3 << EXYNOS_HUFF_TBL_COMP2_SHIFT)
+
+#define EXYNOS_HUFF_TBL_COMP3_SHIFT	10
+#define EXYNOS_HUFF_TBL_COMP3_AC_0_DC_0	(0 << EXYNOS_HUFF_TBL_COMP3_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP3_AC_0_DC_1	(1 << EXYNOS_HUFF_TBL_COMP3_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP3_AC_1_DC_0	(2 << EXYNOS_HUFF_TBL_COMP3_SHIFT)
+#define EXYNOS_HUFF_TBL_COMP3_AC_1_DC_1	(3 << EXYNOS_HUFF_TBL_COMP3_SHIFT)
+
+/* JPEG quantizer table register */
+#define EXYNOS_QTBL_CONTENT(n)	(0x100 + (n) * 0x40)
+
+/* JPEG DC luminance (code length) Huffman table register */
+#define EXYNOS_HUFF_TBL_HDCLL	0x200
+
+/* JPEG DC luminance (values) Huffman table register */
+#define EXYNOS_HUFF_TBL_HDCLV	0x210
+
+/* JPEG DC chrominance (code length) Huffman table register */
+#define EXYNOS_HUFF_TBL_HDCCL	0x220
+
+/* JPEG DC chrominance (values) Huffman table register */
+#define EXYNOS_HUFF_TBL_HDCCV	0x230
+
+/* JPEG AC luminance (code length) Huffman table register */
+#define EXYNOS_HUFF_TBL_HACLL	0x240
+
+/* JPEG AC luminance (values) Huffman table register */
+#define EXYNOS_HUFF_TBL_HACLV	0x250
+
+/* JPEG AC chrominance (code length) Huffman table register */
+#define EXYNOS_HUFF_TBL_HACCL	0x300
+
+/* JPEG AC chrominance (values) Huffman table register */
+#define EXYNOS_HUFF_TBL_HACCV	0x310
+
 #endif /* JPEG_REGS_H_ */
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 11/16] s5p-jpeg: Retrieve "YCbCr subsampling" field from the jpeg header
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (9 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 10/16] s5p-jpeg: Add hardware API for the exynos4x12 JPEG codec Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 12/16] s5p-jpeg: Ensure correct capture format for Exynos4x12 Jacek Anaszewski
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Make s5p_jpeg_parse_hdr function capable of parsing
"YCbCr subsampling" field of a jpeg file header.
Store the parsed value in the context. The information
about source JPEG subsampling is required to make validation
of destination format possible, which must be conducted
for exynos4x12 device as the decoding process will not succeed
if the destination format is set to YUV with subsampling lower
than the one of the source JPEG image. With this knowledge
the driver can adjust the destination format appropriately.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   35 ++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 68a82cc..e09b03a 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -624,10 +624,11 @@ static void skip(struct s5p_jpeg_buffer *buf, long len)
 }
 
 static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
-			       unsigned long buffer, unsigned long size)
+			       unsigned long buffer, unsigned long size,
+			       struct s5p_jpeg_ctx *ctx)
 {
 	int c, components, notfound;
-	unsigned int height, width, word;
+	unsigned int height, width, word, subsampling = 0;
 	long length;
 	struct s5p_jpeg_buffer jpeg_buffer;
 
@@ -666,7 +667,15 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
 				break;
 			notfound = 0;
 
-			skip(&jpeg_buffer, components * 3);
+			if (components == 1) {
+				subsampling = 0x33;
+			} else {
+				skip(&jpeg_buffer, 1);
+				subsampling = get_byte(&jpeg_buffer);
+				skip(&jpeg_buffer, 1);
+			}
+
+			skip(&jpeg_buffer, components * 2);
 			break;
 
 		/* skip payload-less markers */
@@ -688,6 +697,24 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
 	result->w = width;
 	result->h = height;
 	result->size = components;
+
+	switch (subsampling) {
+	case 0x11:
+		ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
+		break;
+	case 0x21:
+		ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
+		break;
+	case 0x22:
+		ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
+		break;
+	case 0x33:
+		ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+		break;
+	default:
+		return false;
+	}
+
 	return !notfound;
 }
 
@@ -1426,7 +1453,7 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
 		ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
 		     (unsigned long)vb2_plane_vaddr(vb, 0),
 		     min((unsigned long)ctx->out_q.size,
-			 vb2_get_plane_payload(vb, 0)));
+			 vb2_get_plane_payload(vb, 0)), ctx);
 		if (!ctx->hdr_parsed) {
 			vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
 			return;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 12/16] s5p-jpeg: Ensure correct capture format for Exynos4x12
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (10 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 11/16] s5p-jpeg: Retrieve "YCbCr subsampling" field from the jpeg header Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 13/16] s5p-jpeg: Allow for wider JPEG subsampling scope for Exynos4x12 encoder Jacek Anaszewski
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Adjust capture format to the Exynos4x12 device limitations,
according to the subsampling value parsed from the source
JPEG image header. If the capture format was set to YUV with
subsampling lower than the one of the source JPEG image
the decoding process would not succeed.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   78 +++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index e09b03a..15b2dea 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -941,6 +941,7 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
 				  struct v4l2_format *f)
 {
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
 	struct s5p_jpeg_fmt *fmt;
 
 	fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
@@ -952,6 +953,83 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
 		return -EINVAL;
 	}
 
+	/*
+	 * The exynos4x12 device requires resulting YUV image
+	 * subsampling not to be lower than the input jpeg subsampling.
+	 * If this requirement is not met then downgrade the requested
+	 * output format to the one with subsampling equal to the input jpeg.
+	 */
+	if ((ctx->jpeg->variant->version != SJPEG_S5P) &&
+	    (ctx->mode == S5P_JPEG_DECODE) &&
+	    (fmt->flags & SJPEG_FMT_NON_RGB) &&
+	    (fmt->subsampling < ctx->subsampling)) {
+		switch (fmt->fourcc) {
+		case V4L2_PIX_FMT_NV24:
+			switch (ctx->subsampling) {
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+				pix->pixelformat = V4L2_PIX_FMT_NV16;
+				break;
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+				pix->pixelformat = V4L2_PIX_FMT_NV12;
+				break;
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+				pix->pixelformat = V4L2_PIX_FMT_GREY;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		case V4L2_PIX_FMT_NV42:
+			switch (ctx->subsampling) {
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+				pix->pixelformat = V4L2_PIX_FMT_NV61;
+				break;
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+				pix->pixelformat = V4L2_PIX_FMT_NV21;
+				break;
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+				pix->pixelformat = V4L2_PIX_FMT_GREY;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_NV16:
+		case V4L2_PIX_FMT_YUV420:
+			switch (ctx->subsampling) {
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+				pix->pixelformat = V4L2_PIX_FMT_NV12;
+				break;
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+				pix->pixelformat = V4L2_PIX_FMT_GREY;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		case V4L2_PIX_FMT_YVYU:
+		case V4L2_PIX_FMT_NV61:
+			switch (ctx->subsampling) {
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+				pix->pixelformat = V4L2_PIX_FMT_NV21;
+				break;
+			case  V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+				pix->pixelformat = V4L2_PIX_FMT_GREY;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		case V4L2_PIX_FMT_NV12:
+		case V4L2_PIX_FMT_NV21:
+			pix->pixelformat = V4L2_PIX_FMT_GREY;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
 	return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 13/16] s5p-jpeg: Allow for wider JPEG subsampling scope for Exynos4x12 encoder
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (11 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 12/16] s5p-jpeg: Ensure correct capture format for Exynos4x12 Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value Jacek Anaszewski
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Exynos4x12 supports wider scope of subsampling modes than
S5PC210. Adjust corresponding mask accordingly.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 15b2dea..319be0c 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1210,7 +1210,8 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
 		v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
 				  V4L2_CID_JPEG_RESTART_INTERVAL,
 				  0, 3, 0xffff, 0);
-		mask = ~0x06; /* 422, 420 */
+		if (ctx->jpeg->variant->version == SJPEG_S5P)
+			mask = ~0x06; /* 422, 420 */
 	}
 
 	ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (12 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 13/16] s5p-jpeg: Allow for wider JPEG subsampling scope for Exynos4x12 encoder Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:46   ` Hans Verkuil
  2013-11-19 14:27 ` [PATCH 15/16] s5p-jpeg: Ensure setting correct value of the chroma subsampling control Jacek Anaszewski
  2013-11-19 14:27 ` [PATCH 16/16] s5p-jpeg: Adjust g_volatile_ctrl callback to Exynos4x12 needs Jacek Anaszewski
  15 siblings, 1 reply; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

When output queue fourcc is set to any flavour of YUV,
the V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value as
well as its in-driver cached counterpart have to be
updated with the subsampling property of the format
so as to be able to provide correct information to the
user space and preclude setting an illegal subsampling
mode for Exynos4x12 encoder.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 319be0c..d4db612 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1038,6 +1038,7 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
 {
 	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 	struct s5p_jpeg_fmt *fmt;
+	struct v4l2_control ctrl_subs;
 
 	fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
 						FMT_TYPE_OUTPUT);
@@ -1048,6 +1049,10 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
 		return -EINVAL;
 	}
 
+	ctrl_subs.id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING;
+	ctrl_subs.value = fmt->subsampling;
+	v4l2_s_ctrl(priv, &ctx->ctrl_handler, &ctrl_subs);
+
 	return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 15/16] s5p-jpeg: Ensure setting correct value of the chroma subsampling control
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (13 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  2013-11-19 14:52   ` Hans Verkuil
  2013-11-19 14:27 ` [PATCH 16/16] s5p-jpeg: Adjust g_volatile_ctrl callback to Exynos4x12 needs Jacek Anaszewski
  15 siblings, 1 reply; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Exynos4x12 has limitations regarding setting chroma subsampling
of an output JPEG image. It cannot be lower than the subsampling
of the raw source image. Also in case of V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY
option the source image fourcc has to be V4L2_PIX_FMT_GREY.
This patch adds mechanism that prevents setting invalid value
of the V4L2_CID_JPEG_CHROMA_SUBSAMPLING control.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index d4db612..3605470 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1176,6 +1176,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&ctx->jpeg->slock, flags);
 
@@ -1187,12 +1188,34 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 		ctx->restart_interval = ctrl->val;
 		break;
 	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
-		ctx->subsampling = ctrl->val;
+		if (ctx->jpeg->variant->version == SJPEG_S5P) {
+			ctx->subsampling = ctrl->val;
+			break;
+		}
+		/*
+		 * The exynos4x12 device requires input raw image fourcc
+		 * to be V4L2_PIX_FMT_GREY if gray jpeg format
+		 * is to be set.
+		 */
+		if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
+		    ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
+			ret = -EINVAL;
+			goto error_free;
+		}
+		/*
+		 * The exynos4x12 device requires resulting jpeg subsampling
+		 * not to be lower than the input raw image subsampling.
+		 */
+		if (ctx->out_q.fmt->subsampling > ctrl->val)
+			ctx->subsampling = ctx->out_q.fmt->subsampling;
+		else
+			ctx->subsampling = ctrl->val;
 		break;
 	}
 
+error_free:
 	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
-	return 0;
+	return ret;
 }
 
 static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 16/16] s5p-jpeg: Adjust g_volatile_ctrl callback to Exynos4x12 needs
  2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
                   ` (14 preceding siblings ...)
  2013-11-19 14:27 ` [PATCH 15/16] s5p-jpeg: Ensure setting correct value of the chroma subsampling control Jacek Anaszewski
@ 2013-11-19 14:27 ` Jacek Anaszewski
  15 siblings, 0 replies; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-19 14:27 UTC (permalink / raw)
  To: linux-media; +Cc: kyungmin.park, s.nawrocki, sw0312.kim, Jacek Anaszewski

Whereas S5PC210 device produces decoded JPEG subsampling
values that map on V4L2_JPEG_CHROMA_SUBSAMPLNG values,
the Exynos4x12 device doesn't. This patch adds helper
function decoded_subsampling_to_v4l2, which performs
HW -> V4L2 translation.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-jpeg/jpeg-core.c |   36 ++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 3605470..90d2f69 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -358,6 +358,13 @@ static const unsigned char hactblg0[162] = {
 	0xf9, 0xfa
 };
 
+static int exynos4x12_decoded_subsampling[] = {
+	V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+};
+
 static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
 {
 	return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
@@ -368,6 +375,28 @@ static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
 	return container_of(fh, struct s5p_jpeg_ctx, fh);
 }
 
+static inline int decoded_subsampling_to_v4l2(struct s5p_jpeg_ctx *ctx)
+{
+	int subsampling;
+
+	WARN_ON(ctx->subsampling > 3);
+
+	if (ctx->jpeg->variant->version == SJPEG_S5P) {
+		if (ctx->subsampling > 2)
+			subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+		else
+			subsampling = ctx->subsampling;
+	} else {
+		if (ctx->subsampling > 2)
+			subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
+		else
+			subsampling =
+			    exynos4x12_decoded_subsampling[ctx->subsampling];
+	}
+
+	return subsampling;
+}
+
 static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
 				     const unsigned char *qtbl,
 				     unsigned long tab, int len)
@@ -1159,12 +1188,7 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 	switch (ctrl->id) {
 	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
 		spin_lock_irqsave(&jpeg->slock, flags);
-
-		WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
-		if (ctx->subsampling > 2)
-			ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
-		else
-			ctrl->val = ctx->subsampling;
+		ctrl->val = decoded_subsampling_to_v4l2(ctx);
 		spin_unlock_irqrestore(&jpeg->slock, flags);
 		break;
 	}
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value
  2013-11-19 14:27 ` [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value Jacek Anaszewski
@ 2013-11-19 14:46   ` Hans Verkuil
  2013-11-20 13:47     ` Jacek Anaszewski
  0 siblings, 1 reply; 21+ messages in thread
From: Hans Verkuil @ 2013-11-19 14:46 UTC (permalink / raw)
  To: Jacek Anaszewski; +Cc: linux-media, kyungmin.park, s.nawrocki, sw0312.kim

On 11/19/2013 03:27 PM, Jacek Anaszewski wrote:
> When output queue fourcc is set to any flavour of YUV,
> the V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value as
> well as its in-driver cached counterpart have to be
> updated with the subsampling property of the format
> so as to be able to provide correct information to the
> user space and preclude setting an illegal subsampling
> mode for Exynos4x12 encoder.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/media/platform/s5p-jpeg/jpeg-core.c |    5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
> index 319be0c..d4db612 100644
> --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
> +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
> @@ -1038,6 +1038,7 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
>  {
>  	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
>  	struct s5p_jpeg_fmt *fmt;
> +	struct v4l2_control ctrl_subs;
>  
>  	fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
>  						FMT_TYPE_OUTPUT);
> @@ -1048,6 +1049,10 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
>  		return -EINVAL;
>  	}
>  
> +	ctrl_subs.id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING;
> +	ctrl_subs.value = fmt->subsampling;
> +	v4l2_s_ctrl(priv, &ctx->ctrl_handler, &ctrl_subs);

TRY_FMT should never have side-effects, so this isn't the correct
way of implementing this.

Also, don't use v4l2_s_ctrl, instead use v4l2_ctrl_s_ctrl. The v4l2_s_ctrl
function is for core framework use only, not for use in drivers.

Regards,

	Hans

> +
>  	return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
>  }
>  
> 


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 15/16] s5p-jpeg: Ensure setting correct value of the chroma subsampling control
  2013-11-19 14:27 ` [PATCH 15/16] s5p-jpeg: Ensure setting correct value of the chroma subsampling control Jacek Anaszewski
@ 2013-11-19 14:52   ` Hans Verkuil
  0 siblings, 0 replies; 21+ messages in thread
From: Hans Verkuil @ 2013-11-19 14:52 UTC (permalink / raw)
  To: Jacek Anaszewski; +Cc: linux-media, kyungmin.park, s.nawrocki, sw0312.kim

On 11/19/2013 03:27 PM, Jacek Anaszewski wrote:
> Exynos4x12 has limitations regarding setting chroma subsampling
> of an output JPEG image. It cannot be lower than the subsampling
> of the raw source image. Also in case of V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY
> option the source image fourcc has to be V4L2_PIX_FMT_GREY.
> This patch adds mechanism that prevents setting invalid value
> of the V4L2_CID_JPEG_CHROMA_SUBSAMPLING control.
> 
> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/media/platform/s5p-jpeg/jpeg-core.c |   27 +++++++++++++++++++++++++--
>  1 file changed, 25 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
> index d4db612..3605470 100644
> --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
> +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
> @@ -1176,6 +1176,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
>  {
>  	struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
>  	unsigned long flags;
> +	int ret = 0;
>  
>  	spin_lock_irqsave(&ctx->jpeg->slock, flags);
>  
> @@ -1187,12 +1188,34 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
>  		ctx->restart_interval = ctrl->val;
>  		break;
>  	case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
> -		ctx->subsampling = ctrl->val;
> +		if (ctx->jpeg->variant->version == SJPEG_S5P) {
> +			ctx->subsampling = ctrl->val;
> +			break;
> +		}
> +		/*
> +		 * The exynos4x12 device requires input raw image fourcc
> +		 * to be V4L2_PIX_FMT_GREY if gray jpeg format
> +		 * is to be set.
> +		 */
> +		if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
> +		    ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
> +			ret = -EINVAL;
> +			goto error_free;
> +		}
> +		/*
> +		 * The exynos4x12 device requires resulting jpeg subsampling
> +		 * not to be lower than the input raw image subsampling.
> +		 */
> +		if (ctx->out_q.fmt->subsampling > ctrl->val)
> +			ctx->subsampling = ctx->out_q.fmt->subsampling;
> +		else
> +			ctx->subsampling = ctrl->val;

I would do this in a try_ctrl op instead: that way VIDIOC_TRY_EXT_CTRLS will
also be able to understand these restrictions.

Before the s_ctrl op is called the control framework will always call the
try_ctrl op as well if it is present.

Regards,

	Hans

>  		break;
>  	}
>  
> +error_free:
>  	spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
> -	return 0;
> +	return ret;
>  }
>  
>  static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
> 


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value
  2013-11-19 14:46   ` Hans Verkuil
@ 2013-11-20 13:47     ` Jacek Anaszewski
  2013-11-20 14:13       ` Hans Verkuil
  0 siblings, 1 reply; 21+ messages in thread
From: Jacek Anaszewski @ 2013-11-20 13:47 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, kyungmin.park, s.nawrocki, sw0312.kim

On 11/19/2013 03:46 PM, Hans Verkuil wrote:
> On 11/19/2013 03:27 PM, Jacek Anaszewski wrote:
>> When output queue fourcc is set to any flavour of YUV,
>> the V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value as
>> well as its in-driver cached counterpart have to be
>> updated with the subsampling property of the format
>> so as to be able to provide correct information to the
>> user space and preclude setting an illegal subsampling
>> mode for Exynos4x12 encoder.
>>
>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>>   drivers/media/platform/s5p-jpeg/jpeg-core.c |    5 +++++
>>   1 file changed, 5 insertions(+)
>>
>> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
>> index 319be0c..d4db612 100644
>> --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
>> +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
>> @@ -1038,6 +1038,7 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
>>   {
>>   	struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
>>   	struct s5p_jpeg_fmt *fmt;
>> +	struct v4l2_control ctrl_subs;
>>
>>   	fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
>>   						FMT_TYPE_OUTPUT);
>> @@ -1048,6 +1049,10 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
>>   		return -EINVAL;
>>   	}
>>
>> +	ctrl_subs.id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING;
>> +	ctrl_subs.value = fmt->subsampling;
>> +	v4l2_s_ctrl(priv, &ctx->ctrl_handler, &ctrl_subs);
>
> TRY_FMT should never have side-effects, so this isn't the correct
> way of implementing this.

I am aware of it, but I couldn't have found more suitable place
for implementing this. Below is the rationale standing behind
such an implementation:

   - Exynos4x12 device doesn't generate an eoc interrupt if the
     subsampling property of an output queue format is lower than the
     target jpeg subsampling (e.g. V4L2_PIX_FMT_YUYV [4:2:2 subsampling]
     and JPEG 4:4:4)
   - It should be possible to inform the user space application that the
     subsampling it wants to set is not supported with the current output
     queue fourcc.
   - It is possible that after calling S_EXT_CTRLS the application
     will call S_FMT on output queue with different fourcc which will
     change the allowed scope of JPEG subsampling settings. Let's assume
     the following flow of ioctls:
       - S_FMT V4L2_PIX_FMT_YUYV (4:2:2)
       - S_EXT_CTRLS V4L2_JPEG_CHROMA_SUBSAMPLING_422
       - S_FMT V4L2_PIX_FMT_YUV420
     Now the JPEG subsampling set is illegal as 4:2:2 is lower than 4:2:0
     (lower refers here to the lower number of luma samples assigned
     to the single chroma sample). It is evident now that the change
     of output queue fourcc entails change of the allowed scope of JPEG
     subsampling settings. The way I implemented it reflects this
     constraint precisely. We could go for adjusting the JPEG subsampling
     e.g. in the device_run callback but the user space application
     wouldn't know about it unless it called G_EXT_CTRLS ioctl after end
     of conversion.

In view of the above it is clear that calling S_FMT in this case HAS
side effect no matter whether we take it into account in the driver
implementation or not. Nevertheless maybe there is some more elegant
way of handling this problem I am not aware of. I am open to any
interesting ideas.

Regards,
Jacek Anaszewski


> Also, don't use v4l2_s_ctrl, instead use v4l2_ctrl_s_ctrl. The v4l2_s_ctrl
> function is for core framework use only, not for use in drivers.
>
> Regards,
>
> 	Hans
>
>> +
>>   	return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
>>   }
>>
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value
  2013-11-20 13:47     ` Jacek Anaszewski
@ 2013-11-20 14:13       ` Hans Verkuil
  0 siblings, 0 replies; 21+ messages in thread
From: Hans Verkuil @ 2013-11-20 14:13 UTC (permalink / raw)
  To: Jacek Anaszewski; +Cc: linux-media, kyungmin.park, s.nawrocki, sw0312.kim

On 11/20/13 14:47, Jacek Anaszewski wrote:
> On 11/19/2013 03:46 PM, Hans Verkuil wrote:
>> On 11/19/2013 03:27 PM, Jacek Anaszewski wrote:
>>> When output queue fourcc is set to any flavour of YUV,
>>> the V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value as
>>> well as its in-driver cached counterpart have to be
>>> updated with the subsampling property of the format
>>> so as to be able to provide correct information to the
>>> user space and preclude setting an illegal subsampling
>>> mode for Exynos4x12 encoder.
>>>
>>> Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
>>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>>> ---
>>>   drivers/media/platform/s5p-jpeg/jpeg-core.c |    5 +++++
>>>   1 file changed, 5 insertions(+)
>>>
>>> diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
>>> index 319be0c..d4db612 100644
>>> --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
>>> +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
>>> @@ -1038,6 +1038,7 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
>>>   {
>>>       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
>>>       struct s5p_jpeg_fmt *fmt;
>>> +    struct v4l2_control ctrl_subs;
>>>
>>>       fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
>>>                           FMT_TYPE_OUTPUT);
>>> @@ -1048,6 +1049,10 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
>>>           return -EINVAL;
>>>       }
>>>
>>> +    ctrl_subs.id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING;
>>> +    ctrl_subs.value = fmt->subsampling;
>>> +    v4l2_s_ctrl(priv, &ctx->ctrl_handler, &ctrl_subs);
>>
>> TRY_FMT should never have side-effects, so this isn't the correct
>> way of implementing this.
> 
> I am aware of it, but I couldn't have found more suitable place
> for implementing this. Below is the rationale standing behind
> such an implementation:
> 
>   - Exynos4x12 device doesn't generate an eoc interrupt if the
>     subsampling property of an output queue format is lower than the
>     target jpeg subsampling (e.g. V4L2_PIX_FMT_YUYV [4:2:2 subsampling]
>     and JPEG 4:4:4)
>   - It should be possible to inform the user space application that the
>     subsampling it wants to set is not supported with the current output
>     queue fourcc.
>   - It is possible that after calling S_EXT_CTRLS the application
>     will call S_FMT on output queue with different fourcc which will
>     change the allowed scope of JPEG subsampling settings. Let's assume
>     the following flow of ioctls:
>       - S_FMT V4L2_PIX_FMT_YUYV (4:2:2)
>       - S_EXT_CTRLS V4L2_JPEG_CHROMA_SUBSAMPLING_422
>       - S_FMT V4L2_PIX_FMT_YUV420
>     Now the JPEG subsampling set is illegal as 4:2:2 is lower than 4:2:0
>     (lower refers here to the lower number of luma samples assigned
>     to the single chroma sample). It is evident now that the change
>     of output queue fourcc entails change of the allowed scope of JPEG
>     subsampling settings. The way I implemented it reflects this
>     constraint precisely. We could go for adjusting the JPEG subsampling
>     e.g. in the device_run callback but the user space application
>     wouldn't know about it unless it called G_EXT_CTRLS ioctl after end
>     of conversion.
> 
> In view of the above it is clear that calling S_FMT in this case HAS
> side effect no matter whether we take it into account in the driver
> implementation or not. Nevertheless maybe there is some more elegant
> way of handling this problem I am not aware of. I am open to any
> interesting ideas.

I think you misunderstood me. It is OK that S_FMT changes the control,
but TRY_FMT shouldn't. So the code that changes the subsampling control
should be moved to s5p_jpeg_s_fmt_vid_out.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2013-11-20 14:14 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-19 14:26 [PATCH 00/16] Add support for Exynox4x12 to the s5p-jpeg driver Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 01/16] s5p-jpeg: Reorder quantization tables Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 02/16] s5p-jpeg: Fix output YUV 4:2:0 fourcc for decoder Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 03/16] s5p-jpeg: Fix erroneous condition while validating bytesperline value Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 04/16] s5p-jpeg: Remove superfluous call to the jpeg_bound_align_image function Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 05/16] s5p-jpeg: Rename functions specific to the S5PC210 SoC accordingly Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 06/16] s5p-jpeg: Fix clock resource management Jacek Anaszewski
2013-11-19 14:26 ` [PATCH 07/16] s5p-jpeg: Fix lack of spin_lock protection Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 08/16] s5p-jpeg: Synchronize cached controls with V4L2 core Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 09/16] s5p-jpeg: Split jpeg-hw.h to jpeg-hw-s5p.c and jpeg-hw-s5p.c Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 10/16] s5p-jpeg: Add hardware API for the exynos4x12 JPEG codec Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 11/16] s5p-jpeg: Retrieve "YCbCr subsampling" field from the jpeg header Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 12/16] s5p-jpeg: Ensure correct capture format for Exynos4x12 Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 13/16] s5p-jpeg: Allow for wider JPEG subsampling scope for Exynos4x12 encoder Jacek Anaszewski
2013-11-19 14:27 ` [PATCH 14/16] s5p-jpeg: Synchronize V4L2_CID_JPEG_CHROMA_SUBSAMPLING control value Jacek Anaszewski
2013-11-19 14:46   ` Hans Verkuil
2013-11-20 13:47     ` Jacek Anaszewski
2013-11-20 14:13       ` Hans Verkuil
2013-11-19 14:27 ` [PATCH 15/16] s5p-jpeg: Ensure setting correct value of the chroma subsampling control Jacek Anaszewski
2013-11-19 14:52   ` Hans Verkuil
2013-11-19 14:27 ` [PATCH 16/16] s5p-jpeg: Adjust g_volatile_ctrl callback to Exynos4x12 needs Jacek Anaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).