linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] dw_dmac: introduce autoconfiguration
@ 2012-09-17  7:39 Andy Shevchenko
  2012-09-17  7:39 ` [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
                   ` (9 more replies)
  0 siblings, 10 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Here is a patchset that allows to adapt the driver to the hardware
configuration during probe time. The hardware should have the specific optional
parameters enabled. Otherwise the driver will consider values stored in the
platform data.

Additionally it brings support of the software LLP transfers. It means that
normal linked list transfer is substituted by set of single block transfers
transparently to the user.

Comments are welcome.

Andy Shevchenko (7):
  dw_dmac: mark dwc_dump_chan_regs as inline
  dw_dmac: fill optional encoded parameters in register structure
  dw_dmac: get number of channels from hardware if possible
  dw_dmac: autoconfigure block_size or use platform data
  dw_dmac: autoconfigure data_width or get it via platform data
  dw_dmac: check if controller supports LLP
  dw_dmac: introduce software emulation of LLP transfers

 arch/arm/mach-spear13xx/spear13xx.c |    3 +
 arch/avr32/mach-at32ap/at32ap700x.c |    3 +
 drivers/dma/dw_dmac.c               |  207 +++++++++++++++++++++++++++++------
 drivers/dma/dw_dmac_regs.h          |   48 ++++++++
 include/linux/dw_dmac.h             |    7 ++
 5 files changed, 235 insertions(+), 33 deletions(-)

-- 
1.7.10.4


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

