linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Add memcpy support for tegra210-adma
@ 2016-09-03  0:32 Nicolin Chen
  2016-09-03  0:32 ` [PATCH v2 1/2] dmaengine: tegra210-adma: Add pre-check for cyclic callback Nicolin Chen
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Nicolin Chen @ 2016-09-03  0:32 UTC (permalink / raw)
  To: vinod.koul, jonathanh
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan

This series of patches add memcpy support for tegra210 ADMA engine.

Changlog
v1->v2 (Suggested by Vinod)
 * PATCH-1: Split the cyclic pre-check to a separate patch
 * PATCH-2: Add ADMA_CH_CTRL_MODE to unify the marcos
 * PATCH-2: Set operation mode depending on cyclic
 * PATCH-2: Add TODO comment at period_len
 * PATCH-2: Revise the commit log

Nicolin Chen (2):
  dmaengine: tegra210-adma: Add pre-check for cyclic callback
  dmaengine: tegra210-adma: Add memcpy support

 drivers/dma/tegra210-adma.c | 98 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 86 insertions(+), 12 deletions(-)

-- 
2.1.4

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

* [PATCH v2 1/2] dmaengine: tegra210-adma: Add pre-check for cyclic callback
  2016-09-03  0:32 [PATCH v2 0/2] Add memcpy support for tegra210-adma Nicolin Chen
@ 2016-09-03  0:32 ` Nicolin Chen
  2016-09-03  0:32 ` [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support Nicolin Chen
  2016-09-06 11:33 ` [PATCH v2 0/2] Add memcpy support for tegra210-adma Jon Hunter
  2 siblings, 0 replies; 10+ messages in thread
From: Nicolin Chen @ 2016-09-03  0:32 UTC (permalink / raw)
  To: vinod.koul, jonathanh
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan

