aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-jpeg
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2012-02-17 09:39:36 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-03-01 15:10:30 -0500
commit15f4bc3b1f42ca73ad073d7390aa34fa358f02a3 (patch)
tree1c8ce26e608bd8a90765d05f1f7fe463d6a4ca0f /drivers/media/video/s5p-jpeg
parent275de24dc0076fac25e86e586c9577b8caee28ce (diff)
[media] s5p-jpeg: Add JPEG controls support
This patch replaces VIDIOC_S/G_JPEGCOMP ioctl handlers with V4L2_CID_JPEG_QUALITY control. Additionally it enables JPEG subsampling and the restart interval configuration through V4L2_CID_JPEG_SUBSAMPLING and V4L2_CID_JPEG_RESTART_INTERVAL controls. For the decoder video node only V4L2_CID_JPEG_SUBSAMPLING is available as a read-only control. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-jpeg')
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.c117
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.h9
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-hw.h18
3 files changed, 111 insertions, 33 deletions
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
index c368c4fc9243..c104aeb2455d 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -203,6 +203,11 @@ static const unsigned char hactblg0[162] = {
203 0xf9, 0xfa 203 0xf9, 0xfa
204}; 204};
205 205
206static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
207{
208 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
209}
210
206static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) 211static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
207{ 212{
208 return container_of(fh, struct s5p_jpeg_ctx, fh); 213 return container_of(fh, struct s5p_jpeg_ctx, fh);
@@ -274,6 +279,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
274 struct vb2_queue *dst_vq); 279 struct vb2_queue *dst_vq);
275static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, 280static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
276 __u32 pixelformat); 281 __u32 pixelformat);
282static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
277 283
278static int s5p_jpeg_open(struct file *file) 284static int s5p_jpeg_open(struct file *file)
279{ 285{
@@ -288,6 +294,8 @@ static int s5p_jpeg_open(struct file *file)
288 return -ENOMEM; 294 return -ENOMEM;
289 295
290 v4l2_fh_init(&ctx->fh, vfd); 296 v4l2_fh_init(&ctx->fh, vfd);
297 /* Use separate control handler per file handle */
298 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
291 file->private_data = &ctx->fh; 299 file->private_data = &ctx->fh;
292 v4l2_fh_add(&ctx->fh); 300 v4l2_fh_add(&ctx->fh);
293 301
@@ -300,6 +308,10 @@ static int s5p_jpeg_open(struct file *file)
300 out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); 308 out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
301 } 309 }
302 310
311 ret = s5p_jpeg_controls_create(ctx);
312 if (ret < 0)
313 goto error;
314
303 ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); 315 ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
304 if (IS_ERR(ctx->m2m_ctx)) { 316 if (IS_ERR(ctx->m2m_ctx)) {
305 ret = PTR_ERR(ctx->m2m_ctx); 317 ret = PTR_ERR(ctx->m2m_ctx);
@@ -322,6 +334,7 @@ static int s5p_jpeg_release(struct file *file)
322 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); 334 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
323 335
324 v4l2_m2m_ctx_release(ctx->m2m_ctx); 336 v4l2_m2m_ctx_release(ctx->m2m_ctx);
337 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
325 v4l2_fh_del(&ctx->fh); 338 v4l2_fh_del(&ctx->fh);
326 v4l2_fh_exit(&ctx->fh); 339 v4l2_fh_exit(&ctx->fh);
327 kfree(ctx); 340 kfree(ctx);
@@ -833,33 +846,89 @@ int s5p_jpeg_g_selection(struct file *file, void *priv,
833 return 0; 846 return 0;
834} 847}
835 848
836static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, 849/*
837 struct v4l2_jpegcompression *compr) 850 * V4L2 controls
851 */
852
853static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
838{ 854{
839 struct s5p_jpeg_ctx *ctx = priv; 855 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
856 struct s5p_jpeg *jpeg = ctx->jpeg;
857 unsigned long flags;
840 858
841 if (ctx->mode == S5P_JPEG_DECODE) 859 switch (ctrl->id) {
842 return -ENOTTY; 860 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
861 spin_lock_irqsave(&jpeg->slock, flags);
843 862
844 memset(compr, 0, sizeof(*compr)); 863 WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
845 compr->quality = ctx->compr_quality; 864 if (ctx->subsampling > 2)
865 ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
866 else
867 ctrl->val = ctx->subsampling;
868 spin_unlock_irqrestore(&jpeg->slock, flags);
869 break;
870 }
846 871
847 return 0; 872 return 0;
848} 873}
849 874
850static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, 875static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
851 struct v4l2_jpegcompression *compr)
852{ 876{
853 struct s5p_jpeg_ctx *ctx = priv; 877 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
878 unsigned long flags;
854 879
855 if (ctx->mode == S5P_JPEG_DECODE) 880 spin_lock_irqsave(&ctx->jpeg->slock, flags);
856 return -ENOTTY;
857 881
858 compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, 882 switch (ctrl->id) {
859 S5P_JPEG_COMPR_QUAL_WORST); 883 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
884 ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
885 break;
886 case V4L2_CID_JPEG_RESTART_INTERVAL:
887 ctx->restart_interval = ctrl->val;
888 break;
889 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
890 ctx->subsampling = ctrl->val;
891 break;
892 }
893
894 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
895 return 0;
896}
897
898static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
899 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
900 .s_ctrl = s5p_jpeg_s_ctrl,
901};
902
903static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
904{
905 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
906 struct v4l2_ctrl *ctrl;
907
908 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
860 909
861 ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; 910 if (ctx->mode == S5P_JPEG_ENCODE) {
911 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
912 V4L2_CID_JPEG_COMPRESSION_QUALITY,
913 0, 3, 1, 3);
914
915 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
916 V4L2_CID_JPEG_RESTART_INTERVAL,
917 0, 3, 0xffff, 0);
918 mask = ~0x06; /* 422, 420 */
919 }
920
921 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
922 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
923 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
924 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
862 925
926 if (ctx->ctrl_handler.error)
927 return ctx->ctrl_handler.error;
928
929 if (ctx->mode == S5P_JPEG_DECODE)
930 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
931 V4L2_CTRL_FLAG_READ_ONLY;
863 return 0; 932 return 0;
864} 933}
865 934
@@ -888,9 +957,6 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
888 .vidioc_streamoff = s5p_jpeg_streamoff, 957 .vidioc_streamoff = s5p_jpeg_streamoff,
889 958
890 .vidioc_g_selection = s5p_jpeg_g_selection, 959 .vidioc_g_selection = s5p_jpeg_g_selection,
891
892 .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp,
893 .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp,
894}; 960};
895 961
896/* 962/*
@@ -919,13 +985,8 @@ static void s5p_jpeg_device_run(void *priv)
919 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); 985 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
920 else 986 else
921 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); 987 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
922 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) 988 jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
923 jpeg_subsampling_mode(jpeg->regs, 989 jpeg_dri(jpeg->regs, ctx->restart_interval);
924 S5P_JPEG_SUBSAMPLING_422);
925 else
926 jpeg_subsampling_mode(jpeg->regs,
927 S5P_JPEG_SUBSAMPLING_420);
928 jpeg_dri(jpeg->regs, 0);
929 jpeg_x(jpeg->regs, ctx->out_q.w); 990 jpeg_x(jpeg->regs, ctx->out_q.w);
930 jpeg_y(jpeg->regs, ctx->out_q.h); 991 jpeg_y(jpeg->regs, ctx->out_q.h);
931 jpeg_imgadr(jpeg->regs, src_addr); 992 jpeg_imgadr(jpeg->regs, src_addr);
@@ -972,6 +1033,7 @@ static void s5p_jpeg_device_run(void *priv)
972 jpeg_jpgadr(jpeg->regs, src_addr); 1033 jpeg_jpgadr(jpeg->regs, src_addr);
973 jpeg_imgadr(jpeg->regs, dst_addr); 1034 jpeg_imgadr(jpeg->regs, dst_addr);
974 } 1035 }
1036
975 jpeg_start(jpeg->regs); 1037 jpeg_start(jpeg->regs);
976} 1038}
977 1039
@@ -1173,6 +1235,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1173 bool timer_elapsed = false; 1235 bool timer_elapsed = false;
1174 bool op_completed = false; 1236 bool op_completed = false;
1175 1237
1238 spin_lock(&jpeg->slock);
1239
1176 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); 1240 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1177 1241
1178 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); 1242 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
@@ -1203,6 +1267,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1203 v4l2_m2m_buf_done(dst_buf, state); 1267 v4l2_m2m_buf_done(dst_buf, state);
1204 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); 1268 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
1205 1269
1270 curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
1271 spin_unlock(&jpeg->slock);
1206 jpeg_clear_int(jpeg->regs); 1272 jpeg_clear_int(jpeg->regs);
1207 1273
1208 return IRQ_HANDLED; 1274 return IRQ_HANDLED;
@@ -1226,6 +1292,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
1226 return -ENOMEM; 1292 return -ENOMEM;
1227 1293
1228 mutex_init(&jpeg->lock); 1294 mutex_init(&jpeg->lock);
1295 spin_lock_init(&jpeg->slock);
1229 jpeg->dev = &pdev->dev; 1296 jpeg->dev = &pdev->dev;
1230 1297
1231 /* memory-mapped registers */ 1298 /* memory-mapped registers */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
index 4dd705fb99d5..38d7367f7a6d 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -15,6 +15,7 @@
15 15
16#include <media/v4l2-device.h> 16#include <media/v4l2-device.h>
17#include <media/v4l2-fh.h> 17#include <media/v4l2-fh.h>
18#include <media/v4l2-ctrls.h>
18 19
19#define S5P_JPEG_M2M_NAME "s5p-jpeg" 20#define S5P_JPEG_M2M_NAME "s5p-jpeg"
20 21
@@ -48,6 +49,7 @@
48/** 49/**
49 * struct s5p_jpeg - JPEG IP abstraction 50 * struct s5p_jpeg - JPEG IP abstraction
50 * @lock: the mutex protecting this structure 51 * @lock: the mutex protecting this structure
52 * @slock: spinlock protecting the device contexts
51 * @v4l2_dev: v4l2 device for mem2mem mode 53 * @v4l2_dev: v4l2 device for mem2mem mode
52 * @vfd_encoder: video device node for encoder mem2mem mode 54 * @vfd_encoder: video device node for encoder mem2mem mode
53 * @vfd_decoder: video device node for decoder mem2mem mode 55 * @vfd_decoder: video device node for decoder mem2mem mode
@@ -61,6 +63,7 @@
61 */ 63 */
62struct s5p_jpeg { 64struct s5p_jpeg {
63 struct mutex lock; 65 struct mutex lock;
66 struct spinlock slock;
64 67
65 struct v4l2_device v4l2_dev; 68 struct v4l2_device v4l2_dev;
66 struct video_device *vfd_encoder; 69 struct video_device *vfd_encoder;
@@ -118,16 +121,20 @@ struct s5p_jpeg_q_data {
118 * @out_q: source (output) queue information 121 * @out_q: source (output) queue information
119 * @cap_fmt: destination (capture) queue queue information 122 * @cap_fmt: destination (capture) queue queue information
120 * @hdr_parsed: set if header has been parsed during decompression 123 * @hdr_parsed: set if header has been parsed during decompression
124 * @ctrl_handler: controls handler
121 */ 125 */
122struct s5p_jpeg_ctx { 126struct s5p_jpeg_ctx {
123 struct s5p_jpeg *jpeg; 127 struct s5p_jpeg *jpeg;
124 unsigned int mode; 128 unsigned int mode;
125 unsigned int compr_quality; 129 unsigned short compr_quality;
130 unsigned short restart_interval;
131 unsigned short subsampling;
126 struct v4l2_m2m_ctx *m2m_ctx; 132 struct v4l2_m2m_ctx *m2m_ctx;
127 struct s5p_jpeg_q_data out_q; 133 struct s5p_jpeg_q_data out_q;
128 struct s5p_jpeg_q_data cap_q; 134 struct s5p_jpeg_q_data cap_q;
129 struct v4l2_fh fh; 135 struct v4l2_fh fh;
130 bool hdr_parsed; 136 bool hdr_parsed;
137 struct v4l2_ctrl_handler ctrl_handler;
131}; 138};
132 139
133/** 140/**
diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h
index e10c744e9f23..f12f0fdbde7c 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-hw.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h
@@ -13,6 +13,7 @@
13#define JPEG_HW_H_ 13#define JPEG_HW_H_
14 14
15#include <linux/io.h> 15#include <linux/io.h>
16#include <linux/videodev2.h>
16 17
17#include "jpeg-hw.h" 18#include "jpeg-hw.h"
18#include "jpeg-regs.h" 19#include "jpeg-regs.h"
@@ -25,8 +26,6 @@
25#define S5P_JPEG_DECODE 1 26#define S5P_JPEG_DECODE 1
26#define S5P_JPEG_RAW_IN_565 0 27#define S5P_JPEG_RAW_IN_565 0
27#define S5P_JPEG_RAW_IN_422 1 28#define S5P_JPEG_RAW_IN_422 1
28#define S5P_JPEG_SUBSAMPLING_422 0
29#define S5P_JPEG_SUBSAMPLING_420 1
30#define S5P_JPEG_RAW_OUT_422 0 29#define S5P_JPEG_RAW_OUT_422 0
31#define S5P_JPEG_RAW_OUT_420 1 30#define S5P_JPEG_RAW_OUT_420 1
32 31
@@ -91,21 +90,26 @@ static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
91 writel(reg, regs + S5P_JPGMOD); 90 writel(reg, regs + S5P_JPGMOD);
92} 91}
93 92
94static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) 93static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
95{ 94{
96 unsigned long reg, m; 95 unsigned long reg, m;
97 96
98 m = S5P_SUBSAMPLING_MODE_422; 97 if (mode == V4L2_JPEG_CHROMA_SUBSAMPLING_420)
99 if (mode == S5P_JPEG_SUBSAMPLING_422)
100 m = S5P_SUBSAMPLING_MODE_422;
101 else if (mode == S5P_JPEG_SUBSAMPLING_420)
102 m = S5P_SUBSAMPLING_MODE_420; 98 m = S5P_SUBSAMPLING_MODE_420;
99 else
100 m = S5P_SUBSAMPLING_MODE_422;
101
103 reg = readl(regs + S5P_JPGMOD); 102 reg = readl(regs + S5P_JPGMOD);
104 reg &= ~S5P_SUBSAMPLING_MODE_MASK; 103 reg &= ~S5P_SUBSAMPLING_MODE_MASK;
105 reg |= m; 104 reg |= m;
106 writel(reg, regs + S5P_JPGMOD); 105 writel(reg, regs + S5P_JPGMOD);
107} 106}
108 107
108static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
109{
110 return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
111}
112
109static inline void jpeg_dri(void __iomem *regs, unsigned int dri) 113static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
110{ 114{
111 unsigned long reg; 115 unsigned long reg;