DMA Engine development
 help / color / mirror / Atom feed
* dma: cppi41: delete channel from pending list when stop channel
From: Peter Ujfalusi @ 2018-11-28 11:16 UTC (permalink / raw)
  To: Bin Liu, dmaengine; +Cc: linux-usb, Vinod, stable

Hi,

On 28/11/2018 13.15, Peter Ujfalusi wrote:

forgot to fix up Vinod's email address.

> 
> 
> On 12/11/2018 17.40, Bin Liu wrote:
> 
> Can you fix up the subject line to:
> dmaengine: ti: cppi4: delete channel from pending list when stop channel
> 
>> The driver defines three states for a cppi channel.
>> - idle: .chan_busy == 0 && not in .pending list
>> - pending: .chan_busy == 0 && in .pending list
>> - busy: .chan_busy == 1 && not in .pending list
>>
>> There are cases in which the cppi channel could be in the pending state
>> when cppi41_dma_issue_pending() is called after cppi41_runtime_suspend()
>> is called.
>>
>> cppi41_stop_chan() has a bug for these cases to set channels to idle state.
>> It only checks the .chan_busy flag, but not the .pending list, then later
>> when cppi41_runtime_resume() is called the channels in .pending list will
>> be transitioned to busy state.
>>
>> Removing channels from the .pending list solves the problem.
> 
> So, let me see if I understand this correctly:
> - client issued a transfer _after_ the cppi4 driver is suspended
> - cppi41_dma_issue_pending() will place it to pending list and will not
> start the transfer right away as cdd->is_suspended is true.
> - on resume the cppi4 will pick up the pending transfers from the
> pending list
> 
> This is so far a sane thing to do.
> 
> If I guess right, then after the issue_pending the client driver will
> call terminate_all, presumably from it's suspend callback?
> 
> As per the purpose of terminate_all we should terminated all future
> transfers on the channel, so clearing the pending list is the correct
> thing to do.
> 
> With the fixed subject:
> Reviewed-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> 
> I have one question:
> 
>> Fixes: 975faaeb9985 ("dma: cppi41: start tear down only if channel is busy")
>> Cc: stable@vger.kernel.org # v3.15+
>> Signed-off-by: Bin Liu <b-liu@ti.com>
>> ---
>>  drivers/dma/ti/cppi41.c | 16 +++++++++++++++-
>>  1 file changed, 15 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/dma/ti/cppi41.c b/drivers/dma/ti/cppi41.c
>> index 1497da367710..e507ec36c0d3 100644
>> --- a/drivers/dma/ti/cppi41.c
>> +++ b/drivers/dma/ti/cppi41.c
>> @@ -723,8 +723,22 @@ static int cppi41_stop_chan(struct dma_chan *chan)
>>  
>>  	desc_phys = lower_32_bits(c->desc_phys);
>>  	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
>> -	if (!cdd->chan_busy[desc_num])
>> +	if (!cdd->chan_busy[desc_num]) {
>> +		struct cppi41_channel *cc, *_ct;
>> +
>> +		/*
>> +		 * channels might still be in the pendling list if
>> +		 * cppi41_dma_issue_pending() is called after
>> +		 * cppi41_runtime_suspend() is called
>> +		 */
>> +		list_for_each_entry_safe(cc, _ct, &cdd->pending, node) {
>> +			if (cc != c)
>> +				continue;
>> +			list_del(&cc->node);
> 
> If we delete from the pending list, are we going to leak memory?
> I'm not familiar with the cppi4, it might not be an issue for it.
> 
>> +			break;
>> +		}
>>  		return 0;
>> +	}
>>  
>>  	ret = cppi41_tear_down_chan(c);
>>  	if (ret)
>>
> 
> - Péter
> 
> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
> 

- Péter

Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

^ permalink raw reply

* [v2] dmaengine: sh: Remove R-Mobile APE6 support
From: Geert Uytterhoeven @ 2018-11-29 11:18 UTC (permalink / raw)
  To: Vinod Koul, Dan Williams
  Cc: Guennadi Liakhovetski, Laurent Pinchart, Wolfram Sang,
	Simon Horman, Magnus Damm, Yoshinori Sato, Rich Felker, dmaengine,
	linux-renesas-soc, linux-sh, linux-kernel, Geert Uytterhoeven

Renesas R-Mobile APE6 support is currently unused:
  - DMA slaves were never enabled in r8a73a4.dtsi,
  - The driver relies on legacy filter matching and describing all
    slaves and MID/RIDs in a table, unlike modern DMA engine drivers for
    similar hardware like rcar-dmac,
  - The driver doesn't seem to work well.

Remove the driver, it can be resurrected from git history when needed.

As this was the last user of SH_DMAE_BASE on Renesas ARM SoCs, the
sh-dma-engine driver core is now used on SuperH only.

Note that the DT bindings are still present, as r8a73a4.dtsi uses them.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Ulrich Hecht <uli+renesas@fpond.eu>
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
---
v2:
  - Add Reviewed-by,
  - Drop RFC.

---
 drivers/dma/sh/Kconfig         | 11 +----
 drivers/dma/sh/Makefile        |  1 -
 drivers/dma/sh/shdma-r8a73a4.c | 74 ----------------------------------
 drivers/dma/sh/shdma.h         |  7 ----
 drivers/dma/sh/shdmac.c        |  7 ----
 5 files changed, 1 insertion(+), 99 deletions(-)
 delete mode 100644 drivers/dma/sh/shdma-r8a73a4.c

diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 6e0685f1a83814f4..b728cfaf4d700f96 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -12,7 +12,7 @@ config RENESAS_DMA
 
 config SH_DMAE_BASE
 	bool "Renesas SuperH DMA Engine support"
-	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
+	depends on SUPERH || COMPILE_TEST
 	depends on !SUPERH || SH_DMA
 	depends on !SH_DMA_API
 	default y
@@ -30,15 +30,6 @@ config SH_DMAE
 	help
 	  Enable support for the Renesas SuperH DMA controllers.
 
-if SH_DMAE
-
-config SH_DMAE_R8A73A4
-	def_bool y
-	depends on ARCH_R8A73A4
-	depends on OF
-
-endif
-
 config RCAR_DMAC
 	tristate "Renesas R-Car Gen2 DMA Controller"
 	depends on ARCH_RENESAS || COMPILE_TEST
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index 7d7c9491ade1216d..42110dd57a56fda8 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
 #
 
 shdma-y := shdmac.o
-shdma-$(CONFIG_SH_DMAE_R8A73A4) += shdma-r8a73a4.o
 shdma-objs := $(shdma-y)
 obj-$(CONFIG_SH_DMAE) += shdma.o
 
diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c
deleted file mode 100644
index ddc9a35783534bdd..0000000000000000
--- a/drivers/dma/sh/shdma-r8a73a4.c
+++ /dev/null
@@ -1,74 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
- *
- * Copyright (C) 2013 Renesas Electronics, Inc.
- */
-#include <linux/sh_dma.h>
-
-#include "shdma-arm.h"
-
-static const unsigned int dma_ts_shift[] = SH_DMAE_TS_SHIFT;
-
-static const struct sh_dmae_slave_config dma_slaves[] = {
-	{
-		.chcr		= CHCR_TX(XMIT_SZ_32BIT),
-		.mid_rid	= 0xd1,		/* MMC0 Tx */
-	}, {
-		.chcr		= CHCR_RX(XMIT_SZ_32BIT),
-		.mid_rid	= 0xd2,		/* MMC0 Rx */
-	}, {
-		.chcr		= CHCR_TX(XMIT_SZ_32BIT),
-		.mid_rid	= 0xe1,		/* MMC1 Tx */
-	}, {
-		.chcr		= CHCR_RX(XMIT_SZ_32BIT),
-		.mid_rid	= 0xe2,		/* MMC1 Rx */
-	},
-};
-
-#define DMAE_CHANNEL(a, b)				\
-	{						\
-		.offset         = (a) - 0x20,		\
-		.dmars          = (a) - 0x20 + 0x40,	\
-		.chclr_bit	= (b),			\
-		.chclr_offset	= 0x80 - 0x20,		\
-	}
-
-static const struct sh_dmae_channel dma_channels[] = {
-	DMAE_CHANNEL(0x8000, 0),
-	DMAE_CHANNEL(0x8080, 1),
-	DMAE_CHANNEL(0x8100, 2),
-	DMAE_CHANNEL(0x8180, 3),
-	DMAE_CHANNEL(0x8200, 4),
-	DMAE_CHANNEL(0x8280, 5),
-	DMAE_CHANNEL(0x8300, 6),
-	DMAE_CHANNEL(0x8380, 7),
-	DMAE_CHANNEL(0x8400, 8),
-	DMAE_CHANNEL(0x8480, 9),
-	DMAE_CHANNEL(0x8500, 10),
-	DMAE_CHANNEL(0x8580, 11),
-	DMAE_CHANNEL(0x8600, 12),
-	DMAE_CHANNEL(0x8680, 13),
-	DMAE_CHANNEL(0x8700, 14),
-	DMAE_CHANNEL(0x8780, 15),
-	DMAE_CHANNEL(0x8800, 16),
-	DMAE_CHANNEL(0x8880, 17),
-	DMAE_CHANNEL(0x8900, 18),
-	DMAE_CHANNEL(0x8980, 19),
-};
-
-const struct sh_dmae_pdata r8a73a4_dma_pdata = {
-	.slave		= dma_slaves,
-	.slave_num	= ARRAY_SIZE(dma_slaves),
-	.channel	= dma_channels,
-	.channel_num	= ARRAY_SIZE(dma_channels),
-	.ts_low_shift	= TS_LOW_SHIFT,
-	.ts_low_mask	= TS_LOW_BIT << TS_LOW_SHIFT,
-	.ts_high_shift	= TS_HI_SHIFT,
-	.ts_high_mask	= TS_HI_BIT << TS_HI_SHIFT,
-	.ts_shift	= dma_ts_shift,
-	.ts_shift_num	= ARRAY_SIZE(dma_ts_shift),
-	.dmaor_init     = DMAOR_DME,
-	.chclr_present	= 1,
-	.chclr_bitwise	= 1,
-};
diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h
index bfb69909bd192759..9c121a4b33ad829c 100644
--- a/drivers/dma/sh/shdma.h
+++ b/drivers/dma/sh/shdma.h
@@ -58,11 +58,4 @@ struct sh_dmae_desc {
 #define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\
 				     struct sh_dmae_device, shdma_dev.dma_dev)
 
-#ifdef CONFIG_SH_DMAE_R8A73A4
-extern const struct sh_dmae_pdata r8a73a4_dma_pdata;
-#define r8a73a4_shdma_devid (&r8a73a4_dma_pdata)
-#else
-#define r8a73a4_shdma_devid NULL
-#endif
-
 #endif	/* __DMA_SHDMA_H */
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
index 2ab7971928e3d8b5..ce19ab7ed30c3a8f 100644
--- a/drivers/dma/sh/shdmac.c
+++ b/drivers/dma/sh/shdmac.c
@@ -662,12 +662,6 @@ static const struct shdma_ops sh_dmae_shdma_ops = {
 	.get_residue = sh_dmae_get_residue,
 };
 
-static const struct of_device_id sh_dmae_of_match[] = {
-	{.compatible = "renesas,shdma-r8a73a4", .data = r8a73a4_shdma_devid,},
-	{}
-};
-MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
-
 static int sh_dmae_probe(struct platform_device *pdev)
 {
 	const enum dma_slave_buswidth widths =
@@ -912,7 +906,6 @@ static struct platform_driver sh_dmae_driver = {
 	.driver		= {
 		.pm	= &sh_dmae_pm,
 		.name	= SH_DMAE_DRV_NAME,
-		.of_match_table = sh_dmae_of_match,
 	},
 	.remove		= sh_dmae_remove,
 };

^ permalink raw reply related

* dmaengine: at_hdmac: fix memory leak in at_dma_xlate()
From: Ludovic Desroches @ 2018-11-29 13:51 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Dan Williams, Vinod Koul, Alexandre Belloni, Nicolas Ferre,
	Maxime Ripard, Mario Forner, linux-arm-kernel, dmaengine,
	linux-kernel, linux-serial, stable

On Tue, Nov 27, 2018 at 05:06:34PM +0100, Richard Genoud wrote:
> The leak was found when opening/closing a serial port a great number of
> time, increasing kmalloc-32 in slabinfo.
> 
> Each time the port was opened, dma_request_slave_channel() was called.
> Then, in at_dma_xlate(), atslave was allocated with devm_kzalloc() and
> never freed. (Well, it was free at module unload, but that's not what we
> want).
> So, here, kzalloc is more suited for the job since it has to be freed in
> atc_free_chan_resources().
> 
> Cc: stable@vger.kernel.org
> Fixes: bbe89c8e3d59 ("at_hdmac: move to generic DMA binding")
> Reported-by: Mario Forner <m.forner@be4energy.com>
> Suggested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>

Thanks for handling this issue.

Ludovic

> ---
>  drivers/dma/at_hdmac.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
> index 7cbac6e8c113..1b7f0ca0d5cd 100644
> --- a/drivers/dma/at_hdmac.c
> +++ b/drivers/dma/at_hdmac.c
> @@ -1641,6 +1641,12 @@ static void atc_free_chan_resources(struct dma_chan *chan)
>  	atchan->descs_allocated = 0;
>  	atchan->status = 0;
>  
> +	/*
> +	 * Free atslave allocated in at_dma_xlate()
> +	 */
> +	kfree(chan->private);
> +	chan->private = NULL;
> +
>  	dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
>  }
>  
> @@ -1675,7 +1681,7 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
>  	dma_cap_zero(mask);
>  	dma_cap_set(DMA_SLAVE, mask);
>  
> -	atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL);
> +	atslave = kzalloc(sizeof(*atslave), GFP_KERNEL);
>  	if (!atslave)
>  		return NULL;
>

^ permalink raw reply

* dmaengine: at_hdmac: fix module unloading
From: Ludovic Desroches @ 2018-11-29 13:52 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Dan Williams, Vinod Koul, Alexandre Belloni, Nicolas Ferre,
	Maxime Ripard, Mario Forner, linux-arm-kernel, dmaengine,
	linux-kernel, linux-serial, stable

On Tue, Nov 27, 2018 at 05:06:35PM +0100, Richard Genoud wrote:
> of_dma_controller_free() was not called on module onloading.

s/onloading/unloading

> This lead to a soft lockup:
> watchdog: BUG: soft lockup - CPU#0 stuck for 23s!
> Modules linked in: at_hdmac [last unloaded: at_hdmac]
> when of_dma_request_slave_channel() tried to call ofdma->of_dma_xlate().
> 
> Cc: stable@vger.kernel.org
> Fixes: bbe89c8e3d59 ("at_hdmac: move to generic DMA binding")
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>

Thanks

Ludovic

> ---
>  drivers/dma/at_hdmac.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
> index 1b7f0ca0d5cd..01d936c9fe89 100644
> --- a/drivers/dma/at_hdmac.c
> +++ b/drivers/dma/at_hdmac.c
> @@ -2006,6 +2006,8 @@ static int at_dma_remove(struct platform_device *pdev)
>  	struct resource		*io;
>  
>  	at_dma_off(atdma);
> +	if (pdev->dev.of_node)
> +		of_dma_controller_free(pdev->dev.of_node);
>  	dma_async_device_unregister(&atdma->dma_common);
>  
>  	dma_pool_destroy(atdma->memset_pool);

^ permalink raw reply

* dmaengine: at_hdmac: fix memory leak in at_dma_xlate()
From: Vinod Koul @ 2018-11-29 14:20 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Ludovic Desroches, Dan Williams, Alexandre Belloni, Nicolas Ferre,
	Maxime Ripard, Mario Forner, linux-arm-kernel, dmaengine,
	linux-kernel, linux-serial, stable

On 27-11-18, 17:06, Richard Genoud wrote:
> The leak was found when opening/closing a serial port a great number of
> time, increasing kmalloc-32 in slabinfo.
> 
> Each time the port was opened, dma_request_slave_channel() was called.
> Then, in at_dma_xlate(), atslave was allocated with devm_kzalloc() and
> never freed. (Well, it was free at module unload, but that's not what we
> want).
> So, here, kzalloc is more suited for the job since it has to be freed in
> atc_free_chan_resources().

Applied, thanks

^ permalink raw reply

