DMA Engine development
 help / color / mirror / Atom feed
* [v4,15/18] dmaengine: dma-jz4780: Use dma_set_residue()
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips,
	Daniel Silsby

From: Daniel Silsby <dansilsby@gmail.com>

This is the standard method provided by dmaengine header.

Signed-off-by: Daniel Silsby <dansilsby@gmail.com>
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

 v2: No change

 v3: No change

 v4: Add my Signed-off-by

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 351dc8268515..32e10edc55e0 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -639,6 +639,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
 	struct virt_dma_desc *vdesc;
 	enum dma_status status;
 	unsigned long flags;
+	unsigned long residue = 0;
 
 	status = dma_cookie_status(chan, cookie, txstate);
 	if ((status == DMA_COMPLETE) || (txstate == NULL))
@@ -649,13 +650,13 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
 	vdesc = vchan_find_desc(&jzchan->vchan, cookie);
 	if (vdesc) {
 		/* On the issued list, so hasn't been processed yet */
-		txstate->residue = jz4780_dma_desc_residue(jzchan,
+		residue = jz4780_dma_desc_residue(jzchan,
 					to_jz4780_dma_desc(vdesc), 0);
 	} else if (cookie == jzchan->desc->vdesc.tx.cookie) {
-		txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
+		residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
 					jzchan->curr_hwdesc + 1);
-	} else
-		txstate->residue = 0;
+	}
+	dma_set_residue(txstate, residue);
 
 	if (vdesc && jzchan->desc && vdesc == &jzchan->desc->vdesc
 	    && jzchan->desc->status & (JZ_DMA_DCS_AR | JZ_DMA_DCS_HLT))

^ permalink raw reply related

* [v4,14/18] dmaengine: dma-jz4780: Further residue status fix
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips,
	Daniel Silsby

From: Daniel Silsby <dansilsby@gmail.com>

Func jz4780_dma_desc_residue() expects the index to the next hw
descriptor as its last parameter. Caller func jz4780_dma_tx_status(),
however, applied modulus before passing it. When the current hw
descriptor was last in the list, the index passed became zero.

The resulting excess of reported residue especially caused problems
with cyclic DMA transfer clients, i.e. ALSA AIC audio output, which
rely on this for determining current DMA location within buffer.

Combined with the recent and related residue-reporting fixes, spurious
ALSA audio underruns on jz4770 hardware are now fixed.

Signed-off-by: Daniel Silsby <dansilsby@gmail.com>
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

 v2: No change

 v3: No change

 v4: Add my Signed-off-by

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index d03711834a44..351dc8268515 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -653,7 +653,7 @@ static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,
 					to_jz4780_dma_desc(vdesc), 0);
 	} else if (cookie == jzchan->desc->vdesc.tx.cookie) {
 		txstate->residue = jz4780_dma_desc_residue(jzchan, jzchan->desc,
-			  (jzchan->curr_hwdesc + 1) % jzchan->desc->count);
+					jzchan->curr_hwdesc + 1);
 	} else
 		txstate->residue = 0;
 

^ permalink raw reply related

* [v4,13/18] dmaengine: dma-jz4780: Set DTCn register explicitly
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips,
	Daniel Silsby

From: Daniel Silsby <dansilsby@gmail.com>

Normally, we wouldn't set the channel transfer count register directly
when using descriptor-driven transfers. However, there is no harm in
doing so, and it allows jz4780_dma_desc_residue() to report the correct
residue of an ongoing transfer, no matter when it is called.

Signed-off-by: Daniel Silsby <dansilsby@gmail.com>
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 9 +++++++++
 1 file changed, 9 insertions(+)

 v2: No change

 v3: No change

 v4: Add my Signed-off-by

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 019cebc2e5e5..d03711834a44 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -532,6 +532,15 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT,
 			      jzchan->transfer_type);
 
+	/*
+	 * Set the transfer count. This is redundant for a descriptor-driven
+	 * transfer. However, there can be a delay between the transfer start
+	 * time and when DTCn reg contains the new transfer count. Setting
+	 * it explicitly ensures residue is computed correctly at all times.
+	 */
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC,
+				jzchan->desc->desc[jzchan->curr_hwdesc].dtc);
+
 	/* Write descriptor address and initiate descriptor fetch. */
 	desc_phys = jzchan->desc->desc_phys +
 		    (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc));

^ permalink raw reply related

* [v4,12/18] dmaengine: dma-jz4780: Simplify jz4780_dma_desc_residue()
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips,
	Daniel Silsby

From: Daniel Silsby <dansilsby@gmail.com>

Simple cleanup, no changes to actual logic here.

Signed-off-by: Daniel Silsby <dansilsby@gmail.com>
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

 v2: No change

 v3: No change

 v4: Add my Signed-off-by

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index a4292ac4c686..019cebc2e5e5 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -610,22 +610,17 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan,
 	struct jz4780_dma_desc *desc, unsigned int next_sg)
 {
 	struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
-	unsigned int residue, count;
+	unsigned int count = 0;
 	unsigned int i;
 
-	residue = 0;
-
 	for (i = next_sg; i < desc->count; i++)
-		residue += (desc->desc[i].dtc & 0xffffff) <<
-			jzchan->transfer_shift;
+		count += desc->desc[i].dtc & 0xffffff;
 
-	if (next_sg != 0) {
-		count = jz4780_dma_chn_readl(jzdma, jzchan->id,
+	if (next_sg != 0)
+		count += jz4780_dma_chn_readl(jzdma, jzchan->id,
 					 JZ_DMA_REG_DTC);
-		residue += count << jzchan->transfer_shift;
-	}
 
-	return residue;
+	return count << jzchan->transfer_shift;
 }
 
 static enum dma_status jz4780_dma_tx_status(struct dma_chan *chan,

^ permalink raw reply related

* [v4,11/18] dmaengine: dma-jz4780: Add missing residue DTC mask
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips,
	Daniel Silsby

From: Daniel Silsby <dansilsby@gmail.com>

The 'dtc' word in jz DMA descriptors contains two fields: The
lowest 24 bits are the transfer count, and upper 8 bits are the DOA
offset to next descriptor. The upper 8 bits are now correctly masked
off when computing residue in jz4780_dma_desc_residue(). Note that
reads of the DTCn hardware reg are automatically masked this way.

Signed-off-by: Daniel Silsby <dansilsby@gmail.com>
Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

 v2: No change

 v3: No change

 v4: Add my Signed-off-by

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 3a4d0a4b550d..a4292ac4c686 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -616,7 +616,8 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan,
 	residue = 0;
 
 	for (i = next_sg; i < desc->count; i++)
-		residue += desc->desc[i].dtc << jzchan->transfer_shift;
+		residue += (desc->desc[i].dtc & 0xffffff) <<
+			jzchan->transfer_shift;
 
 	if (next_sg != 0) {
 		count = jz4780_dma_chn_readl(jzdma, jzchan->id,

^ permalink raw reply related

* [v4,10/18] dmaengine: dma-jz4780: Enable Fast DMA to the AIC
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

With the fast DMA bit set, the DMA will transfer twice as much data
per clock period to the AIC, so there is little point not to set it.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
---
 drivers/dma/dma-jz4780.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

 v2: No change

 v3: No change

 v4: No change

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 565971c2a33c..3a4d0a4b550d 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -52,6 +52,7 @@
 #define JZ_DMA_DMAC_DMAE	BIT(0)
 #define JZ_DMA_DMAC_AR		BIT(2)
 #define JZ_DMA_DMAC_HLT		BIT(3)
+#define JZ_DMA_DMAC_FAIC	BIT(27)
 #define JZ_DMA_DMAC_FMSC	BIT(31)
 
 #define JZ_DMA_DRT_AUTO		0x8
@@ -923,8 +924,8 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 	 * Also set the FMSC bit - it increases MSC performance, so it makes
 	 * little sense not to enable it.
 	 */
-	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC,
-			  JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC);
+	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE |
+			       JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC);
 
 	if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA)
 		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);

^ permalink raw reply related

* [v4,09/18] dmaengine: dma-jz4780: Add support for the JZ4725B SoC
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The JZ4725B has one DMA core starring six DMA channels.
As for the JZ4770, each DMA channel's clock can be enabled with
a register write, the difference here being that once started, it
is not possible to turn it off.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
---
 drivers/dma/dma-jz4780.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

 v2: - Add comments about channel enabling/disabling
     - The documentation update is now in patch 01/17

 v3: No change

 v4: Drop the SoC version ID and use the 'flags' field of the
     jz4780_dma_soc_data structure

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 2d194dfa697e..565971c2a33c 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -94,6 +94,7 @@
 #define JZ_SOC_DATA_ALLOW_LEGACY_DT	BIT(0)
 #define JZ_SOC_DATA_PROGRAMMABLE_DMA	BIT(1)
 #define JZ_SOC_DATA_PER_CHAN_PM		BIT(2)
+#define JZ_SOC_DATA_NO_DCKES_DCKEC	BIT(3)
 
 /**
  * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
@@ -208,14 +209,23 @@ static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma,
 static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma,
 	unsigned int chn)
 {
-	if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM)
-		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKES, BIT(chn));
+	if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) {
+		unsigned int reg;
+
+		if (jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC)
+			reg = JZ_DMA_REG_DCKE;
+		else
+			reg = JZ_DMA_REG_DCKES;
+
+		jz4780_dma_ctrl_writel(jzdma, reg, BIT(chn));
+	}
 }
 
 static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma,
 	unsigned int chn)
 {
-	if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM)
+	if ((jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM) &&
+			!(jzdma->soc_data->flags & JZ_SOC_DATA_NO_DCKES_DCKEC))
 		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn));
 }
 
@@ -978,6 +988,12 @@ static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
 	.transfer_ord_max = 5,
 };
 
+static const struct jz4780_dma_soc_data jz4725b_dma_soc_data = {
+	.nb_channels = 6,
+	.transfer_ord_max = 5,
+	.flags = JZ_SOC_DATA_PER_CHAN_PM | JZ_SOC_DATA_NO_DCKES_DCKEC,
+};
+
 static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
 	.nb_channels = 6,
 	.transfer_ord_max = 6,
@@ -992,6 +1008,7 @@ static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
 
 static const struct of_device_id jz4780_dma_dt_match[] = {
 	{ .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data },
+	{ .compatible = "ingenic,jz4725b-dma", .data = &jz4725b_dma_soc_data },
 	{ .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
 	{ .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
 	{},

^ permalink raw reply related

* [v4,08/18] dmaengine: dma-jz4780: Add support for the JZ4740 SoC
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The JZ4740 SoC has a single DMA core starring six DMA channels.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
---
 drivers/dma/dma-jz4780.c | 6 ++++++
 1 file changed, 6 insertions(+)

 v2: The documentation update is now in patch 01/17

 v3: The Kconfig update was dropped thanks to patch 06/18

 v4: No change

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 184d1a2bf9ba..2d194dfa697e 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -973,6 +973,11 @@ static int jz4780_dma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
+	.nb_channels = 6,
+	.transfer_ord_max = 5,
+};
+
 static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
 	.nb_channels = 6,
 	.transfer_ord_max = 6,
@@ -986,6 +991,7 @@ static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
 };
 
 static const struct of_device_id jz4780_dma_dt_match[] = {
+	{ .compatible = "ingenic,jz4740-dma", .data = &jz4740_dma_soc_data },
 	{ .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
 	{ .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
 	{},

^ permalink raw reply related

* [v4,07/18] dmaengine: dma-jz4780: Add support for the JZ4770 SoC
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The JZ4770 SoC has two DMA cores, each one featuring six DMA channels.
The major change is that each channel's clock can be enabled or disabled
through register writes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 61 ++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 54 insertions(+), 7 deletions(-)

 v2: - Move transfer_ord_max variable to the new jz4780_dma_soc_data
       structure
     - The documentation update is now in patch 01/17

 v3: The Kconfig update was dropped thanks to patch 06/18

 v4: Pass jz4780_dma_soc_data structure pointer directly as devicetree
     match data; Add a 'flags' field in that structure and macros for
     it, to replace checking vs. the SoC version.

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 7683de9fb9ee..184d1a2bf9ba 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -29,6 +29,9 @@
 #define JZ_DMA_REG_DIRQP	0x04
 #define JZ_DMA_REG_DDR		0x08
 #define JZ_DMA_REG_DDRS		0x0c
+#define JZ_DMA_REG_DCKE		0x10
+#define JZ_DMA_REG_DCKES	0x14
+#define JZ_DMA_REG_DCKEC	0x18
 #define JZ_DMA_REG_DMACP	0x1c
 #define JZ_DMA_REG_DSIRQP	0x20
 #define JZ_DMA_REG_DSIRQM	0x24
@@ -87,6 +90,11 @@
 
 #define JZ4780_DMA_CTRL_OFFSET	0x1000
 
+/* macros for use with jz4780_dma_soc_data.flags */
+#define JZ_SOC_DATA_ALLOW_LEGACY_DT	BIT(0)
+#define JZ_SOC_DATA_PROGRAMMABLE_DMA	BIT(1)
+#define JZ_SOC_DATA_PER_CHAN_PM		BIT(2)
+
 /**
  * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
  * @dcm: value for the DCM (channel command) register
@@ -133,6 +141,8 @@ struct jz4780_dma_chan {
 
 struct jz4780_dma_soc_data {
 	unsigned int nb_channels;
+	unsigned int transfer_ord_max;
+	unsigned long flags;
 };
 
 struct jz4780_dma_dev {
@@ -195,6 +205,20 @@ static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma,
 	writel(val, jzdma->ctrl_base + reg);
 }
 
+static inline void jz4780_dma_chan_enable(struct jz4780_dma_dev *jzdma,
+	unsigned int chn)
+{
+	if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM)
+		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKES, BIT(chn));
+}
+
+static inline void jz4780_dma_chan_disable(struct jz4780_dma_dev *jzdma,
+	unsigned int chn)
+{
+	if (jzdma->soc_data->flags & JZ_SOC_DATA_PER_CHAN_PM)
+		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DCKEC, BIT(chn));
+}
+
 static struct jz4780_dma_desc *jz4780_dma_desc_alloc(
 	struct jz4780_dma_chan *jzchan, unsigned int count,
 	enum dma_transaction_type type)
@@ -229,8 +253,10 @@ static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc)
 	kfree(desc);
 }
 
-static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
+static uint32_t jz4780_dma_transfer_size(struct jz4780_dma_chan *jzchan,
+	unsigned long val, uint32_t *shift)
 {
+	struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
 	int ord = ffs(val) - 1;
 
 	/*
@@ -242,8 +268,8 @@ static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
 	 */
 	if (ord == 3)
 		ord = 2;
-	else if (ord > 7)
-		ord = 7;
+	else if (ord > jzdma->soc_data->transfer_ord_max)
+		ord = jzdma->soc_data->transfer_ord_max;
 
 	*shift = ord;
 
@@ -295,7 +321,7 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
 	 * divisible by the transfer size, and we must not use more than the
 	 * maximum burst specified by the user.
 	 */
-	tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst),
+	tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst),
 				       &jzchan->transfer_shift);
 
 	switch (width) {
@@ -424,7 +450,7 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
 	if (!desc)
 		return NULL;
 
-	tsz = jz4780_dma_transfer_size(dest | src | len,
+	tsz = jz4780_dma_transfer_size(jzchan, dest | src | len,
 				       &jzchan->transfer_shift);
 
 	jzchan->transfer_type = JZ_DMA_DRT_AUTO;
@@ -485,6 +511,9 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 			(jzchan->curr_hwdesc + 1) % jzchan->desc->count;
 	}
 
+	/* Enable the channel's clock. */
+	jz4780_dma_chan_enable(jzdma, jzchan->id);
+
 	/* Use 4-word descriptors. */
 	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
 
@@ -532,6 +561,8 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
 		jzchan->desc = NULL;
 	}
 
+	jz4780_dma_chan_disable(jzdma, jzchan->id);
+
 	vchan_get_all_descriptors(&jzchan->vchan, &head);
 
 	spin_unlock_irqrestore(&jzchan->vchan.lock, flags);
@@ -543,8 +574,10 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
 static void jz4780_dma_synchronize(struct dma_chan *chan)
 {
 	struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan);
+	struct jz4780_dma_dev *jzdma = jz4780_dma_chan_parent(jzchan);
 
 	vchan_synchronize(&jzchan->vchan);
+	jz4780_dma_chan_disable(jzdma, jzchan->id);
 }
 
 static int jz4780_dma_config(struct dma_chan *chan,
@@ -812,13 +845,16 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 		jzdma->ctrl_base = devm_ioremap_resource(dev, res);
 		if (IS_ERR(jzdma->ctrl_base))
 			return PTR_ERR(jzdma->ctrl_base);
-	} else {
+	} else if (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) {
 		/*
 		 * On JZ4780, if the second memory resource was not supplied,
 		 * assume we're using an old devicetree, and calculate the
 		 * offset to the control registers.
 		 */
 		jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET;
+	} else {
+		dev_err(dev, "failed to get I/O memory\n");
+		return -EINVAL;
 	}
 
 	ret = platform_get_irq(pdev, 0);
@@ -879,7 +915,9 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 	 */
 	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC,
 			  JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC);
-	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);
+
+	if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA)
+		jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);
 
 	INIT_LIST_HEAD(&dd->channels);
 
@@ -935,11 +973,20 @@ static int jz4780_dma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct jz4780_dma_soc_data jz4770_dma_soc_data = {
+	.nb_channels = 6,
+	.transfer_ord_max = 6,
+	.flags = JZ_SOC_DATA_PER_CHAN_PM,
+};
+
 static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
 	.nb_channels = 32,
+	.transfer_ord_max = 7,
+	.flags = JZ_SOC_DATA_ALLOW_LEGACY_DT | JZ_SOC_DATA_PROGRAMMABLE_DMA,
 };
 
 static const struct of_device_id jz4780_dma_dt_match[] = {
+	{ .compatible = "ingenic,jz4770-dma", .data = &jz4770_dma_soc_data },
 	{ .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
 	{},
 };

^ permalink raw reply related

* [v4,06/18] dmaengine: dma-jz4780: Don't depend on MACH_JZ4780
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

If we make this driver depend on MACH_JZ4780, that means it can be
enabled only if we're building a kernel specially crafted for a
JZ4780-based board, while most GNU/Linux distributions will want one
generic MIPS kernel that works on multiple boards.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/dma/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

v3: New patch

v4: No change

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ca1680afa20a..0680e1eb0d73 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -143,7 +143,7 @@ config DMA_JZ4740
 
 config DMA_JZ4780
 	tristate "JZ4780 DMA support"
-	depends on MACH_JZ4780 || COMPILE_TEST
+	depends on MIPS || COMPILE_TEST
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 	help

^ permalink raw reply related

* [v4,05/18] dmaengine: dma-jz4780: Use 4-word descriptors
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The only information we use in the 8-word version of the hardware DMA
descriptor that is not present in the 4-word version is the transfer
type, aka. the ID of the source or recipient device.

Since the transfer type will never change for a DMA channel in use,
we can just set it once for all in the corresponding DMA register
before starting any transfer.

This has several benefits:

* the driver will handle twice as many hardware DMA descriptors;

* the driver is closer to support the JZ4740, which only supports 4-word
  hardware DMA descriptors;

* the JZ4770 SoC needs the transfer type to be set in the corresponding
  DMA register anyway, even if 8-word descriptors are in use.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
Reviewed-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
---
 drivers/dma/dma-jz4780.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

 v2: No change

 v3: No change

 v4: No change

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index adf4d5efced6..7683de9fb9ee 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -95,17 +95,12 @@
  * @dtc: transfer count (number of blocks of the transfer size specified in DCM
  * to transfer) in the low 24 bits, offset of the next descriptor from the
  * descriptor base address in the upper 8 bits.
- * @sd: target/source stride difference (in stride transfer mode).
- * @drt: request type
  */
 struct jz4780_dma_hwdesc {
 	uint32_t dcm;
 	uint32_t dsa;
 	uint32_t dta;
 	uint32_t dtc;
-	uint32_t sd;
-	uint32_t drt;
-	uint32_t reserved[2];
 };
 
 /* Size of allocations for hardware descriptor blocks. */
@@ -281,7 +276,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
 		desc->dcm = JZ_DMA_DCM_SAI;
 		desc->dsa = addr;
 		desc->dta = config->dst_addr;
-		desc->drt = jzchan->transfer_type;
 
 		width = config->dst_addr_width;
 		maxburst = config->dst_maxburst;
@@ -289,7 +283,6 @@ static int jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
 		desc->dcm = JZ_DMA_DCM_DAI;
 		desc->dsa = config->src_addr;
 		desc->dta = addr;
-		desc->drt = jzchan->transfer_type;
 
 		width = config->src_addr_width;
 		maxburst = config->src_maxburst;
@@ -434,9 +427,10 @@ static struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
 	tsz = jz4780_dma_transfer_size(dest | src | len,
 				       &jzchan->transfer_shift);
 
+	jzchan->transfer_type = JZ_DMA_DRT_AUTO;
+
 	desc->desc[0].dsa = src;
 	desc->desc[0].dta = dest;
-	desc->desc[0].drt = JZ_DMA_DRT_AUTO;
 	desc->desc[0].dcm = JZ_DMA_DCM_TIE | JZ_DMA_DCM_SAI | JZ_DMA_DCM_DAI |
 			    tsz << JZ_DMA_DCM_TSZ_SHIFT |
 			    JZ_DMA_WIDTH_32_BIT << JZ_DMA_DCM_SP_SHIFT |
@@ -491,9 +485,12 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 			(jzchan->curr_hwdesc + 1) % jzchan->desc->count;
 	}
 
