diff options
Diffstat (limited to 'drivers/media/video/s5p-jpeg')
-rw-r--r-- | drivers/media/video/s5p-jpeg/jpeg-core.c | 199 | ||||
-rw-r--r-- | drivers/media/video/s5p-jpeg/jpeg-core.h | 11 | ||||
-rw-r--r-- | drivers/media/video/s5p-jpeg/jpeg-hw.h | 18 |
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 | ||
33 | static struct s5p_jpeg_fmt formats_enc[] = { | 33 | static 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 | ||
205 | static 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 | |||
210 | static 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 | |||
206 | static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, | 215 | static 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); |
270 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, | 279 | static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, |
271 | __u32 pixelformat); | 280 | __u32 pixelformat); |
281 | static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx); | ||
272 | 282 | ||
273 | static int s5p_jpeg_open(struct file *file) | 283 | static 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 | |||
324 | error: | ||
325 | v4l2_fh_del(&ctx->fh); | ||
326 | v4l2_fh_exit(&ctx->fh); | ||
327 | kfree(ctx); | ||
328 | return ret; | ||
305 | } | 329 | } |
306 | 330 | ||
307 | static int s5p_jpeg_release(struct file *file) | 331 | static 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) | |||
317 | static unsigned int s5p_jpeg_poll(struct file *file, | 344 | static 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 | ||
325 | static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) | 352 | static 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, | |||
448 | static int s5p_jpeg_querycap(struct file *file, void *priv, | 475 | static 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, | |||
497 | static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, | 524 | static 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, | |||
511 | static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, | 536 | static 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, | |||
659 | static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, | 682 | static 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, | |||
676 | static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, | 699 | static 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 | ||
734 | static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, | 757 | static 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 | ||
746 | static int s5p_jpeg_reqbufs(struct file *file, void *priv, | 769 | static 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, | |||
754 | static int s5p_jpeg_querybuf(struct file *file, void *priv, | 777 | static 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 | ||
762 | static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | 785 | static 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) | |||
769 | static int s5p_jpeg_dqbuf(struct file *file, void *priv, | 792 | static 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, | |||
777 | static int s5p_jpeg_streamon(struct file *file, void *priv, | 800 | static 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, | |||
785 | static int s5p_jpeg_streamoff(struct file *file, void *priv, | 808 | static 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, | |||
793 | int s5p_jpeg_g_selection(struct file *file, void *priv, | 816 | int 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 | ||
825 | static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, | 848 | /* |
826 | struct v4l2_jpegcompression *compr) | 849 | * V4L2 controls |
850 | */ | ||
851 | |||
852 | static 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 | ||
839 | static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, | 874 | static 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 | |||
897 | static 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 | ||
902 | static 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 | */ |
61 | struct s5p_jpeg { | 64 | struct 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 | */ |
121 | struct s5p_jpeg_ctx { | 126 | struct 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 | ||
94 | static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) | 93 | static 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 | ||
108 | static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs) | ||
109 | { | ||
110 | return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK; | ||
111 | } | ||
112 | |||
109 | static inline void jpeg_dri(void __iomem *regs, unsigned int dri) | 113 | static inline void jpeg_dri(void __iomem *regs, unsigned int dri) |
110 | { | 114 | { |
111 | unsigned long reg; | 115 | unsigned long reg; |