* dmaengine: at_hdmac: fix module unloading
From: Vinod Koul @ 2018-11-29 14:21 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Ludovic Desroches, Dan Williams, Alexandre Belloni, Nicolas Ferre,
	Maxime Ripard, Mario Forner, linux-arm-kernel, dmaengine,
	linux-kernel, linux-serial, stable

On 27-11-18, 17:06, Richard Genoud wrote:
> of_dma_controller_free() was not called on module onloading.
> This lead to a soft lockup:
> watchdog: BUG: soft lockup - CPU#0 stuck for 23s!
> Modules linked in: at_hdmac [last unloaded: at_hdmac]
> when of_dma_request_slave_channel() tried to call ofdma->of_dma_xlate().

Applied, thanks

^ permalink raw reply

* [v2] dmaengine: sh: Remove R-Mobile APE6 support
From: Vinod Koul @ 2018-11-29 14:25 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Dan Williams, Guennadi Liakhovetski, Laurent Pinchart,
	Wolfram Sang, Simon Horman, Magnus Damm, Yoshinori Sato,
	Rich Felker, dmaengine, linux-renesas-soc, linux-sh, linux-kernel

On 29-11-18, 12:18, Geert Uytterhoeven wrote:
> Renesas R-Mobile APE6 support is currently unused:
>   - DMA slaves were never enabled in r8a73a4.dtsi,
>   - The driver relies on legacy filter matching and describing all
>     slaves and MID/RIDs in a table, unlike modern DMA engine drivers for
>     similar hardware like rcar-dmac,
>   - The driver doesn't seem to work well.
> 
> Remove the driver, it can be resurrected from git history when needed.
> 
> As this was the last user of SH_DMAE_BASE on Renesas ARM SoCs, the
> sh-dma-engine driver core is now used on SuperH only.
> 
> Note that the DT bindings are still present, as r8a73a4.dtsi uses them.

Sorry but this doesnt apply for me, can you please rebase on topic/sh
and resend.

Thanks

^ permalink raw reply

* dmaengine: at_hdmac: fix memory leak in at_dma_xlate()
From: Mario Forner @ 2018-11-30 10:07 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Ludovic Desroches, Dan Williams, Vinod Koul, Alexandre Belloni,
	Nicolas Ferre, Maxime Ripard, linux-arm-kernel, dmaengine,
	linux-kernel, linux-serial, stable

Am Dienstag, 27. November 2018, 17:06:34 CET schrieb Richard Genoud:
> The leak was found when opening/closing a serial port a great number of
> time, increasing kmalloc-32 in slabinfo.
> 
> Each time the port was opened, dma_request_slave_channel() was called.
> Then, in at_dma_xlate(), atslave was allocated with devm_kzalloc() and
> never freed. (Well, it was free at module unload, but that's not what we
> want).
> So, here, kzalloc is more suited for the job since it has to be freed in
> atc_free_chan_resources().
> 
> Cc: stable@vger.kernel.org
> Fixes: bbe89c8e3d59 ("at_hdmac: move to generic DMA binding")
> Reported-by: Mario Forner <m.forner@be4energy.com>
> Suggested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

After testing I installed an updated kernel on a production machine, which
worked fine. The memory leak has been repaired successfully.  There have been
no adverse side-effects.

Thank you for providing the patch.

> ---
>  drivers/dma/at_hdmac.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
> index 7cbac6e8c113..1b7f0ca0d5cd 100644
> --- a/drivers/dma/at_hdmac.c
> +++ b/drivers/dma/at_hdmac.c
> @@ -1641,6 +1641,12 @@ static void atc_free_chan_resources(struct dma_chan *chan)
>  	atchan->descs_allocated = 0;
>  	atchan->status = 0;
>  
> +	/*
> +	 * Free atslave allocated in at_dma_xlate()
> +	 */
> +	kfree(chan->private);
> +	chan->private = NULL;
> +
>  	dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
>  }
>  
> @@ -1675,7 +1681,7 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
>  	dma_cap_zero(mask);
>  	dma_cap_set(DMA_SLAVE, mask);
>  
> -	atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL);
> +	atslave = kzalloc(sizeof(*atslave), GFP_KERNEL);
>  	if (!atslave)
>  		return NULL;
>  
>

^ permalink raw reply

* dmaengine: remove DBGFS_FUNC_DECL()
From: Yangtao Li @ 2018-11-30 15:42 UTC (permalink / raw)
  To: dan.j.williams, vkoul, sudeep.dutt, ashutosh.dixit, daniel,
	haojian.zhuang, robert.jarzmik, okaya, andy.gross, david.brown
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-arm-msm,
	linux-soc, Yangtao Li

We already have the DEFINE_SHOW_ATTRIBUTE,There is no need to define
such a macro,so remove DBGFS_FUNC_DECL.Also use macro to simplify some
code.

Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
---
 drivers/dma/amba-pl08x.c     | 14 ++------------
 drivers/dma/mic_x100_dma.c   | 22 +++-------------------
 drivers/dma/pxa_dma.c        | 24 ++++++++++++------------
 drivers/dma/qcom/hidma_dbg.c | 33 ++++++---------------------------
 4 files changed, 23 insertions(+), 70 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 97483df1f82e..fc8c2bab563c 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -2505,24 +2505,14 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
 	return 0;
 }
 
-static int pl08x_debugfs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, pl08x_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations pl08x_debugfs_operations = {
-	.open		= pl08x_debugfs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(pl08x_debugfs);
 
 static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
 {
 	/* Expose a simple debugfs interface to view all clocks */
 	(void) debugfs_create_file(dev_name(&pl08x->adev->dev),
 			S_IFREG | S_IRUGO, NULL, pl08x,
-			&pl08x_debugfs_operations);
+			&pl08x_debugfs_fops);
 }
 
 #else
diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index adfd316db1a8..6a91e28d537d 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -676,7 +676,7 @@ static void mic_dma_dev_unreg(struct mic_dma_device *mic_dma_dev)
 }
 
 /* DEBUGFS CODE */
-static int mic_dma_reg_seq_show(struct seq_file *s, void *pos)
+static int mic_dma_reg_show(struct seq_file *s, void *pos)
 {
 	struct mic_dma_device *mic_dma_dev = s->private;
 	int i, chan_num, first_chan = mic_dma_dev->start_ch;
@@ -707,23 +707,7 @@ static int mic_dma_reg_seq_show(struct seq_file *s, void *pos)
 	return 0;
 }
 
-static int mic_dma_reg_debug_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, mic_dma_reg_seq_show, inode->i_private);
-}
-
-static int mic_dma_reg_debug_release(struct inode *inode, struct file *file)
-{
-	return single_release(inode, file);
-}
-
-static const struct file_operations mic_dma_reg_ops = {
-	.owner   = THIS_MODULE,
-	.open    = mic_dma_reg_debug_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = mic_dma_reg_debug_release
-};
+DEFINE_SHOW_ATTRIBUTE(mic_dma_reg);
 
 /* Debugfs parent dir */
 static struct dentry *mic_dma_dbg;
@@ -747,7 +731,7 @@ static int mic_dma_driver_probe(struct mbus_device *mbdev)
 		if (mic_dma_dev->dbg_dir)
 			debugfs_create_file("mic_dma_reg", 0444,
 					    mic_dma_dev->dbg_dir, mic_dma_dev,
-					    &mic_dma_reg_ops);
+					    &mic_dma_reg_fops);
 	}
 	return 0;
 }
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index 825725057e00..8e1e1b07d32f 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -189,7 +189,7 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param);
 #include <linux/uaccess.h>
 #include <linux/seq_file.h>
 
-static int dbg_show_requester_chan(struct seq_file *s, void *p)
+static int requester_chan_show(struct seq_file *s, void *p)
 {
 	struct pxad_phy *phy = s->private;
 	int i;
@@ -220,7 +220,7 @@ static int is_phys_valid(unsigned long addr)
 #define PXA_DCSR_STR(flag) (dcsr & PXA_DCSR_##flag ? #flag" " : "")
 #define PXA_DCMD_STR(flag) (dcmd & PXA_DCMD_##flag ? #flag" " : "")
 
-static int dbg_show_descriptors(struct seq_file *s, void *p)
+static int descriptors_show(struct seq_file *s, void *p)
 {
 	struct pxad_phy *phy = s->private;
 	int i, max_show = 20, burst, width;
@@ -263,7 +263,7 @@ static int dbg_show_descriptors(struct seq_file *s, void *p)
 	return 0;
 }
 
-static int dbg_show_chan_state(struct seq_file *s, void *p)
+static int chan_state_show(struct seq_file *s, void *p)
 {
 	struct pxad_phy *phy = s->private;
 	u32 dcsr, dcmd;
@@ -306,7 +306,7 @@ static int dbg_show_chan_state(struct seq_file *s, void *p)
 	return 0;
 }
 
-static int dbg_show_state(struct seq_file *s, void *p)
+static int state_show(struct seq_file *s, void *p)
 {
 	struct pxad_device *pdev = s->private;
 
@@ -329,10 +329,10 @@ static const struct file_operations dbg_fops_##name = { \
 	.release	= single_release, \
 }
 
-DBGFS_FUNC_DECL(state);
-DBGFS_FUNC_DECL(chan_state);
-DBGFS_FUNC_DECL(descriptors);
-DBGFS_FUNC_DECL(requester_chan);
+DEFINE_SHOW_ATTRIBUTE(state);
+DEFINE_SHOW_ATTRIBUTE(chan_state);
+DEFINE_SHOW_ATTRIBUTE(descriptors);
+DEFINE_SHOW_ATTRIBUTE(requester_chan);
 
 static struct dentry *pxad_dbg_alloc_chan(struct pxad_device *pdev,
 					     int ch, struct dentry *chandir)
@@ -348,13 +348,13 @@ static struct dentry *pxad_dbg_alloc_chan(struct pxad_device *pdev,
 
 	if (chan)
 		chan_state = debugfs_create_file("state", 0400, chan, dt,
-						 &dbg_fops_chan_state);
+						 &chan_state_fops);
 	if (chan_state)
 		chan_descr = debugfs_create_file("descriptors", 0400, chan, dt,
-						 &dbg_fops_descriptors);
+						 &descriptors_fops);
 	if (chan_descr)
 		chan_reqs = debugfs_create_file("requesters", 0400, chan, dt,
-						&dbg_fops_requester_chan);
+						&requester_chan_fops);
 	if (!chan_reqs)
 		goto err_state;
 
@@ -375,7 +375,7 @@ static void pxad_init_debugfs(struct pxad_device *pdev)
 		goto err_root;
 
 	pdev->dbgfs_state = debugfs_create_file("state", 0400, pdev->dbgfs_root,
-						pdev, &dbg_fops_state);
+						pdev, &state_fops);
 	if (!pdev->dbgfs_state)
 		goto err_state;
 
diff --git a/drivers/dma/qcom/hidma_dbg.c b/drivers/dma/qcom/hidma_dbg.c
index 3bdcb8056a36..9523faf7acdc 100644
--- a/drivers/dma/qcom/hidma_dbg.c
+++ b/drivers/dma/qcom/hidma_dbg.c
@@ -85,11 +85,11 @@ static void hidma_ll_devstats(struct seq_file *s, void *llhndl)
 }
 
 /*
- * hidma_chan_stats: display HIDMA channel statistics
+ * hidma_chan_show: display HIDMA channel statistics
  *
  * Display the statistics for the current HIDMA virtual channel device.
  */
-static int hidma_chan_stats(struct seq_file *s, void *unused)
+static int hidma_chan_show(struct seq_file *s, void *unused)
 {
 	struct hidma_chan *mchan = s->private;
 	struct hidma_desc *mdesc;
@@ -117,11 +117,11 @@ static int hidma_chan_stats(struct seq_file *s, void *unused)
 }
 
 /*
- * hidma_dma_info: display HIDMA device info
+ * hidma_dma_show: display HIDMA device info
  *
  * Display the info for the current HIDMA device.
  */
-static int hidma_dma_info(struct seq_file *s, void *unused)
+static int hidma_dma_show(struct seq_file *s, void *unused)
 {
 	struct hidma_dev *dmadev = s->private;
 	resource_size_t sz;
@@ -138,29 +138,8 @@ static int hidma_dma_info(struct seq_file *s, void *unused)
 	return 0;
 }
 