-	/* Use 8-word descriptors. */
-	jz4780_dma_chn_writel(jzdma, jzchan->id,
-			      JZ_DMA_REG_DCS, JZ_DMA_DCS_DES8);
+	/* Use 4-word descriptors. */
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
+
+	/* Set transfer type. */
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT,
+			      jzchan->transfer_type);
 
 	/* Write descriptor address and initiate descriptor fetch. */
 	desc_phys = jzchan->desc->desc_phys +
@@ -503,7 +500,7 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 
 	/* Enable the channel. */
 	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS,
-			      JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE);
+			      JZ_DMA_DCS_CTE);
 }
 
 static void jz4780_dma_issue_pending(struct dma_chan *chan)

^ permalink raw reply related

* [v4,04/18] dmaengine: dma-jz4780: Separate chan/ctrl registers
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The register area of the JZ4780 DMA core can be split into different
sections for different purposes:

* one set of registers is used to perform actions at the DMA core level,
that will generally affect all channels;

* one set of registers per DMA channel, to perform actions at the DMA
channel level, that will only affect the channel in question.

The problem rises when trying to support new versions of the JZ47xx
Ingenic SoC. For instance, the JZ4770 has two DMA cores, each one
with six DMA channels, and the register sets are interleaved:
<DMA0 chan regs> <DMA1 chan regs> <DMA0 ctrl regs> <DMA1 ctrl regs>

By using one memory resource for the channel-specific registers and
one memory resource for the core-specific registers, we can support
the JZ4770, by initializing the driver once per DMA core with different
addresses.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 112 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 71 insertions(+), 41 deletions(-)

 v2: - Add a fallback mechanism for JZ4780 if the second memory resource
       was not supplied in the devicetree.
     - The documentation update was moved to patch 01/17

 v3: No change

 v4: No change

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 9ec22cf15a33..adf4d5efced6 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -25,26 +25,26 @@
 #include "virt-dma.h"
 
 /* Global registers. */
-#define JZ_DMA_REG_DMAC		0x1000
-#define JZ_DMA_REG_DIRQP	0x1004
-#define JZ_DMA_REG_DDR		0x1008
-#define JZ_DMA_REG_DDRS		0x100c
-#define JZ_DMA_REG_DMACP	0x101c
-#define JZ_DMA_REG_DSIRQP	0x1020
-#define JZ_DMA_REG_DSIRQM	0x1024
-#define JZ_DMA_REG_DCIRQP	0x1028
-#define JZ_DMA_REG_DCIRQM	0x102c
+#define JZ_DMA_REG_DMAC		0x00
+#define JZ_DMA_REG_DIRQP	0x04
+#define JZ_DMA_REG_DDR		0x08
+#define JZ_DMA_REG_DDRS		0x0c
+#define JZ_DMA_REG_DMACP	0x1c
+#define JZ_DMA_REG_DSIRQP	0x20
+#define JZ_DMA_REG_DSIRQM	0x24
+#define JZ_DMA_REG_DCIRQP	0x28
+#define JZ_DMA_REG_DCIRQM	0x2c
 
 /* Per-channel registers. */
 #define JZ_DMA_REG_CHAN(n)	(n * 0x20)
-#define JZ_DMA_REG_DSA(n)	(0x00 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DTA(n)	(0x04 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DTC(n)	(0x08 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DRT(n)	(0x0c + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DCS(n)	(0x10 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DCM(n)	(0x14 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DDA(n)	(0x18 + JZ_DMA_REG_CHAN(n))
-#define JZ_DMA_REG_DSD(n)	(0x1c + JZ_DMA_REG_CHAN(n))
+#define JZ_DMA_REG_DSA		0x00
+#define JZ_DMA_REG_DTA		0x04
+#define JZ_DMA_REG_DTC		0x08
+#define JZ_DMA_REG_DRT		0x0c
+#define JZ_DMA_REG_DCS		0x10
+#define JZ_DMA_REG_DCM		0x14
+#define JZ_DMA_REG_DDA		0x18
+#define JZ_DMA_REG_DSD		0x1c
 
 #define JZ_DMA_DMAC_DMAE	BIT(0)
 #define JZ_DMA_DMAC_AR		BIT(2)
@@ -85,6 +85,8 @@
 				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
 				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
 
+#define JZ4780_DMA_CTRL_OFFSET	0x1000
+
 /**
  * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
  * @dcm: value for the DCM (channel command) register
@@ -140,7 +142,8 @@ struct jz4780_dma_soc_data {
 
 struct jz4780_dma_dev {
 	struct dma_device dma_device;
-	void __iomem *base;
+	void __iomem *chn_base;
+	void __iomem *ctrl_base;
 	struct clk *clk;
 	unsigned int irq;
 	const struct jz4780_dma_soc_data *soc_data;
@@ -173,16 +176,28 @@ static inline struct jz4780_dma_dev *jz4780_dma_chan_parent(
 			    dma_device);
 }
 
-static inline uint32_t jz4780_dma_readl(struct jz4780_dma_dev *jzdma,
+static inline uint32_t jz4780_dma_chn_readl(struct jz4780_dma_dev *jzdma,
+	unsigned int chn, unsigned int reg)
+{
+	return readl(jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
+}
+
+static inline void jz4780_dma_chn_writel(struct jz4780_dma_dev *jzdma,
+	unsigned int chn, unsigned int reg, uint32_t val)
+{
+	writel(val, jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
+}
+
+static inline uint32_t jz4780_dma_ctrl_readl(struct jz4780_dma_dev *jzdma,
 	unsigned int reg)
 {
-	return readl(jzdma->base + reg);
+	return readl(jzdma->ctrl_base + reg);
 }
 
-static inline void jz4780_dma_writel(struct jz4780_dma_dev *jzdma,
+static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma,
 	unsigned int reg, uint32_t val)
 {
-	writel(val, jzdma->base + reg);
+	writel(val, jzdma->ctrl_base + reg);
 }
 
 static struct jz4780_dma_desc *jz4780_dma_desc_alloc(
@@ -477,17 +492,18 @@ static void jz4780_dma_begin(struct jz4780_dma_chan *jzchan)
 	}
 
 	/* Use 8-word descriptors. */
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), JZ_DMA_DCS_DES8);
+	jz4780_dma_chn_writel(jzdma, jzchan->id,
+			      JZ_DMA_REG_DCS, JZ_DMA_DCS_DES8);
 
 	/* Write descriptor address and initiate descriptor fetch. */
 	desc_phys = jzchan->desc->desc_phys +
 		    (jzchan->curr_hwdesc * sizeof(*jzchan->desc->desc));
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DDA(jzchan->id), desc_phys);
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DDA, desc_phys);
+	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DDRS, BIT(jzchan->id));
 
 	/* Enable the channel. */
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id),
-			  JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE);
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS,
+			      JZ_DMA_DCS_DES8 | JZ_DMA_DCS_CTE);
 }
 
 static void jz4780_dma_issue_pending(struct dma_chan *chan)
@@ -513,7 +529,7 @@ static int jz4780_dma_terminate_all(struct dma_chan *chan)
 	spin_lock_irqsave(&jzchan->vchan.lock, flags);
 
 	/* Clear the DMA status and stop the transfer. */
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0);
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
 	if (jzchan->desc) {
 		vchan_terminate_vdesc(&jzchan->desc->vdesc);
 		jzchan->desc = NULL;
@@ -562,8 +578,8 @@ static size_t jz4780_dma_desc_residue(struct jz4780_dma_chan *jzchan,
 		residue += desc->desc[i].dtc << jzchan->transfer_shift;
 
 	if (next_sg != 0) {
-		count = jz4780_dma_readl(jzdma,
-					 JZ_DMA_REG_DTC(jzchan->id));
+		count = jz4780_dma_chn_readl(jzdma, jzchan->id,
+					 JZ_DMA_REG_DTC);
 		residue += count << jzchan->transfer_shift;
 	}
 
@@ -610,8 +626,8 @@ static void jz4780_dma_chan_irq(struct jz4780_dma_dev *jzdma,
 
 	spin_lock(&jzchan->vchan.lock);
 
-	dcs = jz4780_dma_readl(jzdma, JZ_DMA_REG_DCS(jzchan->id));
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DCS(jzchan->id), 0);
+	dcs = jz4780_dma_chn_readl(jzdma, jzchan->id, JZ_DMA_REG_DCS);
+	jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
 
 	if (dcs & JZ_DMA_DCS_AR) {
 		dev_warn(&jzchan->vchan.chan.dev->device,
@@ -650,7 +666,7 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
 	uint32_t pending, dmac;
 	int i;
 
-	pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP);
+	pending = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DIRQP);
 
 	for (i = 0; i < jzdma->soc_data->nb_channels; i++) {
 		if (!(pending & (1<<i)))
@@ -660,12 +676,12 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
 	}
 
 	/* Clear halt and address error status of all channels. */
-	dmac = jz4780_dma_readl(jzdma, JZ_DMA_REG_DMAC);
+	dmac = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DMAC);
 	dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR);
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
+	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
 
 	/* Clear interrupt pending status. */
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
+	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DIRQP, 0);
 
 	return IRQ_HANDLED;
 }
@@ -790,9 +806,23 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	jzdma->base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(jzdma->base))
-		return PTR_ERR(jzdma->base);
+	jzdma->chn_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(jzdma->chn_base))
+		return PTR_ERR(jzdma->chn_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		jzdma->ctrl_base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(jzdma->ctrl_base))
+			return PTR_ERR(jzdma->ctrl_base);
+	} else {
+		/*
+		 * On JZ4780, if the second memory resource was not supplied,
+		 * assume we're using an old devicetree, and calculate the
+		 * offset to the control registers.
+		 */
+		jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET;
+	}
 
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
@@ -850,9 +880,9 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 	 * Also set the FMSC bit - it increases MSC performance, so it makes
 	 * little sense not to enable it.
 	 */
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DMAC,
+	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC,
 			  JZ_DMA_DMAC_DMAE | JZ_DMA_DMAC_FMSC);
-	jz4780_dma_writel(jzdma, JZ_DMA_REG_DMACP, 0);
+	jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);
 
 	INIT_LIST_HEAD(&dd->channels);
 

^ permalink raw reply related

* [v4,03/18] dmaengine: dma-jz4780: Avoid hardcoding number of channels
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

As part of the work to support various other Ingenic JZ47xx SoC versions,
which don't feature the same number of DMA channels per core, we now
deduce the number of DMA channels available from the devicetree
compatible string.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)

 v2: - don't hardcode jz_version to ID_JZ4780 when not probed from DT,
       because it cannot happen
     - Put SoC-specific data into a jz4780_dma_soc_data structure

 v3: No change

 v4: Remove jz_version; pass the jz4780_dma_soc_data structure pointer
     as devicetree match data, and use device_get_match_data().

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 987899610b46..9ec22cf15a33 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -23,8 +24,6 @@
 #include "dmaengine.h"
 #include "virt-dma.h"
 
-#define JZ_DMA_NR_CHANNELS	32
-
 /* Global registers. */
 #define JZ_DMA_REG_DMAC		0x1000
 #define JZ_DMA_REG_DIRQP	0x1004
@@ -135,14 +134,19 @@ struct jz4780_dma_chan {
 	unsigned int curr_hwdesc;
 };
 