* [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  6:35   ` viresh kumar
  2012-09-17  7:39 ` [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 832538c..75ab5af 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -208,7 +208,7 @@ static inline unsigned int dwc_fast_fls(unsigned long long v)
 	return 0;
 }
 
-static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
 {
 	dev_err(chan2dev(&dwc->chan),
 		"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-- 
1.7.10.4


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

* [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
  2012-09-17  7:39 ` [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  6:39   ` viresh kumar
  2012-09-17  7:39 ` [PATCH 3/7] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

There is a block of the registers that are optional. However, if enabled they
contain useful information about the controller hardware configuration. We will
use this piece of data to autoconfigure the driver.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac_regs.h |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index f6d92d7..4633d39 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -82,9 +82,28 @@ struct dw_dma_regs {
 	DW_REG(ID);
 	DW_REG(TEST);
 
+	/* reserved */
+	DW_REG(__reserved0);
+	DW_REG(__reserved1);
+
 	/* optional encoded params, 0x3c8..0x3f7 */
+	u32	__reserved;
+
+	/* per-channel configuration registers */
+	u32	DWC_PARAMS[DW_DMA_MAX_NR_CHANNELS];
+	u32	MULTI_BLK_TYPE;
+	u32	MAX_BLK_SIZE;
+
+	/* top-level parameters */
+	u32	DW_PARAMS;
 };
 
+#define dma_raw_readl(addr, name) \
+	readl((addr) + offsetof(struct dw_dma_regs, name))
+
+#define dma_raw_writel(addr, name, val) \
+	writel((val), (addr) + offsetof(struct dw_dma_regs, name))
+
 /* Bitfields in CTL_LO */
 #define DWC_CTLL_INT_EN		(1 << 0)	/* irqs enabled? */
 #define DWC_CTLL_DST_WIDTH(n)	((n)<<1)	/* bytes per element */
-- 
1.7.10.4


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

* [PATCH 3/7] dw_dmac: get number of channels from hardware if possible
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
  2012-09-17  7:39 ` [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
  2012-09-17  7:39 ` [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  6:50   ` viresh kumar
  2012-09-17  7:39 ` [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

In case the controller has the encoded parameters feature enabled the driver
will use it to get the number of channels. In the future it will be used for
the other important parameters as well.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac.c      |   33 +++++++++++++++++++++++----------
 drivers/dma/dw_dmac_regs.h |    4 ++++
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 75ab5af..2a3b730 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1376,6 +1376,10 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	struct resource		*io;
 	struct dw_dma		*dw;
 	size_t			size;
+	void __iomem		*regs;
+	bool			autocfg;
+	unsigned int		dw_params;
+	unsigned int		nr_channels;
 	int			irq;
 	int			err;
 	int			i;
@@ -1392,23 +1396,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
-	size = sizeof(struct dw_dma);
-	size += pdata->nr_channels * sizeof(struct dw_dma_chan);
+	regs = devm_request_and_ioremap(&pdev->dev, io);
+	if (!regs)
+		return -EBUSY;
+
+	dw_params = dma_raw_readl(regs, DW_PARAMS);
+	autocfg = dw_params >> DW_PARAMS_EN & 0x1;
+
+	if (autocfg)
+		nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 0x7) + 1;
+	else
+		nr_channels = pdata->nr_channels;
+
+	size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
 	dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
 	if (!dw)
 		return -ENOMEM;
 
-	dw->regs = devm_request_and_ioremap(&pdev->dev, io);
-	if (!dw->regs)
-		return -EBUSY;
-
 	dw->clk = devm_clk_get(&pdev->dev, "hclk");
 	if (IS_ERR(dw->clk))
 		return PTR_ERR(dw->clk);
 	clk_prepare_enable(dw->clk);
 
+	dw->regs = regs;
+
 	/* Calculate all channel mask before DMA setup */
-	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
+	dw->all_chan_mask = (1 << nr_channels) - 1;
 
 	/* force dma off, just in case */
 	dw_dma_off(dw);
@@ -1426,7 +1439,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
 
 	INIT_LIST_HEAD(&dw->dma.channels);
-	for (i = 0; i < pdata->nr_channels; i++) {
+	for (i = 0; i < nr_channels; i++) {
 		struct dw_dma_chan	*dwc = &dw->chan[i];
 
 		dwc->chan.device = &dw->dma;
@@ -1439,7 +1452,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		/* 7 is highest priority & 0 is lowest. */
 		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
-			dwc->priority = pdata->nr_channels - i - 1;
+			dwc->priority = nr_channels - i - 1;
 		else
 			dwc->priority = i;
 
@@ -1480,7 +1493,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	dma_writel(dw, CFG, DW_CFG_DMA_EN);
 
 	printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n",
-			dev_name(&pdev->dev), pdata->nr_channels);
+			dev_name(&pdev->dev), nr_channels);
 
 	dma_async_device_register(&dw->dma);
 
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 4633d39..0f96965 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -104,6 +104,10 @@ struct dw_dma_regs {
 #define dma_raw_writel(addr, name, val) \
 	writel((val), (addr) + offsetof(struct dw_dma_regs, name))
 
+/* Bitfields in DW_PARAMS */
+#define DW_PARAMS_NR_CHAN	8		/* number of channels */
+#define DW_PARAMS_EN		28		/* encoded parameters */
+
 /* Bitfields in CTL_LO */
 #define DWC_CTLL_INT_EN		(1 << 0)	/* irqs enabled? */
 #define DWC_CTLL_DST_WIDTH(n)	((n)<<1)	/* bytes per element */
-- 
1.7.10.4


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

* [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (2 preceding siblings ...)
  2012-09-17  7:39 ` [PATCH 3/7] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  6:57   ` viresh kumar
  2012-09-17  7:39 ` [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

The maximum block size is a configurable parameter for the chip. So, driver
will try to get it from the encoded component parameters. Otherwise it will
come from the platform data.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 arch/arm/mach-spear13xx/spear13xx.c |    1 +
 arch/avr32/mach-at32ap/at32ap700x.c |    1 +
 drivers/dma/dw_dmac.c               |   34 ++++++++++++++++++----------------
 drivers/dma/dw_dmac_regs.h          |    3 +++
 include/linux/dw_dmac.h             |    2 ++
 5 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index cf936b1..c64d812 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -78,6 +78,7 @@ struct dw_dma_platform_data dmac_plat_data = {
 	.nr_channels = 8,
 	.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
 	.chan_priority = CHAN_PRIORITY_DESCENDING,
+	.block_size = 4095U,
 };
 
 void __init spear13xx_l2x0_init(void)
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 0445c4f..2c4aefe 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -605,6 +605,7 @@ static void __init genclk_init_parent(struct clk *clk)
 
 static struct dw_dma_platform_data dw_dmac0_data = {
 	.nr_channels	= 3,
+	.block_size	= 4095U,
 };
 
 static struct resource dw_dmac0_resource[] = {
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 2a3b730..ab718ee 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -58,16 +58,6 @@
 	})
 
 /*
- * This is configuration-dependent and usually a funny size like 4095.
- *
- * Note that this is a transfer count, i.e. if we transfer 32-bit
- * words, we can do 16380 bytes per descriptor.
- *
- * This parameter is also system-specific.
- */
-#define DWC_MAX_COUNT	4095U
-
-/*
  * Number of descriptors to allocate for each channel. This should be
  * made configurable somehow; preferably, the clients (at least the
  * ones using slave transfers) should be able to give us a hint.
@@ -669,7 +659,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
 	for (offset = 0; offset < len; offset += xfer_count << src_width) {
 		xfer_count = min_t(size_t, (len - offset) >> src_width,
-				DWC_MAX_COUNT);
+					   dwc->block_size);
 
 		desc = dwc_desc_get(dwc);
 		if (!desc)
@@ -770,8 +760,8 @@ slave_sg_todev_fill_desc:
 			desc->lli.sar = mem;
 			desc->lli.dar = reg;
 			desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
-			if ((len >> mem_width) > DWC_MAX_COUNT) {
-				dlen = DWC_MAX_COUNT << mem_width;
+			if ((len >> mem_width) > dwc->block_size) {
+				dlen = dwc->block_size << mem_width;
 				mem += dlen;
 				len -= dlen;
 			} else {
@@ -830,8 +820,8 @@ slave_sg_fromdev_fill_desc:
 			desc->lli.sar = reg;
 			desc->lli.dar = mem;
 			desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
-			if ((len >> reg_width) > DWC_MAX_COUNT) {
-				dlen = DWC_MAX_COUNT << reg_width;
+			if ((len >> reg_width) > dwc->block_size) {
+				dlen = dwc->block_size << reg_width;
 				mem += dlen;
 				len -= dlen;
 			} else {
@@ -1214,7 +1204,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
 	periods = buf_len / period_len;
 
 	/* Check for too big/unaligned periods and unaligned DMA buffer. */
-	if (period_len > (DWC_MAX_COUNT << reg_width))
+	if (period_len > (dwc->block_size << reg_width))
 		goto out_err;
 	if (unlikely(period_len & ((1 << reg_width) - 1)))
 		goto out_err;
@@ -1380,6 +1370,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	bool			autocfg;
 	unsigned int		dw_params;
 	unsigned int		nr_channels;
+	unsigned int		max_blk_size;
 	int			irq;
 	int			err;
 	int			i;
@@ -1420,6 +1411,9 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 	dw->regs = regs;
 
+	/* get hardware configuration parameters */
+	max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
+
 	/* Calculate all channel mask before DMA setup */
 	dw->all_chan_mask = (1 << nr_channels) - 1;
 
@@ -1465,6 +1459,14 @@ static int __devinit dw_probe(struct platform_device *pdev)
 		INIT_LIST_HEAD(&dwc->free_list);
 
 		channel_clear_bit(dw, CH_EN, dwc->mask);
+
+		/* hardware configuration */
+		if (autocfg) {
+			dwc->block_size =
+				(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
+		} else {
+			dwc->block_size = pdata->block_size;
+		}
 	}
 
 	/* Clear all interrupts on all channels. */
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 0f96965..233f5e5 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -186,6 +186,9 @@ struct dw_dma_chan {
 
 	unsigned int		descs_allocated;
 
+	/* hardware configuration */
+	unsigned short		block_size;
+
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
 };
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 2412e02..3315ef9 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -19,6 +19,7 @@
  * @nr_channels: Number of channels supported by hardware (max 8)
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
+ * @block_size: Maximum block size supported by the controller
  */
 struct dw_dma_platform_data {
 	unsigned int	nr_channels;
@@ -29,6 +30,7 @@ struct dw_dma_platform_data {
 #define CHAN_PRIORITY_ASCENDING		0	/* chan0 highest */
 #define CHAN_PRIORITY_DESCENDING	1	/* chan7 highest */
 	unsigned char	chan_priority;
+	unsigned short	block_size;
 };
 
 /* bursts size */
-- 
1.7.10.4


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

* [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (3 preceding siblings ...)
  2012-09-17  7:39 ` [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  7:11   ` viresh kumar
  2012-09-17  7:39 ` [PATCH 6/7] dw_dmac: check if controller supports LLP Andy Shevchenko
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Not all of the controllers support the 64 bit data width. Make it configurable
via platform data. The driver will try to get a value from the component
parameters, otherwise it will use the platform data..

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 arch/arm/mach-spear13xx/spear13xx.c |    2 ++
 arch/avr32/mach-at32ap/at32ap700x.c |    2 ++
 drivers/dma/dw_dmac.c               |   46 +++++++++++++++++++++++++++++++----
 drivers/dma/dw_dmac_regs.h          |   13 ++++++++++
 include/linux/dw_dmac.h             |    5 ++++
 5 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index c64d812..6a7dfe1 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -79,6 +79,8 @@ struct dw_dma_platform_data dmac_plat_data = {
 	.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
 	.chan_priority = CHAN_PRIORITY_DESCENDING,
 	.block_size = 4095U,
+	.nr_masters = 2,
+	.data_width = { 3, 3, 0, 0 },
 };
 
 void __init spear13xx_l2x0_init(void)
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 2c4aefe..b323d8d 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -606,6 +606,8 @@ static void __init genclk_init_parent(struct clk *clk)
 static struct dw_dma_platform_data dw_dmac0_data = {
 	.nr_channels	= 3,
 	.block_size	= 4095U,
+	.nr_masters	= 2,
+	.data_width	= { 2, 2, 0, 0 },
 };
 
 static struct resource dw_dmac0_resource[] = {
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index ab718ee..fdb7d5a 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -38,12 +38,22 @@
  * which does not support descriptor writeback.
  */
 
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+	return slave ? slave->dst_master : 0;
+}
+
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+	return slave ? slave->src_master : 1;
+}
+
 #define DWC_DEFAULT_CTLLO(_chan) ({				\
 		struct dw_dma_slave *__slave = (_chan->private);	\
 		struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan);	\
 		struct dma_slave_config	*_sconfig = &_dwc->dma_sconfig;	\
-		int _dms = __slave ? __slave->dst_master : 0;	\
-		int _sms = __slave ? __slave->src_master : 1;	\
+		int _dms = dwc_get_dms(__slave);		\
+		int _sms = dwc_get_sms(__slave);		\
 		u8 _smsize = __slave ? _sconfig->src_maxburst :	\
 			DW_DMA_MSIZE_16;			\
 		u8 _dmsize = __slave ? _sconfig->dst_maxburst :	\
@@ -647,7 +657,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		return NULL;
 	}
 
-	src_width = dst_width = dwc_fast_fls(src | dest | len);
+	src_width = dst_width = min_t(unsigned int,
+				      /* For memory-to-memory transfers we
+				       * always use AHB master 1 */
+				      dwc->dw->data_width[0],
+				      dwc_fast_fls(src | dest | len));
 
 	ctllo = DWC_DEFAULT_CTLLO(chan)
 			| DWC_CTLL_DST_WIDTH(dst_width)
@@ -717,6 +731,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	dma_addr_t		reg;
 	unsigned int		reg_width;
 	unsigned int		mem_width;
+	unsigned int		data_width;
 	unsigned int		i;
 	struct scatterlist	*sg;
 	size_t			total_len = 0;
@@ -740,6 +755,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
 			DWC_CTLL_FC(DW_DMA_FC_D_M2P);
 
+		data_width = dwc->dw->data_width[dwc_get_sms(dws)];
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
@@ -747,7 +764,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = dwc_fast_fls(mem | len);
+			mem_width = min_t(unsigned int,
+					  data_width,
+					  dwc_fast_fls(mem | len));
 
 slave_sg_todev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -800,6 +819,8 @@ slave_sg_todev_fill_desc:
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
 			DWC_CTLL_FC(DW_DMA_FC_D_P2M);
 
+		data_width = dwc->dw->data_width[dwc_get_dms(dws)];
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
@@ -807,7 +828,9 @@ slave_sg_todev_fill_desc:
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = dwc_fast_fls(mem | len);
+			mem_width = min_t(unsigned int,
+					  data_width,
+					  dwc_fast_fls(mem | len));
 
 slave_sg_fromdev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -1413,6 +1436,17 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 	/* get hardware configuration parameters */
 	max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
+	if (autocfg)
+		dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
+	else
+		dw->nr_masters = pdata->nr_masters;
+	for (i = 0; i < dw->nr_masters; i++) {
+		if (autocfg)
+			dw->data_width[i] =
+				(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
+		else
+			dw->data_width[i] = pdata->data_width[i];
+	}
 
 	/* Calculate all channel mask before DMA setup */
 	dw->all_chan_mask = (1 << nr_channels) - 1;
@@ -1460,6 +1494,8 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		channel_clear_bit(dw, CH_EN, dwc->mask);
 
+		dwc->dw = dw;
+
 		/* hardware configuration */
 		if (autocfg) {
 			dwc->block_size =
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 233f5e5..9beaef0 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -106,6 +106,12 @@ struct dw_dma_regs {
 
 /* Bitfields in DW_PARAMS */
 #define DW_PARAMS_NR_CHAN	8		/* number of channels */
+#define DW_PARAMS_NR_MASTER	11		/* number of AHB masters */
+#define DW_PARAMS_DATA_WIDTH(n)	(15 + 2 * (n))
+#define DW_PARAMS_DATA_WIDTH1	15		/* master 1 data width */
+#define DW_PARAMS_DATA_WIDTH2	17		/* master 2 data width */
+#define DW_PARAMS_DATA_WIDTH3	19		/* master 3 data width */
+#define DW_PARAMS_DATA_WIDTH4	21		/* master 4 data width */
 #define DW_PARAMS_EN		28		/* encoded parameters */
 
 /* Bitfields in CTL_LO */
@@ -191,6 +197,9 @@ struct dw_dma_chan {
 
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
+
+	/* backlink to dw_dma */
+	struct dw_dma		*dw;
 };
 
 static inline struct dw_dma_chan_regs __iomem *
@@ -217,6 +226,10 @@ struct dw_dma {
 
 	u8			all_chan_mask;
 
+	/* hardware configuration */
+	unsigned char		nr_masters;
+	unsigned char		data_width[4];
+
 	struct dw_dma_chan	chan[0];
 };
 
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 3315ef9..e1c8c9e 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -20,6 +20,9 @@
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
  * @block_size: Maximum block size supported by the controller
+ * @nr_masters: Number of AHB masters supported by the controller
+ * @data_width: Maximum data width supported by hardware per AHB master
+ *		(0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
  */
 struct dw_dma_platform_data {
 	unsigned int	nr_channels;
@@ -31,6 +34,8 @@ struct dw_dma_platform_data {
 #define CHAN_PRIORITY_DESCENDING	1	/* chan7 highest */
 	unsigned char	chan_priority;
 	unsigned short	block_size;
+	unsigned char	nr_masters;
+	unsigned char	data_width[4];
 };
 
 /* bursts size */
-- 
1.7.10.4


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

* [PATCH 6/7] dw_dmac: check if controller supports LLP
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (4 preceding siblings ...)
  2012-09-17  7:39 ` [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  7:13   ` viresh kumar
  2012-09-17  7:39 ` [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Some controllers have the reduced functionality where the LLP multi block
transfers are not supported. This patch introduces a check and refuses to deal
with such devices.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac.c      |   35 ++++++++++++++++++++++++++++++++++-
 drivers/dma/dw_dmac_regs.h |    4 ++++
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index fdb7d5a..00958ad 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -647,6 +647,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	unsigned int		dst_width;
 	u32			ctllo;
 
+	if (dwc->nollp) {
+		dev_dbg(chan2dev(&dwc->chan),
+				"channel doesn't support LLP transfers\n");
+		return NULL;
+	}
+
 	dev_vdbg(chan2dev(chan),
 			"%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
 			(unsigned long long)dest, (unsigned long long)src,
@@ -741,6 +747,12 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	if (unlikely(!dws || !sg_len))
 		return NULL;
 
+	if (dwc->nollp) {
+		dev_dbg(chan2dev(&dwc->chan),
+				"channel doesn't support LLP transfers\n");
+		return NULL;
+	}
+
 	prev = first = NULL;
 
 	switch (direction) {
@@ -1202,6 +1214,13 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
 	unsigned long			flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->nollp) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dev_dbg(chan2dev(&dwc->chan),
+				"channel doesn't support LLP transfers\n");
+		return ERR_PTR(-EINVAL);
+	}
+
 	if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) {
 		spin_unlock_irqrestore(&dwc->lock, flags);
 		dev_dbg(chan2dev(&dwc->chan),
@@ -1469,6 +1488,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&dw->dma.channels);
 	for (i = 0; i < nr_channels; i++) {
 		struct dw_dma_chan	*dwc = &dw->chan[i];
+		int			r = nr_channels - i - 1;
 
 		dwc->chan.device = &dw->dma;
 		dma_cookie_init(&dwc->chan);
@@ -1480,7 +1500,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		/* 7 is highest priority & 0 is lowest. */
 		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
-			dwc->priority = nr_channels - i - 1;
+			dwc->priority = r;
 		else
 			dwc->priority = i;
 
@@ -1498,10 +1518,23 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		/* hardware configuration */
 		if (autocfg) {
+			unsigned int dwc_params;
+
+			dwc_params = dma_raw_readl(regs + r * sizeof(u32),
+						   DWC_PARAMS);
+
 			dwc->block_size =
 				(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
+			dwc->nollp =
+				(dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
 		} else {
 			dwc->block_size = pdata->block_size;
+
+			/* Check if channel supports multi block transfer */
+			channel_writel(dwc, LLP, 0xfffffffc);
+			dwc->nollp =
+				(channel_readl(dwc, LLP) & 0xfffffffc) == 0;
+			channel_writel(dwc, LLP, 0);
 		}
 	}
 
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 9beaef0..b66a716 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -114,6 +114,9 @@ struct dw_dma_regs {
 #define DW_PARAMS_DATA_WIDTH4	21		/* master 4 data width */
 #define DW_PARAMS_EN		28		/* encoded parameters */
 
+/* Bitfields in DWC_PARAMS */
+#define DWC_PARAMS_MBLK_EN	11		/* multi block transfer */
+
 /* Bitfields in CTL_LO */
 #define DWC_CTLL_INT_EN		(1 << 0)	/* irqs enabled? */
 #define DWC_CTLL_DST_WIDTH(n)	((n)<<1)	/* bytes per element */
@@ -194,6 +197,7 @@ struct dw_dma_chan {
 
 	/* hardware configuration */
 	unsigned short		block_size;
+	bool			nollp;
 
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
-- 
1.7.10.4


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

* [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (5 preceding siblings ...)
  2012-09-17  7:39 ` [PATCH 6/7] dw_dmac: check if controller supports LLP Andy Shevchenko
@ 2012-09-17  7:39 ` Andy Shevchenko
  2012-09-18  7:17   ` viresh kumar
  2012-09-17 16:50 ` [PATCH 0/7] dw_dmac: introduce autoconfiguration Hein Tibosch
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-17  7:39 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Some controllers have the reduced functionality where the LLP multi block
transfers are not supported. This patch introduces a support of such
controllers. In case of memory copy or scatter-gather lists it emulates LLP
transfers via bunch of the regular single block ones.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac.c      |   83 +++++++++++++++++++++++++++++++++++++-------
 drivers/dma/dw_dmac_regs.h |    5 +++
 2 files changed, 75 insertions(+), 13 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 00958ad..fa23711 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -229,10 +229,29 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
 
 /*----------------------------------------------------------------------*/
 
+/* Perform single block transfer */
+static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
+				       struct dw_desc *desc)
+{
+	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
+	u32		ctllo;
+
+	/* Software emulation of LLP mode relies on interrupts to continue
+	 * multi block transfer. */
+	ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
+
+	channel_writel(dwc, SAR, desc->lli.sar);
+	channel_writel(dwc, DAR, desc->lli.dar);
+	channel_writel(dwc, CTL_LO, ctllo);
+	channel_writel(dwc, CTL_HI, desc->lli.ctlhi);
+	channel_set_bit(dw, CH_EN, dwc->mask);
+}
+
 /* Called with dwc->lock held and bh disabled */
 static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 {
 	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
+	unsigned long	was_soft_llp;
 
 	/* ASSERT:  channel is idle */
 	if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -244,6 +263,26 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 		return;
 	}
 
+	if (dwc->nollp) {
+		was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP,
+						&dwc->flags);
+		if (was_soft_llp) {
+			dev_err(chan2dev(&dwc->chan),
+				"BUG: Attempted to start new LLP transfer "
+				"inside ongoing one\n");
+			return;
+		}
+
+		dwc_initialize(dwc);
+
+		dwc->tx_list = &first->tx_list;
+		dwc->tx_node_active = first->tx_list.next;
+
+		dwc_do_single_block(dwc, first);
+
+		return;
+	}
+
 	dwc_initialize(dwc);
 
 	channel_writel(dwc, LLP, first->txd.phys);
@@ -555,8 +594,36 @@ static void dw_dma_tasklet(unsigned long data)
 			dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
 		else if (status_err & (1 << i))
 			dwc_handle_error(dw, dwc);
-		else if (status_xfer & (1 << i))
+		else if (status_xfer & (1 << i)) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&dwc->lock, flags);
+			if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
+				if (dwc->tx_node_active != dwc->tx_list) {
+					struct dw_desc *desc =
+						list_entry(dwc->tx_node_active,
+							   struct dw_desc,
+							   desc_node);
+
+					dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+					/* move pointer to next descriptor */
+					dwc->tx_node_active =
+						dwc->tx_node_active->next;
+
+					dwc_do_single_block(dwc, desc);
+
+					spin_unlock_irqrestore(&dwc->lock, flags);
+					continue;
+				} else {
+					/* we are done here */
+					clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+				}
+			}
+			spin_unlock_irqrestore(&dwc->lock, flags);
+
 			dwc_scan_descriptors(dw, dwc);
+		}
 	}
 
 	/*
@@ -647,12 +714,6 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	unsigned int		dst_width;
 	u32			ctllo;
 
-	if (dwc->nollp) {
-		dev_dbg(chan2dev(&dwc->chan),
-				"channel doesn't support LLP transfers\n");
-		return NULL;
-	}
-
 	dev_vdbg(chan2dev(chan),
 			"%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
 			(unsigned long long)dest, (unsigned long long)src,
@@ -747,12 +808,6 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	if (unlikely(!dws || !sg_len))
 		return NULL;
 
-	if (dwc->nollp) {
-		dev_dbg(chan2dev(&dwc->chan),
-				"channel doesn't support LLP transfers\n");
-		return NULL;
-	}
-
 	prev = first = NULL;
 
 	switch (direction) {
@@ -972,6 +1027,8 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 	} else if (cmd == DMA_TERMINATE_ALL) {
 		spin_lock_irqsave(&dwc->lock, flags);
 
+		clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+
 		dwc_chan_disable(dw, dwc);
 
 		dwc->paused = false;
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index b66a716..297ab18 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -174,6 +174,7 @@ struct dw_dma_regs {
 
 enum dw_dmac_flags {
 	DW_DMA_IS_CYCLIC = 0,
+	DW_DMA_IS_SOFT_LLP = 1,
 };
 
 struct dw_dma_chan {
@@ -184,6 +185,10 @@ struct dw_dma_chan {
 	bool			paused;
 	bool			initialized;
 
+	/* software emulation of the LLP transfers */
+	struct list_head	*tx_list;
+	struct list_head	*tx_node_active;
+
 	spinlock_t		lock;
 
 	/* these other elements are all protected by lock */
-- 
1.7.10.4


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

* Re: [PATCH 0/7] dw_dmac: introduce autoconfiguration
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (6 preceding siblings ...)
  2012-09-17  7:39 ` [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
@ 2012-09-17 16:50 ` Hein Tibosch
  2012-09-18  6:11 ` Hein Tibosch
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
  9 siblings, 0 replies; 58+ messages in thread
From: Hein Tibosch @ 2012-09-17 16:50 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel

On 9/17/2012 3:39 PM, Andy Shevchenko wrote:
> Here is a patchset that allows to adapt the driver to the hardware
> configuration during probe time. The hardware should have the specific optional
> parameters enabled. Otherwise the driver will consider values stored in the
> platform data.
>
> Additionally it brings support of the software LLP transfers. It means that
> normal linked list transfer is substituted by set of single block transfers
> transparently to the user.
>
> Comments are welcome.
>
> Andy Shevchenko (7):
>   dw_dmac: mark dwc_dump_chan_regs as inline
>   dw_dmac: fill optional encoded parameters in register structure
>   dw_dmac: get number of channels from hardware if possible
>   dw_dmac: autoconfigure block_size or use platform data
>   dw_dmac: autoconfigure data_width or get it via platform data
>   dw_dmac: check if controller supports LLP
>   dw_dmac: introduce software emulation of LLP transfers
>
>  arch/arm/mach-spear13xx/spear13xx.c |    3 +
>  arch/avr32/mach-at32ap/at32ap700x.c |    3 +
>  drivers/dma/dw_dmac.c               |  207 +++++++++++++++++++++++++++++------
>  drivers/dma/dw_dmac_regs.h          |   48 ++++++++
>  include/linux/dw_dmac.h             |    7 ++
>  5 files changed, 235 insertions(+), 33 deletions(-)
Thanks a lot Andy,

I will soon test these patches on my avr32 platform and make a separate
patch for the 'configurable' endianness. I'm sure this can also be detected
automatically but at the cost of performance

Hein


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

* Re: [PATCH 0/7] dw_dmac: introduce autoconfiguration
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (7 preceding siblings ...)
  2012-09-17 16:50 ` [PATCH 0/7] dw_dmac: introduce autoconfiguration Hein Tibosch
@ 2012-09-18  6:11 ` Hein Tibosch
  2012-09-18  7:18   ` viresh kumar
  2012-09-20  9:48   ` Andy Shevchenko
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
  9 siblings, 2 replies; 58+ messages in thread
From: Hein Tibosch @ 2012-09-18  6:11 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel,
	ludovic.desroches, Nicolas Ferre, Hans-Christian Egtvedt

On 9/17/2012 3:39 PM, Andy Shevchenko wrote:
> Here is a patchset that allows to adapt the driver to the hardware
> configuration during probe time. The hardware should have the specific optional
> parameters enabled. Otherwise the driver will consider values stored in the
> platform data.
>
> Additionally it brings support of the software LLP transfers. It means that
> normal linked list transfer is substituted by set of single block transfers
> transparently to the user.
>
> Comments are welcome.
>
> Andy Shevchenko (7):
>   dw_dmac: mark dwc_dump_chan_regs as inline
>   dw_dmac: fill optional encoded parameters in register structure
>   dw_dmac: get number of channels from hardware if possible
>   dw_dmac: autoconfigure block_size or use platform data
>   dw_dmac: autoconfigure data_width or get it via platform data
>   dw_dmac: check if controller supports LLP
>   dw_dmac: introduce software emulation of LLP transfers
>
>  arch/arm/mach-spear13xx/spear13xx.c |    3 +
>  arch/avr32/mach-at32ap/at32ap700x.c |    3 +
>  drivers/dma/dw_dmac.c               |  207 +++++++++++++++++++++++++++++------
>  drivers/dma/dw_dmac_regs.h          |   48 ++++++++
>  include/linux/dw_dmac.h             |    7 ++
>  5 files changed, 235 insertions(+), 33 deletions(-)
Andy,

The (embedded) dw dma on the AP7000 indeed does not support auto
configuration (the register reads as zero) and so it needs the
platform data.

I tested the driver on AVR32 with the atmel-mci driver and it all
worked well.

I also tested the new software emulation of LLP mode by setting
nollp for each channel to true. That also worked as expected.


Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>

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

* Re: [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline
  2012-09-17  7:39 ` [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
@ 2012-09-18  6:35   ` viresh kumar
  0 siblings, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-18  6:35 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw_dmac.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> index 832538c..75ab5af 100644
> --- a/drivers/dma/dw_dmac.c
> +++ b/drivers/dma/dw_dmac.c
> @@ -208,7 +208,7 @@ static inline unsigned int dwc_fast_fls(unsigned long long v)
>         return 0;
>  }
>
> -static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
> +static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
>  {
>         dev_err(chan2dev(&dwc->chan),
>                 "  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* Re: [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-17  7:39 ` [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
@ 2012-09-18  6:39   ` viresh kumar
  2012-09-18  6:55     ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  6:39 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
> index f6d92d7..4633d39 100644
> --- a/drivers/dma/dw_dmac_regs.h
> +++ b/drivers/dma/dw_dmac_regs.h
> @@ -82,9 +82,28 @@ struct dw_dma_regs {
>         DW_REG(ID);
>         DW_REG(TEST);
>
> +       /* reserved */
> +       DW_REG(__reserved0);
> +       DW_REG(__reserved1);
> +
>         /* optional encoded params, 0x3c8..0x3f7 */
> +       u32     __reserved;
> +
> +       /* per-channel configuration registers */
> +       u32     DWC_PARAMS[DW_DMA_MAX_NR_CHANNELS];
> +       u32     MULTI_BLK_TYPE;
> +       u32     MAX_BLK_SIZE;
> +
> +       /* top-level parameters */
> +       u32     DW_PARAMS;
>  };

Above is Ok.

> +#define dma_raw_readl(addr, name) \
> +       readl((addr) + offsetof(struct dw_dma_regs, name))
> +
> +#define dma_raw_writel(addr, name, val) \
> +       writel((val), (addr) + offsetof(struct dw_dma_regs, name))
> +

But why don't you use earlier defined readl/writel macros:
dma_readl and dma_writel?

--
viresh

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

* Re: [PATCH 3/7] dw_dmac: get number of channels from hardware if possible
  2012-09-17  7:39 ` [PATCH 3/7] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
@ 2012-09-18  6:50   ` viresh kumar
  2012-09-20  9:35     ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  6:50 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> In case the controller has the encoded parameters feature enabled the driver
> will use it to get the number of channels. In the future it will be used for
> the other important parameters as well.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw_dmac.c      |   33 +++++++++++++++++++++++----------
>  drivers/dma/dw_dmac_regs.h |    4 ++++
>  2 files changed, 27 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> index 75ab5af..2a3b730 100644
> --- a/drivers/dma/dw_dmac.c
> +++ b/drivers/dma/dw_dmac.c
> @@ -1376,6 +1376,10 @@ static int __devinit dw_probe(struct platform_device *pdev)
>         struct resource         *io;
>         struct dw_dma           *dw;
>         size_t                  size;
> +       void __iomem            *regs;
> +       bool                    autocfg;
> +       unsigned int            dw_params;
> +       unsigned int            nr_channels;
>         int                     irq;
>         int                     err;
>         int                     i;
> @@ -1392,23 +1396,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
>         if (irq < 0)
>                 return irq;
>
> -       size = sizeof(struct dw_dma);
> -       size += pdata->nr_channels * sizeof(struct dw_dma_chan);
> +       regs = devm_request_and_ioremap(&pdev->dev, io);
> +       if (!regs)
> +               return -EBUSY;
> +
> +       dw_params = dma_raw_readl(regs, DW_PARAMS);

Is this valid for every SoC implementation. What if this configuration
is not valid
for a particular SoC and it is invalid to access this address? Or this
gives a invalid
value instead of returning 0?

> +       autocfg = dw_params >> DW_PARAMS_EN & 0x1;
> +
> +       if (autocfg)
> +               nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 0x7) + 1;
> +       else
> +               nr_channels = pdata->nr_channels;
> +
> +       size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
>         dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
>         if (!dw)
>                 return -ENOMEM;
>
> -       dw->regs = devm_request_and_ioremap(&pdev->dev, io);
> -       if (!dw->regs)
> -               return -EBUSY;
> -
>         dw->clk = devm_clk_get(&pdev->dev, "hclk");
>         if (IS_ERR(dw->clk))
>                 return PTR_ERR(dw->clk);
>         clk_prepare_enable(dw->clk);
>
> +       dw->regs = regs;
> +
>         /* Calculate all channel mask before DMA setup */
> -       dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
> +       dw->all_chan_mask = (1 << nr_channels) - 1;
>
>         /* force dma off, just in case */
>         dw_dma_off(dw);
> @@ -1426,7 +1439,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
>         tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
>
>         INIT_LIST_HEAD(&dw->dma.channels);
> -       for (i = 0; i < pdata->nr_channels; i++) {
> +       for (i = 0; i < nr_channels; i++) {
>                 struct dw_dma_chan      *dwc = &dw->chan[i];
>
>                 dwc->chan.device = &dw->dma;
> @@ -1439,7 +1452,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
>
>                 /* 7 is highest priority & 0 is lowest. */
>                 if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
> -                       dwc->priority = pdata->nr_channels - i - 1;
> +                       dwc->priority = nr_channels - i - 1;
>                 else
>                         dwc->priority = i;
>
> @@ -1480,7 +1493,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
>         dma_writel(dw, CFG, DW_CFG_DMA_EN);
>
>         printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n",
> -                       dev_name(&pdev->dev), pdata->nr_channels);
> +                       dev_name(&pdev->dev), nr_channels);
>
>         dma_async_device_register(&dw->dma);
>
> diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
> index 4633d39..0f96965 100644
> --- a/drivers/dma/dw_dmac_regs.h
> +++ b/drivers/dma/dw_dmac_regs.h
> @@ -104,6 +104,10 @@ struct dw_dma_regs {
>  #define dma_raw_writel(addr, name, val) \
>         writel((val), (addr) + offsetof(struct dw_dma_regs, name))
>
> +/* Bitfields in DW_PARAMS */
> +#define DW_PARAMS_NR_CHAN      8               /* number of channels */
> +#define DW_PARAMS_EN           28              /* encoded parameters */
> +

Can you make this part of patch 2/7?

>  /* Bitfields in CTL_LO */
>  #define DWC_CTLL_INT_EN                (1 << 0)        /* irqs enabled? */
>  #define DWC_CTLL_DST_WIDTH(n)  ((n)<<1)        /* bytes per element */
> --
> 1.7.10.4
>

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

* Re: [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-18  6:39   ` viresh kumar
@ 2012-09-18  6:55     ` Andy Shevchenko
  2012-09-18  7:59       ` viresh kumar
  0 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-18  6:55 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 12:09 +0530, viresh kumar wrote:

[snip]

> > +#define dma_raw_readl(addr, name) \
> > +       readl((addr) + offsetof(struct dw_dma_regs, name))
> > +
> > +#define dma_raw_writel(addr, name, val) \
> > +       writel((val), (addr) + offsetof(struct dw_dma_regs, name))
> > +
> 
> But why don't you use earlier defined readl/writel macros:
> dma_readl and dma_writel?
If you look at further patches, namely 3rd, the access to the register
is needed before we allocate memory for the dw_dma structure.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data
  2012-09-17  7:39 ` [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
@ 2012-09-18  6:57   ` viresh kumar
  2012-09-20  9:38     ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  6:57 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> @@ -1380,6 +1370,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
>         bool                    autocfg;
>         unsigned int            dw_params;
>         unsigned int            nr_channels;
> +       unsigned int            max_blk_size;
>         int                     irq;
>         int                     err;
>         int                     i;
> @@ -1420,6 +1411,9 @@ static int __devinit dw_probe(struct platform_device *pdev)
>
>         dw->regs = regs;
>
> +       /* get hardware configuration parameters */
> +       max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
> +

Do this only for autocfg case.

>         /* Calculate all channel mask before DMA setup */
>         dw->all_chan_mask = (1 << nr_channels) - 1;
>
> @@ -1465,6 +1459,14 @@ static int __devinit dw_probe(struct platform_device *pdev)
>                 INIT_LIST_HEAD(&dwc->free_list);
>
>                 channel_clear_bit(dw, CH_EN, dwc->mask);
> +
> +               /* hardware configuration */
> +               if (autocfg) {
> +                       dwc->block_size =
> +                               (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;

Put a comment on what are you doing here.

> +               } else {
> +                       dwc->block_size = pdata->block_size;
> +               }

Don't need {} for single line statements.

>         }
>
>         /* Clear all interrupts on all channels. */
> diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
> index 0f96965..233f5e5 100644
> --- a/drivers/dma/dw_dmac_regs.h
> +++ b/drivers/dma/dw_dmac_regs.h
> @@ -186,6 +186,9 @@ struct dw_dma_chan {
>
>         unsigned int            descs_allocated;
>
> +       /* hardware configuration */
> +       unsigned short          block_size;
> +

You actually don't save any memory here with short and actually makes access
to block_size more complex. keeping it int would be better i believe.

viresh

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

* Re: [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-17  7:39 ` [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
@ 2012-09-18  7:11   ` viresh kumar
  2012-09-20  9:42     ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  7:11 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> @@ -647,7 +657,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>                 return NULL;
>         }
>
> -       src_width = dst_width = dwc_fast_fls(src | dest | len);
> +       src_width = dst_width = min_t(unsigned int,
> +                                     /* For memory-to-memory transfers we
> +                                      * always use AHB master 1 */

Sorry couldn't understand your comment. :(
We use master 0 for src and master 1 for dst in memcpy.

> +                                     dwc->dw->data_width[0],
> +                                     dwc_fast_fls(src | dest | len));
>
>         ctllo = DWC_DEFAULT_CTLLO(chan)
>                         | DWC_CTLL_DST_WIDTH(dst_width)
> @@ -717,6 +731,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>         dma_addr_t              reg;
>         unsigned int            reg_width;
>         unsigned int            mem_width;
> +       unsigned int            data_width;
>         unsigned int            i;
>         struct scatterlist      *sg;
>         size_t                  total_len = 0;
> @@ -740,6 +755,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>                 ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
>                         DWC_CTLL_FC(DW_DMA_FC_D_M2P);
>
> +               data_width = dwc->dw->data_width[dwc_get_sms(dws)];
> +
>                 for_each_sg(sgl, sg, sg_len, i) {
>                         struct dw_desc  *desc;
>                         u32             len, dlen, mem;
> @@ -747,7 +764,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>                         mem = sg_dma_address(sg);
>                         len = sg_dma_len(sg);
>
> -                       mem_width = dwc_fast_fls(mem | len);
> +                       mem_width = min_t(unsigned int,
> +                                         data_width,
> +                                         dwc_fast_fls(mem | len));

can above three be merged into a single line or two lines?

>
>  slave_sg_todev_fill_desc:
>                         desc = dwc_desc_get(dwc);
> @@ -800,6 +819,8 @@ slave_sg_todev_fill_desc:
>                 ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
>                         DWC_CTLL_FC(DW_DMA_FC_D_P2M);
>
> +               data_width = dwc->dw->data_width[dwc_get_dms(dws)];
> +
>                 for_each_sg(sgl, sg, sg_len, i) {
>                         struct dw_desc  *desc;
>                         u32             len, dlen, mem;
> @@ -807,7 +828,9 @@ slave_sg_todev_fill_desc:
>                         mem = sg_dma_address(sg);
>                         len = sg_dma_len(sg);
>
> -                       mem_width = dwc_fast_fls(mem | len);
> +                       mem_width = min_t(unsigned int,
> +                                         data_width,
> +                                         dwc_fast_fls(mem | len));

ditto

>
>  slave_sg_fromdev_fill_desc:
>                         desc = dwc_desc_get(dwc);
> @@ -1413,6 +1436,17 @@ static int __devinit dw_probe(struct platform_device *pdev)
>
>         /* get hardware configuration parameters */
>         max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
> +       if (autocfg)
> +               dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
> +       else
> +               dw->nr_masters = pdata->nr_masters;
> +       for (i = 0; i < dw->nr_masters; i++) {
> +               if (autocfg)
> +                       dw->data_width[i] =
> +                               (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
> +               else
> +                       dw->data_width[i] = pdata->data_width[i];
> +       }

There are many autocfg, if, else statements now in probe. Can you try
to group these
into as minimum if, else calls?

>
>         /* Calculate all channel mask before DMA setup */
>         dw->all_chan_mask = (1 << nr_channels) - 1;
> @@ -1460,6 +1494,8 @@ static int __devinit dw_probe(struct platform_device *pdev)
>
>                 channel_clear_bit(dw, CH_EN, dwc->mask);
>
> +               dwc->dw = dw;
> +
>                 /* hardware configuration */
>                 if (autocfg) {
>                         dwc->block_size =
> diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
> index 233f5e5..9beaef0 100644
> --- a/drivers/dma/dw_dmac_regs.h
> +++ b/drivers/dma/dw_dmac_regs.h
> @@ -106,6 +106,12 @@ struct dw_dma_regs {
>
>  /* Bitfields in DW_PARAMS */
>  #define DW_PARAMS_NR_CHAN      8               /* number of channels */
> +#define DW_PARAMS_NR_MASTER    11              /* number of AHB masters */
> +#define DW_PARAMS_DATA_WIDTH(n)        (15 + 2 * (n))
> +#define DW_PARAMS_DATA_WIDTH1  15              /* master 1 data width */
> +#define DW_PARAMS_DATA_WIDTH2  17              /* master 2 data width */
> +#define DW_PARAMS_DATA_WIDTH3  19              /* master 3 data width */
> +#define DW_PARAMS_DATA_WIDTH4  21              /* master 4 data width */
>  #define DW_PARAMS_EN           28              /* encoded parameters */
>

Do these changes in a single patch 2/7

viresh

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

* Re: [PATCH 6/7] dw_dmac: check if controller supports LLP
  2012-09-17  7:39 ` [PATCH 6/7] dw_dmac: check if controller supports LLP Andy Shevchenko
@ 2012-09-18  7:13   ` viresh kumar
  2012-09-20  9:43     ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  7:13 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> Some controllers have the reduced functionality where the LLP multi block
> transfers are not supported. This patch introduces a check and refuses to deal
> with such devices.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw_dmac.c      |   35 ++++++++++++++++++++++++++++++++++-
>  drivers/dma/dw_dmac_regs.h |    4 ++++
>  2 files changed, 38 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> index fdb7d5a..00958ad 100644
> --- a/drivers/dma/dw_dmac.c
> +++ b/drivers/dma/dw_dmac.c
> @@ -647,6 +647,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>         unsigned int            dst_width;
>         u32                     ctllo;
>
> +       if (dwc->nollp) {
> +               dev_dbg(chan2dev(&dwc->chan),
> +                               "channel doesn't support LLP transfers\n");
> +               return NULL;
> +       }

But this could have been a single block request. Isn't it?

--
viresh

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

* Re: [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers
  2012-09-17  7:39 ` [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
@ 2012-09-18  7:17   ` viresh kumar
  2012-09-20  9:46     ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  7:17 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> index 00958ad..fa23711 100644
> --- a/drivers/dma/dw_dmac.c
> +++ b/drivers/dma/dw_dmac.c
> @@ -229,10 +229,29 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
>
>  /*----------------------------------------------------------------------*/
>
> +/* Perform single block transfer */
> +static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
> +                                      struct dw_desc *desc)
> +{
> +       struct dw_dma   *dw = to_dw_dma(dwc->chan.device);
> +       u32             ctllo;
> +
> +       /* Software emulation of LLP mode relies on interrupts to continue
> +        * multi block transfer. */
> +       ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
> +
> +       channel_writel(dwc, SAR, desc->lli.sar);
> +       channel_writel(dwc, DAR, desc->lli.dar);
> +       channel_writel(dwc, CTL_LO, ctllo);
> +       channel_writel(dwc, CTL_HI, desc->lli.ctlhi);
> +       channel_set_bit(dw, CH_EN, dwc->mask);
> +}
> +
>  /* Called with dwc->lock held and bh disabled */
>  static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
>  {
>         struct dw_dma   *dw = to_dw_dma(dwc->chan.device);
> +       unsigned long   was_soft_llp;
>
>         /* ASSERT:  channel is idle */
>         if (dma_readl(dw, CH_EN) & dwc->mask) {
> @@ -244,6 +263,26 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
>                 return;
>         }
>
> +       if (dwc->nollp) {
> +               was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP,
> +                                               &dwc->flags);
> +               if (was_soft_llp) {
> +                       dev_err(chan2dev(&dwc->chan),
> +                               "BUG: Attempted to start new LLP transfer "
> +                               "inside ongoing one\n");
> +                       return;
> +               }
> +
> +               dwc_initialize(dwc);
> +
> +               dwc->tx_list = &first->tx_list;
> +               dwc->tx_node_active = first->tx_list.next;
> +
> +               dwc_do_single_block(dwc, first);
> +
> +               return;
> +       }
> +
>         dwc_initialize(dwc);
>
>         channel_writel(dwc, LLP, first->txd.phys);
> @@ -555,8 +594,36 @@ static void dw_dma_tasklet(unsigned long data)
>                         dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
>                 else if (status_err & (1 << i))
>                         dwc_handle_error(dw, dwc);
> -               else if (status_xfer & (1 << i))
> +               else if (status_xfer & (1 << i)) {
> +                       unsigned long flags;
> +
> +                       spin_lock_irqsave(&dwc->lock, flags);
> +                       if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
> +                               if (dwc->tx_node_active != dwc->tx_list) {
> +                                       struct dw_desc *desc =
> +                                               list_entry(dwc->tx_node_active,
> +                                                          struct dw_desc,
> +                                                          desc_node);

can come in single line.

> +
> +                                       dma_writel(dw, CLEAR.XFER, dwc->mask);
> +
> +                                       /* move pointer to next descriptor */
> +                                       dwc->tx_node_active =
> +                                               dwc->tx_node_active->next;
> +
> +                                       dwc_do_single_block(dwc, desc);
> +
> +                                       spin_unlock_irqrestore(&dwc->lock, flags);
> +                                       continue;
> +                               } else {
> +                                       /* we are done here */
> +                                       clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
> +                               }
> +                       }
> +                       spin_unlock_irqrestore(&dwc->lock, flags);
> +
>                         dwc_scan_descriptors(dw, dwc);
> +               }
>         }
>
>         /*
> @@ -647,12 +714,6 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>         unsigned int            dst_width;
>         u32                     ctllo;
>
> -       if (dwc->nollp) {
> -               dev_dbg(chan2dev(&dwc->chan),
> -                               "channel doesn't support LLP transfers\n");
> -               return NULL;
> -       }
> -

:)
You should actually merge 6/7 with 7/7... You can't revert something
in the same patchset.

viresh

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

* Re: [PATCH 0/7] dw_dmac: introduce autoconfiguration
  2012-09-18  6:11 ` Hein Tibosch
@ 2012-09-18  7:18   ` viresh kumar
  2012-09-20  9:48   ` Andy Shevchenko
  1 sibling, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-18  7:18 UTC (permalink / raw)
  To: Hein Tibosch
  Cc: Andy Shevchenko, Vinod Koul, spear-devel, linux-kernel,
	ludovic.desroches, Nicolas Ferre, Hans-Christian Egtvedt

On Tue, Sep 18, 2012 at 11:41 AM, Hein Tibosch <hein_tibosch@yahoo.es> wrote:
> The (embedded) dw dma on the AP7000 indeed does not support auto
> configuration (the register reads as zero) and so it needs the
> platform data.
>
> I tested the driver on AVR32 with the atmel-mci driver and it all
> worked well.
>
> I also tested the new software emulation of LLP mode by setting
> nollp for each channel to true. That also worked as expected.
>
>
> Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>

Great. :)

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

* Re: [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-18  6:55     ` Andy Shevchenko
@ 2012-09-18  7:59       ` viresh kumar
  2012-09-20  9:30         ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-18  7:59 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, Sep 18, 2012 at 12:25 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>> > +#define dma_raw_readl(addr, name) \
>> > +       readl((addr) + offsetof(struct dw_dma_regs, name))
>> > +
>> > +#define dma_raw_writel(addr, name, val) \
>> > +       writel((val), (addr) + offsetof(struct dw_dma_regs, name))
>> > +
>>
>> But why don't you use earlier defined readl/writel macros:
>> dma_readl and dma_writel?

> If you look at further patches, namely 3rd, the access to the register
> is needed before we allocate memory for the dw_dma structure.

Ok. If i am not wrong, such calls are only required once for below line:

dw_params = dma_raw_readl(regs, DW_PARAMS

dma_raw_writel() is not used and shouldn't be required in future too.
So remove it.
dma_raw_readl() is required but the name is a bit confusing... this
raw type is different
from raw_readl...

Can we name it dma_read_byaddr()?

to make it more explicit.

viresh

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

* Re: [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-18  7:59       ` viresh kumar
@ 2012-09-20  9:30         ` Andy Shevchenko
  2012-09-20  9:32           ` viresh kumar
  0 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:30 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 13:29 +0530, viresh kumar wrote: 
> On Tue, Sep 18, 2012 at 12:25 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> >> > +#define dma_raw_readl(addr, name) \
> >> > +       readl((addr) + offsetof(struct dw_dma_regs, name))
> >> > +
> >> > +#define dma_raw_writel(addr, name, val) \
> >> > +       writel((val), (addr) + offsetof(struct dw_dma_regs, name))
> >> > +
> >>
> >> But why don't you use earlier defined readl/writel macros:
> >> dma_readl and dma_writel?
> 
> > If you look at further patches, namely 3rd, the access to the register
> > is needed before we allocate memory for the dw_dma structure.
> 
> Ok. If i am not wrong, such calls are only required once for below line:
Actually twice... 
> dw_params = dma_raw_readl(regs, DW_PARAMS
...here and for channel parameters.

> dma_raw_writel() is not used and shouldn't be required in future too.
> So remove it.
Ok

> dma_raw_readl() is required but the name is a bit confusing... this
> raw type is different
> from raw_readl...
> 
> Can we name it dma_read_byaddr()?
> to make it more explicit.
Ok.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-20  9:30         ` Andy Shevchenko
@ 2012-09-20  9:32           ` viresh kumar
  2012-09-20  9:51             ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-20  9:32 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 20, 2012 at 3:00 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>> Ok. If i am not wrong, such calls are only required once for below line:
> Actually twice...
>> dw_params = dma_raw_readl(regs, DW_PARAMS
> ...here and for channel parameters.

Till the time we hit channel code, we can allocate memory for dw and so
can use dma_readl/writel. Isn't it?

viresh

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

* Re: [PATCH 3/7] dw_dmac: get number of channels from hardware if possible
  2012-09-18  6:50   ` viresh kumar
@ 2012-09-20  9:35     ` Andy Shevchenko
  2012-09-20  9:40       ` viresh kumar
  0 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:35 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 12:20 +0530, viresh kumar wrote: 
> On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > In case the controller has the encoded parameters feature enabled the driver
> > will use it to get the number of channels. In the future it will be used for
> > the other important parameters as well.

[snip]

> > @@ -1392,23 +1396,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
> >         if (irq < 0)
> >                 return irq;
> >
> > -       size = sizeof(struct dw_dma);
> > -       size += pdata->nr_channels * sizeof(struct dw_dma_chan);
> > +       regs = devm_request_and_ioremap(&pdev->dev, io);
> > +       if (!regs)
> > +               return -EBUSY;
> > +
> > +       dw_params = dma_raw_readl(regs, DW_PARAMS);
> 
> Is this valid for every SoC implementation. What if this configuration
> is not valid
> for a particular SoC and it is invalid to access this address? Or this
> gives a invalid
> value instead of returning 0?
Actually I didn't get it clearly from the documentation. We have only
one test report from Hein until now.

> > diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
> > index 4633d39..0f96965 100644
> > --- a/drivers/dma/dw_dmac_regs.h
> > +++ b/drivers/dma/dw_dmac_regs.h
> > @@ -104,6 +104,10 @@ struct dw_dma_regs {
> >  #define dma_raw_writel(addr, name, val) \
> >         writel((val), (addr) + offsetof(struct dw_dma_regs, name))
> >
> > +/* Bitfields in DW_PARAMS */
> > +#define DW_PARAMS_NR_CHAN      8               /* number of channels */
> > +#define DW_PARAMS_EN           28              /* encoded parameters */
> > +
> 
> Can you make this part of patch 2/7?
Do you mean to combine patch 2 and 3 together or only the parts related
to dw_dmac_regs.h?


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data
  2012-09-18  6:57   ` viresh kumar
@ 2012-09-20  9:38     ` Andy Shevchenko
  0 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:38 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 12:27 +0530, viresh kumar wrote:

[snip]

> > @@ -1420,6 +1411,9 @@ static int __devinit dw_probe(struct platform_device *pdev)
> >
> >         dw->regs = regs;
> >
> > +       /* get hardware configuration parameters */
> > +       max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
> > +
> 
> Do this only for autocfg case.
Ok.

> > @@ -1465,6 +1459,14 @@ static int __devinit dw_probe(struct platform_device *pdev)
> >                 INIT_LIST_HEAD(&dwc->free_list);
> >
> >                 channel_clear_bit(dw, CH_EN, dwc->mask);
> > +
> > +               /* hardware configuration */
> > +               if (autocfg) {
> > +                       dwc->block_size =
> > +                               (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
> 
> Put a comment on what are you doing here.
Ok.

> 
> > +               } else {
> > +                       dwc->block_size = pdata->block_size;
> > +               }
> 
> Don't need {} for single line statements.
Ok. By the way it comes by next patch anyway.

> > --- a/drivers/dma/dw_dmac_regs.h
> > +++ b/drivers/dma/dw_dmac_regs.h
> > @@ -186,6 +186,9 @@ struct dw_dma_chan {
> >
> >         unsigned int            descs_allocated;
> >
> > +       /* hardware configuration */
> > +       unsigned short          block_size;
> > +
> 
> You actually don't save any memory here with short and actually makes access
> to block_size more complex. keeping it int would be better i believe.
I rather agree with you. I'll change it.

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 3/7] dw_dmac: get number of channels from hardware if possible
  2012-09-20  9:35     ` Andy Shevchenko
@ 2012-09-20  9:40       ` viresh kumar
  2012-09-21  6:04         ` viresh kumar
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-20  9:40 UTC (permalink / raw)
  To: Andy Shevchenko, Shiraz HASHIM
  Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 20, 2012 at 3:05 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> On Tue, 2012-09-18 at 12:20 +0530, viresh kumar wrote:
>> > @@ -1392,23 +1396,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
>> > +       dw_params = dma_raw_readl(regs, DW_PARAMS);
>>
>> Is this valid for every SoC implementation. What if this configuration
>> is not valid
>> for a particular SoC and it is invalid to access this address? Or this
>> gives a invalid
>> value instead of returning 0?

> Actually I didn't get it clearly from the documentation. We have only
> one test report from Hein until now.

@Shiraz: Can you please verify reading this register from u-boot? This
is important before we apply this patch to linux-next.

>> > diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
>> > index 4633d39..0f96965 100644
>> > --- a/drivers/dma/dw_dmac_regs.h
>> > +++ b/drivers/dma/dw_dmac_regs.h
>> > @@ -104,6 +104,10 @@ struct dw_dma_regs {
>> >  #define dma_raw_writel(addr, name, val) \
>> >         writel((val), (addr) + offsetof(struct dw_dma_regs, name))
>> >
>> > +/* Bitfields in DW_PARAMS */
>> > +#define DW_PARAMS_NR_CHAN      8               /* number of channels */
>> > +#define DW_PARAMS_EN           28              /* encoded parameters */
>> > +
>>
>> Can you make this part of patch 2/7?
> Do you mean to combine patch 2 and 3 together or only the parts related
> to dw_dmac_regs.h?

Only the new register definition macros in dmac_regs.h. :)

--
viresh

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

* Re: [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-18  7:11   ` viresh kumar
@ 2012-09-20  9:42     ` Andy Shevchenko
  2012-09-20  9:46       ` viresh kumar
  0 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:42 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 12:41 +0530, viresh kumar wrote: 
> On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > @@ -647,7 +657,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
> >                 return NULL;
> >         }
> >
> > -       src_width = dst_width = dwc_fast_fls(src | dest | len);
> > +       src_width = dst_width = min_t(unsigned int,
> > +                                     /* For memory-to-memory transfers we
> > +                                      * always use AHB master 1 */
> 
> Sorry couldn't understand your comment. :(
> We use master 0 for src and master 1 for dst in memcpy.
Yeah, it might require to rewrite the logic a bit to depend on proper
AHB master properties.

I will fix it.

> > @@ -747,7 +764,9 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
> >                         mem = sg_dma_address(sg);
> >                         len = sg_dma_len(sg);
> >
> > -                       mem_width = dwc_fast_fls(mem | len);
> > +                       mem_width = min_t(unsigned int,
> > +                                         data_width,
> > +                                         dwc_fast_fls(mem | len));
> 
> can above three be merged into a single line or two lines?
I think so, if there no objections from checkpatch.pl side.

> > @@ -807,7 +828,9 @@ slave_sg_todev_fill_desc:
> >                         mem = sg_dma_address(sg);
> >                         len = sg_dma_len(sg);
> >
> > -                       mem_width = dwc_fast_fls(mem | len);
> > +                       mem_width = min_t(unsigned int,
> > +                                         data_width,
> > +                                         dwc_fast_fls(mem | len));
> 
> ditto
See above.

> > @@ -1413,6 +1436,17 @@ static int __devinit dw_probe(struct platform_device *pdev)
> >
> >         /* get hardware configuration parameters */
> >         max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
> > +       if (autocfg)
> > +               dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
> > +       else
> > +               dw->nr_masters = pdata->nr_masters;
> > +       for (i = 0; i < dw->nr_masters; i++) {
> > +               if (autocfg)
> > +                       dw->data_width[i] =
> > +                               (dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
> > +               else
> > +                       dw->data_width[i] = pdata->data_width[i];
> > +       }
> 
> There are many autocfg, if, else statements now in probe. Can you try
> to group these
> into as minimum if, else calls?
Ok, will try to optimize it.

> > --- a/drivers/dma/dw_dmac_regs.h
> > +++ b/drivers/dma/dw_dmac_regs.h
> > @@ -106,6 +106,12 @@ struct dw_dma_regs {
> >
> >  /* Bitfields in DW_PARAMS */
> >  #define DW_PARAMS_NR_CHAN      8               /* number of channels */
> > +#define DW_PARAMS_NR_MASTER    11              /* number of AHB masters */
> > +#define DW_PARAMS_DATA_WIDTH(n)        (15 + 2 * (n))
> > +#define DW_PARAMS_DATA_WIDTH1  15              /* master 1 data width */
> > +#define DW_PARAMS_DATA_WIDTH2  17              /* master 2 data width */
> > +#define DW_PARAMS_DATA_WIDTH3  19              /* master 3 data width */
> > +#define DW_PARAMS_DATA_WIDTH4  21              /* master 4 data width */
> >  #define DW_PARAMS_EN           28              /* encoded parameters */

> Do these changes in a single patch 2/7
>From this comment I guess you would like to have dw_dmac_regs.h changes
at one place. Am I right?


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 6/7] dw_dmac: check if controller supports LLP
  2012-09-18  7:13   ` viresh kumar
@ 2012-09-20  9:43     ` Andy Shevchenko
  0 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:43 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 12:43 +0530, viresh kumar wrote: 
> On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > Some controllers have the reduced functionality where the LLP multi block
> > transfers are not supported. This patch introduces a check and refuses to deal
> > with such devices.
> >
> > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > ---
> >  drivers/dma/dw_dmac.c      |   35 ++++++++++++++++++++++++++++++++++-
> >  drivers/dma/dw_dmac_regs.h |    4 ++++
> >  2 files changed, 38 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> > index fdb7d5a..00958ad 100644
> > --- a/drivers/dma/dw_dmac.c
> > +++ b/drivers/dma/dw_dmac.c
> > @@ -647,6 +647,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
> >         unsigned int            dst_width;
> >         u32                     ctllo;
> >
> > +       if (dwc->nollp) {
> > +               dev_dbg(chan2dev(&dwc->chan),
> > +                               "channel doesn't support LLP transfers\n");
> > +               return NULL;
> > +       }
> 
> But this could have been a single block request. Isn't it?
I think we could discard this comment in regard to comments on next
patch.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers
  2012-09-18  7:17   ` viresh kumar
@ 2012-09-20  9:46     ` Andy Shevchenko
  0 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:46 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-18 at 12:47 +0530, viresh kumar wrote: 
> On Mon, Sep 17, 2012 at 1:09 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > @@ -555,8 +594,36 @@ static void dw_dma_tasklet(unsigned long data)
> >                         dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
> >                 else if (status_err & (1 << i))
> >                         dwc_handle_error(dw, dwc);
> > -               else if (status_xfer & (1 << i))
> > +               else if (status_xfer & (1 << i)) {
> > +                       unsigned long flags;
> > +
> > +                       spin_lock_irqsave(&dwc->lock, flags);
> > +                       if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
> > +                               if (dwc->tx_node_active != dwc->tx_list) {
> > +                                       struct dw_desc *desc =
> > +                                               list_entry(dwc->tx_node_active,
> > +                                                          struct dw_desc,
> > +                                                          desc_node);
> 
> can come in single line.
Depends on checkpatch.pl. Anyway I'll try to squeeze it.

> > @@ -647,12 +714,6 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
> >         unsigned int            dst_width;
> >         u32                     ctllo;
> >
> > -       if (dwc->nollp) {
> > -               dev_dbg(chan2dev(&dwc->chan),
> > -                               "channel doesn't support LLP transfers\n");
> > -               return NULL;
> > -       }
> > -
> 
> :)
> You should actually merge 6/7 with 7/7... You can't revert something
> in the same patchset.
Ok. It was done just in regard to have a bisectability working.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-20  9:42     ` Andy Shevchenko
@ 2012-09-20  9:46       ` viresh kumar
  2012-09-20  9:53         ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-20  9:46 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 20, 2012 at 3:12 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>> Do these changes in a single patch 2/7
> From this comment I guess you would like to have dw_dmac_regs.h changes
> at one place. Am I right?

yes.

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

* Re: [PATCH 0/7] dw_dmac: introduce autoconfiguration
  2012-09-18  6:11 ` Hein Tibosch
  2012-09-18  7:18   ` viresh kumar
@ 2012-09-20  9:48   ` Andy Shevchenko
  1 sibling, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:48 UTC (permalink / raw)
  To: Hein Tibosch
  Cc: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel,
	ludovic.desroches, Nicolas Ferre, Hans-Christian Egtvedt

On Tue, 2012-09-18 at 14:11 +0800, Hein Tibosch wrote: 
> On 9/17/2012 3:39 PM, Andy Shevchenko wrote:
> > Here is a patchset that allows to adapt the driver to the hardware
> > configuration during probe time. The hardware should have the specific optional
> > parameters enabled. Otherwise the driver will consider values stored in the
> > platform data.
> >
> > Additionally it brings support of the software LLP transfers. It means that
> > normal linked list transfer is substituted by set of single block transfers
> > transparently to the user.
> >
> > Comments are welcome.
> >
> > Andy Shevchenko (7):
> >   dw_dmac: mark dwc_dump_chan_regs as inline
> >   dw_dmac: fill optional encoded parameters in register structure
> >   dw_dmac: get number of channels from hardware if possible
> >   dw_dmac: autoconfigure block_size or use platform data
> >   dw_dmac: autoconfigure data_width or get it via platform data
> >   dw_dmac: check if controller supports LLP
> >   dw_dmac: introduce software emulation of LLP transfers
> >
> >  arch/arm/mach-spear13xx/spear13xx.c |    3 +
> >  arch/avr32/mach-at32ap/at32ap700x.c |    3 +
> >  drivers/dma/dw_dmac.c               |  207 +++++++++++++++++++++++++++++------
> >  drivers/dma/dw_dmac_regs.h          |   48 ++++++++
> >  include/linux/dw_dmac.h             |    7 ++
> >  5 files changed, 235 insertions(+), 33 deletions(-)
> Andy,
> 
> The (embedded) dw dma on the AP7000 indeed does not support auto
> configuration (the register reads as zero)
Nice to have the test report. I have no devices around without auto
configuration block.

> and so it needs the platform data.
> 
> I tested the driver on AVR32 with the atmel-mci driver and it all
> worked well.

> I also tested the new software emulation of LLP mode by setting
> nollp for each channel to true. That also worked as expected.

Thanks!

> Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure
  2012-09-20  9:32           ` viresh kumar
@ 2012-09-20  9:51             ` Andy Shevchenko
  0 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:51 UTC (permalink / raw)
  To: viresh kumar
  Cc: Andy Shevchenko, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 20, 2012 at 12:32 PM, viresh kumar <viresh.kumar@linaro.org> wrote:
> On Thu, Sep 20, 2012 at 3:00 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
>>> Ok. If i am not wrong, such calls are only required once for below line:
>> Actually twice...
>>> dw_params = dma_raw_readl(regs, DW_PARAMS
>> ...here and for channel parameters.
>
> Till the time we hit channel code, we can allocate memory for dw and so
> can use dma_readl/writel. Isn't it?
Actually no. Becase we have the same name for 8 registers.

-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-20  9:46       ` viresh kumar
@ 2012-09-20  9:53         ` Andy Shevchenko
  0 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-20  9:53 UTC (permalink / raw)
  To: viresh kumar
  Cc: Andy Shevchenko, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 20, 2012 at 12:46 PM, viresh kumar <viresh.kumar@linaro.org> wrote:
> On Thu, Sep 20, 2012 at 3:12 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
>>> Do these changes in a single patch 2/7
>> From this comment I guess you would like to have dw_dmac_regs.h changes
>> at one place. Am I right?
>
> yes.
Okay, will do.

-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCH 3/7] dw_dmac: get number of channels from hardware if possible
  2012-09-20  9:40       ` viresh kumar
@ 2012-09-21  6:04         ` viresh kumar
  0 siblings, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-21  6:04 UTC (permalink / raw)
  To: Andy Shevchenko, Shiraz HASHIM
  Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 20, 2012 at 3:10 PM, viresh kumar <viresh.kumar@linaro.org> wrote:
> On Thu, Sep 20, 2012 at 3:05 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
>> On Tue, 2012-09-18 at 12:20 +0530, viresh kumar wrote:
>>> > @@ -1392,23 +1396,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
>>> > +       dw_params = dma_raw_readl(regs, DW_PARAMS);
>>>
>>> Is this valid for every SoC implementation. What if this configuration
>>> is not valid
>>> for a particular SoC and it is invalid to access this address? Or this
>>> gives a invalid
>>> value instead of returning 0?
>
>> Actually I didn't get it clearly from the documentation. We have only
>> one test report from Hein until now.
>
> @Shiraz: Can you please verify reading this register from u-boot? This
> is important before we apply this patch to linux-next.

Ok. I have verified from the documentation. This are valid registers for SPEAr.
@Shiraz: No need to check now. :)

--
viresh

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

* [PATCHv2 0/6] dw_dmac: introduce autoconfiguration
  2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
                   ` (8 preceding siblings ...)
  2012-09-18  6:11 ` Hein Tibosch
@ 2012-09-21 12:05 ` Andy Shevchenko
  2012-09-21 12:05   ` [PATCHv2 1/6] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
                     ` (6 more replies)
  9 siblings, 7 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Here is a patchset that allows to adapt the driver to the hardware
configuration during probe time. The hardware should have the specific optional
parameters enabled. Otherwise the driver will consider values stored in the
platform data.

Additionally it brings support of the software LLP transfers. It means that
normal linked list transfer is substituted by set of single block transfers
transparently to the user.

Since v1:
 - addressed all Viresh's comments.

Andy Shevchenko (6):
  dw_dmac: mark dwc_dump_chan_regs as inline
  dw_dmac: fill optional encoded parameters in register structure
  dw_dmac: get number of channels from hardware if possible
  dw_dmac: autoconfigure block_size or use platform data
  dw_dmac: autoconfigure data_width or get it via platform data
  dw_dmac: introduce software emulation of LLP transfers

 arch/arm/mach-spear13xx/spear13xx.c |    3 +
 arch/avr32/mach-at32ap/at32ap700x.c |    3 +
 drivers/dma/dw_dmac.c               |  209 +++++++++++++++++++++++++++++------
 drivers/dma/dw_dmac_regs.h          |   46 ++++++++
 include/linux/dw_dmac.h             |    7 ++
 5 files changed, 235 insertions(+), 33 deletions(-)

-- 
1.7.10.4


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

* [PATCHv2 1/6] dw_dmac: mark dwc_dump_chan_regs as inline
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
@ 2012-09-21 12:05   ` Andy Shevchenko
  2012-09-21 12:05   ` [PATCHv2 2/6] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/dma/dw_dmac.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 8db1ab2..2272f79 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -213,7 +213,7 @@ static inline unsigned int dwc_fast_fls(unsigned long long v)
 	return 0;
 }
 
-static void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
+static inline void dwc_dump_chan_regs(struct dw_dma_chan *dwc)
 {
 	dev_err(chan2dev(&dwc->chan),
 		"  SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
-- 
1.7.10.4


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

* [PATCHv2 2/6] dw_dmac: fill optional encoded parameters in register structure
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
  2012-09-21 12:05   ` [PATCHv2 1/6] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
@ 2012-09-21 12:05   ` Andy Shevchenko
  2012-09-21 13:55     ` viresh kumar
  2012-09-21 12:05   ` [PATCHv2 3/6] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

There is a block of the registers that are optional. However, if enabled they
contain useful information about the controller hardware configuration. We will
use this piece of data to autoconfigure the driver.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac_regs.h |   30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index f6d92d7..8a3a81a 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -82,9 +82,39 @@ struct dw_dma_regs {
 	DW_REG(ID);
 	DW_REG(TEST);
 
+	/* reserved */
+	DW_REG(__reserved0);
+	DW_REG(__reserved1);
+
 	/* optional encoded params, 0x3c8..0x3f7 */
+	u32	__reserved;
+
+	/* per-channel configuration registers */
+	u32	DWC_PARAMS[DW_DMA_MAX_NR_CHANNELS];
+	u32	MULTI_BLK_TYPE;
+	u32	MAX_BLK_SIZE;
+
+	/* top-level parameters */
+	u32	DW_PARAMS;
 };
 
+/* To access the registers in early stage of probe */
+#define dma_read_byaddr(addr, name) \
+	readl((addr) + offsetof(struct dw_dma_regs, name))
+
+/* Bitfields in DW_PARAMS */
+#define DW_PARAMS_NR_CHAN	8		/* number of channels */
+#define DW_PARAMS_NR_MASTER	11		/* number of AHB masters */
+#define DW_PARAMS_DATA_WIDTH(n)	(15 + 2 * (n))
+#define DW_PARAMS_DATA_WIDTH1	15		/* master 1 data width */
+#define DW_PARAMS_DATA_WIDTH2	17		/* master 2 data width */
+#define DW_PARAMS_DATA_WIDTH3	19		/* master 3 data width */
+#define DW_PARAMS_DATA_WIDTH4	21		/* master 4 data width */
+#define DW_PARAMS_EN		28		/* encoded parameters */
+
+/* Bitfields in DWC_PARAMS */
+#define DWC_PARAMS_MBLK_EN	11		/* multi block transfer */
+
 /* Bitfields in CTL_LO */
 #define DWC_CTLL_INT_EN		(1 << 0)	/* irqs enabled? */
 #define DWC_CTLL_DST_WIDTH(n)	((n)<<1)	/* bytes per element */
-- 
1.7.10.4


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

* [PATCHv2 3/6] dw_dmac: get number of channels from hardware if possible
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
  2012-09-21 12:05   ` [PATCHv2 1/6] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
  2012-09-21 12:05   ` [PATCHv2 2/6] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
@ 2012-09-21 12:05   ` Andy Shevchenko
  2012-09-21 13:56     ` viresh kumar
  2012-09-21 12:05   ` [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

In case the controller has the encoded parameters feature enabled the driver
will use it to get the number of channels. In the future it will be used for
the other important parameters as well.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac.c |   33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 2272f79..c964f6e 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1381,6 +1381,10 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	struct resource		*io;
 	struct dw_dma		*dw;
 	size_t			size;
+	void __iomem		*regs;
+	bool			autocfg;
+	unsigned int		dw_params;
+	unsigned int		nr_channels;
 	int			irq;
 	int			err;
 	int			i;
@@ -1397,23 +1401,32 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
-	size = sizeof(struct dw_dma);
-	size += pdata->nr_channels * sizeof(struct dw_dma_chan);
+	regs = devm_request_and_ioremap(&pdev->dev, io);
+	if (!regs)
+		return -EBUSY;
+
+	dw_params = dma_read_byaddr(regs, DW_PARAMS);
+	autocfg = dw_params >> DW_PARAMS_EN & 0x1;
+
+	if (autocfg)
+		nr_channels = (dw_params >> DW_PARAMS_NR_CHAN & 0x7) + 1;
+	else
+		nr_channels = pdata->nr_channels;
+
+	size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
 	dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
 	if (!dw)
 		return -ENOMEM;
 
-	dw->regs = devm_request_and_ioremap(&pdev->dev, io);
-	if (!dw->regs)
-		return -EBUSY;
-
 	dw->clk = devm_clk_get(&pdev->dev, "hclk");
 	if (IS_ERR(dw->clk))
 		return PTR_ERR(dw->clk);
 	clk_prepare_enable(dw->clk);
 
+	dw->regs = regs;
+
 	/* Calculate all channel mask before DMA setup */
-	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
+	dw->all_chan_mask = (1 << nr_channels) - 1;
 
 	/* force dma off, just in case */
 	dw_dma_off(dw);
@@ -1431,7 +1444,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
 
 	INIT_LIST_HEAD(&dw->dma.channels);
-	for (i = 0; i < pdata->nr_channels; i++) {
+	for (i = 0; i < nr_channels; i++) {
 		struct dw_dma_chan	*dwc = &dw->chan[i];
 
 		dwc->chan.device = &dw->dma;
@@ -1444,7 +1457,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		/* 7 is highest priority & 0 is lowest. */
 		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
-			dwc->priority = pdata->nr_channels - i - 1;
+			dwc->priority = nr_channels - i - 1;
 		else
 			dwc->priority = i;
 
@@ -1485,7 +1498,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	dma_writel(dw, CFG, DW_CFG_DMA_EN);
 
 	printk(KERN_INFO "%s: DesignWare DMA Controller, %d channels\n",
-			dev_name(&pdev->dev), pdata->nr_channels);
+			dev_name(&pdev->dev), nr_channels);
 
 	dma_async_device_register(&dw->dma);
 
-- 
1.7.10.4


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

* [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
                     ` (2 preceding siblings ...)
  2012-09-21 12:05   ` [PATCHv2 3/6] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
@ 2012-09-21 12:05   ` Andy Shevchenko
  2012-09-21 14:00     ` viresh kumar
  2012-09-21 12:05   ` [PATCHv2 5/6] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

The maximum block size is a configurable parameter for the chip. So, driver
will try to get it from the encoded component parameters. Otherwise it will
come from the platform data.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 arch/arm/mach-spear13xx/spear13xx.c |    1 +
 arch/avr32/mach-at32ap/at32ap700x.c |    1 +
 drivers/dma/dw_dmac.c               |   37 ++++++++++++++++++++---------------
 drivers/dma/dw_dmac_regs.h          |    3 +++
 include/linux/dw_dmac.h             |    2 ++
 5 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index e106488..9491137 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -78,6 +78,7 @@ struct dw_dma_platform_data dmac_plat_data = {
 	.nr_channels = 8,
 	.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
 	.chan_priority = CHAN_PRIORITY_DESCENDING,
+	.block_size = 4095U,
 };
 
 void __init spear13xx_l2x0_init(void)
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 0445c4f..2c4aefe 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -605,6 +605,7 @@ static void __init genclk_init_parent(struct clk *clk)
 
 static struct dw_dma_platform_data dw_dmac0_data = {
 	.nr_channels	= 3,
+	.block_size	= 4095U,
 };
 
 static struct resource dw_dmac0_resource[] = {
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index c964f6e..4af9fad 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -58,16 +58,6 @@
 	})
 
 /*
- * This is configuration-dependent and usually a funny size like 4095.
- *
- * Note that this is a transfer count, i.e. if we transfer 32-bit
- * words, we can do 16380 bytes per descriptor.
- *
- * This parameter is also system-specific.
- */
-#define DWC_MAX_COUNT	4095U
-
-/*
  * Number of descriptors to allocate for each channel. This should be
  * made configurable somehow; preferably, the clients (at least the
  * ones using slave transfers) should be able to give us a hint.
@@ -674,7 +664,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
 	for (offset = 0; offset < len; offset += xfer_count << src_width) {
 		xfer_count = min_t(size_t, (len - offset) >> src_width,
-				DWC_MAX_COUNT);
+					   dwc->block_size);
 
 		desc = dwc_desc_get(dwc);
 		if (!desc)
@@ -775,8 +765,8 @@ slave_sg_todev_fill_desc:
 			desc->lli.sar = mem;
 			desc->lli.dar = reg;
 			desc->lli.ctllo = ctllo | DWC_CTLL_SRC_WIDTH(mem_width);
-			if ((len >> mem_width) > DWC_MAX_COUNT) {
-				dlen = DWC_MAX_COUNT << mem_width;
+			if ((len >> mem_width) > dwc->block_size) {
+				dlen = dwc->block_size << mem_width;
 				mem += dlen;
 				len -= dlen;
 			} else {
@@ -835,8 +825,8 @@ slave_sg_fromdev_fill_desc:
 			desc->lli.sar = reg;
 			desc->lli.dar = mem;
 			desc->lli.ctllo = ctllo | DWC_CTLL_DST_WIDTH(mem_width);
-			if ((len >> reg_width) > DWC_MAX_COUNT) {
-				dlen = DWC_MAX_COUNT << reg_width;
+			if ((len >> reg_width) > dwc->block_size) {
+				dlen = dwc->block_size << reg_width;
 				mem += dlen;
 				len -= dlen;
 			} else {
@@ -1219,7 +1209,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
 	periods = buf_len / period_len;
 
 	/* Check for too big/unaligned periods and unaligned DMA buffer. */
-	if (period_len > (DWC_MAX_COUNT << reg_width))
+	if (period_len > (dwc->block_size << reg_width))
 		goto out_err;
 	if (unlikely(period_len & ((1 << reg_width) - 1)))
 		goto out_err;
@@ -1385,6 +1375,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	bool			autocfg;
 	unsigned int		dw_params;
 	unsigned int		nr_channels;
+	unsigned int		max_blk_size = 0;
 	int			irq;
 	int			err;
 	int			i;
@@ -1425,6 +1416,10 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 	dw->regs = regs;
 
+	/* get hardware configuration parameters */
+	if (autocfg)
+		max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
+
 	/* Calculate all channel mask before DMA setup */
 	dw->all_chan_mask = (1 << nr_channels) - 1;
 
@@ -1470,6 +1465,16 @@ static int __devinit dw_probe(struct platform_device *pdev)
 		INIT_LIST_HEAD(&dwc->free_list);
 
 		channel_clear_bit(dw, CH_EN, dwc->mask);
+
+		/* hardware configuration */
+		if (autocfg)
+			/* Decode maximum block size for given channel. The
+			 * stored 4 bit value represents blocks from 0x00 for 3
+			 * up to 0x0a for 4095. */
+			dwc->block_size =
+				(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
+		else
+			dwc->block_size = pdata->block_size;
 	}
 
 	/* Clear all interrupts on all channels. */
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 8a3a81a..2a1cc53 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -193,6 +193,9 @@ struct dw_dma_chan {
 
 	unsigned int		descs_allocated;
 
+	/* hardware configuration */
+	unsigned int		block_size;
+
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
 };
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 2412e02..3315ef9 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -19,6 +19,7 @@
  * @nr_channels: Number of channels supported by hardware (max 8)
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
+ * @block_size: Maximum block size supported by the controller
  */
 struct dw_dma_platform_data {
 	unsigned int	nr_channels;
@@ -29,6 +30,7 @@ struct dw_dma_platform_data {
 #define CHAN_PRIORITY_ASCENDING		0	/* chan0 highest */
 #define CHAN_PRIORITY_DESCENDING	1	/* chan7 highest */
 	unsigned char	chan_priority;
+	unsigned short	block_size;
 };
 
 /* bursts size */
-- 
1.7.10.4


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

* [PATCHv2 5/6] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
                     ` (3 preceding siblings ...)
  2012-09-21 12:05   ` [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
@ 2012-09-21 12:05   ` Andy Shevchenko
  2012-09-21 14:02     ` viresh kumar
  2012-09-21 12:05   ` [PATCHv2 6/6] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
  2012-09-27 10:05   ` [PATCHv2 0/6] dw_dmac: introduce autoconfiguration Vinod Koul
  6 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Not all of the controllers support the 64 bit data width. Make it configurable
via platform data. The driver will try to get a value from the component
parameters, otherwise it will use the platform data.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 arch/arm/mach-spear13xx/spear13xx.c |    2 ++
 arch/avr32/mach-at32ap/at32ap700x.c |    2 ++
 drivers/dma/dw_dmac.c               |   46 ++++++++++++++++++++++++++++++-----
 drivers/dma/dw_dmac_regs.h          |    7 ++++++
 include/linux/dw_dmac.h             |    5 ++++
 5 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index 9491137..5633d69 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -79,6 +79,8 @@ struct dw_dma_platform_data dmac_plat_data = {
 	.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
 	.chan_priority = CHAN_PRIORITY_DESCENDING,
 	.block_size = 4095U,
+	.nr_masters = 2,
+	.data_width = { 3, 3, 0, 0 },
 };
 
 void __init spear13xx_l2x0_init(void)
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 2c4aefe..b323d8d 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -606,6 +606,8 @@ static void __init genclk_init_parent(struct clk *clk)
 static struct dw_dma_platform_data dw_dmac0_data = {
 	.nr_channels	= 3,
 	.block_size	= 4095U,
+	.nr_masters	= 2,
+	.data_width	= { 2, 2, 0, 0 },
 };
 
 static struct resource dw_dmac0_resource[] = {
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 4af9fad..d47b76a 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -38,12 +38,22 @@
  * which does not support descriptor writeback.
  */
 
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+	return slave ? slave->dst_master : 0;
+}
+
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+	return slave ? slave->src_master : 1;
+}
+
 #define DWC_DEFAULT_CTLLO(_chan) ({				\
 		struct dw_dma_slave *__slave = (_chan->private);	\
 		struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan);	\
 		struct dma_slave_config	*_sconfig = &_dwc->dma_sconfig;	\
-		int _dms = __slave ? __slave->dst_master : 0;	\
-		int _sms = __slave ? __slave->src_master : 1;	\
+		int _dms = dwc_get_dms(__slave);		\
+		int _sms = dwc_get_sms(__slave);		\
 		u8 _smsize = __slave ? _sconfig->src_maxburst :	\
 			DW_DMA_MSIZE_16;			\
 		u8 _dmsize = __slave ? _sconfig->dst_maxburst :	\
@@ -633,6 +643,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		size_t len, unsigned long flags)
 {
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
+	struct dw_dma_slave	*dws = chan->private;
 	struct dw_desc		*desc;
 	struct dw_desc		*first;
 	struct dw_desc		*prev;
@@ -652,7 +663,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		return NULL;
 	}
 
-	src_width = dst_width = dwc_fast_fls(src | dest | len);
+	src_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_sms(dws)],
+			  dwc_fast_fls(src | len));
+
+	dst_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_dms(dws)],
+			  dwc_fast_fls(dest | len));
 
 	ctllo = DWC_DEFAULT_CTLLO(chan)
 			| DWC_CTLL_DST_WIDTH(dst_width)
@@ -722,6 +737,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	dma_addr_t		reg;
 	unsigned int		reg_width;
 	unsigned int		mem_width;
+	unsigned int		data_width;
 	unsigned int		i;
 	struct scatterlist	*sg;
 	size_t			total_len = 0;
@@ -745,6 +761,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
 			DWC_CTLL_FC(DW_DMA_FC_D_M2P);
 
+		data_width = dwc->dw->data_width[dwc_get_sms(dws)];
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
@@ -752,7 +770,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = dwc_fast_fls(mem | len);
+			mem_width = min_t(unsigned int,
+					  data_width, dwc_fast_fls(mem | len));
 
 slave_sg_todev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -805,6 +824,8 @@ slave_sg_todev_fill_desc:
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
 			DWC_CTLL_FC(DW_DMA_FC_D_P2M);
 
+		data_width = dwc->dw->data_width[dwc_get_dms(dws)];
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
@@ -812,7 +833,8 @@ slave_sg_todev_fill_desc:
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = dwc_fast_fls(mem | len);
+			mem_width = min_t(unsigned int,
+					  data_width, dwc_fast_fls(mem | len));
 
 slave_sg_fromdev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -1417,9 +1439,19 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	dw->regs = regs;
 
 	/* get hardware configuration parameters */
-	if (autocfg)
+	if (autocfg) {
 		max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
 
+		dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
+		for (i = 0; i < dw->nr_masters; i++) {
+			dw->data_width[i] =
+				(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
+		}
+	} else {
+		dw->nr_masters = pdata->nr_masters;
+		memcpy(dw->data_width, pdata->data_width, 4);
+	}
+
 	/* Calculate all channel mask before DMA setup */
 	dw->all_chan_mask = (1 << nr_channels) - 1;
 
@@ -1466,6 +1498,8 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		channel_clear_bit(dw, CH_EN, dwc->mask);
 
+		dwc->dw = dw;
+
 		/* hardware configuration */
 		if (autocfg)
 			/* Decode maximum block size for given channel. The
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 2a1cc53..06f0391 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -198,6 +198,9 @@ struct dw_dma_chan {
 
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
+
+	/* backlink to dw_dma */
+	struct dw_dma		*dw;
 };
 
 static inline struct dw_dma_chan_regs __iomem *
@@ -224,6 +227,10 @@ struct dw_dma {
 
 	u8			all_chan_mask;
 
+	/* hardware configuration */
+	unsigned char		nr_masters;
+	unsigned char		data_width[4];
+
 	struct dw_dma_chan	chan[0];
 };
 
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 3315ef9..e1c8c9e 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -20,6 +20,9 @@
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
  * @block_size: Maximum block size supported by the controller
+ * @nr_masters: Number of AHB masters supported by the controller
+ * @data_width: Maximum data width supported by hardware per AHB master
+ *		(0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
  */
 struct dw_dma_platform_data {
 	unsigned int	nr_channels;
@@ -31,6 +34,8 @@ struct dw_dma_platform_data {
 #define CHAN_PRIORITY_DESCENDING	1	/* chan7 highest */
 	unsigned char	chan_priority;
 	unsigned short	block_size;
+	unsigned char	nr_masters;
+	unsigned char	data_width[4];
 };
 
 /* bursts size */
-- 
1.7.10.4


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

* [PATCHv2 6/6] dw_dmac: introduce software emulation of LLP transfers
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
                     ` (4 preceding siblings ...)
  2012-09-21 12:05   ` [PATCHv2 5/6] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
@ 2012-09-21 12:05   ` Andy Shevchenko
  2012-09-21 14:03     ` viresh kumar
  2012-09-27 10:05   ` [PATCHv2 0/6] dw_dmac: introduce autoconfiguration Vinod Koul
  6 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 12:05 UTC (permalink / raw)
  To: Viresh Kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Some controllers have the reduced functionality where the LLP multi block
transfers are not supported. This patch introduces a support of such
controllers. In case of memory copy or scatter-gather lists it emulates LLP
transfers via bunch of the regular single block ones.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw_dmac.c      |   99 ++++++++++++++++++++++++++++++++++++++++++--
 drivers/dma/dw_dmac_regs.h |    6 +++
 2 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index d47b76a..47b9b3e 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -234,10 +234,29 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
 
 /*----------------------------------------------------------------------*/
 
+/* Perform single block transfer */
+static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
+				       struct dw_desc *desc)
+{
+	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
+	u32		ctllo;
+
+	/* Software emulation of LLP mode relies on interrupts to continue
+	 * multi block transfer. */
+	ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
+
+	channel_writel(dwc, SAR, desc->lli.sar);
+	channel_writel(dwc, DAR, desc->lli.dar);
+	channel_writel(dwc, CTL_LO, ctllo);
+	channel_writel(dwc, CTL_HI, desc->lli.ctlhi);
+	channel_set_bit(dw, CH_EN, dwc->mask);
+}
+
 /* Called with dwc->lock held and bh disabled */
 static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 {
 	struct dw_dma	*dw = to_dw_dma(dwc->chan.device);
+	unsigned long	was_soft_llp;
 
 	/* ASSERT:  channel is idle */
 	if (dma_readl(dw, CH_EN) & dwc->mask) {
@@ -249,6 +268,26 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
 		return;
 	}
 
+	if (dwc->nollp) {
+		was_soft_llp = test_and_set_bit(DW_DMA_IS_SOFT_LLP,
+						&dwc->flags);
+		if (was_soft_llp) {
+			dev_err(chan2dev(&dwc->chan),
+				"BUG: Attempted to start new LLP transfer "
+				"inside ongoing one\n");
+			return;
+		}
+
+		dwc_initialize(dwc);
+
+		dwc->tx_list = &first->tx_list;
+		dwc->tx_node_active = first->tx_list.next;
+
+		dwc_do_single_block(dwc, first);
+
+		return;
+	}
+
 	dwc_initialize(dwc);
 
 	channel_writel(dwc, LLP, first->txd.phys);
@@ -560,8 +599,36 @@ static void dw_dma_tasklet(unsigned long data)
 			dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
 		else if (status_err & (1 << i))
 			dwc_handle_error(dw, dwc);
-		else if (status_xfer & (1 << i))
+		else if (status_xfer & (1 << i)) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&dwc->lock, flags);
+			if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
+				if (dwc->tx_node_active != dwc->tx_list) {
+					struct dw_desc *desc =
+						list_entry(dwc->tx_node_active,
+							   struct dw_desc,
+							   desc_node);
+
+					dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+					/* move pointer to next descriptor */
+					dwc->tx_node_active =
+						dwc->tx_node_active->next;
+
+					dwc_do_single_block(dwc, desc);
+
+					spin_unlock_irqrestore(&dwc->lock, flags);
+					continue;
+				} else {
+					/* we are done here */
+					clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+				}
+			}
+			spin_unlock_irqrestore(&dwc->lock, flags);
+
 			dwc_scan_descriptors(dw, dwc);
+		}
 	}
 
 	/*
@@ -964,6 +1031,8 @@ static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 	} else if (cmd == DMA_TERMINATE_ALL) {
 		spin_lock_irqsave(&dwc->lock, flags);
 
+		clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+
 		dwc_chan_disable(dw, dwc);
 
 		dwc->paused = false;
@@ -1206,6 +1275,13 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
 	unsigned long			flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+	if (dwc->nollp) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dev_dbg(chan2dev(&dwc->chan),
+				"channel doesn't support LLP transfers\n");
+		return ERR_PTR(-EINVAL);
+	}
+
 	if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) {
 		spin_unlock_irqrestore(&dwc->lock, flags);
 		dev_dbg(chan2dev(&dwc->chan),
@@ -1473,6 +1549,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&dw->dma.channels);
 	for (i = 0; i < nr_channels; i++) {
 		struct dw_dma_chan	*dwc = &dw->chan[i];
+		int			r = nr_channels - i - 1;
 
 		dwc->chan.device = &dw->dma;
 		dma_cookie_init(&dwc->chan);
@@ -1484,7 +1561,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		/* 7 is highest priority & 0 is lowest. */
 		if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING)
-			dwc->priority = nr_channels - i - 1;
+			dwc->priority = r;
 		else
 			dwc->priority = i;
 
@@ -1501,14 +1578,28 @@ static int __devinit dw_probe(struct platform_device *pdev)
 		dwc->dw = dw;
 
 		/* hardware configuration */
-		if (autocfg)
+		if (autocfg) {
+			unsigned int dwc_params;
+
+			dwc_params = dma_read_byaddr(regs + r * sizeof(u32),
+						     DWC_PARAMS);
+
 			/* Decode maximum block size for given channel. The
 			 * stored 4 bit value represents blocks from 0x00 for 3
 			 * up to 0x0a for 4095. */
 			dwc->block_size =
 				(4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
-		else
+			dwc->nollp =
+				(dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
+		} else {
 			dwc->block_size = pdata->block_size;
+
+			/* Check if channel supports multi block transfer */
+			channel_writel(dwc, LLP, 0xfffffffc);
+			dwc->nollp =
+				(channel_readl(dwc, LLP) & 0xfffffffc) == 0;
+			channel_writel(dwc, LLP, 0);
+		}
 	}
 
 	/* Clear all interrupts on all channels. */
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 06f0391..ff39fa6 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -172,6 +172,7 @@ struct dw_dma_regs {
 
 enum dw_dmac_flags {
 	DW_DMA_IS_CYCLIC = 0,
+	DW_DMA_IS_SOFT_LLP = 1,
 };
 
 struct dw_dma_chan {
@@ -182,6 +183,10 @@ struct dw_dma_chan {
 	bool			paused;
 	bool			initialized;
 
+	/* software emulation of the LLP transfers */
+	struct list_head	*tx_list;
+	struct list_head	*tx_node_active;
+
 	spinlock_t		lock;
 
 	/* these other elements are all protected by lock */
@@ -195,6 +200,7 @@ struct dw_dma_chan {
 
 	/* hardware configuration */
 	unsigned int		block_size;
+	bool			nollp;
 
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
-- 
1.7.10.4


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

* Re: [PATCHv2 2/6] dw_dmac: fill optional encoded parameters in register structure
  2012-09-21 12:05   ` [PATCHv2 2/6] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
@ 2012-09-21 13:55     ` viresh kumar
  0 siblings, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-21 13:55 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> There is a block of the registers that are optional. However, if enabled they
> contain useful information about the controller hardware configuration. We will
> use this piece of data to autoconfigure the driver.

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* Re: [PATCHv2 3/6] dw_dmac: get number of channels from hardware if possible
  2012-09-21 12:05   ` [PATCHv2 3/6] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
@ 2012-09-21 13:56     ` viresh kumar
  0 siblings, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-21 13:56 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> In case the controller has the encoded parameters feature enabled the driver
> will use it to get the number of channels. In the future it will be used for
> the other important parameters as well.

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* Re: [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data
  2012-09-21 12:05   ` [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
@ 2012-09-21 14:00     ` viresh kumar
  2012-09-21 15:09       ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-21 14:00 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> @@ -1385,6 +1375,7 @@ static int __devinit dw_probe(struct platform_device *pdev)

> +       /* get hardware configuration parameters */
> +       if (autocfg)
> +               max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
> +

Why don't you do above with the below ++ code

>         /* Calculate all channel mask before DMA setup */
>         dw->all_chan_mask = (1 << nr_channels) - 1;
>
> @@ -1470,6 +1465,16 @@ static int __devinit dw_probe(struct platform_device *pdev)
>                 INIT_LIST_HEAD(&dwc->free_list);
>
>                 channel_clear_bit(dw, CH_EN, dwc->mask);
> +
> +               /* hardware configuration */
> +               if (autocfg)
> +                       /* Decode maximum block size for given channel. The
> +                        * stored 4 bit value represents blocks from 0x00 for 3
> +                        * up to 0x0a for 4095. */

i.e. here?

> +                       dwc->block_size =
> +                               (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
> +               else
> +                       dwc->block_size = pdata->block_size;
>         }

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

* Re: [PATCHv2 5/6] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-21 12:05   ` [PATCHv2 5/6] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
@ 2012-09-21 14:02     ` viresh kumar
  2012-09-25 11:39       ` [PATCHv3] " Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: viresh kumar @ 2012-09-21 14:02 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> Not all of the controllers support the 64 bit data width. Make it configurable
> via platform data. The driver will try to get a value from the component
> parameters, otherwise it will use the platform data.

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* Re: [PATCHv2 6/6] dw_dmac: introduce software emulation of LLP transfers
  2012-09-21 12:05   ` [PATCHv2 6/6] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
@ 2012-09-21 14:03     ` viresh kumar
  0 siblings, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-21 14:03 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> Some controllers have the reduced functionality where the LLP multi block
> transfers are not supported. This patch introduces a support of such
> controllers. In case of memory copy or scatter-gather lists it emulates LLP
> transfers via bunch of the regular single block ones.

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* Re: [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data
  2012-09-21 14:00     ` viresh kumar
@ 2012-09-21 15:09       ` Andy Shevchenko
  2012-09-21 15:30         ` Viresh Kumar
  0 siblings, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-21 15:09 UTC (permalink / raw)
  To: viresh kumar; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Fri, 2012-09-21 at 19:30 +0530, viresh kumar wrote: 
> On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
> > @@ -1385,6 +1375,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
> 
> > +       /* get hardware configuration parameters */
> > +       if (autocfg)
> > +               max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
> > +
> 
> Why don't you do above with the below ++ code
> 
> >         /* Calculate all channel mask before DMA setup */
> >         dw->all_chan_mask = (1 << nr_channels) - 1;
> >
> > @@ -1470,6 +1465,16 @@ static int __devinit dw_probe(struct platform_device *pdev)
> >                 INIT_LIST_HEAD(&dwc->free_list);
> >
> >                 channel_clear_bit(dw, CH_EN, dwc->mask);
> > +
> > +               /* hardware configuration */
> > +               if (autocfg)
> > +                       /* Decode maximum block size for given channel. The
> > +                        * stored 4 bit value represents blocks from 0x00 for 3
> > +                        * up to 0x0a for 4095. */
> 
> i.e. here?
Because there is only one register, but we have loop for channels. Shall
we read the same register as many times as amount of channels we have?

> 
> > +                       dwc->block_size =
> > +                               (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
> > +               else
> > +                       dwc->block_size = pdata->block_size;
> >         }

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data
  2012-09-21 15:09       ` Andy Shevchenko
@ 2012-09-21 15:30         ` Viresh Kumar
  0 siblings, 0 replies; 58+ messages in thread
From: Viresh Kumar @ 2012-09-21 15:30 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On 21 September 2012 20:39, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> On Fri, 2012-09-21 at 19:30 +0530, viresh kumar wrote:
>> On Fri, Sep 21, 2012 at 5:35 PM, Andy Shevchenko
>> <andriy.shevchenko@linux.intel.com> wrote:
>> > diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
>> > @@ -1385,6 +1375,7 @@ static int __devinit dw_probe(struct platform_device *pdev)
>>
>> > +       /* get hardware configuration parameters */
>> > +       if (autocfg)
>> > +               max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
>> > +
>>
>> Why don't you do above with the below ++ code
>>
>> >         /* Calculate all channel mask before DMA setup */
>> >         dw->all_chan_mask = (1 << nr_channels) - 1;
>> >
>> > @@ -1470,6 +1465,16 @@ static int __devinit dw_probe(struct platform_device *pdev)
>> >                 INIT_LIST_HEAD(&dwc->free_list);
>> >
>> >                 channel_clear_bit(dw, CH_EN, dwc->mask);
>> > +
>> > +               /* hardware configuration */
>> > +               if (autocfg)
>> > +                       /* Decode maximum block size for given channel. The
>> > +                        * stored 4 bit value represents blocks from 0x00 for 3
>> > +                        * up to 0x0a for 4095. */
>>
>> i.e. here?
> Because there is only one register, but we have loop for channels. Shall
> we read the same register as many times as amount of channels we have?

Obviously not :)
I misread the code.

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-21 14:02     ` viresh kumar
@ 2012-09-25 11:39       ` Andy Shevchenko
  2012-09-26  3:29         ` viresh kumar
  2012-09-27 10:06         ` Vinod Koul
  0 siblings, 2 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-25 11:39 UTC (permalink / raw)
  To: viresh.kumar, Vinod Koul, spear-devel, linux-kernel, Hein Tibosch
  Cc: Andy Shevchenko

Not all of the controllers support the 64 bit data width. Make it configurable
via platform data. The driver will try to get a value from the component
parameters, otherwise it will use the platform data.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
Since v2:
- sometimes memory-to-memory test is failed, that's why we need to choose
  minimum data portion between source and destination limits

 arch/arm/mach-spear13xx/spear13xx.c |    2 ++
 arch/avr32/mach-at32ap/at32ap700x.c |    2 ++
 drivers/dma/dw_dmac.c               |   47 ++++++++++++++++++++++++++++++-----
 drivers/dma/dw_dmac_regs.h          |    7 ++++++
 include/linux/dw_dmac.h             |    5 ++++
 5 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c
index 9491137..5633d69 100644
--- a/arch/arm/mach-spear13xx/spear13xx.c
+++ b/arch/arm/mach-spear13xx/spear13xx.c
@@ -79,6 +79,8 @@ struct dw_dma_platform_data dmac_plat_data = {
 	.chan_allocation_order = CHAN_ALLOCATION_DESCENDING,
 	.chan_priority = CHAN_PRIORITY_DESCENDING,
 	.block_size = 4095U,
+	.nr_masters = 2,
+	.data_width = { 3, 3, 0, 0 },
 };
 
 void __init spear13xx_l2x0_init(void)
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 2c4aefe..b323d8d 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -606,6 +606,8 @@ static void __init genclk_init_parent(struct clk *clk)
 static struct dw_dma_platform_data dw_dmac0_data = {
 	.nr_channels	= 3,
 	.block_size	= 4095U,
+	.nr_masters	= 2,
+	.data_width	= { 2, 2, 0, 0 },
 };
 
 static struct resource dw_dmac0_resource[] = {
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 4af9fad..33c46f0 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -38,12 +38,22 @@
  * which does not support descriptor writeback.
  */
 
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+	return slave ? slave->dst_master : 0;
+}
+
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+	return slave ? slave->src_master : 1;
+}
+
 #define DWC_DEFAULT_CTLLO(_chan) ({				\
 		struct dw_dma_slave *__slave = (_chan->private);	\
 		struct dw_dma_chan *_dwc = to_dw_dma_chan(_chan);	\
 		struct dma_slave_config	*_sconfig = &_dwc->dma_sconfig;	\
-		int _dms = __slave ? __slave->dst_master : 0;	\
-		int _sms = __slave ? __slave->src_master : 1;	\
+		int _dms = dwc_get_dms(__slave);		\
+		int _sms = dwc_get_sms(__slave);		\
 		u8 _smsize = __slave ? _sconfig->src_maxburst :	\
 			DW_DMA_MSIZE_16;			\
 		u8 _dmsize = __slave ? _sconfig->dst_maxburst :	\
@@ -633,6 +643,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		size_t len, unsigned long flags)
 {
 	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
+	struct dw_dma_slave	*dws = chan->private;
 	struct dw_desc		*desc;
 	struct dw_desc		*first;
 	struct dw_desc		*prev;
@@ -640,6 +651,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	size_t			offset;
 	unsigned int		src_width;
 	unsigned int		dst_width;
+	unsigned int		data_width;
 	u32			ctllo;
 
 	dev_vdbg(chan2dev(chan),
@@ -652,7 +664,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		return NULL;
 	}
 
-	src_width = dst_width = dwc_fast_fls(src | dest | len);
+	data_width = min_t(unsigned int, dwc->dw->data_width[dwc_get_sms(dws)],
+					 dwc->dw->data_width[dwc_get_dms(dws)]);
+
+	src_width = dst_width = min_t(unsigned int, data_width,
+				      dwc_fast_fls(src | dest | len));
 
 	ctllo = DWC_DEFAULT_CTLLO(chan)
 			| DWC_CTLL_DST_WIDTH(dst_width)
@@ -722,6 +738,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	dma_addr_t		reg;
 	unsigned int		reg_width;
 	unsigned int		mem_width;
+	unsigned int		data_width;
 	unsigned int		i;
 	struct scatterlist	*sg;
 	size_t			total_len = 0;
@@ -745,6 +762,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
 			DWC_CTLL_FC(DW_DMA_FC_D_M2P);
 
+		data_width = dwc->dw->data_width[dwc_get_sms(dws)];
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
@@ -752,7 +771,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = dwc_fast_fls(mem | len);
+			mem_width = min_t(unsigned int,
+					  data_width, dwc_fast_fls(mem | len));
 
 slave_sg_todev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -805,6 +825,8 @@ slave_sg_todev_fill_desc:
 		ctllo |= sconfig->device_fc ? DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
 			DWC_CTLL_FC(DW_DMA_FC_D_P2M);
 
+		data_width = dwc->dw->data_width[dwc_get_dms(dws)];
+
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct dw_desc	*desc;
 			u32		len, dlen, mem;
@@ -812,7 +834,8 @@ slave_sg_todev_fill_desc:
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
 
-			mem_width = dwc_fast_fls(mem | len);
+			mem_width = min_t(unsigned int,
+					  data_width, dwc_fast_fls(mem | len));
 
 slave_sg_fromdev_fill_desc:
 			desc = dwc_desc_get(dwc);
@@ -1417,9 +1440,19 @@ static int __devinit dw_probe(struct platform_device *pdev)
 	dw->regs = regs;
 
 	/* get hardware configuration parameters */
-	if (autocfg)
+	if (autocfg) {
 		max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
 
+		dw->nr_masters = (dw_params >> DW_PARAMS_NR_MASTER & 3) + 1;
+		for (i = 0; i < dw->nr_masters; i++) {
+			dw->data_width[i] =
+				(dw_params >> DW_PARAMS_DATA_WIDTH(i) & 3) + 2;
+		}
+	} else {
+		dw->nr_masters = pdata->nr_masters;
+		memcpy(dw->data_width, pdata->data_width, 4);
+	}
+
 	/* Calculate all channel mask before DMA setup */
 	dw->all_chan_mask = (1 << nr_channels) - 1;
 
@@ -1466,6 +1499,8 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
 		channel_clear_bit(dw, CH_EN, dwc->mask);
 
+		dwc->dw = dw;
+
 		/* hardware configuration */
 		if (autocfg)
 			/* Decode maximum block size for given channel. The
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index 2a1cc53..06f0391 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -198,6 +198,9 @@ struct dw_dma_chan {
 
 	/* configuration passed via DMA_SLAVE_CONFIG */
 	struct dma_slave_config dma_sconfig;
+
+	/* backlink to dw_dma */
+	struct dw_dma		*dw;
 };
 
 static inline struct dw_dma_chan_regs __iomem *
@@ -224,6 +227,10 @@ struct dw_dma {
 
 	u8			all_chan_mask;
 
+	/* hardware configuration */
+	unsigned char		nr_masters;
+	unsigned char		data_width[4];
+
 	struct dw_dma_chan	chan[0];
 };
 
diff --git a/include/linux/dw_dmac.h b/include/linux/dw_dmac.h
index 3315ef9..e1c8c9e 100644
--- a/include/linux/dw_dmac.h
+++ b/include/linux/dw_dmac.h
@@ -20,6 +20,9 @@
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
  * @block_size: Maximum block size supported by the controller
+ * @nr_masters: Number of AHB masters supported by the controller
+ * @data_width: Maximum data width supported by hardware per AHB master
+ *		(0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
  */
 struct dw_dma_platform_data {
 	unsigned int	nr_channels;
@@ -31,6 +34,8 @@ struct dw_dma_platform_data {
 #define CHAN_PRIORITY_DESCENDING	1	/* chan7 highest */
 	unsigned char	chan_priority;
 	unsigned short	block_size;
+	unsigned char	nr_masters;
+	unsigned char	data_width[4];
 };
 
 /* bursts size */
-- 
1.7.10.4


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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-25 11:39       ` [PATCHv3] " Andy Shevchenko
@ 2012-09-26  3:29         ` viresh kumar
  2012-09-27 10:06         ` Vinod Koul
  1 sibling, 0 replies; 58+ messages in thread
From: viresh kumar @ 2012-09-26  3:29 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Vinod Koul, spear-devel, linux-kernel, Hein Tibosch

On Tue, Sep 25, 2012 at 5:09 PM, Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
> Not all of the controllers support the 64 bit data width. Make it configurable
> via platform data. The driver will try to get a value from the component
> parameters, otherwise it will use the platform data.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> Since v2:
> - sometimes memory-to-memory test is failed, that's why we need to choose
>   minimum data portion between source and destination limits

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>

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

* Re: [PATCHv2 0/6] dw_dmac: introduce autoconfiguration
  2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
                     ` (5 preceding siblings ...)
  2012-09-21 12:05   ` [PATCHv2 6/6] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
@ 2012-09-27 10:05   ` Vinod Koul
  6 siblings, 0 replies; 58+ messages in thread
From: Vinod Koul @ 2012-09-27 10:05 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: Viresh Kumar, spear-devel, linux-kernel, Hein Tibosch

On Fri, 2012-09-21 at 15:05 +0300, Andy Shevchenko wrote:
> Here is a patchset that allows to adapt the driver to the hardware
> configuration during probe time. The hardware should have the specific optional
> parameters enabled. Otherwise the driver will consider values stored in the
> platform data.
> 
> Additionally it brings support of the software LLP transfers. It means that
> normal linked list transfer is substituted by set of single block transfers
> transparently to the user.
> 
> Since v1:
>  - addressed all Viresh's comments.
Applied all, Thanks

> 
> Andy Shevchenko (6):
>   dw_dmac: mark dwc_dump_chan_regs as inline
>   dw_dmac: fill optional encoded parameters in register structure
>   dw_dmac: get number of channels from hardware if possible
>   dw_dmac: autoconfigure block_size or use platform data
>   dw_dmac: autoconfigure data_width or get it via platform data
>   dw_dmac: introduce software emulation of LLP transfers
> 
>  arch/arm/mach-spear13xx/spear13xx.c |    3 +
>  arch/avr32/mach-at32ap/at32ap700x.c |    3 +
>  drivers/dma/dw_dmac.c               |  209 +++++++++++++++++++++++++++++------
>  drivers/dma/dw_dmac_regs.h          |   46 ++++++++
>  include/linux/dw_dmac.h             |    7 ++
>  5 files changed, 235 insertions(+), 33 deletions(-)
> 


-- 
~Vinod


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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-25 11:39       ` [PATCHv3] " Andy Shevchenko
  2012-09-26  3:29         ` viresh kumar
@ 2012-09-27 10:06         ` Vinod Koul
  2012-09-27 10:33           ` Vinod Koul
  2012-09-27 14:00           ` Andy Shevchenko
  1 sibling, 2 replies; 58+ messages in thread
From: Vinod Koul @ 2012-09-27 10:06 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> Not all of the controllers support the 64 bit data width. Make it configurable
> via platform data. The driver will try to get a value from the component
> parameters, otherwise it will use the platform data.
> 
What was this gen against, I can apply this.

-- 
~Vinod


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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-27 10:06         ` Vinod Koul
@ 2012-09-27 10:33           ` Vinod Koul
  2012-09-27 13:10             ` Andy Shevchenko
  2012-10-01  9:04             ` Andy Shevchenko
  2012-09-27 14:00           ` Andy Shevchenko
  1 sibling, 2 replies; 58+ messages in thread
From: Vinod Koul @ 2012-09-27 10:33 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Thu, 2012-09-27 at 15:36 +0530, Vinod Koul wrote:
> On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> > Not all of the controllers support the 64 bit data width. Make it configurable
> > via platform data. The driver will try to get a value from the component
> > parameters, otherwise it will use the platform data.
> > 
> What was this gen against, I can apply this.
> 

%s/can/can't
-- 
~Vinod


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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-27 10:33           ` Vinod Koul
@ 2012-09-27 13:10             ` Andy Shevchenko
  2012-10-01  9:04             ` Andy Shevchenko
  1 sibling, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-27 13:10 UTC (permalink / raw)
  To: Vinod Koul; +Cc: viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Thu, 2012-09-27 at 16:03 +0530, Vinod Koul wrote: 
> On Thu, 2012-09-27 at 15:36 +0530, Vinod Koul wrote:
> > On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> > > Not all of the controllers support the 64 bit data width. Make it configurable
> > > via platform data. The driver will try to get a value from the component
> > > parameters, otherwise it will use the platform data.
> > > 
> > What was this gen against, I can apply this.
> > 
> 
> %s/can/can't
Against linux-next, last used was yesterday's version of it.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-27 10:06         ` Vinod Koul
  2012-09-27 10:33           ` Vinod Koul
@ 2012-09-27 14:00           ` Andy Shevchenko
  2012-09-27 14:27             ` Vinod Koul
  1 sibling, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-09-27 14:00 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Andy Shevchenko, viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Thu, Sep 27, 2012 at 1:06 PM, Vinod Koul <vinod.koul@linux.intel.com> wrote:
> On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
>> Not all of the controllers support the 64 bit data width. Make it configurable
>> via platform data. The driver will try to get a value from the component
>> parameters, otherwise it will use the platform data.
>>
> What was this gen against, I can apply this.
Just rebased to recent linux-next, no conflicts.
...
Applying: dw_dmac: mark dwc_dump_chan_regs as inline
Applying: dw_dmac: fill optional encoded parameters in register structure
Applying: dw_dmac: get number of channels from hardware if possible
Applying: dw_dmac: autoconfigure block_size or use platform data
Applying: dw_dmac: autoconfigure data_width or get it via platform data
Applying: dw_dmac: introduce software emulation of LLP transfers
...

Have you kept the order of the patches?



-- 
With Best Regards,
Andy Shevchenko

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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-27 14:00           ` Andy Shevchenko
@ 2012-09-27 14:27             ` Vinod Koul
  0 siblings, 0 replies; 58+ messages in thread
From: Vinod Koul @ 2012-09-27 14:27 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Andy Shevchenko, viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Thu, 2012-09-27 at 17:00 +0300, Andy Shevchenko wrote:
> On Thu, Sep 27, 2012 at 1:06 PM, Vinod Koul <vinod.koul@linux.intel.com> wrote:
> > On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> >> Not all of the controllers support the 64 bit data width. Make it configurable
> >> via platform data. The driver will try to get a value from the component
> >> parameters, otherwise it will use the platform data.
> >>
> > What was this gen against, I can apply this.
> Just rebased to recent linux-next, no conflicts.
And I dont apply patches against linux-next!! I apply against
slave-dma-next.
> ...
> Applying: dw_dmac: mark dwc_dump_chan_regs as inline
> Applying: dw_dmac: fill optional encoded parameters in register structure
> Applying: dw_dmac: get number of channels from hardware if possible
> Applying: dw_dmac: autoconfigure block_size or use platform data
> Applying: dw_dmac: autoconfigure data_width or get it via platform data
> Applying: dw_dmac: introduce software emulation of LLP transfers
> ...
> 
> Have you kept the order of the patches?
Obviously see my next

The reason for conflict is nature of this patch. It should be split up. 
arch/arm/mach-spear13xx/spear13xx.c |    2 ++
arch/avr32/mach-at32ap/at32ap700x.c |    2 ++

It fails here, send these separately to Arnd.


-- 
~Vinod


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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-09-27 10:33           ` Vinod Koul
  2012-09-27 13:10             ` Andy Shevchenko
@ 2012-10-01  9:04             ` Andy Shevchenko
  2012-10-01  9:45               ` Vinod Koul
  1 sibling, 1 reply; 58+ messages in thread
From: Andy Shevchenko @ 2012-10-01  9:04 UTC (permalink / raw)
  To: Vinod Koul; +Cc: viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Thu, 2012-09-27 at 16:03 +0530, Vinod Koul wrote: 
> On Thu, 2012-09-27 at 15:36 +0530, Vinod Koul wrote:
> > On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> > > Not all of the controllers support the 64 bit data width. Make it configurable
> > > via platform data. The driver will try to get a value from the component
> > > parameters, otherwise it will use the platform data.
> > > 
> > What was this gen against, I can apply this.
> %s/can/can't
Today I got what was happened. I sent an update to one patch of the
series, but you tried to apply it on top of previous version. It seems I
was not clear. So, now we have a regression, and I will send a fix soon
today.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-10-01  9:04             ` Andy Shevchenko
@ 2012-10-01  9:45               ` Vinod Koul
  2012-10-01 10:07                 ` Andy Shevchenko
  0 siblings, 1 reply; 58+ messages in thread
From: Vinod Koul @ 2012-10-01  9:45 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Mon, 2012-10-01 at 12:04 +0300, Andy Shevchenko wrote:
> On Thu, 2012-09-27 at 16:03 +0530, Vinod Koul wrote: 
> > On Thu, 2012-09-27 at 15:36 +0530, Vinod Koul wrote:
> > > On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> > > > Not all of the controllers support the 64 bit data width. Make it configurable
> > > > via platform data. The driver will try to get a value from the component
> > > > parameters, otherwise it will use the platform data.
> > > > 
> > > What was this gen against, I can apply this.
> > %s/can/can't
> Today I got what was happened. I sent an update to one patch of the
> series, but you tried to apply it on top of previous version. It seems I
> was not clear. So, now we have a regression, and I will send a fix soon
> today.
I received a series, and a patch on top and that what I tried to
apply :(
I am okay to revert the whole series now.

Please send me fix by today, merge window has started, I hate to change
stuff now.



-- 
~Vinod


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

* Re: [PATCHv3] dw_dmac: autoconfigure data_width or get it via platform data
  2012-10-01  9:45               ` Vinod Koul
@ 2012-10-01 10:07                 ` Andy Shevchenko
  0 siblings, 0 replies; 58+ messages in thread
From: Andy Shevchenko @ 2012-10-01 10:07 UTC (permalink / raw)
  To: Vinod Koul; +Cc: viresh.kumar, spear-devel, linux-kernel, Hein Tibosch

On Mon, 2012-10-01 at 15:15 +0530, Vinod Koul wrote: 
> On Mon, 2012-10-01 at 12:04 +0300, Andy Shevchenko wrote:
> > On Thu, 2012-09-27 at 16:03 +0530, Vinod Koul wrote: 
> > > On Thu, 2012-09-27 at 15:36 +0530, Vinod Koul wrote:
> > > > On Tue, 2012-09-25 at 14:39 +0300, Andy Shevchenko wrote:
> > > > > Not all of the controllers support the 64 bit data width. Make it configurable
> > > > > via platform data. The driver will try to get a value from the component
> > > > > parameters, otherwise it will use the platform data.
> > > > > 
> > > > What was this gen against, I can apply this.
> > > %s/can/can't
> > Today I got what was happened. I sent an update to one patch of the
> > series, but you tried to apply it on top of previous version. It seems I
> > was not clear. So, now we have a regression, and I will send a fix soon
> > today.
> I received a series, and a patch on top and that what I tried to
> apply :(
> I am okay to revert the whole series now.
> 
> Please send me fix by today, merge window has started, I hate to change
> stuff now.
I've sent a patch. You could apply on top of the series, or squash it
with the one called "dw_dmac: autoconfigure data_width or get it via
platform data"

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

end of thread, other threads:[~2012-10-01 10:07 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-17  7:39 [PATCH 0/7] dw_dmac: introduce autoconfiguration Andy Shevchenko
2012-09-17  7:39 ` [PATCH 1/7] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
2012-09-18  6:35   ` viresh kumar
2012-09-17  7:39 ` [PATCH 2/7] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
2012-09-18  6:39   ` viresh kumar
2012-09-18  6:55     ` Andy Shevchenko
2012-09-18  7:59       ` viresh kumar
2012-09-20  9:30         ` Andy Shevchenko
2012-09-20  9:32           ` viresh kumar
2012-09-20  9:51             ` Andy Shevchenko
2012-09-17  7:39 ` [PATCH 3/7] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
2012-09-18  6:50   ` viresh kumar
2012-09-20  9:35     ` Andy Shevchenko
2012-09-20  9:40       ` viresh kumar
2012-09-21  6:04         ` viresh kumar
2012-09-17  7:39 ` [PATCH 4/7] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
2012-09-18  6:57   ` viresh kumar
2012-09-20  9:38     ` Andy Shevchenko
2012-09-17  7:39 ` [PATCH 5/7] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
2012-09-18  7:11   ` viresh kumar
2012-09-20  9:42     ` Andy Shevchenko
2012-09-20  9:46       ` viresh kumar
2012-09-20  9:53         ` Andy Shevchenko
2012-09-17  7:39 ` [PATCH 6/7] dw_dmac: check if controller supports LLP Andy Shevchenko
2012-09-18  7:13   ` viresh kumar
2012-09-20  9:43     ` Andy Shevchenko
2012-09-17  7:39 ` [PATCH 7/7] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
2012-09-18  7:17   ` viresh kumar
2012-09-20  9:46     ` Andy Shevchenko
2012-09-17 16:50 ` [PATCH 0/7] dw_dmac: introduce autoconfiguration Hein Tibosch
2012-09-18  6:11 ` Hein Tibosch
2012-09-18  7:18   ` viresh kumar
2012-09-20  9:48   ` Andy Shevchenko
2012-09-21 12:05 ` [PATCHv2 0/6] " Andy Shevchenko
2012-09-21 12:05   ` [PATCHv2 1/6] dw_dmac: mark dwc_dump_chan_regs as inline Andy Shevchenko
2012-09-21 12:05   ` [PATCHv2 2/6] dw_dmac: fill optional encoded parameters in register structure Andy Shevchenko
2012-09-21 13:55     ` viresh kumar
2012-09-21 12:05   ` [PATCHv2 3/6] dw_dmac: get number of channels from hardware if possible Andy Shevchenko
2012-09-21 13:56     ` viresh kumar
2012-09-21 12:05   ` [PATCHv2 4/6] dw_dmac: autoconfigure block_size or use platform data Andy Shevchenko
2012-09-21 14:00     ` viresh kumar
2012-09-21 15:09       ` Andy Shevchenko
2012-09-21 15:30         ` Viresh Kumar
2012-09-21 12:05   ` [PATCHv2 5/6] dw_dmac: autoconfigure data_width or get it via " Andy Shevchenko
2012-09-21 14:02     ` viresh kumar
2012-09-25 11:39       ` [PATCHv3] " Andy Shevchenko
2012-09-26  3:29         ` viresh kumar
2012-09-27 10:06         ` Vinod Koul
2012-09-27 10:33           ` Vinod Koul
2012-09-27 13:10             ` Andy Shevchenko
2012-10-01  9:04             ` Andy Shevchenko
2012-10-01  9:45               ` Vinod Koul
2012-10-01 10:07                 ` Andy Shevchenko
2012-09-27 14:00           ` Andy Shevchenko
2012-09-27 14:27             ` Vinod Koul
2012-09-21 12:05   ` [PATCHv2 6/6] dw_dmac: introduce software emulation of LLP transfers Andy Shevchenko
2012-09-21 14:03     ` viresh kumar
2012-09-27 10:05   ` [PATCHv2 0/6] dw_dmac: introduce autoconfiguration 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).