From: tomasz.figa@gmail.com (Tomasz Figa)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC PATCH 08/11] dmaengine: PL08x: Add cyclic transfer support
Date: Sun, 16 Jun 2013 22:54:15 +0200 [thread overview]
Message-ID: <1371416058-22047-9-git-send-email-tomasz.figa@gmail.com> (raw)
In-Reply-To: <1371416058-22047-1-git-send-email-tomasz.figa@gmail.com>
From: Alban Bedel <alban.bedel@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.bedel@avionic-design.de>
Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
---
drivers/dma/amba-pl08x.c | 181 +++++++++++++++++++++++++++++++++++------------
1 file changed, 136 insertions(+), 45 deletions(-)
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index bb3b36b..210a893 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -184,6 +184,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;
@@ -198,6 +199,8 @@ struct pl08x_txd {
*/
u32 ccfg;
bool done;
+
+ bool cyclic;
};
/**
@@ -561,9 +564,9 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
bytes += get_bytes_in_cctl(llis_va[index].cctl);
/*
- * A LLI pointer of 0 terminates the LLI list
++ * A LLI pointer going backward terminates the LLI list
*/
- if (!llis_va[index].lli)
+ if (llis_va[index].lli <= clli)
break;
}
@@ -1075,10 +1078,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
}
llis_va = txd->llis_va;
- /* The final LLI terminates the LLI. */
- llis_va[num_llis - 1].lli = 0;
- /* The final LLI element shall also fire an interrupt. */
- llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+ if (txd->cyclic) {
+ /* Link back to the first LLI. */
+ llis_va[num_llis - 1].lli = txd->llis_bus | bd.lli_bus;
+ } else {
+ /* The final LLI terminates the LLI. */
+ llis_va[num_llis - 1].lli = 0;
+ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+ }
#ifdef VERBOSE_DEBUG
{
@@ -1470,25 +1477,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__);
@@ -1502,14 +1503,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;
@@ -1558,24 +1559,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 pl08x_sg), GFP_NOWAIT);
+ if (!dsg)
+ return -ENOMEM;
+
+ list_add_tail(&dsg->node, &txd->dsg_list);
+
+ dsg->len = len;
+ if (direction == DMA_MEM_TO_DEV) {
+ dsg->src_addr = buf_addr;
+ dsg->dst_addr = slave_addr;
+ } else {
+ dsg->src_addr = slave_addr;
+ dsg->dst_addr = buf_addr;
+ }
+
+ return 0;
+}
+
+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)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ struct scatterlist *sg;
+ int ret, tmp;
+ dma_addr_t slave_addr;
+
+ dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
+ __func__, sg_dma_len(sgl), plchan->name);
+
+ txd = pl08x_init_txd(chan, direction, &slave_addr);
+ if (!txd)
+ return NULL;
+
for_each_sg(sgl, sg, sg_len, tmp) {
- dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
- if (!dsg) {
+ ret = pl08x_tx_add_sg(txd, direction, slave_addr,
+ sg_dma_address(sg),
+ sg_dma_len(sg));
+ if (ret) {
pl08x_release_mux(plchan);
pl08x_free_txd(pl08x, txd);
dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n",
__func__);
return NULL;
}
- list_add_tail(&dsg->node, &txd->dsg_list);
+ }
- dsg->len = sg_dma_len(sg);
- if (direction == DMA_MEM_TO_DEV) {
- dsg->src_addr = sg_dma_address(sg);
- dsg->dst_addr = slave_addr;
- } else {
- dsg->src_addr = slave_addr;
- dsg->dst_addr = sg_dma_address(sg);
+ ret = pl08x_fill_llis_for_desc(plchan->host, txd);
+ if (!ret) {
+ pl08x_release_mux(plchan);
+ pl08x_free_txd(pl08x, txd);
+ return NULL;
+ }
+
+ return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ int ret, tmp;
+ dma_addr_t slave_addr;
+
+ dev_dbg(&pl08x->adev->dev,
+ "%s prepare cyclic transaction of %d/%d bytes %s %s\n",
+ __func__, period_len, buf_len,
+ direction == DMA_MEM_TO_DEV ? "to" : "from",
+ plchan->name);
+
+ txd = pl08x_init_txd(chan, direction, &slave_addr);
+ if (!txd)
+ return NULL;
+
+ txd->cyclic = true;
+ txd->cctl |= PL080_CONTROL_TC_IRQ_EN;
+ for (tmp = 0 ; tmp < buf_len ; tmp += period_len) {
+ ret = pl08x_tx_add_sg(txd, direction, slave_addr,
+ buf_addr + tmp, period_len);
+ if (ret) {
+ pl08x_release_mux(plchan);
+ pl08x_free_txd(pl08x, txd);
+ return NULL;
}
}
@@ -1719,23 +1803,28 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
spin_lock(&plchan->vc.lock);
tx = plchan->at;
if (tx) {
- plchan->at = NULL;
- /*
- * This descriptor is done, release its mux
- * reservation.
- */
- pl08x_release_mux(plchan);
- tx->done = true;
- vchan_cookie_complete(&tx->vd);
-
- /*
- * And start the next descriptor (if any),
- * otherwise free this channel.
- */
- if (vchan_next_desc(&plchan->vc))
- pl08x_start_next_txd(plchan);
- else
- pl08x_phy_free(plchan);
+ if (tx->cyclic) {
+ vchan_cyclic_callback(&tx->vd);
+ } else {
+ plchan->at = NULL;
+ /*
+ * This descriptor is done, release
+ * its mux reservation.
+ */
+ pl08x_release_mux(plchan);
+ tx->done = true;
+ vchan_cookie_complete(&tx->vd);
+
+ /*
+ * And start the next descriptor
+ * (if any), otherwise free this
+ * channel.
+ */
+ if (vchan_next_desc(&plchan->vc))
+ pl08x_start_next_txd(plchan);
+ else
+ pl08x_phy_free(plchan);
+ }
}
spin_unlock(&plchan->vc.lock);
@@ -1939,6 +2028,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
/* Initialize slave engine */
dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
+ dma_cap_set(DMA_CYCLIC, pl08x->slave.cap_mask);
pl08x->slave.dev = &adev->dev;
pl08x->slave.device_alloc_chan_resources = pl08x_alloc_chan_resources;
pl08x->slave.device_free_chan_resources = pl08x_free_chan_resources;
@@ -1946,6 +2036,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->slave.device_tx_status = pl08x_dma_tx_status;
pl08x->slave.device_issue_pending = pl08x_issue_pending;
pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
+ pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic;
pl08x->slave.device_control = pl08x_control;
/* Get the platform data */
--
1.8.2.1
next prev parent reply other threads:[~2013-06-16 20:54 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-16 20:54 [RFC PATCH 00/11] ARM: s3c64xx: Let amba-pl08x driver handle DMA Tomasz Figa
2013-06-16 20:54 ` [RFC PATCH 01/11] dma: amba-pl08x: Use bitmap to pass variant specific quirks Tomasz Figa
2013-06-17 13:25 ` Linus Walleij
2013-06-17 18:48 ` Russell King - ARM Linux
2013-06-17 18:56 ` Tomasz Figa
2013-06-18 7:47 ` Linus Walleij
2013-06-18 13:33 ` Arnd Bergmann
2013-06-16 20:54 ` [RFC PATCH 02/11] dma: amba-pl08x: Refactor pl08x_getbytes_chan() to lower indentation Tomasz Figa
2013-06-17 13:29 ` Linus Walleij
2013-06-16 20:54 ` [RFC PATCH 03/11] dma: amba-pl08x: Add support for different offset of CONFIG register Tomasz Figa
2013-06-17 13:31 ` Linus Walleij
2013-06-17 18:52 ` Russell King - ARM Linux
2013-06-17 19:02 ` Tomasz Figa
2013-06-16 20:54 ` [RFC PATCH 04/11] dma: amba-pl08x: Add support for PL080S variant Tomasz Figa
2013-06-17 13:39 ` Linus Walleij
2013-06-17 18:22 ` Tomasz Figa
2013-06-16 20:54 ` [RFC PATCH 05/11] dma: amba-pl08x: Add support for different maximum transfer size Tomasz Figa
2013-06-17 13:42 ` Linus Walleij
2013-06-17 18:27 ` Tomasz Figa
2013-06-16 20:54 ` [RFC PATCH 06/11] dma: amba-pl08x: Keep LLIs aligned to 4-word boundary Tomasz Figa
2013-06-17 13:51 ` Linus Walleij
2013-06-17 18:28 ` Tomasz Figa
2013-06-17 19:01 ` Russell King - ARM Linux
2013-06-16 20:54 ` [RFC PATCH 07/11] dmaengine: PL08x: Fix reading the byte count in cctl Tomasz Figa
2013-06-17 13:53 ` Linus Walleij
2013-06-17 18:32 ` Tomasz Figa
2013-06-17 19:03 ` Russell King - ARM Linux
2013-06-16 20:54 ` Tomasz Figa [this message]
2013-06-17 13:57 ` [RFC PATCH 08/11] dmaengine: PL08x: Add cyclic transfer support Linus Walleij
2013-06-17 18:52 ` Tomasz Figa
2013-06-17 18:56 ` Russell King - ARM Linux
2013-06-16 20:54 ` [RFC PATCH 09/11] spi: s3c64xx: Do not require legacy DMA API in case of S3C64XX Tomasz Figa
2013-06-17 13:59 ` Linus Walleij
2013-06-17 16:06 ` Mark Brown
2013-06-17 19:36 ` Tomasz Figa
2013-06-16 20:54 ` [RFC PATCH 10/11] ASoC: samsung: " Tomasz Figa
2013-06-17 14:01 ` Linus Walleij
2013-06-16 20:54 ` [RFC PATCH 11/11] ARM: s3c64xx: Add support for DMA using generic amba-pl08x driver Tomasz Figa
2013-06-17 14:04 ` Linus Walleij
2013-06-19 18:23 ` Tomasz Figa
2013-06-19 19:50 ` Linus Walleij
2013-06-17 14:06 ` [RFC PATCH 00/11] ARM: s3c64xx: Let amba-pl08x driver handle DMA Linus Walleij
2013-06-17 19:38 ` Tomasz Figa
2013-06-19 17:40 ` Mark Brown
2013-06-19 18:26 ` Tomasz Figa
2013-06-19 19:01 ` Arnd Bergmann
2013-06-19 19:24 ` Mark Brown
2013-06-19 19:22 ` Mark Brown
2013-06-19 19:32 ` Tomasz Figa
2013-06-19 22:48 ` Mark Brown
2013-06-20 9:24 ` Phil Carmody
2013-06-20 10:35 ` Mark Brown
2013-06-20 11:14 ` Phil Carmody
2013-06-21 9:47 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1371416058-22047-9-git-send-email-tomasz.figa@gmail.com \
--to=tomasz.figa@gmail.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).