+struct jz4780_dma_soc_data {
+	unsigned int nb_channels;
+};
+
 struct jz4780_dma_dev {
 	struct dma_device dma_device;
 	void __iomem *base;
 	struct clk *clk;
 	unsigned int irq;
+	const struct jz4780_dma_soc_data *soc_data;
 
 	uint32_t chan_reserved;
-	struct jz4780_dma_chan chan[JZ_DMA_NR_CHANNELS];
+	struct jz4780_dma_chan chan[];
 };
 
 struct jz4780_dma_filter_data {
@@ -648,7 +652,7 @@ static irqreturn_t jz4780_dma_irq_handler(int irq, void *data)
 
 	pending = jz4780_dma_readl(jzdma, JZ_DMA_REG_DIRQP);
 
-	for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) {
+	for (i = 0; i < jzdma->soc_data->nb_channels; i++) {
 		if (!(pending & (1<<i)))
 			continue;
 
@@ -728,7 +732,7 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
 	data.channel = dma_spec->args[1];
 
 	if (data.channel > -1) {
-		if (data.channel >= JZ_DMA_NR_CHANNELS) {
+		if (data.channel >= jzdma->soc_data->nb_channels) {
 			dev_err(jzdma->dma_device.dev,
 				"device requested non-existent channel %u\n",
 				data.channel);
@@ -755,6 +759,7 @@ static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
 static int jz4780_dma_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	const struct jz4780_dma_soc_data *soc_data;
 	struct jz4780_dma_dev *jzdma;
 	struct jz4780_dma_chan *jzchan;
 	struct dma_device *dd;
@@ -766,10 +771,17 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL);
+	soc_data = device_get_match_data(dev);
+	if (!soc_data)
+		return -EINVAL;
+
+	jzdma = devm_kzalloc(dev, sizeof(*jzdma)
+				+ sizeof(*jzdma->chan) * soc_data->nb_channels,
+				GFP_KERNEL);
 	if (!jzdma)
 		return -ENOMEM;
 
+	jzdma->soc_data = soc_data;
 	platform_set_drvdata(pdev, jzdma);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -844,7 +856,7 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 
 	INIT_LIST_HEAD(&dd->channels);
 
-	for (i = 0; i < JZ_DMA_NR_CHANNELS; i++) {
+	for (i = 0; i < soc_data->nb_channels; i++) {
 		jzchan = &jzdma->chan[i];
 		jzchan->id = i;
 
@@ -889,15 +901,19 @@ static int jz4780_dma_remove(struct platform_device *pdev)
 
 	free_irq(jzdma->irq, jzdma);
 
-	for (i = 0; i < JZ_DMA_NR_CHANNELS; i++)
+	for (i = 0; i < jzdma->soc_data->nb_channels; i++)
 		tasklet_kill(&jzdma->chan[i].vchan.task);
 
 	dma_async_device_unregister(&jzdma->dma_device);
 	return 0;
 }
 
+static const struct jz4780_dma_soc_data jz4780_dma_soc_data = {
+	.nb_channels = 32,
+};
+
 static const struct of_device_id jz4780_dma_dt_match[] = {
-	{ .compatible = "ingenic,jz4780-dma", .data = NULL },
+	{ .compatible = "ingenic,jz4780-dma", .data = &jz4780_dma_soc_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match);

^ permalink raw reply related

* [v4,02/18] dmaengine: dma-jz4780: Return error if not probed from DT
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The driver calls clk_get() with the clock name set to NULL, which means
that the driver could only work when probed from devicetree. From now
on, we explicitly require the driver to be probed from devicetree.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 drivers/dma/dma-jz4780.c | 5 +++++
 1 file changed, 5 insertions(+)

 v2: New patch

 v3: No change

 v4: No change

diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 85820a2d69d4..987899610b46 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -761,6 +761,11 @@ static int jz4780_dma_probe(struct platform_device *pdev)
 	struct resource *res;
 	int i, ret;
 
+	if (!dev->of_node) {
+		dev_err(dev, "This driver must be probed from devicetree\n");
+		return -EINVAL;
+	}
+
 	jzdma = devm_kzalloc(dev, sizeof(*jzdma), GFP_KERNEL);
 	if (!jzdma)
 		return -ENOMEM;

^ permalink raw reply related

* [v4,01/18] doc: dt-bindings: jz4780-dma: Update bindings to reflect driver changes
From: Paul Cercueil @ 2018-08-07 11:42 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Mark Rutland, Ralf Baechle, Paul Burton,
	James Hogan, Zubair Lutfullah Kakakhel
  Cc: Paul Cercueil, dmaengine, devicetree, linux-kernel, linux-mips

The driver now expects the devicetree to supply a second memory
resource. This resource is mandatory on the newly supported SoCs.
For the JZ4780, new devicetree code must also provide it, although the
driver is still compatible with older devicetree binaries.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Tested-by: Mathieu Malaterre <malat@debian.org>
---
 Documentation/devicetree/bindings/dma/jz4780-dma.txt | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

 v2: New patch in this series; regroups the changes made to the
 jz4780-dma.txt doc file in the previous version of the patchset.

 v3: Updated example to comply with devicetree specification

 v4: Removed driver-specific comment in commit message

diff --git a/Documentation/devicetree/bindings/dma/jz4780-dma.txt b/Documentation/devicetree/bindings/dma/jz4780-dma.txt
index f25feee62b15..14f33305e194 100644
--- a/Documentation/devicetree/bindings/dma/jz4780-dma.txt
+++ b/Documentation/devicetree/bindings/dma/jz4780-dma.txt
@@ -2,8 +2,13 @@
 
 Required properties:
 
-- compatible: Should be "ingenic,jz4780-dma"
-- reg: Should contain the DMA controller registers location and length.
+- compatible: Should be one of:
+  * ingenic,jz4740-dma
+  * ingenic,jz4725b-dma
+  * ingenic,jz4770-dma
+  * ingenic,jz4780-dma
+- reg: Should contain the DMA channel registers location and length, followed
+  by the DMA controller registers location and length.
 - interrupts: Should contain the interrupt specifier of the DMA controller.
 - interrupt-parent: Should be the phandle of the interrupt controller that
 - clocks: Should contain a clock specifier for the JZ4780 PDMA clock.
@@ -20,9 +25,10 @@ Optional properties:
 
 Example:
 
-dma: dma@13420000 {
+dma: dma-controller@13420000 {
 	compatible = "ingenic,jz4780-dma";
-	reg = <0x13420000 0x10000>;
+	reg = <0x13420000 0x400
+	       0x13421000 0x40>;
 
 	interrupt-parent = <&intc>;
 	interrupts = <10>;

^ permalink raw reply related

* [v8,1/3] dmaengine: fsl-edma: extract common fsl-edma code (no changes in behavior intended)
From: Stefan Agner @ 2018-08-07  8:08 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: vinod.koul, dmaengine, linux-arm-kernel, linux-m68k, krzk

On 03.08.2018 21:32, Angelo Dureghello wrote:
> This patch adds a new fsl-edma-common module to allow new
> mcf-edma module code to use most of the fsl-edma code.
> 
> Signed-off-by: Angelo Dureghello <angelo@sysam.it>
> ---
> Changes for v2:
> - patch splitted into 4
> - add mcf-edma as minimal different parts from fsl-edma
> 
> Changes for v3:
> none
> 
> Changes for v4:
> - patch simplified from 4/4 into 2/2
> - collecting all the mcf-edma-related changes
> 
> Changes for v5:
> none
> 
> Changes for v6:
> - adjusted comment header
> - fixed bit shift with BIT()
> - we need to free the interrupts at remove(), so removed all devm_
>   interrupt related calls
> 
> Changes for v7:
> none
> 
> Changes for v8:
> - patch rewritten from scratch, splitted into 3, common code isolated,
>   minimal changes from the original Freescale code have been done.
>   The patch has been tested with both Iris + Colibri Vybrid VF50 and
>   stmark2/mcf54415 Coldfire boards.
> ---
>  drivers/dma/Makefile          |   2 +-
>  drivers/dma/fsl-edma-common.c | 576 ++++++++++++++++++++++++++++
>  drivers/dma/fsl-edma-common.h | 196 ++++++++++
>  drivers/dma/fsl-edma.c        | 697 +---------------------------------
>  4 files changed, 774 insertions(+), 697 deletions(-)
>  create mode 100644 drivers/dma/fsl-edma-common.c
>  create mode 100644 drivers/dma/fsl-edma-common.h
> 
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index 203a99d68315..66022f59fca4 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -31,7 +31,7 @@ obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
>  obj-$(CONFIG_DW_DMAC_CORE) += dw/
>  obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
>  obj-$(CONFIG_FSL_DMA) += fsldma.o
> -obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
> +obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
>  obj-$(CONFIG_FSL_RAID) += fsl_raid.o
>  obj-$(CONFIG_HSU_DMA) += hsu/
>  obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
> diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> new file mode 100644
> index 000000000000..0ae7094f477a
> --- /dev/null
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -0,0 +1,576 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
> +// Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
> +
> +#include <linux/dmapool.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +
> +#include "fsl-edma-common.h"
> +
> +/*
> + * R/W functions for big- or little-endian registers:
> + * The eDMA controller's endian is independent of the CPU core's endian.
> + * For the big-endian IP module, the offset for 8-bit or 16-bit registers
> + * should also be swapped opposite to that in little-endian IP.
> + */
> +u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
> +{
> +	if (edma->big_endian)
> +		return ioread32be(addr);
> +	else
> +		return ioread32(addr);
> +}
> +EXPORT_SYMBOL_GPL(edma_readl);

In 3/3 you link the common object into the two modules individually:

obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o

Therefor you do not access those functions from another module (they are
within the module). No exporting should be necessary. Drop all those
exports.

If possible I would prefer if you start with cleanup/conversions, then
split-up and finally add functionality.

So ideally:
1. Use macros for preprocessor defines (where you move to BIT/GENMASK)
2. Split
3. Add EDMA macros etc.
4. Add ColdFire mcf5441x edma support
---
Stefan

> +
> +void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr)
> +{
> +	/* swap the reg offset for these in big-endian mode */
> +	if (edma->big_endian)
> +		iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
> +	else
> +		iowrite8(val, addr);
> +}
> +EXPORT_SYMBOL_GPL(edma_writeb);
> +
> +void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr)
> +{
> +	/* swap the reg offset for these in big-endian mode */
> +	if (edma->big_endian)
> +		iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
> +	else
> +		iowrite16(val, addr);
> +}
> +EXPORT_SYMBOL_GPL(edma_writew);
> +
> +void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr)
> +{
> +	if (edma->big_endian)
> +		iowrite32be(val, addr);
> +	else
> +		iowrite32(val, addr);
> +}
> +EXPORT_SYMBOL_GPL(edma_writel);
> +
> +struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
> +{
> +	return container_of(chan, struct fsl_edma_chan, vchan.chan);
> +}
> +EXPORT_SYMBOL_GPL(to_fsl_edma_chan);
> +
> +struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
> +{
> +	return container_of(vd, struct fsl_edma_desc, vdesc);
> +}
> +EXPORT_SYMBOL_GPL(to_fsl_edma_desc);
> +
> +static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
> +{
> +	void __iomem *addr = fsl_chan->edma->membase;
> +	u32 ch = fsl_chan->vchan.chan.chan_id;
> +
> +	edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
> +	edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
> +}
> +
> +void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
> +{
> +	void __iomem *addr = fsl_chan->edma->membase;
> +	u32 ch = fsl_chan->vchan.chan.chan_id;
> +
> +	edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
> +	edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
> +
> +void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
> +			unsigned int slot, bool enable)
> +{
> +	u32 ch = fsl_chan->vchan.chan.chan_id;
> +	void __iomem *muxaddr;
> +	unsigned int chans_per_mux, ch_off;
> +
> +	chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
> +	ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
> +	muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
> +	slot = EDMAMUX_CHCFG_SOURCE(slot);
> +
> +	if (enable)
> +		iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
> +	else
> +		iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_chan_mux);
> +
> +static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
> +{
> +	switch (addr_width) {
> +	case 1:
> +		return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
> +	case 2:
> +		return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
> +	case 4:
> +		return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
> +	case 8:
> +		return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
> +	default:
> +		return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
> +	}
> +}
> +
> +void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
> +{
> +	struct fsl_edma_desc *fsl_desc;
> +	int i;
> +
> +	fsl_desc = to_fsl_edma_desc(vdesc);
> +	for (i = 0; i < fsl_desc->n_tcds; i++)
> +		dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
> +			      fsl_desc->tcd[i].ptcd);
> +	kfree(fsl_desc);
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_free_desc);
> +
> +int fsl_edma_terminate_all(struct dma_chan *chan)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	unsigned long flags;
> +	LIST_HEAD(head);
> +
> +	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> +	fsl_edma_disable_request(fsl_chan);
> +	fsl_chan->edesc = NULL;
> +	fsl_chan->idle = true;
> +	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
> +	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_terminate_all);
> +
> +int fsl_edma_pause(struct dma_chan *chan)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> +	if (fsl_chan->edesc) {
> +		fsl_edma_disable_request(fsl_chan);
> +		fsl_chan->status = DMA_PAUSED;
> +		fsl_chan->idle = true;
> +	}
> +	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_pause);
> +
> +int fsl_edma_resume(struct dma_chan *chan)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> +	if (fsl_chan->edesc) {
> +		fsl_edma_enable_request(fsl_chan);
> +		fsl_chan->status = DMA_IN_PROGRESS;
> +		fsl_chan->idle = false;
> +	}
> +	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_resume);
> +
> +int fsl_edma_slave_config(struct dma_chan *chan,
> +				 struct dma_slave_config *cfg)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +
> +	fsl_chan->fsc.dir = cfg->direction;
> +	if (cfg->direction == DMA_DEV_TO_MEM) {
> +		fsl_chan->fsc.dev_addr = cfg->src_addr;
> +		fsl_chan->fsc.addr_width = cfg->src_addr_width;
> +		fsl_chan->fsc.burst = cfg->src_maxburst;
> +		fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
> +	} else if (cfg->direction == DMA_MEM_TO_DEV) {
> +		fsl_chan->fsc.dev_addr = cfg->dst_addr;
> +		fsl_chan->fsc.addr_width = cfg->dst_addr_width;
> +		fsl_chan->fsc.burst = cfg->dst_maxburst;
> +		fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
> +	} else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_slave_config);
> +
> +static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
> +		struct virt_dma_desc *vdesc, bool in_progress)
> +{
> +	struct fsl_edma_desc *edesc = fsl_chan->edesc;
> +	void __iomem *addr = fsl_chan->edma->membase;
> +	u32 ch = fsl_chan->vchan.chan.chan_id;
> +	enum dma_transfer_direction dir = fsl_chan->fsc.dir;
> +	dma_addr_t cur_addr, dma_addr;
> +	size_t len, size;
> +	int i;
> +
> +	/* calculate the total size in this desc */
> +	for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
> +		len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
> +			* le16_to_cpu(edesc->tcd[i].vtcd->biter);
> +
> +	if (!in_progress)
> +		return len;
> +
> +	if (dir == DMA_MEM_TO_DEV)
> +		cur_addr = edma_readl(
> +			fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
> +	else
> +		cur_addr = edma_readl(
> +			fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
> +
> +	/* figure out the finished and calculate the residue */
> +	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
> +		size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
> +			* le16_to_cpu(edesc->tcd[i].vtcd->biter);
> +		if (dir == DMA_MEM_TO_DEV)
> +			dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
> +		else
> +			dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
> +
> +		len -= size;
> +		if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
> +			len += dma_addr + size - cur_addr;
> +			break;
> +		}
> +	}
> +
> +	return len;
> +}
> +
> +enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
> +		dma_cookie_t cookie, struct dma_tx_state *txstate)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	struct virt_dma_desc *vdesc;
> +	enum dma_status status;
> +	unsigned long flags;
> +
> +	status = dma_cookie_status(chan, cookie, txstate);
> +	if (status == DMA_COMPLETE)
> +		return status;
> +
> +	if (!txstate)
> +		return fsl_chan->status;
> +
> +	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> +	vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
> +	if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
> +		txstate->residue =
> +			fsl_edma_desc_residue(fsl_chan, vdesc, true);
> +	else if (vdesc)
> +		txstate->residue =
> +			fsl_edma_desc_residue(fsl_chan, vdesc, false);
> +	else
> +		txstate->residue = 0;
> +
> +	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +
> +	return fsl_chan->status;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_tx_status);
> +
> +static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
> +				  struct fsl_edma_hw_tcd *tcd)
> +{
> +	struct fsl_edma_engine *edma = fsl_chan->edma;
> +	void __iomem *addr = fsl_chan->edma->membase;
> +	u32 ch = fsl_chan->vchan.chan.chan_id;
> +
> +	/*
> +	 * TCD parameters are stored in struct fsl_edma_hw_tcd in little
> +	 * endian format. However, we need to load the TCD registers in
> +	 * big- or little-endian obeying the eDMA engine model endian.
> +	 */
> +	edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
> +	edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
> +	edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
> +
> +	edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
> +	edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
> +
> +	edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
> +	edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
> +
> +	edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
> +	edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
> +	edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
> +
> +	edma_writel(edma,
> +		    le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
> +
> +	edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
> +}
> +
> +static inline
> +void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
> +		       u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
> +		       u16 biter, u16 doff, u32 dlast_sga, bool major_int,
> +		       bool disable_req, bool enable_sg)
> +{
> +	u16 csr = 0;
> +
> +	/*
> +	 * eDMA hardware SGs require the TCDs to be stored in little
> +	 * endian format irrespective of the register endian model.
> +	 * So we put the value in little endian in memory, waiting
> +	 * for fsl_edma_set_tcd_regs doing the swap.
> +	 */
> +	tcd->saddr = cpu_to_le32(src);
> +	tcd->daddr = cpu_to_le32(dst);
> +
> +	tcd->attr = cpu_to_le16(attr);
> +
> +	tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
> +
> +	tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
> +	tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
> +
> +	tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
> +	tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
> +
> +	tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
> +
> +	tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
> +	if (major_int)
> +		csr |= EDMA_TCD_CSR_INT_MAJOR;
> +
> +	if (disable_req)
> +		csr |= EDMA_TCD_CSR_D_REQ;
> +
> +	if (enable_sg)
> +		csr |= EDMA_TCD_CSR_E_SG;
> +
> +	tcd->csr = cpu_to_le16(csr);
> +}
> +
> +static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan
> *fsl_chan,
> +		int sg_len)
> +{
> +	struct fsl_edma_desc *fsl_desc;
> +	int i;
> +
> +	fsl_desc = kzalloc(sizeof(*fsl_desc) +
> +			   sizeof(struct fsl_edma_sw_tcd) *
> +			   sg_len, GFP_NOWAIT);
> +	if (!fsl_desc)
> +		return NULL;
> +
> +	fsl_desc->echan = fsl_chan;
> +	fsl_desc->n_tcds = sg_len;
> +	for (i = 0; i < sg_len; i++) {
> +		fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
> +					GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
> +		if (!fsl_desc->tcd[i].vtcd)
> +			goto err;
> +	}
> +	return fsl_desc;
> +
> +err:
> +	while (--i >= 0)
> +		dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
> +				fsl_desc->tcd[i].ptcd);
> +	kfree(fsl_desc);
> +	return NULL;
> +}
> +
> +struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
> +		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
> +		size_t period_len, enum dma_transfer_direction direction,
> +		unsigned long flags)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	struct fsl_edma_desc *fsl_desc;
> +	dma_addr_t dma_buf_next;
> +	int sg_len, i;
> +	u32 src_addr, dst_addr, last_sg, nbytes;
> +	u16 soff, doff, iter;
> +
> +	if (!is_slave_direction(fsl_chan->fsc.dir))
> +		return NULL;
> +
> +	sg_len = buf_len / period_len;
> +	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> +	if (!fsl_desc)
> +		return NULL;
> +	fsl_desc->iscyclic = true;
> +
> +	dma_buf_next = dma_addr;
> +	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> +	iter = period_len / nbytes;
> +
> +	for (i = 0; i < sg_len; i++) {
> +		if (dma_buf_next >= dma_addr + buf_len)
> +			dma_buf_next = dma_addr;
> +
> +		/* get next sg's physical address */
> +		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
> +
> +		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
> +			src_addr = dma_buf_next;
> +			dst_addr = fsl_chan->fsc.dev_addr;
> +			soff = fsl_chan->fsc.addr_width;
> +			doff = 0;
> +		} else {
> +			src_addr = fsl_chan->fsc.dev_addr;
> +			dst_addr = dma_buf_next;
> +			soff = 0;
> +			doff = fsl_chan->fsc.addr_width;
> +		}
> +
> +		fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
> +				  fsl_chan->fsc.attr, soff, nbytes, 0, iter,
> +				  iter, doff, last_sg, true, false, true);
> +		dma_buf_next += period_len;
> +	}
> +
> +	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_prep_dma_cyclic);
> +
> +struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
> +		struct dma_chan *chan, struct scatterlist *sgl,
> +		unsigned int sg_len, enum dma_transfer_direction direction,
> +		unsigned long flags, void *context)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	struct fsl_edma_desc *fsl_desc;
> +	struct scatterlist *sg;
> +	u32 src_addr, dst_addr, last_sg, nbytes;
> +	u16 soff, doff, iter;
> +	int i;
> +
> +	if (!is_slave_direction(fsl_chan->fsc.dir))
> +		return NULL;
> +
> +	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> +	if (!fsl_desc)
> +		return NULL;
> +	fsl_desc->iscyclic = false;
> +
> +	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> +	for_each_sg(sgl, sg, sg_len, i) {
> +		/* get next sg's physical address */
> +		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
> +
> +		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
> +			src_addr = sg_dma_address(sg);
> +			dst_addr = fsl_chan->fsc.dev_addr;
> +			soff = fsl_chan->fsc.addr_width;
> +			doff = 0;
> +		} else {
> +			src_addr = fsl_chan->fsc.dev_addr;
> +			dst_addr = sg_dma_address(sg);
> +			soff = 0;
> +			doff = fsl_chan->fsc.addr_width;
> +		}
> +
> +		iter = sg_dma_len(sg) / nbytes;
> +		if (i < sg_len - 1) {
> +			last_sg = fsl_desc->tcd[(i + 1)].ptcd;
> +			fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
> +					  dst_addr, fsl_chan->fsc.attr, soff,
> +					  nbytes, 0, iter, iter, doff, last_sg,
> +					  false, false, true);
> +		} else {
> +			last_sg = 0;
> +			fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
> +					  dst_addr, fsl_chan->fsc.attr, soff,
> +					  nbytes, 0, iter, iter, doff, last_sg,
> +					  true, true, false);
> +		}
> +	}
> +
> +	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_prep_slave_sg);
> +
> +void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
> +{
> +	struct virt_dma_desc *vdesc;
> +
> +	vdesc = vchan_next_desc(&fsl_chan->vchan);
> +	if (!vdesc)
> +		return;
> +	fsl_chan->edesc = to_fsl_edma_desc(vdesc);
> +	fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
> +	fsl_edma_enable_request(fsl_chan);
> +	fsl_chan->status = DMA_IN_PROGRESS;
> +	fsl_chan->idle = false;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_xfer_desc);
> +
> +void fsl_edma_issue_pending(struct dma_chan *chan)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> +
> +	if (unlikely(fsl_chan->pm_state != RUNNING)) {
> +		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +		/* cannot submit due to suspend */
> +		return;
> +	}
> +
> +	if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
> +		fsl_edma_xfer_desc(fsl_chan);
> +
> +	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_issue_pending);
> +
> +int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +
> +	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
> +				sizeof(struct fsl_edma_hw_tcd),
> +				32, 0);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_alloc_chan_resources);
> +
> +void fsl_edma_free_chan_resources(struct dma_chan *chan)
> +{
> +	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +	unsigned long flags;
> +	LIST_HEAD(head);
> +
> +	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> +	fsl_edma_disable_request(fsl_chan);
> +	fsl_edma_chan_mux(fsl_chan, 0, false);
> +	fsl_chan->edesc = NULL;
> +	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
> +	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> +
> +	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> +	dma_pool_destroy(fsl_chan->tcd_pool);
> +	fsl_chan->tcd_pool = NULL;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_free_chan_resources);
> +
> +void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
> +{
> +	struct fsl_edma_chan *chan, *_chan;
> +
> +	list_for_each_entry_safe(chan, _chan,
> +				&dmadev->channels, vchan.chan.device_node) {
> +		list_del(&chan->vchan.chan.device_node);
> +		tasklet_kill(&chan->vchan.task);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
> new file mode 100644
> index 000000000000..f3ea68e15b23
> --- /dev/null
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -0,0 +1,196 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright 2013-2014 Freescale Semiconductor, Inc.
> + * Copyright 2018 Angelo Dureghello <angelo@sysam.it>
> + */
> +#ifndef _FSL_EDMA_COMMON_H_
> +#define _FSL_EDMA_COMMON_H_
> +
> +#include "virt-dma.h"
> +
> +#define EDMA_CR			0x00
> +#define EDMA_ES			0x04
> +#define EDMA_ERQ		0x0C
> +#define EDMA_EEI		0x14
> +#define EDMA_SERQ		0x1B
> +#define EDMA_CERQ		0x1A
> +#define EDMA_SEEI		0x19
> +#define EDMA_CEEI		0x18
> +#define EDMA_CINT		0x1F
> +#define EDMA_CERR		0x1E
> +#define EDMA_SSRT		0x1D
> +#define EDMA_CDNE		0x1C
> +#define EDMA_INTR		0x24
> +#define EDMA_ERR		0x2C
> +
> +#define EDMA_TCD_SADDR(x)	(0x1000 + 32 * (x))
> +#define EDMA_TCD_SOFF(x)	(0x1004 + 32 * (x))
> +#define EDMA_TCD_ATTR(x)	(0x1006 + 32 * (x))
> +#define EDMA_TCD_NBYTES(x)	(0x1008 + 32 * (x))
> +#define EDMA_TCD_SLAST(x)	(0x100C + 32 * (x))
> +#define EDMA_TCD_DADDR(x)	(0x1010 + 32 * (x))
> +#define EDMA_TCD_DOFF(x)	(0x1014 + 32 * (x))
> +#define EDMA_TCD_CITER_ELINK(x)	(0x1016 + 32 * (x))
> +#define EDMA_TCD_CITER(x)	(0x1016 + 32 * (x))
> +#define EDMA_TCD_DLAST_SGA(x)	(0x1018 + 32 * (x))
> +#define EDMA_TCD_CSR(x)		(0x101C + 32 * (x))
> +#define EDMA_TCD_BITER_ELINK(x)	(0x101E + 32 * (x))
> +#define EDMA_TCD_BITER(x)	(0x101E + 32 * (x))
> +
> +#define EDMA_CR_EDBG		BIT(1)
> +#define EDMA_CR_ERCA		BIT(2)
> +#define EDMA_CR_ERGA		BIT(3)
> +#define EDMA_CR_HOE		BIT(4)
> +#define EDMA_CR_HALT		BIT(5)
> +#define EDMA_CR_CLM		BIT(6)
> +#define EDMA_CR_EMLM		BIT(7)
> +#define EDMA_CR_ECX		BIT(16)
> +#define EDMA_CR_CX		BIT(17)
> +
> +#define EDMA_SEEI_SEEI(x)	((x) & 0x1F)
> +#define EDMA_CEEI_CEEI(x)	((x) & 0x1F)
> +#define EDMA_CINT_CINT(x)	((x) & 0x1F)
> +#define EDMA_CERR_CERR(x)	((x) & 0x1F)
> +
> +#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & 0x0007))
> +#define EDMA_TCD_ATTR_DMOD(x)		(((x) & 0x001F) << 3)
> +#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & 0x0007) << 8)
> +#define EDMA_TCD_ATTR_SMOD(x)		(((x) & 0x001F) << 11)
> +#define EDMA_TCD_ATTR_SSIZE_8BIT	(0x0000)
> +#define EDMA_TCD_ATTR_SSIZE_16BIT	(0x0100)
> +#define EDMA_TCD_ATTR_SSIZE_32BIT	(0x0200)
> +#define EDMA_TCD_ATTR_SSIZE_64BIT	(0x0300)
> +#define EDMA_TCD_ATTR_SSIZE_32BYTE	(0x0500)
> +#define EDMA_TCD_ATTR_DSIZE_8BIT	(0x0000)
> +#define EDMA_TCD_ATTR_DSIZE_16BIT	(0x0001)
> +#define EDMA_TCD_ATTR_DSIZE_32BIT	(0x0002)
> +#define EDMA_TCD_ATTR_DSIZE_64BIT	(0x0003)
> +#define EDMA_TCD_ATTR_DSIZE_32BYTE	(0x0005)
> +
> +#define EDMA_TCD_SOFF_SOFF(x)		(x)
> +#define EDMA_TCD_NBYTES_NBYTES(x)	(x)
> +#define EDMA_TCD_SLAST_SLAST(x)		(x)
> +#define EDMA_TCD_DADDR_DADDR(x)		(x)
> +#define EDMA_TCD_CITER_CITER(x)		((x) & 0x7FFF)
> +#define EDMA_TCD_DOFF_DOFF(x)		(x)
> +#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)	(x)
> +#define EDMA_TCD_BITER_BITER(x)		((x) & 0x7FFF)
> +
> +#define EDMA_TCD_CSR_START		BIT(0)
> +#define EDMA_TCD_CSR_INT_MAJOR		BIT(1)
> +#define EDMA_TCD_CSR_INT_HALF		BIT(2)
> +#define EDMA_TCD_CSR_D_REQ		BIT(3)
> +#define EDMA_TCD_CSR_E_SG		BIT(4)
> +#define EDMA_TCD_CSR_E_LINK		BIT(5)
> +#define EDMA_TCD_CSR_ACTIVE		BIT(6)
> +#define EDMA_TCD_CSR_DONE		BIT(7)
> +
> +#define EDMAMUX_CHCFG_DIS		0x0
> +#define EDMAMUX_CHCFG_ENBL		0x80
> +#define EDMAMUX_CHCFG_SOURCE(n)		((n) & 0x3F)
> +
> +#define DMAMUX_NR	2
> +
> +#define FSL_EDMA_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
> +				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
> +				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
> +				 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
> +enum fsl_edma_pm_state {
> +	RUNNING = 0,
> +	SUSPENDED,
> +};
> +
> +struct fsl_edma_hw_tcd {
> +	__le32	saddr;
> +	__le16	soff;
> +	__le16	attr;
> +	__le32	nbytes;
> +	__le32	slast;
> +	__le32	daddr;
> +	__le16	doff;
> +	__le16	citer;
> +	__le32	dlast_sga;
> +	__le16	csr;
> +	__le16	biter;
> +};
> +
> +struct fsl_edma_sw_tcd {
> +	dma_addr_t			ptcd;
> +	struct fsl_edma_hw_tcd		*vtcd;
> +};
> +
> +struct fsl_edma_slave_config {
> +	enum dma_transfer_direction	dir;
> +	enum dma_slave_buswidth		addr_width;
> +	u32				dev_addr;
> +	u32				burst;
> +	u32				attr;
> +};
> +
> +struct fsl_edma_chan {
> +	struct virt_dma_chan		vchan;
> +	enum dma_status			status;
> +	enum fsl_edma_pm_state		pm_state;
> +	bool				idle;
> +	u32				slave_id;
> +	struct fsl_edma_engine		*edma;
> +	struct fsl_edma_desc		*edesc;
> +	struct fsl_edma_slave_config	fsc;
> +	struct dma_pool			*tcd_pool;
> +};
> +
> +struct fsl_edma_desc {
> +	struct virt_dma_desc		vdesc;
> +	struct fsl_edma_chan		*echan;
> +	bool				iscyclic;
> +	unsigned int			n_tcds;
> +	struct fsl_edma_sw_tcd		tcd[];
> +};
> +
> +struct fsl_edma_engine {
> +	struct dma_device	dma_dev;
> +	void __iomem		*membase;
> +	void __iomem		*muxbase[DMAMUX_NR];
> +	struct clk		*muxclk[DMAMUX_NR];
> +	struct mutex		fsl_edma_mutex;
> +	u32			n_chans;
> +	int			txirq;
> +	int			errirq;
> +	bool			big_endian;
> +	struct fsl_edma_chan	chans[];
> +};
> +
> +u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr);
> +void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr);
> +void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr);
> +void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr);
> +
> +struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan);
> +struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd);
> +
> +void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan);
> +void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
> +			unsigned int slot, bool enable);
> +void fsl_edma_free_desc(struct virt_dma_desc *vdesc);
> +int fsl_edma_terminate_all(struct dma_chan *chan);
> +int fsl_edma_pause(struct dma_chan *chan);
> +int fsl_edma_resume(struct dma_chan *chan);
> +int fsl_edma_slave_config(struct dma_chan *chan,
> +				 struct dma_slave_config *cfg);
> +enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
> +		dma_cookie_t cookie, struct dma_tx_state *txstate);
> +struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
> +		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
> +		size_t period_len, enum dma_transfer_direction direction,
> +		unsigned long flags);
> +struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
> +		struct dma_chan *chan, struct scatterlist *sgl,
> +		unsigned int sg_len, enum dma_transfer_direction direction,
> +		unsigned long flags, void *context);
> +void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan);
> +void fsl_edma_issue_pending(struct dma_chan *chan);
> +int fsl_edma_alloc_chan_resources(struct dma_chan *chan);
> +void fsl_edma_free_chan_resources(struct dma_chan *chan);
> +void fsl_edma_cleanup_vchan(struct dma_device *dmadev);
> +
> +#endif /* _FSL_EDMA_COMMON_H_ */
> diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
> index c7568869284e..337ad0c0ea78 100644
> --- a/drivers/dma/fsl-edma.c
> +++ b/drivers/dma/fsl-edma.c
> @@ -13,653 +13,16 @@
>   * option) any later version.
>   */
>  
> -#include <linux/init.h>
>  #include <linux/module.h>
>  #include <linux/interrupt.h>
>  #include <linux/clk.h>
> -#include <linux/dma-mapping.h>
> -#include <linux/dmapool.h>
> -#include <linux/slab.h>
> -#include <linux/spinlock.h>
>  #include <linux/of.h>
>  #include <linux/of_device.h>
>  #include <linux/of_address.h>
>  #include <linux/of_irq.h>
>  #include <linux/of_dma.h>
>  
> -#include "virt-dma.h"
> -
> -#define EDMA_CR			0x00
> -#define EDMA_ES			0x04
> -#define EDMA_ERQ		0x0C
> -#define EDMA_EEI		0x14
> -#define EDMA_SERQ		0x1B
> -#define EDMA_CERQ		0x1A
> -#define EDMA_SEEI		0x19
> -#define EDMA_CEEI		0x18
> -#define EDMA_CINT		0x1F
> -#define EDMA_CERR		0x1E
> -#define EDMA_SSRT		0x1D
> -#define EDMA_CDNE		0x1C
> -#define EDMA_INTR		0x24
> -#define EDMA_ERR		0x2C
> -
> -#define EDMA_TCD_SADDR(x)	(0x1000 + 32 * (x))
> -#define EDMA_TCD_SOFF(x)	(0x1004 + 32 * (x))
> -#define EDMA_TCD_ATTR(x)	(0x1006 + 32 * (x))
> -#define EDMA_TCD_NBYTES(x)	(0x1008 + 32 * (x))
> -#define EDMA_TCD_SLAST(x)	(0x100C + 32 * (x))
> -#define EDMA_TCD_DADDR(x)	(0x1010 + 32 * (x))
> -#define EDMA_TCD_DOFF(x)	(0x1014 + 32 * (x))
> -#define EDMA_TCD_CITER_ELINK(x)	(0x1016 + 32 * (x))
> -#define EDMA_TCD_CITER(x)	(0x1016 + 32 * (x))
> -#define EDMA_TCD_DLAST_SGA(x)	(0x1018 + 32 * (x))
> -#define EDMA_TCD_CSR(x)		(0x101C + 32 * (x))
> -#define EDMA_TCD_BITER_ELINK(x)	(0x101E + 32 * (x))
> -#define EDMA_TCD_BITER(x)	(0x101E + 32 * (x))
> -
> -#define EDMA_CR_EDBG		BIT(1)
> -#define EDMA_CR_ERCA		BIT(2)
> -#define EDMA_CR_ERGA		BIT(3)
> -#define EDMA_CR_HOE		BIT(4)
> -#define EDMA_CR_HALT		BIT(5)
> -#define EDMA_CR_CLM		BIT(6)
> -#define EDMA_CR_EMLM		BIT(7)
> -#define EDMA_CR_ECX		BIT(16)
> -#define EDMA_CR_CX		BIT(17)
> -
> -#define EDMA_SEEI_SEEI(x)	((x) & 0x1F)
> -#define EDMA_CEEI_CEEI(x)	((x) & 0x1F)
> -#define EDMA_CINT_CINT(x)	((x) & 0x1F)
> -#define EDMA_CERR_CERR(x)	((x) & 0x1F)
> -
> -#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & 0x0007))
> -#define EDMA_TCD_ATTR_DMOD(x)		(((x) & 0x001F) << 3)
> -#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & 0x0007) << 8)
> -#define EDMA_TCD_ATTR_SMOD(x)		(((x) & 0x001F) << 11)
> -#define EDMA_TCD_ATTR_SSIZE_8BIT	(0x0000)
> -#define EDMA_TCD_ATTR_SSIZE_16BIT	(0x0100)
> -#define EDMA_TCD_ATTR_SSIZE_32BIT	(0x0200)
> -#define EDMA_TCD_ATTR_SSIZE_64BIT	(0x0300)
> -#define EDMA_TCD_ATTR_SSIZE_32BYTE	(0x0500)
> -#define EDMA_TCD_ATTR_DSIZE_8BIT	(0x0000)
> -#define EDMA_TCD_ATTR_DSIZE_16BIT	(0x0001)
> -#define EDMA_TCD_ATTR_DSIZE_32BIT	(0x0002)
> -#define EDMA_TCD_ATTR_DSIZE_64BIT	(0x0003)
> -#define EDMA_TCD_ATTR_DSIZE_32BYTE	(0x0005)
> -
> -#define EDMA_TCD_SOFF_SOFF(x)		(x)
> -#define EDMA_TCD_NBYTES_NBYTES(x)	(x)
> -#define EDMA_TCD_SLAST_SLAST(x)		(x)
> -#define EDMA_TCD_DADDR_DADDR(x)		(x)
> -#define EDMA_TCD_CITER_CITER(x)		((x) & 0x7FFF)
> -#define EDMA_TCD_DOFF_DOFF(x)		(x)
> -#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)	(x)
> -#define EDMA_TCD_BITER_BITER(x)		((x) & 0x7FFF)
> -
> -#define EDMA_TCD_CSR_START		BIT(0)
> -#define EDMA_TCD_CSR_INT_MAJOR		BIT(1)
> -#define EDMA_TCD_CSR_INT_HALF		BIT(2)
> -#define EDMA_TCD_CSR_D_REQ		BIT(3)
> -#define EDMA_TCD_CSR_E_SG		BIT(4)
> -#define EDMA_TCD_CSR_E_LINK		BIT(5)
> -#define EDMA_TCD_CSR_ACTIVE		BIT(6)
> -#define EDMA_TCD_CSR_DONE		BIT(7)
> -
> -#define EDMAMUX_CHCFG_DIS		0x0
> -#define EDMAMUX_CHCFG_ENBL		0x80
> -#define EDMAMUX_CHCFG_SOURCE(n)		((n) & 0x3F)
> -
> -#define DMAMUX_NR	2
> -
> -#define FSL_EDMA_BUSWIDTHS	BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
> -				BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
> -				BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
> -				BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
> -enum fsl_edma_pm_state {
> -	RUNNING = 0,
> -	SUSPENDED,
> -};
> -
> -struct fsl_edma_hw_tcd {
> -	__le32	saddr;
> -	__le16	soff;
> -	__le16	attr;
> -	__le32	nbytes;
> -	__le32	slast;
> -	__le32	daddr;
> -	__le16	doff;
> -	__le16	citer;
> -	__le32	dlast_sga;
> -	__le16	csr;
> -	__le16	biter;
> -};
> -
> -struct fsl_edma_sw_tcd {
> -	dma_addr_t			ptcd;
> -	struct fsl_edma_hw_tcd		*vtcd;
> -};
> -
> -struct fsl_edma_slave_config {
> -	enum dma_transfer_direction	dir;
> -	enum dma_slave_buswidth		addr_width;
> -	u32				dev_addr;
> -	u32				burst;
> -	u32				attr;
> -};
> -
> -struct fsl_edma_chan {
> -	struct virt_dma_chan		vchan;
> -	enum dma_status			status;
> -	enum fsl_edma_pm_state		pm_state;
> -	bool				idle;
> -	u32				slave_id;
> -	struct fsl_edma_engine		*edma;
> -	struct fsl_edma_desc		*edesc;
> -	struct fsl_edma_slave_config	fsc;
> -	struct dma_pool			*tcd_pool;
> -};
> -
> -struct fsl_edma_desc {
> -	struct virt_dma_desc		vdesc;
> -	struct fsl_edma_chan		*echan;
> -	bool				iscyclic;
> -	unsigned int			n_tcds;
> -	struct fsl_edma_sw_tcd		tcd[];
> -};
> -
> -struct fsl_edma_engine {
> -	struct dma_device	dma_dev;
> -	void __iomem		*membase;
> -	void __iomem		*muxbase[DMAMUX_NR];
> -	struct clk		*muxclk[DMAMUX_NR];
> -	struct mutex		fsl_edma_mutex;
> -	u32			n_chans;
> -	int			txirq;
> -	int			errirq;
> -	bool			big_endian;
> -	struct fsl_edma_chan	chans[];
> -};
> -
> -/*
> - * R/W functions for big- or little-endian registers:
> - * The eDMA controller's endian is independent of the CPU core's endian.
> - * For the big-endian IP module, the offset for 8-bit or 16-bit registers
> - * should also be swapped opposite to that in little-endian IP.
> - */
> -
> -static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
> -{
> -	if (edma->big_endian)
> -		return ioread32be(addr);
> -	else
> -		return ioread32(addr);
> -}
> -
> -static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void
> __iomem *addr)
> -{
> -	/* swap the reg offset for these in big-endian mode */
> -	if (edma->big_endian)
> -		iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
> -	else
> -		iowrite8(val, addr);
> -}
> -
> -static void edma_writew(struct fsl_edma_engine *edma, u16 val, void
> __iomem *addr)
> -{
> -	/* swap the reg offset for these in big-endian mode */
> -	if (edma->big_endian)
> -		iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2));
> -	else
> -		iowrite16(val, addr);
> -}
> -
> -static void edma_writel(struct fsl_edma_engine *edma, u32 val, void
> __iomem *addr)
> -{
> -	if (edma->big_endian)
> -		iowrite32be(val, addr);
> -	else
> -		iowrite32(val, addr);
> -}
> -
> -static struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
> -{
> -	return container_of(chan, struct fsl_edma_chan, vchan.chan);
> -}
> -
> -static struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
> -{
> -	return container_of(vd, struct fsl_edma_desc, vdesc);
> -}
> -
> -static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
> -{
> -	void __iomem *addr = fsl_chan->edma->membase;
> -	u32 ch = fsl_chan->vchan.chan.chan_id;
> -
> -	edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
> -	edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
> -}
> -
> -static void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
> -{
> -	void __iomem *addr = fsl_chan->edma->membase;
> -	u32 ch = fsl_chan->vchan.chan.chan_id;
> -
> -	edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
> -	edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
> -}
> -
> -static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
> -			unsigned int slot, bool enable)
> -{
> -	u32 ch = fsl_chan->vchan.chan.chan_id;
> -	void __iomem *muxaddr;
> -	unsigned chans_per_mux, ch_off;
> -
> -	chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
> -	ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
> -	muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
> -	slot = EDMAMUX_CHCFG_SOURCE(slot);
> -
> -	if (enable)
> -		iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
> -	else
> -		iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
> -}
> -
> -static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
> -{
> -	switch (addr_width) {
> -	case 1:
> -		return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
> -	case 2:
> -		return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
> -	case 4:
> -		return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
> -	case 8:
> -		return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
> -	default:
> -		return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
> -	}
> -}
> -
> -static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
> -{
> -	struct fsl_edma_desc *fsl_desc;
> -	int i;
> -
> -	fsl_desc = to_fsl_edma_desc(vdesc);
> -	for (i = 0; i < fsl_desc->n_tcds; i++)
> -		dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
> -			      fsl_desc->tcd[i].ptcd);
> -	kfree(fsl_desc);
> -}
> -
> -static int fsl_edma_terminate_all(struct dma_chan *chan)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	unsigned long flags;
> -	LIST_HEAD(head);
> -
> -	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> -	fsl_edma_disable_request(fsl_chan);
> -	fsl_chan->edesc = NULL;
> -	fsl_chan->idle = true;
> -	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
> -	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> -	return 0;
> -}
> -
> -static int fsl_edma_pause(struct dma_chan *chan)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> -	if (fsl_chan->edesc) {
> -		fsl_edma_disable_request(fsl_chan);
> -		fsl_chan->status = DMA_PAUSED;
> -		fsl_chan->idle = true;
> -	}
> -	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -	return 0;
> -}
> -
> -static int fsl_edma_resume(struct dma_chan *chan)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> -	if (fsl_chan->edesc) {
> -		fsl_edma_enable_request(fsl_chan);
> -		fsl_chan->status = DMA_IN_PROGRESS;
> -		fsl_chan->idle = false;
> -	}
> -	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -	return 0;
> -}
> -
> -static int fsl_edma_slave_config(struct dma_chan *chan,
> -				 struct dma_slave_config *cfg)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -
> -	fsl_chan->fsc.dir = cfg->direction;
> -	if (cfg->direction == DMA_DEV_TO_MEM) {
> -		fsl_chan->fsc.dev_addr = cfg->src_addr;
> -		fsl_chan->fsc.addr_width = cfg->src_addr_width;
> -		fsl_chan->fsc.burst = cfg->src_maxburst;
> -		fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
> -	} else if (cfg->direction == DMA_MEM_TO_DEV) {
> -		fsl_chan->fsc.dev_addr = cfg->dst_addr;
> -		fsl_chan->fsc.addr_width = cfg->dst_addr_width;
> -		fsl_chan->fsc.burst = cfg->dst_maxburst;
> -		fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
> -	} else {
> -			return -EINVAL;
> -	}
> -	return 0;
> -}
> -
> -static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
> -		struct virt_dma_desc *vdesc, bool in_progress)
> -{
> -	struct fsl_edma_desc *edesc = fsl_chan->edesc;
> -	void __iomem *addr = fsl_chan->edma->membase;
> -	u32 ch = fsl_chan->vchan.chan.chan_id;
> -	enum dma_transfer_direction dir = fsl_chan->fsc.dir;
> -	dma_addr_t cur_addr, dma_addr;
> -	size_t len, size;
> -	int i;
> -
> -	/* calculate the total size in this desc */
> -	for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
> -		len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
> -			* le16_to_cpu(edesc->tcd[i].vtcd->biter);
> -
> -	if (!in_progress)
> -		return len;
> -
> -	if (dir == DMA_MEM_TO_DEV)
> -		cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
> -	else
> -		cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
> -
> -	/* figure out the finished and calculate the residue */
> -	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
> -		size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
> -			* le16_to_cpu(edesc->tcd[i].vtcd->biter);
> -		if (dir == DMA_MEM_TO_DEV)
> -			dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
> -		else
> -			dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
> -
> -		len -= size;
> -		if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
> -			len += dma_addr + size - cur_addr;
> -			break;
> -		}
> -	}
> -
> -	return len;
> -}
> -
> -static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
> -		dma_cookie_t cookie, struct dma_tx_state *txstate)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	struct virt_dma_desc *vdesc;
> -	enum dma_status status;
> -	unsigned long flags;
> -
> -	status = dma_cookie_status(chan, cookie, txstate);
> -	if (status == DMA_COMPLETE)
> -		return status;
> -
> -	if (!txstate)
> -		return fsl_chan->status;
> -
> -	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> -	vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
> -	if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
> -		txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true);
> -	else if (vdesc)
> -		txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false);
> -	else
> -		txstate->residue = 0;
> -
> -	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -
> -	return fsl_chan->status;
> -}
> -
> -static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
> -				  struct fsl_edma_hw_tcd *tcd)
> -{
> -	struct fsl_edma_engine *edma = fsl_chan->edma;
> -	void __iomem *addr = fsl_chan->edma->membase;
> -	u32 ch = fsl_chan->vchan.chan.chan_id;
> -
> -	/*
> -	 * TCD parameters are stored in struct fsl_edma_hw_tcd in little
> -	 * endian format. However, we need to load the TCD registers in
> -	 * big- or little-endian obeying the eDMA engine model endian.
> -	 */
> -	edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
> -	edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
> -	edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
> -
> -	edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
> -	edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
> -
> -	edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
> -	edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
> -
> -	edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
> -	edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
> -	edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
> -
> -	edma_writel(edma, le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
> -
> -	edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
> -}
> -
> -static inline
> -void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
> -		       u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
> -		       u16 biter, u16 doff, u32 dlast_sga, bool major_int,
> -		       bool disable_req, bool enable_sg)
> -{
> -	u16 csr = 0;
> -
> -	/*
> -	 * eDMA hardware SGs require the TCDs to be stored in little
> -	 * endian format irrespective of the register endian model.
> -	 * So we put the value in little endian in memory, waiting
> -	 * for fsl_edma_set_tcd_regs doing the swap.
> -	 */
> -	tcd->saddr = cpu_to_le32(src);
> -	tcd->daddr = cpu_to_le32(dst);
> -
> -	tcd->attr = cpu_to_le16(attr);
> -
> -	tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
> -
> -	tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
> -	tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
> -
> -	tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
> -	tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
> -
> -	tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
> -
> -	tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
> -	if (major_int)
> -		csr |= EDMA_TCD_CSR_INT_MAJOR;
> -
> -	if (disable_req)
> -		csr |= EDMA_TCD_CSR_D_REQ;
> -
> -	if (enable_sg)
> -		csr |= EDMA_TCD_CSR_E_SG;
> -
> -	tcd->csr = cpu_to_le16(csr);
> -}
> -
> -static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan
> *fsl_chan,
> -		int sg_len)
> -{
> -	struct fsl_edma_desc *fsl_desc;
> -	int i;
> -
> -	fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct
> fsl_edma_sw_tcd) * sg_len,
> -				GFP_NOWAIT);
> -	if (!fsl_desc)
> -		return NULL;
> -
> -	fsl_desc->echan = fsl_chan;
> -	fsl_desc->n_tcds = sg_len;
> -	for (i = 0; i < sg_len; i++) {
> -		fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
> -					GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
> -		if (!fsl_desc->tcd[i].vtcd)
> -			goto err;
> -	}
> -	return fsl_desc;
> -
> -err:
> -	while (--i >= 0)
> -		dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
> -				fsl_desc->tcd[i].ptcd);
> -	kfree(fsl_desc);
> -	return NULL;
> -}
> -
> -static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
> -		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
> -		size_t period_len, enum dma_transfer_direction direction,
> -		unsigned long flags)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	struct fsl_edma_desc *fsl_desc;
> -	dma_addr_t dma_buf_next;
> -	int sg_len, i;
> -	u32 src_addr, dst_addr, last_sg, nbytes;
> -	u16 soff, doff, iter;
> -
> -	if (!is_slave_direction(fsl_chan->fsc.dir))
> -		return NULL;
> -
> -	sg_len = buf_len / period_len;
> -	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> -	if (!fsl_desc)
> -		return NULL;
> -	fsl_desc->iscyclic = true;
> -
> -	dma_buf_next = dma_addr;
> -	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> -	iter = period_len / nbytes;
> -
> -	for (i = 0; i < sg_len; i++) {
> -		if (dma_buf_next >= dma_addr + buf_len)
> -			dma_buf_next = dma_addr;
> -
> -		/* get next sg's physical address */
> -		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
> -
> -		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
> -			src_addr = dma_buf_next;
> -			dst_addr = fsl_chan->fsc.dev_addr;
> -			soff = fsl_chan->fsc.addr_width;
> -			doff = 0;
> -		} else {
> -			src_addr = fsl_chan->fsc.dev_addr;
> -			dst_addr = dma_buf_next;
> -			soff = 0;
> -			doff = fsl_chan->fsc.addr_width;
> -		}
> -
> -		fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
> -				  fsl_chan->fsc.attr, soff, nbytes, 0, iter,
> -				  iter, doff, last_sg, true, false, true);
> -		dma_buf_next += period_len;
> -	}
> -
> -	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
> -}
> -
> -static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
> -		struct dma_chan *chan, struct scatterlist *sgl,
> -		unsigned int sg_len, enum dma_transfer_direction direction,
> -		unsigned long flags, void *context)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	struct fsl_edma_desc *fsl_desc;
> -	struct scatterlist *sg;
> -	u32 src_addr, dst_addr, last_sg, nbytes;
> -	u16 soff, doff, iter;
> -	int i;
> -
> -	if (!is_slave_direction(fsl_chan->fsc.dir))
> -		return NULL;
> -
> -	fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> -	if (!fsl_desc)
> -		return NULL;
> -	fsl_desc->iscyclic = false;
> -
> -	nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> -	for_each_sg(sgl, sg, sg_len, i) {
> -		/* get next sg's physical address */
> -		last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
> -
> -		if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
> -			src_addr = sg_dma_address(sg);
> -			dst_addr = fsl_chan->fsc.dev_addr;
> -			soff = fsl_chan->fsc.addr_width;
> -			doff = 0;
> -		} else {
> -			src_addr = fsl_chan->fsc.dev_addr;
> -			dst_addr = sg_dma_address(sg);
> -			soff = 0;
> -			doff = fsl_chan->fsc.addr_width;
> -		}
> -
> -		iter = sg_dma_len(sg) / nbytes;
> -		if (i < sg_len - 1) {
> -			last_sg = fsl_desc->tcd[(i + 1)].ptcd;
> -			fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
> -					  dst_addr, fsl_chan->fsc.attr, soff,
> -					  nbytes, 0, iter, iter, doff, last_sg,
> -					  false, false, true);
> -		} else {
> -			last_sg = 0;
> -			fsl_edma_fill_tcd(fsl_desc->tcd[i].vtcd, src_addr,
> -					  dst_addr, fsl_chan->fsc.attr, soff,
> -					  nbytes, 0, iter, iter, doff, last_sg,
> -					  true, true, false);
> -		}
> -	}
> -
> -	return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
> -}
> -
> -static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
> -{
> -	struct virt_dma_desc *vdesc;
> -
> -	vdesc = vchan_next_desc(&fsl_chan->vchan);
> -	if (!vdesc)
> -		return;
> -	fsl_chan->edesc = to_fsl_edma_desc(vdesc);
> -	fsl_edma_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
> -	fsl_edma_enable_request(fsl_chan);
> -	fsl_chan->status = DMA_IN_PROGRESS;
> -	fsl_chan->idle = false;
> -}
> +#include "fsl-edma-common.h"
>  
>  static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
>  {
> @@ -730,25 +93,6 @@ static irqreturn_t fsl_edma_irq_handler(int irq,
> void *dev_id)
>  	return fsl_edma_err_handler(irq, dev_id);
>  }
>  
> -static void fsl_edma_issue_pending(struct dma_chan *chan)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> -
> -	if (unlikely(fsl_chan->pm_state != RUNNING)) {
> -		spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -		/* cannot submit due to suspend */
> -		return;
> -	}
> -
> -	if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
> -		fsl_edma_xfer_desc(fsl_chan);
> -
> -	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -}
> -
>  static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
>  		struct of_dma *ofdma)
>  {
> @@ -781,34 +125,6 @@ static struct dma_chan *fsl_edma_xlate(struct
> of_phandle_args *dma_spec,
>  	return NULL;
>  }
>  
> -static int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -
> -	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
> -				sizeof(struct fsl_edma_hw_tcd),
> -				32, 0);
> -	return 0;
> -}
> -
> -static void fsl_edma_free_chan_resources(struct dma_chan *chan)
> -{
> -	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> -	unsigned long flags;
> -	LIST_HEAD(head);
> -
> -	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
> -	fsl_edma_disable_request(fsl_chan);
> -	fsl_edma_chan_mux(fsl_chan, 0, false);
> -	fsl_chan->edesc = NULL;
> -	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
> -	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
> -
> -	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
> -	dma_pool_destroy(fsl_chan->tcd_pool);
> -	fsl_chan->tcd_pool = NULL;
> -}
> -
>  static int
>  fsl_edma_irq_init(struct platform_device *pdev, struct
> fsl_edma_engine *fsl_edma)
>  {
> @@ -995,17 +311,6 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
> -{
> -	struct fsl_edma_chan *chan, *_chan;
> -
> -	list_for_each_entry_safe(chan, _chan,
> -				&dmadev->channels, vchan.chan.device_node) {
> -		list_del(&chan->vchan.chan.device_node);
> -		tasklet_kill(&chan->vchan.task);
> -	}
> -}
> -
>  static int fsl_edma_remove(struct platform_device *pdev)
>  {
>  	struct device_node *np = pdev->dev.of_node;
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v8,2/3] dmaengine: fsl-edma: add edma version and configurable registers
From: Stefan Agner @ 2018-08-07  8:01 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: vinod.koul, dmaengine, linux-arm-kernel, linux-m68k, krzk

On 03.08.2018 21:32, Angelo Dureghello wrote:
> This patch adds configurable registers (using __iomem addresses)
> to allow the use of fsl-edma-common code with slightly different
> edma module versions, as Vybrid (v1) and ColdFire (v2) are.
> 
> Removal of old membase-referenced registers, amd some fixes on
> macroes are included.

s/amd/and
s/macroes/macros

Also split the macro fixes into a separate commit. We really want one
commit for each change... Its better to have 9 patches which might even
touch the same macros again, but patches which do one logical step.
---
Stefan

> 
> Signed-off-by: Angelo Dureghello <angelo@sysam.it>
> ---
> Changes from v7:
> - patch rewritten from scratch, this patch (2/3) has just been added.
> ---
>  drivers/dma/fsl-edma-common.c | 138 ++++++++++++++++++++++++++--------
>  drivers/dma/fsl-edma-common.h | 115 ++++++++++++++--------------
>  drivers/dma/fsl-edma.c        |  32 ++++----
>  3 files changed, 182 insertions(+), 103 deletions(-)
> 
> diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> index 0ae7094f477a..948a3ee51bbb 100644
> --- a/drivers/dma/fsl-edma-common.c
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -9,6 +9,38 @@
>  
>  #include "fsl-edma-common.h"
>  
> +#define EDMA_CR			0x00
> +#define EDMA_ES			0x04
> +#define EDMA_ERQ		0x0C
> +#define EDMA_EEI		0x14
> +#define EDMA_SERQ		0x1B
> +#define EDMA_CERQ		0x1A
> +#define EDMA_SEEI		0x19
> +#define EDMA_CEEI		0x18
> +#define EDMA_CINT		0x1F
> +#define EDMA_CERR		0x1E
> +#define EDMA_SSRT		0x1D
> +#define EDMA_CDNE		0x1C
> +#define EDMA_INTR		0x24
> +#define EDMA_ERR		0x2C
> +
> +#define EDMA64_ERQH		0x08
> +#define EDMA64_EEIH		0x10
> +#define EDMA64_SERQ		0x18
> +#define EDMA64_CERQ		0x19
> +#define EDMA64_SEEI		0x1a
> +#define EDMA64_CEEI		0x1b
> +#define EDMA64_CINT		0x1c
> +#define EDMA64_CERR		0x1d
> +#define EDMA64_SSRT		0x1e
> +#define EDMA64_CDNE		0x1f
> +#define EDMA64_INTH		0x20
> +#define EDMA64_INTL		0x24
> +#define EDMA64_ERRH		0x28
> +#define EDMA64_ERRL		0x2c
> +
> +#define EDMA_TCD		0x1000
> +
>  /*
>   * R/W functions for big- or little-endian registers:
>   * The eDMA controller's endian is independent of the CPU core's endian.
> @@ -67,20 +99,20 @@ EXPORT_SYMBOL_GPL(to_fsl_edma_desc);
>  
>  static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
>  {
> -	void __iomem *addr = fsl_chan->edma->membase;
> +	struct edma_regs *regs = &fsl_chan->edma->regs;
>  	u32 ch = fsl_chan->vchan.chan.chan_id;
>  
> -	edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
> -	edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
> +	edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
> +	edma_writeb(fsl_chan->edma, ch, regs->serq);
>  }
>  
>  void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
>  {
> -	void __iomem *addr = fsl_chan->edma->membase;
> +	struct edma_regs *regs = &fsl_chan->edma->regs;
>  	u32 ch = fsl_chan->vchan.chan.chan_id;
>  
> -	edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
> -	edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
> +	edma_writeb(fsl_chan->edma, ch, regs->cerq);
> +	edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
>  }
>  EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
>  
> @@ -208,7 +240,7 @@ static size_t fsl_edma_desc_residue(struct
> fsl_edma_chan *fsl_chan,
>  		struct virt_dma_desc *vdesc, bool in_progress)
>  {
>  	struct fsl_edma_desc *edesc = fsl_chan->edesc;
> -	void __iomem *addr = fsl_chan->edma->membase;
> +	struct edma_regs *regs = &fsl_chan->edma->regs;
>  	u32 ch = fsl_chan->vchan.chan.chan_id;
>  	enum dma_transfer_direction dir = fsl_chan->fsc.dir;
>  	dma_addr_t cur_addr, dma_addr;
> @@ -224,11 +256,9 @@ static size_t fsl_edma_desc_residue(struct
> fsl_edma_chan *fsl_chan,
>  		return len;
>  
>  	if (dir == DMA_MEM_TO_DEV)
> -		cur_addr = edma_readl(
> -			fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
> +		cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].saddr);
>  	else
> -		cur_addr = edma_readl(
> -			fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
> +		cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].daddr);
>  
>  	/* figure out the finished and calculate the residue */
>  	for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
> @@ -285,7 +315,7 @@ static void fsl_edma_set_tcd_regs(struct
> fsl_edma_chan *fsl_chan,
>  				  struct fsl_edma_hw_tcd *tcd)
>  {
>  	struct fsl_edma_engine *edma = fsl_chan->edma;
> -	void __iomem *addr = fsl_chan->edma->membase;
> +	struct edma_regs *regs = &fsl_chan->edma->regs;
>  	u32 ch = fsl_chan->vchan.chan.chan_id;
>  
>  	/*
> @@ -293,24 +323,24 @@ static void fsl_edma_set_tcd_regs(struct
> fsl_edma_chan *fsl_chan,
>  	 * endian format. However, we need to load the TCD registers in
>  	 * big- or little-endian obeying the eDMA engine model endian.
>  	 */
> -	edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
> -	edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
> -	edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
> +	edma_writew(edma, 0,  &regs->tcd[ch].csr);
> +	edma_writel(edma, le32_to_cpu(tcd->saddr), &regs->tcd[ch].saddr);
> +	edma_writel(edma, le32_to_cpu(tcd->daddr), &regs->tcd[ch].daddr);
>  
> -	edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
> -	edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
> +	edma_writew(edma, le16_to_cpu(tcd->attr), &regs->tcd[ch].attr);
> +	edma_writew(edma, le16_to_cpu(tcd->soff), &regs->tcd[ch].soff);
>  
> -	edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
> -	edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
> +	edma_writel(edma, le32_to_cpu(tcd->nbytes), &regs->tcd[ch].nbytes);
> +	edma_writel(edma, le32_to_cpu(tcd->slast), &regs->tcd[ch].slast);
>  
> -	edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
> -	edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
> -	edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
> +	edma_writew(edma, le16_to_cpu(tcd->citer), &regs->tcd[ch].citer);
> +	edma_writew(edma, le16_to_cpu(tcd->biter), &regs->tcd[ch].biter);
> +	edma_writew(edma, le16_to_cpu(tcd->doff), &regs->tcd[ch].doff);
>  
> -	edma_writel(edma,
> -		    le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
> +	edma_writel(edma, le32_to_cpu(tcd->dlast_sga),
> +			&regs->tcd[ch].dlast_sga);
>  
> -	edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
> +	edma_writew(edma, le16_to_cpu(tcd->csr), &regs->tcd[ch].csr);
>  }
>  
>  static inline
> @@ -332,15 +362,15 @@ void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd
> *tcd, u32 src, u32 dst,
>  
>  	tcd->attr = cpu_to_le16(attr);
>  
> -	tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
> +	tcd->soff = cpu_to_le16(soff);
>  
> -	tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
> -	tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
> +	tcd->nbytes = cpu_to_le32(nbytes);
> +	tcd->slast = cpu_to_le32(slast);
>  
>  	tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
> -	tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
> +	tcd->doff = cpu_to_le16(doff);
>  
> -	tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
> +	tcd->dlast_sga = cpu_to_le32(dlast_sga);
>  
>  	tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
>  	if (major_int)
> @@ -573,4 +603,52 @@ void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
>  }
>  EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan);
>  
> +/*
> + * On the 32 channels Vybrid/mpc577x edma version (here called "v1"),
> + * register offsets are different compared to ColdFire mcf5441x 64 channels
> + * edma (here called "v2").
> + *
> + * This function sets up register offsets as per proper declared version
> + * so must be called in xxx_edma_probe() just after setting the
> + * edma "version" and "membase" appropriately.
> + */
> +void fsl_edma_setup_regs(struct fsl_edma_engine *edma)
> +{
> +	edma->regs.cr = edma->membase + EDMA_CR;
> +	edma->regs.es = edma->membase + EDMA_ES;
> +	edma->regs.erql = edma->membase + EDMA_ERQ;
> +	edma->regs.eeil = edma->membase + EDMA_EEI;
> +
> +	edma->regs.serq = edma->membase + ((edma->version == v1) ?
> +			EDMA_SERQ : EDMA64_SERQ);
> +	edma->regs.cerq = edma->membase + ((edma->version == v1) ?
> +			EDMA_CERQ : EDMA64_CERQ);
> +	edma->regs.seei = edma->membase + ((edma->version == v1) ?
> +			EDMA_SEEI : EDMA64_SEEI);
> +	edma->regs.ceei = edma->membase + ((edma->version == v1) ?
> +			EDMA_CEEI : EDMA64_CEEI);
> +	edma->regs.cint = edma->membase + ((edma->version == v1) ?
> +			EDMA_CINT : EDMA64_CINT);
> +	edma->regs.cerr = edma->membase + ((edma->version == v1) ?
> +			EDMA_CERR : EDMA64_CERR);
> +	edma->regs.ssrt = edma->membase + ((edma->version == v1) ?
> +			EDMA_SSRT : EDMA64_SSRT);
> +	edma->regs.cdne = edma->membase + ((edma->version == v1) ?
> +			EDMA_CDNE : EDMA64_CDNE);
> +	edma->regs.intl = edma->membase + ((edma->version == v1) ?
> +			EDMA_INTR : EDMA64_INTL);
> +	edma->regs.errl = edma->membase + ((edma->version == v1) ?
> +			EDMA_ERR : EDMA64_ERRL);
> +
> +	if (edma->version == v2) {
> +		edma->regs.erqh = edma->membase + EDMA64_ERQH;
> +		edma->regs.eeih = edma->membase + EDMA64_EEIH;
> +		edma->regs.errh = edma->membase + EDMA64_ERRH;
> +		edma->regs.inth = edma->membase + EDMA64_INTH;
> +	}
> +
> +	edma->regs.tcd = edma->membase + EDMA_TCD;
> +}
> +EXPORT_SYMBOL_GPL(fsl_edma_setup_regs);
> +
>  MODULE_LICENSE("GPL v2");
> diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
> index f3ea68e15b23..7a9231e7639f 100644
> --- a/drivers/dma/fsl-edma-common.h
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -8,35 +8,6 @@
>  
>  #include "virt-dma.h"
>  
> -#define EDMA_CR			0x00
> -#define EDMA_ES			0x04
> -#define EDMA_ERQ		0x0C
> -#define EDMA_EEI		0x14
> -#define EDMA_SERQ		0x1B
> -#define EDMA_CERQ		0x1A
> -#define EDMA_SEEI		0x19
> -#define EDMA_CEEI		0x18
> -#define EDMA_CINT		0x1F
> -#define EDMA_CERR		0x1E
> -#define EDMA_SSRT		0x1D
> -#define EDMA_CDNE		0x1C
> -#define EDMA_INTR		0x24
> -#define EDMA_ERR		0x2C
> -
> -#define EDMA_TCD_SADDR(x)	(0x1000 + 32 * (x))
> -#define EDMA_TCD_SOFF(x)	(0x1004 + 32 * (x))
> -#define EDMA_TCD_ATTR(x)	(0x1006 + 32 * (x))
> -#define EDMA_TCD_NBYTES(x)	(0x1008 + 32 * (x))
> -#define EDMA_TCD_SLAST(x)	(0x100C + 32 * (x))
> -#define EDMA_TCD_DADDR(x)	(0x1010 + 32 * (x))
> -#define EDMA_TCD_DOFF(x)	(0x1014 + 32 * (x))
> -#define EDMA_TCD_CITER_ELINK(x)	(0x1016 + 32 * (x))
> -#define EDMA_TCD_CITER(x)	(0x1016 + 32 * (x))
> -#define EDMA_TCD_DLAST_SGA(x)	(0x1018 + 32 * (x))
> -#define EDMA_TCD_CSR(x)		(0x101C + 32 * (x))
> -#define EDMA_TCD_BITER_ELINK(x)	(0x101E + 32 * (x))
> -#define EDMA_TCD_BITER(x)	(0x101E + 32 * (x))
> -
>  #define EDMA_CR_EDBG		BIT(1)
>  #define EDMA_CR_ERCA		BIT(2)
>  #define EDMA_CR_ERGA		BIT(3)
> @@ -47,34 +18,29 @@
>  #define EDMA_CR_ECX		BIT(16)
>  #define EDMA_CR_CX		BIT(17)
>  
> -#define EDMA_SEEI_SEEI(x)	((x) & 0x1F)
> -#define EDMA_CEEI_CEEI(x)	((x) & 0x1F)
> -#define EDMA_CINT_CINT(x)	((x) & 0x1F)
> -#define EDMA_CERR_CERR(x)	((x) & 0x1F)
> -
> -#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & 0x0007))
> -#define EDMA_TCD_ATTR_DMOD(x)		(((x) & 0x001F) << 3)
> -#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & 0x0007) << 8)
> -#define EDMA_TCD_ATTR_SMOD(x)		(((x) & 0x001F) << 11)
> -#define EDMA_TCD_ATTR_SSIZE_8BIT	(0x0000)
> -#define EDMA_TCD_ATTR_SSIZE_16BIT	(0x0100)
> -#define EDMA_TCD_ATTR_SSIZE_32BIT	(0x0200)
> -#define EDMA_TCD_ATTR_SSIZE_64BIT	(0x0300)
> -#define EDMA_TCD_ATTR_SSIZE_32BYTE	(0x0500)
> -#define EDMA_TCD_ATTR_DSIZE_8BIT	(0x0000)
> -#define EDMA_TCD_ATTR_DSIZE_16BIT	(0x0001)
> -#define EDMA_TCD_ATTR_DSIZE_32BIT	(0x0002)
> -#define EDMA_TCD_ATTR_DSIZE_64BIT	(0x0003)
> -#define EDMA_TCD_ATTR_DSIZE_32BYTE	(0x0005)
> -
> -#define EDMA_TCD_SOFF_SOFF(x)		(x)
> -#define EDMA_TCD_NBYTES_NBYTES(x)	(x)
> -#define EDMA_TCD_SLAST_SLAST(x)		(x)
> -#define EDMA_TCD_DADDR_DADDR(x)		(x)
> -#define EDMA_TCD_CITER_CITER(x)		((x) & 0x7FFF)
> -#define EDMA_TCD_DOFF_DOFF(x)		(x)
> -#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)	(x)
> -#define EDMA_TCD_BITER_BITER(x)		((x) & 0x7FFF)
> +#define EDMA_SEEI_SEEI(x)	((x) & GENMASK(4, 0))
> +#define EDMA_CEEI_CEEI(x)	((x) & GENMASK(4, 0))
> +#define EDMA_CINT_CINT(x)	((x) & GENMASK(4, 0))
> +#define EDMA_CERR_CERR(x)	((x) & GENMASK(4, 0))
> +
> +#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & GENMASK(2, 0)))
> +#define EDMA_TCD_ATTR_DMOD(x)		(((x) & GENMASK(4, 0)) << 3)
> +#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & GENMASK(2, 0)) << 8)
> +#define EDMA_TCD_ATTR_SMOD(x)		(((x) & GENMASK(4, 0)) << 11)
> +
> +#define EDMA_TCD_ATTR_DSIZE_8BIT	0
> +#define EDMA_TCD_ATTR_DSIZE_16BIT	BIT(0)
> +#define EDMA_TCD_ATTR_DSIZE_32BIT	BIT(1)
> +#define EDMA_TCD_ATTR_DSIZE_64BIT	(BIT(0) | BIT(1))
> +#define EDMA_TCD_ATTR_DSIZE_32BYTE	(BIT(3) | BIT(0))
> +#define EDMA_TCD_ATTR_SSIZE_8BIT	0
> +#define EDMA_TCD_ATTR_SSIZE_16BIT	(EDMA_TCD_ATTR_DSIZE_16BIT << 8)
> +#define EDMA_TCD_ATTR_SSIZE_32BIT	(EDMA_TCD_ATTR_DSIZE_32BIT << 8)
> +#define EDMA_TCD_ATTR_SSIZE_64BIT	(EDMA_TCD_ATTR_DSIZE_64BIT << 8)
> +#define EDMA_TCD_ATTR_SSIZE_32BYTE	(EDMA_TCD_ATTR_DSIZE_32BYTE << 8)
> +
> +#define EDMA_TCD_CITER_CITER(x)		((x) & GENMASK(14, 0))
> +#define EDMA_TCD_BITER_BITER(x)		((x) & GENMASK(14, 0))
>  
>  #define EDMA_TCD_CSR_START		BIT(0)
>  #define EDMA_TCD_CSR_INT_MAJOR		BIT(1)
> @@ -87,7 +53,7 @@
>  
>  #define EDMAMUX_CHCFG_DIS		0x0
>  #define EDMAMUX_CHCFG_ENBL		0x80
> -#define EDMAMUX_CHCFG_SOURCE(n)		((n) & 0x3F)
> +#define EDMAMUX_CHCFG_SOURCE(n)		((n) & GENMASK(6, 0))
>  
>  #define DMAMUX_NR	2
>  
> @@ -114,6 +80,31 @@ struct fsl_edma_hw_tcd {
>  	__le16	biter;
>  };
>  
> +/*
> + * This are iomem pointers, for both v32 and v64.
> + */
> +struct edma_regs {
> +	void __iomem *cr;
> +	void __iomem *es;
> +	void __iomem *erqh;
> +	void __iomem *erql;	/* aka erq on v32 */
> +	void __iomem *eeih;
> +	void __iomem *eeil;	/* aka eei on v32 */
> +	void __iomem *seei;
> +	void __iomem *ceei;
> +	void __iomem *serq;
> +	void __iomem *cerq;
> +	void __iomem *cint;
> +	void __iomem *cerr;
> +	void __iomem *ssrt;
> +	void __iomem *cdne;
> +	void __iomem *inth;
> +	void __iomem *intl;
> +	void __iomem *errh;
> +	void __iomem *errl;
> +	struct fsl_edma_hw_tcd __iomem *tcd;
> +};
> +
>  struct fsl_edma_sw_tcd {
>  	dma_addr_t			ptcd;
>  	struct fsl_edma_hw_tcd		*vtcd;
> @@ -147,6 +138,11 @@ struct fsl_edma_desc {
>  	struct fsl_edma_sw_tcd		tcd[];
>  };
>  
> +enum edma_version {
> +	v1, /* 32ch, Vybdir, mpc57x, etc */
> +	v2, /* 64ch Coldfire */
> +};
> +
>  struct fsl_edma_engine {
>  	struct dma_device	dma_dev;
>  	void __iomem		*membase;
> @@ -157,6 +153,8 @@ struct fsl_edma_engine {
>  	int			txirq;
>  	int			errirq;
>  	bool			big_endian;
> +	enum edma_version	version;
> +	struct edma_regs	regs;
>  	struct fsl_edma_chan	chans[];
>  };
>  
> @@ -192,5 +190,6 @@ void fsl_edma_issue_pending(struct dma_chan *chan);
>  int fsl_edma_alloc_chan_resources(struct dma_chan *chan);
>  void fsl_edma_free_chan_resources(struct dma_chan *chan);
>  void fsl_edma_cleanup_vchan(struct dma_device *dmadev);
> +void fsl_edma_setup_regs(struct fsl_edma_engine *edma);
>  
>  #endif /* _FSL_EDMA_COMMON_H_ */
> diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
> index 337ad0c0ea78..34d70112fcc9 100644
> --- a/drivers/dma/fsl-edma.c
> +++ b/drivers/dma/fsl-edma.c
> @@ -28,19 +28,16 @@ static irqreturn_t fsl_edma_tx_handler(int irq,
> void *dev_id)
>  {
>  	struct fsl_edma_engine *fsl_edma = dev_id;
>  	unsigned int intr, ch;
> -	void __iomem *base_addr;
> +	struct edma_regs *regs = &fsl_edma->regs;
>  	struct fsl_edma_chan *fsl_chan;
>  
> -	base_addr = fsl_edma->membase;
> -
> -	intr = edma_readl(fsl_edma, base_addr + EDMA_INTR);
> +	intr = edma_readl(fsl_edma, regs->intl);
>  	if (!intr)
>  		return IRQ_NONE;
>  
>  	for (ch = 0; ch < fsl_edma->n_chans; ch++) {
>  		if (intr & (0x1 << ch)) {
> -			edma_writeb(fsl_edma, EDMA_CINT_CINT(ch),
> -				base_addr + EDMA_CINT);
> +			edma_writeb(fsl_edma, EDMA_CINT_CINT(ch), regs->cint);
>  
>  			fsl_chan = &fsl_edma->chans[ch];
>  
> @@ -68,16 +65,16 @@ static irqreturn_t fsl_edma_err_handler(int irq,
> void *dev_id)
>  {
>  	struct fsl_edma_engine *fsl_edma = dev_id;
>  	unsigned int err, ch;
> +	struct edma_regs *regs = &fsl_edma->regs;
>  
> -	err = edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERR);
> +	err = edma_readl(fsl_edma, regs->errl);
>  	if (!err)
>  		return IRQ_NONE;
>  
>  	for (ch = 0; ch < fsl_edma->n_chans; ch++) {
>  		if (err & (0x1 << ch)) {
>  			fsl_edma_disable_request(&fsl_edma->chans[ch]);
> -			edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
> -				fsl_edma->membase + EDMA_CERR);
> +			edma_writeb(fsl_edma, EDMA_CERR_CERR(ch), regs->cerr);
>  			fsl_edma->chans[ch].status = DMA_ERROR;
>  			fsl_edma->chans[ch].idle = true;
>  		}
> @@ -192,6 +189,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  	struct device_node *np = pdev->dev.of_node;
>  	struct fsl_edma_engine *fsl_edma;
>  	struct fsl_edma_chan *fsl_chan;
> +	struct edma_regs *regs;
>  	struct resource *res;
>  	int len, chans;
>  	int ret, i;
> @@ -207,6 +205,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  	if (!fsl_edma)
>  		return -ENOMEM;
>  
> +	fsl_edma->version = v1;
>  	fsl_edma->n_chans = chans;
>  	mutex_init(&fsl_edma->fsl_edma_mutex);
>  
> @@ -215,6 +214,9 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  	if (IS_ERR(fsl_edma->membase))
>  		return PTR_ERR(fsl_edma->membase);
>  
> +	fsl_edma_setup_regs(fsl_edma);
> +	regs = &fsl_edma->regs;
> +
>  	for (i = 0; i < DMAMUX_NR; i++) {
>  		char clkname[32];
>  
> @@ -255,11 +257,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  		fsl_chan->vchan.desc_free = fsl_edma_free_desc;
>  		vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
>  
> -		edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
> +		edma_writew(fsl_edma, 0x0, &regs->tcd[i].csr);
>  		fsl_edma_chan_mux(fsl_chan, 0, false);
>  	}
>  
> -	edma_writel(fsl_edma, ~0, fsl_edma->membase + EDMA_INTR);
> +	edma_writel(fsl_edma, ~0, regs->intl);
>  	ret = fsl_edma_irq_init(pdev, fsl_edma);
>  	if (ret)
>  		return ret;
> @@ -306,7 +308,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
>  	}
>  
>  	/* enable round robin arbitration */
> -	edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, fsl_edma->membase
> + EDMA_CR);
> +	edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
>  
>  	return 0;
>  }
> @@ -353,18 +355,18 @@ static int fsl_edma_resume_early(struct device *dev)
>  {
>  	struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
>  	struct fsl_edma_chan *fsl_chan;
> +	struct edma_regs *regs = &fsl_edma->regs;
>  	int i;
>  
>  	for (i = 0; i < fsl_edma->n_chans; i++) {
>  		fsl_chan = &fsl_edma->chans[i];
>  		fsl_chan->pm_state = RUNNING;
> -		edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
> +		edma_writew(fsl_edma, 0x0, &regs->tcd[i].csr);
>  		if (fsl_chan->slave_id != 0)
>  			fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true);
>  	}
>  
> -	edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA,
> -			fsl_edma->membase + EDMA_CR);
> +	edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
>  
>  	return 0;
>  }
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [09/46] dmaengine: cppi41: use dmaenginem_async_device_register to simplify the code
From: Huang Shijie @ 2018-08-07  7:16 UTC (permalink / raw)
  To: Peter Ujfalusi
  Cc: Alexandre Bailon, Tony Lindgren, vkoul, dmaengine, linux-kernel,
	dave.jiang, radhey.shyam.pandey, appana.durga.rao, jmkrzyszt,
	gomonovych, keescook, horms+renesas, geert+renesas, shawnguo,
	michal.simek, baohua, ludovic.desroches, linus.walleij,
	david.brown

