linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 1/3] dmaengine: sun6i: Set default maxburst size and bus width
  2016-04-28 15:19 [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Jean-Francois Moine
@ 2016-04-28 15:07 ` Jean-Francois Moine
  2016-04-28 15:09 ` [PATCH v6 2/3] dmaengine: sun6i: Remove useless check Jean-Francois Moine
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Jean-Francois Moine @ 2016-04-28 15:07 UTC (permalink / raw)
  To: linux-arm-kernel

Some DMA clients, as audio, don't set the maxburst size and bus width
on the memory side when starting DMA transfers.
This patch prevents such transfers to be aborted by providing system
default values to the lacking ones.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
---
 drivers/dma/sun6i-dma.c | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index b08245e..cd436c6 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -470,10 +470,30 @@ static int set_config(struct sun6i_dma_dev *sdev,
 {
 	s8 src_width, dst_width, src_burst, dst_burst;
 
-	src_burst = convert_burst(sconfig->src_maxburst);
-	src_width = convert_buswidth(sconfig->src_addr_width);
-	dst_burst = convert_burst(sconfig->dst_maxburst);
-	dst_width = convert_buswidth(sconfig->dst_addr_width);
+	switch (direction) {
+	case DMA_MEM_TO_DEV:
+		src_burst = convert_burst(sconfig->src_maxburst ?
+					sconfig->src_maxburst : 8);
+		src_width = convert_buswidth(sconfig->src_addr_width !=
+						DMA_SLAVE_BUSWIDTH_UNDEFINED ?
+				sconfig->src_addr_width :
+				DMA_SLAVE_BUSWIDTH_4_BYTES);
+		dst_burst = convert_burst(sconfig->dst_maxburst);
+		dst_width = convert_buswidth(sconfig->dst_addr_width);
+		break;
+	case DMA_DEV_TO_MEM:
+		src_burst = convert_burst(sconfig->src_maxburst);
+		src_width = convert_buswidth(sconfig->src_addr_width);
+		dst_burst = convert_burst(sconfig->dst_maxburst ?
+					sconfig->dst_maxburst : 8);
+		dst_width = convert_buswidth(sconfig->dst_addr_width !=
+						DMA_SLAVE_BUSWIDTH_UNDEFINED ?
+				sconfig->dst_addr_width :
+				DMA_SLAVE_BUSWIDTH_4_BYTES);
+		break;
+	default:
+		return -EINVAL;
+	}
 
 	if (src_burst < 0)
 		return src_burst;
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v6 2/3] dmaengine: sun6i: Remove useless check
  2016-04-28 15:19 [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Jean-Francois Moine
  2016-04-28 15:07 ` [PATCH v6 1/3] dmaengine: sun6i: Set default maxburst size and bus width Jean-Francois Moine
@ 2016-04-28 15:09 ` Jean-Francois Moine
  2016-04-28 15:13 ` [PATCH v6 3/3] dmaengine: sun6i: Add cyclic capability Jean-Francois Moine
  2016-05-02 10:29 ` [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Vinod Koul
  3 siblings, 0 replies; 5+ messages in thread
From: Jean-Francois Moine @ 2016-04-28 15:09 UTC (permalink / raw)
  To: linux-arm-kernel

The transfer direction is now checked in set_config.
There is no need to check it twice.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
---
 drivers/dma/sun6i-dma.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index cd436c6..80e426d 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -585,11 +585,6 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
 	if (!sgl)
 		return NULL;
 
-	if (!is_slave_direction(dir)) {
-		dev_err(chan2dev(chan), "Invalid DMA direction\n");
-		return NULL;
-	}
-
 	ret = set_config(sdev, sconfig, dir, &lli_cfg);
 	if (ret) {
 		dev_err(chan2dev(chan), "Invalid DMA configuration\n");
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v6 3/3] dmaengine: sun6i: Add cyclic capability
  2016-04-28 15:19 [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Jean-Francois Moine
  2016-04-28 15:07 ` [PATCH v6 1/3] dmaengine: sun6i: Set default maxburst size and bus width Jean-Francois Moine
  2016-04-28 15:09 ` [PATCH v6 2/3] dmaengine: sun6i: Remove useless check Jean-Francois Moine
@ 2016-04-28 15:13 ` Jean-Francois Moine
  2016-05-02 10:29 ` [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Vinod Koul
  3 siblings, 0 replies; 5+ messages in thread
From: Jean-Francois Moine @ 2016-04-28 15:13 UTC (permalink / raw)
  To: linux-arm-kernel

DMA cyclic transfers are required by audio streaming.

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
---
 drivers/dma/sun6i-dma.c | 129 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 122 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 80e426d..5065ca4 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -146,6 +146,8 @@ struct sun6i_vchan {
 	struct dma_slave_config	cfg;
 	struct sun6i_pchan	*phy;
 	u8			port;
+	u8			irq_type;
+	bool			cyclic;
 };
 
 struct sun6i_dma_dev {
@@ -254,6 +256,30 @@ static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width)
 	return addr_width >> 1;
 }
 
+static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
+{
+	struct sun6i_desc *txd = pchan->desc;
+	struct sun6i_dma_lli *lli;
+	size_t bytes;
+	dma_addr_t pos;
+
+	pos = readl(pchan->base + DMA_CHAN_LLI_ADDR);
+	bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+
+	if (pos == LLI_LAST_ITEM)
+		return bytes;
+
+	for (lli = txd->v_lli; lli; lli = lli->v_lli_next) {
+		if (lli->p_lli_next == pos) {
+			for (lli = lli->v_lli_next; lli; lli = lli->v_lli_next)
+				bytes += lli->len;
+			break;
+		}
+	}
+
+	return bytes;
+}
+
 static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
 			       struct sun6i_dma_lli *next,
 			       dma_addr_t next_phy,
@@ -342,8 +368,12 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
 	irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
 	irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
 
+	vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE;
+
 	irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
-	irq_val |= DMA_IRQ_QUEUE << (irq_offset * DMA_IRQ_CHAN_WIDTH);
+	irq_val &= ~((DMA_IRQ_HALF | DMA_IRQ_PKG | DMA_IRQ_QUEUE) <<
+			(irq_offset * DMA_IRQ_CHAN_WIDTH));
+	irq_val |= vchan->irq_type << (irq_offset * DMA_IRQ_CHAN_WIDTH);
 	writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
 
 	writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
@@ -440,11 +470,12 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
 		writel(status, sdev->base + DMA_IRQ_STAT(i));
 
 		for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) {
-			if (status & DMA_IRQ_QUEUE) {
-				pchan = sdev->pchans + j;
-				vchan = pchan->vchan;
-
-				if (vchan) {
+			pchan = sdev->pchans + j;
+			vchan = pchan->vchan;
+			if (vchan && (status & vchan->irq_type)) {
+				if (vchan->cyclic) {
+					vchan_cyclic_callback(&pchan->desc->vd);
+				} else {
 					spin_lock(&vchan->vc.lock);
 					vchan_cookie_complete(&pchan->desc->vd);
 					pchan->done = pchan->desc;
@@ -650,6 +681,78 @@ err_lli_free:
 	return NULL;
 }
 
+static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
+					struct dma_chan *chan,
+					dma_addr_t buf_addr,
+					size_t buf_len,
+					size_t period_len,
+					enum dma_transfer_direction dir,
+					unsigned long flags)
+{
+	struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+	struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+	struct dma_slave_config *sconfig = &vchan->cfg;
+	struct sun6i_dma_lli *v_lli, *prev = NULL;
+	struct sun6i_desc *txd;
+	dma_addr_t p_lli;
+	u32 lli_cfg;
+	unsigned int i, periods = buf_len / period_len;
+	int ret;
+
+	ret = set_config(sdev, sconfig, dir, &lli_cfg);
+	if (ret) {
+		dev_err(chan2dev(chan), "Invalid DMA configuration\n");
+		return NULL;
+	}
+
+	txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+	if (!txd)
+		return NULL;
+
+	for (i = 0; i < periods; i++) {
+		v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+		if (!v_lli) {
+			dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
+			goto err_lli_free;
+		}
+
+		v_lli->len = period_len;
+		v_lli->para = NORMAL_WAIT;
+
+		if (dir == DMA_MEM_TO_DEV) {
+			v_lli->src = buf_addr + period_len * i;
+			v_lli->dst = sconfig->dst_addr;
+			v_lli->cfg = lli_cfg |
+				DMA_CHAN_CFG_DST_IO_MODE |
+				DMA_CHAN_CFG_SRC_LINEAR_MODE |
+				DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
+				DMA_CHAN_CFG_DST_DRQ(vchan->port);
+		} else {
+			v_lli->src = sconfig->src_addr;
+			v_lli->dst = buf_addr + period_len * i;
+			v_lli->cfg = lli_cfg |
+				DMA_CHAN_CFG_DST_LINEAR_MODE |
+				DMA_CHAN_CFG_SRC_IO_MODE |
+				DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
+				DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+		}
+
+		prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
+	}
+
+	prev->p_lli_next = txd->p_lli;		/* cyclic list */
+
+	vchan->cyclic = true;
+
+	return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_lli_free:
+	for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
+		dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
+	kfree(txd);
+	return NULL;
+}
+
 static int sun6i_dma_config(struct dma_chan *chan,
 			    struct dma_slave_config *config)
 {
@@ -719,6 +822,16 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
 
 	spin_lock_irqsave(&vchan->vc.lock, flags);
 
+	if (vchan->cyclic) {
+		vchan->cyclic = false;
+		if (pchan && pchan->desc) {
+			struct virt_dma_desc *vd = &pchan->desc->vd;
+			struct virt_dma_chan *vc = &vchan->vc;
+
+			list_add_tail(&vd->node, &vc->desc_completed);
+		}
+	}
+
 	vchan_get_all_descriptors(&vchan->vc, &head);
 
 	if (pchan) {
@@ -766,7 +879,7 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
 	} else if (!pchan || !pchan->desc) {
 		bytes = 0;
 	} else {
-		bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+		bytes = sun6i_get_chan_size(pchan);
 	}
 
 	spin_unlock_irqrestore(&vchan->vc.lock, flags);
@@ -970,6 +1083,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
 	dma_cap_set(DMA_PRIVATE, sdc->slave.cap_mask);
 	dma_cap_set(DMA_MEMCPY, sdc->slave.cap_mask);
 	dma_cap_set(DMA_SLAVE, sdc->slave.cap_mask);
+	dma_cap_set(DMA_CYCLIC, sdc->slave.cap_mask);
 
 	INIT_LIST_HEAD(&sdc->slave.channels);
 	sdc->slave.device_free_chan_resources	= sun6i_dma_free_chan_resources;
@@ -977,6 +1091,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
 	sdc->slave.device_issue_pending		= sun6i_dma_issue_pending;
 	sdc->slave.device_prep_slave_sg		= sun6i_dma_prep_slave_sg;
 	sdc->slave.device_prep_dma_memcpy	= sun6i_dma_prep_dma_memcpy;
+	sdc->slave.device_prep_dma_cyclic	= sun6i_dma_prep_dma_cyclic;
 	sdc->slave.copy_align			= DMAENGINE_ALIGN_4_BYTES;
 	sdc->slave.device_config		= sun6i_dma_config;
 	sdc->slave.device_pause			= sun6i_dma_pause;
-- 
2.8.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers
@ 2016-04-28 15:19 Jean-Francois Moine
  2016-04-28 15:07 ` [PATCH v6 1/3] dmaengine: sun6i: Set default maxburst size and bus width Jean-Francois Moine
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Jean-Francois Moine @ 2016-04-28 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series contains most of the remaining changes to
the sun6i DMA driver for audio streaming (tested in
a Allwinner H3 - Orange PI 2).
The lacking patch (Add 4 as a possible burst value for H3) will be
submitted when a consensus with Maxime Ripard will be found.
This series is based on the previous patches applied by Vinod Koul.

v6
 - check the transfer direction in all cases (Vinod Koul)
 - a new patch about useless check has been added
 - the applied patch has been removed from this series
v5
 - fix checkpatch error (Vinod Koul)
v4
 - remove 'Add 4 as a possible burst value for H3'
	(no consensus yet)
 - remove 'Simplify some macros' (Maxime Ripard)
 - remove 'Compact a bit some config constants' (not critical)
 - split 'lli setting' into 'simplify' and 'default burst and bus width'
	(Maxime Ripard)
v3
 - do some optimizations
 - add a check about the maxburst value '4' (Maxime Ripard)
 - remove the driver fixes
v2 (comments from Vinod Koul and Sergei Shtylyov - thanks)
 - typo fixes
 - change some comments
 - better handling of burst and bus width
 - remove useless code in the cyclic capability patch

Jean-Francois Moine (3):
  dmaengine: sun6i: Set default maxburst size and bus width
  dmaengine: sun6i: Remove useless check
  dmaengine: sun6i: Add cyclic capability

 drivers/dma/sun6i-dma.c | 162 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 146 insertions(+), 16 deletions(-)

-- 
2.8.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers
  2016-04-28 15:19 [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Jean-Francois Moine
                   ` (2 preceding siblings ...)
  2016-04-28 15:13 ` [PATCH v6 3/3] dmaengine: sun6i: Add cyclic capability Jean-Francois Moine
@ 2016-05-02 10:29 ` Vinod Koul
  3 siblings, 0 replies; 5+ messages in thread
From: Vinod Koul @ 2016-05-02 10:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 28, 2016 at 05:19:11PM +0200, Jean-Francois Moine wrote:
> This patch series contains most of the remaining changes to
> the sun6i DMA driver for audio streaming (tested in
> a Allwinner H3 - Orange PI 2).
> The lacking patch (Add 4 as a possible burst value for H3) will be
> submitted when a consensus with Maxime Ripard will be found.
> This series is based on the previous patches applied by Vinod Koul.

Applied, thanks

-- 
~Vinod

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-05-02 10:29 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-28 15:19 [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Jean-Francois Moine
2016-04-28 15:07 ` [PATCH v6 1/3] dmaengine: sun6i: Set default maxburst size and bus width Jean-Francois Moine
2016-04-28 15:09 ` [PATCH v6 2/3] dmaengine: sun6i: Remove useless check Jean-Francois Moine
2016-04-28 15:13 ` [PATCH v6 3/3] dmaengine: sun6i: Add cyclic capability Jean-Francois Moine
2016-05-02 10:29 ` [PATCH v6 0/3] dmaengine: sun6i: Upgrade for audio transfers Vinod Koul

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).