[PATCH 08/18] dmaengine: PL08x: Add cyclic transfer support

2013-08-11 Thread Tomasz Figa
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

2013-08-11 Thread Tomasz Figa
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,
+