On Tue, Aug 07, 2018 at 10:01:47AM +0300, Peter Ujfalusi wrote:
> Hi,
> 
> On 2018-08-06 06:28, Huang Shijie wrote:
> It might be only me, but I like to keep the resource teardown in a
> reverse order of their creation. If everything is devm then it is granted.
Yes.

If everything is devm then it is granted..

> 
> In case of cppi4 it looks safe after reading in to the DMAengine core,
> module core and platform core code.
> 
> But does the removed three lines worth over the clarity of how the
> module removal is proceeding?
Please keep the driver as it is if you like the traditional way. :)

The DMA driver's maintainer has the right to decide whether
to use the dmaenginem_async_device_register or not.

Thanks
Huang Shijie
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [09/46] dmaengine: cppi41: use dmaenginem_async_device_register to simplify the code
From: Peter Ujfalusi @ 2018-08-07  7:01 UTC (permalink / raw)
  To: Huang Shijie, Alexandre Bailon, Tony Lindgren
  Cc: vkoul, dmaengine, linux-kernel, dave.jiang, radhey.shyam.pandey,
	appana.durga.rao, jmkrzyszt, gomonovych, keescook, horms+renesas,
	geert+renesas, shawnguo, baoyou.xie, michal.simek, baohua,
	ludovic.desroches, linus.walleij, david.brown