-static int hidma_chan_stats_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, hidma_chan_stats, inode->i_private);
-}
-
-static int hidma_dma_info_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, hidma_dma_info, inode->i_private);
-}
-
-static const struct file_operations hidma_chan_fops = {
-	.open = hidma_chan_stats_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations hidma_dma_fops = {
-	.open = hidma_dma_info_open,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(hidma_chan);
+DEFINE_SHOW_ATTRIBUTE(hidma_dma);
 
 void hidma_debug_uninit(struct hidma_dev *dmadev)
 {

^ permalink raw reply related

* dmaengine: remove DBGFS_FUNC_DECL()
From: Sinan Kaya @ 2018-11-30 15:59 UTC (permalink / raw)
  To: Yangtao Li, dan.j.williams, vkoul, sudeep.dutt, ashutosh.dixit,
	daniel, haojian.zhuang, robert.jarzmik, andy.gross, david.brown
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-arm-msm,
	linux-soc

On 11/30/2018 10:42 AM, Yangtao Li wrote:
> We already have the DEFINE_SHOW_ATTRIBUTE,There is no need to define
> such a macro,so remove DBGFS_FUNC_DECL.Also use macro to simplify some
> code.
> 
> Signed-off-by: Yangtao Li<tiny.windzz@gmail.com>
> ---
>   drivers/dma/amba-pl08x.c     | 14 ++------------
>   drivers/dma/mic_x100_dma.c   | 22 +++-------------------
>   drivers/dma/pxa_dma.c        | 24 ++++++++++++------------
>   drivers/dma/qcom/hidma_dbg.c | 33 ++++++---------------------------

Acked-by: Sinan Kaya <okaya@kernel.org> for drivers/dma/qcom/hidma_dbg.c

>   4 files changed, 23 insertions(+), 70 deletions(-)

^ permalink raw reply

* dmaengine: remove DBGFS_FUNC_DECL()
From: Robert Jarzmik @ 2018-11-30 19:18 UTC (permalink / raw)
  To: Sinan Kaya
  Cc: Yangtao Li, dan.j.williams, vkoul, sudeep.dutt, ashutosh.dixit,
	daniel, haojian.zhuang, andy.gross, david.brown, dmaengine,
	linux-kernel, linux-arm-kernel, linux-arm-msm, linux-soc

Sinan Kaya <okaya@kernel.org> writes:

> On 11/30/2018 10:42 AM, Yangtao Li wrote:
>> We already have the DEFINE_SHOW_ATTRIBUTE,There is no need to define
>> such a macro,so remove DBGFS_FUNC_DECL.Also use macro to simplify some
>> code.
>>
>> Signed-off-by: Yangtao Li<tiny.windzz@gmail.com>
>> ---
>>   drivers/dma/amba-pl08x.c     | 14 ++------------
>>   drivers/dma/mic_x100_dma.c   | 22 +++-------------------
>>   drivers/dma/pxa_dma.c        | 24 ++++++++++++------------
>>   drivers/dma/qcom/hidma_dbg.c | 33 ++++++---------------------------

For pxa_dma:
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>

Cheers.

^ permalink raw reply

* [v1,1/5] dmaengine: dw: Fix FIFO size for Intel Merrifield
From: Andy Shevchenko @ 2018-11-30 20:36 UTC (permalink / raw)
  To: Viresh Kumar, dmaengine, Vinod Koul; +Cc: Andy Shevchenko, stable

Intel Merrifield has a reduced size of FIFO used in iDMA 32-bit controller,
i.e. 512 bytes instead of 1024.

Fix this by partitioning it as 64 bytes per channel.

Note, in the future we might switch to 'fifo-size' property instead of
hard coded value.

Fixes: 199244d69458 ("dmaengine: dw: add support of iDMA 32-bit hardware")
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/dw/core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index d0c3e50b39fb..e85b078fc207 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -1059,12 +1059,12 @@ static void dwc_issue_pending(struct dma_chan *chan)
 /*
  * Program FIFO size of channels.
  *
- * By default full FIFO (1024 bytes) is assigned to channel 0. Here we
+ * By default full FIFO (512 bytes) is assigned to channel 0. Here we
  * slice FIFO on equal parts between channels.
  */
 static void idma32_fifo_partition(struct dw_dma *dw)
 {
-	u64 value = IDMA32C_FP_PSIZE_CH0(128) | IDMA32C_FP_PSIZE_CH1(128) |
+	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
 		    IDMA32C_FP_UPDATE;
 	u64 fifo_partition = 0;
 

^ permalink raw reply related

* [v1,2/5] dmaengine: dw: Add missed multi-block support for iDMA 32-bit
From: Andy Shevchenko @ 2018-11-30 20:36 UTC (permalink / raw)
  To: Viresh Kumar, dmaengine, Vinod Koul; +Cc: Andy Shevchenko, stable

Intel integrated DMA 32-bit support multi-block transfers.
Add missed setting to the platform data.

Fixes: f7c799e950f9 ("dmaengine: dw: we do support Merrifield SoC in PCI mode")
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/dw/pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
index 7778ed705a1a..61f2274f6dd4 100644
--- a/drivers/dma/dw/pci.c
+++ b/drivers/dma/dw/pci.c
@@ -25,6 +25,7 @@ static struct dw_dma_platform_data mrfld_pdata = {
 	.block_size = 131071,
 	.nr_masters = 1,
 	.data_width = {4},
+	.multi_block = {true, true, true, true, true, true, true, true},
 };
 
 static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)

^ permalink raw reply related

* [v1,3/5] dmaengine: dw: Split DW and iDMA 32-bit operations
From: Andy Shevchenko @ 2018-11-30 20:36 UTC (permalink / raw)
  To: Viresh Kumar, dmaengine, Vinod Koul; +Cc: Andy Shevchenko

Here is a kinda big refactoring that should have been done
in the first place, when Intel iDMA 32-bit support appeared.

It splits operations which are different to Synopsys DesignWare and
Intel iDMA 32-bit controllers.

No functional change intended.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw/Makefile              |   2 +-
 drivers/dma/dw/core.c                | 188 +++++----------------------
 drivers/dma/dw/dw.c                  | 109 ++++++++++++++++
 drivers/dma/dw/idma32.c              | 137 +++++++++++++++++++
 drivers/dma/dw/internal.h            |  10 +-
 drivers/dma/dw/pci.c                 |  45 ++++---
 drivers/dma/dw/platform.c            |   8 +-
 drivers/dma/dw/regs.h                |  13 ++
 include/linux/dma/dw.h               |   4 +
 include/linux/platform_data/dma-dw.h |   2 -
 10 files changed, 339 insertions(+), 179 deletions(-)
 create mode 100644 drivers/dma/dw/dw.c
 create mode 100644 drivers/dma/dw/idma32.c

diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile
index 2b949c2e4504..63ed895c09aa 100644
--- a/drivers/dma/dw/Makefile
+++ b/drivers/dma/dw/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DW_DMAC_CORE)	+= dw_dmac_core.o
-dw_dmac_core-objs	:= core.o
+dw_dmac_core-objs	:= core.o dw.o idma32.o
 
 obj-$(CONFIG_DW_DMAC)		+= dw_dmac.o
 dw_dmac-objs		:= platform.o
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index e85b078fc207..711f4d19bbf1 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -138,42 +138,6 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
 	dwc->descs_allocated--;
 }
 
-static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc)
-{
-	u32 cfghi = 0;
-	u32 cfglo = 0;
-
-	/* Set default burst alignment */
-	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
-
-	/* Low 4 bits of the request lines */
-	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
-	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
-
-	/* Request line extension (2 bits) */
-	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
-	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
-
-	channel_writel(dwc, CFG_LO, cfglo);
-	channel_writel(dwc, CFG_HI, cfghi);
-}
-
-static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc)
-{
-	u32 cfghi = DWC_CFGH_FIFO_MODE;
-	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
-	bool hs_polarity = dwc->dws.hs_polarity;
-
-	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
-	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
-
-	/* Set polarity of handshake interface */
-	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
-
-	channel_writel(dwc, CFG_LO, cfglo);
-	channel_writel(dwc, CFG_HI, cfghi);
-}
-
 static void dwc_initialize(struct dw_dma_chan *dwc)
 {
 	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
@@ -181,10 +145,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
 	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
 		return;
 
-	if (dw->pdata->is_idma32)
-		dwc_initialize_chan_idma32(dwc);
-	else
-		dwc_initialize_chan_dw(dwc);
+	dw->initialize_chan(dwc);
 
 	/* Enable interrupts */
 	channel_set_bit(dw, MASK.XFER, dwc->mask);
@@ -213,37 +174,6 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
 		cpu_relax();
 }
 
-static u32 bytes2block(struct dw_dma_chan *dwc, size_t bytes,
-			  unsigned int width, size_t *len)
-{
-	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
-	u32 block;
-
-	/* Always in bytes for iDMA 32-bit */
-	if (dw->pdata->is_idma32)
-		width = 0;
-
-	if ((bytes >> width) > dwc->block_size) {
-		block = dwc->block_size;
-		*len = block << width;
-	} else {
-		block = bytes >> width;
-		*len = bytes;
-	}
-
-	return block;
-}
-
-static size_t block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
-{
-	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
-
-	if (dw->pdata->is_idma32)
-		return IDMA32C_CTLH_BLOCK_TS(block);
-
-	return DWC_CTLH_BLOCK_TS(block) << width;
-}
-
 /*----------------------------------------------------------------------*/
 
 /* Perform single block transfer */
@@ -389,10 +319,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
 /* Returns how many bytes were already received from source */
 static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
 {
+	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
 	u32 ctlhi = channel_readl(dwc, CTL_HI);
 	u32 ctllo = channel_readl(dwc, CTL_LO);
 
-	return block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
+	return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
 }
 
 static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
@@ -649,7 +580,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	unsigned int		src_width;
 	unsigned int		dst_width;
 	unsigned int		data_width = dw->pdata->data_width[m_master];
-	u32			ctllo;
+	u32			ctllo, ctlhi;
 	u8			lms = DWC_LLP_LMS(m_master);
 
 	dev_vdbg(chan2dev(chan),
@@ -678,10 +609,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		if (!desc)
 			goto err_desc_get;
 
+		ctlhi = dw->bytes2block(dwc, len - offset, src_width, &xfer_count);
+
 		lli_write(desc, sar, src + offset);
 		lli_write(desc, dar, dest + offset);
 		lli_write(desc, ctllo, ctllo);
-		lli_write(desc, ctlhi, bytes2block(dwc, len - offset, src_width, &xfer_count));
+		lli_write(desc, ctlhi, ctlhi);
 		desc->len = xfer_count;
 
 		if (!first) {
@@ -719,7 +652,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
 	struct dw_desc		*prev;
 	struct dw_desc		*first;
-	u32			ctllo;
+	u32			ctllo, ctlhi;
 	u8			m_master = dwc->dws.m_master;
 	u8			lms = DWC_LLP_LMS(m_master);
 	dma_addr_t		reg;
@@ -766,9 +699,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			if (!desc)
 				goto err_desc_get;
 
+			ctlhi = dw->bytes2block(dwc, len, mem_width, &dlen);
+
 			lli_write(desc, sar, mem);
 			lli_write(desc, dar, reg);
-			lli_write(desc, ctlhi, bytes2block(dwc, len, mem_width, &dlen));
+			lli_write(desc, ctlhi, ctlhi);
 			lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
 			desc->len = dlen;
 
@@ -812,9 +747,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			if (!desc)
 				goto err_desc_get;
 
+			ctlhi = dw->bytes2block(dwc, len, reg_width, &dlen);
+
 			lli_write(desc, sar, reg);
 			lli_write(desc, dar, mem);
-			lli_write(desc, ctlhi, bytes2block(dwc, len, reg_width, &dlen));
+			lli_write(desc, ctlhi, ctlhi);
 			mem_width = __ffs(data_width | mem | dlen);
 			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
 			desc->len = dlen;
@@ -874,22 +811,12 @@ EXPORT_SYMBOL_GPL(dw_dma_filter);
 static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
 	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
-	struct dma_slave_config *sc = &dwc->dma_sconfig;
 	struct dw_dma *dw = to_dw_dma(chan->device);
-	/*
-	 * Fix sconfig's burst size according to dw_dmac. We need to convert
-	 * them as:
-	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
-	 *
-	 * NOTE: burst size 2 is not supported by DesignWare controller.
-	 *       iDMA 32-bit supports it.
-	 */
-	u32 s = dw->pdata->is_idma32 ? 1 : 2;
 
 	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
 
-	sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
-	sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;
+	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
+	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
 
 	return 0;
 }
@@ -898,16 +825,9 @@ static void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain)
 {
 	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
 	unsigned int		count = 20;	/* timeout iterations */
-	u32			cfglo;
 
-	cfglo = channel_readl(dwc, CFG_LO);
-	if (dw->pdata->is_idma32) {
-		if (drain)
-			cfglo |= IDMA32C_CFGL_CH_DRAIN;
-		else
-			cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
-	}
-	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
+	dw->suspend_chan(dwc, drain);
+
 	while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
 		udelay(2);
 
@@ -1056,33 +976,7 @@ static void dwc_issue_pending(struct dma_chan *chan)
 
 /*----------------------------------------------------------------------*/
 
-/*
- * Program FIFO size of channels.
- *
- * By default full FIFO (512 bytes) is assigned to channel 0. Here we
- * slice FIFO on equal parts between channels.
- */
-static void idma32_fifo_partition(struct dw_dma *dw)
-{
-	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
-		    IDMA32C_FP_UPDATE;
-	u64 fifo_partition = 0;
-
-	if (!dw->pdata->is_idma32)
-		return;
-
-	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
-	fifo_partition |= value << 0;
-
-	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
-	fifo_partition |= value << 32;
-
-	/* Program FIFO Partition registers - 128 bytes for each channel */
-	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
-	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
-}
-
-static void dw_dma_off(struct dw_dma *dw)
+void do_dma_off(struct dw_dma *dw)
 {
 	unsigned int i;
 
@@ -1101,7 +995,7 @@ static void dw_dma_off(struct dw_dma *dw)
 		clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags);
 }
 
-static void dw_dma_on(struct dw_dma *dw)
+void do_dma_on(struct dw_dma *dw)
 {
 	dma_writel(dw, CFG, DW_CFG_DMA_EN);
 }
@@ -1137,7 +1031,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
 
 	/* Enable controller here if needed */
 	if (!dw->in_use)
-		dw_dma_on(dw);
+		do_dma_on(dw);
 	dw->in_use |= dwc->mask;
 
 	return 0;
@@ -1175,30 +1069,25 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
 	/* Disable controller in case it was a last user */
 	dw->in_use &= ~dwc->mask;
 	if (!dw->in_use)
-		dw_dma_off(dw);
+		do_dma_off(dw);
 
 	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
 }
 
