aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mx3_camera.c
diff options
context:
space:
mode:
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