aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafal Prylowski <prylowski@metasoft.pl>2012-04-19 05:19:00 -0400
committerRyan Mallon <rmallon@gmail.com>2012-04-19 18:37:19 -0400
commit2b3c83efc9a653af6a24799eeb1a2900ba0439e6 (patch)
tree27e96e2942b8d2c7ae04655796f20d83bfe20735
parent5528a8469fbc01db218fbc00ebec1e3fc088e759 (diff)
dmaengine/ep93xx_dma: Implement double buffering for M2M DMA channels
Add double buffering support for M2M DMA channels. Implement this by using EP93xx M2M DMA Buffer and Control Finite State Machines to be sure that we are not disabling the channel when it's actually operating. Signed-off-by: Rafal Prylowski <prylowski@metasoft.pl> Tested-by: H Hartley Sweeten <hsweeten@visionengravers.com> Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com> Acked-by: Mika Westerberg <mika.westerberg@iki.fi> Signed-off-by: Ryan Mallon <rmallon@gmail.com>
-rw-r--r--drivers/dma/ep93xx_dma.c117
1 files changed, 93 insertions, 24 deletions
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index e6f133b78dc2..bbfbb0622d35 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -71,6 +71,7 @@
71#define M2M_CONTROL_TM_SHIFT 13 71#define M2M_CONTROL_TM_SHIFT 13
72#define M2M_CONTROL_TM_TX (1 << M2M_CONTROL_TM_SHIFT) 72#define M2M_CONTROL_TM_TX (1 << M2M_CONTROL_TM_SHIFT)
73#define M2M_CONTROL_TM_RX (2 << M2M_CONTROL_TM_SHIFT) 73#define M2M_CONTROL_TM_RX (2 << M2M_CONTROL_TM_SHIFT)
74#define M2M_CONTROL_NFBINT BIT(21)
74#define M2M_CONTROL_RSS_SHIFT 22 75#define M2M_CONTROL_RSS_SHIFT 22
75#define M2M_CONTROL_RSS_SSPRX (1 << M2M_CONTROL_RSS_SHIFT) 76#define M2M_CONTROL_RSS_SSPRX (1 << M2M_CONTROL_RSS_SHIFT)
76#define M2M_CONTROL_RSS_SSPTX (2 << M2M_CONTROL_RSS_SHIFT) 77#define M2M_CONTROL_RSS_SSPTX (2 << M2M_CONTROL_RSS_SHIFT)
@@ -79,7 +80,22 @@
79#define M2M_CONTROL_PWSC_SHIFT 25 80#define M2M_CONTROL_PWSC_SHIFT 25
80 81
81#define M2M_INTERRUPT 0x0004 82#define M2M_INTERRUPT 0x0004
82#define M2M_INTERRUPT_DONEINT BIT(1) 83#define M2M_INTERRUPT_MASK 6
84
85#define M2M_STATUS 0x000c
86#define M2M_STATUS_CTL_SHIFT 1
87#define M2M_STATUS_CTL_IDLE (0 << M2M_STATUS_CTL_SHIFT)
88#define M2M_STATUS_CTL_STALL (1 << M2M_STATUS_CTL_SHIFT)
89#define M2M_STATUS_CTL_MEMRD (2 << M2M_STATUS_CTL_SHIFT)
90#define M2M_STATUS_CTL_MEMWR (3 << M2M_STATUS_CTL_SHIFT)
91#define M2M_STATUS_CTL_BWCWAIT (4 << M2M_STATUS_CTL_SHIFT)
92#define M2M_STATUS_CTL_MASK (7 << M2M_STATUS_CTL_SHIFT)
93#define M2M_STATUS_BUF_SHIFT 4
94#define M2M_STATUS_BUF_NO (0 << M2M_STATUS_BUF_SHIFT)
95#define M2M_STATUS_BUF_ON (1 << M2M_STATUS_BUF_SHIFT)
96#define M2M_STATUS_BUF_NEXT (2 << M2M_STATUS_BUF_SHIFT)
97#define M2M_STATUS_BUF_MASK (3 << M2M_STATUS_BUF_SHIFT)
98#define M2M_STATUS_DONE BIT(6)
83 99
84#define M2M_BCR0 0x0010 100#define M2M_BCR0 0x0010
85#define M2M_BCR1 0x0014 101#define M2M_BCR1 0x0014
@@ -426,15 +442,6 @@ static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac)
426 442
427/* 443/*
428 * M2M DMA implementation 444 * M2M DMA implementation
429 *
430 * For the M2M transfers we don't use NFB at all. This is because it simply
431 * doesn't work well with memcpy transfers. When you submit both buffers it is
432 * extremely unlikely that you get an NFB interrupt, but it instead reports
433 * DONE interrupt and both buffers are already transferred which means that we
434 * weren't able to update the next buffer.
435 *
436 * So for now we "simulate" NFB by just submitting buffer after buffer
437 * without double buffering.
438 */ 445 */
439 446
440static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) 447static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
@@ -543,6 +550,11 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac)
543 m2m_fill_desc(edmac); 550 m2m_fill_desc(edmac);
544 control |= M2M_CONTROL_DONEINT; 551 control |= M2M_CONTROL_DONEINT;
545 552
553 if (ep93xx_dma_advance_active(edmac)) {
554 m2m_fill_desc(edmac);
555 control |= M2M_CONTROL_NFBINT;
556 }
557
546 /* 558 /*
547 * Now we can finally enable the channel. For M2M channel this must be 559 * Now we can finally enable the channel. For M2M channel this must be
548 * done _after_ the BCRx registers are programmed. 560 * done _after_ the BCRx registers are programmed.
@@ -560,32 +572,89 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac)
560 } 572 }
561} 573}
562 574
575/*
576 * According to EP93xx User's Guide, we should receive DONE interrupt when all
577 * M2M DMA controller transactions complete normally. This is not always the
578 * case - sometimes EP93xx M2M DMA asserts DONE interrupt when the DMA channel
579 * is still running (channel Buffer FSM in DMA_BUF_ON state, and channel
580 * Control FSM in DMA_MEM_RD state, observed at least in IDE-DMA operation).
581 * In effect, disabling the channel when only DONE bit is set could stop
582 * currently running DMA transfer. To avoid this, we use Buffer FSM and
583 * Control FSM to check current state of DMA channel.
584 */
563static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac) 585static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac)
564{ 586{
587 u32 status = readl(edmac->regs + M2M_STATUS);
588 u32 ctl_fsm = status & M2M_STATUS_CTL_MASK;
589 u32 buf_fsm = status & M2M_STATUS_BUF_MASK;
590 bool done = status & M2M_STATUS_DONE;
591 bool last_done;
565 u32 control; 592 u32 control;
593 struct ep93xx_dma_desc *desc;
566 594
567 if (!(readl(edmac->regs + M2M_INTERRUPT) & M2M_INTERRUPT_DONEINT)) 595 /* Accept only DONE and NFB interrupts */
596 if (!(readl(edmac->regs + M2M_INTERRUPT) & M2M_INTERRUPT_MASK))
568 return INTERRUPT_UNKNOWN; 597 return INTERRUPT_UNKNOWN;
569 598
570 /* Clear the DONE bit */ 599 if (done) {
571 writel(0, edmac->regs + M2M_INTERRUPT); 600 /* Clear the DONE bit */
601 writel(0, edmac->regs + M2M_INTERRUPT);
602 }
572 603
573 /* Disable interrupts and the channel */ 604 /*
574 control = readl(edmac->regs + M2M_CONTROL); 605 * Check whether we are done with descriptors or not. This, together
575 control &= ~(M2M_CONTROL_DONEINT | M2M_CONTROL_ENABLE); 606 * with DMA channel state, determines action to take in interrupt.
576 writel(control, edmac->regs + M2M_CONTROL); 607 */
608 desc = ep93xx_dma_get_active(edmac);
609 last_done = !desc || desc->txd.cookie;
577 610
578 /* 611 /*
579 * Since we only get DONE interrupt we have to find out ourselves 612 * Use M2M DMA Buffer FSM and Control FSM to check current state of
580 * whether there still is something to process. So we try to advance 613 * DMA channel. Using DONE and NFB bits from channel status register
581 * the chain an see whether it succeeds. 614 * or bits from channel interrupt register is not reliable.
582 */ 615 */
583 if (ep93xx_dma_advance_active(edmac)) { 616 if (!last_done &&
584 edmac->edma->hw_submit(edmac); 617 (buf_fsm == M2M_STATUS_BUF_NO ||
585 return INTERRUPT_NEXT_BUFFER; 618 buf_fsm == M2M_STATUS_BUF_ON)) {
619 /*
620 * Two buffers are ready for update when Buffer FSM is in
621 * DMA_NO_BUF state. Only one buffer can be prepared without
622 * disabling the channel or polling the DONE bit.
623 * To simplify things, always prepare only one buffer.
624 */
625 if (ep93xx_dma_advance_active(edmac)) {
626 m2m_fill_desc(edmac);
627 if (done && !edmac->chan.private) {
628 /* Software trigger for memcpy channel */
629 control = readl(edmac->regs + M2M_CONTROL);
630 control |= M2M_CONTROL_START;
631 writel(control, edmac->regs + M2M_CONTROL);
632 }
633 return INTERRUPT_NEXT_BUFFER;
634 } else {
635 last_done = true;
636 }
637 }
638
639 /*
640 * Disable the channel only when Buffer FSM is in DMA_NO_BUF state
641 * and Control FSM is in DMA_STALL state.
642 */
643 if (last_done &&
644 buf_fsm == M2M_STATUS_BUF_NO &&
645 ctl_fsm == M2M_STATUS_CTL_STALL) {
646 /* Disable interrupts and the channel */
647 control = readl(edmac->regs + M2M_CONTROL);
648 control &= ~(M2M_CONTROL_DONEINT | M2M_CONTROL_NFBINT
649 | M2M_CONTROL_ENABLE);
650 writel(control, edmac->regs + M2M_CONTROL);
651 return INTERRUPT_DONE;
586 } 652 }
587 653
588 return INTERRUPT_DONE; 654 /*
655 * Nothing to do this time.
656 */
657 return INTERRUPT_NEXT_BUFFER;
589} 658}
590 659
591/* 660/*