ADMA driver will support more than cyclic type of transaction.
So this patch limits the cyclic callback for the cyclic type
only in order to support other types.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/dma/tegra210-adma.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index 09b46f7..5b5d298 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -111,6 +111,7 @@ struct tegra_adma_desc {
 	size_t				buf_len;
 	size_t				period_len;
 	size_t				num_periods;
+	bool				cyclic;
 };
 
 /*
@@ -408,7 +409,8 @@ static irqreturn_t tegra_adma_isr(int irq, void *dev_id)
 		return IRQ_NONE;
 	}
 
-	vchan_cyclic_callback(&tdc->desc->vd);
+	if (tdc->desc->cyclic)
+		vchan_cyclic_callback(&tdc->desc->vd);
 
 	spin_unlock_irqrestore(&tdc->vc.lock, flags);
 
@@ -557,6 +559,7 @@ static struct dma_async_tx_descriptor *tegra_adma_prep_dma_cyclic(
 	if (!desc)
 		return NULL;
 
+	desc->cyclic = true;
 	desc->buf_len = buf_len;
 	desc->period_len = period_len;
 	desc->num_periods = buf_len / period_len;
-- 
2.1.4

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

* [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support
  2016-09-03  0:32 [PATCH v2 0/2] Add memcpy support for tegra210-adma Nicolin Chen
  2016-09-03  0:32 ` [PATCH v2 1/2] dmaengine: tegra210-adma: Add pre-check for cyclic callback Nicolin Chen
@ 2016-09-03  0:32 ` Nicolin Chen
  2016-09-06 11:52   ` Jon Hunter
  2016-09-06 11:33 ` [PATCH v2 0/2] Add memcpy support for tegra210-adma Jon Hunter
  2 siblings, 1 reply; 10+ messages in thread
From: Nicolin Chen @ 2016-09-03  0:32 UTC (permalink / raw)
  To: vinod.koul, jonathanh
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan

ADMA supports non-flow controlled Memory-to-Memory direction
transactions. So this patch just adds an initial support for
that. It passed a simple dmatest:
        echo dma1chan0 > /sys/module/dmatest/parameters/channel
	echo 1024 > /sys/module/dmatest/parameters/iterations
	echo 0 > /sys/module/dmatest/parameters/dmatest
	echo 1 > /sys/module/dmatest/parameters/run
	dmesg | grep dmatest
Started 1 threads using dma1chan0
dma1chan0-copy0: summary 1024 tests, 0 failures 2054 iops 16520 KB/s (0)

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/dma/tegra210-adma.c | 95 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 83 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index 5b5d298..d62b373 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -42,9 +42,14 @@
 #define ADMA_CH_CTRL_RX_REQ(val)			(((val) & 0xf) << 24)
 #define ADMA_CH_CTRL_RX_REQ_MAX				10
 #define ADMA_CH_CTRL_DIR(val)				(((val) & 0xf) << 12)
+#define ADMA_CH_CTRL_DIR_MEM2MEM			1
 #define ADMA_CH_CTRL_DIR_AHUB2MEM			2
 #define ADMA_CH_CTRL_DIR_MEM2AHUB			4
-#define ADMA_CH_CTRL_MODE_CONTINUOUS			(2 << 8)
+#define ADMA_CH_CTRL_DIR_AHUB2AHUB			8
+#define ADMA_CH_CTRL_MODE(val)				(((val) & 0x7) << 8)
+#define ADMA_CH_CTRL_MODE_ONCE				1
+#define ADMA_CH_CTRL_MODE_CONTINUOUS			2
+#define ADMA_CH_CTRL_MODE_LINKED_LIST			4
 #define ADMA_CH_CTRL_FLOWCTRL_EN			BIT(1)
 
 #define ADMA_CH_CONFIG					0x28
@@ -264,6 +269,9 @@ static int tegra_adma_request_alloc(struct tegra_adma_chan *tdc,
 		}
 		break;
 
+	case DMA_MEM_TO_MEM:
+		break;
+
 	default:
 		dev_WARN(tdma->dev, "channel %s has invalid transfer type\n",
 			 dma_chan_name(&tdc->vc.chan));
@@ -292,6 +300,9 @@ static void tegra_adma_request_free(struct tegra_adma_chan *tdc)
 		clear_bit(tdc->sreq_index, &tdma->rx_requests_reserved);
 		break;
 
+	case DMA_MEM_TO_MEM:
+		break;
+
 	default:
 		dev_WARN(tdma->dev, "channel %s has invalid transfer type\n",
 			 dma_chan_name(&tdc->vc.chan));
@@ -409,8 +420,14 @@ static irqreturn_t tegra_adma_isr(int irq, void *dev_id)
 		return IRQ_NONE;
 	}
 
-	if (tdc->desc->cyclic)
+	if (tdc->desc->cyclic) {
 		vchan_cyclic_callback(&tdc->desc->vd);
+	} else {
+		/* Disable the channel */
+		tdma_ch_write(tdc, ADMA_CH_CMD, 0);
+		vchan_cookie_complete(&tdc->desc->vd);
+		tdc->desc = NULL;
+	}
 
 	spin_unlock_irqrestore(&tdc->vc.lock, flags);
 
@@ -488,42 +505,59 @@ static enum dma_status tegra_adma_tx_status(struct dma_chan *dc,
 static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
 				      struct tegra_adma_desc *desc,
 				      dma_addr_t buf_addr,
+				      dma_addr_t buf_addr2,
 				      enum dma_transfer_direction direction)
 {
 	struct tegra_adma_chan_regs *ch_regs = &desc->ch_regs;
-	unsigned int burst_size, adma_dir;
+	unsigned int num_periods = desc->num_periods;
+	unsigned int burst_size, adma_dir, adma_mode;
 
-	if (desc->num_periods > ADMA_CH_CONFIG_MAX_BUFS)
+	if (num_periods > ADMA_CH_CONFIG_MAX_BUFS)
 		return -EINVAL;
 
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
 		adma_dir = ADMA_CH_CTRL_DIR_MEM2AHUB;
 		burst_size = fls(tdc->sconfig.dst_maxburst);
-		ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(desc->num_periods - 1);
-		ch_regs->ctrl = ADMA_CH_CTRL_TX_REQ(tdc->sreq_index);
+		ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(num_periods - 1);
+		ch_regs->ctrl = ADMA_CH_CTRL_TX_REQ(tdc->sreq_index) |
+				ADMA_CH_CTRL_FLOWCTRL_EN;
 		ch_regs->src_addr = buf_addr;
 		break;
 
 	case DMA_DEV_TO_MEM:
 		adma_dir = ADMA_CH_CTRL_DIR_AHUB2MEM;
 		burst_size = fls(tdc->sconfig.src_maxburst);
-		ch_regs->config = ADMA_CH_CONFIG_TRG_BUF(desc->num_periods - 1);
-		ch_regs->ctrl = ADMA_CH_CTRL_RX_REQ(tdc->sreq_index);
+		ch_regs->config = ADMA_CH_CONFIG_TRG_BUF(num_periods - 1);
+		ch_regs->ctrl = ADMA_CH_CTRL_RX_REQ(tdc->sreq_index) |
+				ADMA_CH_CTRL_FLOWCTRL_EN;
 		ch_regs->trg_addr = buf_addr;
 		break;
 
+	case DMA_MEM_TO_MEM:
+		adma_dir = ADMA_CH_CTRL_DIR_MEM2MEM;
+		burst_size = ADMA_CH_CONFIG_BURST_16;
+		ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(num_periods - 1) |
+				  ADMA_CH_CONFIG_TRG_BUF(num_periods - 1);
+		ch_regs->src_addr = buf_addr;
+		ch_regs->trg_addr = buf_addr2;
+		break;
+
 	default:
 		dev_err(tdc2dev(tdc), "DMA direction is not supported\n");
 		return -EINVAL;
 	}
 
