diff options
Diffstat (limited to 'drivers/media/video/mx3_camera.c')
-rw-r--r-- | drivers/media/video/mx3_camera.c | 114 |
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 | ||
547 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, | 547 | static 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 | ||
729 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, | 728 | static 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 | ||
755 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | 749 | static 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 | */ | ||
787 | static 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 | */ | ||
789 | static int mx3_camera_set_crop(struct soc_camera_device *icd, | 799 | static 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 | ||
812 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | 853 | static 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 | ||