-int dw_dma_probe(struct dw_dma_chip *chip)
+int do_dma_probe(struct dw_dma_chip *chip)
 {
+	struct dw_dma *dw = chip->dw;
 	struct dw_dma_platform_data *pdata;
-	struct dw_dma		*dw;
 	bool			autocfg = false;
 	unsigned int		dw_params;
 	unsigned int		i;
 	int			err;
 
-	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
-	if (!dw)
-		return -ENOMEM;
-
 	dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
 	if (!dw->pdata)
 		return -ENOMEM;
 
 	dw->regs = chip->regs;
-	chip->dw = dw;
 
 	pm_runtime_get_sync(chip->dev);
 
@@ -1250,15 +1139,10 @@ int dw_dma_probe(struct dw_dma_chip *chip)
 	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
 
 	/* Force dma off, just in case */
-	dw_dma_off(dw);
-
-	idma32_fifo_partition(dw);
+	dw->disable(dw);
 
 	/* Device and instance ID for IRQ and DMA pool */
-	if (pdata->is_idma32)
-		snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", chip->id);
-	else
-		snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", chip->id);
+	dw->set_device_name(dw, chip->id);
 
 	/* Create a pool of consistent memory blocks for hardware descriptors */
 	dw->desc_pool = dmam_pool_create(dw->name, chip->dev,
@@ -1382,16 +1266,15 @@ int dw_dma_probe(struct dw_dma_chip *chip)
 	pm_runtime_put_sync_suspend(chip->dev);
 	return err;
 }
-EXPORT_SYMBOL_GPL(dw_dma_probe);
 
-int dw_dma_remove(struct dw_dma_chip *chip)
+int do_dma_remove(struct dw_dma_chip *chip)
 {
 	struct dw_dma		*dw = chip->dw;
 	struct dw_dma_chan	*dwc, *_dwc;
 
 	pm_runtime_get_sync(chip->dev);
 
-	dw_dma_off(dw);
+	do_dma_off(dw);
 	dma_async_device_unregister(&dw->dma);
 
 	free_irq(chip->irq, dw);
@@ -1406,27 +1289,24 @@ int dw_dma_remove(struct dw_dma_chip *chip)
 	pm_runtime_put_sync_suspend(chip->dev);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(dw_dma_remove);
 
-int dw_dma_disable(struct dw_dma_chip *chip)
+int do_dw_dma_disable(struct dw_dma_chip *chip)
 {
 	struct dw_dma *dw = chip->dw;
 
-	dw_dma_off(dw);
+	dw->disable(dw);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(dw_dma_disable);
+EXPORT_SYMBOL_GPL(do_dw_dma_disable);
 
-int dw_dma_enable(struct dw_dma_chip *chip)
+int do_dw_dma_enable(struct dw_dma_chip *chip)
 {
 	struct dw_dma *dw = chip->dw;
 
-	idma32_fifo_partition(dw);
-
-	dw_dma_on(dw);
+	dw->disable(dw);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(dw_dma_enable);
+EXPORT_SYMBOL_GPL(do_dw_dma_enable);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c
new file mode 100644
index 000000000000..998a9eeb561d
--- /dev/null
+++ b/drivers/dma/dw/dw.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2007-2008 Atmel Corporation
+// Copyright (C) 2010-2011 ST Microelectronics
+// Copyright (C) 2013,2018 Intel Corporation
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static void dw_dma_initialize_chan(struct dw_dma_chan *dwc)
+{
+	u32 cfghi = DWC_CFGH_FIFO_MODE;
+	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
+	bool hs_polarity = dwc->dws.hs_polarity;
+
+	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
+	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
+
+	/* Set polarity of handshake interface */
+	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
+
+	channel_writel(dwc, CFG_LO, cfglo);
+	channel_writel(dwc, CFG_HI, cfghi);
+}
+
+static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain)
+{
+	u32 cfglo = channel_readl(dwc, CFG_LO);
+
+	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
+}
+
+static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc,
+			      size_t bytes, unsigned int width, size_t *len)
+{
+	u32 block;
+
+	if ((bytes >> width) > dwc->block_size) {
+		block = dwc->block_size;
+		*len = block << width;
+	} else {
+		block = bytes >> width;
+		*len = bytes;
+	}
+
+	return block;
+}
+
+static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
+{
+	return DWC_CTLH_BLOCK_TS(block) << width;
+}
+
+static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
+{
+	/*
+	 * Fix burst size according to dw_dmac. We need to convert them as:
+	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+	 */
+	*maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0;
+}
+
+static void dw_dma_set_device_name(struct dw_dma *dw, int id)
+{
+	snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", id);
+}
+
+static void dw_dma_disable(struct dw_dma *dw)
+{
+	do_dma_off(dw);
+}
+
+static void dw_dma_enable(struct dw_dma *dw)
+{
+	do_dma_on(dw);
+}
+
+int dw_dma_probe(struct dw_dma_chip *chip)
+{
+	struct dw_dma *dw;
+
+	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	/* Channel operations */
+	dw->initialize_chan = dw_dma_initialize_chan;
+	dw->suspend_chan = dw_dma_suspend_chan;
+	dw->encode_maxburst = dw_dma_encode_maxburst;
+	dw->bytes2block = dw_dma_bytes2block;
+	dw->block2bytes = dw_dma_block2bytes;
+
+	/* Device operations */
+	dw->set_device_name = dw_dma_set_device_name;
+	dw->disable = dw_dma_disable;
+	dw->enable = dw_dma_enable;
+
+	chip->dw = dw;
+	return do_dma_probe(chip);
+}
+EXPORT_SYMBOL_GPL(dw_dma_probe);
+
+int dw_dma_remove(struct dw_dma_chip *chip)
+{
+	return do_dma_remove(chip);
+}
+EXPORT_SYMBOL_GPL(dw_dma_remove);
diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c
new file mode 100644
index 000000000000..d06fb00fb862
--- /dev/null
+++ b/drivers/dma/dw/idma32.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2013,2018 Intel Corporation
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static void idma32_initialize_chan(struct dw_dma_chan *dwc)
+{
+	u32 cfghi = 0;
+	u32 cfglo = 0;
+
+	/* Set default burst alignment */
+	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
+
+	/* Low 4 bits of the request lines */
+	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
+	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
+
+	/* Request line extension (2 bits) */
+	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
+	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
+
+	channel_writel(dwc, CFG_LO, cfglo);
+	channel_writel(dwc, CFG_HI, cfghi);
+}
+
+static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain)
+{
+	u32 cfglo = channel_readl(dwc, CFG_LO);
+
+	if (drain)
+		cfglo |= IDMA32C_CFGL_CH_DRAIN;
+	else
+		cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
+
+	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
+}
+
+static u32 idma32_bytes2block(struct dw_dma_chan *dwc,
+			      size_t bytes, unsigned int width, size_t *len)
+{
+	u32 block;
+
+	if (bytes > dwc->block_size) {
+		block = dwc->block_size;
+		*len = dwc->block_size;
+	} else {
+		block = bytes;
+		*len = bytes;
+	}
+
+	return block;
+}
+
+static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
+{
+	return IDMA32C_CTLH_BLOCK_TS(block);
+}
+
+static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
+{
+	*maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0;
+}
+
+static void idma32_set_device_name(struct dw_dma *dw, int id)
+{
+	snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", id);
+}
+
+/*
+ * Program FIFO size of channels.
+ *
+ * By default full FIFO (512 bytes) is assigned to channel 0. Here we
+ * slice FIFO on equal parts between channels.
+ */
+static void idma32_fifo_partition(struct dw_dma *dw)
+{
+	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
+		    IDMA32C_FP_UPDATE;
+	u64 fifo_partition = 0;
+
+	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
+	fifo_partition |= value << 0;
+
+	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
+	fifo_partition |= value << 32;
+
+	/* Program FIFO Partition registers - 128 bytes for each channel */
+	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
+	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
+}
+
+static void idma32_disable(struct dw_dma *dw)
+{
+	do_dma_off(dw);
+	idma32_fifo_partition(dw);
+}
+
+static void idma32_enable(struct dw_dma *dw)
+{
+	idma32_fifo_partition(dw);
+	do_dma_on(dw);
+}
+
+int idma32_dma_probe(struct dw_dma_chip *chip)
+{
+	struct dw_dma *dw;
+
+	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
+	if (!dw)
+		return -ENOMEM;
+
+	/* Channel operations */
+	dw->initialize_chan = idma32_initialize_chan;
+	dw->suspend_chan = idma32_suspend_chan;
+	dw->encode_maxburst = idma32_encode_maxburst;
+	dw->bytes2block = idma32_bytes2block;
+	dw->block2bytes = idma32_block2bytes;
+
+	/* Device operations */
+	dw->set_device_name = idma32_set_device_name;
+	dw->disable = idma32_disable;
+	dw->enable = idma32_enable;
+
+	chip->dw = dw;
+	return do_dma_probe(chip);
+}
+EXPORT_SYMBOL_GPL(idma32_dma_probe);
+
+int idma32_dma_remove(struct dw_dma_chip *chip)
+{
+	return do_dma_remove(chip);
+}
+EXPORT_SYMBOL_GPL(idma32_dma_remove);
diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h
index 41439732ff6b..1f2ddfe745bb 100644
--- a/drivers/dma/dw/internal.h
+++ b/drivers/dma/dw/internal.h
@@ -15,8 +15,14 @@
 
 #include "regs.h"
 
-int dw_dma_disable(struct dw_dma_chip *chip);
-int dw_dma_enable(struct dw_dma_chip *chip);
+int do_dma_probe(struct dw_dma_chip *chip);
+int do_dma_remove(struct dw_dma_chip *chip);
+
+void do_dma_on(struct dw_dma *dw);
+void do_dma_off(struct dw_dma *dw);
+
+int do_dw_dma_disable(struct dw_dma_chip *chip);
+int do_dw_dma_enable(struct dw_dma_chip *chip);
 
 extern bool dw_dma_filter(struct dma_chan *chan, void *param);
 
diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
index 61f2274f6dd4..f5ea58cc027b 100644
--- a/drivers/dma/dw/pci.c
+++ b/drivers/dma/dw/pci.c
@@ -15,11 +15,19 @@
 
 #include "internal.h"
 
-static struct dw_dma_platform_data mrfld_pdata = {
+static struct dw_dma_pci_data {
+	const struct dw_dma_platform_data *pdata;
+	int (*probe)(struct dw_dma_chip *chip);
+};
+
+static const struct dw_dma_pci_data dw_pci_data = {
+	.probe = dw_dma_probe,
+};
+
+static const struct dw_dma_platform_data idma32_pdata = {
 	.nr_channels = 8,
 	.is_private = true,
 	.is_memcpy = true,
-	.is_idma32 = true,
 	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
 	.chan_priority = CHAN_PRIORITY_ASCENDING,
 	.block_size = 131071,
@@ -28,9 +36,14 @@ static struct dw_dma_platform_data mrfld_pdata = {
 	.multi_block = {true, true, true, true, true, true, true, true},
 };
 
+static const struct dw_dma_pci_data idma32_pci_data = {
+	.pdata = &idma32_pdata,
+	.probe = idma32_dma_probe,
+};
+
 static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
-	const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
+	const struct dw_dma_pci_data *data = (void *)pid->driver_data;
 	struct dw_dma_chip *chip;
 	int ret;
 
@@ -63,9 +76,9 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 	chip->id = pdev->devfn;
 	chip->regs = pcim_iomap_table(pdev)[0];
 	chip->irq = pdev->irq;
-	chip->pdata = pdata;
+	chip->pdata = data->pdata;
 
-	ret = dw_dma_probe(chip);
+	ret = data->probe(chip);
 	if (ret)
 		return ret;
 
@@ -91,7 +104,7 @@ static int dw_pci_suspend_late(struct device *dev)
 	struct pci_dev *pci = to_pci_dev(dev);
 	struct dw_dma_chip *chip = pci_get_drvdata(pci);
 
-	return dw_dma_disable(chip);
+	return do_dw_dma_disable(chip);
 };
 
 static int dw_pci_resume_early(struct device *dev)
@@ -99,7 +112,7 @@ static int dw_pci_resume_early(struct device *dev)
 	struct pci_dev *pci = to_pci_dev(dev);
 	struct dw_dma_chip *chip = pci_get_drvdata(pci);
 
-	return dw_dma_enable(chip);
+	return do_dw_dma_enable(chip);
 };
 
 #endif /* CONFIG_PM_SLEEP */
@@ -110,24 +123,24 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
 
 static const struct pci_device_id dw_pci_id_table[] = {
 	/* Medfield (GPDMA) */
-	{ PCI_VDEVICE(INTEL, 0x0827) },
+	{ PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data },
 
 	/* BayTrail */
-	{ PCI_VDEVICE(INTEL, 0x0f06) },
-	{ PCI_VDEVICE(INTEL, 0x0f40) },
+	{ PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data },
+	{ PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data },
 
-	/* Merrifield iDMA 32-bit (GPDMA) */
-	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&mrfld_pdata },
+	/* Merrifield */
+	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data },
 
 	/* Braswell */
-	{ PCI_VDEVICE(INTEL, 0x2286) },
-	{ PCI_VDEVICE(INTEL, 0x22c0) },
+	{ PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data },
+	{ PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data },
 
 	/* Haswell */
-	{ PCI_VDEVICE(INTEL, 0x9c60) },
+	{ PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data },
 
 	/* Broadwell */
-	{ PCI_VDEVICE(INTEL, 0x9ce0) },
+	{ PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data },
 
 	{ }
 };
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index f01b2c173fa6..6bf46c9b7ee4 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -258,7 +258,7 @@ static void dw_shutdown(struct platform_device *pdev)
 	struct dw_dma_chip *chip = platform_get_drvdata(pdev);
 
 	/*
-	 * We have to call dw_dma_disable() to stop any ongoing transfer. On
+	 * We have to call do_dw_dma_disable() to stop any ongoing transfer. On
 	 * some platforms we can't do that since DMA device is powered off.
 	 * Moreover we have no possibility to check if the platform is affected
 	 * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put()
@@ -267,7 +267,7 @@ static void dw_shutdown(struct platform_device *pdev)
 	 * used by the driver.
 	 */
 	pm_runtime_get_sync(chip->dev);
-	dw_dma_disable(chip);
+	do_dw_dma_disable(chip);
 	pm_runtime_put_sync_suspend(chip->dev);
 
 	clk_disable_unprepare(chip->clk);
@@ -297,7 +297,7 @@ static int dw_suspend_late(struct device *dev)
 {
 	struct dw_dma_chip *chip = dev_get_drvdata(dev);
 
-	dw_dma_disable(chip);
+	do_dw_dma_disable(chip);
 	clk_disable_unprepare(chip->clk);
 
 	return 0;
@@ -312,7 +312,7 @@ static int dw_resume_early(struct device *dev)
 	if (ret)
 		return ret;
 
-	return dw_dma_enable(chip);
+	return do_dw_dma_enable(chip);
 }
 
 #endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 09e7dfdbb790..90e46e69c047 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -308,6 +308,19 @@ struct dw_dma {
 	u8			all_chan_mask;
 	u8			in_use;
 
+	/* Channel operations */
+	void	(*initialize_chan)(struct dw_dma_chan *dwc);
+	void	(*suspend_chan)(struct dw_dma_chan *dwc, bool drain);
+	void	(*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst);
+	u32	(*bytes2block)(struct dw_dma_chan *dwc, size_t bytes,
+			       unsigned int width, size_t *len);
+	size_t	(*block2bytes)(struct dw_dma_chan *dwc, u32 block, u32 width);
+
+	/* Device operations */
+	void (*set_device_name)(struct dw_dma *dw, int id);
+	void (*disable)(struct dw_dma *dw);
+	void (*enable)(struct dw_dma *dw);
+
 	/* platform data */
 	struct dw_dma_platform_data	*pdata;
 };
diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h
index e166cac8e870..d643d331c20e 100644
--- a/include/linux/dma/dw.h
+++ b/include/linux/dma/dw.h
@@ -45,9 +45,13 @@ struct dw_dma_chip {
 #if IS_ENABLED(CONFIG_DW_DMAC_CORE)
 int dw_dma_probe(struct dw_dma_chip *chip);
 int dw_dma_remove(struct dw_dma_chip *chip);
+int idma32_dma_probe(struct dw_dma_chip *chip);
+int idma32_dma_remove(struct dw_dma_chip *chip);
 #else
 static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
 static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; }
+static inline int idma32_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
+static inline int idma32_dma_remove(struct dw_dma_chip *chip) { return 0; }
 #endif /* CONFIG_DW_DMAC_CORE */
 
 #endif /* _DMA_DW_H */
diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h
index 896cb71a382c..e69e415d0d98 100644
--- a/include/linux/platform_data/dma-dw.h
+++ b/include/linux/platform_data/dma-dw.h
@@ -41,7 +41,6 @@ struct dw_dma_slave {
  * @is_private: The device channels should be marked as private and not for
  *	by the general purpose DMA channel allocator.
  * @is_memcpy: The device channels do support memory-to-memory transfers.
- * @is_idma32: The type of the DMA controller is iDMA32
  * @chan_allocation_order: Allocate channels starting from 0 or 7
  * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
  * @block_size: Maximum block size supported by the controller
@@ -54,7 +53,6 @@ struct dw_dma_platform_data {
 	unsigned int	nr_channels;
 	bool		is_private;
 	bool		is_memcpy;
-	bool		is_idma32;
 #define CHAN_ALLOCATION_ASCENDING	0	/* zero to seven */
 #define CHAN_ALLOCATION_DESCENDING	1	/* seven to zero */
 	unsigned char	chan_allocation_order;

^ permalink raw reply related

* [v1,4/5] dmaengine: dw: Reset DRAIN bit when resume the channel
From: Andy Shevchenko @ 2018-11-30 20:36 UTC (permalink / raw)
  To: Viresh Kumar, dmaengine, Vinod Koul; +Cc: Andy Shevchenko

For Intel iDMA 32-bit the channel can be drained on a suspend.
We need to reset the bit on the resume to return a status quo.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw/core.c   | 10 +++++-----
 drivers/dma/dw/dw.c     |  8 ++++++++
 drivers/dma/dw/idma32.c | 13 +++++++++++--
 drivers/dma/dw/regs.h   |  1 +
 4 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 711f4d19bbf1..092d642bec83 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -846,11 +846,11 @@ static int dwc_pause(struct dma_chan *chan)
 	return 0;
 }
 
-static inline void dwc_chan_resume(struct dw_dma_chan *dwc)
+static inline void dwc_chan_resume(struct dw_dma_chan *dwc, bool drain)
 {
-	u32 cfglo = channel_readl(dwc, CFG_LO);
+	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
 
-	channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP);
+	dw->resume_chan(dwc, drain);
 
 	clear_bit(DW_DMA_IS_PAUSED, &dwc->flags);
 }
@@ -863,7 +863,7 @@ static int dwc_resume(struct dma_chan *chan)
 	spin_lock_irqsave(&dwc->lock, flags);
 
 	if (test_bit(DW_DMA_IS_PAUSED, &dwc->flags))
-		dwc_chan_resume(dwc);
+		dwc_chan_resume(dwc, false);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -886,7 +886,7 @@ static int dwc_terminate_all(struct dma_chan *chan)
 
 	dwc_chan_disable(dw, dwc);
 
-	dwc_chan_resume(dwc);
+	dwc_chan_resume(dwc, true);
 
 	/* active_list entries will end up before queued entries */
 	list_splice_init(&dwc->queue, &list);
diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c
index 998a9eeb561d..92f1e9c7b6f6 100644
--- a/drivers/dma/dw/dw.c
+++ b/drivers/dma/dw/dw.c
@@ -32,6 +32,13 @@ static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain)
 	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
 }
 
+static void dw_dma_resume_chan(struct dw_dma_chan *dwc, bool drain)
+{
+	u32 cfglo = channel_readl(dwc, CFG_LO);
+
+	channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP);
+}
+
 static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc,
 			      size_t bytes, unsigned int width, size_t *len)
 {
@@ -88,6 +95,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
 	/* Channel operations */
 	dw->initialize_chan = dw_dma_initialize_chan;
 	dw->suspend_chan = dw_dma_suspend_chan;
+	dw->resume_chan = dw_dma_resume_chan;
 	dw->encode_maxburst = dw_dma_encode_maxburst;
 	dw->bytes2block = dw_dma_bytes2block;
 	dw->block2bytes = dw_dma_block2bytes;
diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c
index d06fb00fb862..7c013b257802 100644
--- a/drivers/dma/dw/idma32.c
+++ b/drivers/dma/dw/idma32.c
@@ -33,12 +33,20 @@ static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain)
 
 	if (drain)
 		cfglo |= IDMA32C_CFGL_CH_DRAIN;
-	else
-		cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
 
 	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
 }
 
