diff options
| -rw-r--r-- | drivers/dma/ep93xx_dma.c | 117 |
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 | ||
| 440 | static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) | 447 | static 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 | */ | ||
| 563 | static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac) | 585 | static 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 | /* |
