diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2009-03-31 02:44:21 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-04-06 20:43:45 -0400 |
commit | 256b02332a0ba1d7382d736d776e605be63ded17 (patch) | |
tree | 10f661d4bd82e23272379ecdd6acd5ed4a23ef98 /drivers/media/video/pxa_camera.c | |
parent | 37f5aefd537d5f98b3fa9726362effeccf1d2161 (diff) |
V4L/DVB (11321): pxa_camera: Redesign DMA handling
The DMA transfers in pxa_camera showed some weaknesses in
multiple queued buffers context :
- poll/select problem
The bug shows up with capture_example tool from v4l2 hg
tree. The process just "stalls" on a "select timeout".
- multiple buffers DMA starting
When multiple buffers were queued, the DMA channels were
always started right away. This is not optimal, as a
special case appears when the first EOF was not yet
reached, and the DMA channels were prematurely started.
- Maintainability
DMA code was a bit obfuscated. Rationalize the code to be
easily maintainable by anyone.
- DMA hot chaining
DMA is not stopped anymore to queue a buffer, the buffer
is queued with DMA running. As a tribute, a corner case
exists where chaining happens while DMA finishes the
chain, and the capture is restarted to deal with the
missed link buffer.
This patch attemps to address these issues / improvements.
create mode 100644 Documentation/video4linux/pxa_camera.txt
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 319 |
1 files changed, 191 insertions, 128 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 07f792b659d9..a2f98ec14d9a 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -369,6 +369,10 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
369 | pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset; | 369 | pxa_dma->sg_cpu[i].dtadr = sg_dma_address(sg) + offset; |
370 | pxa_dma->sg_cpu[i].dcmd = | 370 | pxa_dma->sg_cpu[i].dcmd = |
371 | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; | 371 | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len; |
372 | #ifdef DEBUG | ||
373 | if (!i) | ||
374 | pxa_dma->sg_cpu[i].dcmd |= DCMD_STARTIRQEN; | ||
375 | #endif | ||
372 | pxa_dma->sg_cpu[i].ddadr = | 376 | pxa_dma->sg_cpu[i].ddadr = |
373 | pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); | 377 | pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); |
374 | 378 | ||
@@ -381,8 +385,8 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
381 | break; | 385 | break; |
382 | } | 386 | } |
383 | 387 | ||
384 | pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP; | 388 | pxa_dma->sg_cpu[sglen].ddadr = DDADR_STOP; |
385 | pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN; | 389 | pxa_dma->sg_cpu[sglen].dcmd = DCMD_FLOWSRC | DCMD_BURST8 | DCMD_ENDIRQEN; |
386 | 390 | ||
387 | /* | 391 | /* |
388 | * Handle 1 special case : | 392 | * Handle 1 special case : |
@@ -402,6 +406,20 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, | |||
402 | return 0; | 406 | return 0; |
403 | } | 407 | } |
404 | 408 | ||
409 | static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev, | ||
410 | struct pxa_buffer *buf) | ||
411 | { | ||
412 | buf->active_dma = DMA_Y; | ||
413 | if (pcdev->channels == 3) | ||
414 | buf->active_dma |= DMA_U | DMA_V; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Please check the DMA prepared buffer structure in : | ||
419 | * Documentation/video4linux/pxa_camera.txt | ||
420 | * Please check also in pxa_camera_check_link_miss() to understand why DMA chain | ||
421 | * modification while DMA chain is running will work anyway. | ||
422 | */ | ||
405 | static int pxa_videobuf_prepare(struct videobuf_queue *vq, | 423 | static int pxa_videobuf_prepare(struct videobuf_queue *vq, |
406 | struct videobuf_buffer *vb, enum v4l2_field field) | 424 | struct videobuf_buffer *vb, enum v4l2_field field) |
407 | { | 425 | { |
@@ -499,9 +517,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
499 | } | 517 | } |
500 | 518 | ||
501 | buf->inwork = 0; | 519 | buf->inwork = 0; |
502 | buf->active_dma = DMA_Y; | 520 | pxa_videobuf_set_actdma(pcdev, buf); |
503 | if (pcdev->channels == 3) | ||
504 | buf->active_dma |= DMA_U | DMA_V; | ||
505 | 521 | ||
506 | return 0; | 522 | return 0; |
507 | 523 | ||
@@ -518,6 +534,99 @@ out: | |||
518 | return ret; | 534 | return ret; |
519 | } | 535 | } |
520 | 536 | ||
537 | /** | ||
538 | * pxa_dma_start_channels - start DMA channel for active buffer | ||
539 | * @pcdev: pxa camera device | ||
540 | * | ||
541 | * Initialize DMA channels to the beginning of the active video buffer, and | ||
542 | * start these channels. | ||
543 | */ | ||
544 | static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) | ||
545 | { | ||
546 | int i; | ||
547 | struct pxa_buffer *active; | ||
548 | |||
549 | active = pcdev->active; | ||
550 | |||
551 | for (i = 0; i < pcdev->channels; i++) { | ||
552 | dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__, | ||
553 | i, active->dmas[i].sg_dma); | ||
554 | DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; | ||
555 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) | ||
560 | { | ||
561 | int i; | ||
562 | |||
563 | for (i = 0; i < pcdev->channels; i++) { | ||
564 | dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i); | ||
565 | DCSR(pcdev->dma_chans[i]) = 0; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | static void pxa_dma_update_sg_tail(struct pxa_camera_dev *pcdev, | ||
570 | struct pxa_buffer *buf) | ||
571 | { | ||
572 | int i; | ||
573 | |||
574 | for (i = 0; i < pcdev->channels; i++) | ||
575 | pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen; | ||
576 | } | ||
577 | |||
578 | static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev, | ||
579 | struct pxa_buffer *buf) | ||
580 | { | ||
581 | int i; | ||
582 | struct pxa_dma_desc *buf_last_desc; | ||
583 | |||
584 | for (i = 0; i < pcdev->channels; i++) { | ||
585 | buf_last_desc = buf->dmas[i].sg_cpu + buf->dmas[i].sglen; | ||
586 | buf_last_desc->ddadr = DDADR_STOP; | ||
587 | |||
588 | if (!pcdev->sg_tail[i]) | ||
589 | continue; | ||
590 | pcdev->sg_tail[i]->ddadr = buf->dmas[i].sg_dma; | ||
591 | } | ||
592 | |||
593 | pxa_dma_update_sg_tail(pcdev, buf); | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * pxa_camera_start_capture - start video capturing | ||
598 | * @pcdev: camera device | ||
599 | * | ||
600 | * Launch capturing. DMA channels should not be active yet. They should get | ||
601 | * activated at the end of frame interrupt, to capture only whole frames, and | ||
602 | * never begin the capture of a partial frame. | ||
603 | */ | ||
604 | static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) | ||
605 | { | ||
606 | unsigned long cicr0, cifr; | ||
607 | |||
608 | dev_dbg(pcdev->dev, "%s\n", __func__); | ||
609 | /* Reset the FIFOs */ | ||
610 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; | ||
611 | __raw_writel(cifr, pcdev->base + CIFR); | ||
612 | /* Enable End-Of-Frame Interrupt */ | ||
613 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; | ||
614 | cicr0 &= ~CICR0_EOFM; | ||
615 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
616 | } | ||
617 | |||
618 | static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) | ||
619 | { | ||
620 | unsigned long cicr0; | ||
621 | |||
622 | pxa_dma_stop_channels(pcdev); | ||
623 | |||
624 | cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; | ||
625 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
626 | |||
627 | dev_dbg(pcdev->dev, "%s\n", __func__); | ||
628 | } | ||
629 | |||
521 | static void pxa_videobuf_queue(struct videobuf_queue *vq, | 630 | static void pxa_videobuf_queue(struct videobuf_queue *vq, |
522 | struct videobuf_buffer *vb) | 631 | struct videobuf_buffer *vb) |
523 | { | 632 | { |
@@ -525,81 +634,20 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
525 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 634 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
526 | struct pxa_camera_dev *pcdev = ici->priv; | 635 | struct pxa_camera_dev *pcdev = ici->priv; |
527 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 636 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
528 | struct pxa_buffer *active; | ||
529 | unsigned long flags; | 637 | unsigned long flags; |
530 | int i; | ||
531 | 638 | ||
532 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 639 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__, |
533 | vb, vb->baddr, vb->bsize); | 640 | vb, vb->baddr, vb->bsize, pcdev->active); |
641 | |||
534 | spin_lock_irqsave(&pcdev->lock, flags); | 642 | spin_lock_irqsave(&pcdev->lock, flags); |
535 | 643 | ||
536 | list_add_tail(&vb->queue, &pcdev->capture); | 644 | list_add_tail(&vb->queue, &pcdev->capture); |
537 | 645 | ||
538 | vb->state = VIDEOBUF_ACTIVE; | 646 | vb->state = VIDEOBUF_ACTIVE; |
539 | active = pcdev->active; | 647 | pxa_dma_add_tail_buf(pcdev, buf); |
540 | 648 | ||
541 | if (!active) { | 649 | if (!pcdev->active) |
542 | unsigned long cifr, cicr0; | 650 | pxa_camera_start_capture(pcdev); |
543 | |||
544 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; | ||
545 | __raw_writel(cifr, pcdev->base + CIFR); | ||
546 | |||
547 | for (i = 0; i < pcdev->channels; i++) { | ||
548 | DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma; | ||
549 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
550 | pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1; | ||
551 | } | ||
552 | |||
553 | pcdev->active = buf; | ||
554 | |||
555 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; | ||
556 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
557 | } else { | ||
558 | struct pxa_cam_dma *buf_dma; | ||
559 | struct pxa_cam_dma *act_dma; | ||
560 | int nents; | ||
561 | |||
562 | for (i = 0; i < pcdev->channels; i++) { | ||
563 | buf_dma = &buf->dmas[i]; | ||
564 | act_dma = &active->dmas[i]; | ||
565 | nents = buf_dma->sglen; | ||
566 | |||
567 | /* Stop DMA engine */ | ||
568 | DCSR(pcdev->dma_chans[i]) = 0; | ||
569 | |||
570 | /* Add the descriptors we just initialized to | ||
571 | the currently running chain */ | ||
572 | pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma; | ||
573 | pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1; | ||
574 | |||
575 | /* Setup a dummy descriptor with the DMA engines current | ||
576 | * state | ||
577 | */ | ||
578 | buf_dma->sg_cpu[nents].dsadr = | ||
579 | pcdev->res->start + 0x28 + i*8; /* CIBRx */ | ||
580 | buf_dma->sg_cpu[nents].dtadr = | ||
581 | DTADR(pcdev->dma_chans[i]); | ||
582 | buf_dma->sg_cpu[nents].dcmd = | ||
583 | DCMD(pcdev->dma_chans[i]); | ||
584 | |||
585 | if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) { | ||
586 | /* The DMA engine is on the last | ||
587 | descriptor, set the next descriptors | ||
588 | address to the descriptors we just | ||
589 | initialized */ | ||
590 | buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma; | ||
591 | } else { | ||
592 | buf_dma->sg_cpu[nents].ddadr = | ||
593 | DDADR(pcdev->dma_chans[i]); | ||
594 | } | ||
595 | |||
596 | /* The next descriptor is the dummy descriptor */ | ||
597 | DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents * | ||
598 | sizeof(struct pxa_dma_desc); | ||
599 | |||
600 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
601 | } | ||
602 | } | ||
603 | 651 | ||
604 | spin_unlock_irqrestore(&pcdev->lock, flags); | 652 | spin_unlock_irqrestore(&pcdev->lock, flags); |
605 | } | 653 | } |
@@ -637,7 +685,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | |||
637 | struct videobuf_buffer *vb, | 685 | struct videobuf_buffer *vb, |
638 | struct pxa_buffer *buf) | 686 | struct pxa_buffer *buf) |
639 | { | 687 | { |
640 | unsigned long cicr0; | 688 | int i; |
641 | 689 | ||
642 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ | 690 | /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ |
643 | list_del_init(&vb->queue); | 691 | list_del_init(&vb->queue); |
@@ -645,15 +693,13 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | |||
645 | do_gettimeofday(&vb->ts); | 693 | do_gettimeofday(&vb->ts); |
646 | vb->field_count++; | 694 | vb->field_count++; |
647 | wake_up(&vb->done); | 695 | wake_up(&vb->done); |
696 | dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb); | ||
648 | 697 | ||
649 | if (list_empty(&pcdev->capture)) { | 698 | if (list_empty(&pcdev->capture)) { |
699 | pxa_camera_stop_capture(pcdev); | ||
650 | pcdev->active = NULL; | 700 | pcdev->active = NULL; |
651 | DCSR(pcdev->dma_chans[0]) = 0; | 701 | for (i = 0; i < pcdev->channels; i++) |
652 | DCSR(pcdev->dma_chans[1]) = 0; | 702 | pcdev->sg_tail[i] = NULL; |
653 | DCSR(pcdev->dma_chans[2]) = 0; | ||
654 | |||
655 | cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; | ||
656 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
657 | return; | 703 | return; |
658 | } | 704 | } |
659 | 705 | ||
@@ -661,6 +707,35 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, | |||
661 | struct pxa_buffer, vb.queue); | 707 | struct pxa_buffer, vb.queue); |
662 | } | 708 | } |
663 | 709 | ||
710 | /** | ||
711 | * pxa_camera_check_link_miss - check missed DMA linking | ||
712 | * @pcdev: camera device | ||
713 | * | ||
714 | * The DMA chaining is done with DMA running. This means a tiny temporal window | ||
715 | * remains, where a buffer is queued on the chain, while the chain is already | ||
716 | * stopped. This means the tailed buffer would never be transfered by DMA. | ||
717 | * This function restarts the capture for this corner case, where : | ||
718 | * - DADR() == DADDR_STOP | ||
719 | * - a videobuffer is queued on the pcdev->capture list | ||
720 | * | ||
721 | * Please check the "DMA hot chaining timeslice issue" in | ||
722 | * Documentation/video4linux/pxa_camera.txt | ||
723 | * | ||
724 | * Context: should only be called within the dma irq handler | ||
725 | */ | ||
726 | static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) | ||
727 | { | ||
728 | int i, is_dma_stopped = 1; | ||
729 | |||
730 | for (i = 0; i < pcdev->channels; i++) | ||
731 | if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) | ||
732 | is_dma_stopped = 0; | ||
733 | dev_dbg(pcdev->dev, "%s : top queued buffer=%p, dma_stopped=%d\n", | ||
734 | __func__, pcdev->active, is_dma_stopped); | ||
735 | if (pcdev->active && is_dma_stopped) | ||
736 | pxa_camera_start_capture(pcdev); | ||
737 | } | ||
738 | |||
664 | static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | 739 | static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, |
665 | enum pxa_camera_active_dma act_dma) | 740 | enum pxa_camera_active_dma act_dma) |
666 | { | 741 | { |
@@ -668,19 +743,23 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | |||
668 | unsigned long flags; | 743 | unsigned long flags; |
669 | u32 status, camera_status, overrun; | 744 | u32 status, camera_status, overrun; |
670 | struct videobuf_buffer *vb; | 745 | struct videobuf_buffer *vb; |
671 | unsigned long cifr, cicr0; | ||
672 | 746 | ||
673 | spin_lock_irqsave(&pcdev->lock, flags); | 747 | spin_lock_irqsave(&pcdev->lock, flags); |
674 | 748 | ||
675 | status = DCSR(channel); | 749 | status = DCSR(channel); |
676 | DCSR(channel) = status | DCSR_ENDINTR; | 750 | DCSR(channel) = status; |
751 | |||
752 | camera_status = __raw_readl(pcdev->base + CISR); | ||
753 | overrun = CISR_IFO_0; | ||
754 | if (pcdev->channels == 3) | ||
755 | overrun |= CISR_IFO_1 | CISR_IFO_2; | ||
677 | 756 | ||
678 | if (status & DCSR_BUSERR) { | 757 | if (status & DCSR_BUSERR) { |
679 | dev_err(pcdev->dev, "DMA Bus Error IRQ!\n"); | 758 | dev_err(pcdev->dev, "DMA Bus Error IRQ!\n"); |
680 | goto out; | 759 | goto out; |
681 | } | 760 | } |
682 | 761 | ||
683 | if (!(status & DCSR_ENDINTR)) { | 762 | if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { |
684 | dev_err(pcdev->dev, "Unknown DMA IRQ source, " | 763 | dev_err(pcdev->dev, "Unknown DMA IRQ source, " |
685 | "status: 0x%08x\n", status); | 764 | "status: 0x%08x\n", status); |
686 | goto out; | 765 | goto out; |
@@ -691,38 +770,28 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, | |||
691 | goto out; | 770 | goto out; |
692 | } | 771 | } |
693 | 772 | ||
694 | camera_status = __raw_readl(pcdev->base + CISR); | ||
695 | overrun = CISR_IFO_0; | ||
696 | if (pcdev->channels == 3) | ||
697 | overrun |= CISR_IFO_1 | CISR_IFO_2; | ||
698 | if (camera_status & overrun) { | ||
699 | dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status); | ||
700 | /* Stop the Capture Interface */ | ||
701 | cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; | ||
702 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
703 | |||
704 | /* Stop DMA */ | ||
705 | DCSR(channel) = 0; | ||
706 | /* Reset the FIFOs */ | ||
707 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; | ||
708 | __raw_writel(cifr, pcdev->base + CIFR); | ||
709 | /* Enable End-Of-Frame Interrupt */ | ||
710 | cicr0 &= ~CICR0_EOFM; | ||
711 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
712 | /* Restart the Capture Interface */ | ||
713 | __raw_writel(cicr0 | CICR0_ENB, pcdev->base + CICR0); | ||
714 | goto out; | ||
715 | } | ||
716 | |||
717 | vb = &pcdev->active->vb; | 773 | vb = &pcdev->active->vb; |
718 | buf = container_of(vb, struct pxa_buffer, vb); | 774 | buf = container_of(vb, struct pxa_buffer, vb); |
719 | WARN_ON(buf->inwork || list_empty(&vb->queue)); | 775 | WARN_ON(buf->inwork || list_empty(&vb->queue)); |
720 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | ||
721 | vb, vb->baddr, vb->bsize); | ||
722 | 776 | ||
723 | buf->active_dma &= ~act_dma; | 777 | dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", |
724 | if (!buf->active_dma) | 778 | __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", |
725 | pxa_camera_wakeup(pcdev, vb, buf); | 779 | status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); |
780 | |||
781 | if (status & DCSR_ENDINTR) { | ||
782 | if (camera_status & overrun) { | ||
783 | dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", | ||
784 | camera_status); | ||
785 | pxa_camera_stop_capture(pcdev); | ||
786 | pxa_camera_start_capture(pcdev); | ||
787 | goto out; | ||
788 | } | ||
789 | buf->active_dma &= ~act_dma; | ||
790 | if (!buf->active_dma) { | ||
791 | pxa_camera_wakeup(pcdev, vb, buf); | ||
792 | pxa_camera_check_link_miss(pcdev); | ||
793 | } | ||
794 | } | ||
726 | 795 | ||
727 | out: | 796 | out: |
728 | spin_unlock_irqrestore(&pcdev->lock, flags); | 797 | spin_unlock_irqrestore(&pcdev->lock, flags); |
@@ -851,6 +920,8 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) | |||
851 | { | 920 | { |
852 | struct pxa_camera_dev *pcdev = data; | 921 | struct pxa_camera_dev *pcdev = data; |
853 | unsigned long status, cicr0; | 922 | unsigned long status, cicr0; |
923 | struct pxa_buffer *buf; | ||
924 | struct videobuf_buffer *vb; | ||
854 | 925 | ||
855 | status = __raw_readl(pcdev->base + CISR); | 926 | status = __raw_readl(pcdev->base + CISR); |
856 | dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status); | 927 | dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status); |
@@ -861,12 +932,14 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) | |||
861 | __raw_writel(status, pcdev->base + CISR); | 932 | __raw_writel(status, pcdev->base + CISR); |
862 | 933 | ||
863 | if (status & CISR_EOF) { | 934 | if (status & CISR_EOF) { |
864 | int i; | 935 | pcdev->active = list_first_entry(&pcdev->capture, |
865 | for (i = 0; i < pcdev->channels; i++) { | 936 | struct pxa_buffer, vb.queue); |
866 | DDADR(pcdev->dma_chans[i]) = | 937 | vb = &pcdev->active->vb; |
867 | pcdev->active->dmas[i].sg_dma; | 938 | buf = container_of(vb, struct pxa_buffer, vb); |
868 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | 939 | pxa_videobuf_set_actdma(pcdev, buf); |
869 | } | 940 | |
941 | pxa_dma_start_channels(pcdev); | ||
942 | |||
870 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; | 943 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; |
871 | __raw_writel(cicr0, pcdev->base + CICR0); | 944 | __raw_writel(cicr0, pcdev->base + CICR0); |
872 | } | 945 | } |
@@ -1449,18 +1522,8 @@ static int pxa_camera_resume(struct soc_camera_device *icd) | |||
1449 | ret = pcdev->icd->ops->resume(pcdev->icd); | 1522 | ret = pcdev->icd->ops->resume(pcdev->icd); |
1450 | 1523 | ||
1451 | /* Restart frame capture if active buffer exists */ | 1524 | /* Restart frame capture if active buffer exists */ |
1452 | if (!ret && pcdev->active) { | 1525 | if (!ret && pcdev->active) |
1453 | unsigned long cifr, cicr0; | 1526 | pxa_camera_start_capture(pcdev); |
1454 | |||
1455 | /* Reset the FIFOs */ | ||
1456 | cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; | ||
1457 | __raw_writel(cifr, pcdev->base + CIFR); | ||
1458 | |||
1459 | cicr0 = __raw_readl(pcdev->base + CICR0); | ||
1460 | cicr0 &= ~CICR0_EOFM; /* Enable End-Of-Frame Interrupt */ | ||
1461 | cicr0 |= CICR0_ENB; /* Restart the Capture Interface */ | ||
1462 | __raw_writel(cicr0, pcdev->base + CICR0); | ||
1463 | } | ||
1464 | 1527 | ||
1465 | return ret; | 1528 | return ret; |
1466 | } | 1529 | } |