+static void idma32_resume_chan(struct dw_dma_chan *dwc, bool drain)
+{
+	u32 cfglo = channel_readl(dwc, CFG_LO);
+
+	if (drain)
+		cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
+
+	channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP);
+}
+
 static u32 idma32_bytes2block(struct dw_dma_chan *dwc,
 			      size_t bytes, unsigned int width, size_t *len)
 {
@@ -116,6 +124,7 @@ int idma32_dma_probe(struct dw_dma_chip *chip)
 	/* Channel operations */
 	dw->initialize_chan = idma32_initialize_chan;
 	dw->suspend_chan = idma32_suspend_chan;
+	dw->resume_chan = idma32_resume_chan;
 	dw->encode_maxburst = idma32_encode_maxburst;
 	dw->bytes2block = idma32_bytes2block;
 	dw->block2bytes = idma32_block2bytes;
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 90e46e69c047..bd26c492507b 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -311,6 +311,7 @@ struct dw_dma {
 	/* Channel operations */
 	void	(*initialize_chan)(struct dw_dma_chan *dwc);
 	void	(*suspend_chan)(struct dw_dma_chan *dwc, bool drain);
+	void	(*resume_chan)(struct dw_dma_chan *dwc, bool drain);
 	void	(*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst);
 	u32	(*bytes2block)(struct dw_dma_chan *dwc, size_t bytes,
 			       unsigned int width, size_t *len);

^ permalink raw reply related

* [v1,5/5] dmaengine: dw: convert to SPDX identifiers
From: Andy Shevchenko @ 2018-11-30 20:36 UTC (permalink / raw)
  To: Viresh Kumar, dmaengine, Vinod Koul; +Cc: Andy Shevchenko

This patch updates license to use SPDX-License-Identifier
instead of verbose license text.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/dma/dw/Kconfig               | 2 ++
 drivers/dma/dw/core.c                | 5 +----
 drivers/dma/dw/internal.h            | 5 +----
 drivers/dma/dw/pci.c                 | 5 +----
 drivers/dma/dw/platform.c            | 5 +----
 drivers/dma/dw/regs.h                | 5 +----
 include/linux/dma/dw.h               | 5 +----
 include/linux/platform_data/dma-dw.h | 5 +----
 8 files changed, 9 insertions(+), 28 deletions(-)

diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig
index 04b9728c1d26..e5162690de8f 100644
--- a/drivers/dma/dw/Kconfig
+++ b/drivers/dma/dw/Kconfig
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
 #
 # DMA engine configuration for dw
 #
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 092d642bec83..266fc518b3f1 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Core driver for the Synopsys DesignWare DMA Controller
  *
  * Copyright (C) 2007-2008 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
  * Copyright (C) 2013 Intel Corporation
- *
- * 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.
  */
 
 #include <linux/bitops.h>
diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h
index 1f2ddfe745bb..4e47c8de8ef1 100644
--- a/drivers/dma/dw/internal.h
+++ b/drivers/dma/dw/internal.h
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Driver for the Synopsys DesignWare DMA Controller
  *
  * Copyright (C) 2013 Intel Corporation
- *
- * 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.
  */
 
 #ifndef _DMA_DW_INTERNAL_H
diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
index f5ea58cc027b..d3f2600b52a4 100644
--- a/drivers/dma/dw/pci.c
+++ b/drivers/dma/dw/pci.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * PCI driver for the Synopsys DesignWare DMA Controller
  *
  * Copyright (C) 2013 Intel Corporation
  * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
- *
- * 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.
  */
 
 #include <linux/module.h>
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index 6bf46c9b7ee4..25e693d9a045 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Platform driver for the Synopsys DesignWare DMA Controller
  *
@@ -6,10 +7,6 @@
  * Copyright (C) 2013 Intel Corporation
  *
  * Some parts of this driver are derived from the original dw_dmac.
- *
- * 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.
  */
 
 #include <linux/module.h>
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index bd26c492507b..a556970413dd 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Driver for the Synopsys DesignWare AHB DMA Controller
  *
  * Copyright (C) 2005-2007 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
  * Copyright (C) 2016 Intel Corporation
- *
- * 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.
  */
 
 #include <linux/bitops.h>
diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h
index d643d331c20e..4412073a7f1a 100644
--- a/include/linux/dma/dw.h
+++ b/include/linux/dma/dw.h
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Driver for the Synopsys DesignWare DMA Controller
  *
  * Copyright (C) 2007 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
  * Copyright (C) 2014 Intel Corporation
- *
- * 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.
  */
 #ifndef _DMA_DW_H
 #define _DMA_DW_H
diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h
index e69e415d0d98..9e96ef404d51 100644
--- a/include/linux/platform_data/dma-dw.h
+++ b/include/linux/platform_data/dma-dw.h
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Driver for the Synopsys DesignWare DMA Controller
  *
  * Copyright (C) 2007 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
- *
- * 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.
  */
 #ifndef _PLATFORM_DATA_DMA_DW_H
 #define _PLATFORM_DATA_DMA_DW_H

^ permalink raw reply related

* [v1,3/5] dmaengine: dw: Split DW and iDMA 32-bit operations
From: Andy Shevchenko @ 2018-11-30 20:54 UTC (permalink / raw)
  To: Viresh Kumar, dmaengine, Vinod Koul

On Fri, Nov 30, 2018 at 10:36:44PM +0200, Andy Shevchenko wrote:
> Here is a kinda big refactoring that should have been done
> in the first place, when Intel iDMA 32-bit support appeared.
> 
> It splits operations which are different to Synopsys DesignWare and
> Intel iDMA 32-bit controllers.
> 
> No functional change intended.

While first two are real bug fixes and really small, this one bigger and
suddenly has a typo which I didn't notice during my tests.

Vinod, please, consider applying first two until I will come with better this
one and might be something more.

> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/dma/dw/Makefile              |   2 +-
>  drivers/dma/dw/core.c                | 188 +++++----------------------
>  drivers/dma/dw/dw.c                  | 109 ++++++++++++++++
>  drivers/dma/dw/idma32.c              | 137 +++++++++++++++++++
>  drivers/dma/dw/internal.h            |  10 +-
>  drivers/dma/dw/pci.c                 |  45 ++++---
>  drivers/dma/dw/platform.c            |   8 +-
>  drivers/dma/dw/regs.h                |  13 ++
>  include/linux/dma/dw.h               |   4 +
>  include/linux/platform_data/dma-dw.h |   2 -
>  10 files changed, 339 insertions(+), 179 deletions(-)
>  create mode 100644 drivers/dma/dw/dw.c
>  create mode 100644 drivers/dma/dw/idma32.c
> 
> diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile
> index 2b949c2e4504..63ed895c09aa 100644
> --- a/drivers/dma/dw/Makefile
> +++ b/drivers/dma/dw/Makefile
> @@ -1,6 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  obj-$(CONFIG_DW_DMAC_CORE)	+= dw_dmac_core.o
> -dw_dmac_core-objs	:= core.o
> +dw_dmac_core-objs	:= core.o dw.o idma32.o
>  
>  obj-$(CONFIG_DW_DMAC)		+= dw_dmac.o
>  dw_dmac-objs		:= platform.o
> diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
> index e85b078fc207..711f4d19bbf1 100644
> --- a/drivers/dma/dw/core.c
> +++ b/drivers/dma/dw/core.c
> @@ -138,42 +138,6 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
>  	dwc->descs_allocated--;
>  }
>  
> -static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc)
> -{
> -	u32 cfghi = 0;
> -	u32 cfglo = 0;
> -
> -	/* Set default burst alignment */
> -	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
> -
> -	/* Low 4 bits of the request lines */
> -	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
> -	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
> -
> -	/* Request line extension (2 bits) */
> -	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
> -	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
> -
> -	channel_writel(dwc, CFG_LO, cfglo);
> -	channel_writel(dwc, CFG_HI, cfghi);
> -}
> -
> -static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc)
> -{
> -	u32 cfghi = DWC_CFGH_FIFO_MODE;
> -	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
> -	bool hs_polarity = dwc->dws.hs_polarity;
> -
> -	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
> -	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
> -
> -	/* Set polarity of handshake interface */
> -	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
> -
> -	channel_writel(dwc, CFG_LO, cfglo);
> -	channel_writel(dwc, CFG_HI, cfghi);
> -}
> -
>  static void dwc_initialize(struct dw_dma_chan *dwc)
>  {
>  	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
> @@ -181,10 +145,7 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
>  	if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
>  		return;
>  
> -	if (dw->pdata->is_idma32)
> -		dwc_initialize_chan_idma32(dwc);
> -	else
> -		dwc_initialize_chan_dw(dwc);
> +	dw->initialize_chan(dwc);
>  
>  	/* Enable interrupts */
>  	channel_set_bit(dw, MASK.XFER, dwc->mask);
> @@ -213,37 +174,6 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
>  		cpu_relax();
>  }
>  
> -static u32 bytes2block(struct dw_dma_chan *dwc, size_t bytes,
> -			  unsigned int width, size_t *len)
> -{
> -	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
> -	u32 block;
> -
> -	/* Always in bytes for iDMA 32-bit */
> -	if (dw->pdata->is_idma32)
> -		width = 0;
> -
> -	if ((bytes >> width) > dwc->block_size) {
> -		block = dwc->block_size;
> -		*len = block << width;
> -	} else {
> -		block = bytes >> width;
> -		*len = bytes;
> -	}
> -
> -	return block;
> -}
> -
> -static size_t block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
> -{
> -	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
> -
> -	if (dw->pdata->is_idma32)
> -		return IDMA32C_CTLH_BLOCK_TS(block);
> -
> -	return DWC_CTLH_BLOCK_TS(block) << width;
> -}
> -
>  /*----------------------------------------------------------------------*/
>  
>  /* Perform single block transfer */
> @@ -389,10 +319,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
>  /* Returns how many bytes were already received from source */
>  static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
>  {
> +	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
>  	u32 ctlhi = channel_readl(dwc, CTL_HI);
>  	u32 ctllo = channel_readl(dwc, CTL_LO);
>  
> -	return block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
> +	return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
>  }
>  
>  static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
> @@ -649,7 +580,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>  	unsigned int		src_width;
>  	unsigned int		dst_width;
>  	unsigned int		data_width = dw->pdata->data_width[m_master];
> -	u32			ctllo;
> +	u32			ctllo, ctlhi;
>  	u8			lms = DWC_LLP_LMS(m_master);
>  
>  	dev_vdbg(chan2dev(chan),
> @@ -678,10 +609,12 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>  		if (!desc)
>  			goto err_desc_get;
>  
> +		ctlhi = dw->bytes2block(dwc, len - offset, src_width, &xfer_count);
> +
>  		lli_write(desc, sar, src + offset);
>  		lli_write(desc, dar, dest + offset);
>  		lli_write(desc, ctllo, ctllo);
> -		lli_write(desc, ctlhi, bytes2block(dwc, len - offset, src_width, &xfer_count));
> +		lli_write(desc, ctlhi, ctlhi);
>  		desc->len = xfer_count;
>  
>  		if (!first) {
> @@ -719,7 +652,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>  	struct dma_slave_config	*sconfig = &dwc->dma_sconfig;
>  	struct dw_desc		*prev;
>  	struct dw_desc		*first;
> -	u32			ctllo;
> +	u32			ctllo, ctlhi;
>  	u8			m_master = dwc->dws.m_master;
>  	u8			lms = DWC_LLP_LMS(m_master);
>  	dma_addr_t		reg;
> @@ -766,9 +699,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>  			if (!desc)
>  				goto err_desc_get;
>  
> +			ctlhi = dw->bytes2block(dwc, len, mem_width, &dlen);
> +
>  			lli_write(desc, sar, mem);
>  			lli_write(desc, dar, reg);
> -			lli_write(desc, ctlhi, bytes2block(dwc, len, mem_width, &dlen));
> +			lli_write(desc, ctlhi, ctlhi);
>  			lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
>  			desc->len = dlen;
>  
> @@ -812,9 +747,11 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>  			if (!desc)
>  				goto err_desc_get;
>  
> +			ctlhi = dw->bytes2block(dwc, len, reg_width, &dlen);
> +
>  			lli_write(desc, sar, reg);
>  			lli_write(desc, dar, mem);
> -			lli_write(desc, ctlhi, bytes2block(dwc, len, reg_width, &dlen));
> +			lli_write(desc, ctlhi, ctlhi);
>  			mem_width = __ffs(data_width | mem | dlen);
>  			lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
>  			desc->len = dlen;
> @@ -874,22 +811,12 @@ EXPORT_SYMBOL_GPL(dw_dma_filter);
>  static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
>  {
>  	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
> -	struct dma_slave_config *sc = &dwc->dma_sconfig;
>  	struct dw_dma *dw = to_dw_dma(chan->device);
> -	/*
> -	 * Fix sconfig's burst size according to dw_dmac. We need to convert
> -	 * them as:
> -	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
> -	 *
> -	 * NOTE: burst size 2 is not supported by DesignWare controller.
> -	 *       iDMA 32-bit supports it.
> -	 */
> -	u32 s = dw->pdata->is_idma32 ? 1 : 2;
>  
>  	memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
>  
> -	sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
> -	sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;
> +	dw->encode_maxburst(dwc, &dwc->dma_sconfig.src_maxburst);
> +	dw->encode_maxburst(dwc, &dwc->dma_sconfig.dst_maxburst);
>  
>  	return 0;
>  }
> @@ -898,16 +825,9 @@ static void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain)
>  {
>  	struct dw_dma *dw = to_dw_dma(dwc->chan.device);
>  	unsigned int		count = 20;	/* timeout iterations */
> -	u32			cfglo;
>  
> -	cfglo = channel_readl(dwc, CFG_LO);
> -	if (dw->pdata->is_idma32) {
> -		if (drain)
> -			cfglo |= IDMA32C_CFGL_CH_DRAIN;
> -		else
> -			cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
> -	}
> -	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
> +	dw->suspend_chan(dwc, drain);
> +
>  	while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
>  		udelay(2);
>  
> @@ -1056,33 +976,7 @@ static void dwc_issue_pending(struct dma_chan *chan)
>  
>  /*----------------------------------------------------------------------*/
>  
> -/*
> - * Program FIFO size of channels.
> - *
> - * By default full FIFO (512 bytes) is assigned to channel 0. Here we
> - * slice FIFO on equal parts between channels.
> - */
> -static void idma32_fifo_partition(struct dw_dma *dw)
> -{
> -	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
> -		    IDMA32C_FP_UPDATE;
> -	u64 fifo_partition = 0;
> -
> -	if (!dw->pdata->is_idma32)
> -		return;
> -
> -	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
> -	fifo_partition |= value << 0;
> -
> -	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
> -	fifo_partition |= value << 32;
> -
> -	/* Program FIFO Partition registers - 128 bytes for each channel */
> -	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
> -	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
> -}
> -
> -static void dw_dma_off(struct dw_dma *dw)
> +void do_dma_off(struct dw_dma *dw)
>  {
>  	unsigned int i;
>  
> @@ -1101,7 +995,7 @@ static void dw_dma_off(struct dw_dma *dw)
>  		clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags);
>  }
>  
> -static void dw_dma_on(struct dw_dma *dw)
> +void do_dma_on(struct dw_dma *dw)
>  {
>  	dma_writel(dw, CFG, DW_CFG_DMA_EN);
>  }
> @@ -1137,7 +1031,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
>  
>  	/* Enable controller here if needed */
>  	if (!dw->in_use)
> -		dw_dma_on(dw);
> +		do_dma_on(dw);
>  	dw->in_use |= dwc->mask;
>  
>  	return 0;
> @@ -1175,30 +1069,25 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
>  	/* Disable controller in case it was a last user */
>  	dw->in_use &= ~dwc->mask;
>  	if (!dw->in_use)
> -		dw_dma_off(dw);
> +		do_dma_off(dw);
>  
>  	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
>  }
>  
> -int dw_dma_probe(struct dw_dma_chip *chip)
> +int do_dma_probe(struct dw_dma_chip *chip)
>  {
> +	struct dw_dma *dw = chip->dw;
>  	struct dw_dma_platform_data *pdata;
> -	struct dw_dma		*dw;
>  	bool			autocfg = false;
>  	unsigned int		dw_params;
>  	unsigned int		i;
>  	int			err;
>  
> -	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
> -	if (!dw)
> -		return -ENOMEM;
> -
>  	dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL);
>  	if (!dw->pdata)
>  		return -ENOMEM;
>  
>  	dw->regs = chip->regs;
> -	chip->dw = dw;
>  
>  	pm_runtime_get_sync(chip->dev);
>  
> @@ -1250,15 +1139,10 @@ int dw_dma_probe(struct dw_dma_chip *chip)
>  	dw->all_chan_mask = (1 << pdata->nr_channels) - 1;
>  
>  	/* Force dma off, just in case */
> -	dw_dma_off(dw);
> -
> -	idma32_fifo_partition(dw);
> +	dw->disable(dw);
>  
>  	/* Device and instance ID for IRQ and DMA pool */
> -	if (pdata->is_idma32)
> -		snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", chip->id);
> -	else
> -		snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", chip->id);
> +	dw->set_device_name(dw, chip->id);
>  
>  	/* Create a pool of consistent memory blocks for hardware descriptors */
>  	dw->desc_pool = dmam_pool_create(dw->name, chip->dev,
> @@ -1382,16 +1266,15 @@ int dw_dma_probe(struct dw_dma_chip *chip)
>  	pm_runtime_put_sync_suspend(chip->dev);
>  	return err;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_probe);
>  
> -int dw_dma_remove(struct dw_dma_chip *chip)
> +int do_dma_remove(struct dw_dma_chip *chip)
>  {
>  	struct dw_dma		*dw = chip->dw;
>  	struct dw_dma_chan	*dwc, *_dwc;
>  
>  	pm_runtime_get_sync(chip->dev);
>  
> -	dw_dma_off(dw);
> +	do_dma_off(dw);
>  	dma_async_device_unregister(&dw->dma);
>  
>  	free_irq(chip->irq, dw);
> @@ -1406,27 +1289,24 @@ int dw_dma_remove(struct dw_dma_chip *chip)
>  	pm_runtime_put_sync_suspend(chip->dev);
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_remove);
>  
> -int dw_dma_disable(struct dw_dma_chip *chip)
> +int do_dw_dma_disable(struct dw_dma_chip *chip)
>  {
>  	struct dw_dma *dw = chip->dw;
>  
> -	dw_dma_off(dw);
> +	dw->disable(dw);
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_disable);
> +EXPORT_SYMBOL_GPL(do_dw_dma_disable);
>  
> -int dw_dma_enable(struct dw_dma_chip *chip)
> +int do_dw_dma_enable(struct dw_dma_chip *chip)
>  {
>  	struct dw_dma *dw = chip->dw;
>  
> -	idma32_fifo_partition(dw);
> -
> -	dw_dma_on(dw);
> +	dw->disable(dw);
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(dw_dma_enable);
> +EXPORT_SYMBOL_GPL(do_dw_dma_enable);
>  
>  MODULE_LICENSE("GPL v2");
>  MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
> diff --git a/drivers/dma/dw/dw.c b/drivers/dma/dw/dw.c
> new file mode 100644
> index 000000000000..998a9eeb561d
> --- /dev/null
> +++ b/drivers/dma/dw/dw.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2007-2008 Atmel Corporation
> +// Copyright (C) 2010-2011 ST Microelectronics
> +// Copyright (C) 2013,2018 Intel Corporation
> +
> +#include <linux/bitops.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +
> +#include "internal.h"
> +
> +static void dw_dma_initialize_chan(struct dw_dma_chan *dwc)
> +{
> +	u32 cfghi = DWC_CFGH_FIFO_MODE;
> +	u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
> +	bool hs_polarity = dwc->dws.hs_polarity;
> +
> +	cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
> +	cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
> +
> +	/* Set polarity of handshake interface */
> +	cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
> +
> +	channel_writel(dwc, CFG_LO, cfglo);
> +	channel_writel(dwc, CFG_HI, cfghi);
> +}
> +
> +static void dw_dma_suspend_chan(struct dw_dma_chan *dwc, bool drain)
> +{
> +	u32 cfglo = channel_readl(dwc, CFG_LO);
> +
> +	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
> +}
> +
> +static u32 dw_dma_bytes2block(struct dw_dma_chan *dwc,
> +			      size_t bytes, unsigned int width, size_t *len)
> +{
> +	u32 block;
> +
> +	if ((bytes >> width) > dwc->block_size) {
> +		block = dwc->block_size;
> +		*len = block << width;
> +	} else {
> +		block = bytes >> width;
> +		*len = bytes;
> +	}
> +
> +	return block;
> +}
> +
> +static size_t dw_dma_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
> +{
> +	return DWC_CTLH_BLOCK_TS(block) << width;
> +}
> +
> +static void dw_dma_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
> +{
> +	/*
> +	 * Fix burst size according to dw_dmac. We need to convert them as:
> +	 * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
> +	 */
> +	*maxburst = *maxburst > 1 ? fls(*maxburst) - 2 : 0;
> +}
> +
> +static void dw_dma_set_device_name(struct dw_dma *dw, int id)
> +{
> +	snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", id);
> +}
> +
> +static void dw_dma_disable(struct dw_dma *dw)
> +{
> +	do_dma_off(dw);
> +}
> +
> +static void dw_dma_enable(struct dw_dma *dw)
> +{
> +	do_dma_on(dw);
> +}
> +
> +int dw_dma_probe(struct dw_dma_chip *chip)
> +{
> +	struct dw_dma *dw;
> +
> +	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	/* Channel operations */
> +	dw->initialize_chan = dw_dma_initialize_chan;
> +	dw->suspend_chan = dw_dma_suspend_chan;
> +	dw->encode_maxburst = dw_dma_encode_maxburst;
> +	dw->bytes2block = dw_dma_bytes2block;
> +	dw->block2bytes = dw_dma_block2bytes;
> +
> +	/* Device operations */
> +	dw->set_device_name = dw_dma_set_device_name;
> +	dw->disable = dw_dma_disable;
> +	dw->enable = dw_dma_enable;
> +
> +	chip->dw = dw;
> +	return do_dma_probe(chip);
> +}
> +EXPORT_SYMBOL_GPL(dw_dma_probe);
> +
> +int dw_dma_remove(struct dw_dma_chip *chip)
> +{
> +	return do_dma_remove(chip);
> +}
> +EXPORT_SYMBOL_GPL(dw_dma_remove);
> diff --git a/drivers/dma/dw/idma32.c b/drivers/dma/dw/idma32.c
> new file mode 100644
> index 000000000000..d06fb00fb862
> --- /dev/null
> +++ b/drivers/dma/dw/idma32.c
> @@ -0,0 +1,137 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2013,2018 Intel Corporation
> +
> +#include <linux/bitops.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +
> +#include "internal.h"
> +
> +static void idma32_initialize_chan(struct dw_dma_chan *dwc)
> +{
> +	u32 cfghi = 0;
> +	u32 cfglo = 0;
> +
> +	/* Set default burst alignment */
> +	cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
> +
> +	/* Low 4 bits of the request lines */
> +	cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
> +	cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
> +
> +	/* Request line extension (2 bits) */
> +	cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
> +	cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
> +
> +	channel_writel(dwc, CFG_LO, cfglo);
> +	channel_writel(dwc, CFG_HI, cfghi);
> +}
> +
> +static void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain)
> +{
> +	u32 cfglo = channel_readl(dwc, CFG_LO);
> +
> +	if (drain)
> +		cfglo |= IDMA32C_CFGL_CH_DRAIN;
> +	else
> +		cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
> +
> +	channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
> +}
> +
> +static u32 idma32_bytes2block(struct dw_dma_chan *dwc,
> +			      size_t bytes, unsigned int width, size_t *len)
> +{
> +	u32 block;
> +
> +	if (bytes > dwc->block_size) {
> +		block = dwc->block_size;
> +		*len = dwc->block_size;
> +	} else {
> +		block = bytes;
> +		*len = bytes;
> +	}
> +
> +	return block;
> +}
> +
> +static size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
> +{
> +	return IDMA32C_CTLH_BLOCK_TS(block);
> +}
> +
> +static void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst)
> +{
> +	*maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0;
> +}
> +
> +static void idma32_set_device_name(struct dw_dma *dw, int id)
> +{
> +	snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", id);
> +}
> +
> +/*
> + * Program FIFO size of channels.
> + *
> + * By default full FIFO (512 bytes) is assigned to channel 0. Here we
> + * slice FIFO on equal parts between channels.
> + */
> +static void idma32_fifo_partition(struct dw_dma *dw)
> +{
> +	u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) |
> +		    IDMA32C_FP_UPDATE;
> +	u64 fifo_partition = 0;
> +
> +	/* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
> +	fifo_partition |= value << 0;
> +
> +	/* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
> +	fifo_partition |= value << 32;
> +
> +	/* Program FIFO Partition registers - 128 bytes for each channel */
> +	idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
> +	idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
> +}
> +
> +static void idma32_disable(struct dw_dma *dw)
> +{
> +	do_dma_off(dw);
> +	idma32_fifo_partition(dw);
> +}
> +
> +static void idma32_enable(struct dw_dma *dw)
> +{
> +	idma32_fifo_partition(dw);
> +	do_dma_on(dw);
> +}
> +
> +int idma32_dma_probe(struct dw_dma_chip *chip)
> +{
> +	struct dw_dma *dw;
> +
> +	dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
> +	if (!dw)
> +		return -ENOMEM;
> +
> +	/* Channel operations */
> +	dw->initialize_chan = idma32_initialize_chan;
> +	dw->suspend_chan = idma32_suspend_chan;
> +	dw->encode_maxburst = idma32_encode_maxburst;
> +	dw->bytes2block = idma32_bytes2block;
> +	dw->block2bytes = idma32_block2bytes;
> +
> +	/* Device operations */
> +	dw->set_device_name = idma32_set_device_name;
> +	dw->disable = idma32_disable;
> +	dw->enable = idma32_enable;
> +
> +	chip->dw = dw;
> +	return do_dma_probe(chip);
> +}
> +EXPORT_SYMBOL_GPL(idma32_dma_probe);
> +
> +int idma32_dma_remove(struct dw_dma_chip *chip)
> +{
> +	return do_dma_remove(chip);
> +}
> +EXPORT_SYMBOL_GPL(idma32_dma_remove);
> diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h
> index 41439732ff6b..1f2ddfe745bb 100644
> --- a/drivers/dma/dw/internal.h
> +++ b/drivers/dma/dw/internal.h
> @@ -15,8 +15,14 @@
>  
>  #include "regs.h"
>  
> -int dw_dma_disable(struct dw_dma_chip *chip);
> -int dw_dma_enable(struct dw_dma_chip *chip);
> +int do_dma_probe(struct dw_dma_chip *chip);
> +int do_dma_remove(struct dw_dma_chip *chip);
> +
> +void do_dma_on(struct dw_dma *dw);
> +void do_dma_off(struct dw_dma *dw);
> +
> +int do_dw_dma_disable(struct dw_dma_chip *chip);
> +int do_dw_dma_enable(struct dw_dma_chip *chip);
>  
>  extern bool dw_dma_filter(struct dma_chan *chan, void *param);
>  
> diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
> index 61f2274f6dd4..f5ea58cc027b 100644
> --- a/drivers/dma/dw/pci.c
> +++ b/drivers/dma/dw/pci.c
> @@ -15,11 +15,19 @@
>  
>  #include "internal.h"
>  
> -static struct dw_dma_platform_data mrfld_pdata = {
> +static struct dw_dma_pci_data {
> +	const struct dw_dma_platform_data *pdata;
> +	int (*probe)(struct dw_dma_chip *chip);
> +};
> +
> +static const struct dw_dma_pci_data dw_pci_data = {
> +	.probe = dw_dma_probe,
> +};
> +
> +static const struct dw_dma_platform_data idma32_pdata = {
>  	.nr_channels = 8,
>  	.is_private = true,
>  	.is_memcpy = true,
> -	.is_idma32 = true,
>  	.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
>  	.chan_priority = CHAN_PRIORITY_ASCENDING,
>  	.block_size = 131071,
> @@ -28,9 +36,14 @@ static struct dw_dma_platform_data mrfld_pdata = {
>  	.multi_block = {true, true, true, true, true, true, true, true},
>  };
>  
> +static const struct dw_dma_pci_data idma32_pci_data = {
> +	.pdata = &idma32_pdata,
> +	.probe = idma32_dma_probe,
> +};
> +
>  static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
>  {
> -	const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
> +	const struct dw_dma_pci_data *data = (void *)pid->driver_data;
>  	struct dw_dma_chip *chip;
>  	int ret;
>  
> @@ -63,9 +76,9 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
>  	chip->id = pdev->devfn;
>  	chip->regs = pcim_iomap_table(pdev)[0];
>  	chip->irq = pdev->irq;
> -	chip->pdata = pdata;
> +	chip->pdata = data->pdata;
>  
> -	ret = dw_dma_probe(chip);
> +	ret = data->probe(chip);
>  	if (ret)
>  		return ret;
>  
> @@ -91,7 +104,7 @@ static int dw_pci_suspend_late(struct device *dev)
>  	struct pci_dev *pci = to_pci_dev(dev);
>  	struct dw_dma_chip *chip = pci_get_drvdata(pci);
>  
> -	return dw_dma_disable(chip);
> +	return do_dw_dma_disable(chip);
>  };
>  
>  static int dw_pci_resume_early(struct device *dev)
> @@ -99,7 +112,7 @@ static int dw_pci_resume_early(struct device *dev)
>  	struct pci_dev *pci = to_pci_dev(dev);
>  	struct dw_dma_chip *chip = pci_get_drvdata(pci);
>  
> -	return dw_dma_enable(chip);
> +	return do_dw_dma_enable(chip);
>  };
>  
>  #endif /* CONFIG_PM_SLEEP */
> @@ -110,24 +123,24 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
>  
>  static const struct pci_device_id dw_pci_id_table[] = {
>  	/* Medfield (GPDMA) */
> -	{ PCI_VDEVICE(INTEL, 0x0827) },
> +	{ PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data },
>  
>  	/* BayTrail */
> -	{ PCI_VDEVICE(INTEL, 0x0f06) },
> -	{ PCI_VDEVICE(INTEL, 0x0f40) },
> +	{ PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data },
> +	{ PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data },
>  
> -	/* Merrifield iDMA 32-bit (GPDMA) */
> -	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&mrfld_pdata },
> +	/* Merrifield */
> +	{ PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data },
>  
>  	/* Braswell */
> -	{ PCI_VDEVICE(INTEL, 0x2286) },
> -	{ PCI_VDEVICE(INTEL, 0x22c0) },
> +	{ PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data },
> +	{ PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data },
>  
>  	/* Haswell */
> -	{ PCI_VDEVICE(INTEL, 0x9c60) },
> +	{ PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data },
>  
>  	/* Broadwell */
> -	{ PCI_VDEVICE(INTEL, 0x9ce0) },
> +	{ PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data },
>  
>  	{ }
>  };
> diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
> index f01b2c173fa6..6bf46c9b7ee4 100644
> --- a/drivers/dma/dw/platform.c
> +++ b/drivers/dma/dw/platform.c
> @@ -258,7 +258,7 @@ static void dw_shutdown(struct platform_device *pdev)
>  	struct dw_dma_chip *chip = platform_get_drvdata(pdev);
>  
>  	/*
> -	 * We have to call dw_dma_disable() to stop any ongoing transfer. On
> +	 * We have to call do_dw_dma_disable() to stop any ongoing transfer. On
>  	 * some platforms we can't do that since DMA device is powered off.
>  	 * Moreover we have no possibility to check if the platform is affected
>  	 * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put()
> @@ -267,7 +267,7 @@ static void dw_shutdown(struct platform_device *pdev)
>  	 * used by the driver.
>  	 */
>  	pm_runtime_get_sync(chip->dev);
> -	dw_dma_disable(chip);
> +	do_dw_dma_disable(chip);
>  	pm_runtime_put_sync_suspend(chip->dev);
>  
>  	clk_disable_unprepare(chip->clk);
> @@ -297,7 +297,7 @@ static int dw_suspend_late(struct device *dev)
>  {
>  	struct dw_dma_chip *chip = dev_get_drvdata(dev);
>  
> -	dw_dma_disable(chip);
> +	do_dw_dma_disable(chip);
>  	clk_disable_unprepare(chip->clk);
>  
>  	return 0;
> @@ -312,7 +312,7 @@ static int dw_resume_early(struct device *dev)
>  	if (ret)
>  		return ret;
>  
> -	return dw_dma_enable(chip);
> +	return do_dw_dma_enable(chip);
>  }
>  
>  #endif /* CONFIG_PM_SLEEP */
> diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
> index 09e7dfdbb790..90e46e69c047 100644
> --- a/drivers/dma/dw/regs.h
> +++ b/drivers/dma/dw/regs.h
> @@ -308,6 +308,19 @@ struct dw_dma {
>  	u8			all_chan_mask;
>  	u8			in_use;
>  
> +	/* Channel operations */
> +	void	(*initialize_chan)(struct dw_dma_chan *dwc);
> +	void	(*suspend_chan)(struct dw_dma_chan *dwc, bool drain);
> +	void	(*encode_maxburst)(struct dw_dma_chan *dwc, u32 *maxburst);
> +	u32	(*bytes2block)(struct dw_dma_chan *dwc, size_t bytes,
> +			       unsigned int width, size_t *len);
> +	size_t	(*block2bytes)(struct dw_dma_chan *dwc, u32 block, u32 width);
> +
> +	/* Device operations */
> +	void (*set_device_name)(struct dw_dma *dw, int id);
> +	void (*disable)(struct dw_dma *dw);
> +	void (*enable)(struct dw_dma *dw);
> +
>  	/* platform data */
>  	struct dw_dma_platform_data	*pdata;
>  };
> diff --git a/include/linux/dma/dw.h b/include/linux/dma/dw.h
> index e166cac8e870..d643d331c20e 100644
> --- a/include/linux/dma/dw.h
> +++ b/include/linux/dma/dw.h
> @@ -45,9 +45,13 @@ struct dw_dma_chip {
>  #if IS_ENABLED(CONFIG_DW_DMAC_CORE)
>  int dw_dma_probe(struct dw_dma_chip *chip);
>  int dw_dma_remove(struct dw_dma_chip *chip);
> +int idma32_dma_probe(struct dw_dma_chip *chip);
> +int idma32_dma_remove(struct dw_dma_chip *chip);
>  #else
>  static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
>  static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; }
> +static inline int idma32_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
> +static inline int idma32_dma_remove(struct dw_dma_chip *chip) { return 0; }
>  #endif /* CONFIG_DW_DMAC_CORE */
>  
>  #endif /* _DMA_DW_H */
> diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h
> index 896cb71a382c..e69e415d0d98 100644
> --- a/include/linux/platform_data/dma-dw.h
> +++ b/include/linux/platform_data/dma-dw.h
> @@ -41,7 +41,6 @@ struct dw_dma_slave {
>   * @is_private: The device channels should be marked as private and not for
>   *	by the general purpose DMA channel allocator.
>   * @is_memcpy: The device channels do support memory-to-memory transfers.
> - * @is_idma32: The type of the DMA controller is iDMA32
>   * @chan_allocation_order: Allocate channels starting from 0 or 7
>   * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
>   * @block_size: Maximum block size supported by the controller
> @@ -54,7 +53,6 @@ struct dw_dma_platform_data {
>  	unsigned int	nr_channels;
>  	bool		is_private;
>  	bool		is_memcpy;
> -	bool		is_idma32;
>  #define CHAN_ALLOCATION_ASCENDING	0	/* zero to seven */
>  #define CHAN_ALLOCATION_DESCENDING	1	/* seven to zero */
>  	unsigned char	chan_allocation_order;
> -- 
> 2.19.2
>

^ permalink raw reply

* [v1,3/5] dmaengine: dw: Split DW and iDMA 32-bit operations
From: kbuild test robot @ 2018-12-01  3:30 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: kbuild-all, Viresh Kumar, dmaengine, Vinod Koul

Hi Andy,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v4.20-rc4]
[cannot apply to next-20181130]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Andy-Shevchenko/dmaengine-dw-Fix-FIFO-size-for-Intel-Merrifield/20181201-110953
config: x86_64-randconfig-x014-201847 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

>> drivers/dma/dw/pci.c:21:1: warning: useless storage class specifier in empty declaration
    };
    ^