Hi,

On 2018-08-06 06:28, Huang Shijie wrote:
> On Fri, Aug 03, 2018 at 10:55:25AM +0300, Peter Ujfalusi wrote:
>>
>>
>> On 2018-08-03 10:19, Huang Shijie wrote:
>>> Use dmaenginem_async_device_register to simplify the code:
>>>    remove dma_async_device_unregister
>>>
>>> Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
>>> ---
>>>  drivers/dma/ti/cppi41.c | 7 ++-----
>>>  1 file changed, 2 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/dma/ti/cppi41.c b/drivers/dma/ti/cppi41.c
>>> index 1497da367710..d2998a19ed2e 100644
>>> --- a/drivers/dma/ti/cppi41.c
>>> +++ b/drivers/dma/ti/cppi41.c
>>> @@ -1096,21 +1096,19 @@ static int cppi41_dma_probe(struct platform_device *pdev)
>>>  		goto err_chans;
>>>  	cdd->irq = irq;
>>>  
>>> -	ret = dma_async_device_register(&cdd->ddev);
>>> +	ret = dmaenginem_async_device_register(&cdd->ddev);
>>>  	if (ret)
>>>  		goto err_chans;
>>>  
>>>  	ret = of_dma_controller_register(dev->of_node,
>>>  			cppi41_dma_xlate, &cpp41_dma_info);
>>>  	if (ret)
>>> -		goto err_of;
>>> +		goto err_chans;
>>>  
>>>  	pm_runtime_mark_last_busy(dev);
>>>  	pm_runtime_put_autosuspend(dev);
>>>  
>>>  	return 0;
>>> -err_of:
>>> -	dma_async_device_unregister(&cdd->ddev);
>>>  err_chans:
>>>  	deinit_cppi41(dev, cdd);
>>>  err_init_cppi:
>>> @@ -1132,7 +1130,6 @@ static int cppi41_dma_remove(struct platform_device *pdev)
>>>  		dev_err(&pdev->dev, "%s could not pm_runtime_get: %i\n",
>>>  			__func__, error);
>>>  	of_dma_controller_free(pdev->dev.of_node);
>>> -	dma_async_device_unregister(&cdd->ddev);
>>
>> If I read the code right then this is not safe.
> I read the code again, and find it is okay.
> 
>> We would have deinitalized cppi41 driver which is not functional, but we
>> will still have the dma device registered and if a channel is requested
>> we will have kernel crash.
> We cannot succeed to request a channel when the drv->remove() is called.
> 
> Please see __device_release_driver:
>   ---------------------------------------------------------------------
> 		if (dev->bus && dev->bus->remove)
> 			dev->bus->remove(dev);
> 		else if (drv->remove)
> 			drv->remove(dev);
> 
> 		device_links_driver_cleanup(dev);
> 		dma_deconfigure(dev);
> 
> 		devres_release_all(dev);    ============> Devres release
>   ---------------------------------------------------------------------
> 
> For the DMA engine driver, there is only one case which will calls drv->remove():
>         Use the rmmod(or modprobe -r).
> 
> We do not use the device_link_add API for DMA engines.
> And we not manually call the device_release_driver() for DMA engines.
> 
> But when we use the rmmod, the module state will be MODULE_STATE_GOING.
> In the find_candidate(), dma_chan_get() will fail.
> And we cannot get a channel.
> 
> Please correct me if I am wrong :)

