diff options
author | Vinod Koul <vkoul@kernel.org> | 2018-06-04 00:59:00 -0400 |
---|---|---|
committer | Vinod Koul <vkoul@kernel.org> | 2018-06-04 00:59:00 -0400 |
commit | 2f62304d81b815782739261713702358d84dd97c (patch) | |
tree | eee6692294296345ed562c8f2c0c00d6da379d43 | |
parent | d39dae11c77c34f9a8dae8f3ce87113bc7010414 (diff) | |
parent | ca1b7d3daff43a269fb7a0479055ac5b741638d8 (diff) |
Merge branch 'topic/sprd' into for-linus
-rw-r--r-- | drivers/dma/sprd-dma.c | 349 | ||||
-rw-r--r-- | include/linux/dma/sprd-dma.h | 61 |
2 files changed, 264 insertions, 146 deletions
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index b106e8a60af6..ab69f835ea02 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | #include <linux/clk.h> | 7 | #include <linux/clk.h> |
8 | #include <linux/dma-mapping.h> | 8 | #include <linux/dma-mapping.h> |
9 | #include <linux/dma/sprd-dma.h> | ||
9 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
10 | #include <linux/init.h> | 11 | #include <linux/init.h> |
11 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
@@ -116,57 +117,21 @@ | |||
116 | #define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0 | 117 | #define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0 |
117 | #define SPRD_DMA_TRSF_STEP_MASK GENMASK(15, 0) | 118 | #define SPRD_DMA_TRSF_STEP_MASK GENMASK(15, 0) |
118 | 119 | ||
120 | /* define the DMA transfer step type */ | ||
121 | #define SPRD_DMA_NONE_STEP 0 | ||
122 | #define SPRD_DMA_BYTE_STEP 1 | ||
123 | #define SPRD_DMA_SHORT_STEP 2 | ||
124 | #define SPRD_DMA_WORD_STEP 4 | ||
125 | #define SPRD_DMA_DWORD_STEP 8 | ||
126 | |||
119 | #define SPRD_DMA_SOFTWARE_UID 0 | 127 | #define SPRD_DMA_SOFTWARE_UID 0 |
120 | 128 | ||
121 | /* | 129 | /* dma data width values */ |
122 | * enum sprd_dma_req_mode: define the DMA request mode | 130 | enum sprd_dma_datawidth { |
123 | * @SPRD_DMA_FRAG_REQ: fragment request mode | 131 | SPRD_DMA_DATAWIDTH_1_BYTE, |
124 | * @SPRD_DMA_BLK_REQ: block request mode | 132 | SPRD_DMA_DATAWIDTH_2_BYTES, |
125 | * @SPRD_DMA_TRANS_REQ: transaction request mode | 133 | SPRD_DMA_DATAWIDTH_4_BYTES, |
126 | * @SPRD_DMA_LIST_REQ: link-list request mode | 134 | SPRD_DMA_DATAWIDTH_8_BYTES, |
127 | * | ||
128 | * We have 4 types request mode: fragment mode, block mode, transaction mode | ||
129 | * and linklist mode. One transaction can contain several blocks, one block can | ||
130 | * contain several fragments. Link-list mode means we can save several DMA | ||
131 | * configuration into one reserved memory, then DMA can fetch each DMA | ||
132 | * configuration automatically to start transfer. | ||
133 | */ | ||
134 | enum sprd_dma_req_mode { | ||
135 | SPRD_DMA_FRAG_REQ, | ||
136 | SPRD_DMA_BLK_REQ, | ||
137 | SPRD_DMA_TRANS_REQ, | ||
138 | SPRD_DMA_LIST_REQ, | ||
139 | }; | ||
140 | |||
141 | /* | ||
142 | * enum sprd_dma_int_type: define the DMA interrupt type | ||
143 | * @SPRD_DMA_NO_INT: do not need generate DMA interrupts. | ||
144 | * @SPRD_DMA_FRAG_INT: fragment done interrupt when one fragment request | ||
145 | * is done. | ||
146 | * @SPRD_DMA_BLK_INT: block done interrupt when one block request is done. | ||
147 | * @SPRD_DMA_BLK_FRAG_INT: block and fragment interrupt when one fragment | ||
148 | * or one block request is done. | ||
149 | * @SPRD_DMA_TRANS_INT: tansaction done interrupt when one transaction | ||
150 | * request is done. | ||
151 | * @SPRD_DMA_TRANS_FRAG_INT: transaction and fragment interrupt when one | ||
152 | * transaction request or fragment request is done. | ||
153 | * @SPRD_DMA_TRANS_BLK_INT: transaction and block interrupt when one | ||
154 | * transaction request or block request is done. | ||
155 | * @SPRD_DMA_LIST_INT: link-list done interrupt when one link-list request | ||
156 | * is done. | ||
157 | * @SPRD_DMA_CFGERR_INT: configure error interrupt when configuration is | ||
158 | * incorrect. | ||
159 | */ | ||
160 | enum sprd_dma_int_type { | ||
161 | SPRD_DMA_NO_INT, | ||
162 | SPRD_DMA_FRAG_INT, | ||
163 | SPRD_DMA_BLK_INT, | ||
164 | SPRD_DMA_BLK_FRAG_INT, | ||
165 | SPRD_DMA_TRANS_INT, | ||
166 | SPRD_DMA_TRANS_FRAG_INT, | ||
167 | SPRD_DMA_TRANS_BLK_INT, | ||
168 | SPRD_DMA_LIST_INT, | ||
169 | SPRD_DMA_CFGERR_INT, | ||
170 | }; | 135 | }; |
171 | 136 | ||
172 | /* dma channel hardware configuration */ | 137 | /* dma channel hardware configuration */ |
@@ -199,6 +164,7 @@ struct sprd_dma_desc { | |||
199 | struct sprd_dma_chn { | 164 | struct sprd_dma_chn { |
200 | struct virt_dma_chan vc; | 165 | struct virt_dma_chan vc; |
201 | void __iomem *chn_base; | 166 | void __iomem *chn_base; |
167 | struct dma_slave_config slave_cfg; | ||
202 | u32 chn_num; | 168 | u32 chn_num; |
203 | u32 dev_id; | 169 | u32 dev_id; |
204 | struct sprd_dma_desc *cur_desc; | 170 | struct sprd_dma_desc *cur_desc; |
@@ -587,52 +553,97 @@ static void sprd_dma_issue_pending(struct dma_chan *chan) | |||
587 | spin_unlock_irqrestore(&schan->vc.lock, flags); | 553 | spin_unlock_irqrestore(&schan->vc.lock, flags); |
588 | } | 554 | } |
589 | 555 | ||
590 | static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, | 556 | static int sprd_dma_get_datawidth(enum dma_slave_buswidth buswidth) |
591 | dma_addr_t dest, dma_addr_t src, size_t len) | 557 | { |
558 | switch (buswidth) { | ||
559 | case DMA_SLAVE_BUSWIDTH_1_BYTE: | ||
560 | case DMA_SLAVE_BUSWIDTH_2_BYTES: | ||
561 | case DMA_SLAVE_BUSWIDTH_4_BYTES: | ||
562 | case DMA_SLAVE_BUSWIDTH_8_BYTES: | ||
563 | return ffs(buswidth) - 1; | ||
564 | |||
565 | default: | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | static int sprd_dma_get_step(enum dma_slave_buswidth buswidth) | ||
571 | { | ||
572 | switch (buswidth) { | ||
573 | case DMA_SLAVE_BUSWIDTH_1_BYTE: | ||
574 | case DMA_SLAVE_BUSWIDTH_2_BYTES: | ||
575 | case DMA_SLAVE_BUSWIDTH_4_BYTES: | ||
576 | case DMA_SLAVE_BUSWIDTH_8_BYTES: | ||
577 | return buswidth; | ||
578 | |||
579 | default: | ||
580 | return -EINVAL; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static int sprd_dma_fill_desc(struct dma_chan *chan, | ||
585 | struct sprd_dma_desc *sdesc, | ||
586 | dma_addr_t src, dma_addr_t dst, u32 len, | ||
587 | enum dma_transfer_direction dir, | ||
588 | unsigned long flags, | ||
589 | struct dma_slave_config *slave_cfg) | ||
592 | { | 590 | { |
593 | struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan); | 591 | struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan); |
592 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); | ||
594 | struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; | 593 | struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; |
595 | u32 datawidth, src_step, des_step, fragment_len; | 594 | u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK; |
596 | u32 block_len, req_mode, irq_mode, transcation_len; | 595 | u32 int_mode = flags & SPRD_DMA_INT_MASK; |
597 | u32 fix_mode = 0, fix_en = 0; | 596 | int src_datawidth, dst_datawidth, src_step, dst_step; |
598 | 597 | u32 temp, fix_mode = 0, fix_en = 0; | |
599 | if (IS_ALIGNED(len, 4)) { | 598 | |
600 | datawidth = 2; | 599 | if (dir == DMA_MEM_TO_DEV) { |
601 | src_step = 4; | 600 | src_step = sprd_dma_get_step(slave_cfg->src_addr_width); |
602 | des_step = 4; | 601 | if (src_step < 0) { |
603 | } else if (IS_ALIGNED(len, 2)) { | 602 | dev_err(sdev->dma_dev.dev, "invalid source step\n"); |
604 | datawidth = 1; | 603 | return src_step; |
605 | src_step = 2; | 604 | } |
606 | des_step = 2; | 605 | dst_step = SPRD_DMA_NONE_STEP; |
607 | } else { | 606 | } else { |
608 | datawidth = 0; | 607 | dst_step = sprd_dma_get_step(slave_cfg->dst_addr_width); |
609 | src_step = 1; | 608 | if (dst_step < 0) { |
610 | des_step = 1; | 609 | dev_err(sdev->dma_dev.dev, "invalid destination step\n"); |
610 | return dst_step; | ||
611 | } | ||
612 | src_step = SPRD_DMA_NONE_STEP; | ||
611 | } | 613 | } |
612 | 614 | ||
613 | fragment_len = SPRD_DMA_MEMCPY_MIN_SIZE; | 615 | src_datawidth = sprd_dma_get_datawidth(slave_cfg->src_addr_width); |
614 | if (len <= SPRD_DMA_BLK_LEN_MASK) { | 616 | if (src_datawidth < 0) { |
615 | block_len = len; | 617 | dev_err(sdev->dma_dev.dev, "invalid source datawidth\n"); |
616 | transcation_len = 0; | 618 | return src_datawidth; |
617 | req_mode = SPRD_DMA_BLK_REQ; | ||
618 | irq_mode = SPRD_DMA_BLK_INT; | ||
619 | } else { | ||
620 | block_len = SPRD_DMA_MEMCPY_MIN_SIZE; | ||
621 | transcation_len = len; | ||
622 | req_mode = SPRD_DMA_TRANS_REQ; | ||
623 | irq_mode = SPRD_DMA_TRANS_INT; | ||
624 | } | 619 | } |
625 | 620 | ||
621 | dst_datawidth = sprd_dma_get_datawidth(slave_cfg->dst_addr_width); | ||
622 | if (dst_datawidth < 0) { | ||
623 | dev_err(sdev->dma_dev.dev, "invalid destination datawidth\n"); | ||
624 | return dst_datawidth; | ||
625 | } | ||
626 | |||
627 | if (slave_cfg->slave_id) | ||
628 | schan->dev_id = slave_cfg->slave_id; | ||
629 | |||
626 | hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; | 630 | hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; |
627 | hw->wrap_ptr = (u32)((src >> SPRD_DMA_HIGH_ADDR_OFFSET) & | ||
628 | SPRD_DMA_HIGH_ADDR_MASK); | ||
629 | hw->wrap_to = (u32)((dest >> SPRD_DMA_HIGH_ADDR_OFFSET) & | ||
630 | SPRD_DMA_HIGH_ADDR_MASK); | ||
631 | 631 | ||
632 | hw->src_addr = (u32)(src & SPRD_DMA_LOW_ADDR_MASK); | 632 | /* |
633 | hw->des_addr = (u32)(dest & SPRD_DMA_LOW_ADDR_MASK); | 633 | * wrap_ptr and wrap_to will save the high 4 bits source address and |
634 | * destination address. | ||
635 | */ | ||
636 | hw->wrap_ptr = (src >> SPRD_DMA_HIGH_ADDR_OFFSET) & SPRD_DMA_HIGH_ADDR_MASK; | ||
637 | hw->wrap_to = (dst >> SPRD_DMA_HIGH_ADDR_OFFSET) & SPRD_DMA_HIGH_ADDR_MASK; | ||
638 | hw->src_addr = src & SPRD_DMA_LOW_ADDR_MASK; | ||
639 | hw->des_addr = dst & SPRD_DMA_LOW_ADDR_MASK; | ||
634 | 640 | ||
635 | if ((src_step != 0 && des_step != 0) || (src_step | des_step) == 0) { | 641 | /* |
642 | * If the src step and dst step both are 0 or both are not 0, that means | ||
643 | * we can not enable the fix mode. If one is 0 and another one is not, | ||
644 | * we can enable the fix mode. | ||
645 | */ | ||
646 | if ((src_step != 0 && dst_step != 0) || (src_step | dst_step) == 0) { | ||
636 | fix_en = 0; | 647 | fix_en = 0; |
637 | } else { | 648 | } else { |
638 | fix_en = 1; | 649 | fix_en = 1; |
@@ -642,87 +653,119 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, | |||
642 | fix_mode = 0; | 653 | fix_mode = 0; |
643 | } | 654 | } |
644 | 655 | ||
645 | hw->frg_len = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET | | 656 | hw->intc = int_mode | SPRD_DMA_CFG_ERR_INT_EN; |
646 | datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET | | ||
647 | req_mode << SPRD_DMA_REQ_MODE_OFFSET | | ||
648 | fix_mode << SPRD_DMA_FIX_SEL_OFFSET | | ||
649 | fix_en << SPRD_DMA_FIX_EN_OFFSET | | ||
650 | (fragment_len & SPRD_DMA_FRG_LEN_MASK); | ||
651 | hw->blk_len = block_len & SPRD_DMA_BLK_LEN_MASK; | ||
652 | |||
653 | hw->intc = SPRD_DMA_CFG_ERR_INT_EN; | ||
654 | |||
655 | switch (irq_mode) { | ||
656 | case SPRD_DMA_NO_INT: | ||
657 | break; | ||
658 | |||
659 | case SPRD_DMA_FRAG_INT: | ||
660 | hw->intc |= SPRD_DMA_FRAG_INT_EN; | ||
661 | break; | ||
662 | 657 | ||
663 | case SPRD_DMA_BLK_INT: | 658 | temp = src_datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET; |
664 | hw->intc |= SPRD_DMA_BLK_INT_EN; | 659 | temp |= dst_datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET; |
665 | break; | 660 | temp |= req_mode << SPRD_DMA_REQ_MODE_OFFSET; |
661 | temp |= fix_mode << SPRD_DMA_FIX_SEL_OFFSET; | ||
662 | temp |= fix_en << SPRD_DMA_FIX_EN_OFFSET; | ||
663 | temp |= slave_cfg->src_maxburst & SPRD_DMA_FRG_LEN_MASK; | ||
664 | hw->frg_len = temp; | ||
666 | 665 | ||
667 | case SPRD_DMA_BLK_FRAG_INT: | 666 | hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK; |
668 | hw->intc |= SPRD_DMA_BLK_INT_EN | SPRD_DMA_FRAG_INT_EN; | 667 | hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK; |
669 | break; | ||
670 | 668 | ||
671 | case SPRD_DMA_TRANS_INT: | 669 | temp = (dst_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET; |
672 | hw->intc |= SPRD_DMA_TRANS_INT_EN; | 670 | temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET; |
673 | break; | 671 | hw->trsf_step = temp; |
674 | 672 | ||
675 | case SPRD_DMA_TRANS_FRAG_INT: | 673 | hw->frg_step = 0; |
676 | hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_FRAG_INT_EN; | 674 | hw->src_blk_step = 0; |
677 | break; | 675 | hw->des_blk_step = 0; |
676 | return 0; | ||
677 | } | ||
678 | 678 | ||
679 | case SPRD_DMA_TRANS_BLK_INT: | 679 | static struct dma_async_tx_descriptor * |
680 | hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_BLK_INT_EN; | 680 | sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, |
681 | break; | 681 | size_t len, unsigned long flags) |
682 | { | ||
683 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); | ||
684 | struct sprd_dma_desc *sdesc; | ||
685 | struct sprd_dma_chn_hw *hw; | ||
686 | enum sprd_dma_datawidth datawidth; | ||
687 | u32 step, temp; | ||
682 | 688 | ||
683 | case SPRD_DMA_LIST_INT: | 689 | sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); |
684 | hw->intc |= SPRD_DMA_LIST_INT_EN; | 690 | if (!sdesc) |
685 | break; | 691 | return NULL; |
686 | 692 | ||
687 | case SPRD_DMA_CFGERR_INT: | 693 | hw = &sdesc->chn_hw; |
688 | hw->intc |= SPRD_DMA_CFG_ERR_INT_EN; | ||
689 | break; | ||
690 | 694 | ||
691 | default: | 695 | hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; |
692 | dev_err(sdev->dma_dev.dev, "invalid irq mode\n"); | 696 | hw->intc = SPRD_DMA_TRANS_INT | SPRD_DMA_CFG_ERR_INT_EN; |
693 | return -EINVAL; | 697 | hw->src_addr = src & SPRD_DMA_LOW_ADDR_MASK; |
698 | hw->des_addr = dest & SPRD_DMA_LOW_ADDR_MASK; | ||
699 | hw->wrap_ptr = (src >> SPRD_DMA_HIGH_ADDR_OFFSET) & | ||
700 | SPRD_DMA_HIGH_ADDR_MASK; | ||
701 | hw->wrap_to = (dest >> SPRD_DMA_HIGH_ADDR_OFFSET) & | ||
702 | SPRD_DMA_HIGH_ADDR_MASK; | ||
703 | |||
704 | if (IS_ALIGNED(len, 8)) { | ||
705 | datawidth = SPRD_DMA_DATAWIDTH_8_BYTES; | ||
706 | step = SPRD_DMA_DWORD_STEP; | ||
707 | } else if (IS_ALIGNED(len, 4)) { | ||
708 | datawidth = SPRD_DMA_DATAWIDTH_4_BYTES; | ||
709 | step = SPRD_DMA_WORD_STEP; | ||
710 | } else if (IS_ALIGNED(len, 2)) { | ||
711 | datawidth = SPRD_DMA_DATAWIDTH_2_BYTES; | ||
712 | step = SPRD_DMA_SHORT_STEP; | ||
713 | } else { | ||
714 | datawidth = SPRD_DMA_DATAWIDTH_1_BYTE; | ||
715 | step = SPRD_DMA_BYTE_STEP; | ||
694 | } | 716 | } |
695 | 717 | ||
696 | if (transcation_len == 0) | 718 | temp = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET; |
697 | hw->trsc_len = block_len & SPRD_DMA_TRSC_LEN_MASK; | 719 | temp |= datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET; |
698 | else | 720 | temp |= SPRD_DMA_TRANS_REQ << SPRD_DMA_REQ_MODE_OFFSET; |
699 | hw->trsc_len = transcation_len & SPRD_DMA_TRSC_LEN_MASK; | 721 | temp |= len & SPRD_DMA_FRG_LEN_MASK; |
722 | hw->frg_len = temp; | ||
700 | 723 | ||
701 | hw->trsf_step = (des_step & SPRD_DMA_TRSF_STEP_MASK) << | 724 | hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK; |
702 | SPRD_DMA_DEST_TRSF_STEP_OFFSET | | 725 | hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK; |
703 | (src_step & SPRD_DMA_TRSF_STEP_MASK) << | ||
704 | SPRD_DMA_SRC_TRSF_STEP_OFFSET; | ||
705 | 726 | ||
706 | hw->frg_step = 0; | 727 | temp = (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET; |
707 | hw->src_blk_step = 0; | 728 | temp |= (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET; |
708 | hw->des_blk_step = 0; | 729 | hw->trsf_step = temp; |
709 | hw->src_blk_step = 0; | 730 | |
710 | return 0; | 731 | return vchan_tx_prep(&schan->vc, &sdesc->vd, flags); |
711 | } | 732 | } |
712 | 733 | ||
713 | static struct dma_async_tx_descriptor * | 734 | static struct dma_async_tx_descriptor * |
714 | sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | 735 | sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, |
715 | size_t len, unsigned long flags) | 736 | unsigned int sglen, enum dma_transfer_direction dir, |
737 | unsigned long flags, void *context) | ||
716 | { | 738 | { |
717 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); | 739 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); |
740 | struct dma_slave_config *slave_cfg = &schan->slave_cfg; | ||
741 | dma_addr_t src = 0, dst = 0; | ||
718 | struct sprd_dma_desc *sdesc; | 742 | struct sprd_dma_desc *sdesc; |
719 | int ret; | 743 | struct scatterlist *sg; |
744 | u32 len = 0; | ||
745 | int ret, i; | ||
746 | |||
747 | /* TODO: now we only support one sg for each DMA configuration. */ | ||
748 | if (!is_slave_direction(dir) || sglen > 1) | ||
749 | return NULL; | ||
720 | 750 | ||
721 | sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); | 751 | sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); |
722 | if (!sdesc) | 752 | if (!sdesc) |
723 | return NULL; | 753 | return NULL; |
724 | 754 | ||
725 | ret = sprd_dma_config(chan, sdesc, dest, src, len); | 755 | for_each_sg(sgl, sg, sglen, i) { |
756 | len = sg_dma_len(sg); | ||
757 | |||
758 | if (dir == DMA_MEM_TO_DEV) { | ||
759 | src = sg_dma_address(sg); | ||
760 | dst = slave_cfg->dst_addr; | ||
761 | } else { | ||
762 | src = slave_cfg->src_addr; | ||
763 | dst = sg_dma_address(sg); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags, | ||
768 | slave_cfg); | ||
726 | if (ret) { | 769 | if (ret) { |
727 | kfree(sdesc); | 770 | kfree(sdesc); |
728 | return NULL; | 771 | return NULL; |
@@ -731,6 +774,19 @@ sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, | |||
731 | return vchan_tx_prep(&schan->vc, &sdesc->vd, flags); | 774 | return vchan_tx_prep(&schan->vc, &sdesc->vd, flags); |
732 | } | 775 | } |
733 | 776 | ||
777 | static int sprd_dma_slave_config(struct dma_chan *chan, | ||
778 | struct dma_slave_config *config) | ||
779 | { | ||
780 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); | ||
781 | struct dma_slave_config *slave_cfg = &schan->slave_cfg; | ||
782 | |||
783 | if (!is_slave_direction(config->direction)) | ||
784 | return -EINVAL; | ||
785 | |||
786 | memcpy(slave_cfg, config, sizeof(*config)); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
734 | static int sprd_dma_pause(struct dma_chan *chan) | 790 | static int sprd_dma_pause(struct dma_chan *chan) |
735 | { | 791 | { |
736 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); | 792 | struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); |
@@ -842,10 +898,9 @@ static int sprd_dma_probe(struct platform_device *pdev) | |||
842 | } | 898 | } |
843 | 899 | ||
844 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 900 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
845 | sdev->glb_base = devm_ioremap_nocache(&pdev->dev, res->start, | 901 | sdev->glb_base = devm_ioremap_resource(&pdev->dev, res); |
846 | resource_size(res)); | 902 | if (IS_ERR(sdev->glb_base)) |
847 | if (!sdev->glb_base) | 903 | return PTR_ERR(sdev->glb_base); |
848 | return -ENOMEM; | ||
849 | 904 | ||
850 | dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask); | 905 | dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask); |
851 | sdev->total_chns = chn_count; | 906 | sdev->total_chns = chn_count; |
@@ -858,6 +913,8 @@ static int sprd_dma_probe(struct platform_device *pdev) | |||
858 | sdev->dma_dev.device_tx_status = sprd_dma_tx_status; | 913 | sdev->dma_dev.device_tx_status = sprd_dma_tx_status; |
859 | sdev->dma_dev.device_issue_pending = sprd_dma_issue_pending; | 914 | sdev->dma_dev.device_issue_pending = sprd_dma_issue_pending; |
860 | sdev->dma_dev.device_prep_dma_memcpy = sprd_dma_prep_dma_memcpy; | 915 | sdev->dma_dev.device_prep_dma_memcpy = sprd_dma_prep_dma_memcpy; |
916 | sdev->dma_dev.device_prep_slave_sg = sprd_dma_prep_slave_sg; | ||
917 | sdev->dma_dev.device_config = sprd_dma_slave_config; | ||
861 | sdev->dma_dev.device_pause = sprd_dma_pause; | 918 | sdev->dma_dev.device_pause = sprd_dma_pause; |
862 | sdev->dma_dev.device_resume = sprd_dma_resume; | 919 | sdev->dma_dev.device_resume = sprd_dma_resume; |
863 | sdev->dma_dev.device_terminate_all = sprd_dma_terminate_all; | 920 | sdev->dma_dev.device_terminate_all = sprd_dma_terminate_all; |
diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h new file mode 100644 index 000000000000..b0115e340fbc --- /dev/null +++ b/include/linux/dma/sprd-dma.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | |||
3 | #ifndef _SPRD_DMA_H_ | ||
4 | #define _SPRD_DMA_H_ | ||
5 | |||
6 | #define SPRD_DMA_REQ_SHIFT 16 | ||
7 | #define SPRD_DMA_FLAGS(req_mode, int_type) \ | ||
8 | ((req_mode) << SPRD_DMA_REQ_SHIFT | (int_type)) | ||
9 | |||
10 | /* | ||
11 | * enum sprd_dma_req_mode: define the DMA request mode | ||
12 | * @SPRD_DMA_FRAG_REQ: fragment request mode | ||
13 | * @SPRD_DMA_BLK_REQ: block request mode | ||
14 | * @SPRD_DMA_TRANS_REQ: transaction request mode | ||
15 | * @SPRD_DMA_LIST_REQ: link-list request mode | ||
16 | * | ||
17 | * We have 4 types request mode: fragment mode, block mode, transaction mode | ||
18 | * and linklist mode. One transaction can contain several blocks, one block can | ||
19 | * contain several fragments. Link-list mode means we can save several DMA | ||
20 | * configuration into one reserved memory, then DMA can fetch each DMA | ||
21 | * configuration automatically to start transfer. | ||
22 | */ | ||
23 | enum sprd_dma_req_mode { | ||
24 | SPRD_DMA_FRAG_REQ, | ||
25 | SPRD_DMA_BLK_REQ, | ||
26 | SPRD_DMA_TRANS_REQ, | ||
27 | SPRD_DMA_LIST_REQ, | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | * enum sprd_dma_int_type: define the DMA interrupt type | ||
32 | * @SPRD_DMA_NO_INT: do not need generate DMA interrupts. | ||
33 | * @SPRD_DMA_FRAG_INT: fragment done interrupt when one fragment request | ||
34 | * is done. | ||
35 | * @SPRD_DMA_BLK_INT: block done interrupt when one block request is done. | ||
36 | * @SPRD_DMA_BLK_FRAG_INT: block and fragment interrupt when one fragment | ||
37 | * or one block request is done. | ||
38 | * @SPRD_DMA_TRANS_INT: tansaction done interrupt when one transaction | ||
39 | * request is done. | ||
40 | * @SPRD_DMA_TRANS_FRAG_INT: transaction and fragment interrupt when one | ||
41 | * transaction request or fragment request is done. | ||
42 | * @SPRD_DMA_TRANS_BLK_INT: transaction and block interrupt when one | ||
43 | * transaction request or block request is done. | ||
44 | * @SPRD_DMA_LIST_INT: link-list done interrupt when one link-list request | ||
45 | * is done. | ||
46 | * @SPRD_DMA_CFGERR_INT: configure error interrupt when configuration is | ||
47 | * incorrect. | ||
48 | */ | ||
49 | enum sprd_dma_int_type { | ||
50 | SPRD_DMA_NO_INT, | ||
51 | SPRD_DMA_FRAG_INT, | ||
52 | SPRD_DMA_BLK_INT, | ||
53 | SPRD_DMA_BLK_FRAG_INT, | ||
54 | SPRD_DMA_TRANS_INT, | ||
55 | SPRD_DMA_TRANS_FRAG_INT, | ||
56 | SPRD_DMA_TRANS_BLK_INT, | ||
57 | SPRD_DMA_LIST_INT, | ||
58 | SPRD_DMA_CFGERR_INT, | ||
59 | }; | ||
60 | |||
61 | #endif | ||