diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 32402c2615de..9a31a315dbef 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -99,6 +99,7 @@ /* DMA_CHN_WARP_* register definition */ #define SPRD_DMA_HIGH_ADDR_MASK GENMASK(31, 28) #define SPRD_DMA_LOW_ADDR_MASK GENMASK(31, 0) +#define SPRD_DMA_WRAP_ADDR_MASK GENMASK(27, 0) #define SPRD_DMA_HIGH_ADDR_OFFSET 4 /* SPRD_DMA_CHN_INTC register definition */ @@ -118,6 +119,8 @@ #define SPRD_DMA_SWT_MODE_OFFSET 26 #define SPRD_DMA_REQ_MODE_OFFSET 24 #define SPRD_DMA_REQ_MODE_MASK GENMASK(1, 0) +#define SPRD_DMA_WRAP_SEL_DEST BIT(23) +#define SPRD_DMA_WRAP_EN BIT(22) #define SPRD_DMA_FIX_SEL_OFFSET 21 #define SPRD_DMA_FIX_EN_OFFSET 20 #define SPRD_DMA_LLIST_END BIT(19) @@ -804,6 +807,8 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, temp |= req_mode << SPRD_DMA_REQ_MODE_OFFSET; temp |= fix_mode << SPRD_DMA_FIX_SEL_OFFSET; temp |= fix_en << SPRD_DMA_FIX_EN_OFFSET; + temp |= schan->linklist.wrap_addr ? + SPRD_DMA_WRAP_EN | SPRD_DMA_WRAP_SEL_DEST : 0; temp |= slave_cfg->src_maxburst & SPRD_DMA_FRG_LEN_MASK; hw->frg_len = temp; @@ -831,6 +836,12 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, hw->llist_ptr = lower_32_bits(llist_ptr); hw->src_blk_step = (upper_32_bits(llist_ptr) << SPRD_DMA_LLIST_HIGH_SHIFT) & SPRD_DMA_LLIST_HIGH_MASK; + + if (schan->linklist.wrap_addr) { + hw->wrap_ptr |= schan->linklist.wrap_addr & + SPRD_DMA_WRAP_ADDR_MASK; + hw->wrap_to |= dst & SPRD_DMA_WRAP_ADDR_MASK; + } } else { hw->llist_ptr = 0; hw->src_blk_step = 0; @@ -939,9 +950,11 @@ sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, schan->linklist.phy_addr = ll_cfg->phy_addr; schan->linklist.virt_addr = ll_cfg->virt_addr; + schan->linklist.wrap_addr = ll_cfg->wrap_addr; } else { schan->linklist.phy_addr = 0; schan->linklist.virt_addr = 0; + schan->linklist.wrap_addr = 0; } /* diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h index ab82df64682a..d09c6f6f6da5 100644 --- a/include/linux/dma/sprd-dma.h +++ b/include/linux/dma/sprd-dma.h @@ -118,6 +118,9 @@ enum sprd_dma_int_type { * struct sprd_dma_linklist - DMA link-list address structure * @virt_addr: link-list virtual address to configure link-list node * @phy_addr: link-list physical address to link DMA transfer + * @wrap_addr: the wrap address for link-list mode, which means once the + * transfer address reaches the wrap address, the next transfer address + * will jump to the address specified by wrap_to register. * * The Spreadtrum DMA controller supports the link-list mode, that means slaves * can supply several groups configurations (each configuration represents one @@ -181,6 +184,7 @@ enum sprd_dma_int_type { struct sprd_dma_linklist { unsigned long virt_addr; phys_addr_t phy_addr; + phys_addr_t wrap_addr; }; #endif