vim +21 drivers/dma/dw/pci.c

    17	
    18	static struct dw_dma_pci_data {
    19		const struct dw_dma_platform_data *pdata;
    20		int (*probe)(struct dw_dma_chip *chip);
  > 21	};
    22
---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* [RFC,01/10] dma-engine: sun4i: Add a quirk to support different chips
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

Allwinner suniv F1C100s has similar DMA engine to sun4i. Several
registers has different addresses. Total dma channels, endpoint counts
and max burst counts are also different.

In order to support F1C100s add a quirk structure to hold IC specific
data.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 drivers/dma/sun4i-dma.c | 138 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 106 insertions(+), 32 deletions(-)

diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index f4ed3f1..e86b424 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of_dma.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -34,6 +35,8 @@
 #define SUN4I_DMA_CFG_SRC_ADDR_MODE(mode)	((mode) << 5)
 #define SUN4I_DMA_CFG_SRC_DRQ_TYPE(type)	(type)
 
+#define SUN4I_MAX_BURST	8
+
 /** Normal DMA register values **/
 
 /* Normal DMA source/destination data request type values */
@@ -126,6 +129,32 @@
 	 SUN4I_DDMA_PARA_DST_WAIT_CYCLES(2) |				\
 	 SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(2))
 
+/*
+ * Hardware channels / ports representation
+ *
+ * The hardware is used in several SoCs, with differing numbers
+ * of channels and endpoints. This structure ties those numbers
+ * to a certain compatible string.
+ */
+struct sun4i_dma_config {
+	u32 ndma_nr_max_channels;
+	u32 ndma_nr_max_vchans;
+
+	u32 ddma_nr_max_channels;
+	u32 ddma_nr_max_vchans;
+
+	u32 dma_nr_max_channels;
+
+        void (*set_dst_data_width)(u32 *p_cfg, s8 data_width);
+        void (*set_src_data_width)(u32 *p_cfg, s8 data_width);
+	int (*convert_burst)(u32 maxburst);
+
+	u8 ndma_drq_sdram;
+	u8 ddma_drq_sdram;
+
+	u8 max_burst;
+};
+
 struct sun4i_dma_pchan {
 	/* Register base of channel */
 	void __iomem			*base;
@@ -163,7 +192,7 @@ struct sun4i_dma_contract {
 };
 
 struct sun4i_dma_dev {
-	DECLARE_BITMAP(pchans_used, SUN4I_DMA_NR_MAX_CHANNELS);
+	unsigned long *pchans_used;
 	struct dma_device		slave;
 	struct sun4i_dma_pchan		*pchans;
 	struct sun4i_dma_vchan		*vchans;
@@ -171,6 +200,7 @@ struct sun4i_dma_dev {
 	struct clk			*clk;
 	int				irq;
 	spinlock_t			lock;
+	const struct sun4i_dma_config *cfg;
 };
 
 static struct sun4i_dma_dev *to_sun4i_dma_dev(struct dma_device *dev)
@@ -193,7 +223,17 @@ static struct device *chan2dev(struct dma_chan *chan)
 	return &chan->dev->device;
 }
 
-static int convert_burst(u32 maxburst)
+static void set_dst_data_width_a10(u32 *p_cfg, s8 data_width)
+{
+	*p_cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(data_width);
+}
+
+static void set_src_data_width_a10(u32 *p_cfg, s8 data_width)
+{
+	*p_cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(data_width);
+}
+
+static int convert_burst_a10(u32 maxburst)
 {
 	if (maxburst > 8)
 		return -EINVAL;
@@ -226,15 +266,15 @@ static struct sun4i_dma_pchan *find_and_use_pchan(struct sun4i_dma_dev *priv,
 	int i, max;
 
 	/*
-	 * pchans 0-SUN4I_NDMA_NR_MAX_CHANNELS are normal, and
-	 * SUN4I_NDMA_NR_MAX_CHANNELS+ are dedicated ones
+	 * pchans 0-priv->cfg->ndma_nr_max_channels are normal, and
+	 * priv->cfg->ndma_nr_max_channels+ are dedicated ones
 	 */
 	if (vchan->is_dedicated) {
-		i = SUN4I_NDMA_NR_MAX_CHANNELS;
-		max = SUN4I_DMA_NR_MAX_CHANNELS;
+		i = priv->cfg->ndma_nr_max_channels;
+		max = priv->cfg->dma_nr_max_channels;
 	} else {
 		i = 0;
-		max = SUN4I_NDMA_NR_MAX_CHANNELS;
+		max = priv->cfg->ndma_nr_max_channels;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -437,6 +477,7 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 		      size_t len, struct dma_slave_config *sconfig,
 		      enum dma_transfer_direction direction)
 {
+	struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
 	struct sun4i_dma_promise *promise;
 	int ret;
 
@@ -460,13 +501,13 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 		sconfig->src_addr_width, sconfig->dst_addr_width);
 
 	/* Source burst */
-	ret = convert_burst(sconfig->src_maxburst);
+	ret = priv->cfg->convert_burst(sconfig->src_maxburst);
 	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
 
 	/* Destination burst */
-	ret = convert_burst(sconfig->dst_maxburst);
+	ret = priv->cfg->convert_burst(sconfig->dst_maxburst);
 	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
@@ -475,13 +516,13 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 	ret = convert_buswidth(sconfig->src_addr_width);
 	if (ret < 0)
 		goto fail;
-	promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
+	priv->cfg->set_src_data_width(&promise->cfg, ret);
 
 	/* Destination bus width */
 	ret = convert_buswidth(sconfig->dst_addr_width);
 	if (ret < 0)
 		goto fail;
-	promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
+	priv->cfg->set_dst_data_width(&promise->cfg, ret);
 
 	return promise;
 
@@ -503,6 +544,7 @@ static struct sun4i_dma_promise *
 generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 		      size_t len, struct dma_slave_config *sconfig)
 {
+	struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
 	struct sun4i_dma_promise *promise;
 	int ret;
 
@@ -517,13 +559,13 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 		SUN4I_DDMA_CFG_BYTE_COUNT_MODE_REMAIN;
 
 	/* Source burst */
-	ret = convert_burst(sconfig->src_maxburst);
+	ret = priv->cfg->convert_burst(sconfig->src_maxburst);
 	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
 
 	/* Destination burst */
-	ret = convert_burst(sconfig->dst_maxburst);
+	ret = priv->cfg->convert_burst(sconfig->dst_maxburst);
 	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
@@ -532,13 +574,13 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 	ret = convert_buswidth(sconfig->src_addr_width);
 	if (ret < 0)
 		goto fail;
-	promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
+	priv->cfg->set_src_data_width(&promise->cfg, ret);
 
 	/* Destination bus width */
 	ret = convert_buswidth(sconfig->dst_addr_width);
 	if (ret < 0)
 		goto fail;
-	promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
+	priv->cfg->set_dst_data_width(&promise->cfg, ret);
 
 	return promise;
 
@@ -615,6 +657,7 @@ static struct dma_async_tx_descriptor *
 sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
 			  dma_addr_t src, size_t len, unsigned long flags)
 {
+	struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
 	struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
 	struct dma_slave_config *sconfig = &vchan->cfg;
 	struct sun4i_dma_promise *promise;
@@ -631,8 +674,8 @@ sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
 	 */
 	sconfig->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 	sconfig->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	sconfig->src_maxburst = 8;
-	sconfig->dst_maxburst = 8;
+	sconfig->src_maxburst = priv->cfg->max_burst;
+	sconfig->dst_maxburst = priv->cfg->max_burst;
 
 	if (vchan->is_dedicated)
 		promise = generate_ddma_promise(chan, src, dest, len, sconfig);
@@ -647,11 +690,13 @@ sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
 
 	/* Configure memcpy mode */
 	if (vchan->is_dedicated) {
-		promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM) |
-				SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM);
+		promise->cfg |=
+			SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ddma_drq_sdram) |
+			SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ddma_drq_sdram);
 	} else {
-		promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) |
-				SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM);
+		promise->cfg |=
+			SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ndma_drq_sdram) |
+			SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ndma_drq_sdram);
 	}
 
 	/* Fill the contract with our only promise */
