diff options
author | Javier Martin <javier.martin@vista-silicon.com> | 2012-02-07 05:14:42 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-03-08 07:41:56 -0500 |
commit | cdc9d6f191d81aa1b1b34db9d3a33f779f5c5ec7 (patch) | |
tree | 3223a3fa758c180fdd17e88b48c6c59506410d51 | |
parent | fb51cbdd3ec868b903bd706aa7db065c8c36bcd4 (diff) |
[media] media i.MX27 camera: improve discard buffer handling
The way discard buffer was previously handled lead
to possible races that made a buffer that was not
yet ready to be overwritten by new video data. This
is easily detected at 25fps just adding "#define DEBUG"
to enable the "memset" check and seeing how the image
is corrupted.
A new "discard" queue and two discard buffers have
been added to make them flow trough the pipeline
of queues and thus provide suitable event ordering.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/mx2_camera.c | 287 |
1 files changed, 161 insertions, 126 deletions
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 2e232092fc10..fc5ffe47c558 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c | |||
@@ -235,7 +235,8 @@ struct mx2_buffer { | |||
235 | struct list_head queue; | 235 | struct list_head queue; |
236 | enum mx2_buffer_state state; | 236 | enum mx2_buffer_state state; |
237 | 237 | ||
238 | int bufnum; | 238 | int bufnum; |
239 | bool discard; | ||
239 | }; | 240 | }; |
240 | 241 | ||
241 | struct mx2_camera_dev { | 242 | struct mx2_camera_dev { |
@@ -254,6 +255,7 @@ struct mx2_camera_dev { | |||
254 | 255 | ||
255 | struct list_head capture; | 256 | struct list_head capture; |
256 | struct list_head active_bufs; | 257 | struct list_head active_bufs; |
258 | struct list_head discard; | ||
257 | 259 | ||
258 | spinlock_t lock; | 260 | spinlock_t lock; |
259 | 261 | ||
@@ -264,6 +266,7 @@ struct mx2_camera_dev { | |||
264 | 266 | ||
265 | u32 csicr1; | 267 | u32 csicr1; |
266 | 268 | ||
269 | struct mx2_buffer buf_discard[2]; | ||
267 | void *discard_buffer; | 270 | void *discard_buffer; |
268 | dma_addr_t discard_buffer_dma; | 271 | dma_addr_t discard_buffer_dma; |
269 | size_t discard_size; | 272 | size_t discard_size; |
@@ -325,6 +328,29 @@ static struct mx2_fmt_cfg *mx27_emma_prp_get_format( | |||
325 | return &mx27_emma_prp_table[0]; | 328 | return &mx27_emma_prp_table[0]; |
326 | }; | 329 | }; |
327 | 330 | ||
331 | static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, | ||
332 | unsigned long phys, int bufnum) | ||
333 | { | ||
334 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
335 | |||
336 | if (prp->cfg.channel == 1) { | ||
337 | writel(phys, pcdev->base_emma + | ||
338 | PRP_DEST_RGB1_PTR + 4 * bufnum); | ||
339 | } else { | ||
340 | writel(phys, pcdev->base_emma + | ||
341 | PRP_DEST_Y_PTR - 0x14 * bufnum); | ||
342 | if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { | ||
343 | u32 imgsize = pcdev->icd->user_height * | ||
344 | pcdev->icd->user_width; | ||
345 | |||
346 | writel(phys + imgsize, pcdev->base_emma + | ||
347 | PRP_DEST_CB_PTR - 0x14 * bufnum); | ||
348 | writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + | ||
349 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | |||
328 | static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) | 354 | static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) |
329 | { | 355 | { |
330 | unsigned long flags; | 356 | unsigned long flags; |
@@ -373,7 +399,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) | |||
373 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | 399 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); |
374 | 400 | ||
375 | pcdev->icd = icd; | 401 | pcdev->icd = icd; |
376 | pcdev->frame_count = -1; | 402 | pcdev->frame_count = 0; |
377 | 403 | ||
378 | dev_info(icd->parent, "Camera driver attached to camera %d\n", | 404 | dev_info(icd->parent, "Camera driver attached to camera %d\n", |
379 | icd->devnum); | 405 | icd->devnum); |
@@ -393,13 +419,6 @@ static void mx2_camera_remove_device(struct soc_camera_device *icd) | |||
393 | 419 | ||
394 | mx2_camera_deactivate(pcdev); | 420 | mx2_camera_deactivate(pcdev); |
395 | 421 | ||
396 | if (pcdev->discard_buffer) { | ||
397 | dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size, | ||
398 | pcdev->discard_buffer, | ||
399 | pcdev->discard_buffer_dma); | ||
400 | pcdev->discard_buffer = NULL; | ||
401 | } | ||
402 | |||
403 | pcdev->icd = NULL; | 422 | pcdev->icd = NULL; |
404 | } | 423 | } |
405 | 424 | ||
@@ -628,7 +647,6 @@ static void mx2_videobuf_release(struct vb2_buffer *vb) | |||
628 | */ | 647 | */ |
629 | 648 | ||
630 | spin_lock_irqsave(&pcdev->lock, flags); | 649 | spin_lock_irqsave(&pcdev->lock, flags); |
631 | list_del_init(&buf->queue); | ||
632 | if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { | 650 | if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) { |
633 | if (pcdev->fb1_active == buf) { | 651 | if (pcdev->fb1_active == buf) { |
634 | pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; | 652 | pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN; |
@@ -644,6 +662,34 @@ static void mx2_videobuf_release(struct vb2_buffer *vb) | |||
644 | spin_unlock_irqrestore(&pcdev->lock, flags); | 662 | spin_unlock_irqrestore(&pcdev->lock, flags); |
645 | } | 663 | } |
646 | 664 | ||
665 | static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | ||
666 | int bytesperline) | ||
667 | { | ||
668 | struct soc_camera_host *ici = | ||
669 | to_soc_camera_host(icd->parent); | ||
670 | struct mx2_camera_dev *pcdev = ici->priv; | ||
671 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
672 | |||
673 | writel((icd->user_width << 16) | icd->user_height, | ||
674 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
675 | writel(prp->cfg.src_pixel, | ||
676 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | ||
677 | if (prp->cfg.channel == 1) { | ||
678 | writel((icd->user_width << 16) | icd->user_height, | ||
679 | pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); | ||
680 | writel(bytesperline, | ||
681 | pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); | ||
682 | writel(prp->cfg.ch1_pixel, | ||
683 | pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); | ||
684 | } else { /* channel 2 */ | ||
685 | writel((icd->user_width << 16) | icd->user_height, | ||
686 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | ||
687 | } | ||
688 | |||
689 | /* Enable interrupts */ | ||
690 | writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); | ||
691 | } | ||
692 | |||
647 | static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) | 693 | static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) |
648 | { | 694 | { |
649 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | 695 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); |
@@ -651,6 +697,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) | |||
651 | to_soc_camera_host(icd->parent); | 697 | to_soc_camera_host(icd->parent); |
652 | struct mx2_camera_dev *pcdev = ici->priv; | 698 | struct mx2_camera_dev *pcdev = ici->priv; |
653 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | 699 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; |
700 | struct vb2_buffer *vb; | ||
701 | struct mx2_buffer *buf; | ||
702 | unsigned long phys; | ||
703 | int bytesperline; | ||
654 | 704 | ||
655 | if (cpu_is_mx27()) { | 705 | if (cpu_is_mx27()) { |
656 | unsigned long flags; | 706 | unsigned long flags; |
@@ -658,6 +708,56 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) | |||
658 | return -EINVAL; | 708 | return -EINVAL; |
659 | 709 | ||
660 | spin_lock_irqsave(&pcdev->lock, flags); | 710 | spin_lock_irqsave(&pcdev->lock, flags); |
711 | |||
712 | buf = list_entry(pcdev->capture.next, | ||
713 | struct mx2_buffer, queue); | ||
714 | buf->bufnum = 0; | ||
715 | vb = &buf->vb; | ||
716 | buf->state = MX2_STATE_ACTIVE; | ||
717 | |||
718 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
719 | mx27_update_emma_buf(pcdev, phys, buf->bufnum); | ||
720 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
721 | |||
722 | buf = list_entry(pcdev->capture.next, | ||
723 | struct mx2_buffer, queue); | ||
724 | buf->bufnum = 1; | ||
725 | vb = &buf->vb; | ||
726 | buf->state = MX2_STATE_ACTIVE; | ||
727 | |||
728 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
729 | mx27_update_emma_buf(pcdev, phys, buf->bufnum); | ||
730 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
731 | |||
732 | bytesperline = soc_mbus_bytes_per_line(icd->user_width, | ||
733 | icd->current_fmt->host_fmt); | ||
734 | if (bytesperline < 0) | ||
735 | return bytesperline; | ||
736 | |||
737 | /* | ||
738 | * I didn't manage to properly enable/disable the prp | ||
739 | * on a per frame basis during running transfers, | ||
740 | * thus we allocate a buffer here and use it to | ||
741 | * discard frames when no buffer is available. | ||
742 | * Feel free to work on this ;) | ||
743 | */ | ||
744 | pcdev->discard_size = icd->user_height * bytesperline; | ||
745 | pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, | ||
746 | pcdev->discard_size, &pcdev->discard_buffer_dma, | ||
747 | GFP_KERNEL); | ||
748 | if (!pcdev->discard_buffer) | ||
749 | return -ENOMEM; | ||
750 | |||
751 | pcdev->buf_discard[0].discard = true; | ||
752 | list_add_tail(&pcdev->buf_discard[0].queue, | ||
753 | &pcdev->discard); | ||
754 | |||
755 | pcdev->buf_discard[1].discard = true; | ||
756 | list_add_tail(&pcdev->buf_discard[1].queue, | ||
757 | &pcdev->discard); | ||
758 | |||
759 | mx27_camera_emma_buf_init(icd, bytesperline); | ||
760 | |||
661 | if (prp->cfg.channel == 1) { | 761 | if (prp->cfg.channel == 1) { |
662 | writel(PRP_CNTL_CH1EN | | 762 | writel(PRP_CNTL_CH1EN | |
663 | PRP_CNTL_CSIEN | | 763 | PRP_CNTL_CSIEN | |
@@ -692,10 +792,12 @@ static int mx2_stop_streaming(struct vb2_queue *q) | |||
692 | struct mx2_camera_dev *pcdev = ici->priv; | 792 | struct mx2_camera_dev *pcdev = ici->priv; |
693 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | 793 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; |
694 | unsigned long flags; | 794 | unsigned long flags; |
795 | void *b; | ||
695 | u32 cntl; | 796 | u32 cntl; |
696 | 797 | ||
697 | spin_lock_irqsave(&pcdev->lock, flags); | ||
698 | if (cpu_is_mx27()) { | 798 | if (cpu_is_mx27()) { |
799 | spin_lock_irqsave(&pcdev->lock, flags); | ||
800 | |||
699 | cntl = readl(pcdev->base_emma + PRP_CNTL); | 801 | cntl = readl(pcdev->base_emma + PRP_CNTL); |
700 | if (prp->cfg.channel == 1) { | 802 | if (prp->cfg.channel == 1) { |
701 | writel(cntl & ~PRP_CNTL_CH1EN, | 803 | writel(cntl & ~PRP_CNTL_CH1EN, |
@@ -704,8 +806,18 @@ static int mx2_stop_streaming(struct vb2_queue *q) | |||
704 | writel(cntl & ~PRP_CNTL_CH2EN, | 806 | writel(cntl & ~PRP_CNTL_CH2EN, |
705 | pcdev->base_emma + PRP_CNTL); | 807 | pcdev->base_emma + PRP_CNTL); |
706 | } | 808 | } |
809 | INIT_LIST_HEAD(&pcdev->capture); | ||
810 | INIT_LIST_HEAD(&pcdev->active_bufs); | ||
811 | INIT_LIST_HEAD(&pcdev->discard); | ||
812 | |||
813 | b = pcdev->discard_buffer; | ||
814 | pcdev->discard_buffer = NULL; | ||
815 | |||
816 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
817 | |||
818 | dma_free_coherent(ici->v4l2_dev.dev, | ||
819 | pcdev->discard_size, b, pcdev->discard_buffer_dma); | ||
707 | } | 820 | } |
708 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
709 | 821 | ||
710 | return 0; | 822 | return 0; |
711 | } | 823 | } |
@@ -759,63 +871,6 @@ static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | |||
759 | return -ETIMEDOUT; | 871 | return -ETIMEDOUT; |
760 | } | 872 | } |
761 | 873 | ||
762 | static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | ||
763 | int bytesperline) | ||
764 | { | ||
765 | struct soc_camera_host *ici = | ||
766 | to_soc_camera_host(icd->parent); | ||
767 | struct mx2_camera_dev *pcdev = ici->priv; | ||
768 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
769 | u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; | ||
770 | |||
771 | if (prp->cfg.channel == 1) { | ||
772 | writel(pcdev->discard_buffer_dma, | ||
773 | pcdev->base_emma + PRP_DEST_RGB1_PTR); | ||
774 | writel(pcdev->discard_buffer_dma, | ||
775 | pcdev->base_emma + PRP_DEST_RGB2_PTR); | ||
776 | |||
777 | writel((icd->user_width << 16) | icd->user_height, | ||
778 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
779 | writel((icd->user_width << 16) | icd->user_height, | ||
780 | pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); | ||
781 | writel(bytesperline, | ||
782 | pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); | ||
783 | writel(prp->cfg.src_pixel, | ||
784 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | ||
785 | writel(prp->cfg.ch1_pixel, | ||
786 | pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); | ||
787 | } else { /* channel 2 */ | ||
788 | writel(pcdev->discard_buffer_dma, | ||
789 | pcdev->base_emma + PRP_DEST_Y_PTR); | ||
790 | writel(pcdev->discard_buffer_dma, | ||
791 | pcdev->base_emma + PRP_SOURCE_Y_PTR); | ||
792 | |||
793 | if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { | ||
794 | writel(pcdev->discard_buffer_dma + imgsize, | ||
795 | pcdev->base_emma + PRP_DEST_CB_PTR); | ||
796 | writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), | ||
797 | pcdev->base_emma + PRP_DEST_CR_PTR); | ||
798 | writel(pcdev->discard_buffer_dma + imgsize, | ||
799 | pcdev->base_emma + PRP_SOURCE_CB_PTR); | ||
800 | writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), | ||
801 | pcdev->base_emma + PRP_SOURCE_CR_PTR); | ||
802 | } | ||
803 | |||
804 | writel((icd->user_width << 16) | icd->user_height, | ||
805 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
806 | |||
807 | writel((icd->user_width << 16) | icd->user_height, | ||
808 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | ||
809 | |||
810 | writel(prp->cfg.src_pixel, | ||
811 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | ||
812 | |||
813 | } | ||
814 | |||
815 | /* Enable interrupts */ | ||
816 | writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); | ||
817 | } | ||
818 | |||
819 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | 874 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd) |
820 | { | 875 | { |
821 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 876 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
@@ -898,27 +953,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | |||
898 | ret = mx27_camera_emma_prp_reset(pcdev); | 953 | ret = mx27_camera_emma_prp_reset(pcdev); |
899 | if (ret) | 954 | if (ret) |
900 | return ret; | 955 | return ret; |
901 | |||
902 | if (pcdev->discard_buffer) | ||
903 | dma_free_coherent(ici->v4l2_dev.dev, | ||
904 | pcdev->discard_size, pcdev->discard_buffer, | ||
905 | pcdev->discard_buffer_dma); | ||
906 | |||
907 | /* | ||
908 | * I didn't manage to properly enable/disable the prp | ||
909 | * on a per frame basis during running transfers, | ||
910 | * thus we allocate a buffer here and use it to | ||
911 | * discard frames when no buffer is available. | ||
912 | * Feel free to work on this ;) | ||
913 | */ | ||
914 | pcdev->discard_size = icd->user_height * bytesperline; | ||
915 | pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, | ||
916 | pcdev->discard_size, &pcdev->discard_buffer_dma, | ||
917 | GFP_KERNEL); | ||
918 | if (!pcdev->discard_buffer) | ||
919 | return -ENOMEM; | ||
920 | |||
921 | mx27_camera_emma_buf_init(icd, bytesperline); | ||
922 | } else if (cpu_is_mx25()) { | 956 | } else if (cpu_is_mx25()) { |
923 | writel((bytesperline * icd->user_height) >> 2, | 957 | writel((bytesperline * icd->user_height) >> 2, |
924 | pcdev->base_csi + CSIRXCNT); | 958 | pcdev->base_csi + CSIRXCNT); |
@@ -1166,18 +1200,23 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = { | |||
1166 | static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, | 1200 | static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, |
1167 | int bufnum) | 1201 | int bufnum) |
1168 | { | 1202 | { |
1169 | u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; | ||
1170 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | 1203 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; |
1171 | struct mx2_buffer *buf; | 1204 | struct mx2_buffer *buf; |
1172 | struct vb2_buffer *vb; | 1205 | struct vb2_buffer *vb; |
1173 | unsigned long phys; | 1206 | unsigned long phys; |
1174 | 1207 | ||
1175 | if (!list_empty(&pcdev->active_bufs)) { | 1208 | buf = list_entry(pcdev->active_bufs.next, |
1176 | buf = list_entry(pcdev->active_bufs.next, | 1209 | struct mx2_buffer, queue); |
1177 | struct mx2_buffer, queue); | ||
1178 | 1210 | ||
1179 | BUG_ON(buf->bufnum != bufnum); | 1211 | BUG_ON(buf->bufnum != bufnum); |
1180 | 1212 | ||
1213 | if (buf->discard) { | ||
1214 | /* | ||
1215 | * Discard buffer must not be returned to user space. | ||
1216 | * Just return it to the discard queue. | ||
1217 | */ | ||
1218 | list_move_tail(pcdev->active_bufs.next, &pcdev->discard); | ||
1219 | } else { | ||
1181 | vb = &buf->vb; | 1220 | vb = &buf->vb; |
1182 | #ifdef DEBUG | 1221 | #ifdef DEBUG |
1183 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | 1222 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); |
@@ -1212,29 +1251,25 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, | |||
1212 | pcdev->frame_count++; | 1251 | pcdev->frame_count++; |
1213 | 1252 | ||
1214 | if (list_empty(&pcdev->capture)) { | 1253 | if (list_empty(&pcdev->capture)) { |
1215 | if (prp->cfg.channel == 1) { | 1254 | if (list_empty(&pcdev->discard)) { |
1216 | writel(pcdev->discard_buffer_dma, pcdev->base_emma + | 1255 | dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", |
1217 | PRP_DEST_RGB1_PTR + 4 * bufnum); | 1256 | __func__); |
1218 | } else { | 1257 | return; |
1219 | writel(pcdev->discard_buffer_dma, pcdev->base_emma + | ||
1220 | PRP_DEST_Y_PTR - | ||
1221 | 0x14 * bufnum); | ||
1222 | if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { | ||
1223 | writel(pcdev->discard_buffer_dma + imgsize, | ||
1224 | pcdev->base_emma + PRP_DEST_CB_PTR - | ||
1225 | 0x14 * bufnum); | ||
1226 | writel(pcdev->discard_buffer_dma + | ||
1227 | ((5 * imgsize) / 4), pcdev->base_emma + | ||
1228 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
1229 | } | ||
1230 | } | 1258 | } |
1259 | |||
1260 | buf = list_entry(pcdev->discard.next, | ||
1261 | struct mx2_buffer, queue); | ||
1262 | buf->bufnum = bufnum; | ||
1263 | |||
1264 | list_move_tail(pcdev->discard.next, &pcdev->active_bufs); | ||
1265 | mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); | ||
1231 | return; | 1266 | return; |
1232 | } | 1267 | } |
1233 | 1268 | ||
1234 | buf = list_entry(pcdev->capture.next, | 1269 | buf = list_entry(pcdev->capture.next, |
1235 | struct mx2_buffer, queue); | 1270 | struct mx2_buffer, queue); |
1236 | 1271 | ||
1237 | buf->bufnum = !bufnum; | 1272 | buf->bufnum = bufnum; |
1238 | 1273 | ||
1239 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | 1274 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); |
1240 | 1275 | ||
@@ -1242,18 +1277,7 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, | |||
1242 | buf->state = MX2_STATE_ACTIVE; | 1277 | buf->state = MX2_STATE_ACTIVE; |
1243 | 1278 | ||
1244 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | 1279 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); |
1245 | if (prp->cfg.channel == 1) { | 1280 | mx27_update_emma_buf(pcdev, phys, bufnum); |
1246 | writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); | ||
1247 | } else { | ||
1248 | writel(phys, pcdev->base_emma + | ||
1249 | PRP_DEST_Y_PTR - 0x14 * bufnum); | ||
1250 | if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { | ||
1251 | writel(phys + imgsize, pcdev->base_emma + | ||
1252 | PRP_DEST_CB_PTR - 0x14 * bufnum); | ||
1253 | writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + | ||
1254 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
1255 | } | ||
1256 | } | ||
1257 | } | 1281 | } |
1258 | 1282 | ||
1259 | static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | 1283 | static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) |
@@ -1261,6 +1285,15 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | |||
1261 | struct mx2_camera_dev *pcdev = data; | 1285 | struct mx2_camera_dev *pcdev = data; |
1262 | unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); | 1286 | unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); |
1263 | struct mx2_buffer *buf; | 1287 | struct mx2_buffer *buf; |
1288 | unsigned long flags; | ||
1289 | |||
1290 | spin_lock_irqsave(&pcdev->lock, flags); | ||
1291 | |||
1292 | if (list_empty(&pcdev->active_bufs)) { | ||
1293 | dev_warn(pcdev->dev, "%s: called while active list is empty\n", | ||
1294 | __func__); | ||
1295 | goto irq_ok; | ||
1296 | } | ||
1264 | 1297 | ||
1265 | if (status & (1 << 7)) { /* overflow */ | 1298 | if (status & (1 << 7)) { /* overflow */ |
1266 | u32 cntl; | 1299 | u32 cntl; |
@@ -1277,9 +1310,8 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | |||
1277 | pcdev->base_emma + PRP_CNTL); | 1310 | pcdev->base_emma + PRP_CNTL); |
1278 | writel(cntl, pcdev->base_emma + PRP_CNTL); | 1311 | writel(cntl, pcdev->base_emma + PRP_CNTL); |
1279 | } | 1312 | } |
1280 | if ((((status & (3 << 5)) == (3 << 5)) || | 1313 | if (((status & (3 << 5)) == (3 << 5)) || |
1281 | ((status & (3 << 3)) == (3 << 3))) | 1314 | ((status & (3 << 3)) == (3 << 3))) { |
1282 | && !list_empty(&pcdev->active_bufs)) { | ||
1283 | /* | 1315 | /* |
1284 | * Both buffers have triggered, process the one we're expecting | 1316 | * Both buffers have triggered, process the one we're expecting |
1285 | * to first | 1317 | * to first |
@@ -1294,6 +1326,8 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | |||
1294 | if ((status & (1 << 5)) || (status & (1 << 3))) | 1326 | if ((status & (1 << 5)) || (status & (1 << 3))) |
1295 | mx27_camera_frame_done_emma(pcdev, 1); | 1327 | mx27_camera_frame_done_emma(pcdev, 1); |
1296 | 1328 | ||
1329 | irq_ok: | ||
1330 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
1297 | writel(status, pcdev->base_emma + PRP_INTRSTATUS); | 1331 | writel(status, pcdev->base_emma + PRP_INTRSTATUS); |
1298 | 1332 | ||
1299 | return IRQ_HANDLED; | 1333 | return IRQ_HANDLED; |
@@ -1403,6 +1437,7 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev) | |||
1403 | 1437 | ||
1404 | INIT_LIST_HEAD(&pcdev->capture); | 1438 | INIT_LIST_HEAD(&pcdev->capture); |
1405 | INIT_LIST_HEAD(&pcdev->active_bufs); | 1439 | INIT_LIST_HEAD(&pcdev->active_bufs); |
1440 | INIT_LIST_HEAD(&pcdev->discard); | ||
1406 | spin_lock_init(&pcdev->lock); | 1441 | spin_lock_init(&pcdev->lock); |
1407 | 1442 | ||
1408 | /* | 1443 | /* |