[PATCH 08/18] dmaengine: PL08x: Add cyclic transfer support
From: Alban Bedel Many audio interface drivers require support of cyclic transfers to work correctly, for example Samsung ASoC DMA driver. This patch adds support for cyclic transfers to the amba-pl08x driver. Signed-off-by: Alban Bedel [tfiga: Rebase and slightly beautify the original patch.] Signed-off-by: Tomasz Figa Acked-by: Linus Walleij --- drivers/dma/amba-pl08x.c | 147 +-- 1 file changed, 118 insertions(+), 29 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 6b9cba2..cd29434 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -173,6 +173,7 @@ struct pl08x_sg { * @ccfg: config reg values for current txd * @done: this marks completed descriptors, which should not have their * mux released. + * @cyclic: indicate cyclic transfers */ struct pl08x_txd { struct virt_dma_desc vd; @@ -187,6 +188,7 @@ struct pl08x_txd { */ u32 ccfg; bool done; + bool cyclic; }; /** @@ -574,9 +576,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]); /* -* A LLI pointer of 0 terminates the LLI list +* A LLI pointer going backward terminates the LLI list */ - if (!llis_va[PL080_LLI_LLI]) + if (llis_va[PL080_LLI_LLI] <= clli) break; } @@ -1125,10 +1127,16 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, llis_va = txd->llis_va; last_lli = llis_va + (num_llis - 1) * pl08x->lli_words; - /* The final LLI terminates the LLI. */ - last_lli[PL080_LLI_LLI] = 0; - /* The final LLI element shall also fire an interrupt. */ - last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN; + + if (txd->cyclic) { + /* Link back to the first LLI. */ + last_lli[PL080_LLI_LLI] = txd->llis_bus | bd.lli_bus; + } else { + /* The final LLI terminates the LLI. */ + last_lli[PL080_LLI_LLI] = 0; + /* The final LLI element shall also fire an interrupt. */ + last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN; + } pl08x_dump_lli(pl08x, llis_va, num_llis); @@ -1513,25 +1521,19 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( return vchan_tx_prep(>vc, >vd, flags); } -static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) +static struct pl08x_txd *pl08x_init_txd( + struct dma_chan *chan, + enum dma_transfer_direction direction, + dma_addr_t *slave_addr) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; - struct pl08x_sg *dsg; - struct scatterlist *sg; enum dma_slave_buswidth addr_width; - dma_addr_t slave_addr; int ret, tmp; u8 src_buses, dst_buses; u32 maxburst, cctl; - dev_dbg(>adev->dev, "%s prepare transaction of %d bytes from %s\n", - __func__, sg_dma_len(sgl), plchan->name); - txd = pl08x_get_txd(plchan); if (!txd) { dev_err(>adev->dev, "%s no txd\n", __func__); @@ -1545,14 +1547,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( */ if (direction == DMA_MEM_TO_DEV) { cctl = PL080_CONTROL_SRC_INCR; - slave_addr = plchan->cfg.dst_addr; + *slave_addr = plchan->cfg.dst_addr; addr_width = plchan->cfg.dst_addr_width; maxburst = plchan->cfg.dst_maxburst; src_buses = pl08x->mem_buses; dst_buses = plchan->cd->periph_buses; } else if (direction == DMA_DEV_TO_MEM) { cctl = PL080_CONTROL_DST_INCR; - slave_addr = plchan->cfg.src_addr; + *slave_addr = plchan->cfg.src_addr; addr_width = plchan->cfg.src_addr_width; maxburst = plchan->cfg.src_maxburst; src_buses = plchan->cd->periph_buses; @@ -1601,24 +1603,107 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( else txd->ccfg |= plchan->signal << PL080_CONFIG_SRC_SEL_SHIFT; + return txd; +} + +static int pl08x_tx_add_sg(struct pl08x_txd *txd, + enum dma_transfer_direction direction, + dma_addr_t slave_addr, + dma_addr_t buf_addr, + unsigned int len) +{ + struct pl08x_sg *dsg; + + dsg = kzalloc(sizeof(struct
[PATCH 08/18] dmaengine: PL08x: Add cyclic transfer support
From: Alban Bedel alban.be...@avionic-design.de Many audio interface drivers require support of cyclic transfers to work correctly, for example Samsung ASoC DMA driver. This patch adds support for cyclic transfers to the amba-pl08x driver. Signed-off-by: Alban Bedel alban.be...@avionic-design.de [tfiga: Rebase and slightly beautify the original patch.] Signed-off-by: Tomasz Figa tomasz.f...@gmail.com Acked-by: Linus Walleij linus.wall...@linaro.org --- drivers/dma/amba-pl08x.c | 147 +-- 1 file changed, 118 insertions(+), 29 deletions(-) diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 6b9cba2..cd29434 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -173,6 +173,7 @@ struct pl08x_sg { * @ccfg: config reg values for current txd * @done: this marks completed descriptors, which should not have their * mux released. + * @cyclic: indicate cyclic transfers */ struct pl08x_txd { struct virt_dma_desc vd; @@ -187,6 +188,7 @@ struct pl08x_txd { */ u32 ccfg; bool done; + bool cyclic; }; /** @@ -574,9 +576,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]); /* -* A LLI pointer of 0 terminates the LLI list +* A LLI pointer going backward terminates the LLI list */ - if (!llis_va[PL080_LLI_LLI]) + if (llis_va[PL080_LLI_LLI] = clli) break; } @@ -1125,10 +1127,16 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, llis_va = txd-llis_va; last_lli = llis_va + (num_llis - 1) * pl08x-lli_words; - /* The final LLI terminates the LLI. */ - last_lli[PL080_LLI_LLI] = 0; - /* The final LLI element shall also fire an interrupt. */ - last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN; + + if (txd-cyclic) { + /* Link back to the first LLI. */ + last_lli[PL080_LLI_LLI] = txd-llis_bus | bd.lli_bus; + } else { + /* The final LLI terminates the LLI. */ + last_lli[PL080_LLI_LLI] = 0; + /* The final LLI element shall also fire an interrupt. */ + last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN; + } pl08x_dump_lli(pl08x, llis_va, num_llis); @@ -1513,25 +1521,19 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( return vchan_tx_prep(plchan-vc, txd-vd, flags); } -static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) +static struct pl08x_txd *pl08x_init_txd( + struct dma_chan *chan, + enum dma_transfer_direction direction, + dma_addr_t *slave_addr) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan-host; struct pl08x_txd *txd; - struct pl08x_sg *dsg; - struct scatterlist *sg; enum dma_slave_buswidth addr_width; - dma_addr_t slave_addr; int ret, tmp; u8 src_buses, dst_buses; u32 maxburst, cctl; - dev_dbg(pl08x-adev-dev, %s prepare transaction of %d bytes from %s\n, - __func__, sg_dma_len(sgl), plchan-name); - txd = pl08x_get_txd(plchan); if (!txd) { dev_err(pl08x-adev-dev, %s no txd\n, __func__); @@ -1545,14 +1547,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( */ if (direction == DMA_MEM_TO_DEV) { cctl = PL080_CONTROL_SRC_INCR; - slave_addr = plchan-cfg.dst_addr; + *slave_addr = plchan-cfg.dst_addr; addr_width = plchan-cfg.dst_addr_width; maxburst = plchan-cfg.dst_maxburst; src_buses = pl08x-mem_buses; dst_buses = plchan-cd-periph_buses; } else if (direction == DMA_DEV_TO_MEM) { cctl = PL080_CONTROL_DST_INCR; - slave_addr = plchan-cfg.src_addr; + *slave_addr = plchan-cfg.src_addr; addr_width = plchan-cfg.src_addr_width; maxburst = plchan-cfg.src_maxburst; src_buses = plchan-cd-periph_buses; @@ -1601,24 +1603,107 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( else txd-ccfg |= plchan-signal PL080_CONFIG_SRC_SEL_SHIFT; + return txd; +} + +static int pl08x_tx_add_sg(struct pl08x_txd *txd, + enum dma_transfer_direction direction, + dma_addr_t slave_addr, + dma_addr_t buf_addr, +