@@ -666,6 +711,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
 			  size_t period_len, enum dma_transfer_direction dir,
 			  unsigned long flags)
 {
+	struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
 	struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
 	struct dma_slave_config *sconfig = &vchan->cfg;
 	struct sun4i_dma_promise *promise;
@@ -701,7 +747,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
 	if (dir == DMA_MEM_TO_DEV) {
 		src = buf;
 		dest = sconfig->dst_addr;
-		endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) |
+		endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ndma_drq_sdram) |
 			    SUN4I_DMA_CFG_DST_DRQ_TYPE(vchan->endpoint) |
 			    SUN4I_DMA_CFG_DST_ADDR_MODE(SUN4I_NDMA_ADDR_MODE_IO);
 	} else {
@@ -709,7 +755,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
 		dest = buf;
 		endpoints = SUN4I_DMA_CFG_SRC_DRQ_TYPE(vchan->endpoint) |
 			    SUN4I_DMA_CFG_SRC_ADDR_MODE(SUN4I_NDMA_ADDR_MODE_IO) |
-			    SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM);
+			    SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ndma_drq_sdram);
 	}
 
 	/*
@@ -772,6 +818,7 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			unsigned int sg_len, enum dma_transfer_direction dir,
 			unsigned long flags, void *context)
 {
+	struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
 	struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
 	struct dma_slave_config *sconfig = &vchan->cfg;
 	struct sun4i_dma_promise *promise;
@@ -797,11 +844,11 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	if (vchan->is_dedicated) {
 		io_mode = SUN4I_DDMA_ADDR_MODE_IO;
 		linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR;
-		ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM;
+		ram_type = priv->cfg->ddma_drq_sdram;
 	} else {
 		io_mode = SUN4I_NDMA_ADDR_MODE_IO;
 		linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR;
-		ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM;
+		ram_type = priv->cfg->ndma_drq_sdram;
 	}
 
 	if (dir == DMA_MEM_TO_DEV)
@@ -1130,6 +1177,10 @@ static int sun4i_dma_probe(struct platform_device *pdev)
 	if (!priv)
 		return -ENOMEM;
 
+	priv->cfg = of_device_get_match_data(&pdev->dev);
+	if (!priv->cfg)
+		return -ENODEV;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	priv->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(priv->base))
@@ -1178,23 +1229,26 @@ static int sun4i_dma_probe(struct platform_device *pdev)
 
 	priv->slave.dev = &pdev->dev;
 
-	priv->pchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_CHANNELS,
+	priv->pchans = devm_kcalloc(&pdev->dev, priv->cfg->dma_nr_max_channels,
 				    sizeof(struct sun4i_dma_pchan), GFP_KERNEL);
 	priv->vchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_VCHANS,
 				    sizeof(struct sun4i_dma_vchan), GFP_KERNEL);
-	if (!priv->vchans || !priv->pchans)
+	priv->pchans_used = devm_kcalloc(&pdev->dev,
+			BITS_TO_LONGS(priv->cfg->dma_nr_max_channels),
+			sizeof(unsigned long), GFP_KERNEL);
+	if (!priv->vchans || !priv->pchans || !priv->pchans_used)
 		return -ENOMEM;
 
 	/*
-	 * [0..SUN4I_NDMA_NR_MAX_CHANNELS) are normal pchans, and
-	 * [SUN4I_NDMA_NR_MAX_CHANNELS..SUN4I_DMA_NR_MAX_CHANNELS) are
+	 * [0..priv->cfg->ndma_nr_max_channels) are normal pchans, and
+	 * [priv->cfg->ndma_nr_max_channels..priv->cfg->dma_nr_max_channels) are
 	 * dedicated ones
 	 */
-	for (i = 0; i < SUN4I_NDMA_NR_MAX_CHANNELS; i++)
+	for (i = 0; i < priv->cfg->ndma_nr_max_channels; i++)
 		priv->pchans[i].base = priv->base +
 			SUN4I_NDMA_CHANNEL_REG_BASE(i);
 
