aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-fimc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-15 15:49:56 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-15 15:49:56 -0500
commit122804ecb59493fbb4d31b3ba9ac59faaf45276f (patch)
treecff4d8a158c412e4a8d3abc8d91bb0eb52b01c9a /drivers/media/video/s5p-fimc
parent16008d641670571ff4cd750b416c7caf2d89f467 (diff)
parent126400033940afb658123517a2e80eb68259fbd7 (diff)
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (655 commits) [media] revert patch: HDIC HD29L2 DMB-TH USB2.0 reference design driver mb86a20s: Add a few more register settings at the init seq mb86a20s: Group registers into the same line [media] [PATCH] don't reset the delivery system on DTV_CLEAR [media] [BUG] it913x-fe fix typo error making SNR levels unstable [media] cx23885: Query the CX25840 during enum_input for status [media] cx25840: Add support for g_input_status [media] rc-videomate-m1f.c Rename to match remote controler name [media] drivers: media: au0828: Fix dependency for VIDEO_AU0828 [media] convert drivers/media/* to use module_platform_driver() [media] drivers: video: cx231xx: Fix dependency for VIDEO_CX231XX_DVB [media] Exynos4 JPEG codec v4l2 driver [media] doc: v4l: selection: choose pixels as units for selection rectangles [media] v4l: s5p-tv: mixer: fix setup of VP scaling [media] v4l: s5p-tv: mixer: add support for selection API [media] v4l: emulate old crop API using extended crop/compose API [media] doc: v4l: add documentation for selection API [media] doc: v4l: add binary images for selection API [media] v4l: add support for selection api [media] hd29l2: fix review findings ...
Diffstat (limited to 'drivers/media/video/s5p-fimc')
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c11
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c134
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h30
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c53
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.c22
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.h3
-rw-r--r--drivers/media/video/s5p-fimc/regs-fimc.h5
7 files changed, 213 insertions, 45 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 2cc3b9166724..510cfab477ff 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -63,6 +63,8 @@ static int fimc_init_capture(struct fimc_dev *fimc)
63 fimc_hw_set_effect(ctx, false); 63 fimc_hw_set_effect(ctx, false);
64 fimc_hw_set_output_path(ctx); 64 fimc_hw_set_output_path(ctx);
65 fimc_hw_set_out_dma(ctx); 65 fimc_hw_set_out_dma(ctx);
66 if (fimc->variant->has_alpha)
67 fimc_hw_set_rgb_alpha(ctx);
66 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); 68 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
67 } 69 }
68 spin_unlock_irqrestore(&fimc->slock, flags); 70 spin_unlock_irqrestore(&fimc->slock, flags);
@@ -154,6 +156,8 @@ int fimc_capture_config_update(struct fimc_ctx *ctx)
154 fimc_hw_set_rotation(ctx); 156 fimc_hw_set_rotation(ctx);
155 fimc_prepare_dma_offset(ctx, &ctx->d_frame); 157 fimc_prepare_dma_offset(ctx, &ctx->d_frame);
156 fimc_hw_set_out_dma(ctx); 158 fimc_hw_set_out_dma(ctx);
159 if (fimc->variant->has_alpha)
160 fimc_hw_set_rgb_alpha(ctx);
157 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); 161 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
158 } 162 }
159 spin_unlock(&ctx->slock); 163 spin_unlock(&ctx->slock);
@@ -812,6 +816,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
812 FIMC_SD_PAD_SOURCE); 816 FIMC_SD_PAD_SOURCE);
813 if (!ff->fmt) 817 if (!ff->fmt)
814 return -EINVAL; 818 return -EINVAL;
819
820 /* Update RGB Alpha control state and value range */
821 fimc_alpha_ctrl_update(ctx);
822
815 /* Try to match format at the host and the sensor */ 823 /* Try to match format at the host and the sensor */
816 if (!fimc->vid_cap.user_subdev_api) { 824 if (!fimc->vid_cap.user_subdev_api) {
817 mf->code = ff->fmt->mbus_code; 825 mf->code = ff->fmt->mbus_code;
@@ -1235,6 +1243,9 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
1235 *mf = fmt->format; 1243 *mf = fmt->format;
1236 return 0; 1244 return 0;
1237 } 1245 }
1246 /* Update RGB Alpha control state and value range */
1247 fimc_alpha_ctrl_update(ctx);
1248
1238 fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); 1249 fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color));
1239 1250
1240 ff = fmt->pad == FIMC_SD_PAD_SINK ? 1251 ff = fmt->pad == FIMC_SD_PAD_SINK ?
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 07c6254faee3..f5cbb8a4c540 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -52,13 +52,29 @@ static struct fimc_fmt fimc_formats[] = {
52 .colplanes = 1, 52 .colplanes = 1,
53 .flags = FMT_FLAGS_M2M, 53 .flags = FMT_FLAGS_M2M,
54 }, { 54 }, {
55 .name = "XRGB-8-8-8-8, 32 bpp", 55 .name = "ARGB8888, 32 bpp",
56 .fourcc = V4L2_PIX_FMT_RGB32, 56 .fourcc = V4L2_PIX_FMT_RGB32,
57 .depth = { 32 }, 57 .depth = { 32 },
58 .color = S5P_FIMC_RGB888, 58 .color = S5P_FIMC_RGB888,
59 .memplanes = 1, 59 .memplanes = 1,
60 .colplanes = 1, 60 .colplanes = 1,
61 .flags = FMT_FLAGS_M2M, 61 .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
62 }, {
63 .name = "ARGB1555",
64 .fourcc = V4L2_PIX_FMT_RGB555,
65 .depth = { 16 },
66 .color = S5P_FIMC_RGB555,
67 .memplanes = 1,
68 .colplanes = 1,
69 .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
70 }, {
71 .name = "ARGB4444",
72 .fourcc = V4L2_PIX_FMT_RGB444,
73 .depth = { 16 },
74 .color = S5P_FIMC_RGB444,
75 .memplanes = 1,
76 .colplanes = 1,
77 .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
62 }, { 78 }, {
63 .name = "YUV 4:2:2 packed, YCbYCr", 79 .name = "YUV 4:2:2 packed, YCbYCr",
64 .fourcc = V4L2_PIX_FMT_YUYV, 80 .fourcc = V4L2_PIX_FMT_YUYV,
@@ -171,6 +187,14 @@ static struct fimc_fmt fimc_formats[] = {
171 }, 187 },
172}; 188};
173 189
190static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
191{
192 if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
193 return FMT_FLAGS_M2M_IN;
194 else
195 return FMT_FLAGS_M2M_OUT;
196}
197
174int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, 198int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
175 int dw, int dh, int rotation) 199 int dw, int dh, int rotation)
176{ 200{
@@ -652,8 +676,11 @@ static void fimc_dma_run(void *priv)
652 if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS)) 676 if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
653 fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1); 677 fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
654 678
655 if (ctx->state & FIMC_PARAMS) 679 if (ctx->state & FIMC_PARAMS) {
656 fimc_hw_set_out_dma(ctx); 680 fimc_hw_set_out_dma(ctx);
681 if (fimc->variant->has_alpha)
682 fimc_hw_set_rgb_alpha(ctx);
683 }
657 684
658 fimc_activate_capture(ctx); 685 fimc_activate_capture(ctx);
659 686
@@ -750,12 +777,11 @@ static struct vb2_ops fimc_qops = {
750#define ctrl_to_ctx(__ctrl) \ 777#define ctrl_to_ctx(__ctrl) \
751 container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler) 778 container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
752 779
753static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) 780static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
754{ 781{
755 struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
756 struct fimc_dev *fimc = ctx->fimc_dev; 782 struct fimc_dev *fimc = ctx->fimc_dev;
757 struct samsung_fimc_variant *variant = fimc->variant; 783 struct samsung_fimc_variant *variant = fimc->variant;
758 unsigned long flags; 784 unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
759 int ret = 0; 785 int ret = 0;
760 786
761 if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) 787 if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
@@ -763,52 +789,63 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
763 789
764 switch (ctrl->id) { 790 switch (ctrl->id) {
765 case V4L2_CID_HFLIP: 791 case V4L2_CID_HFLIP:
766 spin_lock_irqsave(&ctx->slock, flags);
767 ctx->hflip = ctrl->val; 792 ctx->hflip = ctrl->val;
768 break; 793 break;
769 794
770 case V4L2_CID_VFLIP: 795 case V4L2_CID_VFLIP:
771 spin_lock_irqsave(&ctx->slock, flags);
772 ctx->vflip = ctrl->val; 796 ctx->vflip = ctrl->val;
773 break; 797 break;
774 798
775 case V4L2_CID_ROTATE: 799 case V4L2_CID_ROTATE:
776 if (fimc_capture_pending(fimc) || 800 if (fimc_capture_pending(fimc) ||
777 fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { 801 (ctx->state & flags) == flags) {
778 ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, 802 ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
779 ctx->s_frame.height, ctx->d_frame.width, 803 ctx->s_frame.height, ctx->d_frame.width,
780 ctx->d_frame.height, ctrl->val); 804 ctx->d_frame.height, ctrl->val);
781 } 805 if (ret)
782 if (ret) { 806 return -EINVAL;
783 v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
784 return -EINVAL;
785 } 807 }
786 if ((ctrl->val == 90 || ctrl->val == 270) && 808 if ((ctrl->val == 90 || ctrl->val == 270) &&
787 !variant->has_out_rot) 809 !variant->has_out_rot)
788 return -EINVAL; 810 return -EINVAL;
789 spin_lock_irqsave(&ctx->slock, flags); 811
790 ctx->rotation = ctrl->val; 812 ctx->rotation = ctrl->val;
791 break; 813 break;
792 814
793 default: 815 case V4L2_CID_ALPHA_COMPONENT:
794 v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id); 816 ctx->d_frame.alpha = ctrl->val;
795 return -EINVAL; 817 break;
796 } 818 }
797 ctx->state |= FIMC_PARAMS; 819 ctx->state |= FIMC_PARAMS;
798 set_bit(ST_CAPT_APPLY_CFG, &fimc->state); 820 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
799 spin_unlock_irqrestore(&ctx->slock, flags);
800 return 0; 821 return 0;
801} 822}
802 823
824static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
825{
826 struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
827 unsigned long flags;
828 int ret;
829
830 spin_lock_irqsave(&ctx->slock, flags);
831 ret = __fimc_s_ctrl(ctx, ctrl);
832 spin_unlock_irqrestore(&ctx->slock, flags);
833
834 return ret;
835}
836
803static const struct v4l2_ctrl_ops fimc_ctrl_ops = { 837static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
804 .s_ctrl = fimc_s_ctrl, 838 .s_ctrl = fimc_s_ctrl,
805}; 839};
806 840
807int fimc_ctrls_create(struct fimc_ctx *ctx) 841int fimc_ctrls_create(struct fimc_ctx *ctx)
808{ 842{
843 struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
844 unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
845
809 if (ctx->ctrls_rdy) 846 if (ctx->ctrls_rdy)
810 return 0; 847 return 0;
811 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); 848 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
812 849
813 ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, 850 ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
814 V4L2_CID_HFLIP, 0, 1, 1, 0); 851 V4L2_CID_HFLIP, 0, 1, 1, 0);
@@ -816,6 +853,13 @@ int fimc_ctrls_create(struct fimc_ctx *ctx)
816 V4L2_CID_VFLIP, 0, 1, 1, 0); 853 V4L2_CID_VFLIP, 0, 1, 1, 0);
817 ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, 854 ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
818 V4L2_CID_ROTATE, 0, 270, 90, 0); 855 V4L2_CID_ROTATE, 0, 270, 90, 0);
856 if (variant->has_alpha)
857 ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
858 &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
859 0, max_alpha, 1, 0);
860 else
861 ctx->ctrl_alpha = NULL;
862
819 ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; 863 ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
820 864
821 return ctx->ctrl_handler.error; 865 return ctx->ctrl_handler.error;
@@ -826,11 +870,14 @@ void fimc_ctrls_delete(struct fimc_ctx *ctx)
826 if (ctx->ctrls_rdy) { 870 if (ctx->ctrls_rdy) {
827 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 871 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
828 ctx->ctrls_rdy = false; 872 ctx->ctrls_rdy = false;
873 ctx->ctrl_alpha = NULL;
829 } 874 }
830} 875}
831 876
832void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) 877void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
833{ 878{
879 unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
880
834 if (!ctx->ctrls_rdy) 881 if (!ctx->ctrls_rdy)
835 return; 882 return;
836 883
@@ -838,6 +885,8 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
838 v4l2_ctrl_activate(ctx->ctrl_rotate, active); 885 v4l2_ctrl_activate(ctx->ctrl_rotate, active);
839 v4l2_ctrl_activate(ctx->ctrl_hflip, active); 886 v4l2_ctrl_activate(ctx->ctrl_hflip, active);
840 v4l2_ctrl_activate(ctx->ctrl_vflip, active); 887 v4l2_ctrl_activate(ctx->ctrl_vflip, active);
888 if (ctx->ctrl_alpha)
889 v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha);
841 890
842 if (active) { 891 if (active) {
843 ctx->rotation = ctx->ctrl_rotate->val; 892 ctx->rotation = ctx->ctrl_rotate->val;
@@ -851,6 +900,24 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
851 mutex_unlock(&ctx->ctrl_handler.lock); 900 mutex_unlock(&ctx->ctrl_handler.lock);
852} 901}
853 902
903/* Update maximum value of the alpha color control */
904void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
905{
906 struct fimc_dev *fimc = ctx->fimc_dev;
907 struct v4l2_ctrl *ctrl = ctx->ctrl_alpha;
908
909 if (ctrl == NULL || !fimc->variant->has_alpha)
910 return;
911
912 v4l2_ctrl_lock(ctrl);
913 ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
914
915 if (ctrl->cur.val > ctrl->maximum)
916 ctrl->cur.val = ctrl->maximum;
917
918 v4l2_ctrl_unlock(ctrl);
919}
920
854/* 921/*
855 * V4L2 ioctl handlers 922 * V4L2 ioctl handlers
856 */ 923 */
@@ -874,7 +941,8 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
874{ 941{
875 struct fimc_fmt *fmt; 942 struct fimc_fmt *fmt;
876 943
877 fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index); 944 fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
945 f->index);
878 if (!fmt) 946 if (!fmt)
879 return -EINVAL; 947 return -EINVAL;
880 948
@@ -938,6 +1006,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
938 pix->colorspace = V4L2_COLORSPACE_JPEG; 1006 pix->colorspace = V4L2_COLORSPACE_JPEG;
939 pix->field = V4L2_FIELD_NONE; 1007 pix->field = V4L2_FIELD_NONE;
940 pix->num_planes = fmt->memplanes; 1008 pix->num_planes = fmt->memplanes;
1009 pix->pixelformat = fmt->fourcc;
941 pix->height = height; 1010 pix->height = height;
942 pix->width = width; 1011 pix->width = width;
943 1012
@@ -1017,7 +1086,8 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
1017 1086
1018 dbg("w: %d, h: %d", pix->width, pix->height); 1087 dbg("w: %d, h: %d", pix->width, pix->height);
1019 1088
1020 fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0); 1089 fmt = fimc_find_format(&pix->pixelformat, NULL,
1090 get_m2m_fmt_flags(f->type), 0);
1021 if (WARN(fmt == NULL, "Pixel format lookup failed")) 1091 if (WARN(fmt == NULL, "Pixel format lookup failed"))
1022 return -EINVAL; 1092 return -EINVAL;
1023 1093
@@ -1087,10 +1157,13 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
1087 1157
1088 pix = &f->fmt.pix_mp; 1158 pix = &f->fmt.pix_mp;
1089 frame->fmt = fimc_find_format(&pix->pixelformat, NULL, 1159 frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
1090 FMT_FLAGS_M2M, 0); 1160 get_m2m_fmt_flags(f->type), 0);
1091 if (!frame->fmt) 1161 if (!frame->fmt)
1092 return -EINVAL; 1162 return -EINVAL;
1093 1163
1164 /* Update RGB Alpha control state and value range */
1165 fimc_alpha_ctrl_update(ctx);
1166
1094 for (i = 0; i < frame->fmt->colplanes; i++) { 1167 for (i = 0; i < frame->fmt->colplanes; i++) {
1095 frame->payload[i] = 1168 frame->payload[i] =
1096 (pix->width * pix->height * frame->fmt->depth[i]) / 8; 1169 (pix->width * pix->height * frame->fmt->depth[i]) / 8;
@@ -1374,6 +1447,12 @@ static int fimc_m2m_open(struct file *file)
1374 if (!ctx) 1447 if (!ctx)
1375 return -ENOMEM; 1448 return -ENOMEM;
1376 v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); 1449 v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
1450 ctx->fimc_dev = fimc;
1451
1452 /* Default color format */
1453 ctx->s_frame.fmt = &fimc_formats[0];
1454 ctx->d_frame.fmt = &fimc_formats[0];
1455
1377 ret = fimc_ctrls_create(ctx); 1456 ret = fimc_ctrls_create(ctx);
1378 if (ret) 1457 if (ret)
1379 goto error_fh; 1458 goto error_fh;
@@ -1383,10 +1462,6 @@ static int fimc_m2m_open(struct file *file)
1383 file->private_data = &ctx->fh; 1462 file->private_data = &ctx->fh;
1384 v4l2_fh_add(&ctx->fh); 1463 v4l2_fh_add(&ctx->fh);
1385 1464
1386 ctx->fimc_dev = fimc;
1387 /* Default color format */
1388 ctx->s_frame.fmt = &fimc_formats[0];
1389 ctx->d_frame.fmt = &fimc_formats[0];
1390 /* Setup the device context for memory-to-memory mode */ 1465 /* Setup the device context for memory-to-memory mode */
1391 ctx->state = FIMC_CTX_M2M; 1466 ctx->state = FIMC_CTX_M2M;
1392 ctx->flags = 0; 1467 ctx->flags = 0;
@@ -1709,9 +1784,8 @@ static int fimc_runtime_resume(struct device *dev)
1709 /* Resume the capture or mem-to-mem device */ 1784 /* Resume the capture or mem-to-mem device */
1710 if (fimc_capture_busy(fimc)) 1785 if (fimc_capture_busy(fimc))
1711 return fimc_capture_resume(fimc); 1786 return fimc_capture_resume(fimc);
1712 else if (fimc_m2m_pending(fimc)) 1787
1713 return fimc_m2m_resume(fimc); 1788 return fimc_m2m_resume(fimc);
1714 return 0;
1715} 1789}
1716 1790
1717static int fimc_runtime_suspend(struct device *dev) 1791static int fimc_runtime_suspend(struct device *dev)
@@ -1893,6 +1967,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = {
1893 .has_cam_if = 1, 1967 .has_cam_if = 1,
1894 .has_cistatus2 = 1, 1968 .has_cistatus2 = 1,
1895 .has_mainscaler_ext = 1, 1969 .has_mainscaler_ext = 1,
1970 .has_alpha = 1,
1896 .min_inp_pixsize = 16, 1971 .min_inp_pixsize = 16,
1897 .min_out_pixsize = 16, 1972 .min_out_pixsize = 16,
1898 .hor_offs_align = 2, 1973 .hor_offs_align = 2,
@@ -1906,6 +1981,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = {
1906 .has_cam_if = 1, 1981 .has_cam_if = 1,
1907 .has_cistatus2 = 1, 1982 .has_cistatus2 = 1,
1908 .has_mainscaler_ext = 1, 1983 .has_mainscaler_ext = 1,
1984 .has_alpha = 1,
1909 .min_inp_pixsize = 16, 1985 .min_inp_pixsize = 16,
1910 .min_out_pixsize = 16, 1986 .min_out_pixsize = 16,
1911 .hor_offs_align = 2, 1987 .hor_offs_align = 2,
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index c7f01c47b20f..4e20560c73d4 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -85,7 +85,9 @@ enum fimc_datapath {
85}; 85};
86 86
87enum fimc_color_fmt { 87enum fimc_color_fmt {
88 S5P_FIMC_RGB565 = 0x10, 88 S5P_FIMC_RGB444 = 0x10,
89 S5P_FIMC_RGB555,
90 S5P_FIMC_RGB565,
89 S5P_FIMC_RGB666, 91 S5P_FIMC_RGB666,
90 S5P_FIMC_RGB888, 92 S5P_FIMC_RGB888,
91 S5P_FIMC_RGB30_LOCAL, 93 S5P_FIMC_RGB30_LOCAL,
@@ -160,8 +162,11 @@ struct fimc_fmt {
160 u16 colplanes; 162 u16 colplanes;
161 u8 depth[VIDEO_MAX_PLANES]; 163 u8 depth[VIDEO_MAX_PLANES];
162 u16 flags; 164 u16 flags;
163#define FMT_FLAGS_CAM (1 << 0) 165#define FMT_FLAGS_CAM (1 << 0)
164#define FMT_FLAGS_M2M (1 << 1) 166#define FMT_FLAGS_M2M_IN (1 << 1)
167#define FMT_FLAGS_M2M_OUT (1 << 2)
168#define FMT_FLAGS_M2M (1 << 1 | 1 << 2)
169#define FMT_HAS_ALPHA (1 << 3)
165}; 170};
166 171
167/** 172/**
@@ -283,6 +288,7 @@ struct fimc_frame {
283 struct fimc_addr paddr; 288 struct fimc_addr paddr;
284 struct fimc_dma_offset dma_offset; 289 struct fimc_dma_offset dma_offset;
285 struct fimc_fmt *fmt; 290 struct fimc_fmt *fmt;
291 u8 alpha;
286}; 292};
287 293
288/** 294/**
@@ -387,6 +393,7 @@ struct samsung_fimc_variant {
387 unsigned int has_cistatus2:1; 393 unsigned int has_cistatus2:1;
388 unsigned int has_mainscaler_ext:1; 394 unsigned int has_mainscaler_ext:1;
389 unsigned int has_cam_if:1; 395 unsigned int has_cam_if:1;
396 unsigned int has_alpha:1;
390 struct fimc_pix_limit *pix_limit; 397 struct fimc_pix_limit *pix_limit;
391 u16 min_inp_pixsize; 398 u16 min_inp_pixsize;
392 u16 min_out_pixsize; 399 u16 min_out_pixsize;
@@ -482,7 +489,8 @@ struct fimc_dev {
482 * @ctrl_handler: v4l2 controls handler 489 * @ctrl_handler: v4l2 controls handler
483 * @ctrl_rotate image rotation control 490 * @ctrl_rotate image rotation control
484 * @ctrl_hflip horizontal flip control 491 * @ctrl_hflip horizontal flip control
485 * @ctrl_vflip vartical flip control 492 * @ctrl_vflip vertical flip control
493 * @ctrl_alpha RGB alpha control
486 * @ctrls_rdy: true if the control handler is initialized 494 * @ctrls_rdy: true if the control handler is initialized
487 */ 495 */
488struct fimc_ctx { 496struct fimc_ctx {
@@ -509,6 +517,7 @@ struct fimc_ctx {
509 struct v4l2_ctrl *ctrl_rotate; 517 struct v4l2_ctrl *ctrl_rotate;
510 struct v4l2_ctrl *ctrl_hflip; 518 struct v4l2_ctrl *ctrl_hflip;
511 struct v4l2_ctrl *ctrl_vflip; 519 struct v4l2_ctrl *ctrl_vflip;
520 struct v4l2_ctrl *ctrl_alpha;
512 bool ctrls_rdy; 521 bool ctrls_rdy;
513}; 522};
514 523
@@ -578,6 +587,17 @@ static inline int tiled_fmt(struct fimc_fmt *fmt)
578 return fmt->fourcc == V4L2_PIX_FMT_NV12MT; 587 return fmt->fourcc == V4L2_PIX_FMT_NV12MT;
579} 588}
580 589
590/* Return the alpha component bit mask */
591static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt)
592{
593 switch (fmt->color) {
594 case S5P_FIMC_RGB444: return 0x0f;
595 case S5P_FIMC_RGB555: return 0x01;
596 case S5P_FIMC_RGB888: return 0xff;
597 default: return 0;
598 };
599}
600
581static inline void fimc_hw_clear_irq(struct fimc_dev *dev) 601static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
582{ 602{
583 u32 cfg = readl(dev->regs + S5P_CIGCTRL); 603 u32 cfg = readl(dev->regs + S5P_CIGCTRL);
@@ -674,6 +694,7 @@ void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
674void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); 694void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
675void fimc_hw_en_capture(struct fimc_ctx *ctx); 695void fimc_hw_en_capture(struct fimc_ctx *ctx);
676void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active); 696void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active);
697void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
677void fimc_hw_set_in_dma(struct fimc_ctx *ctx); 698void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
678void fimc_hw_set_input_path(struct fimc_ctx *ctx); 699void fimc_hw_set_input_path(struct fimc_ctx *ctx);
679void fimc_hw_set_output_path(struct fimc_ctx *ctx); 700void fimc_hw_set_output_path(struct fimc_ctx *ctx);
@@ -695,6 +716,7 @@ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
695int fimc_ctrls_create(struct fimc_ctx *ctx); 716int fimc_ctrls_create(struct fimc_ctx *ctx);
696void fimc_ctrls_delete(struct fimc_ctx *ctx); 717void fimc_ctrls_delete(struct fimc_ctx *ctx);
697void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); 718void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
719void fimc_alpha_ctrl_update(struct fimc_ctx *ctx);
698int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); 720int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
699void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, 721void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
700 struct v4l2_pix_format_mplane *pix); 722 struct v4l2_pix_format_mplane *pix);
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 44f5c2d1920b..15466d0529c1 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -117,7 +117,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
117 S5P_CITRGFMT_VSIZE_MASK); 117 S5P_CITRGFMT_VSIZE_MASK);
118 118
119 switch (frame->fmt->color) { 119 switch (frame->fmt->color) {
120 case S5P_FIMC_RGB565...S5P_FIMC_RGB888: 120 case S5P_FIMC_RGB444...S5P_FIMC_RGB888:
121 cfg |= S5P_CITRGFMT_RGB; 121 cfg |= S5P_CITRGFMT_RGB;
122 break; 122 break;
123 case S5P_FIMC_YCBCR420: 123 case S5P_FIMC_YCBCR420:
@@ -175,6 +175,7 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
175 struct fimc_dev *dev = ctx->fimc_dev; 175 struct fimc_dev *dev = ctx->fimc_dev;
176 struct fimc_frame *frame = &ctx->d_frame; 176 struct fimc_frame *frame = &ctx->d_frame;
177 struct fimc_dma_offset *offset = &frame->dma_offset; 177 struct fimc_dma_offset *offset = &frame->dma_offset;
178 struct fimc_fmt *fmt = frame->fmt;
178 179
179 /* Set the input dma offsets. */ 180 /* Set the input dma offsets. */
180 cfg = 0; 181 cfg = 0;
@@ -198,15 +199,22 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
198 cfg = readl(dev->regs + S5P_CIOCTRL); 199 cfg = readl(dev->regs + S5P_CIOCTRL);
199 200
200 cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | 201 cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
201 S5P_CIOCTRL_YCBCR_PLANE_MASK); 202 S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
202 203
203 if (frame->fmt->colplanes == 1) 204 if (fmt->colplanes == 1)
204 cfg |= ctx->out_order_1p; 205 cfg |= ctx->out_order_1p;
205 else if (frame->fmt->colplanes == 2) 206 else if (fmt->colplanes == 2)
206 cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; 207 cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
207 else if (frame->fmt->colplanes == 3) 208 else if (fmt->colplanes == 3)
208 cfg |= S5P_CIOCTRL_YCBCR_3PLANE; 209 cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
209 210
211 if (fmt->color == S5P_FIMC_RGB565)
212 cfg |= S5P_CIOCTRL_RGB565;
213 else if (fmt->color == S5P_FIMC_RGB555)
214 cfg |= S5P_CIOCTRL_ARGB1555;
215 else if (fmt->color == S5P_FIMC_RGB444)
216 cfg |= S5P_CIOCTRL_ARGB4444;
217
210 writel(cfg, dev->regs + S5P_CIOCTRL); 218 writel(cfg, dev->regs + S5P_CIOCTRL);
211} 219}
212 220
@@ -278,22 +286,28 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
278 if (sc->copy_mode) 286 if (sc->copy_mode)
279 cfg |= S5P_CISCCTRL_ONE2ONE; 287 cfg |= S5P_CISCCTRL_ONE2ONE;
280 288
281
282 if (ctx->in_path == FIMC_DMA) { 289 if (ctx->in_path == FIMC_DMA) {
283 if (src_frame->fmt->color == S5P_FIMC_RGB565) 290 switch (src_frame->fmt->color) {
291 case S5P_FIMC_RGB565:
284 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565; 292 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
285 else if (src_frame->fmt->color == S5P_FIMC_RGB666) 293 break;
294 case S5P_FIMC_RGB666:
286 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666; 295 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
287 else if (src_frame->fmt->color == S5P_FIMC_RGB888) 296 break;
297 case S5P_FIMC_RGB888:
288 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888; 298 cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
299 break;
300 }
289 } 301 }
290 302
291 if (ctx->out_path == FIMC_DMA) { 303 if (ctx->out_path == FIMC_DMA) {
292 if (dst_frame->fmt->color == S5P_FIMC_RGB565) 304 u32 color = dst_frame->fmt->color;
305
306 if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565)
293 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565; 307 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
294 else if (dst_frame->fmt->color == S5P_FIMC_RGB666) 308 else if (color == S5P_FIMC_RGB666)
295 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666; 309 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
296 else if (dst_frame->fmt->color == S5P_FIMC_RGB888) 310 else if (color == S5P_FIMC_RGB888)
297 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; 311 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
298 } else { 312 } else {
299 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; 313 cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
@@ -379,6 +393,21 @@ void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
379 writel(cfg, dev->regs + S5P_CIIMGEFF); 393 writel(cfg, dev->regs + S5P_CIIMGEFF);
380} 394}
381 395
396void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
397{
398 struct fimc_dev *dev = ctx->fimc_dev;
399 struct fimc_frame *frame = &ctx->d_frame;
400 u32 cfg;
401
402 if (!(frame->fmt->flags & FMT_HAS_ALPHA))
403 return;
404
405 cfg = readl(dev->regs + S5P_CIOCTRL);
406 cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
407 cfg |= (frame->alpha << 4);
408 writel(cfg, dev->regs + S5P_CIOCTRL);
409}
410
382static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) 411static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
383{ 412{
384 struct fimc_dev *dev = ctx->fimc_dev; 413 struct fimc_dev *dev = ctx->fimc_dev;
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
index 59d79bc2f58a..130335cf62fd 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.c
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -427,6 +427,23 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
427 return 0; 427 return 0;
428} 428}
429 429
430static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
431{
432 struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
433
434 format->colorspace = V4L2_COLORSPACE_JPEG;
435 format->code = s5pcsis_formats[0].code;
436 format->width = S5PCSIS_DEF_PIX_WIDTH;
437 format->height = S5PCSIS_DEF_PIX_HEIGHT;
438 format->field = V4L2_FIELD_NONE;
439
440 return 0;
441}
442
443static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = {
444 .open = s5pcsis_open,
445};
446
430static struct v4l2_subdev_core_ops s5pcsis_core_ops = { 447static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
431 .s_power = s5pcsis_s_power, 448 .s_power = s5pcsis_s_power,
432}; 449};
@@ -544,8 +561,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
544 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); 561 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
545 state->sd.owner = THIS_MODULE; 562 state->sd.owner = THIS_MODULE;
546 strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); 563 strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
564 state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
547 state->csis_fmt = &s5pcsis_formats[0]; 565 state->csis_fmt = &s5pcsis_formats[0];
548 566
567 state->format.code = s5pcsis_formats[0].code;
568 state->format.width = S5PCSIS_DEF_PIX_WIDTH;
569 state->format.height = S5PCSIS_DEF_PIX_HEIGHT;
570
549 state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 571 state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
550 state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 572 state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
551 ret = media_entity_init(&state->sd.entity, 573 ret = media_entity_init(&state->sd.entity,
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h
index f5691336dd5c..2709286396e1 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.h
+++ b/drivers/media/video/s5p-fimc/mipi-csis.h
@@ -19,4 +19,7 @@
19#define CSIS_PAD_SOURCE 1 19#define CSIS_PAD_SOURCE 1
20#define CSIS_PADS_NUM 2 20#define CSIS_PADS_NUM 2
21 21
22#define S5PCSIS_DEF_PIX_WIDTH 640
23#define S5PCSIS_DEF_PIX_HEIGHT 480
24
22#endif 25#endif
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
index c8e3b94bd91d..c7a5bc51d571 100644
--- a/drivers/media/video/s5p-fimc/regs-fimc.h
+++ b/drivers/media/video/s5p-fimc/regs-fimc.h
@@ -107,6 +107,11 @@
107#define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3) 107#define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3)
108#define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3) 108#define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3)
109#define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) 109#define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
110#define S5P_CIOCTRL_ALPHA_OUT_MASK (0xff << 4)
111#define S5P_CIOCTRL_RGB16FMT_MASK (3 << 16)
112#define S5P_CIOCTRL_RGB565 (0 << 16)
113#define S5P_CIOCTRL_ARGB1555 (1 << 16)
114#define S5P_CIOCTRL_ARGB4444 (2 << 16)
110#define S5P_CIOCTRL_ORDER2P_SHIFT (24) 115#define S5P_CIOCTRL_ORDER2P_SHIFT (24)
111#define S5P_CIOCTRL_ORDER2P_MASK (3 << 24) 116#define S5P_CIOCTRL_ORDER2P_MASK (3 << 24)
112#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24) 117#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)