aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mx3_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-08-25 10:50:46 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:19:17 -0400
commit6a6c8786725c0b3d143674effa8b772f47b1c189 (patch)
tree8bb76c5dcbd579f13e876bd1a0bb56bee4bcebdd /drivers/media/video/mx3_camera.c
parent0166b74374cae3fa8bff0caef726a3d960a9a50a (diff)
V4L/DVB (12534): soc-camera: V4L2 API compliant scaling (S_FMT) and cropping (S_CROP)
The initial soc-camera scaling and cropping implementation turned out to be incompliant with the V4L2 API, e.g., it expected the user to specify cropping in output window pixels, instead of input window pixels. This patch converts the soc-camera core and all drivers to comply with the standard. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mx3_camera.c')
-rw-r--r--drivers/media/video/mx3_camera.c114
1 files changed, 77 insertions, 37 deletions
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index d5b51e9900bb..dff2e5e2d8c6 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -220,7 +220,7 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
220 if (!mx3_cam->idmac_channel[0]) 220 if (!mx3_cam->idmac_channel[0])
221 return -EINVAL; 221 return -EINVAL;
222 222
223 *size = icd->rect_current.width * icd->rect_current.height * bpp; 223 *size = icd->user_width * icd->user_height * bpp;
224 224
225 if (!*count) 225 if (!*count)
226 *count = 32; 226 *count = 32;
@@ -241,7 +241,7 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
241 struct mx3_camera_buffer *buf = 241 struct mx3_camera_buffer *buf =
242 container_of(vb, struct mx3_camera_buffer, vb); 242 container_of(vb, struct mx3_camera_buffer, vb);
243 /* current_fmt _must_ always be set */ 243 /* current_fmt _must_ always be set */
244 size_t new_size = icd->rect_current.width * icd->rect_current.height * 244 size_t new_size = icd->user_width * icd->user_height *
245 ((icd->current_fmt->depth + 7) >> 3); 245 ((icd->current_fmt->depth + 7) >> 3);
246 int ret; 246 int ret;
247 247
@@ -251,12 +251,12 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq,
251 */ 251 */
252 252
253 if (buf->fmt != icd->current_fmt || 253 if (buf->fmt != icd->current_fmt ||
254 vb->width != icd->rect_current.width || 254 vb->width != icd->user_width ||
255 vb->height != icd->rect_current.height || 255 vb->height != icd->user_height ||
256 vb->field != field) { 256 vb->field != field) {
257 buf->fmt = icd->current_fmt; 257 buf->fmt = icd->current_fmt;
258 vb->width = icd->rect_current.width; 258 vb->width = icd->user_width;
259 vb->height = icd->rect_current.height; 259 vb->height = icd->user_height;
260 vb->field = field; 260 vb->field = field;
261 if (vb->state != VIDEOBUF_NEEDS_INIT) 261 if (vb->state != VIDEOBUF_NEEDS_INIT)
262 free_buffer(vq, buf); 262 free_buffer(vq, buf);
@@ -354,9 +354,9 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq,
354 354
355 /* This is the configuration of one sg-element */ 355 /* This is the configuration of one sg-element */
356 video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); 356 video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc);
357 video->out_width = icd->rect_current.width; 357 video->out_width = icd->user_width;
358 video->out_height = icd->rect_current.height; 358 video->out_height = icd->user_height;
359 video->out_stride = icd->rect_current.width; 359 video->out_stride = icd->user_width;
360 360
361#ifdef DEBUG 361#ifdef DEBUG
362 /* helps to see what DMA actually has written */ 362 /* helps to see what DMA actually has written */
@@ -541,7 +541,7 @@ static bool channel_change_requested(struct soc_camera_device *icd,
541 541
542 /* Do buffers have to be re-allocated or channel re-configured? */ 542 /* Do buffers have to be re-allocated or channel re-configured? */
543 return ichan && rect->width * rect->height > 543 return ichan && rect->width * rect->height >
544 icd->rect_current.width * icd->rect_current.height; 544 icd->user_width * icd->user_height;
545} 545}
546 546
547static int test_platform_param(struct mx3_camera_dev *mx3_cam, 547static int test_platform_param(struct mx3_camera_dev *mx3_cam,
@@ -589,8 +589,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
589 *flags |= SOCAM_DATAWIDTH_4; 589 *flags |= SOCAM_DATAWIDTH_4;
590 break; 590 break;
591 default: 591 default:
592 dev_info(mx3_cam->soc_host.v4l2_dev.dev, "Unsupported bus width %d\n", 592 dev_warn(mx3_cam->soc_host.v4l2_dev.dev,
593 buswidth); 593 "Unsupported bus width %d\n", buswidth);
594 return -EINVAL; 594 return -EINVAL;
595 } 595 }
596 596
@@ -605,8 +605,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
605 unsigned long bus_flags, camera_flags; 605 unsigned long bus_flags, camera_flags;
606 int ret = test_platform_param(mx3_cam, depth, &bus_flags); 606 int ret = test_platform_param(mx3_cam, depth, &bus_flags);
607 607
608 dev_dbg(icd->dev.parent, "requested bus width %d bit: %d\n", 608 dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret);
609 depth, ret);
610 609
611 if (ret < 0) 610 if (ret < 0)
612 return ret; 611 return ret;
@@ -727,13 +726,13 @@ passthrough:
727} 726}
728 727
729static void configure_geometry(struct mx3_camera_dev *mx3_cam, 728static void configure_geometry(struct mx3_camera_dev *mx3_cam,
730 struct v4l2_rect *rect) 729 unsigned int width, unsigned int height)
731{ 730{
732 u32 ctrl, width_field, height_field; 731 u32 ctrl, width_field, height_field;
733 732
734 /* Setup frame size - this cannot be changed on-the-fly... */ 733 /* Setup frame size - this cannot be changed on-the-fly... */
735 width_field = rect->width - 1; 734 width_field = width - 1;
736 height_field = rect->height - 1; 735 height_field = height - 1;
737 csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); 736 csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
738 737
739 csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); 738 csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
@@ -745,11 +744,6 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam,
745 ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; 744 ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
746 /* Sensor does the cropping */ 745 /* Sensor does the cropping */
747 csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); 746 csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
748
749 /*
750 * No need to free resources here if we fail, we'll see if we need to
751 * do this next time we are called
752 */
753} 747}
754 748
755static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) 749static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
@@ -786,6 +780,22 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
786 return 0; 780 return 0;
787} 781}
788 782
783/*
784 * FIXME: learn to use stride != width, then we can keep stride properly aligned
785 * and support arbitrary (even) widths.
786 */
787static inline void stride_align(__s32 *width)
788{
789 if (((*width + 7) & ~7) < 4096)
790 *width = (*width + 7) & ~7;
791 else
792 *width = *width & ~7;
793}
794
795/*
796 * As long as we don't implement host-side cropping and scaling, we can use
797 * default g_crop and cropcap from soc_camera.c
798 */
789static int mx3_camera_set_crop(struct soc_camera_device *icd, 799static int mx3_camera_set_crop(struct soc_camera_device *icd,
790 struct v4l2_crop *a) 800 struct v4l2_crop *a)
791{ 801{
@@ -793,20 +803,51 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
793 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 803 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
794 struct mx3_camera_dev *mx3_cam = ici->priv; 804 struct mx3_camera_dev *mx3_cam = ici->priv;
795 struct v4l2_subdev *sd = soc_camera_to_subdev(icd); 805 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
806 struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
807 struct v4l2_pix_format *pix = &f.fmt.pix;
808 int ret;
796 809
797 /* 810 soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
798 * We now know pixel formats and can decide upon DMA-channel(s) 811 soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
799 * So far only direct camera-to-memory is supported 812
800 */ 813 ret = v4l2_subdev_call(sd, video, s_crop, a);
801 if (channel_change_requested(icd, rect)) { 814 if (ret < 0)
802 int ret = acquire_dma_channel(mx3_cam); 815 return ret;
816
817 /* The capture device might have changed its output */
818 ret = v4l2_subdev_call(sd, video, g_fmt, &f);
819 if (ret < 0)
820 return ret;
821
822 if (pix->width & 7) {
823 /* Ouch! We can only handle 8-byte aligned width... */
824 stride_align(&pix->width);
825 ret = v4l2_subdev_call(sd, video, s_fmt, &f);
803 if (ret < 0) 826 if (ret < 0)
804 return ret; 827 return ret;
805 } 828 }
806 829
807 configure_geometry(mx3_cam, rect); 830 if (pix->width != icd->user_width || pix->height != icd->user_height) {
831 /*
832 * We now know pixel formats and can decide upon DMA-channel(s)
833 * So far only direct camera-to-memory is supported
834 */
835 if (channel_change_requested(icd, rect)) {
836 int ret = acquire_dma_channel(mx3_cam);
837 if (ret < 0)
838 return ret;
839 }
808 840
809 return v4l2_subdev_call(sd, video, s_crop, a); 841 configure_geometry(mx3_cam, pix->width, pix->height);
842 }
843
844 dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
845 pix->width, pix->height);
846
847 icd->user_width = pix->width;
848 icd->user_height = pix->height;
849
850 return ret;
810} 851}
811 852
812static int mx3_camera_set_fmt(struct soc_camera_device *icd, 853static int mx3_camera_set_fmt(struct soc_camera_device *icd,
@@ -817,12 +858,6 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
817 struct v4l2_subdev *sd = soc_camera_to_subdev(icd); 858 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
818 const struct soc_camera_format_xlate *xlate; 859 const struct soc_camera_format_xlate *xlate;
819 struct v4l2_pix_format *pix = &f->fmt.pix; 860 struct v4l2_pix_format *pix = &f->fmt.pix;
820 struct v4l2_rect rect = {
821 .left = icd->rect_current.left,
822 .top = icd->rect_current.top,
823 .width = pix->width,
824 .height = pix->height,
825 };
826 int ret; 861 int ret;
827 862
828 xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); 863 xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
@@ -832,6 +867,9 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
832 return -EINVAL; 867 return -EINVAL;
833 } 868 }
834 869
870 stride_align(&pix->width);
871 dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height);
872
835 ret = acquire_dma_channel(mx3_cam); 873 ret = acquire_dma_channel(mx3_cam);
836 if (ret < 0) 874 if (ret < 0)
837 return ret; 875 return ret;
@@ -842,7 +880,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
842 * mxc_v4l2_s_fmt() 880 * mxc_v4l2_s_fmt()
843 */ 881 */
844 882
845 configure_geometry(mx3_cam, &rect); 883 configure_geometry(mx3_cam, pix->width, pix->height);
846 884
847 ret = v4l2_subdev_call(sd, video, s_fmt, f); 885 ret = v4l2_subdev_call(sd, video, s_fmt, f);
848 if (!ret) { 886 if (!ret) {
@@ -850,6 +888,8 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
850 icd->current_fmt = xlate->host_fmt; 888 icd->current_fmt = xlate->host_fmt;
851 } 889 }
852 890
891 dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height);
892
853 return ret; 893 return ret;
854} 894}
855 895