+	if (desc->cyclic)
+		adma_mode = ADMA_CH_CTRL_MODE_CONTINUOUS;
+	else
+		adma_mode = ADMA_CH_CTRL_MODE_ONCE;
+
 	if (!burst_size || burst_size > ADMA_CH_CONFIG_BURST_16)
 		burst_size = ADMA_CH_CONFIG_BURST_16;
 
 	ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir) |
-			 ADMA_CH_CTRL_MODE_CONTINUOUS |
-			 ADMA_CH_CTRL_FLOWCTRL_EN;
+			 ADMA_CH_CTRL_MODE(adma_mode);
 	ch_regs->config |= ADMA_CH_CONFIG_BURST_SIZE(burst_size);
 	ch_regs->config |= ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1);
 	ch_regs->fifo_ctrl = ADMA_CH_FIFO_CTRL_DEFAULT;
@@ -564,7 +598,39 @@ static struct dma_async_tx_descriptor *tegra_adma_prep_dma_cyclic(
 	desc->period_len = period_len;
 	desc->num_periods = buf_len / period_len;
 
-	if (tegra_adma_set_xfer_params(tdc, desc, buf_addr, direction)) {
+	if (tegra_adma_set_xfer_params(tdc, desc, buf_addr, 0, direction)) {
+		kfree(desc);
+		return NULL;
+	}
+
+	return vchan_tx_prep(&tdc->vc, &desc->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *tegra_adma_prep_dma_memcpy(
+	struct dma_chan *dc, dma_addr_t dest, dma_addr_t src,
+	size_t buf_len, unsigned long flags)
+{
+	struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc);
+	struct device *dev = dc->device->dev;
+	struct tegra_adma_desc *desc = NULL;
+
+	dev_dbg(dev, "%s channel: %d src=0x%llx dst=0x%llx len=%zu\n",
+		__func__, dc->chan_id, (unsigned long long)src,
+		(unsigned long long)dest, buf_len);
+
+	if (unlikely(!tdc || !buf_len))
+		return NULL;
+
+	desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
+	if (!desc)
+		return NULL;
+
+	/* TODO: ADMA should support up to 8 chunks or periods */
+	desc->num_periods = 1;
+	desc->buf_len = buf_len;
+	desc->period_len = buf_len;
+
+	if (tegra_adma_set_xfer_params(tdc, desc, src, dest, DMA_MEM_TO_MEM)) {
 		kfree(desc);
 		return NULL;
 	}
@@ -741,6 +807,7 @@ static int tegra_adma_probe(struct platform_device *pdev)
 	dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
 	dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
 	dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask);
+	dma_cap_set(DMA_MEMCPY, tdma->dma_dev.cap_mask);
 
 	tdma->dma_dev.dev = &pdev->dev;
 	tdma->dma_dev.device_alloc_chan_resources =
@@ -749,14 +816,18 @@ static int tegra_adma_probe(struct platform_device *pdev)
 					tegra_adma_free_chan_resources;
 	tdma->dma_dev.device_issue_pending = tegra_adma_issue_pending;
 	tdma->dma_dev.device_prep_dma_cyclic = tegra_adma_prep_dma_cyclic;
+	tdma->dma_dev.device_prep_dma_memcpy = tegra_adma_prep_dma_memcpy;
 	tdma->dma_dev.device_config = tegra_adma_slave_config;
 	tdma->dma_dev.device_tx_status = tegra_adma_tx_status;
 	tdma->dma_dev.device_terminate_all = tegra_adma_terminate_all;
 	tdma->dma_dev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	tdma->dma_dev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
-	tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+	tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
+				   BIT(DMA_MEM_TO_MEM);
 	tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
 
+	tdma->dma_dev.copy_align = DMAENGINE_ALIGN_4_BYTES;
+
 	ret = dma_async_device_register(&tdma->dma_dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "ADMA registration failed: %d\n", ret);
-- 
2.1.4

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

* Re: [PATCH v2 0/2] Add memcpy support for tegra210-adma
  2016-09-03  0:32 [PATCH v2 0/2] Add memcpy support for tegra210-adma Nicolin Chen
  2016-09-03  0:32 ` [PATCH v2 1/2] dmaengine: tegra210-adma: Add pre-check for cyclic callback Nicolin Chen
  2016-09-03  0:32 ` [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support Nicolin Chen
@ 2016-09-06 11:33 ` Jon Hunter
  2016-09-06 12:03   ` Dmitry Osipenko
  2 siblings, 1 reply; 10+ messages in thread
From: Jon Hunter @ 2016-09-06 11:33 UTC (permalink / raw)
  To: Nicolin Chen, vinod.koul
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan


On 03/09/16 01:32, Nicolin Chen wrote:
> This series of patches add memcpy support for tegra210 ADMA engine.

Thanks. Any reason you choose this DMA and not the APB DMA? The APB DMA
is more of a generic DMA and so for memcpy it would seem to be a good
choice and it is available on all Tegras not just Tegra210.

Furthermore, from a power standpoint the ADMA is in the audio power
domain and so using it for memcpy would mean the audio power domain is
turned on. It may not be a big deal for some, but given the APB is in
the CORE domain (always on when not in low-power) it seems like a better
choice for power as well.

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support
  2016-09-03  0:32 ` [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support Nicolin Chen
@ 2016-09-06 11:52   ` Jon Hunter
  2016-09-06 17:21     ` Nicolin Chen
  0 siblings, 1 reply; 10+ messages in thread
From: Jon Hunter @ 2016-09-06 11:52 UTC (permalink / raw)
  To: Nicolin Chen, vinod.koul
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan


On 03/09/16 01:32, Nicolin Chen wrote:
> ADMA supports non-flow controlled Memory-to-Memory direction
> transactions. So this patch just adds an initial support for
> that. It passed a simple dmatest:
>         echo dma1chan0 > /sys/module/dmatest/parameters/channel
> 	echo 1024 > /sys/module/dmatest/parameters/iterations
> 	echo 0 > /sys/module/dmatest/parameters/dmatest
> 	echo 1 > /sys/module/dmatest/parameters/run
> 	dmesg | grep dmatest
> Started 1 threads using dma1chan0
> dma1chan0-copy0: summary 1024 tests, 0 failures 2054 iops 16520 KB/s (0)
> 
> Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
> ---
>  drivers/dma/tegra210-adma.c | 95 +++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 83 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
> index 5b5d298..d62b373 100644
> --- a/drivers/dma/tegra210-adma.c
> +++ b/drivers/dma/tegra210-adma.c
> @@ -42,9 +42,14 @@
>  #define ADMA_CH_CTRL_RX_REQ(val)			(((val) & 0xf) << 24)
>  #define ADMA_CH_CTRL_RX_REQ_MAX				10
>  #define ADMA_CH_CTRL_DIR(val)				(((val) & 0xf) << 12)
> +#define ADMA_CH_CTRL_DIR_MEM2MEM			1
>  #define ADMA_CH_CTRL_DIR_AHUB2MEM			2
>  #define ADMA_CH_CTRL_DIR_MEM2AHUB			4
> -#define ADMA_CH_CTRL_MODE_CONTINUOUS			(2 << 8)
> +#define ADMA_CH_CTRL_DIR_AHUB2AHUB			8
> +#define ADMA_CH_CTRL_MODE(val)				(((val) & 0x7) << 8)
> +#define ADMA_CH_CTRL_MODE_ONCE				1
> +#define ADMA_CH_CTRL_MODE_CONTINUOUS			2
> +#define ADMA_CH_CTRL_MODE_LINKED_LIST			4
>  #define ADMA_CH_CTRL_FLOWCTRL_EN			BIT(1)
>  
>  #define ADMA_CH_CONFIG					0x28
> @@ -264,6 +269,9 @@ static int tegra_adma_request_alloc(struct tegra_adma_chan *tdc,
>  		}
>  		break;
>  
> +	case DMA_MEM_TO_MEM:
> +		break;
> +
>  	default:
>  		dev_WARN(tdma->dev, "channel %s has invalid transfer type\n",
>  			 dma_chan_name(&tdc->vc.chan));
> @@ -292,6 +300,9 @@ static void tegra_adma_request_free(struct tegra_adma_chan *tdc)
>  		clear_bit(tdc->sreq_index, &tdma->rx_requests_reserved);
>  		break;
>  
> +	case DMA_MEM_TO_MEM:
> +		break;
> +
>  	default:
>  		dev_WARN(tdma->dev, "channel %s has invalid transfer type\n",
>  			 dma_chan_name(&tdc->vc.chan));
> @@ -409,8 +420,14 @@ static irqreturn_t tegra_adma_isr(int irq, void *dev_id)
>  		return IRQ_NONE;
>  	}
>  
> -	if (tdc->desc->cyclic)
> +	if (tdc->desc->cyclic) {
>  		vchan_cyclic_callback(&tdc->desc->vd);
> +	} else {
> +		/* Disable the channel */
> +		tdma_ch_write(tdc, ADMA_CH_CMD, 0);
> +		vchan_cookie_complete(&tdc->desc->vd);
> +		tdc->desc = NULL;
> +	}
>  
>  	spin_unlock_irqrestore(&tdc->vc.lock, flags);
>  
> @@ -488,42 +505,59 @@ static enum dma_status tegra_adma_tx_status(struct dma_chan *dc,
>  static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
>  				      struct tegra_adma_desc *desc,
>  				      dma_addr_t buf_addr,
> +				      dma_addr_t buf_addr2,
>  				      enum dma_transfer_direction direction)
>  {
>  	struct tegra_adma_chan_regs *ch_regs = &desc->ch_regs;
> -	unsigned int burst_size, adma_dir;
> +	unsigned int num_periods = desc->num_periods;
> +	unsigned int burst_size, adma_dir, adma_mode;
>  
> -	if (desc->num_periods > ADMA_CH_CONFIG_MAX_BUFS)
> +	if (num_periods > ADMA_CH_CONFIG_MAX_BUFS)
>  		return -EINVAL;
>  
>  	switch (direction) {
>  	case DMA_MEM_TO_DEV:
>  		adma_dir = ADMA_CH_CTRL_DIR_MEM2AHUB;
>  		burst_size = fls(tdc->sconfig.dst_maxburst);
> -		ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(desc->num_periods - 1);
> -		ch_regs->ctrl = ADMA_CH_CTRL_TX_REQ(tdc->sreq_index);
> +		ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(num_periods - 1);
> +		ch_regs->ctrl = ADMA_CH_CTRL_TX_REQ(tdc->sreq_index) |
> +				ADMA_CH_CTRL_FLOWCTRL_EN;
>  		ch_regs->src_addr = buf_addr;
>  		break;
>  
>  	case DMA_DEV_TO_MEM:
>  		adma_dir = ADMA_CH_CTRL_DIR_AHUB2MEM;
>  		burst_size = fls(tdc->sconfig.src_maxburst);
> -		ch_regs->config = ADMA_CH_CONFIG_TRG_BUF(desc->num_periods - 1);
> -		ch_regs->ctrl = ADMA_CH_CTRL_RX_REQ(tdc->sreq_index);
> +		ch_regs->config = ADMA_CH_CONFIG_TRG_BUF(num_periods - 1);
> +		ch_regs->ctrl = ADMA_CH_CTRL_RX_REQ(tdc->sreq_index) |
> +				ADMA_CH_CTRL_FLOWCTRL_EN;
>  		ch_regs->trg_addr = buf_addr;
>  		break;
>  
> +	case DMA_MEM_TO_MEM:
> +		adma_dir = ADMA_CH_CTRL_DIR_MEM2MEM;
> +		burst_size = ADMA_CH_CONFIG_BURST_16;
> +		ch_regs->config = ADMA_CH_CONFIG_SRC_BUF(num_periods - 1) |
> +				  ADMA_CH_CONFIG_TRG_BUF(num_periods - 1);
> +		ch_regs->src_addr = buf_addr;
> +		ch_regs->trg_addr = buf_addr2;
> +		break;
> +
>  	default:
>  		dev_err(tdc2dev(tdc), "DMA direction is not supported\n");
>  		return -EINVAL;
>  	}
>  
> +	if (desc->cyclic)
> +		adma_mode = ADMA_CH_CTRL_MODE_CONTINUOUS;
> +	else
> +		adma_mode = ADMA_CH_CTRL_MODE_ONCE;
> +
>  	if (!burst_size || burst_size > ADMA_CH_CONFIG_BURST_16)
>  		burst_size = ADMA_CH_CONFIG_BURST_16;
>  
>  	ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir) |
> -			 ADMA_CH_CTRL_MODE_CONTINUOUS |
> -			 ADMA_CH_CTRL_FLOWCTRL_EN;
> +			 ADMA_CH_CTRL_MODE(adma_mode);
>  	ch_regs->config |= ADMA_CH_CONFIG_BURST_SIZE(burst_size);
>  	ch_regs->config |= ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1);
>  	ch_regs->fifo_ctrl = ADMA_CH_FIFO_CTRL_DEFAULT;
> @@ -564,7 +598,39 @@ static struct dma_async_tx_descriptor *tegra_adma_prep_dma_cyclic(
>  	desc->period_len = period_len;
>  	desc->num_periods = buf_len / period_len;
>  
> -	if (tegra_adma_set_xfer_params(tdc, desc, buf_addr, direction)) {
> +	if (tegra_adma_set_xfer_params(tdc, desc, buf_addr, 0, direction)) {
> +		kfree(desc);
> +		return NULL;
> +	}
> +
> +	return vchan_tx_prep(&tdc->vc, &desc->vd, flags);
> +}
> +
> +static struct dma_async_tx_descriptor *tegra_adma_prep_dma_memcpy(
> +	struct dma_chan *dc, dma_addr_t dest, dma_addr_t src,
> +	size_t buf_len, unsigned long flags)
> +{
> +	struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc);
> +	struct device *dev = dc->device->dev;
> +	struct tegra_adma_desc *desc = NULL;
> +
> +	dev_dbg(dev, "%s channel: %d src=0x%llx dst=0x%llx len=%zu\n",
> +		__func__, dc->chan_id, (unsigned long long)src,
> +		(unsigned long long)dest, buf_len);
> +
> +	if (unlikely(!tdc || !buf_len))
> +		return NULL;
> +
> +	desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
> +	if (!desc)
> +		return NULL;
> +
> +	/* TODO: ADMA should support up to 8 chunks or periods */
> +	desc->num_periods = 1;
> +	desc->buf_len = buf_len;
> +	desc->period_len = buf_len;

What would be the benefit of using 8 periods here? My understanding is
that you will get an interrupt per period and do you really want this
for memcpy?

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 0/2] Add memcpy support for tegra210-adma
  2016-09-06 11:33 ` [PATCH v2 0/2] Add memcpy support for tegra210-adma Jon Hunter
@ 2016-09-06 12:03   ` Dmitry Osipenko
  2016-09-06 13:04     ` Jon Hunter
  0 siblings, 1 reply; 10+ messages in thread
From: Dmitry Osipenko @ 2016-09-06 12:03 UTC (permalink / raw)
  To: Jon Hunter, Nicolin Chen, vinod.koul
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan

On 06.09.2016 14:33, Jon Hunter wrote:
> 
> On 03/09/16 01:32, Nicolin Chen wrote:
>> This series of patches add memcpy support for tegra210 ADMA engine.
> 
> Thanks. Any reason you choose this DMA and not the APB DMA? The APB DMA
> is more of a generic DMA and so for memcpy it would seem to be a good
> choice and it is available on all Tegras not just Tegra210.
> 

Just a small clarification:

If I'm not mistaken, APB DMA is mem-to-device, while AHB DMA is mem-to-mem. So,
you probably meant AHB and not the APB.

> Furthermore, from a power standpoint the ADMA is in the audio power
> domain and so using it for memcpy would mean the audio power domain is
> turned on. It may not be a big deal for some, but given the APB is in
> the CORE domain (always on when not in low-power) it seems like a better
> choice for power as well.
> 

-- 
Dmitry

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

* Re: [PATCH v2 0/2] Add memcpy support for tegra210-adma
  2016-09-06 12:03   ` Dmitry Osipenko
@ 2016-09-06 13:04     ` Jon Hunter
  2016-09-06 13:46       ` Jon Hunter
  0 siblings, 1 reply; 10+ messages in thread
From: Jon Hunter @ 2016-09-06 13:04 UTC (permalink / raw)
  To: Dmitry Osipenko, Nicolin Chen, vinod.koul
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan


On 06/09/16 13:03, Dmitry Osipenko wrote:
> On 06.09.2016 14:33, Jon Hunter wrote:
>>
>> On 03/09/16 01:32, Nicolin Chen wrote:
>>> This series of patches add memcpy support for tegra210 ADMA engine.
>>
>> Thanks. Any reason you choose this DMA and not the APB DMA? The APB DMA
>> is more of a generic DMA and so for memcpy it would seem to be a good
>> choice and it is available on all Tegras not just Tegra210.
>>
> 
> Just a small clarification:
> 
> If I'm not mistaken, APB DMA is mem-to-device, while AHB DMA is mem-to-mem. So,
> you probably meant AHB and not the APB.

Description from the Tegra TRM:

"The APB DMA Controller is placed between the AHB Bus and the APB Bus
and is a master on both buses.

The APB DMA Controller is used for block data transfers from a source
location to the destination location. The source may be
DRAM or IRAM, and the destination location could be devices placed on
APB Bus; or vice versa."

Cheers
Jon

-- 
nvpublic

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

* Re: [PATCH v2 0/2] Add memcpy support for tegra210-adma
  2016-09-06 13:04     ` Jon Hunter
@ 2016-09-06 13:46       ` Jon Hunter
  2016-09-06 14:27         ` Dmitry Osipenko
  0 siblings, 1 reply; 10+ messages in thread
From: Jon Hunter @ 2016-09-06 13:46 UTC (permalink / raw)
  To: Dmitry Osipenko, Nicolin Chen, vinod.koul
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan


On 06/09/16 14:04, Jon Hunter wrote:
> 
> On 06/09/16 13:03, Dmitry Osipenko wrote:
>> On 06.09.2016 14:33, Jon Hunter wrote:
>>>
>>> On 03/09/16 01:32, Nicolin Chen wrote:
>>>> This series of patches add memcpy support for tegra210 ADMA engine.
>>>
>>> Thanks. Any reason you choose this DMA and not the APB DMA? The APB DMA
>>> is more of a generic DMA and so for memcpy it would seem to be a good
>>> choice and it is available on all Tegras not just Tegra210.
>>>
>>
>> Just a small clarification:
>>
>> If I'm not mistaken, APB DMA is mem-to-device, while AHB DMA is mem-to-mem. So,
>> you probably meant AHB and not the APB.
> 
> Description from the Tegra TRM:
> 
> "The APB DMA Controller is placed between the AHB Bus and the APB Bus
> and is a master on both buses.
> 
> The APB DMA Controller is used for block data transfers from a source
> location to the destination location. The source may be
> DRAM or IRAM, and the destination location could be devices placed on
> APB Bus; or vice versa."

Sorry this appears to be a completely worthless response :-(

I had made the assumption that if the DMA can transfer from APB-to-AHB
and AHB-to-APB, it could also do AHB to AHB. However, now I look closely
at the registers I see that it cannot and therefore, cannot support
memcpy at all! Ok, so ignore my comment here, as it appears only the
ADMA can support memcpy. Weird.

Jon

-- 
nvpublic

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

* Re: [PATCH v2 0/2] Add memcpy support for tegra210-adma
  2016-09-06 13:46       ` Jon Hunter
@ 2016-09-06 14:27         ` Dmitry Osipenko
  0 siblings, 0 replies; 10+ messages in thread
From: Dmitry Osipenko @ 2016-09-06 14:27 UTC (permalink / raw)
  To: Jon Hunter, Nicolin Chen, vinod.koul
  Cc: linux-kernel, linux-tegra, dmaengine, gnurou, thierry.reding,
	swarren, ldewangan

On 06.09.2016 16:46, Jon Hunter wrote:
> 
> On 06/09/16 14:04, Jon Hunter wrote:
>>
>> On 06/09/16 13:03, Dmitry Osipenko wrote:
>>> On 06.09.2016 14:33, Jon Hunter wrote:
>>>>
>>>> On 03/09/16 01:32, Nicolin Chen wrote:
>>>>> This series of patches add memcpy support for tegra210 ADMA engine.
>>>>
>>>> Thanks. Any reason you choose this DMA and not the APB DMA? The APB DMA
>>>> is more of a generic DMA and so for memcpy it would seem to be a good
>>>> choice and it is available on all Tegras not just Tegra210.
>>>>
>>>
>>> Just a small clarification:
>>>
>>> If I'm not mistaken, APB DMA is mem-to-device, while AHB DMA is mem-to-mem. So,
>>> you probably meant AHB and not the APB.
>>
>> Description from the Tegra TRM:
>>
>> "The APB DMA Controller is placed between the AHB Bus and the APB Bus
>> and is a master on both buses.
>>
>> The APB DMA Controller is used for block data transfers from a source
>> location to the destination location. The source may be
>> DRAM or IRAM, and the destination location could be devices placed on
>> APB Bus; or vice versa."
> 
> Sorry this appears to be a completely worthless response :-(
> 
> I had made the assumption that if the DMA can transfer from APB-to-AHB
> and AHB-to-APB, it could also do AHB to AHB. However, now I look closely
> at the registers I see that it cannot and therefore, cannot support
> memcpy at all! Ok, so ignore my comment here, as it appears only the
> ADMA can support memcpy. Weird.
> 

On older Tegra's there is AHB DMA controller for mem-to-mem transfers. The K1
manual states that it's been deprecated, however there is an interrupt dedicated
to it (probably wrong TRM?). X1 TRM also states the deprecation, doesn't have
the interrupt mention that K1 has and has ADMA.

-- 
Dmitry

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

* Re: [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support
  2016-09-06 11:52   ` Jon Hunter
@ 2016-09-06 17:21     ` Nicolin Chen
  0 siblings, 0 replies; 10+ messages in thread
From: Nicolin Chen @ 2016-09-06 17:21 UTC (permalink / raw)
  To: Jon Hunter
  Cc: vinod.koul, linux-kernel, linux-tegra, dmaengine, gnurou,
	thierry.reding, swarren, ldewangan

On Tue, Sep 06, 2016 at 12:52:03PM +0100, Jon Hunter wrote:
> > +	/* TODO: ADMA should support up to 8 chunks or periods */
> > +	desc->num_periods = 1;
> > +	desc->buf_len = buf_len;
> > +	desc->period_len = buf_len;

> What would be the benefit of using 8 periods here? My understanding is
> that you will get an interrupt per period and do you really want this
> for memcpy?

You are right about the interrupt. And it doesn't seem to be
beneficial unless the period size is over the limitation of
Transfer Count, which is rare but might theoretically exist?

I admit the "TODO" word here is a bit misleading for memcpy.
I can remove the word and write a more appropriate comments.

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

end of thread, other threads:[~2016-09-06 17:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-03  0:32 [PATCH v2 0/2] Add memcpy support for tegra210-adma Nicolin Chen
2016-09-03  0:32 ` [PATCH v2 1/2] dmaengine: tegra210-adma: Add pre-check for cyclic callback Nicolin Chen
2016-09-03  0:32 ` [PATCH v2 2/2] dmaengine: tegra210-adma: Add memcpy support Nicolin Chen
2016-09-06 11:52   ` Jon Hunter
2016-09-06 17:21     ` Nicolin Chen
2016-09-06 11:33 ` [PATCH v2 0/2] Add memcpy support for tegra210-adma Jon Hunter
2016-09-06 12:03   ` Dmitry Osipenko
2016-09-06 13:04     ` Jon Hunter
2016-09-06 13:46       ` Jon Hunter
2016-09-06 14:27         ` Dmitry Osipenko

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