You are perfectly right.

It might be only me, but I like to keep the resource teardown in a
reverse order of their creation. If everything is devm then it is granted.

In case of cppi4 it looks safe after reading in to the DMAengine core,
module core and platform core code.

But does the removed three lines worth over the clarity of how the
module removal is proceeding?

Alexandre and Tony put lots of effort to the cppi4 driver, I let them
decide.

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v2,7/9] dmaengine: pxa_dma: use dmaenginem_async_device_register to simplify the code
From: Robert Jarzmik @ 2018-08-07  6:37 UTC (permalink / raw)
  To: Huang Shijie
  Cc: vkoul, dan.j.williams, Zubair.Kakakhel, daniel, haojian.zhuang,
	patrice.chotard, linus.walleij, mcoquelin.stm32, alexandre.torgue,
	Eugeniy.Paltsev, colin.king, dmaengine, linux-arm-kernel

Huang Shijie <sjhuang@iluvatar.ai> writes:

> Use dmaenginem_async_device_register to simplify the code:
> 	remove dma_async_device_unregister.
>
> Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>

^ permalink raw reply

* [v2,9/9] dmaengine: add COMPILE_TEST for the drivers
From: Robert Jarzmik @ 2018-08-07  6:32 UTC (permalink / raw)
  To: Huang Shijie
  Cc: vkoul, dan.j.williams, Zubair.Kakakhel, daniel, haojian.zhuang,
	patrice.chotard, linus.walleij, mcoquelin.stm32, alexandre.torgue,
	Eugeniy.Paltsev, colin.king, dmaengine, linux-arm-kernel

Huang Shijie <sjhuang@iluvatar.ai> writes:

> We can do the compiling test with COMPILE_TEST.
> This patch adds the COMPILE_TEST for the drivers.
>
> Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
For pxa :
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>

Cheers.
---
Robert
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v8,1/3] dmaengine: fsl-edma: extract common fsl-edma code (no changes in behavior intended)
From: Krzysztof Kozlowski @ 2018-08-07  6:02 UTC (permalink / raw)
  To: Angelo Dureghello
  Cc: vinod.koul, dmaengine, linux-arm-kernel, linux-m68k, Stefan Agner

