Actually the generation of the Control Block info follows some simple rules. So handle this with a separate function to avoid open coding for every DMA operation. Another advantage is that we can easier introduce other platforms with different info bits. Signed-off-by: Stefan Wahren <stefan.wahren@xxxxxxxx> --- drivers/dma/bcm2835-dma.c | 51 ++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index adfe6bc..10c9ba2 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -201,6 +201,35 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc( return container_of(t, struct bcm2835_desc, vd.tx); } +static u32 bcm2835_dma_prepare_cb_info(struct bcm2835_chan *c, + enum dma_transfer_direction direction, + bool zero_page) +{ + u32 result; + + if (direction == DMA_MEM_TO_MEM) + return BCM2835_DMA_D_INC | BCM2835_DMA_S_INC; + + result = BCM2835_DMA_WAIT_RESP; + + /* Setup DREQ channel */ + if (c->dreq != 0) + result |= BCM2835_DMA_PER_MAP(c->dreq); + + if (direction == DMA_DEV_TO_MEM) { + result |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; + } else { + result |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; + + /* non-lite channels can write zeroes w/o accessing memory */ + if (zero_page && !c->is_lite_channel) { + result |= BCM2835_DMA_S_IGNORE; + } + } + + return result; +} + static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc) { size_t i; @@ -615,7 +644,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( { struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; - u32 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC; + u32 info = bcm2835_dma_prepare_cb_info(c, DMA_MEM_TO_MEM, false); u32 extra = BCM2835_DMA_INT_EN | BCM2835_DMA_WAIT_RESP; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; @@ -646,7 +675,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; dma_addr_t src = 0, dst = 0; - u32 info = BCM2835_DMA_WAIT_RESP; + u32 info = bcm2835_dma_prepare_cb_info(c, direction, false); u32 extra = BCM2835_DMA_INT_EN; size_t frames; @@ -656,19 +685,14 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg( return NULL; } - if (c->dreq != 0) - info |= BCM2835_DMA_PER_MAP(c->dreq); - if (direction == DMA_DEV_TO_MEM) { if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; src = c->cfg.src_addr; - info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; dst = c->cfg.dst_addr; - info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; } /* count frames in sg list */ @@ -698,7 +722,8 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; dma_addr_t src, dst; - u32 info = BCM2835_DMA_WAIT_RESP; + u32 info = bcm2835_dma_prepare_cb_info(c, direction, + buf_addr == od->zero_page); u32 extra = 0; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; @@ -729,26 +754,16 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( "%s: buffer_length (%zd) is not a multiple of period_len (%zd)\n", __func__, buf_len, period_len); - /* Setup DREQ channel */ - if (c->dreq != 0) - info |= BCM2835_DMA_PER_MAP(c->dreq); - if (direction == DMA_DEV_TO_MEM) { if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; src = c->cfg.src_addr; dst = buf_addr; - info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC; } else { if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) return NULL; dst = c->cfg.dst_addr; src = buf_addr; - info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; - - /* non-lite channels can write zeroes w/o accessing memory */ - if (buf_addr == od->zero_page && !c->is_lite_channel) - info |= BCM2835_DMA_S_IGNORE; } /* calculate number of frames */ -- 2.7.4