aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-jpeg
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/s5p-jpeg')
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.c199
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.h11
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-hw.h18
3 files changed, 161 insertions, 67 deletions
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
index 1105a8749c8b..5a49c307f9c1 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -32,10 +32,9 @@
32 32
33static struct s5p_jpeg_fmt formats_enc[] = { 33static struct s5p_jpeg_fmt formats_enc[] = {
34 { 34 {
35 .name = "YUV 4:2:0 planar, YCbCr", 35 .name = "JPEG JFIF",
36 .fourcc = V4L2_PIX_FMT_YUV420, 36 .fourcc = V4L2_PIX_FMT_JPEG,
37 .depth = 12, 37 .colplanes = 1,
38 .colplanes = 3,
39 .types = MEM2MEM_CAPTURE, 38 .types = MEM2MEM_CAPTURE,
40 }, 39 },
41 { 40 {
@@ -43,7 +42,7 @@ static struct s5p_jpeg_fmt formats_enc[] = {
43 .fourcc = V4L2_PIX_FMT_YUYV, 42 .fourcc = V4L2_PIX_FMT_YUYV,
44 .depth = 16, 43 .depth = 16,
45 .colplanes = 1, 44 .colplanes = 1,
46 .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, 45 .types = MEM2MEM_OUTPUT,
47 }, 46 },
48 { 47 {
49 .name = "RGB565", 48 .name = "RGB565",
@@ -203,6 +202,16 @@ static const unsigned char hactblg0[162] = {
203 0xf9, 0xfa 202 0xf9, 0xfa
204}; 203};
205 204
205static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
206{
207 return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
208}
209
210static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
211{
212 return container_of(fh, struct s5p_jpeg_ctx, fh);
213}
214
206static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, 215static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
207 unsigned long tab, int len) 216 unsigned long tab, int len)
208{ 217{
@@ -269,6 +278,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
269 struct vb2_queue *dst_vq); 278 struct vb2_queue *dst_vq);
270static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, 279static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
271 __u32 pixelformat); 280 __u32 pixelformat);
281static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
272 282
273static int s5p_jpeg_open(struct file *file) 283static int s5p_jpeg_open(struct file *file)
274{ 284{
@@ -276,12 +286,18 @@ static int s5p_jpeg_open(struct file *file)
276 struct video_device *vfd = video_devdata(file); 286 struct video_device *vfd = video_devdata(file);
277 struct s5p_jpeg_ctx *ctx; 287 struct s5p_jpeg_ctx *ctx;
278 struct s5p_jpeg_fmt *out_fmt; 288 struct s5p_jpeg_fmt *out_fmt;
289 int ret = 0;
279 290
280 ctx = kzalloc(sizeof *ctx, GFP_KERNEL); 291 ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
281 if (!ctx) 292 if (!ctx)
282 return -ENOMEM; 293 return -ENOMEM;
283 294
284 file->private_data = ctx; 295 v4l2_fh_init(&ctx->fh, vfd);
296 /* Use separate control handler per file handle */
297 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
298 file->private_data = &ctx->fh;
299 v4l2_fh_add(&ctx->fh);
300
285 ctx->jpeg = jpeg; 301 ctx->jpeg = jpeg;
286 if (vfd == jpeg->vfd_encoder) { 302 if (vfd == jpeg->vfd_encoder) {
287 ctx->mode = S5P_JPEG_ENCODE; 303 ctx->mode = S5P_JPEG_ENCODE;
@@ -291,24 +307,35 @@ static int s5p_jpeg_open(struct file *file)
291 out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); 307 out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
292 } 308 }
293 309
310 ret = s5p_jpeg_controls_create(ctx);
311 if (ret < 0)
312 goto error;
313
294 ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); 314 ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
295 if (IS_ERR(ctx->m2m_ctx)) { 315 if (IS_ERR(ctx->m2m_ctx)) {
296 int err = PTR_ERR(ctx->m2m_ctx); 316 ret = PTR_ERR(ctx->m2m_ctx);
297 kfree(ctx); 317 goto error;
298 return err;
299 } 318 }
300 319
301 ctx->out_q.fmt = out_fmt; 320 ctx->out_q.fmt = out_fmt;
302 ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); 321 ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
303
304 return 0; 322 return 0;
323
324error:
325 v4l2_fh_del(&ctx->fh);
326 v4l2_fh_exit(&ctx->fh);
327 kfree(ctx);
328 return ret;
305} 329}
306 330
307static int s5p_jpeg_release(struct file *file) 331static int s5p_jpeg_release(struct file *file)
308{ 332{
309 struct s5p_jpeg_ctx *ctx = file->private_data; 333 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
310 334
311 v4l2_m2m_ctx_release(ctx->m2m_ctx); 335 v4l2_m2m_ctx_release(ctx->m2m_ctx);
336 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
337 v4l2_fh_del(&ctx->fh);
338 v4l2_fh_exit(&ctx->fh);
312 kfree(ctx); 339 kfree(ctx);
313 340
314 return 0; 341 return 0;
@@ -317,14 +344,14 @@ static int s5p_jpeg_release(struct file *file)
317static unsigned int s5p_jpeg_poll(struct file *file, 344static unsigned int s5p_jpeg_poll(struct file *file,
318 struct poll_table_struct *wait) 345 struct poll_table_struct *wait)
319{ 346{
320 struct s5p_jpeg_ctx *ctx = file->private_data; 347 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
321 348
322 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); 349 return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
323} 350}
324 351
325static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) 352static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
326{ 353{
327 struct s5p_jpeg_ctx *ctx = file->private_data; 354 struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
328 355
329 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); 356 return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
330} 357}
@@ -448,7 +475,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
448static int s5p_jpeg_querycap(struct file *file, void *priv, 475static int s5p_jpeg_querycap(struct file *file, void *priv,
449 struct v4l2_capability *cap) 476 struct v4l2_capability *cap)
450{ 477{
451 struct s5p_jpeg_ctx *ctx = priv; 478 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
452 479
453 if (ctx->mode == S5P_JPEG_ENCODE) { 480 if (ctx->mode == S5P_JPEG_ENCODE) {
454 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", 481 strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder",
@@ -497,9 +524,7 @@ static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
497static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, 524static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
498 struct v4l2_fmtdesc *f) 525 struct v4l2_fmtdesc *f)
499{ 526{
500 struct s5p_jpeg_ctx *ctx; 527 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
501
502 ctx = priv;
503 528
504 if (ctx->mode == S5P_JPEG_ENCODE) 529 if (ctx->mode == S5P_JPEG_ENCODE)
505 return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, 530 return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
@@ -511,9 +536,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
511static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, 536static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
512 struct v4l2_fmtdesc *f) 537 struct v4l2_fmtdesc *f)
513{ 538{
514 struct s5p_jpeg_ctx *ctx; 539 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
515
516 ctx = priv;
517 540
518 if (ctx->mode == S5P_JPEG_ENCODE) 541 if (ctx->mode == S5P_JPEG_ENCODE)
519 return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, 542 return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
@@ -538,7 +561,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
538 struct vb2_queue *vq; 561 struct vb2_queue *vq;
539 struct s5p_jpeg_q_data *q_data = NULL; 562 struct s5p_jpeg_q_data *q_data = NULL;
540 struct v4l2_pix_format *pix = &f->fmt.pix; 563 struct v4l2_pix_format *pix = &f->fmt.pix;
541 struct s5p_jpeg_ctx *ct = priv; 564 struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
542 565
543 vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); 566 vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
544 if (!vq) 567 if (!vq)
@@ -659,8 +682,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
659static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, 682static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
660 struct v4l2_format *f) 683 struct v4l2_format *f)
661{ 684{
685 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
662 struct s5p_jpeg_fmt *fmt; 686 struct s5p_jpeg_fmt *fmt;
663 struct s5p_jpeg_ctx *ctx = priv;
664 687
665 fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); 688 fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
666 if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { 689 if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
@@ -676,8 +699,8 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
676static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, 699static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
677 struct v4l2_format *f) 700 struct v4l2_format *f)
678{ 701{
702 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
679 struct s5p_jpeg_fmt *fmt; 703 struct s5p_jpeg_fmt *fmt;
680 struct s5p_jpeg_ctx *ctx = priv;
681 704
682 fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); 705 fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
683 if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { 706 if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
@@ -728,7 +751,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
728 if (ret) 751 if (ret)
729 return ret; 752 return ret;
730 753
731 return s5p_jpeg_s_fmt(priv, f); 754 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
732} 755}
733 756
734static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, 757static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
@@ -740,13 +763,13 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
740 if (ret) 763 if (ret)
741 return ret; 764 return ret;
742 765
743 return s5p_jpeg_s_fmt(priv, f); 766 return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
744} 767}
745 768
746static int s5p_jpeg_reqbufs(struct file *file, void *priv, 769static int s5p_jpeg_reqbufs(struct file *file, void *priv,
747 struct v4l2_requestbuffers *reqbufs) 770 struct v4l2_requestbuffers *reqbufs)
748{ 771{
749 struct s5p_jpeg_ctx *ctx = priv; 772 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
750 773
751 return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); 774 return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
752} 775}
@@ -754,14 +777,14 @@ static int s5p_jpeg_reqbufs(struct file *file, void *priv,
754static int s5p_jpeg_querybuf(struct file *file, void *priv, 777static int s5p_jpeg_querybuf(struct file *file, void *priv,
755 struct v4l2_buffer *buf) 778 struct v4l2_buffer *buf)
756{ 779{
757 struct s5p_jpeg_ctx *ctx = priv; 780 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
758 781
759 return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); 782 return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
760} 783}
761 784
762static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) 785static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
763{ 786{
764 struct s5p_jpeg_ctx *ctx = priv; 787 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
765 788
766 return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); 789 return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
767} 790}
@@ -769,7 +792,7 @@ static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
769static int s5p_jpeg_dqbuf(struct file *file, void *priv, 792static int s5p_jpeg_dqbuf(struct file *file, void *priv,
770 struct v4l2_buffer *buf) 793 struct v4l2_buffer *buf)
771{ 794{
772 struct s5p_jpeg_ctx *ctx = priv; 795 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
773 796
774 return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); 797 return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
775} 798}
@@ -777,7 +800,7 @@ static int s5p_jpeg_dqbuf(struct file *file, void *priv,
777static int s5p_jpeg_streamon(struct file *file, void *priv, 800static int s5p_jpeg_streamon(struct file *file, void *priv,
778 enum v4l2_buf_type type) 801 enum v4l2_buf_type type)
779{ 802{
780 struct s5p_jpeg_ctx *ctx = priv; 803 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
781 804
782 return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); 805 return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
783} 806}
@@ -785,7 +808,7 @@ static int s5p_jpeg_streamon(struct file *file, void *priv,
785static int s5p_jpeg_streamoff(struct file *file, void *priv, 808static int s5p_jpeg_streamoff(struct file *file, void *priv,
786 enum v4l2_buf_type type) 809 enum v4l2_buf_type type)
787{ 810{
788 struct s5p_jpeg_ctx *ctx = priv; 811 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
789 812
790 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); 813 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
791} 814}
@@ -793,7 +816,7 @@ static int s5p_jpeg_streamoff(struct file *file, void *priv,
793int s5p_jpeg_g_selection(struct file *file, void *priv, 816int s5p_jpeg_g_selection(struct file *file, void *priv,
794 struct v4l2_selection *s) 817 struct v4l2_selection *s)
795{ 818{
796 struct s5p_jpeg_ctx *ctx = priv; 819 struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
797 820
798 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && 821 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
799 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 822 s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -822,33 +845,89 @@ int s5p_jpeg_g_selection(struct file *file, void *priv,
822 return 0; 845 return 0;
823} 846}
824 847
825static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, 848/*
826 struct v4l2_jpegcompression *compr) 849 * V4L2 controls
850 */
851
852static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
827{ 853{
828 struct s5p_jpeg_ctx *ctx = priv; 854 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
855 struct s5p_jpeg *jpeg = ctx->jpeg;
856 unsigned long flags;
829 857
830 if (ctx->mode == S5P_JPEG_DECODE) 858 switch (ctrl->id) {
831 return -ENOTTY; 859 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
860 spin_lock_irqsave(&jpeg->slock, flags);
832 861
833 memset(compr, 0, sizeof(*compr)); 862 WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
834 compr->quality = ctx->compr_quality; 863 if (ctx->subsampling > 2)
864 ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
865 else
866 ctrl->val = ctx->subsampling;
867 spin_unlock_irqrestore(&jpeg->slock, flags);
868 break;
869 }
835 870
836 return 0; 871 return 0;
837} 872}
838 873
839static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, 874static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
840 struct v4l2_jpegcompression *compr)
841{ 875{
842 struct s5p_jpeg_ctx *ctx = priv; 876 struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
877 unsigned long flags;
843 878
844 if (ctx->mode == S5P_JPEG_DECODE) 879 spin_lock_irqsave(&ctx->jpeg->slock, flags);
845 return -ENOTTY;
846 880
847 compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, 881 switch (ctrl->id) {
848 S5P_JPEG_COMPR_QUAL_WORST); 882 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
883 ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
884 break;
885 case V4L2_CID_JPEG_RESTART_INTERVAL:
886 ctx->restart_interval = ctrl->val;
887 break;
888 case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
889 ctx->subsampling = ctrl->val;
890 break;
891 }
849 892
850 ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; 893 spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
894 return 0;
895}
896
897static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
898 .g_volatile_ctrl = s5p_jpeg_g_volatile_ctrl,
899 .s_ctrl = s5p_jpeg_s_ctrl,
900};
851 901
902static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
903{
904 unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
905 struct v4l2_ctrl *ctrl;
906
907 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
908
909 if (ctx->mode == S5P_JPEG_ENCODE) {
910 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
911 V4L2_CID_JPEG_COMPRESSION_QUALITY,
912 0, 3, 1, 3);
913
914 v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
915 V4L2_CID_JPEG_RESTART_INTERVAL,
916 0, 3, 0xffff, 0);
917 mask = ~0x06; /* 422, 420 */
918 }
919
920 ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
921 V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
922 V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
923 V4L2_JPEG_CHROMA_SUBSAMPLING_422);
924
925 if (ctx->ctrl_handler.error)
926 return ctx->ctrl_handler.error;
927
928 if (ctx->mode == S5P_JPEG_DECODE)
929 ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
930 V4L2_CTRL_FLAG_READ_ONLY;
852 return 0; 931 return 0;
853} 932}
854 933
@@ -877,9 +956,6 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
877 .vidioc_streamoff = s5p_jpeg_streamoff, 956 .vidioc_streamoff = s5p_jpeg_streamoff,
878 957
879 .vidioc_g_selection = s5p_jpeg_g_selection, 958 .vidioc_g_selection = s5p_jpeg_g_selection,
880
881 .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp,
882 .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp,
883}; 959};
884 960
885/* 961/*
@@ -908,13 +984,8 @@ static void s5p_jpeg_device_run(void *priv)
908 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); 984 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
909 else 985 else
910 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); 986 jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
911 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) 987 jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
912 jpeg_subsampling_mode(jpeg->regs, 988 jpeg_dri(jpeg->regs, ctx->restart_interval);
913 S5P_JPEG_SUBSAMPLING_422);
914 else
915 jpeg_subsampling_mode(jpeg->regs,
916 S5P_JPEG_SUBSAMPLING_420);
917 jpeg_dri(jpeg->regs, 0);
918 jpeg_x(jpeg->regs, ctx->out_q.w); 989 jpeg_x(jpeg->regs, ctx->out_q.w);
919 jpeg_y(jpeg->regs, ctx->out_q.h); 990 jpeg_y(jpeg->regs, ctx->out_q.h);
920 jpeg_imgadr(jpeg->regs, src_addr); 991 jpeg_imgadr(jpeg->regs, src_addr);
@@ -953,14 +1024,18 @@ static void s5p_jpeg_device_run(void *priv)
953 jpeg_htbl_dc(jpeg->regs, 2); 1024 jpeg_htbl_dc(jpeg->regs, 2);
954 jpeg_htbl_ac(jpeg->regs, 3); 1025 jpeg_htbl_ac(jpeg->regs, 3);
955 jpeg_htbl_dc(jpeg->regs, 3); 1026 jpeg_htbl_dc(jpeg->regs, 3);
956 } else { 1027 } else { /* S5P_JPEG_DECODE */
957 jpeg_rst_int_enable(jpeg->regs, true); 1028 jpeg_rst_int_enable(jpeg->regs, true);
958 jpeg_data_num_int_enable(jpeg->regs, true); 1029 jpeg_data_num_int_enable(jpeg->regs, true);
959 jpeg_final_mcu_num_int_enable(jpeg->regs, true); 1030 jpeg_final_mcu_num_int_enable(jpeg->regs, true);
960 jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); 1031 if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
1032 jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
1033 else
1034 jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
961 jpeg_jpgadr(jpeg->regs, src_addr); 1035 jpeg_jpgadr(jpeg->regs, src_addr);
962 jpeg_imgadr(jpeg->regs, dst_addr); 1036 jpeg_imgadr(jpeg->regs, dst_addr);
963 } 1037 }
1038
964 jpeg_start(jpeg->regs); 1039 jpeg_start(jpeg->regs);
965} 1040}
966 1041
@@ -1162,6 +1237,8 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1162 bool timer_elapsed = false; 1237 bool timer_elapsed = false;
1163 bool op_completed = false; 1238 bool op_completed = false;
1164 1239
1240 spin_lock(&jpeg->slock);
1241
1165 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); 1242 curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
1166 1243
1167 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); 1244 src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
@@ -1192,6 +1269,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
1192 v4l2_m2m_buf_done(dst_buf, state); 1269 v4l2_m2m_buf_done(dst_buf, state);
1193 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); 1270 v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
1194 1271
1272 curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
1273 spin_unlock(&jpeg->slock);
1274
1195 jpeg_clear_int(jpeg->regs); 1275 jpeg_clear_int(jpeg->regs);
1196 1276
1197 return IRQ_HANDLED; 1277 return IRQ_HANDLED;
@@ -1215,6 +1295,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
1215 return -ENOMEM; 1295 return -ENOMEM;
1216 1296
1217 mutex_init(&jpeg->lock); 1297 mutex_init(&jpeg->lock);
1298 spin_lock_init(&jpeg->slock);
1218 jpeg->dev = &pdev->dev; 1299 jpeg->dev = &pdev->dev;
1219 1300
1220 /* memory-mapped registers */ 1301 /* memory-mapped registers */
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
index facad6114f5e..38d7367f7a6d 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -14,6 +14,8 @@
14#define JPEG_CORE_H_ 14#define JPEG_CORE_H_
15 15
16#include <media/v4l2-device.h> 16#include <media/v4l2-device.h>
17#include <media/v4l2-fh.h>
18#include <media/v4l2-ctrls.h>
17 19
18#define S5P_JPEG_M2M_NAME "s5p-jpeg" 20#define S5P_JPEG_M2M_NAME "s5p-jpeg"
19 21
@@ -47,6 +49,7 @@
47/** 49/**
48 * struct s5p_jpeg - JPEG IP abstraction 50 * struct s5p_jpeg - JPEG IP abstraction
49 * @lock: the mutex protecting this structure 51 * @lock: the mutex protecting this structure
52 * @slock: spinlock protecting the device contexts
50 * @v4l2_dev: v4l2 device for mem2mem mode 53 * @v4l2_dev: v4l2 device for mem2mem mode
51 * @vfd_encoder: video device node for encoder mem2mem mode 54 * @vfd_encoder: video device node for encoder mem2mem mode
52 * @vfd_decoder: video device node for decoder mem2mem mode 55 * @vfd_decoder: video device node for decoder mem2mem mode
@@ -60,6 +63,7 @@
60 */ 63 */
61struct s5p_jpeg { 64struct s5p_jpeg {
62 struct mutex lock; 65 struct mutex lock;
66 struct spinlock slock;
63 67
64 struct v4l2_device v4l2_dev; 68 struct v4l2_device v4l2_dev;
65 struct video_device *vfd_encoder; 69 struct video_device *vfd_encoder;
@@ -117,15 +121,20 @@ struct s5p_jpeg_q_data {
117 * @out_q: source (output) queue information 121 * @out_q: source (output) queue information
118 * @cap_fmt: destination (capture) queue queue information 122 * @cap_fmt: destination (capture) queue queue information
119 * @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
120 */ 125 */
121struct s5p_jpeg_ctx { 126struct s5p_jpeg_ctx {
122 struct s5p_jpeg *jpeg; 127 struct s5p_jpeg *jpeg;
123 unsigned int mode; 128 unsigned int mode;
124 unsigned int compr_quality; 129 unsigned short compr_quality;
130 unsigned short restart_interval;
131 unsigned short subsampling;
125 struct v4l2_m2m_ctx *m2m_ctx; 132 struct v4l2_m2m_ctx *m2m_ctx;
126 struct s5p_jpeg_q_data out_q; 133 struct s5p_jpeg_q_data out_q;
127 struct s5p_jpeg_q_data cap_q; 134 struct s5p_jpeg_q_data cap_q;
135 struct v4l2_fh fh;
128 bool hdr_parsed; 136 bool hdr_parsed;
137 struct v4l2_ctrl_handler ctrl_handler;
129}; 138};
130 139
131/** 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;