On 6 August 2018 at 22:40, Angelo Dureghello <angelo@sysam.it> wrote:
> Hi Krzysztof,
>
> On Mon, Aug 06, 2018 at 09:43:42AM +0200, Krzysztof Kozlowski wrote:
>> On 3 August 2018 at 21:32, Angelo Dureghello <angelo@sysam.it> wrote:
>> > This patch adds a new fsl-edma-common module to allow new
>> > mcf-edma module code to use most of the fsl-edma code.
>> >
>> > Signed-off-by: Angelo Dureghello <angelo@sysam.it>
>> > ---
>> > Changes for v2:
>> > - patch splitted into 4
>> > - add mcf-edma as minimal different parts from fsl-edma
>> >
>> > Changes for v3:
>> > none
>> >
>> > Changes for v4:
>> > - patch simplified from 4/4 into 2/2
>> > - collecting all the mcf-edma-related changes
>> >
>> > Changes for v5:
>> > none
>> >
>> > Changes for v6:
>> > - adjusted comment header
>> > - fixed bit shift with BIT()
>> > - we need to free the interrupts at remove(), so removed all devm_
>> >   interrupt related calls
>> >
>> > Changes for v7:
>> > none
>> >
>> > Changes for v8:
>> > - patch rewritten from scratch, splitted into 3, common code isolated,
>> >   minimal changes from the original Freescale code have been done.
>> >   The patch has been tested with both Iris + Colibri Vybrid VF50 and
>> >   stmark2/mcf54415 Coldfire boards.
>> > ---
>> >  drivers/dma/Makefile          |   2 +-
>> >  drivers/dma/fsl-edma-common.c | 576 ++++++++++++++++++++++++++++
>> >  drivers/dma/fsl-edma-common.h | 196 ++++++++++
>> >  drivers/dma/fsl-edma.c        | 697 +---------------------------------
>> >  4 files changed, 774 insertions(+), 697 deletions(-)
>> >  create mode 100644 drivers/dma/fsl-edma-common.c
>> >  create mode 100644 drivers/dma/fsl-edma-common.h
>> >
>> > diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
>> > index 203a99d68315..66022f59fca4 100644
>> > --- a/drivers/dma/Makefile
>> > +++ b/drivers/dma/Makefile
>> > @@ -31,7 +31,7 @@ obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
>> >  obj-$(CONFIG_DW_DMAC_CORE) += dw/
>> >  obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
>> >  obj-$(CONFIG_FSL_DMA) += fsldma.o
>> > -obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
>> > +obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
>> >  obj-$(CONFIG_FSL_RAID) += fsl_raid.o
>> >  obj-$(CONFIG_HSU_DMA) += hsu/
>> >  obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
>> > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
>> > new file mode 100644
>> > index 000000000000..0ae7094f477a
>> > --- /dev/null
>> > +++ b/drivers/dma/fsl-edma-common.c
>> > @@ -0,0 +1,576 @@
>> > +// SPDX-License-Identifier: GPL-2.0
>>
>> You moved code from fsl-edma.c which is licensed on GPL-2.0+. I think
>> that's not allowed as you effectively relicense the work on new
>> license.
>>
> Ok, so if i undestrand, i should change that comment to
> // SPDX-License-Identifier: GPL-2.0+
> Right ?

Yes, GPL-2.0+.

Best regards,
Krzysztof
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v8,3/3] dmaengine: fsl-edma: add ColdFire mcf5441x edma support
From: Angelo Dureghello @ 2018-08-06 21:01 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: vinod.koul, dmaengine, linux-arm-kernel, linux-m68k, Stefan Agner

Hi Krzysztof,

On Mon, Aug 06, 2018 at 10:09:08AM +0200, Krzysztof Kozlowski wrote:
> On 3 August 2018 at 21:32, Angelo Dureghello <angelo@sysam.it> wrote:
> > This patch adds support for ColdFire mcf5441x-family edma
> > module.
> >
> > The ColdFire edma module is slightly different from fsl-edma,
> > so a new driver is added. But most of the code is common
> > between fsl-edma and mcf-edma so it has been collected into a
> > separate common module fsl-edma-common (patch 1/3).
> >
> > Signed-off-by: Angelo Dureghello <angelo@sysam.it>
> > ---
> > Changes for v7:
> > - patch rewritten from scratch, this patch (3/3) has just been added.
> > ---
> >  drivers/dma/Kconfig                        |  11 +
> >  drivers/dma/Makefile                       |   1 +
> >  drivers/dma/fsl-edma-common.c              |  24 +-
> >  drivers/dma/mcf-edma.c                     | 315 +++++++++++++++++++++
> >  include/linux/platform_data/dma-mcf-edma.h |  38 +++
> >  5 files changed, 385 insertions(+), 4 deletions(-)
> >  create mode 100644 drivers/dma/mcf-edma.c
> >  create mode 100644 include/linux/platform_data/dma-mcf-edma.h
> >
> > diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> > index ca1680afa20a..b45008e9c7e9 100644
> > --- a/drivers/dma/Kconfig
> > +++ b/drivers/dma/Kconfig
> > @@ -320,6 +320,17 @@ config LPC18XX_DMAMUX
> >           Enable support for DMA on NXP LPC18xx/43xx platforms
> >           with PL080 and multiplexed DMA request lines.
> >
> > +config MCF_EDMA
> > +       tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs"
> > +       depends on M5441x
> > +       select DMA_ENGINE
> > +       select DMA_VIRTUAL_CHANNELS
> > +       help
> > +         Support the Freescale ColdFire eDMA engine, 64-channel
> > +         implementation that performs complex data transfers with
> > +         minimal intervention from a host processor.
> > +         This module can be found on Freescale ColdFire mcf5441x SoCs.
> > +
> >  config MMP_PDMA
> >         bool "MMP PDMA support"
> >         depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
> > diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> > index 66022f59fca4..d97f317f4b34 100644
> > --- a/drivers/dma/Makefile
> > +++ b/drivers/dma/Makefile
> > @@ -32,6 +32,7 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw/
> >  obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
> >  obj-$(CONFIG_FSL_DMA) += fsldma.o
> >  obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
> > +obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o
> >  obj-$(CONFIG_FSL_RAID) += fsl_raid.o
> >  obj-$(CONFIG_HSU_DMA) += hsu/
> >  obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
> > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> > index 948a3ee51bbb..5a830a238a0c 100644
> > --- a/drivers/dma/fsl-edma-common.c
> > +++ b/drivers/dma/fsl-edma-common.c
> > @@ -102,8 +102,16 @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
> >         struct edma_regs *regs = &fsl_chan->edma->regs;
> >         u32 ch = fsl_chan->vchan.chan.chan_id;
> >
> > -       edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
> > -       edma_writeb(fsl_chan->edma, ch, regs->serq);
> > +       if (fsl_chan->edma->version == v1) {
> > +               edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
> > +               edma_writeb(fsl_chan->edma, ch, regs->serq);
> > +       } else {
> > +               /* ColdFire is big endian, and accesses natively
> > +                * big endian I/O peripherals
> > +                */
> > +               iowrite8(EDMA_SEEI_SEEI(ch), regs->seei);
> > +               iowrite8(ch, regs->serq);
> > +       }
> >  }
> >
> >  void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
> > @@ -111,8 +119,16 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
> >         struct edma_regs *regs = &fsl_chan->edma->regs;
> >         u32 ch = fsl_chan->vchan.chan.chan_id;
> >
> > -       edma_writeb(fsl_chan->edma, ch, regs->cerq);
> > -       edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
> > +       if (fsl_chan->edma->version == v1) {
> > +               edma_writeb(fsl_chan->edma, ch, regs->cerq);
> > +               edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
> > +       } else {
> > +               /* ColdFire is big endian, and accesses natively
> > +                * big endian I/O peripherals
> > +                */
> > +               iowrite8(ch, regs->cerq);
> > +               iowrite8(EDMA_CEEI_CEEI(ch), regs->ceei);
> > +       }
> >  }
> >  EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
> >
> > diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
> > new file mode 100644
> > index 000000000000..31e5317a8f90
> > --- /dev/null
> > +++ b/drivers/dma/mcf-edma.c
> > @@ -0,0 +1,315 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +//
> > +// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
> 
> Same comment as to 1/3 - if this is derivative work...
> 
Well, in this case the driver is brand new, i maintained the
Freescale Copyright too, since i copied some code from fsl-edma.c.


> > +// Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
> > +
> > +#include <linux/module.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/platform_data/dma-mcf-edma.h>
> > +
> > +#include "fsl-edma-common.h"
> > +
> > +#define EDMA_CHANNELS          64
> > +#define EDMA_MASK_CH(x)                ((x) & GENMASK(5, 0))
> > +
> > +static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
> > +{
> > +       struct fsl_edma_engine *mcf_edma = dev_id;
> > +       struct edma_regs *regs = &mcf_edma->regs;
> > +       unsigned int ch;
> > +       struct fsl_edma_chan *mcf_chan;
> > +       u64 intmap;
> > +
> > +       intmap = ioread32(regs->inth);
> > +       intmap <<= 32;
> > +       intmap |= ioread32(regs->intl);
> > +       if (!intmap)
> > +               return IRQ_NONE;
> > +
> > +       for (ch = 0; ch < mcf_edma->n_chans; ch++) {
> > +               if (intmap & BIT(ch)) {
> > +                       iowrite8(EDMA_MASK_CH(ch), regs->cint);
> > +
> > +                       mcf_chan = &mcf_edma->chans[ch];
> > +
> > +                       spin_lock(&mcf_chan->vchan.lock);
> > +                       if (!mcf_chan->edesc->iscyclic) {
> > +                               list_del(&mcf_chan->edesc->vdesc.node);
> > +                               vchan_cookie_complete(&mcf_chan->edesc->vdesc);
> > +                               mcf_chan->edesc = NULL;
> > +                               mcf_chan->status = DMA_COMPLETE;
> > +                               mcf_chan->idle = true;
> > +                       } else {
> > +                               vchan_cyclic_callback(&mcf_chan->edesc->vdesc);
> > +                       }
> > +
> > +                       if (!mcf_chan->edesc)
> > +                               fsl_edma_xfer_desc(mcf_chan);
> > +
> > +                       spin_unlock(&mcf_chan->vchan.lock);
> > +               }
> > +       }
> > +
> > +       return IRQ_HANDLED;
> > +}
> > +
> > +static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
> > +{
> > +       struct fsl_edma_engine *mcf_edma = dev_id;
> > +       struct edma_regs *regs = &mcf_edma->regs;
> > +       unsigned int err, ch;
> > +
> > +       err = ioread32(regs->errl);
> > +       if (!err)
> > +               return IRQ_NONE;
> > +
> > +       for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
> > +               if (err & BIT(ch)) {
> > +                       fsl_edma_disable_request(&mcf_edma->chans[ch]);
> > +                       iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
> > +                       mcf_edma->chans[ch].status = DMA_ERROR;
> > +                       mcf_edma->chans[ch].idle = true;
> > +               }
> > +       }
> > +
> > +       err = ioread32(regs->errh);
> > +       if (!err)
> > +               return IRQ_NONE;
> > +
> > +       for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
> > +               if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
> > +                       fsl_edma_disable_request(&mcf_edma->chans[ch]);
> > +                       iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
> > +                       mcf_edma->chans[ch].status = DMA_ERROR;
> > +                       mcf_edma->chans[ch].idle = true;
> > +               }
> > +       }
> > +
> > +       return IRQ_HANDLED;
> > +}
> > +
> > +static int mcf_edma_irq_init(struct platform_device *pdev,
> > +                               struct fsl_edma_engine *mcf_edma)
> > +{
> > +       int ret = 0, i;
> > +       struct resource *res;
> > +
> > +       res = platform_get_resource_byname(pdev,
> > +                               IORESOURCE_IRQ, "edma-tx-00-15");
> > +       if (!res)
> > +               return -1;
> > +
> > +       for (ret = 0, i = res->start; i <= res->end; ++i)
> > +               ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
> > +       if (ret)
> > +               return ret;
> > +
> > +       res = platform_get_resource_byname(pdev,
> > +                       IORESOURCE_IRQ, "edma-tx-16-55");
> > +       if (!res)
> > +               return -1;
> > +
> > +       for (ret = 0, i = res->start; i <= res->end; ++i)
> > +               ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
> > +       if (ret != -ENXIO) {
> > +               ret = request_irq(ret, mcf_edma_tx_handler,
> > +                                 0, "eDMA", mcf_edma);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> > +       ret = platform_get_irq_byname(pdev, "edma-err");
> > +       if (ret != -ENXIO) {
> > +               ret = request_irq(ret, mcf_edma_err_handler,
> > +                                 0, "eDMA", mcf_edma);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static void mcf_edma_irq_free(struct platform_device *pdev,
> > +                               struct fsl_edma_engine *mcf_edma)
> > +{
> > +       int irq;
> > +       struct resource *res;
> > +
> > +       res = platform_get_resource_byname(pdev,
> > +                       IORESOURCE_IRQ, "edma-tx-00-15");
> > +       if (res) {
> > +               for (irq = res->start; irq <= res->end; irq++)
> > +                       free_irq(irq, mcf_edma);
> > +       }
> > +
> > +       res = platform_get_resource_byname(pdev,
> > +                       IORESOURCE_IRQ, "edma-tx-16-55");
> > +       if (res) {
> > +               for (irq = res->start; irq <= res->end; irq++)
> > +                       free_irq(irq, mcf_edma);
> > +       }
> > +
> > +       irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
> > +       if (irq != -ENXIO)
> > +               free_irq(irq, mcf_edma);
> > +
> > +       irq = platform_get_irq_byname(pdev, "edma-err");
> > +       if (irq != -ENXIO)
> > +               free_irq(irq, mcf_edma);
> > +}
> > +
> > +static int mcf_edma_probe(struct platform_device *pdev)
> > +{
> > +       struct mcf_edma_platform_data *pdata;
> > +       struct fsl_edma_engine *mcf_edma;
> > +       struct fsl_edma_chan *mcf_chan;
> > +       struct edma_regs *regs;
> > +       struct resource *res;
> > +       int ret, i, len, chans;
> > +
> > +       pdata = dev_get_platdata(&pdev->dev);
> > +       if (!pdata)
> > +               return PTR_ERR(pdata);
> > +
> > +       chans = pdata->dma_channels;
> > +       len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans;
> > +       mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
> > +       if (!mcf_edma)
> > +               return -ENOMEM;
> > +
> > +       mcf_edma->n_chans = chans;
> > +
> > +       /* Set up version for ColdFire edma */
> > +       mcf_edma->version = v2;
> > +       mcf_edma->big_endian = 1;
> > +
> > +       if (!mcf_edma->n_chans) {
> > +               dev_info(&pdev->dev, "setting default channel number to 64");
> > +               mcf_edma->n_chans = 64;
> > +       }
> > +
> > +       mutex_init(&mcf_edma->fsl_edma_mutex);
> > +
> > +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +
> > +       mcf_edma->membase = devm_ioremap_resource(&pdev->dev, res);
> > +       if (IS_ERR(mcf_edma->membase))
> > +               return PTR_ERR(mcf_edma->membase);
> > +
> > +       fsl_edma_setup_regs(mcf_edma);
> > +       regs = &mcf_edma->regs;
> > +
> > +       INIT_LIST_HEAD(&mcf_edma->dma_dev.channels);
> > +       for (i = 0; i < mcf_edma->n_chans; i++) {
> > +               struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i];
> > +
> > +               mcf_chan->edma = mcf_edma;
> > +               mcf_chan->slave_id = i;
> > +               mcf_chan->idle = true;
> > +               mcf_chan->vchan.desc_free = fsl_edma_free_desc;
> > +               vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev);
> > +               iowrite32(0x0, &regs->tcd[i].csr);
> > +       }
> > +
> > +       iowrite32(~0, regs->inth);
> > +       iowrite32(~0, regs->intl);
> > +
> > +       ret = mcf_edma_irq_init(pdev, mcf_edma);
> > +       if (ret)
> > +               return ret;
> > +
> > +       dma_cap_set(DMA_PRIVATE, mcf_edma->dma_dev.cap_mask);
> > +       dma_cap_set(DMA_SLAVE, mcf_edma->dma_dev.cap_mask);
> > +       dma_cap_set(DMA_CYCLIC, mcf_edma->dma_dev.cap_mask);
> > +
> > +       mcf_edma->dma_dev.dev = &pdev->dev;
> > +       mcf_edma->dma_dev.device_alloc_chan_resources =
> > +                       fsl_edma_alloc_chan_resources;
> > +       mcf_edma->dma_dev.device_free_chan_resources =
> > +                       fsl_edma_free_chan_resources;
> > +       mcf_edma->dma_dev.device_config = fsl_edma_slave_config;
> > +       mcf_edma->dma_dev.device_prep_dma_cyclic =
> > +                       fsl_edma_prep_dma_cyclic;
> > +       mcf_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
> > +       mcf_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
> > +       mcf_edma->dma_dev.device_pause = fsl_edma_pause;
> > +       mcf_edma->dma_dev.device_resume = fsl_edma_resume;
> > +       mcf_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
> > +       mcf_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
> > +
> > +       mcf_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
> > +       mcf_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
> > +       mcf_edma->dma_dev.directions =
> > +                       BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
> > +
> > +       mcf_edma->dma_dev.filter.fn = mcf_edma_filter_fn;
> > +       mcf_edma->dma_dev.filter.map = pdata->slave_map;
> > +       mcf_edma->dma_dev.filter.mapcnt = pdata->slavecnt;
> > +
> > +       platform_set_drvdata(pdev, mcf_edma);
> > +
> > +       ret = dma_async_device_register(&mcf_edma->dma_dev);
> > +       if (ret) {
> > +               dev_err(&pdev->dev,
> > +                       "Can't register Freescale eDMA engine. (%d)\n", ret);
> > +               return ret;
> > +       }
> > +
> > +       /* Enable round robin arbitration */
> > +       iowrite32(EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
> > +
> > +       return 0;
> > +}
> > +
> > +static int mcf_edma_remove(struct platform_device *pdev)
> > +{
> > +       struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
> > +
> > +       mcf_edma_irq_free(pdev, mcf_edma);
> > +       fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
> > +       dma_async_device_unregister(&mcf_edma->dma_dev);
> > +
> > +       return 0;
> > +}
> > +
> > +static struct platform_driver mcf_edma_driver = {
> > +       .driver         = {
> > +               .name   = "mcf-edma",
> > +       },
> > +       .probe          = mcf_edma_probe,
> > +       .remove         = mcf_edma_remove,
> > +};
> > +
> > +bool mcf_edma_filter_fn(struct dma_chan *chan, void *param)
> > +{
> > +       if (chan->device->dev->driver == &mcf_edma_driver.driver) {
> > +               struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan);
> > +
> > +               return (mcf_chan->slave_id == (int)param);
> > +       }
> > +
> > +       return false;
> > +}
> > +EXPORT_SYMBOL(mcf_edma_filter_fn);
> > +
> > +static int __init mcf_edma_init(void)
> > +{
> > +       return platform_driver_register(&mcf_edma_driver);
> > +}
> > +subsys_initcall(mcf_edma_init);
> > +
> > +static void __exit mcf_edma_exit(void)
> > +{
> > +       platform_driver_unregister(&mcf_edma_driver);
> > +}
> > +module_exit(mcf_edma_exit);
> > +
> > +MODULE_ALIAS("platform:mcf-edma");
> > +MODULE_DESCRIPTION("Freescale eDMA engine driver, ColdFire family");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/include/linux/platform_data/dma-mcf-edma.h b/include/linux/platform_data/dma-mcf-edma.h
> > new file mode 100644
> > index 000000000000..9a1819acb28f
> > --- /dev/null
> > +++ b/include/linux/platform_data/dma-mcf-edma.h
> > @@ -0,0 +1,38 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Freescale eDMA platform data, ColdFire SoC's family.
> > + *
> > + * Copyright (c) 2017 Angelo Dureghello <angelo@sysam.it>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#ifndef __MACH_MCF_EDMA_H__
> > +#define __MACH_MCF_EDMA_H__
> 
> The guard should rather match current location, e.g.
> __LINUX_PLATFORM_DATA_MCF_EDMA_H__
> 
Ack.

> Tested-by: Krzysztof Kozlowski <krzk@kernel.org>
> 
> Best regards,
> Krzysztof
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Regards,
Angelo
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v8,1/3] dmaengine: fsl-edma: extract common fsl-edma code (no changes in behavior intended)
From: Angelo Dureghello @ 2018-08-06 20:40 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: vinod.koul, dmaengine, linux-arm-kernel, linux-m68k, Stefan Agner

Hi Krzysztof,