-	for (j = 0; i < SUN4I_DMA_NR_MAX_CHANNELS; i++, j++) {
+	for (j = 0; i < priv->cfg->dma_nr_max_channels; i++, j++) {
 		priv->pchans[i].base = priv->base +
 			SUN4I_DDMA_CHANNEL_REG_BASE(j);
 		priv->pchans[i].is_dedicated = 1;
@@ -1267,8 +1321,28 @@ static int sun4i_dma_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static struct sun4i_dma_config sun4i_a10_dma_cfg = {
+	.ndma_nr_max_channels	= SUN4I_NDMA_NR_MAX_CHANNELS,
+	.ndma_nr_max_vchans	= SUN4I_NDMA_NR_MAX_VCHANS,
+
+	.ddma_nr_max_channels	= SUN4I_DDMA_NR_MAX_CHANNELS,
+	.ddma_nr_max_vchans	= SUN4I_DDMA_NR_MAX_VCHANS,
+
+	.dma_nr_max_channels	= SUN4I_NDMA_NR_MAX_CHANNELS + 
+		SUN4I_DDMA_NR_MAX_CHANNELS,
+
+	.set_dst_data_width	= set_dst_data_width_a10,
+	.set_src_data_width	= set_src_data_width_a10,
+	.convert_burst		= convert_burst_a10,
+
+	.ndma_drq_sdram		= SUN4I_NDMA_DRQ_TYPE_SDRAM,
+	.ddma_drq_sdram		= SUN4I_DDMA_DRQ_TYPE_SDRAM,
+
+	.max_burst		= SUN4I_MAX_BURST,
+};
+
 static const struct of_device_id sun4i_dma_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-dma" },
+	{ .compatible = "allwinner,sun4i-a10-dma", .data = &sun4i_a10_dma_cfg },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, sun4i_dma_match);

^ permalink raw reply related

* [RFC,02/10] dma-engine: sun4i: Add has_reset option to quirk
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

Allwinner suniv F1C100s has a reset bit for DMA in CCU. Sun4i do not
has this bit but in order to support suniv we need to add it. So add
support for reset bit.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 drivers/dma/sun4i-dma.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index e86b424..d267ff9 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -18,6 +18,7 @@
 #include <linux/of_dma.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
@@ -153,6 +154,7 @@ struct sun4i_dma_config {
 	u8 ddma_drq_sdram;
 
 	u8 max_burst;
+	bool has_reset;
 };
 
 struct sun4i_dma_pchan {
@@ -201,6 +203,7 @@ struct sun4i_dma_dev {
 	int				irq;
 	spinlock_t			lock;
 	const struct sun4i_dma_config *cfg;
+	struct reset_control *rst;
 };
 
 static struct sun4i_dma_dev *to_sun4i_dma_dev(struct dma_device *dev)
@@ -1198,6 +1201,15 @@ static int sun4i_dma_probe(struct platform_device *pdev)
 		return PTR_ERR(priv->clk);
 	}
 
+	if(priv->cfg->has_reset) {
+		priv->rst = devm_reset_control_get_exclusive(&pdev->dev,
+							       NULL);
+		if (IS_ERR(priv->rst)) {
+			dev_err(&pdev->dev, "Failed to get reset control\n");
+			return PTR_ERR(priv->rst);
+		}
+	}
+
 	platform_set_drvdata(pdev, priv);
 	spin_lock_init(&priv->lock);
 
@@ -1268,6 +1280,16 @@ static int sun4i_dma_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	/* Deassert the reset control */
+	if (priv->rst) {
+		ret = reset_control_deassert(priv->rst);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to deassert the reset control\n");
+			goto err_clk_disable;
+		}
+	}
+
 	/*
 	 * Make sure the IRQs are all disabled and accounted for. The bootloader
 	 * likes to leave these dirty
@@ -1339,6 +1361,7 @@ static struct sun4i_dma_config sun4i_a10_dma_cfg = {
 	.ddma_drq_sdram		= SUN4I_DDMA_DRQ_TYPE_SDRAM,
 
 	.max_burst		= SUN4I_MAX_BURST,
+	.has_reset		= false,
 };
 
 static const struct of_device_id sun4i_dma_match[] = {

^ permalink raw reply related

* [RFC,03/10] dt-bindings: dmaengine: Add Allwinner suniv F1C100s DMA
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

Add compatible string for Allwinner suniv F1C100s DMA.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 Documentation/devicetree/bindings/dma/sun4i-dma.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/dma/sun4i-dma.txt b/Documentation/devicetree/bindings/dma/sun4i-dma.txt
index 8ad556a..ceeb41e 100644
--- a/Documentation/devicetree/bindings/dma/sun4i-dma.txt
+++ b/Documentation/devicetree/bindings/dma/sun4i-dma.txt
@@ -4,7 +4,9 @@ This driver follows the generic DMA bindings defined in dma.txt.
 
 Required properties:
 
-- compatible:	Must be "allwinner,sun4i-a10-dma"
+- compatible:	Should be one of the following:
+		"allwinner,sun4i-a10-dma"
+		"allwinner,suniv-f1c100s-dma"
 - reg:		Should contain the registers base address and length
 - interrupts:	Should contain a reference to the interrupt used by this device
 - clocks:	Should contain a reference to the parent AHB clock

^ permalink raw reply related

* [RFC,04/10] dma-engine: sun4i: Add support for Allwinner suniv F1C100s
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

DMA of Allwinner suniv F1C100s is similar to sun4i. It has 4 NDMA, 4
DDMA channels and endpoints are different. Also F1C100s has reset bit
for DMA in CCU. Add support for it.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 drivers/dma/Kconfig     |  4 ++--
 drivers/dma/sun4i-dma.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index de511db..f8a65d2 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -163,8 +163,8 @@ config DMA_SA11X0
 
 config DMA_SUN4I
 	tristate "Allwinner A10 DMA SoCs support"
-	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
-	default (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I)
+	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNIV
+	default (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNIV)
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 	help
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index d267ff9..c0452c9 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -36,7 +36,11 @@
 #define SUN4I_DMA_CFG_SRC_ADDR_MODE(mode)	((mode) << 5)
 #define SUN4I_DMA_CFG_SRC_DRQ_TYPE(type)	(type)
 
+#define SUNIV_DMA_CFG_DST_DATA_WIDTH(width)	((width) << 24)
+#define SUNIV_DMA_CFG_SRC_DATA_WIDTH(width)	((width) << 8)
+
 #define SUN4I_MAX_BURST	8
+#define SUNIV_MAX_BURST	4
 
 /** Normal DMA register values **/
 
@@ -44,6 +48,9 @@
 #define SUN4I_NDMA_DRQ_TYPE_SDRAM		0x16
 #define SUN4I_NDMA_DRQ_TYPE_LIMIT		(0x1F + 1)
 
+#define SUNIV_NDMA_DRQ_TYPE_SDRAM		0x11
+#define SUNIV_NDMA_DRQ_TYPE_LIMIT		(0x17 + 1)
+
 /** Normal DMA register layout **/
 
 /* Dedicated DMA source/destination address mode values */
@@ -57,6 +64,9 @@
 #define SUN4I_NDMA_CFG_BYTE_COUNT_MODE_REMAIN	BIT(15)
 #define SUN4I_NDMA_CFG_SRC_NON_SECURE		BIT(6)
 
+#define SUNIV_NDMA_CFG_CONT_MODE		BIT(29)
+#define SUNIV_NDMA_CFG_WAIT_STATE(n)		((n) << 26)
+
 /** Dedicated DMA register values **/
 
 /* Dedicated DMA source/destination address mode values */
@@ -69,6 +79,9 @@
 #define SUN4I_DDMA_DRQ_TYPE_SDRAM		0x1
 #define SUN4I_DDMA_DRQ_TYPE_LIMIT		(0x1F + 1)
 
+#define SUNIV_DDMA_DRQ_TYPE_SDRAM		0x1
+#define SUNIV_DDMA_DRQ_TYPE_LIMIT		(0x9 + 1)
+
 /** Dedicated DMA register layout **/
 
 /* Dedicated DMA configuration register layout */
@@ -122,6 +135,11 @@
 #define SUN4I_DMA_NR_MAX_VCHANS						\
 	(SUN4I_NDMA_NR_MAX_VCHANS + SUN4I_DDMA_NR_MAX_VCHANS)
 
+#define SUNIV_NDMA_NR_MAX_CHANNELS	4
+#define SUNIV_DDMA_NR_MAX_CHANNELS	4
+#define SUNIV_NDMA_NR_MAX_VCHANS	(24 * 2 - 1)
+#define SUNIV_DDMA_NR_MAX_VCHANS	10
+
 /* This set of SUN4I_DDMA timing parameters were found experimentally while
  * working with the SPI driver and seem to make it behave correctly */
 #define SUN4I_DDMA_MAGIC_SPI_PARAMETERS \
@@ -236,6 +254,16 @@ static void set_src_data_width_a10(u32 *p_cfg, s8 data_width)
 	*p_cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(data_width);
 }
 
+static void set_dst_data_width_f1c100s(u32 *p_cfg, s8 data_width)
+{
+	*p_cfg |= SUNIV_DMA_CFG_DST_DATA_WIDTH(data_width);
+}
+
+static void set_src_data_width_f1c100s(u32 *p_cfg, s8 data_width)
+{
+	*p_cfg |= SUNIV_DMA_CFG_SRC_DATA_WIDTH(data_width);
+}
+
 static int convert_burst_a10(u32 maxburst)
 {
 	if (maxburst > 8)
@@ -245,6 +273,15 @@ static int convert_burst_a10(u32 maxburst)
 	return (maxburst >> 2);
 }
 
+static int convert_burst_f1c100s(u32 maxburst)
+{
+	if (maxburst > 4)
+		return -EINVAL;
+
+	/* 1 -> 0, 4 -> 1 */
+	return (maxburst >> 2);
+}
+
 static int convert_buswidth(enum dma_slave_buswidth addr_width)
 {
 	if (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)
@@ -1364,8 +1401,31 @@ static struct sun4i_dma_config sun4i_a10_dma_cfg = {
 	.has_reset		= false,
 };
 
+static struct sun4i_dma_config suniv_f1c100s_dma_cfg = {
+	.ndma_nr_max_channels	= SUNIV_NDMA_NR_MAX_CHANNELS,
+	.ndma_nr_max_vchans	= SUNIV_NDMA_NR_MAX_VCHANS,
+
+	.ddma_nr_max_channels	= SUNIV_DDMA_NR_MAX_CHANNELS,
+	.ddma_nr_max_vchans	= SUNIV_DDMA_NR_MAX_VCHANS,
+
+	.dma_nr_max_channels	= SUNIV_NDMA_NR_MAX_CHANNELS +
+		SUNIV_DDMA_NR_MAX_CHANNELS,
+
+	.set_dst_data_width	= set_dst_data_width_f1c100s,
+	.set_src_data_width	= set_src_data_width_f1c100s,
+	.convert_burst		= convert_burst_f1c100s,
+
+	.ndma_drq_sdram		= SUNIV_NDMA_DRQ_TYPE_SDRAM,
+	.ddma_drq_sdram		= SUNIV_DDMA_DRQ_TYPE_SDRAM,
+
+	.max_burst		= SUNIV_MAX_BURST,
+	.has_reset		= true,
+};
+
 static const struct of_device_id sun4i_dma_match[] = {
 	{ .compatible = "allwinner,sun4i-a10-dma", .data = &sun4i_a10_dma_cfg },
+	{ .compatible = "allwinner,suniv-f1c100s-dma",
+		.data = &suniv_f1c100s_dma_cfg },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, sun4i_dma_match);

^ permalink raw reply related

* [RFC,05/10] ARM: dts: suniv: f1c100s: Add support for DMA
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

Allwinner suniv F1C100s now has DMA support. Enable it under device
tree.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 arch/arm/boot/dts/suniv-f1c100s.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/suniv-f1c100s.dtsi b/arch/arm/boot/dts/suniv-f1c100s.dtsi
index aff5f90..4c96a9e 100644
--- a/arch/arm/boot/dts/suniv-f1c100s.dtsi
+++ b/arch/arm/boot/dts/suniv-f1c100s.dtsi
@@ -6,6 +6,7 @@
 
 #include <dt-bindings/clock/suniv-ccu-f1c100s.h>
 #include <dt-bindings/reset/suniv-ccu-f1c100s.h>
+#include <dt-bindings/dma/sun4i-a10.h>
 
 / {
 	#address-cells = <1>;
@@ -65,6 +66,16 @@
 			};
 		};
 
+		dma: dma-controller@1c02000 {
+			compatible = "allwinner,suniv-f1c100s-dma";
+			reg = <0x01c02000 0x1000>;
+			interrupts = <18>;
+			clocks = <&ccu CLK_BUS_DMA>;
+			resets = <&ccu RST_BUS_DMA>;
+			#dma-cells = <2>;
+		};
+
+
 		ccu: clock@1c20000 {
 			compatible = "allwinner,suniv-f1c100s-ccu";
 			reg = <0x01c20000 0x400>;

^ permalink raw reply related

* [RFC,06/10] ASoC: sun4i-codec: Add DMA Max Burst field
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

Allwinner suniv F1C100s has similar DMA engine to sun4i but it has
smaller max burst size compared to sun4i. Add a quirk field to
differantitate between them.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 sound/soc/sunxi/sun4i-codec.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 9a3cb77..7a9f84e 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -224,6 +224,8 @@
 
 /* TODO H3 DAP (Digital Audio Processing) bits */
 
+#define SUN4I_DMA_MAX_BURST			(8)
+
 struct sun4i_codec {
 	struct device	*dev;
 	struct regmap	*regmap;
@@ -1462,6 +1464,7 @@ struct sun4i_codec_quirks {
 	unsigned int reg_dac_txdata;	/* TX FIFO offset for DMA config */
 	unsigned int reg_adc_rxdata;	/* RX FIFO offset for DMA config */
 	bool has_reset;
+	u32 dma_max_burst;
 };
 
 static const struct sun4i_codec_quirks sun4i_codec_quirks = {
@@ -1471,6 +1474,7 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = {
 	.reg_adc_fifoc	= REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
 	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
 	.reg_adc_rxdata	= SUN4I_CODEC_ADC_RXDATA,
+	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
 static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
@@ -1481,6 +1485,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
 	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
 	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
 	.has_reset	= true,
+	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
 static const struct sun4i_codec_quirks sun7i_codec_quirks = {
@@ -1490,6 +1495,7 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = {
 	.reg_adc_fifoc	= REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31),
 	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
 	.reg_adc_rxdata	= SUN4I_CODEC_ADC_RXDATA,
+	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
 static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
@@ -1500,6 +1506,7 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
 	.reg_dac_txdata	= SUN4I_CODEC_DAC_TXDATA,
 	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
 	.has_reset	= true,
+	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
 static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
@@ -1515,6 +1522,7 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
 	.reg_dac_txdata	= SUN8I_H3_CODEC_DAC_TXDATA,
 	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
 	.has_reset	= true,
+	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
 static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
@@ -1529,6 +1537,7 @@ static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
 	.reg_dac_txdata	= SUN8I_H3_CODEC_DAC_TXDATA,
 	.reg_adc_rxdata	= SUN6I_CODEC_ADC_RXDATA,
 	.has_reset	= true,
+	.dma_max_burst	= SUN4I_DMA_MAX_BURST,
 };
 
 static const struct of_device_id sun4i_codec_of_match[] = {
@@ -1655,12 +1664,12 @@ static int sun4i_codec_probe(struct platform_device *pdev)
 
 	/* DMA configuration for TX FIFO */
 	scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
-	scodec->playback_dma_data.maxburst = 8;
+	scodec->playback_dma_data.maxburst = quirks->dma_max_burst;
 	scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
 	/* DMA configuration for RX FIFO */
 	scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata;
-	scodec->capture_dma_data.maxburst = 8;
+	scodec->capture_dma_data.maxburst = quirks->dma_max_burst;
 	scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
 
 	ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,

^ permalink raw reply related

* [RFC,07/10] dt-bindigs: sound: Add Allwinner suniv F1C100s Audio Codec
From: Mesih Kilinc @ 2018-12-02 21:23 UTC (permalink / raw)
  To: dmaengine, devicetree, linux-arm-kernel, linux-kernel, alsa-devel,
	linux-sunxi
  Cc: Mesih Kilinc, Vinod Koul, Rob Herring, Mark Rutland,
	Maxime Ripard, Chen-Yu Tsai, Liam Girdwood, Mark Brown,
	Jaroslav Kysela, Takashi Iwai

Add compatible string for Allwinner suniv F1C100s audio codec.

Signed-off-by: Mesih Kilinc <mesihkilinc@gmail.com>
---
 Documentation/devicetree/bindings/sound/sun4i-codec.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
index 66579bb..9778bc1 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt
@@ -8,6 +8,7 @@ Required properties:
 		- "allwinner,sun8i-a23-codec"
 		- "allwinner,sun8i-h3-codec"
 		- "allwinner,sun8i-v3s-codec"
+		- "allwinner,suniv-f1c100s-codec"
 - reg: must contain the registers location and length
 - interrupts: must contain the codec interrupt
 - dmas: DMA channels for tx and rx dma. See the DMA client binding,
@@ -27,6 +28,7 @@ Required properties for the following compatibles:
 		- "allwinner,sun8i-a23-codec"
 		- "allwinner,sun8i-h3-codec"
 		- "allwinner,sun8i-v3s-codec"
+		- "allwinner,suniv-f1c100s-codec"
 - resets: phandle to the reset control for this device
 - allwinner,audio-routing: A list of the connections between audio components.
 			   Each entry is a pair of strings, the first being the
@@ -41,6 +43,7 @@ Required properties for the following compatibles:
 			   "MIC1"
 			   "MIC2"	(not on sun8i-v3s)
 			   "MIC3"	(sun6i-a31 only)
+			   "MIC"	(suniv-f1c100s only)
 
 			   Microphone biases from the SoC:
 			   "HBIAS"
@@ -51,6 +54,8 @@ Required properties for the following compatibles:
 			   "Headset Mic"
 			   "Line In"
 			   "Line Out"
+			   "Right FM In"	(suniv-f1c100s only)
+			   "Left FM In"		(suniv-f1c100s only)
 			   "Mic"
 			   "Speaker"
 

^ permalink raw reply related


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