On Mon, Aug 06, 2018 at 09:43:42AM +0200, Krzysztof Kozlowski wrote:
> On 3 August 2018 at 21:32, Angelo Dureghello <angelo@sysam.it> wrote:
> > This patch adds a new fsl-edma-common module to allow new
> > mcf-edma module code to use most of the fsl-edma code.
> >
> > Signed-off-by: Angelo Dureghello <angelo@sysam.it>
> > ---
> > Changes for v2:
> > - patch splitted into 4
> > - add mcf-edma as minimal different parts from fsl-edma
> >
> > Changes for v3:
> > none
> >
> > Changes for v4:
> > - patch simplified from 4/4 into 2/2
> > - collecting all the mcf-edma-related changes
> >
> > Changes for v5:
> > none
> >
> > Changes for v6:
> > - adjusted comment header
> > - fixed bit shift with BIT()
> > - we need to free the interrupts at remove(), so removed all devm_
> >   interrupt related calls
> >
> > Changes for v7:
> > none
> >
> > Changes for v8:
> > - patch rewritten from scratch, splitted into 3, common code isolated,
> >   minimal changes from the original Freescale code have been done.
> >   The patch has been tested with both Iris + Colibri Vybrid VF50 and
> >   stmark2/mcf54415 Coldfire boards.
> > ---
> >  drivers/dma/Makefile          |   2 +-
> >  drivers/dma/fsl-edma-common.c | 576 ++++++++++++++++++++++++++++
> >  drivers/dma/fsl-edma-common.h | 196 ++++++++++
> >  drivers/dma/fsl-edma.c        | 697 +---------------------------------
> >  4 files changed, 774 insertions(+), 697 deletions(-)
> >  create mode 100644 drivers/dma/fsl-edma-common.c
> >  create mode 100644 drivers/dma/fsl-edma-common.h
> >
> > diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> > index 203a99d68315..66022f59fca4 100644
> > --- a/drivers/dma/Makefile
> > +++ b/drivers/dma/Makefile
> > @@ -31,7 +31,7 @@ obj-$(CONFIG_DW_AXI_DMAC) += dw-axi-dmac/
> >  obj-$(CONFIG_DW_DMAC_CORE) += dw/
> >  obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
> >  obj-$(CONFIG_FSL_DMA) += fsldma.o
> > -obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
> > +obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
> >  obj-$(CONFIG_FSL_RAID) += fsl_raid.o
> >  obj-$(CONFIG_HSU_DMA) += hsu/
> >  obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
> > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> > new file mode 100644
> > index 000000000000..0ae7094f477a
> > --- /dev/null
> > +++ b/drivers/dma/fsl-edma-common.c
> > @@ -0,0 +1,576 @@
> > +// SPDX-License-Identifier: GPL-2.0
> 
> You moved code from fsl-edma.c which is licensed on GPL-2.0+. I think
> that's not allowed as you effectively relicense the work on new
> license.
> 
Ok, so if i undestrand, i should change that comment to
// SPDX-License-Identifier: GPL-2.0+
Right ?

> Tested-by: Krzysztof Kozlowski <krzk@kernel.org>
> 
> Best regards,
> Krzysztof
>

Best regards,
Angelo
 
> > +//
> > +// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
> > +// Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [v8,2/3] dmaengine: fsl-edma: add edma version and configurable registers
From: Angelo Dureghello @ 2018-08-06 20:31 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: vinod.koul, dmaengine, linux-arm-kernel, linux-m68k, Stefan Agner

Hi Krzysztof,

many thanks for testing.

On Mon, Aug 06, 2018 at 09:59:35AM +0200, Krzysztof Kozlowski wrote:
> On 3 August 2018 at 21:32, Angelo Dureghello <angelo@sysam.it> wrote:
> > This patch adds configurable registers (using __iomem addresses)
> > to allow the use of fsl-edma-common code with slightly different
> > edma module versions, as Vybrid (v1) and ColdFire (v2) are.
> >
> > Removal of old membase-referenced registers, amd some fixes on
> > macroes are included.
> >
> > Signed-off-by: Angelo Dureghello <angelo@sysam.it>
> > ---
> > Changes from v7:
> > - patch rewritten from scratch, this patch (2/3) has just been added.
> > ---
> >  drivers/dma/fsl-edma-common.c | 138 ++++++++++++++++++++++++++--------
> >  drivers/dma/fsl-edma-common.h | 115 ++++++++++++++--------------
> >  drivers/dma/fsl-edma.c        |  32 ++++----
> >  3 files changed, 182 insertions(+), 103 deletions(-)
> >
> > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> > index 0ae7094f477a..948a3ee51bbb 100644
> > --- a/drivers/dma/fsl-edma-common.c
> > +++ b/drivers/dma/fsl-edma-common.c
> > @@ -9,6 +9,38 @@
> >
> >  #include "fsl-edma-common.h"
> >
> > +#define EDMA_CR                        0x00
> > +#define EDMA_ES                        0x04
> > +#define EDMA_ERQ               0x0C
> > +#define EDMA_EEI               0x14
> > +#define EDMA_SERQ              0x1B
> > +#define EDMA_CERQ              0x1A
> > +#define EDMA_SEEI              0x19
> > +#define EDMA_CEEI              0x18
> > +#define EDMA_CINT              0x1F
> > +#define EDMA_CERR              0x1E
> > +#define EDMA_SSRT              0x1D
> > +#define EDMA_CDNE              0x1C
> > +#define EDMA_INTR              0x24
> > +#define EDMA_ERR               0x2C
> > +
> > +#define EDMA64_ERQH            0x08
> > +#define EDMA64_EEIH            0x10
> > +#define EDMA64_SERQ            0x18
> > +#define EDMA64_CERQ            0x19
> > +#define EDMA64_SEEI            0x1a
> > +#define EDMA64_CEEI            0x1b
> > +#define EDMA64_CINT            0x1c
> > +#define EDMA64_CERR            0x1d
> > +#define EDMA64_SSRT            0x1e
> > +#define EDMA64_CDNE            0x1f
> > +#define EDMA64_INTH            0x20
> > +#define EDMA64_INTL            0x24
> > +#define EDMA64_ERRH            0x28
> > +#define EDMA64_ERRL            0x2c
> > +
> > +#define EDMA_TCD               0x1000
> > +
> >  /*
> >   * R/W functions for big- or little-endian registers:
> >   * The eDMA controller's endian is independent of the CPU core's endian.
> > @@ -67,20 +99,20 @@ EXPORT_SYMBOL_GPL(to_fsl_edma_desc);
> >
> >  static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
> >  {
> > -       void __iomem *addr = fsl_chan->edma->membase;
> > +       struct edma_regs *regs = &fsl_chan->edma->regs;
> >         u32 ch = fsl_chan->vchan.chan.chan_id;
> >
> > -       edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
> > -       edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
> > +       edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
> > +       edma_writeb(fsl_chan->edma, ch, regs->serq);
> >  }
> >
> >  void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
> >  {
> > -       void __iomem *addr = fsl_chan->edma->membase;
> > +       struct edma_regs *regs = &fsl_chan->edma->regs;
> >         u32 ch = fsl_chan->vchan.chan.chan_id;
> >
> > -       edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
> > -       edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
> > +       edma_writeb(fsl_chan->edma, ch, regs->cerq);
> > +       edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
> >  }
> >  EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
> >
> > @@ -208,7 +240,7 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
> >                 struct virt_dma_desc *vdesc, bool in_progress)
> >  {
> >         struct fsl_edma_desc *edesc = fsl_chan->edesc;
> > -       void __iomem *addr = fsl_chan->edma->membase;
> > +       struct edma_regs *regs = &fsl_chan->edma->regs;
> >         u32 ch = fsl_chan->vchan.chan.chan_id;
> >         enum dma_transfer_direction dir = fsl_chan->fsc.dir;
> >         dma_addr_t cur_addr, dma_addr;
> > @@ -224,11 +256,9 @@ static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
> >                 return len;
> >
> >         if (dir == DMA_MEM_TO_DEV)
> > -               cur_addr = edma_readl(
> > -                       fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
> > +               cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].saddr);
> >         else
> > -               cur_addr = edma_readl(
> > -                       fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
> > +               cur_addr = edma_readl(fsl_chan->edma, &regs->tcd[ch].daddr);
> >
> >         /* figure out the finished and calculate the residue */
> >         for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
> > @@ -285,7 +315,7 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
> >                                   struct fsl_edma_hw_tcd *tcd)
> >  {
> >         struct fsl_edma_engine *edma = fsl_chan->edma;
> > -       void __iomem *addr = fsl_chan->edma->membase;
> > +       struct edma_regs *regs = &fsl_chan->edma->regs;
> >         u32 ch = fsl_chan->vchan.chan.chan_id;
> >
> >         /*
> > @@ -293,24 +323,24 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
> >          * endian format. However, we need to load the TCD registers in
> >          * big- or little-endian obeying the eDMA engine model endian.
> >          */
> > -       edma_writew(edma, 0, addr + EDMA_TCD_CSR(ch));
> > -       edma_writel(edma, le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR(ch));
> > -       edma_writel(edma, le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR(ch));
> > +       edma_writew(edma, 0,  &regs->tcd[ch].csr);
> > +       edma_writel(edma, le32_to_cpu(tcd->saddr), &regs->tcd[ch].saddr);
> > +       edma_writel(edma, le32_to_cpu(tcd->daddr), &regs->tcd[ch].daddr);
> >
> > -       edma_writew(edma, le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR(ch));
> > -       edma_writew(edma, le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF(ch));
> > +       edma_writew(edma, le16_to_cpu(tcd->attr), &regs->tcd[ch].attr);
> > +       edma_writew(edma, le16_to_cpu(tcd->soff), &regs->tcd[ch].soff);
> >
> > -       edma_writel(edma, le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES(ch));
> > -       edma_writel(edma, le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST(ch));
> > +       edma_writel(edma, le32_to_cpu(tcd->nbytes), &regs->tcd[ch].nbytes);
> > +       edma_writel(edma, le32_to_cpu(tcd->slast), &regs->tcd[ch].slast);
> >
> > -       edma_writew(edma, le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER(ch));
> > -       edma_writew(edma, le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER(ch));
> > -       edma_writew(edma, le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF(ch));
> > +       edma_writew(edma, le16_to_cpu(tcd->citer), &regs->tcd[ch].citer);
> > +       edma_writew(edma, le16_to_cpu(tcd->biter), &regs->tcd[ch].biter);
> > +       edma_writew(edma, le16_to_cpu(tcd->doff), &regs->tcd[ch].doff);
> >
> > -       edma_writel(edma,
> > -                   le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA(ch));
> > +       edma_writel(edma, le32_to_cpu(tcd->dlast_sga),
> > +                       &regs->tcd[ch].dlast_sga);
> >
> > -       edma_writew(edma, le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR(ch));
> > +       edma_writew(edma, le16_to_cpu(tcd->csr), &regs->tcd[ch].csr);
> >  }
> >
> >  static inline
> > @@ -332,15 +362,15 @@ void fsl_edma_fill_tcd(struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
> >
> >         tcd->attr = cpu_to_le16(attr);
> >
> > -       tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
> > +       tcd->soff = cpu_to_le16(soff);
> >
> > -       tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
> > -       tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
> > +       tcd->nbytes = cpu_to_le32(nbytes);
> > +       tcd->slast = cpu_to_le32(slast);
> >
> >         tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
> > -       tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
> > +       tcd->doff = cpu_to_le16(doff);
> >
> > -       tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
> > +       tcd->dlast_sga = cpu_to_le32(dlast_sga);
> >
> >         tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
> >         if (major_int)
> > @@ -573,4 +603,52 @@ void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
> >  }
> >  EXPORT_SYMBOL_GPL(fsl_edma_cleanup_vchan);
> >
> > +/*
> > + * On the 32 channels Vybrid/mpc577x edma version (here called "v1"),
> > + * register offsets are different compared to ColdFire mcf5441x 64 channels
> > + * edma (here called "v2").
> > + *
> > + * This function sets up register offsets as per proper declared version
> > + * so must be called in xxx_edma_probe() just after setting the
> > + * edma "version" and "membase" appropriately.
> > + */
> > +void fsl_edma_setup_regs(struct fsl_edma_engine *edma)
> > +{
> > +       edma->regs.cr = edma->membase + EDMA_CR;
> > +       edma->regs.es = edma->membase + EDMA_ES;
> > +       edma->regs.erql = edma->membase + EDMA_ERQ;
> > +       edma->regs.eeil = edma->membase + EDMA_EEI;
> > +
> > +       edma->regs.serq = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_SERQ : EDMA64_SERQ);
> > +       edma->regs.cerq = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_CERQ : EDMA64_CERQ);
> > +       edma->regs.seei = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_SEEI : EDMA64_SEEI);
> > +       edma->regs.ceei = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_CEEI : EDMA64_CEEI);
> > +       edma->regs.cint = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_CINT : EDMA64_CINT);
> > +       edma->regs.cerr = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_CERR : EDMA64_CERR);
> > +       edma->regs.ssrt = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_SSRT : EDMA64_SSRT);
> > +       edma->regs.cdne = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_CDNE : EDMA64_CDNE);
> > +       edma->regs.intl = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_INTR : EDMA64_INTL);
> > +       edma->regs.errl = edma->membase + ((edma->version == v1) ?
> > +                       EDMA_ERR : EDMA64_ERRL);
> > +
> > +       if (edma->version == v2) {
> > +               edma->regs.erqh = edma->membase + EDMA64_ERQH;
> > +               edma->regs.eeih = edma->membase + EDMA64_EEIH;
> > +               edma->regs.errh = edma->membase + EDMA64_ERRH;
> > +               edma->regs.inth = edma->membase + EDMA64_INTH;
> > +       }
> > +
> > +       edma->regs.tcd = edma->membase + EDMA_TCD;
> > +}
> > +EXPORT_SYMBOL_GPL(fsl_edma_setup_regs);
> > +
> >  MODULE_LICENSE("GPL v2");
> > diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
> > index f3ea68e15b23..7a9231e7639f 100644
> > --- a/drivers/dma/fsl-edma-common.h
> > +++ b/drivers/dma/fsl-edma-common.h
> > @@ -8,35 +8,6 @@
> >
> >  #include "virt-dma.h"
> >
> > -#define EDMA_CR                        0x00
> > -#define EDMA_ES                        0x04
> > -#define EDMA_ERQ               0x0C
> > -#define EDMA_EEI               0x14
> > -#define EDMA_SERQ              0x1B
> > -#define EDMA_CERQ              0x1A
> > -#define EDMA_SEEI              0x19
> > -#define EDMA_CEEI              0x18
> > -#define EDMA_CINT              0x1F
> > -#define EDMA_CERR              0x1E
> > -#define EDMA_SSRT              0x1D
> > -#define EDMA_CDNE              0x1C
> > -#define EDMA_INTR              0x24
> > -#define EDMA_ERR               0x2C
> > -
> > -#define EDMA_TCD_SADDR(x)      (0x1000 + 32 * (x))
> > -#define EDMA_TCD_SOFF(x)       (0x1004 + 32 * (x))
> > -#define EDMA_TCD_ATTR(x)       (0x1006 + 32 * (x))
> > -#define EDMA_TCD_NBYTES(x)     (0x1008 + 32 * (x))
> > -#define EDMA_TCD_SLAST(x)      (0x100C + 32 * (x))
> > -#define EDMA_TCD_DADDR(x)      (0x1010 + 32 * (x))
> > -#define EDMA_TCD_DOFF(x)       (0x1014 + 32 * (x))
> > -#define EDMA_TCD_CITER_ELINK(x)        (0x1016 + 32 * (x))
> > -#define EDMA_TCD_CITER(x)      (0x1016 + 32 * (x))
> > -#define EDMA_TCD_DLAST_SGA(x)  (0x1018 + 32 * (x))
> > -#define EDMA_TCD_CSR(x)                (0x101C + 32 * (x))
> > -#define EDMA_TCD_BITER_ELINK(x)        (0x101E + 32 * (x))
> > -#define EDMA_TCD_BITER(x)      (0x101E + 32 * (x))
> > -
> >  #define EDMA_CR_EDBG           BIT(1)
> >  #define EDMA_CR_ERCA           BIT(2)
> >  #define EDMA_CR_ERGA           BIT(3)
> > @@ -47,34 +18,29 @@
> >  #define EDMA_CR_ECX            BIT(16)
> >  #define EDMA_CR_CX             BIT(17)
> >
> > -#define EDMA_SEEI_SEEI(x)      ((x) & 0x1F)
> > -#define EDMA_CEEI_CEEI(x)      ((x) & 0x1F)
> > -#define EDMA_CINT_CINT(x)      ((x) & 0x1F)
> > -#define EDMA_CERR_CERR(x)      ((x) & 0x1F)
> > -
> > -#define EDMA_TCD_ATTR_DSIZE(x)         (((x) & 0x0007))
> > -#define EDMA_TCD_ATTR_DMOD(x)          (((x) & 0x001F) << 3)
> > -#define EDMA_TCD_ATTR_SSIZE(x)         (((x) & 0x0007) << 8)
> > -#define EDMA_TCD_ATTR_SMOD(x)          (((x) & 0x001F) << 11)
> > -#define EDMA_TCD_ATTR_SSIZE_8BIT       (0x0000)
> > -#define EDMA_TCD_ATTR_SSIZE_16BIT      (0x0100)
> > -#define EDMA_TCD_ATTR_SSIZE_32BIT      (0x0200)
> > -#define EDMA_TCD_ATTR_SSIZE_64BIT      (0x0300)
> > -#define EDMA_TCD_ATTR_SSIZE_32BYTE     (0x0500)
> > -#define EDMA_TCD_ATTR_DSIZE_8BIT       (0x0000)
> > -#define EDMA_TCD_ATTR_DSIZE_16BIT      (0x0001)
> > -#define EDMA_TCD_ATTR_DSIZE_32BIT      (0x0002)
> > -#define EDMA_TCD_ATTR_DSIZE_64BIT      (0x0003)
> > -#define EDMA_TCD_ATTR_DSIZE_32BYTE     (0x0005)
> > -
> > -#define EDMA_TCD_SOFF_SOFF(x)          (x)
> > -#define EDMA_TCD_NBYTES_NBYTES(x)      (x)
> > -#define EDMA_TCD_SLAST_SLAST(x)                (x)
> > -#define EDMA_TCD_DADDR_DADDR(x)                (x)
> > -#define EDMA_TCD_CITER_CITER(x)                ((x) & 0x7FFF)
> > -#define EDMA_TCD_DOFF_DOFF(x)          (x)
> > -#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)        (x)
> > -#define EDMA_TCD_BITER_BITER(x)                ((x) & 0x7FFF)
> > +#define EDMA_SEEI_SEEI(x)      ((x) & GENMASK(4, 0))
> > +#define EDMA_CEEI_CEEI(x)      ((x) & GENMASK(4, 0))
> > +#define EDMA_CINT_CINT(x)      ((x) & GENMASK(4, 0))
> > +#define EDMA_CERR_CERR(x)      ((x) & GENMASK(4, 0))
> > +
> > +#define EDMA_TCD_ATTR_DSIZE(x)         (((x) & GENMASK(2, 0)))
> > +#define EDMA_TCD_ATTR_DMOD(x)          (((x) & GENMASK(4, 0)) << 3)
> > +#define EDMA_TCD_ATTR_SSIZE(x)         (((x) & GENMASK(2, 0)) << 8)
> > +#define EDMA_TCD_ATTR_SMOD(x)          (((x) & GENMASK(4, 0)) << 11)
> 
> This looks like a change for its own commit.
> 
Yes, was previously required the usage of BIT() and GENMASK().

> > +
> > +#define EDMA_TCD_ATTR_DSIZE_8BIT       0
> > +#define EDMA_TCD_ATTR_DSIZE_16BIT      BIT(0)
> > +#define EDMA_TCD_ATTR_DSIZE_32BIT      BIT(1)
> > +#define EDMA_TCD_ATTR_DSIZE_64BIT      (BIT(0) | BIT(1))
> > +#define EDMA_TCD_ATTR_DSIZE_32BYTE     (BIT(3) | BIT(0))
> > +#define EDMA_TCD_ATTR_SSIZE_8BIT       0
> > +#define EDMA_TCD_ATTR_SSIZE_16BIT      (EDMA_TCD_ATTR_DSIZE_16BIT << 8)
> > +#define EDMA_TCD_ATTR_SSIZE_32BIT      (EDMA_TCD_ATTR_DSIZE_32BIT << 8)
> > +#define EDMA_TCD_ATTR_SSIZE_64BIT      (EDMA_TCD_ATTR_DSIZE_64BIT << 8)
> > +#define EDMA_TCD_ATTR_SSIZE_32BYTE     (EDMA_TCD_ATTR_DSIZE_32BYTE << 8)
> > +
> > +#define EDMA_TCD_CITER_CITER(x)                ((x) & GENMASK(14, 0))
> > +#define EDMA_TCD_BITER_BITER(x)                ((x) & GENMASK(14, 0))
> >
> >  #define EDMA_TCD_CSR_START             BIT(0)
> >  #define EDMA_TCD_CSR_INT_MAJOR         BIT(1)
> > @@ -87,7 +53,7 @@
> >
> >  #define EDMAMUX_CHCFG_DIS              0x0
> >  #define EDMAMUX_CHCFG_ENBL             0x80
> > -#define EDMAMUX_CHCFG_SOURCE(n)                ((n) & 0x3F)
> > +#define EDMAMUX_CHCFG_SOURCE(n)                ((n) & GENMASK(6, 0))
> >
> >  #define DMAMUX_NR      2
> >
> > @@ -114,6 +80,31 @@ struct fsl_edma_hw_tcd {
> >         __le16  biter;
> >  };
> >
> > +/*
> > + * This are iomem pointers, for both v32 and v64.
> 
> s/This/These/
>
Ack. Will eventually fix all in a v9. Collecting feedbacks.
 
> Tested-by: Krzysztof Kozlowski <krzk@kernel.org>
> 
> Best regards,
> Krzysztof
> --
> To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Best Regards,
Angelo
---
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox