DMA Engine development
 help / color / mirror / Atom feed
* [v10,3/4] dmaengine: fsl-edma: fix macros
From: Angelo Dureghello @ 2018-08-19 17:27 UTC (permalink / raw)
  To: vinod.koul
  Cc: dmaengine, linux-arm-kernel, linux-m68k, stefan, krzk,
	Angelo Dureghello

This patch fixes macros to use BIT() and GENMASK(), removing
also some unneeded.

Signed-off-by: Angelo Dureghello <angelo@sysam.it>
Tested-by: Krzysztof Kozlowski <krzk@kernel.org>
---
Changes for v9:
- this patch (3/4) has just been added.

Changes for v10:
- none
---
 drivers/dma/fsl-edma-common.h | 50 +++++++++++++++--------------------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index b2ee89ea895a..a6f5b99ee95f 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -18,34 +18,28 @@
 #define EDMA_CR_ECX		BIT(16)
 #define EDMA_CR_CX		BIT(17)
 
-#define EDMA_SEEI_SEEI(x)	((x) & 0x1F)
-#define EDMA_CEEI_CEEI(x)	((x) & 0x1F)
-#define EDMA_CINT_CINT(x)	((x) & 0x1F)
-#define EDMA_CERR_CERR(x)	((x) & 0x1F)
-
-#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & 0x0007))
-#define EDMA_TCD_ATTR_DMOD(x)		(((x) & 0x001F) << 3)
-#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & 0x0007) << 8)
-#define EDMA_TCD_ATTR_SMOD(x)		(((x) & 0x001F) << 11)
-#define EDMA_TCD_ATTR_SSIZE_8BIT	(0x0000)
-#define EDMA_TCD_ATTR_SSIZE_16BIT	(0x0100)
-#define EDMA_TCD_ATTR_SSIZE_32BIT	(0x0200)
-#define EDMA_TCD_ATTR_SSIZE_64BIT	(0x0300)
-#define EDMA_TCD_ATTR_SSIZE_32BYTE	(0x0500)
-#define EDMA_TCD_ATTR_DSIZE_8BIT	(0x0000)
-#define EDMA_TCD_ATTR_DSIZE_16BIT	(0x0001)
-#define EDMA_TCD_ATTR_DSIZE_32BIT	(0x0002)
-#define EDMA_TCD_ATTR_DSIZE_64BIT	(0x0003)
-#define EDMA_TCD_ATTR_DSIZE_32BYTE	(0x0005)
-
-#define EDMA_TCD_SOFF_SOFF(x)		(x)
-#define EDMA_TCD_NBYTES_NBYTES(x)	(x)
-#define EDMA_TCD_SLAST_SLAST(x)		(x)
-#define EDMA_TCD_DADDR_DADDR(x)		(x)
-#define EDMA_TCD_CITER_CITER(x)		((x) & 0x7FFF)
-#define EDMA_TCD_DOFF_DOFF(x)		(x)
-#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)	(x)
-#define EDMA_TCD_BITER_BITER(x)		((x) & 0x7FFF)
+#define EDMA_SEEI_SEEI(x)	((x) & GENMASK(4, 0))
+#define EDMA_CEEI_CEEI(x)	((x) & GENMASK(4, 0))
+#define EDMA_CINT_CINT(x)	((x) & GENMASK(4, 0))
+#define EDMA_CERR_CERR(x)	((x) & GENMASK(4, 0))
+
+#define EDMA_TCD_ATTR_DSIZE(x)		(((x) & GENMASK(2, 0)))
+#define EDMA_TCD_ATTR_DMOD(x)		(((x) & GENMASK(4, 0)) << 3)
+#define EDMA_TCD_ATTR_SSIZE(x)		(((x) & GENMASK(2, 0)) << 8)
+#define EDMA_TCD_ATTR_SMOD(x)		(((x) & GENMASK(4, 0)) << 11)
+#define EDMA_TCD_ATTR_DSIZE_8BIT	0
+#define EDMA_TCD_ATTR_DSIZE_16BIT	BIT(0)
+#define EDMA_TCD_ATTR_DSIZE_32BIT	BIT(1)
+#define EDMA_TCD_ATTR_DSIZE_64BIT	(BIT(0) | BIT(1))
+#define EDMA_TCD_ATTR_DSIZE_32BYTE	(BIT(3) | BIT(0))
+#define EDMA_TCD_ATTR_SSIZE_8BIT	0
+#define EDMA_TCD_ATTR_SSIZE_16BIT	(EDMA_TCD_ATTR_DSIZE_16BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_32BIT	(EDMA_TCD_ATTR_DSIZE_32BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_64BIT	(EDMA_TCD_ATTR_DSIZE_64BIT << 8)
+#define EDMA_TCD_ATTR_SSIZE_32BYTE	(EDMA_TCD_ATTR_DSIZE_32BYTE << 8)
+
+#define EDMA_TCD_CITER_CITER(x)		((x) & GENMASK(14, 0))
+#define EDMA_TCD_BITER_BITER(x)		((x) & GENMASK(14, 0))
 
 #define EDMA_TCD_CSR_START		BIT(0)
 #define EDMA_TCD_CSR_INT_MAJOR		BIT(1)

^ permalink raw reply related

* [v10,4/4] dmaengine: fsl-edma: add ColdFire mcf5441x edma support
From: Angelo Dureghello @ 2018-08-19 17:27 UTC (permalink / raw)
  To: vinod.koul
  Cc: dmaengine, linux-arm-kernel, linux-m68k, stefan, krzk,
	Angelo Dureghello

This patch adds support for ColdFire mcf5441x-family edma
module.

The ColdFire edma module is slightly different from fsl-edma,
so a new driver is added. But most of the code is common
between fsl-edma and mcf-edma so it has been collected into a
separate common module fsl-edma-common (patch 1/3).

Signed-off-by: Angelo Dureghello <angelo@sysam.it>
Tested-by: Krzysztof Kozlowski <krzk@kernel.org>
---
Changes for v8:
- patch rewritten from scratch, this patch (3/3) has just been added.

Changes for v9:
- add compile test for Kconfig,
- fix include guard.

Changes for v10:
- fix robot build "different size" cast,
- fix invalid usage of PTR_ERR.
---
 drivers/dma/Kconfig                        |  11 +
 drivers/dma/Makefile                       |   1 +
 drivers/dma/fsl-edma-common.c              |  24 +-
 drivers/dma/mcf-edma.c                     | 317 +++++++++++++++++++++
 include/linux/platform_data/dma-mcf-edma.h |  38 +++
 5 files changed, 387 insertions(+), 4 deletions(-)
 create mode 100644 drivers/dma/mcf-edma.c
 create mode 100644 include/linux/platform_data/dma-mcf-edma.h

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ca1680afa20a..45ca5e556774 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -320,6 +320,17 @@ config LPC18XX_DMAMUX
 	  Enable support for DMA on NXP LPC18xx/43xx platforms
 	  with PL080 and multiplexed DMA request lines.
 
+config MCF_EDMA
+	tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs"
+	depends on M5441x || COMPILE_TEST
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Support the Freescale ColdFire eDMA engine, 64-channel
+	  implementation that performs complex data transfers with
+	  minimal intervention from a host processor.
+	  This module can be found on Freescale ColdFire mcf5441x SoCs.
+
 config MMP_PDMA
 	bool "MMP PDMA support"
 	depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 66022f59fca4..d97f317f4b34 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw/
 obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_FSL_DMA) += fsldma.o
 obj-$(CONFIG_FSL_EDMA) += fsl-edma.o fsl-edma-common.o
+obj-$(CONFIG_MCF_EDMA) += mcf-edma.o fsl-edma-common.o
 obj-$(CONFIG_FSL_RAID) += fsl_raid.o
 obj-$(CONFIG_HSU_DMA) += hsu/
 obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 227034de256e..8ba80f4b6f55 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -46,8 +46,16 @@ static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
 	struct edma_regs *regs = &fsl_chan->edma->regs;
 	u32 ch = fsl_chan->vchan.chan.chan_id;
 
-	edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
-	edma_writeb(fsl_chan->edma, ch, regs->serq);
+	if (fsl_chan->edma->version == v1) {
+		edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), regs->seei);
+		edma_writeb(fsl_chan->edma, ch, regs->serq);
+	} else {
+		/* ColdFire is big endian, and accesses natively
+		 * big endian I/O peripherals
+		 */
+		iowrite8(EDMA_SEEI_SEEI(ch), regs->seei);
+		iowrite8(ch, regs->serq);
+	}
 }
 
 void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
@@ -55,8 +63,16 @@ void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
 	struct edma_regs *regs = &fsl_chan->edma->regs;
 	u32 ch = fsl_chan->vchan.chan.chan_id;
 
-	edma_writeb(fsl_chan->edma, ch, regs->cerq);
-	edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
+	if (fsl_chan->edma->version == v1) {
+		edma_writeb(fsl_chan->edma, ch, regs->cerq);
+		edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), regs->ceei);
+	} else {
+		/* ColdFire is big endian, and accesses natively
+		 * big endian I/O peripherals
+		 */
+		iowrite8(ch, regs->cerq);
+		iowrite8(EDMA_CEEI_CEEI(ch), regs->ceei);
+	}
 }
 EXPORT_SYMBOL_GPL(fsl_edma_disable_request);
 
diff --git a/drivers/dma/mcf-edma.c b/drivers/dma/mcf-edma.c
new file mode 100644
index 000000000000..4d30d5302649
--- /dev/null
+++ b/drivers/dma/mcf-edma.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (c) 2013-2014 Freescale Semiconductor, Inc
+// Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dma-mcf-edma.h>
+
+#include "fsl-edma-common.h"
+
+#define EDMA_CHANNELS		64
+#define EDMA_MASK_CH(x)		((x) & GENMASK(5, 0))
+
+static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
+{
+	struct fsl_edma_engine *mcf_edma = dev_id;
+	struct edma_regs *regs = &mcf_edma->regs;
+	unsigned int ch;
+	struct fsl_edma_chan *mcf_chan;
+	u64 intmap;
+
+	intmap = ioread32(regs->inth);
+	intmap <<= 32;
+	intmap |= ioread32(regs->intl);
+	if (!intmap)
+		return IRQ_NONE;
+
+	for (ch = 0; ch < mcf_edma->n_chans; ch++) {
+		if (intmap & BIT(ch)) {
+			iowrite8(EDMA_MASK_CH(ch), regs->cint);
+
+			mcf_chan = &mcf_edma->chans[ch];
+
+			spin_lock(&mcf_chan->vchan.lock);
+			if (!mcf_chan->edesc->iscyclic) {
+				list_del(&mcf_chan->edesc->vdesc.node);
+				vchan_cookie_complete(&mcf_chan->edesc->vdesc);
+				mcf_chan->edesc = NULL;
+				mcf_chan->status = DMA_COMPLETE;
+				mcf_chan->idle = true;
+			} else {
+				vchan_cyclic_callback(&mcf_chan->edesc->vdesc);
+			}
+
+			if (!mcf_chan->edesc)
+				fsl_edma_xfer_desc(mcf_chan);
+
+			spin_unlock(&mcf_chan->vchan.lock);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
+{
+	struct fsl_edma_engine *mcf_edma = dev_id;
+	struct edma_regs *regs = &mcf_edma->regs;
+	unsigned int err, ch;
+
+	err = ioread32(regs->errl);
+	if (!err)
+		return IRQ_NONE;
+
+	for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
+		if (err & BIT(ch)) {
+			fsl_edma_disable_request(&mcf_edma->chans[ch]);
+			iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
+			mcf_edma->chans[ch].status = DMA_ERROR;
+			mcf_edma->chans[ch].idle = true;
+		}
+	}
+
+	err = ioread32(regs->errh);
+	if (!err)
+		return IRQ_NONE;
+
+	for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
+		if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
+			fsl_edma_disable_request(&mcf_edma->chans[ch]);
+			iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
+			mcf_edma->chans[ch].status = DMA_ERROR;
+			mcf_edma->chans[ch].idle = true;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mcf_edma_irq_init(struct platform_device *pdev,
+				struct fsl_edma_engine *mcf_edma)
+{
+	int ret = 0, i;
+	struct resource *res;
+
+	res = platform_get_resource_byname(pdev,
+				IORESOURCE_IRQ, "edma-tx-00-15");
+	if (!res)
+		return -1;
+
+	for (ret = 0, i = res->start; i <= res->end; ++i)
+		ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
+	if (ret)
+		return ret;
+
+	res = platform_get_resource_byname(pdev,
+			IORESOURCE_IRQ, "edma-tx-16-55");
+	if (!res)
+		return -1;
+
+	for (ret = 0, i = res->start; i <= res->end; ++i)
+		ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
+	if (ret)
+		return ret;
+
+	ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
+	if (ret != -ENXIO) {
+		ret = request_irq(ret, mcf_edma_tx_handler,
+				  0, "eDMA", mcf_edma);
+		if (ret)
+			return ret;
+	}
+
+	ret = platform_get_irq_byname(pdev, "edma-err");
+	if (ret != -ENXIO) {
+		ret = request_irq(ret, mcf_edma_err_handler,
+				  0, "eDMA", mcf_edma);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void mcf_edma_irq_free(struct platform_device *pdev,
+				struct fsl_edma_engine *mcf_edma)
+{
+	int irq;
+	struct resource *res;
+
+	res = platform_get_resource_byname(pdev,
+			IORESOURCE_IRQ, "edma-tx-00-15");
+	if (res) {
+		for (irq = res->start; irq <= res->end; irq++)
+			free_irq(irq, mcf_edma);
+	}
+
+	res = platform_get_resource_byname(pdev,
+			IORESOURCE_IRQ, "edma-tx-16-55");
+	if (res) {
+		for (irq = res->start; irq <= res->end; irq++)
+			free_irq(irq, mcf_edma);
+	}
+
+	irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
+	if (irq != -ENXIO)
+		free_irq(irq, mcf_edma);
+
+	irq = platform_get_irq_byname(pdev, "edma-err");
+	if (irq != -ENXIO)
+		free_irq(irq, mcf_edma);
+}
+
+static int mcf_edma_probe(struct platform_device *pdev)
+{
+	struct mcf_edma_platform_data *pdata;
+	struct fsl_edma_engine *mcf_edma;
+	struct fsl_edma_chan *mcf_chan;
+	struct edma_regs *regs;
+	struct resource *res;
+	int ret, i, len, chans;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data supplied\n");
+		return -EINVAL;
+	}
+
+	chans = pdata->dma_channels;
+	len = sizeof(*mcf_edma) + sizeof(*mcf_chan) * chans;
+	mcf_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+	if (!mcf_edma)
+		return -ENOMEM;
+
+	mcf_edma->n_chans = chans;
+
+	/* Set up version for ColdFire edma */
+	mcf_edma->version = v2;
+	mcf_edma->big_endian = 1;
+
+	if (!mcf_edma->n_chans) {
+		dev_info(&pdev->dev, "setting default channel number to 64");
+		mcf_edma->n_chans = 64;
+	}
+
+	mutex_init(&mcf_edma->fsl_edma_mutex);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	mcf_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mcf_edma->membase))
+		return PTR_ERR(mcf_edma->membase);
+
+	fsl_edma_setup_regs(mcf_edma);
+	regs = &mcf_edma->regs;
+
+	INIT_LIST_HEAD(&mcf_edma->dma_dev.channels);
+	for (i = 0; i < mcf_edma->n_chans; i++) {
+		struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i];
+
+		mcf_chan->edma = mcf_edma;
+		mcf_chan->slave_id = i;
+		mcf_chan->idle = true;
+		mcf_chan->vchan.desc_free = fsl_edma_free_desc;
+		vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev);
+		iowrite32(0x0, &regs->tcd[i].csr);
+	}
+
+	iowrite32(~0, regs->inth);
+	iowrite32(~0, regs->intl);
+
+	ret = mcf_edma_irq_init(pdev, mcf_edma);
+	if (ret)
+		return ret;
+
+	dma_cap_set(DMA_PRIVATE, mcf_edma->dma_dev.cap_mask);
+	dma_cap_set(DMA_SLAVE, mcf_edma->dma_dev.cap_mask);
+	dma_cap_set(DMA_CYCLIC, mcf_edma->dma_dev.cap_mask);
+
+	mcf_edma->dma_dev.dev = &pdev->dev;
+	mcf_edma->dma_dev.device_alloc_chan_resources =
+			fsl_edma_alloc_chan_resources;
+	mcf_edma->dma_dev.device_free_chan_resources =
+			fsl_edma_free_chan_resources;
+	mcf_edma->dma_dev.device_config = fsl_edma_slave_config;
+	mcf_edma->dma_dev.device_prep_dma_cyclic =
+			fsl_edma_prep_dma_cyclic;
+	mcf_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
+	mcf_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
+	mcf_edma->dma_dev.device_pause = fsl_edma_pause;
+	mcf_edma->dma_dev.device_resume = fsl_edma_resume;
+	mcf_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
+	mcf_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
+
+	mcf_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
+	mcf_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
+	mcf_edma->dma_dev.directions =
+			BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+
+	mcf_edma->dma_dev.filter.fn = mcf_edma_filter_fn;
+	mcf_edma->dma_dev.filter.map = pdata->slave_map;
+	mcf_edma->dma_dev.filter.mapcnt = pdata->slavecnt;
+
+	platform_set_drvdata(pdev, mcf_edma);
+
+	ret = dma_async_device_register(&mcf_edma->dma_dev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Can't register Freescale eDMA engine. (%d)\n", ret);
+		return ret;
+	}
+
+	/* Enable round robin arbitration */
+	iowrite32(EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
+
+	return 0;
+}
+
+static int mcf_edma_remove(struct platform_device *pdev)
+{
+	struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
+
+	mcf_edma_irq_free(pdev, mcf_edma);
+	fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
+	dma_async_device_unregister(&mcf_edma->dma_dev);
+
+	return 0;
+}
+
+static struct platform_driver mcf_edma_driver = {
+	.driver		= {
+		.name	= "mcf-edma",
+	},
+	.probe		= mcf_edma_probe,
+	.remove		= mcf_edma_remove,
+};
+
+bool mcf_edma_filter_fn(struct dma_chan *chan, void *param)
+{
+	if (chan->device->dev->driver == &mcf_edma_driver.driver) {
+		struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan);
+
+		return (mcf_chan->slave_id == (u32)param);
+	}
+
+	return false;
+}
+EXPORT_SYMBOL(mcf_edma_filter_fn);
+
+static int __init mcf_edma_init(void)
+{
+	return platform_driver_register(&mcf_edma_driver);
+}
+subsys_initcall(mcf_edma_init);
+
+static void __exit mcf_edma_exit(void)
+{
+	platform_driver_unregister(&mcf_edma_driver);
+}
+module_exit(mcf_edma_exit);
+
+MODULE_ALIAS("platform:mcf-edma");
+MODULE_DESCRIPTION("Freescale eDMA engine driver, ColdFire family");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/dma-mcf-edma.h b/include/linux/platform_data/dma-mcf-edma.h
new file mode 100644
index 000000000000..d718ccfa3421
--- /dev/null
+++ b/include/linux/platform_data/dma-mcf-edma.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Freescale eDMA platform data, ColdFire SoC's family.
+ *
+ * Copyright (c) 2017 Angelo Dureghello <angelo@sysam.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_MCF_EDMA_H__
+#define __LINUX_PLATFORM_DATA_MCF_EDMA_H__
+
+struct dma_slave_map;
+
+bool mcf_edma_filter_fn(struct dma_chan *chan, void *param);
+
+#define MCF_EDMA_FILTER_PARAM(ch)	((void *)ch)
+
+/**
+ * struct mcf_edma_platform_data - platform specific data for eDMA engine
+ *
+ * @ver			The eDMA module version.
+ * @dma_channels	The number of eDMA channels.
+ */
+struct mcf_edma_platform_data {
+	int dma_channels;
+	const struct dma_slave_map *slave_map;
+	int slavecnt;
+};
+
+#endif /* __LINUX_PLATFORM_DATA_MCF_EDMA_H__ */

^ permalink raw reply related

* [3/3] dmaengine: at_xdmac: move spin_lock_bh to spin_lock in tasklet
From: Ludovic Desroches @ 2018-08-20  9:28 UTC (permalink / raw)
  To: Barry Song
  Cc: vkoul, dan.j.williams, linux-arm-kernel, dmaengine, linux-kernel

On Fri, Aug 17, 2018 at 06:03:43AM -0700, Barry Song wrote:
> as you are already in a tasklet, it is unnecessary to call spin_lock_bh.
> 
> Signed-off-by: Barry Song <21cnbao@gmail.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com> 

Thanks
> ---
>  drivers/dma/at_xdmac.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
> index 4bf7256..4e55768 100644
> --- a/drivers/dma/at_xdmac.c
> +++ b/drivers/dma/at_xdmac.c
> @@ -1600,7 +1600,7 @@ static void at_xdmac_tasklet(unsigned long data)
>  		if (atchan->status & AT_XDMAC_CIS_ROIS)
>  			dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
>  
> -		spin_lock_bh(&atchan->lock);
> +		spin_lock(&atchan->lock);
>  		desc = list_first_entry(&atchan->xfers_list,
>  					struct at_xdmac_desc,
>  					xfer_node);
> @@ -1610,7 +1610,7 @@ static void at_xdmac_tasklet(unsigned long data)
>  		txd = &desc->tx_dma_desc;
>  
>  		at_xdmac_remove_xfer(atchan, desc);
> -		spin_unlock_bh(&atchan->lock);
> +		spin_unlock(&atchan->lock);
>  
>  		if (!at_xdmac_chan_is_cyclic(atchan)) {
>  			dma_cookie_complete(txd);
> -- 
> 2.7.4
>

^ permalink raw reply

* [1/3] dmaengine: xilinx_dma: Refactor axidma channel allocation
From: Appana Durga Kedareswara Rao @ 2018-08-21  7:31 UTC (permalink / raw)
  To: Radhey Shyam Pandey, dan.j.williams@intel.com, vkoul@kernel.org,
	Michal Simek, lars@metafoo.de
  Cc: dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org

Hi,

	Thanks for the patch... 
> 
> In axidma alloc_chan_resources merge BD and cyclic BD allocation.
> 
> Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>

Acked-for-series: Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>

Regards,
Kedar.

> ---
>  drivers/dma/xilinx/xilinx_dma.c |   36 ++++++++++++++++++------------------
>  1 files changed, 18 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/dma/xilinx/xilinx_dma.c
> b/drivers/dma/xilinx/xilinx_dma.c index c124423..06d1632 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -887,6 +887,24 @@ static int xilinx_dma_alloc_chan_resources(struct
> dma_chan *dchan)
>  				chan->id);
>  			return -ENOMEM;
>  		}
> +		/*
> +		 * For cyclic DMA mode we need to program the tail
> Descriptor
> +		 * register with a value which is not a part of the BD chain
> +		 * so allocating a desc segment during channel allocation for
> +		 * programming tail descriptor.
> +		 */
> +		chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev,
> +					sizeof(*chan->cyclic_seg_v),
> +					&chan->cyclic_seg_p, GFP_KERNEL);
> +		if (!chan->cyclic_seg_v) {
> +			dev_err(chan->dev,
> +				"unable to allocate desc segment for cyclic
> DMA\n");
> +			dma_free_coherent(chan->dev, sizeof(*chan->seg_v)
> *
> +				XILINX_DMA_NUM_DESCS, chan->seg_v,
> +				chan->seg_p);
> +			return -ENOMEM;
> +		}
> +		chan->cyclic_seg_v->phys = chan->cyclic_seg_p;
> 
>  		for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) {
>  			chan->seg_v[i].hw.next_desc =
> @@ -922,24 +940,6 @@ static int xilinx_dma_alloc_chan_resources(struct
> dma_chan *dchan)
>  		return -ENOMEM;
>  	}
> 
> -	if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
> -		/*
> -		 * For cyclic DMA mode we need to program the tail
> Descriptor
> -		 * register with a value which is not a part of the BD chain
> -		 * so allocating a desc segment during channel allocation for
> -		 * programming tail descriptor.
> -		 */
> -		chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev,
> -					sizeof(*chan->cyclic_seg_v),
> -					&chan->cyclic_seg_p, GFP_KERNEL);
> -		if (!chan->cyclic_seg_v) {
> -			dev_err(chan->dev,
> -				"unable to allocate desc segment for cyclic
> DMA\n");
> -			return -ENOMEM;
> -		}
> -		chan->cyclic_seg_v->phys = chan->cyclic_seg_p;
> -	}
> -
>  	dma_cookie_init(dchan);
> 
>  	if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
> --
> 1.7.1

^ permalink raw reply

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Masahiro Yamada @ 2018-08-21  9:30 UTC (permalink / raw)
  To: Vinod Koul, dmaengine; +Cc: Masami Hiramatsu, Jassi Brar, Masahiro Yamada

The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
Pro4, and sLD8 SoCs.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt

diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
new file mode 100644
index 0000000..a9e969e
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
@@ -0,0 +1,28 @@
+UniPhier Media IO DMA controller
+
+This works as an external DMA engine for SD/eMMC controllers etc.
+found in UniPhier LD4, Pro4, sLD8 SoCs.
+
+Required properties:
+- compatible: should be "socionext,uniphier-mio-dmac".
+- reg: offset and length of the register set for the device.
+- interrupts: a list of interrupt specifiers associated with the DMA channels.
+- clocks: a single clock specifier
+- #dma-cells: should be <1>. The single cell represents the channel number.
+- dma-channels: specify the number of the DMA channels. This should match to
+  the number of tuples in the interrupts property.
+
+Example:
+	dmac: dmac@5a000000 {
+		compatible = "socionext,uniphier-mio-dmac";
+		reg = <0x5a000000 0x1000>;
+		interrupts = <0 68 4>, <0 68 4>, <0 69 4>, <0 70 4>,
+			     <0 71 4>, <0 72 4>, <0 73 4>, <0 74 4>;
+		clocks = <&mio_clk 7>;
+		#dma-cells = <1>;
+		dma-channels = <8>;
+	};
+
+Note:
+In the example above, "interrupts = <0 68 4>, <0 68 4>, ..." is not a typo.
+The first two channels share a single interrupt line.

^ permalink raw reply related

* [2/2] dmaengine: uniphier-mdmac: add UniPhier MIO DMAC driver
From: Masahiro Yamada @ 2018-08-21  9:30 UTC (permalink / raw)
  To: Vinod Koul, dmaengine; +Cc: Masami Hiramatsu, Jassi Brar, Masahiro Yamada

The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
Pro4, and sLD8 SoCs.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 MAINTAINERS                  |   1 +
 drivers/dma/Kconfig          |  11 +
 drivers/dma/Makefile         |   1 +
 drivers/dma/uniphier-mdmac.c | 484 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 497 insertions(+)
 create mode 100644 drivers/dma/uniphier-mdmac.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8838bf1..c15a024 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2171,6 +2171,7 @@ F:	arch/arm/mm/cache-uniphier.c
 F:	arch/arm64/boot/dts/socionext/uniphier*
 F:	drivers/bus/uniphier-system-bus.c
 F:	drivers/clk/uniphier/
+F:	drivers/dmaengine/uniphier-mdmac.c
 F:	drivers/gpio/gpio-uniphier.c
 F:	drivers/i2c/busses/i2c-uniphier*
 F:	drivers/irqchip/irq-uniphier-aidet.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index dacf3f4..8b8c7f0 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -576,6 +576,17 @@ config TIMB_DMA
 	help
 	  Enable support for the Timberdale FPGA DMA engine.
 
+config UNIPHIER_MDMAC
+	tristate "UniPhier MIO DMAC"
+	depends on ARCH_UNIPHIER || COMPILE_TEST
+	depends on OF
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Enable support for the MIO DMAC (Media I/O DMA controller) on the
+	  UniPhier platform.  This DMA controller is used as the external
+	  DMA engine of the SD/eMMC controllers of the LD4, Pro4, sLD8 SoCs.
+
 config XGENE_DMA
 	tristate "APM X-Gene DMA support"
 	depends on ARCH_XGENE || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index c91702d..973a170 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
 obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
 obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
+obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
 obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
 obj-$(CONFIG_ZX_DMA) += zx_dma.o
 obj-$(CONFIG_ST_FDMA) += st_fdma.o
diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c
new file mode 100644
index 0000000..d558851
--- /dev/null
+++ b/drivers/dma/uniphier-mdmac.c
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2018 Socionext Inc.
+//   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "virt-dma.h"
+
+/* registers common for all channels */
+#define UNIPHIER_MDMAC_CMD		0x000	// issue DMA start/abort
+#define   UNIPHIER_MDMAC_CMD_ABORT		BIT(31) // 1: abort, 0: start
+
+/* per-channel registers */
+#define UNIPHIER_MDMAC_CH_OFFSET	0x100
+#define UNIPHIER_MDMAC_CH_STRIDE	0x040
+
+#define UNIPHIER_MDMAC_CH_IRQ_STAT	0x010	// current hw status (RO)
+#define UNIPHIER_MDMAC_CH_IRQ_REQ	0x014	// latched STAT (WOC)
+#define UNIPHIER_MDMAC_CH_IRQ_EN	0x018	// IRQ enable mask
+#define UNIPHIER_MDMAC_CH_IRQ_DET	0x01c	// REQ & EN (RO)
+#define   UNIPHIER_MDMAC_CH_IRQ__ABORT		BIT(13)
+#define   UNIPHIER_MDMAC_CH_IRQ__DONE		BIT(1)
+#define UNIPHIER_MDMAC_CH_SRC_MODE	0x020	// mode of source
+#define UNIPHIER_MDMAC_CH_DEST_MODE	0x024	// mode of destination
+#define   UNIPHIER_MDMAC_CH_MODE__ADDR_INC	(0 << 4)
+#define   UNIPHIER_MDMAC_CH_MODE__ADDR_DEC	(1 << 4)
+#define   UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED	(2 << 4)
+#define UNIPHIER_MDMAC_CH_SRC_ADDR	0x028	// source address
+#define UNIPHIER_MDMAC_CH_DEST_ADDR	0x02c	// destination address
+#define UNIPHIER_MDMAC_CH_SIZE		0x030	// transfer bytes
+
+struct uniphier_mdmac_desc {
+	struct virt_dma_desc vd;
+	struct scatterlist *sgl;
+	unsigned int sg_len;
+	unsigned int sg_cur;
+	enum dma_transfer_direction dir;
+};
+
+struct uniphier_mdmac_chan {
+	struct virt_dma_chan vc;
+	struct uniphier_mdmac_device *mdev;
+	struct uniphier_mdmac_desc *md;
+	void __iomem *reg_ch_base;
+	unsigned int chan_id;
+};
+
+struct uniphier_mdmac_device {
+	struct dma_device ddev;
+	struct clk *clk;
+	void __iomem *reg_base;
+	struct uniphier_mdmac_chan channels[0];
+};
+
+static struct uniphier_mdmac_chan *to_uniphier_mdmac_chan(
+						struct virt_dma_chan *vc)
+{
+	return container_of(vc, struct uniphier_mdmac_chan, vc);
+}
+
+static struct uniphier_mdmac_desc *to_uniphier_mdmac_desc(
+						struct virt_dma_desc *vd)
+{
+	return container_of(vd, struct uniphier_mdmac_desc, vd);
+}
+
+/* mc->vc.lock must be held by caller */
+static struct uniphier_mdmac_desc *__uniphier_mdmac_next_desc(
+						struct uniphier_mdmac_chan *mc)
+{
+	struct virt_dma_desc *vd;
+
+	vd = vchan_next_desc(&mc->vc);
+	if (!vd) {
+		mc->md = NULL;
+		return NULL;
+	}
+
+	list_del(&vd->node);
+
+	mc->md = to_uniphier_mdmac_desc(vd);
+
+	return mc->md;
+}
+
+/* mc->vc.lock must be held by caller */
+static void __uniphier_mdmac_handle(struct uniphier_mdmac_chan *mc,
+				    struct uniphier_mdmac_desc *md)
+{
+	struct uniphier_mdmac_device *mdev = mc->mdev;
+	struct scatterlist *sg;
+	u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__DONE;
+	u32 src_mode, src_addr, dest_mode, dest_addr, chunk_size;
+
+	sg = &md->sgl[md->sg_cur];
+
+	if (md->dir == DMA_MEM_TO_DEV) {
+		src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
+		src_addr = sg_dma_address(sg);
+		dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
+		dest_addr = 0;
+	} else {
+		src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
+		src_addr = 0;
+		dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
+		dest_addr = sg_dma_address(sg);
+	}
+
+	chunk_size = sg_dma_len(sg);
+
+	writel(src_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_MODE);
+	writel(dest_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_MODE);
+	writel(src_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_ADDR);
+	writel(dest_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_ADDR);
+	writel(chunk_size, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SIZE);
+
+	/* write 1 to clear */
+	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
+
+	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_EN);
+
+	writel(BIT(mc->chan_id), mdev->reg_base + UNIPHIER_MDMAC_CMD);
+}
+
+/* mc->vc.lock must be held by caller */
+static void __uniphier_mdmac_start(struct uniphier_mdmac_chan *mc)
+{
+	struct uniphier_mdmac_desc *md;
+
+	md = __uniphier_mdmac_next_desc(mc);
+	if (md)
+		__uniphier_mdmac_handle(mc, md);
+}
+
+/* mc->vc.lock must be held by caller */
+static int __uniphier_mdmac_abort(struct uniphier_mdmac_chan *mc)
+{
+	struct uniphier_mdmac_device *mdev = mc->mdev;
+	u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__ABORT;
+	u32 val;
+
+	/* write 1 to clear */
+	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
+
+	writel(UNIPHIER_MDMAC_CMD_ABORT | BIT(mc->chan_id),
+	       mdev->reg_base + UNIPHIER_MDMAC_CMD);
+
+	/*
+	 * Abort should be accepted soon. We poll the bit here instead of
+	 * waiting for the interrupt.
+	 */
+	return readl_poll_timeout(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ,
+				  val, val & irq_flag, 0, 20);
+}
+
+/* mc->vc.lock must be held by caller */
+static u32 __uniphier_mdmac_get_residue(struct uniphier_mdmac_desc *md)
+{
+	u32 residue = 0;
+	int i;
+
+	for (i = md->sg_cur; i < md->sg_len; i++)
+		residue += sg_dma_len(&md->sgl[i]);
+
+	return residue;
+}
+
+static irqreturn_t uniphier_mdmac_interrupt(int irq, void *dev_id)
+{
+	struct uniphier_mdmac_chan *mc = dev_id;
+	struct uniphier_mdmac_desc *md;
+	irqreturn_t ret = IRQ_HANDLED;
+	u32 irq_stat;
+
+	spin_lock(&mc->vc.lock);
+
+	irq_stat = readl(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_DET);
+
+	/*
+	 * Some channels share a single interrupt line. If the IRQ status is 0,
+	 * this is probably triggered by a different channel.
+	 */
+	if (!irq_stat) {
+		ret = IRQ_NONE;
+		goto out;
+	}
+
+	/* write 1 to clear */
+	writel(irq_stat, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
+
+	/*
+	 * UNIPHIER_MDMAC_CH_IRQ__DONE interrupt is asserted even when the DMA
+	 * is aborted.  To distinguish the normal completion and the abort,
+	 * check mc->md.  If it is NULL, we are aborting.
+	 */
+	md = mc->md;
+	if (!md)
+		goto out;
+
+	md->sg_cur++;
+
+	if (md->sg_cur >= md->sg_len) {
+		vchan_cookie_complete(&md->vd);
+		md = __uniphier_mdmac_next_desc(mc);
+		if (!md)
+			goto out;
+	}
+
+	__uniphier_mdmac_handle(mc, md);
+
+out:
+	spin_unlock(&mc->vc.lock);
+
+	return ret;
+}
+
+static struct dma_async_tx_descriptor *uniphier_mdmac_prep_slave_sg(
+					struct dma_chan *chan,
+					struct scatterlist *sgl,
+					unsigned int sg_len,
+					enum dma_transfer_direction direction,
+					unsigned long flags, void *context)
+{
+	struct virt_dma_chan *vc = to_virt_chan(chan);
+	struct uniphier_mdmac_desc *md;
+
+	if (!is_slave_direction(direction))
+		return NULL;
+
+	md = kzalloc(sizeof(*md), GFP_KERNEL);
+	if (!md)
+		return NULL;
+
+	md->sgl = sgl;
+	md->sg_len = sg_len;
+	md->dir = direction;
+
+	return vchan_tx_prep(vc, &md->vd, flags);
+}
+
+static int uniphier_mdmac_terminate_all(struct dma_chan *chan)
+{
+	struct virt_dma_chan *vc = to_virt_chan(chan);
+	struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
+	unsigned long flags;
+	int ret = 0;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&vc->lock, flags);
+
+	if (mc->md) {
+		vchan_terminate_vdesc(&mc->md->vd);
+		mc->md = NULL;
+		ret = __uniphier_mdmac_abort(mc);
+	}
+	vchan_get_all_descriptors(vc, &head);
+
+	spin_unlock_irqrestore(&vc->lock, flags);
+
+	vchan_dma_desc_free_list(vc, &head);
+
+	return ret;
+}
+
+static void uniphier_mdmac_synchronize(struct dma_chan *chan)
+{
+	vchan_synchronize(to_virt_chan(chan));
+}
+
+static enum dma_status uniphier_mdmac_tx_status(struct dma_chan *chan,
+						dma_cookie_t cookie,
+						struct dma_tx_state *txstate)
+{
+	struct virt_dma_chan *vc;
+	struct virt_dma_desc *vd;
+	struct uniphier_mdmac_chan *mc;
+	struct uniphier_mdmac_desc *md = NULL;
+	enum dma_status stat;
+	unsigned long flags;
+
+	stat = dma_cookie_status(chan, cookie, txstate);
+	if (stat == DMA_COMPLETE)
+		return stat;
+
+	vc = to_virt_chan(chan);
+
+	spin_lock_irqsave(&vc->lock, flags);
+
+	mc = to_uniphier_mdmac_chan(vc);
+
+	if (mc->md && mc->md->vd.tx.cookie == cookie)
+		md = mc->md;
+
+	if (!md) {
+		vd = vchan_find_desc(vc, cookie);
+		if (vd)
+			md = to_uniphier_mdmac_desc(vd);
+	}
+
+	if (md)
+		txstate->residue = __uniphier_mdmac_get_residue(md);
+
+	spin_unlock_irqrestore(&vc->lock, flags);
+
+	return stat;
+}
+
+static void uniphier_mdmac_issue_pending(struct dma_chan *chan)
+{
+	struct virt_dma_chan *vc = to_virt_chan(chan);
+	struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&vc->lock, flags);
+
+	if (vchan_issue_pending(vc) && !mc->md)
+		__uniphier_mdmac_start(mc);
+
+	spin_unlock_irqrestore(&vc->lock, flags);
+}
+
+static void uniphier_mdmac_desc_free(struct virt_dma_desc *vd)
+{
+	kfree(to_uniphier_mdmac_desc(vd));
+}
+
+static int uniphier_mdmac_chan_init(struct platform_device *pdev,
+				    struct uniphier_mdmac_device *mdev,
+				    int chan_id)
+{
+	struct device *dev = &pdev->dev;
+	struct uniphier_mdmac_chan *mc = &mdev->channels[chan_id];
+	char *irq_name;
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, chan_id);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get IRQ number for ch%d\n",
+			chan_id);
+		return irq;
+	}
+
+	irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d",
+				  chan_id);
+	if (!irq_name)
+		return -ENOMEM;
+
+	ret = devm_request_irq(dev, irq, uniphier_mdmac_interrupt,
+			       IRQF_SHARED, irq_name, mc);
+	if (ret)
+		return ret;
+
+	mc->mdev = mdev;
+	mc->reg_ch_base = mdev->reg_base + UNIPHIER_MDMAC_CH_OFFSET +
+					UNIPHIER_MDMAC_CH_STRIDE * chan_id;
+	mc->chan_id = chan_id;
+	mc->vc.desc_free = uniphier_mdmac_desc_free;
+	vchan_init(&mc->vc, &mdev->ddev);
+
+	return 0;
+}
+
+static int uniphier_mdmac_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct uniphier_mdmac_device *mdev;
+	struct dma_device *ddev;
+	struct resource *res;
+	u32 nr_chans;
+	int ret, i;
+
+	ret = of_property_read_u32(dev->of_node, "dma-channels", &nr_chans);
+	if (ret) {
+		dev_err(dev, "failed to read dma-channels property\n");
+		return ret;
+	}
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
+			    GFP_KERNEL);
+	if (!mdev)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mdev->reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mdev->reg_base))
+		return PTR_ERR(mdev->reg_base);
+
+	mdev->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(mdev->clk)) {
+		dev_err(dev, "failed to get clock\n");
+		return PTR_ERR(mdev->clk);
+	}
+
+	ret = clk_prepare_enable(mdev->clk);
+	if (ret)
+		return ret;
+
+	ddev = &mdev->ddev;
+	ddev->dev = dev;
+	dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
+	ddev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
+	ddev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
+	ddev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+	ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+	ddev->device_prep_slave_sg = uniphier_mdmac_prep_slave_sg;
+	ddev->device_terminate_all = uniphier_mdmac_terminate_all;
+	ddev->device_synchronize = uniphier_mdmac_synchronize;
+	ddev->device_tx_status = uniphier_mdmac_tx_status;
+	ddev->device_issue_pending = uniphier_mdmac_issue_pending;
+	INIT_LIST_HEAD(&ddev->channels);
+
+	for (i = 0; i < nr_chans; i++) {
+		ret = uniphier_mdmac_chan_init(pdev, mdev, i);
+		if (ret)
+			goto disable_clk;
+	}
+
+	ret = dma_async_device_register(ddev);
+	if (ret)
+		goto disable_clk;
+
+	ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id,
+					 ddev);
+	if (ret)
+		goto unregister_dmac;
+
+	platform_set_drvdata(pdev, mdev);
+
+	return 0;
+
+unregister_dmac:
+	dma_async_device_unregister(ddev);
+disable_clk:
+	clk_disable_unprepare(mdev->clk);
+
+	return ret;
+}
+
+static int uniphier_mdmac_remove(struct platform_device *pdev)
+{
+	struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
+
+	of_dma_controller_free(pdev->dev.of_node);
+	dma_async_device_unregister(&mdev->ddev);
+	clk_disable_unprepare(mdev->clk);
+
+	return 0;
+}
+
+static const struct of_device_id uniphier_mdmac_match[] = {
+	{ .compatible = "socionext,uniphier-mio-dmac" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_mdmac_match);
+
+static struct platform_driver uniphier_mdmac_driver = {
+	.probe = uniphier_mdmac_probe,
+	.remove = uniphier_mdmac_remove,
+	.driver = {
+		.name = "uniphier-mio-dmac",
+		.of_match_table = uniphier_mdmac_match,
+	},
+};
+module_platform_driver(uniphier_mdmac_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier MIO DMAC driver");
+MODULE_LICENSE("GPL v2");

^ permalink raw reply related

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Masahiro Yamada @ 2018-08-21  9:47 UTC (permalink / raw)
  To: Vinod Koul, dmaengine
  Cc: Masami Hiramatsu, Jassi Brar, Masahiro Yamada, Rob Herring, DTML,
	Linux Kernel Mailing List

(+CC Rob, DT, LKML)

I forgot to CC this to DT community...


2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
> The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
> Pro4, and sLD8 SoCs.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> ---
>
>  .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>
> diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> new file mode 100644
> index 0000000..a9e969e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> @@ -0,0 +1,28 @@
> +UniPhier Media IO DMA controller
> +
> +This works as an external DMA engine for SD/eMMC controllers etc.
> +found in UniPhier LD4, Pro4, sLD8 SoCs.
> +
> +Required properties:
> +- compatible: should be "socionext,uniphier-mio-dmac".
> +- reg: offset and length of the register set for the device.
> +- interrupts: a list of interrupt specifiers associated with the DMA channels.
> +- clocks: a single clock specifier
> +- #dma-cells: should be <1>. The single cell represents the channel number.
> +- dma-channels: specify the number of the DMA channels. This should match to
> +  the number of tuples in the interrupts property.
> +
> +Example:
> +       dmac: dmac@5a000000 {
> +               compatible = "socionext,uniphier-mio-dmac";
> +               reg = <0x5a000000 0x1000>;
> +               interrupts = <0 68 4>, <0 68 4>, <0 69 4>, <0 70 4>,
> +                            <0 71 4>, <0 72 4>, <0 73 4>, <0 74 4>;
> +               clocks = <&mio_clk 7>;
> +               #dma-cells = <1>;
> +               dma-channels = <8>;
> +       };
> +
> +Note:
> +In the example above, "interrupts = <0 68 4>, <0 68 4>, ..." is not a typo.
> +The first two channels share a single interrupt line.
> --
> 2.7.4
>

^ permalink raw reply

* [2/2] dmaengine: uniphier-mdmac: add UniPhier MIO DMAC driver
From: Masahiro Yamada @ 2018-08-21  9:52 UTC (permalink / raw)
  To: Vinod Koul, dmaengine
  Cc: Masami Hiramatsu, Jassi Brar, Masahiro Yamada,
	Linux Kernel Mailing List

(+CC LKML just in case)

2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
> The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
> Pro4, and sLD8 SoCs.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> ---
>
>  MAINTAINERS                  |   1 +
>  drivers/dma/Kconfig          |  11 +
>  drivers/dma/Makefile         |   1 +
>  drivers/dma/uniphier-mdmac.c | 484 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 497 insertions(+)
>  create mode 100644 drivers/dma/uniphier-mdmac.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8838bf1..c15a024 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2171,6 +2171,7 @@ F:        arch/arm/mm/cache-uniphier.c
>  F:     arch/arm64/boot/dts/socionext/uniphier*
>  F:     drivers/bus/uniphier-system-bus.c
>  F:     drivers/clk/uniphier/
> +F:     drivers/dmaengine/uniphier-mdmac.c
>  F:     drivers/gpio/gpio-uniphier.c
>  F:     drivers/i2c/busses/i2c-uniphier*
>  F:     drivers/irqchip/irq-uniphier-aidet.c
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index dacf3f4..8b8c7f0 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -576,6 +576,17 @@ config TIMB_DMA
>         help
>           Enable support for the Timberdale FPGA DMA engine.
>
> +config UNIPHIER_MDMAC
> +       tristate "UniPhier MIO DMAC"
> +       depends on ARCH_UNIPHIER || COMPILE_TEST
> +       depends on OF
> +       select DMA_ENGINE
> +       select DMA_VIRTUAL_CHANNELS
> +       help
> +         Enable support for the MIO DMAC (Media I/O DMA controller) on the
> +         UniPhier platform.  This DMA controller is used as the external
> +         DMA engine of the SD/eMMC controllers of the LD4, Pro4, sLD8 SoCs.
> +
>  config XGENE_DMA
>         tristate "APM X-Gene DMA support"
>         depends on ARCH_XGENE || COMPILE_TEST
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index c91702d..973a170 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
>  obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
>  obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
>  obj-$(CONFIG_TIMB_DMA) += timb_dma.o
> +obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
>  obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
>  obj-$(CONFIG_ZX_DMA) += zx_dma.o
>  obj-$(CONFIG_ST_FDMA) += st_fdma.o
> diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c
> new file mode 100644
> index 0000000..d558851
> --- /dev/null
> +++ b/drivers/dma/uniphier-mdmac.c
> @@ -0,0 +1,484 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (C) 2018 Socionext Inc.
> +//   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
> +
> +#include <linux/clk.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/dmaengine.h>
> +#include <linux/interrupt.h>
> +#include <linux/iopoll.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_dma.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include "virt-dma.h"
> +
> +/* registers common for all channels */
> +#define UNIPHIER_MDMAC_CMD             0x000   // issue DMA start/abort
> +#define   UNIPHIER_MDMAC_CMD_ABORT             BIT(31) // 1: abort, 0: start
> +
> +/* per-channel registers */
> +#define UNIPHIER_MDMAC_CH_OFFSET       0x100
> +#define UNIPHIER_MDMAC_CH_STRIDE       0x040
> +
> +#define UNIPHIER_MDMAC_CH_IRQ_STAT     0x010   // current hw status (RO)
> +#define UNIPHIER_MDMAC_CH_IRQ_REQ      0x014   // latched STAT (WOC)
> +#define UNIPHIER_MDMAC_CH_IRQ_EN       0x018   // IRQ enable mask
> +#define UNIPHIER_MDMAC_CH_IRQ_DET      0x01c   // REQ & EN (RO)
> +#define   UNIPHIER_MDMAC_CH_IRQ__ABORT         BIT(13)
> +#define   UNIPHIER_MDMAC_CH_IRQ__DONE          BIT(1)
> +#define UNIPHIER_MDMAC_CH_SRC_MODE     0x020   // mode of source
> +#define UNIPHIER_MDMAC_CH_DEST_MODE    0x024   // mode of destination
> +#define   UNIPHIER_MDMAC_CH_MODE__ADDR_INC     (0 << 4)
> +#define   UNIPHIER_MDMAC_CH_MODE__ADDR_DEC     (1 << 4)
> +#define   UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED   (2 << 4)
> +#define UNIPHIER_MDMAC_CH_SRC_ADDR     0x028   // source address
> +#define UNIPHIER_MDMAC_CH_DEST_ADDR    0x02c   // destination address
> +#define UNIPHIER_MDMAC_CH_SIZE         0x030   // transfer bytes
> +
> +struct uniphier_mdmac_desc {
> +       struct virt_dma_desc vd;
> +       struct scatterlist *sgl;
> +       unsigned int sg_len;
> +       unsigned int sg_cur;
> +       enum dma_transfer_direction dir;
> +};
> +
> +struct uniphier_mdmac_chan {
> +       struct virt_dma_chan vc;
> +       struct uniphier_mdmac_device *mdev;
> +       struct uniphier_mdmac_desc *md;
> +       void __iomem *reg_ch_base;
> +       unsigned int chan_id;
> +};
> +
> +struct uniphier_mdmac_device {
> +       struct dma_device ddev;
> +       struct clk *clk;
> +       void __iomem *reg_base;
> +       struct uniphier_mdmac_chan channels[0];
> +};
> +
> +static struct uniphier_mdmac_chan *to_uniphier_mdmac_chan(
> +                                               struct virt_dma_chan *vc)
> +{
> +       return container_of(vc, struct uniphier_mdmac_chan, vc);
> +}
> +
> +static struct uniphier_mdmac_desc *to_uniphier_mdmac_desc(
> +                                               struct virt_dma_desc *vd)
> +{
> +       return container_of(vd, struct uniphier_mdmac_desc, vd);
> +}
> +
> +/* mc->vc.lock must be held by caller */
> +static struct uniphier_mdmac_desc *__uniphier_mdmac_next_desc(
> +                                               struct uniphier_mdmac_chan *mc)
> +{
> +       struct virt_dma_desc *vd;
> +
> +       vd = vchan_next_desc(&mc->vc);
> +       if (!vd) {
> +               mc->md = NULL;
> +               return NULL;
> +       }
> +
> +       list_del(&vd->node);
> +
> +       mc->md = to_uniphier_mdmac_desc(vd);
> +
> +       return mc->md;
> +}
> +
> +/* mc->vc.lock must be held by caller */
> +static void __uniphier_mdmac_handle(struct uniphier_mdmac_chan *mc,
> +                                   struct uniphier_mdmac_desc *md)
> +{
> +       struct uniphier_mdmac_device *mdev = mc->mdev;
> +       struct scatterlist *sg;
> +       u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__DONE;
> +       u32 src_mode, src_addr, dest_mode, dest_addr, chunk_size;
> +
> +       sg = &md->sgl[md->sg_cur];
> +
> +       if (md->dir == DMA_MEM_TO_DEV) {
> +               src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
> +               src_addr = sg_dma_address(sg);
> +               dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
> +               dest_addr = 0;
> +       } else {
> +               src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
> +               src_addr = 0;
> +               dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
> +               dest_addr = sg_dma_address(sg);
> +       }
> +
> +       chunk_size = sg_dma_len(sg);
> +
> +       writel(src_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_MODE);
> +       writel(dest_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_MODE);
> +       writel(src_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_ADDR);
> +       writel(dest_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_ADDR);
> +       writel(chunk_size, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SIZE);
> +
> +       /* write 1 to clear */
> +       writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
> +
> +       writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_EN);
> +
> +       writel(BIT(mc->chan_id), mdev->reg_base + UNIPHIER_MDMAC_CMD);
> +}
> +
> +/* mc->vc.lock must be held by caller */
> +static void __uniphier_mdmac_start(struct uniphier_mdmac_chan *mc)
> +{
> +       struct uniphier_mdmac_desc *md;
> +
> +       md = __uniphier_mdmac_next_desc(mc);
> +       if (md)
> +               __uniphier_mdmac_handle(mc, md);
> +}
> +
> +/* mc->vc.lock must be held by caller */
> +static int __uniphier_mdmac_abort(struct uniphier_mdmac_chan *mc)
> +{
> +       struct uniphier_mdmac_device *mdev = mc->mdev;
> +       u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__ABORT;
> +       u32 val;
> +
> +       /* write 1 to clear */
> +       writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
> +
> +       writel(UNIPHIER_MDMAC_CMD_ABORT | BIT(mc->chan_id),
> +              mdev->reg_base + UNIPHIER_MDMAC_CMD);
> +
> +       /*
> +        * Abort should be accepted soon. We poll the bit here instead of
> +        * waiting for the interrupt.
> +        */
> +       return readl_poll_timeout(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ,
> +                                 val, val & irq_flag, 0, 20);
> +}
> +
> +/* mc->vc.lock must be held by caller */
> +static u32 __uniphier_mdmac_get_residue(struct uniphier_mdmac_desc *md)
> +{
> +       u32 residue = 0;
> +       int i;
> +
> +       for (i = md->sg_cur; i < md->sg_len; i++)
> +               residue += sg_dma_len(&md->sgl[i]);
> +
> +       return residue;
> +}
> +
> +static irqreturn_t uniphier_mdmac_interrupt(int irq, void *dev_id)
> +{
> +       struct uniphier_mdmac_chan *mc = dev_id;
> +       struct uniphier_mdmac_desc *md;
> +       irqreturn_t ret = IRQ_HANDLED;
> +       u32 irq_stat;
> +
> +       spin_lock(&mc->vc.lock);
> +
> +       irq_stat = readl(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_DET);
> +
> +       /*
> +        * Some channels share a single interrupt line. If the IRQ status is 0,
> +        * this is probably triggered by a different channel.
> +        */
> +       if (!irq_stat) {
> +               ret = IRQ_NONE;
> +               goto out;
> +       }
> +
> +       /* write 1 to clear */
> +       writel(irq_stat, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
> +
> +       /*
> +        * UNIPHIER_MDMAC_CH_IRQ__DONE interrupt is asserted even when the DMA
> +        * is aborted.  To distinguish the normal completion and the abort,
> +        * check mc->md.  If it is NULL, we are aborting.
> +        */
> +       md = mc->md;
> +       if (!md)
> +               goto out;
> +
> +       md->sg_cur++;
> +
> +       if (md->sg_cur >= md->sg_len) {
> +               vchan_cookie_complete(&md->vd);
> +               md = __uniphier_mdmac_next_desc(mc);
> +               if (!md)
> +                       goto out;
> +       }
> +
> +       __uniphier_mdmac_handle(mc, md);
> +
> +out:
> +       spin_unlock(&mc->vc.lock);
> +
> +       return ret;
> +}
> +
> +static struct dma_async_tx_descriptor *uniphier_mdmac_prep_slave_sg(
> +                                       struct dma_chan *chan,
> +                                       struct scatterlist *sgl,
> +                                       unsigned int sg_len,
> +                                       enum dma_transfer_direction direction,
> +                                       unsigned long flags, void *context)
> +{
> +       struct virt_dma_chan *vc = to_virt_chan(chan);
> +       struct uniphier_mdmac_desc *md;
> +
> +       if (!is_slave_direction(direction))
> +               return NULL;
> +
> +       md = kzalloc(sizeof(*md), GFP_KERNEL);
> +       if (!md)
> +               return NULL;
> +
> +       md->sgl = sgl;
> +       md->sg_len = sg_len;
> +       md->dir = direction;
> +
> +       return vchan_tx_prep(vc, &md->vd, flags);
> +}
> +
> +static int uniphier_mdmac_terminate_all(struct dma_chan *chan)
> +{
> +       struct virt_dma_chan *vc = to_virt_chan(chan);
> +       struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
> +       unsigned long flags;
> +       int ret = 0;
> +       LIST_HEAD(head);
> +
> +       spin_lock_irqsave(&vc->lock, flags);
> +
> +       if (mc->md) {
> +               vchan_terminate_vdesc(&mc->md->vd);
> +               mc->md = NULL;
> +               ret = __uniphier_mdmac_abort(mc);
> +       }
> +       vchan_get_all_descriptors(vc, &head);
> +
> +       spin_unlock_irqrestore(&vc->lock, flags);
> +
> +       vchan_dma_desc_free_list(vc, &head);
> +
> +       return ret;
> +}
> +
> +static void uniphier_mdmac_synchronize(struct dma_chan *chan)
> +{
> +       vchan_synchronize(to_virt_chan(chan));
> +}
> +
> +static enum dma_status uniphier_mdmac_tx_status(struct dma_chan *chan,
> +                                               dma_cookie_t cookie,
> +                                               struct dma_tx_state *txstate)
> +{
> +       struct virt_dma_chan *vc;
> +       struct virt_dma_desc *vd;
> +       struct uniphier_mdmac_chan *mc;
> +       struct uniphier_mdmac_desc *md = NULL;
> +       enum dma_status stat;
> +       unsigned long flags;
> +
> +       stat = dma_cookie_status(chan, cookie, txstate);
> +       if (stat == DMA_COMPLETE)
> +               return stat;
> +
> +       vc = to_virt_chan(chan);
> +
> +       spin_lock_irqsave(&vc->lock, flags);
> +
> +       mc = to_uniphier_mdmac_chan(vc);
> +
> +       if (mc->md && mc->md->vd.tx.cookie == cookie)
> +               md = mc->md;
> +
> +       if (!md) {
> +               vd = vchan_find_desc(vc, cookie);
> +               if (vd)
> +                       md = to_uniphier_mdmac_desc(vd);
> +       }
> +
> +       if (md)
> +               txstate->residue = __uniphier_mdmac_get_residue(md);
> +
> +       spin_unlock_irqrestore(&vc->lock, flags);
> +
> +       return stat;
> +}
> +
> +static void uniphier_mdmac_issue_pending(struct dma_chan *chan)
> +{
> +       struct virt_dma_chan *vc = to_virt_chan(chan);
> +       struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&vc->lock, flags);
> +
> +       if (vchan_issue_pending(vc) && !mc->md)
> +               __uniphier_mdmac_start(mc);
> +
> +       spin_unlock_irqrestore(&vc->lock, flags);
> +}
> +
> +static void uniphier_mdmac_desc_free(struct virt_dma_desc *vd)
> +{
> +       kfree(to_uniphier_mdmac_desc(vd));
> +}
> +
> +static int uniphier_mdmac_chan_init(struct platform_device *pdev,
> +                                   struct uniphier_mdmac_device *mdev,
> +                                   int chan_id)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct uniphier_mdmac_chan *mc = &mdev->channels[chan_id];
> +       char *irq_name;
> +       int irq, ret;
> +
> +       irq = platform_get_irq(pdev, chan_id);
> +       if (irq < 0) {
> +               dev_err(&pdev->dev, "failed to get IRQ number for ch%d\n",
> +                       chan_id);
> +               return irq;
> +       }
> +
> +       irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d",
> +                                 chan_id);
> +       if (!irq_name)
> +               return -ENOMEM;
> +
> +       ret = devm_request_irq(dev, irq, uniphier_mdmac_interrupt,
> +                              IRQF_SHARED, irq_name, mc);
> +       if (ret)
> +               return ret;
> +
> +       mc->mdev = mdev;
> +       mc->reg_ch_base = mdev->reg_base + UNIPHIER_MDMAC_CH_OFFSET +
> +                                       UNIPHIER_MDMAC_CH_STRIDE * chan_id;
> +       mc->chan_id = chan_id;
> +       mc->vc.desc_free = uniphier_mdmac_desc_free;
> +       vchan_init(&mc->vc, &mdev->ddev);
> +
> +       return 0;
> +}
> +
> +static int uniphier_mdmac_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct uniphier_mdmac_device *mdev;
> +       struct dma_device *ddev;
> +       struct resource *res;
> +       u32 nr_chans;
> +       int ret, i;
> +
> +       ret = of_property_read_u32(dev->of_node, "dma-channels", &nr_chans);
> +       if (ret) {
> +               dev_err(dev, "failed to read dma-channels property\n");
> +               return ret;
> +       }
> +
> +       ret = dma_set_mask(dev, DMA_BIT_MASK(32));
> +       if (ret)
> +               return ret;
> +
> +       mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
> +                           GFP_KERNEL);
> +       if (!mdev)
> +               return -ENOMEM;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       mdev->reg_base = devm_ioremap_resource(dev, res);
> +       if (IS_ERR(mdev->reg_base))
> +               return PTR_ERR(mdev->reg_base);
> +
> +       mdev->clk = devm_clk_get(dev, NULL);
> +       if (IS_ERR(mdev->clk)) {
> +               dev_err(dev, "failed to get clock\n");
> +               return PTR_ERR(mdev->clk);
> +       }
> +
> +       ret = clk_prepare_enable(mdev->clk);
> +       if (ret)
> +               return ret;
> +
> +       ddev = &mdev->ddev;
> +       ddev->dev = dev;
> +       dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
> +       ddev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> +       ddev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED);
> +       ddev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
> +       ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
> +       ddev->device_prep_slave_sg = uniphier_mdmac_prep_slave_sg;
> +       ddev->device_terminate_all = uniphier_mdmac_terminate_all;
> +       ddev->device_synchronize = uniphier_mdmac_synchronize;
> +       ddev->device_tx_status = uniphier_mdmac_tx_status;
> +       ddev->device_issue_pending = uniphier_mdmac_issue_pending;
> +       INIT_LIST_HEAD(&ddev->channels);
> +
> +       for (i = 0; i < nr_chans; i++) {
> +               ret = uniphier_mdmac_chan_init(pdev, mdev, i);
> +               if (ret)
> +                       goto disable_clk;
> +       }
> +
> +       ret = dma_async_device_register(ddev);
> +       if (ret)
> +               goto disable_clk;
> +
> +       ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id,
> +                                        ddev);
> +       if (ret)
> +               goto unregister_dmac;
> +
> +       platform_set_drvdata(pdev, mdev);
> +
> +       return 0;
> +
> +unregister_dmac:
> +       dma_async_device_unregister(ddev);
> +disable_clk:
> +       clk_disable_unprepare(mdev->clk);
> +
> +       return ret;
> +}
> +
> +static int uniphier_mdmac_remove(struct platform_device *pdev)
> +{
> +       struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
> +
> +       of_dma_controller_free(pdev->dev.of_node);
> +       dma_async_device_unregister(&mdev->ddev);
> +       clk_disable_unprepare(mdev->clk);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id uniphier_mdmac_match[] = {
> +       { .compatible = "socionext,uniphier-mio-dmac" },
> +       { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, uniphier_mdmac_match);
> +
> +static struct platform_driver uniphier_mdmac_driver = {
> +       .probe = uniphier_mdmac_probe,
> +       .remove = uniphier_mdmac_remove,
> +       .driver = {
> +               .name = "uniphier-mio-dmac",
> +               .of_match_table = uniphier_mdmac_match,
> +       },
> +};
> +module_platform_driver(uniphier_mdmac_driver);
> +
> +MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
> +MODULE_DESCRIPTION("UniPhier MIO DMAC driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.7.4
>

^ permalink raw reply

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Jassi Brar @ 2018-08-21 10:44 UTC (permalink / raw)
  To: Masahiro Yamada
  Cc: Vinod Koul, dmaengine, Masami Hiramatsu, Rob Herring, DTML,
	Linux Kernel Mailing List

On 21 August 2018 at 15:17, Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
> (+CC Rob, DT, LKML)
>
> I forgot to CC this to DT community...
>
>
> 2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
>> The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
>> Pro4, and sLD8 SoCs.
>>
>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>> ---
>>
>>  .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
>>  1 file changed, 28 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>
>> diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>> new file mode 100644
>> index 0000000..a9e969e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>> @@ -0,0 +1,28 @@
>> +UniPhier Media IO DMA controller
>> +
>> +This works as an external DMA engine for SD/eMMC controllers etc.
>> +found in UniPhier LD4, Pro4, sLD8 SoCs.
>> +
>> +Required properties:
>> +- compatible: should be "socionext,uniphier-mio-dmac".
>> +- reg: offset and length of the register set for the device.
>> +- interrupts: a list of interrupt specifiers associated with the DMA channels.
>> +- clocks: a single clock specifier
>> +- #dma-cells: should be <1>. The single cell represents the channel number.
>> +- dma-channels: specify the number of the DMA channels. This should match to
>> +  the number of tuples in the interrupts property.
>> +
Can we not infer the number of channels from interrupt tuples? After
all the driver assumes they are same.

^ permalink raw reply

* dma: mic_x100_dma: use devm_kzalloc to allocate mic_dma_dev
From: Vinod Koul @ 2018-08-21 11:34 UTC (permalink / raw)
  To: Huang Shijie; +Cc: dmaengine, sudeep.dutt, ashutosh.dixit

On 04-08-18, 10:15, Huang Shijie wrote:
> The following patch introduced an issue.
>        dmaengine: mic_x100_dma: use the new helper to simplify the code

please use cannaonical form for describing patches i.e., commit abcdef:
("....") introduced ...

> 
> This issue is :
> 
> 	kfree(mic_dma_dev)
> 	.....
> 	dma_async_device_unregister(mic_dma_dev->device);
> 
> Free the memory, and use it again.
> 
> So use devm_kzalloc to allocate mic_dma_dev.
> When the Devres try to release the resources, it will call release at the
> following order:
> 
> 	dma_async_device_unregister(mic_dma_dev->device);
> 	.....
> 	kfree(mic_dma_dev)
> 

We should add:
Fixes: ...

And update the title to mention that this is a fix

> Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
> ---
>  drivers/dma/mic_x100_dma.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
> index b76cb17d879c..adfd316db1a8 100644
> --- a/drivers/dma/mic_x100_dma.c
> +++ b/drivers/dma/mic_x100_dma.c
> @@ -639,7 +639,7 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
>  	int ret;
>  	struct device *dev = &mbdev->dev;
>  
> -	mic_dma_dev = kzalloc(sizeof(*mic_dma_dev), GFP_KERNEL);
> +	mic_dma_dev = devm_kzalloc(dev, sizeof(*mic_dma_dev), GFP_KERNEL);
>  	if (!mic_dma_dev) {
>  		ret = -ENOMEM;
>  		goto alloc_error;
> @@ -664,7 +664,6 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
>  reg_error:
>  	mic_dma_uninit(mic_dma_dev);
>  init_error:
> -	kfree(mic_dma_dev);
>  	mic_dma_dev = NULL;
>  alloc_error:
>  	dev_err(dev, "Error at %s %d ret=%d\n", __func__, __LINE__, ret);
> @@ -674,7 +673,6 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
>  static void mic_dma_dev_unreg(struct mic_dma_device *mic_dma_dev)
>  {
>  	mic_dma_uninit(mic_dma_dev);
> -	kfree(mic_dma_dev);
>  }
>  
>  /* DEBUGFS CODE */
> -- 
> 2.17.1

^ permalink raw reply

* [RFC,2/2] dmaengine: xilinx_dma: Add Xilinx AXI MCDMA Engine driver support
From: Vinod Koul @ 2018-08-21 15:46 UTC (permalink / raw)
  To: Radhey Shyam Pandey
  Cc: robh+dt, mark.rutland, michal.simek, dan.j.williams, appanad,
	lars, dmaengine, devicetree, linux-arm-kernel, linux-kernel

On 31-07-18, 23:16, Radhey Shyam Pandey wrote:
>  struct xilinx_dma_config {
> @@ -402,6 +470,7 @@ struct xilinx_dma_config {
>  	int (*clk_init)(struct platform_device *pdev, struct clk **axi_clk,
>  			struct clk **tx_clk, struct clk **txs_clk,
>  			struct clk **rx_clk, struct clk **rxs_clk);
> +	irqreturn_t (*irq_handler)(int irq, void *data);

this sounds like a preparatory change?

> +	} else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIMCDMA) {
> +		/* Allocate the buffer descriptors. */
> +		chan->seg_mv = dma_zalloc_coherent(chan->dev,
> +						  sizeof(*chan->seg_mv) *
> +						  XILINX_DMA_NUM_DESCS,
> +						  &chan->seg_p, GFP_KERNEL);
> +		if (!chan->seg_mv) {
> +			dev_err(chan->dev,
> +				"unable to allocate channel %d descriptors\n",
> +				chan->id);
> +			return -ENOMEM;
> +		}
> +		for (i = 0; i < XILINX_DMA_NUM_DESCS; i++) {
> +			chan->seg_mv[i].hw.next_desc =
> +			lower_32_bits(chan->seg_p + sizeof(*chan->seg_mv) *
> +				((i + 1) % XILINX_DMA_NUM_DESCS));
> +			chan->seg_mv[i].hw.next_desc_msb =
> +			upper_32_bits(chan->seg_p + sizeof(*chan->seg_mv) *
> +				((i + 1) % XILINX_DMA_NUM_DESCS));
> +			chan->seg_mv[i].phys = chan->seg_p +
> +				sizeof(*chan->seg_v) * i;
> +			list_add_tail(&chan->seg_mv[i].node,
> +				      &chan->free_seg_list);
> +		}

only change with this and previous one seems to be use of seg_mv instead
of seg_v right? if so, can you try to modularise this..

>  /**
> + * xilinx_mcdma_start_transfer - Starts MCDMA transfer
> + * @chan: Driver specific channel struct pointer
> + */
> +static void xilinx_mcdma_start_transfer(struct xilinx_dma_chan *chan)
> +{
> +	struct xilinx_dma_tx_descriptor *head_desc, *tail_desc;
> +	struct xilinx_axidma_tx_segment *tail_segment;
> +	u32 reg;
> +
> +	if (chan->err)
> +		return;
> +
> +	if (!chan->idle)
> +		return;
> +
> +	if (list_empty(&chan->pending_list))
> +		return;

okay i was thinking that we need lock here, but then this is called with
lock held, worth mentioning in the comment though..

> +static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data)
> +{
> +	struct xilinx_dma_chan *chan = data;
> +	u32 status, ser_offset, chan_sermask, chan_offset = 0, chan_id;
> +
> +	if (chan->direction == DMA_DEV_TO_MEM)
> +		ser_offset = XILINX_MCDMA_RXINT_SER_OFFSET;
> +	else
> +		ser_offset = XILINX_MCDMA_TXINT_SER_OFFSET;
> +
> +	/* Read the channel id raising the interrupt*/
> +	chan_sermask = dma_ctrl_read(chan, ser_offset);
> +	chan_id = ffs(chan_sermask);
> +
> +	if (!chan_id)
> +		return IRQ_NONE;
> +
> +	if (chan->direction == DMA_DEV_TO_MEM)
> +		chan_offset = XILINX_DMA_MAX_CHANS_PER_DEVICE / 2;
> +
> +	chan_offset = chan_offset + (chan_id - 1);
> +	chan = chan->xdev->chan[chan_offset];
> +	/* Read the status and ack the interrupts. */
> +	status = dma_ctrl_read(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest));
> +	if (!(status & XILINX_MCDMA_IRQ_ALL_MASK))
> +		return IRQ_NONE;
> +
> +	dma_ctrl_write(chan, XILINX_MCDMA_CHAN_SR_OFFSET(chan->tdest),
> +		       status & XILINX_MCDMA_IRQ_ALL_MASK);
> +
> +	if (status & XILINX_MCDMA_IRQ_ERR_MASK) {
> +		dev_err(chan->dev, "Channel %p has errors %x cdr %x tdr %x\n",
> +			chan, dma_ctrl_read(chan,
> +			XILINX_MCDMA_CH_ERR_OFFSET), dma_ctrl_read(chan,
> +			XILINX_MCDMA_CHAN_CDESC_OFFSET(chan->tdest)),
> +			dma_ctrl_read(chan,
> +				      XILINX_MCDMA_CHAN_TDESC_OFFSET
> +				      (chan->tdest)));

this looks very hard to read, please start each dma_ctrl_read() from a
new line to make it better

> +		chan->err = true;
> +	}
> +
> +	if (status & XILINX_MCDMA_IRQ_DELAY_MASK) {
> +		/*
> +		 * Device takes too long to do the transfer when user requires
> +		 * responsiveness.
> +		 */
> +		dev_dbg(chan->dev, "Inter-packet latency too long\n");

so we just log it..?

> +	}
> +
> +	if (status & XILINX_MCDMA_IRQ_IOC_MASK) {
> +		spin_lock(&chan->lock);
> +		xilinx_dma_complete_descriptor(chan);
> +		chan->idle = true;
> +		chan->start_transfer(chan);
> +		spin_unlock(&chan->lock);
> +	}
> +
> +	tasklet_schedule(&chan->tasklet);
> +	return IRQ_HANDLED;
> +

bogus empty line...

> +static struct dma_async_tx_descriptor *xilinx_mcdma_prep_slave_sg(
> +	struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
> +	enum dma_transfer_direction direction, unsigned long flags,
> +	void *context)

indent is pretty bad here too :(

> +{
> +	struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
> +	struct xilinx_dma_tx_descriptor *desc;
> +	struct xilinx_aximcdma_tx_segment *segment = NULL;
> +	u32 *app_w = (u32 *)context;
> +	struct scatterlist *sg;
> +	size_t copy;
> +	size_t sg_used;
> +	unsigned int i;
> +
> +	if (!is_slave_direction(direction))
> +		return NULL;
> +
> +	/* Allocate a transaction descriptor. */
> +	desc = xilinx_dma_alloc_tx_descriptor(chan);
> +	if (!desc)
> +		return NULL;
> +
> +	dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
> +	desc->async_tx.tx_submit = xilinx_dma_tx_submit;
> +
> +	/* Build transactions using information in the scatter gather list */
> +	for_each_sg(sgl, sg, sg_len, i) {
> +		sg_used = 0;
> +
> +		/* Loop until the entire scatterlist entry is used */
> +		while (sg_used < sg_dma_len(sg)) {
> +			struct xilinx_aximcdma_desc_hw *hw;
> +
> +			/* Get a free segment */
> +			segment = xilinx_aximcdma_alloc_tx_segment(chan);
> +			if (!segment)
> +				goto error;
> +
> +			/*
> +			 * Calculate the maximum number of bytes to transfer,
> +			 * making sure it is less than the hw limit
> +			 */
> +			copy = min_t(size_t, sg_dma_len(sg) - sg_used,
> +				     XILINX_DMA_MAX_TRANS_LEN);
> +			hw = &segment->hw;
> +
> +			/* Fill in the descriptor */
> +			xilinx_aximcdma_buf(chan, hw, sg_dma_address(sg),
> +					    sg_used);
> +			hw->control = copy;
> +
> +			if (chan->direction == DMA_MEM_TO_DEV) {
> +				if (app_w)

why not make condition as: chan->direction == DMA_MEM_TO_DEV && app_w

> +					memcpy(hw->app, app_w, sizeof(u32) *
> +					       XILINX_DMA_NUM_APP_WORDS);
> +			}
> +
> +			sg_used += copy;
> +			/*
> +			 * Insert the segment into the descriptor segments
> +			 * list.
> +			 */
> +			list_add_tail(&segment->node, &desc->segments);
> +		}
> +	}
> +
> +	segment = list_first_entry(&desc->segments,
> +				   struct xilinx_aximcdma_tx_segment, node);
> +	desc->async_tx.phys = segment->phys;
> +
> +	/* For the last DMA_MEM_TO_DEV transfer, set EOP */
> +	if (chan->direction == DMA_MEM_TO_DEV) {
> +		segment->hw.control |= XILINX_MCDMA_BD_SOP;
> +		segment = list_last_entry(&desc->segments,
> +					  struct xilinx_aximcdma_tx_segment,
> +					  node);
> +		segment->hw.control |= XILINX_MCDMA_BD_EOP;
> +	}
> +
> +	return &desc->async_tx;
> +
> +error:
> +	xilinx_dma_free_tx_descriptor(chan, desc);

will it free the ones allocated here or all descriptors?

>  /**
>   * xilinx_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
> @@ -2422,12 +2827,16 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
>  
>  	if (of_device_is_compatible(node, "xlnx,axi-vdma-mm2s-channel") ||
>  	    of_device_is_compatible(node, "xlnx,axi-dma-mm2s-channel") ||
> -	    of_device_is_compatible(node, "xlnx,axi-cdma-channel")) {
> +	    of_device_is_compatible(node, "xlnx,axi-cdma-channel") ||
> +	    of_device_is_compatible(node, "xlnx,axi-mcdma-mm2s-channel")) {

this is not scaling, maybe you should use data with each
compatible to check for specific things..

> +static const struct xilinx_dma_config aximcdma_config = {
> +	.dmatype = XDMA_TYPE_AXIMCDMA,
> +	.clk_init = axidma_clk_init,
> +	.irq_handler = xilinx_mcdma_irq_handler,
> +};
>  static const struct xilinx_dma_config axicdma_config = {
>  	.dmatype = XDMA_TYPE_CDMA,
>  	.clk_init = axicdma_clk_init,
> +	.irq_handler = xilinx_dma_irq_handler,

this should be in preparatory patch

^ permalink raw reply

* [2/3] dmaengine: xilinx_dma: Refactor axidma channel validation
From: Vinod Koul @ 2018-08-21 15:50 UTC (permalink / raw)
  To: Radhey Shyam Pandey
  Cc: dan.j.williams, michal.simek, appana.durga.rao, lars, dmaengine,
	linux-arm-kernel, linux-kernel

On 27-07-18, 16:20, Radhey Shyam Pandey wrote:
> In axidma start_transfer, prefer checking channel states before
> other params i.e pending_list.

and what that preference be?

> 
> Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
> ---
>  drivers/dma/xilinx/xilinx_dma.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index 06d1632..a37871e 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -1271,10 +1271,10 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
>  	if (chan->err)
>  		return;
>  
> -	if (list_empty(&chan->pending_list))
> +	if (!chan->idle)
>  		return;
>  
> -	if (!chan->idle)
> +	if (list_empty(&chan->pending_list))
>  		return;
>  
>  	head_desc = list_first_entry(&chan->pending_list,
> -- 
> 1.7.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [3/3] dmaengine: xilinx_dma: Fix 64-bit simple CDMA transfer
From: Vinod Koul @ 2018-08-21 15:55 UTC (permalink / raw)
  To: Radhey Shyam Pandey
  Cc: dan.j.williams, michal.simek, appana.durga.rao, lars, dmaengine,
	linux-arm-kernel, linux-kernel

On 27-07-18, 16:20, Radhey Shyam Pandey wrote:
> In AXI CDMA simple mode also pass MSB bits of source and destination
> address to xilinx_write function. This fixes simple CDMA operation
> mode using 64-bit addressing.
> 
> Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
>  drivers/dma/xilinx/xilinx_dma.c |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
> index a37871e..2e15d86 100644
> --- a/drivers/dma/xilinx/xilinx_dma.c
> +++ b/drivers/dma/xilinx/xilinx_dma.c
> @@ -1245,8 +1245,10 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
>  
>  		hw = &segment->hw;
>  
> -		xilinx_write(chan, XILINX_CDMA_REG_SRCADDR, hw->src_addr);
> -		xilinx_write(chan, XILINX_CDMA_REG_DSTADDR, hw->dest_addr);
> +		xilinx_write(chan, XILINX_CDMA_REG_SRCADDR, (dma_addr_t)
> +			     ((u64)hw->src_addr_msb << 32 | hw->src_addr));

so this is:
        (dma_addr_t)((u64)hw->src_addr_msb << 32 | hw->src_addr)

what is src_addr data type? I think its u32. It would be better to
update xilinx_write() to take u64 and not dma_addr_t.


> +		xilinx_write(chan, XILINX_CDMA_REG_DSTADDR, (dma_addr_t)
> +			     ((u64)hw->dest_addr_msb << 32 | hw->dest_addr));
>  
>  		/* Start the transfer */
>  		dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
> -- 
> 1.7.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dmaengine" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Rob Herring @ 2018-08-21 19:09 UTC (permalink / raw)
  To: Masahiro Yamada
  Cc: Vinod, open list:DMA GENERIC OFFLOAD ENGINE SUBSYSTEM,
	Masami Hiramatsu, Jassi Brar, devicetree,
	linux-kernel@vger.kernel.org

On Tue, Aug 21, 2018 at 4:48 AM Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
>
> (+CC Rob, DT, LKML)
>
> I forgot to CC this to DT community...

You really need to resend so that patchwork will pick it up and I'll
see it for sure.

>
>
> 2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
> > The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
> > Pro4, and sLD8 SoCs.
> >
> > Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> > ---
> >
> >  .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
> >  1 file changed, 28 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> >
> > diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> > new file mode 100644
> > index 0000000..a9e969e
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> > @@ -0,0 +1,28 @@
> > +UniPhier Media IO DMA controller
> > +
> > +This works as an external DMA engine for SD/eMMC controllers etc.
> > +found in UniPhier LD4, Pro4, sLD8 SoCs.
> > +
> > +Required properties:
> > +- compatible: should be "socionext,uniphier-mio-dmac".
> > +- reg: offset and length of the register set for the device.
> > +- interrupts: a list of interrupt specifiers associated with the DMA channels.
> > +- clocks: a single clock specifier
> > +- #dma-cells: should be <1>. The single cell represents the channel number.
> > +- dma-channels: specify the number of the DMA channels. This should match to
> > +  the number of tuples in the interrupts property.
> > +
> > +Example:
> > +       dmac: dmac@5a000000 {

dma-controller@...

> > +               compatible = "socionext,uniphier-mio-dmac";
> > +               reg = <0x5a000000 0x1000>;
> > +               interrupts = <0 68 4>, <0 68 4>, <0 69 4>, <0 70 4>,
> > +                            <0 71 4>, <0 72 4>, <0 73 4>, <0 74 4>;
> > +               clocks = <&mio_clk 7>;
> > +               #dma-cells = <1>;
> > +               dma-channels = <8>;
> > +       };
> > +
> > +Note:
> > +In the example above, "interrupts = <0 68 4>, <0 68 4>, ..." is not a typo.
> > +The first two channels share a single interrupt line.
> > --
> > 2.7.4
> >
>
>
>
> --
> Best Regards
> Masahiro Yamada

^ permalink raw reply

* [02/11] dmaengine: use SPDX identifier for Renesas drivers
From: Wolfram Sang @ 2018-08-21 22:02 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: Kuninori Morimoto, Wolfram Sang, Vinod Koul, Dan Williams,
	dmaengine, linux-kernel

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---

To be applied individually per subsystem tree. Morimoto-san, could you maybe
ack this with your Renesas address?

 drivers/dma/nbpfaxi.c          | 5 +----
 drivers/dma/sh/shdma-arm.h     | 5 +----
 drivers/dma/sh/shdma-base.c    | 5 +----
 drivers/dma/sh/shdma-of.c      | 5 +----
 drivers/dma/sh/shdma-r8a73a4.c | 5 +----
 drivers/dma/sh/shdma.h         | 6 +-----
 drivers/dma/sh/shdmac.c        | 6 +-----
 drivers/dma/sh/sudmac.c        | 5 +----
 drivers/dma/sh/usb-dmac.c      | 5 +----
 9 files changed, 9 insertions(+), 38 deletions(-)

diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 8c7b2e8703da..38d251b198b8 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
  * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/bitmap.h>
diff --git a/drivers/dma/sh/shdma-arm.h b/drivers/dma/sh/shdma-arm.h
index a1b0ef45d6a2..7459f9a13b5b 100644
--- a/drivers/dma/sh/shdma-arm.h
+++ b/drivers/dma/sh/shdma-arm.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Renesas SuperH DMA Engine support
  *
  * Copyright (C) 2013 Renesas Electronics, Inc.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of version 2 the GNU General Public License as published by the Free
- * Software Foundation.
  */
 
 #ifndef SHDMA_ARM_H
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 6b5626e299b2..c51de498b5b4 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Dmaengine driver base library for DMA controllers, found on SH-based SoCs
  *
@@ -7,10 +8,6 @@
  * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/delay.h>
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
index f999f9b0d314..be89dd894328 100644
--- a/drivers/dma/sh/shdma-of.c
+++ b/drivers/dma/sh/shdma-of.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * SHDMA Device Tree glue
  *
  * Copyright (C) 2013 Renesas Electronics Inc.
  * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/dmaengine.h>
diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c
index 96ea3828c3eb..ddc9a3578353 100644
--- a/drivers/dma/sh/shdma-r8a73a4.c
+++ b/drivers/dma/sh/shdma-r8a73a4.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
  *
  * Copyright (C) 2013 Renesas Electronics, Inc.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of version 2 the GNU General Public License as published by the Free
- * Software Foundation.
  */
 #include <linux/sh_dma.h>
 
diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h
index 2c0a969adc9f..fd702ca9a39c 100644
--- a/drivers/dma/sh/shdma.h
+++ b/drivers/dma/sh/shdma.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Renesas SuperH DMA Engine support
  *
  * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
  */
 #ifndef __DMA_SHDMA_H
 #define __DMA_SHDMA_H
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
index 04a74e0a95b7..fa37541b2d05 100644
--- a/drivers/dma/sh/shdmac.c
+++ b/drivers/dma/sh/shdmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Renesas SuperH DMA Engine support
  *
@@ -8,11 +9,6 @@
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
  *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
  * - DMA of SuperH does not have Hardware DMA chain mode.
  * - MAX DMA size is 16MB.
  *
diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c
index 69b9564dc9d9..30cc3553cb8b 100644
--- a/drivers/dma/sh/sudmac.c
+++ b/drivers/dma/sh/sudmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Renesas SUDMAC support
  *
@@ -8,10 +9,6 @@
  * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/dmaengine.h>
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 1bb1a8e09025..7f7184c3cf95 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Renesas USB DMA Controller Driver
  *
@@ -6,10 +7,6 @@
  * based on rcar-dmac.c
  * Copyright (C) 2014 Renesas Electronics Inc.
  * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/delay.h>

^ permalink raw reply related

* [02/11] dmaengine: use SPDX identifier for Renesas drivers
From: Kuninori Morimoto @ 2018-08-22  0:42 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-renesas-soc, Kuninori Morimoto, Vinod Koul, Dan Williams,
	dmaengine, linux-kernel

Hi Wolfram

> diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h
> index 2c0a969adc9f..fd702ca9a39c 100644
> --- a/drivers/dma/sh/shdma.h
> +++ b/drivers/dma/sh/shdma.h
> @@ -1,14 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>  /*
>   * Renesas SuperH DMA Engine support
>   *
>   * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
>   * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
>   *
> - * This is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
>   */

Fabio already indicated samethings on [05/11] but, we want

	- GPL-2.0-or-later
	+ GPL-2.0+

And, we need to care about MODULE_LICENSE() too,
because sometimes header license and MODULE_LICENSE() are mismatched.
# I didn't check detail of this patch-set...

^ permalink raw reply

* [v2] dma: mic_x100_dma: use devm_kzalloc to fix an issue
From: Huang Shijie @ 2018-08-22  2:40 UTC (permalink / raw)
  To: vkoul; +Cc: sudeep.dutt, ashutosh.dixit, dmaengine, linux-kernel,
	Huang Shijie

The following patch introduced an issue.
    commit f6206f00d8c5 ("dmaengine: mic_x100_dma: use the new helper to simplify the code")

This issue is :

	kfree(mic_dma_dev)
	.....
	dma_async_device_unregister(mic_dma_dev->device);

Free the memory, and use it again.

So use devm_kzalloc to allocate mic_dma_dev to fix it.

When the Devres try to release the resources, it will call release at the
following order:

	dma_async_device_unregister(mic_dma_dev->device);
	.....
	kfree(mic_dma_dev)

Fixes: f6206f00d8c5 ("dmaengine: mic_x100_dma: use the new helper to simplify the code")
Signed-off-by: Huang Shijie <sjhuang@iluvatar.ai>
---
v1 --> v2:
     Change the commit message and title
---
 drivers/dma/mic_x100_dma.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c
index b76cb17d879c..adfd316db1a8 100644
--- a/drivers/dma/mic_x100_dma.c
+++ b/drivers/dma/mic_x100_dma.c
@@ -639,7 +639,7 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
 	int ret;
 	struct device *dev = &mbdev->dev;
 
-	mic_dma_dev = kzalloc(sizeof(*mic_dma_dev), GFP_KERNEL);
+	mic_dma_dev = devm_kzalloc(dev, sizeof(*mic_dma_dev), GFP_KERNEL);
 	if (!mic_dma_dev) {
 		ret = -ENOMEM;
 		goto alloc_error;
@@ -664,7 +664,6 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
 reg_error:
 	mic_dma_uninit(mic_dma_dev);
 init_error:
-	kfree(mic_dma_dev);
 	mic_dma_dev = NULL;
 alloc_error:
 	dev_err(dev, "Error at %s %d ret=%d\n", __func__, __LINE__, ret);
@@ -674,7 +673,6 @@ static struct mic_dma_device *mic_dma_dev_reg(struct mbus_device *mbdev,
 static void mic_dma_dev_unreg(struct mic_dma_device *mic_dma_dev)
 {
 	mic_dma_uninit(mic_dma_dev);
-	kfree(mic_dma_dev);
 }
 
 /* DEBUGFS CODE */

^ permalink raw reply related

* [v2] dmaengine: sprd: Support DMA link-list mode
From: Baolin Wang @ 2018-08-22  2:58 UTC (permalink / raw)
  To: Dan Williams, Vinod Koul
  Cc: Eric Long, Mark Brown, Baolin Wang, dmaengine, LKML

Hi Vinod,

On 9 August 2018 at 15:05, Baolin Wang <baolin.wang@linaro.org> wrote:
> From: Eric Long <eric.long@spreadtrum.com>
>
> The Spreadtrum DMA can support the link-list transaction mode, which means
> DMA controller can do transaction one by one automatically once we linked
> these transaction by link-list register.
>
> Signed-off-by: Eric Long <eric.long@spreadtrum.com>
> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
> ---
> Changes since v1:
>  - Remove sprd_dma_fill_chn_desc() function.
>  - Remove the redundant validation of 'sglen' in sprd_dma_fill_linklist_desc().
>  - Add some comments make code more clear.
>  - Fix the typos.
> ---

Do you have any comments for the v2 patch? Thanks.

>  drivers/dma/sprd-dma.c       |   81 ++++++++++++++++++++++++++++++++++++++----
>  include/linux/dma/sprd-dma.h |   69 +++++++++++++++++++++++++++++++++++
>  2 files changed, 143 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
> index 55df0d4..38d4e4f 100644
> --- a/drivers/dma/sprd-dma.c
> +++ b/drivers/dma/sprd-dma.c
> @@ -68,6 +68,7 @@
>
>  /* SPRD_DMA_CHN_CFG register definition */
>  #define SPRD_DMA_CHN_EN                        BIT(0)
> +#define SPRD_DMA_LINKLIST_EN           BIT(4)
>  #define SPRD_DMA_WAIT_BDONE_OFFSET     24
>  #define SPRD_DMA_DONOT_WAIT_BDONE      1
>
> @@ -103,7 +104,7 @@
>  #define SPRD_DMA_REQ_MODE_MASK         GENMASK(1, 0)
>  #define SPRD_DMA_FIX_SEL_OFFSET                21
>  #define SPRD_DMA_FIX_EN_OFFSET         20
> -#define SPRD_DMA_LLIST_END_OFFSET      19
> +#define SPRD_DMA_LLIST_END             BIT(19)
>  #define SPRD_DMA_FRG_LEN_MASK          GENMASK(16, 0)
>
>  /* SPRD_DMA_CHN_BLK_LEN register definition */
> @@ -164,6 +165,7 @@ struct sprd_dma_desc {
>  struct sprd_dma_chn {
>         struct virt_dma_chan    vc;
>         void __iomem            *chn_base;
> +       struct sprd_dma_linklist        linklist;
>         struct dma_slave_config slave_cfg;
>         u32                     chn_num;
>         u32                     dev_id;
> @@ -582,7 +584,8 @@ static int sprd_dma_get_step(enum dma_slave_buswidth buswidth)
>  }
>
>  static int sprd_dma_fill_desc(struct dma_chan *chan,
> -                             struct sprd_dma_desc *sdesc,
> +                             struct sprd_dma_chn_hw *hw,
> +                             unsigned int sglen, int sg_index,
>                               dma_addr_t src, dma_addr_t dst, u32 len,
>                               enum dma_transfer_direction dir,
>                               unsigned long flags,
> @@ -590,7 +593,6 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
>  {
>         struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan);
>         struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
> -       struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
>         u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK;
>         u32 int_mode = flags & SPRD_DMA_INT_MASK;
>         int src_datawidth, dst_datawidth, src_step, dst_step;
> @@ -670,12 +672,52 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
>         temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
>         hw->trsf_step = temp;
>
> +       /* link-list configuration */
> +       if (schan->linklist.phy_addr) {
> +               if (sg_index == sglen - 1)
> +                       hw->frg_len |= SPRD_DMA_LLIST_END;
> +
> +               hw->cfg |= SPRD_DMA_LINKLIST_EN;
> +
> +               /* link-list index */
> +               temp = (sg_index + 1) % sglen;
> +               /* Next link-list configuration's physical address offset */
> +               temp = temp * sizeof(*hw) + SPRD_DMA_CHN_SRC_ADDR;
> +               /*
> +                * Set the link-list pointer point to next link-list
> +                * configuration's physical address.
> +                */
> +               hw->llist_ptr = schan->linklist.phy_addr + temp;
> +       } else {
> +               hw->llist_ptr = 0;
> +       }
> +
>         hw->frg_step = 0;
>         hw->src_blk_step = 0;
>         hw->des_blk_step = 0;
>         return 0;
>  }
>
> +static int sprd_dma_fill_linklist_desc(struct dma_chan *chan,
> +                                      unsigned int sglen, int sg_index,
> +                                      dma_addr_t src, dma_addr_t dst, u32 len,
> +                                      enum dma_transfer_direction dir,
> +                                      unsigned long flags,
> +                                      struct dma_slave_config *slave_cfg)
> +{
> +       struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
> +       struct sprd_dma_chn_hw *hw;
> +
> +       if (!schan->linklist.virt_addr)
> +               return -EINVAL;
> +
> +       hw = (struct sprd_dma_chn_hw *)(schan->linklist.virt_addr +
> +                                       sg_index * sizeof(*hw));
> +
> +       return sprd_dma_fill_desc(chan, hw, sglen, sg_index, src, dst, len,
> +                                 dir, flags, slave_cfg);
> +}
> +
>  static struct dma_async_tx_descriptor *
>  sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
>                          size_t len, unsigned long flags)
> @@ -744,10 +786,20 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
>         u32 len = 0;
>         int ret, i;
>
> -       /* TODO: now we only support one sg for each DMA configuration. */
> -       if (!is_slave_direction(dir) || sglen > 1)
> +       if (!is_slave_direction(dir))
>                 return NULL;
>
> +       if (context) {
> +               struct sprd_dma_linklist *ll_cfg =
> +                       (struct sprd_dma_linklist *)context;
> +
> +               schan->linklist.phy_addr = ll_cfg->phy_addr;
> +               schan->linklist.virt_addr = ll_cfg->virt_addr;
> +       } else {
> +               schan->linklist.phy_addr = 0;
> +               schan->linklist.virt_addr = 0;
> +       }
> +
>         sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
>         if (!sdesc)
>                 return NULL;
> @@ -762,10 +814,25 @@ static int sprd_dma_fill_desc(struct dma_chan *chan,
>                         src = slave_cfg->src_addr;
>                         dst = sg_dma_address(sg);
>                 }
> +
> +               /*
> +                * The link-list mode needs at least 2 link-list
> +                * configurations. If there is only one sg, it doesn't
> +                * need to fill the link-list configuration.
> +                */
> +               if (sglen < 2)
> +                       break;
> +
> +               ret = sprd_dma_fill_linklist_desc(chan, sglen, i, src, dst, len,
> +                                                 dir, flags, slave_cfg);
> +               if (ret) {
> +                       kfree(sdesc);
> +                       return NULL;
> +               }
>         }
>
> -       ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags,
> -                                slave_cfg);
> +       ret = sprd_dma_fill_desc(chan, &sdesc->chn_hw, 0, 0, src, dst, len,
> +                                dir, flags, slave_cfg);
>         if (ret) {
>                 kfree(sdesc);
>                 return NULL;
> diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h
> index b0115e3..b42b80e5 100644
> --- a/include/linux/dma/sprd-dma.h
> +++ b/include/linux/dma/sprd-dma.h
> @@ -58,4 +58,73 @@ enum sprd_dma_int_type {
>         SPRD_DMA_CFGERR_INT,
>  };
>
> +/*
> + * struct sprd_dma_linklist - DMA link-list address structure
> + * @virt_addr: link-list virtual address to configure link-list node
> + * @phy_addr: link-list physical address to link DMA transfer
> + *
> + * The Spreadtrum DMA controller supports the link-list mode, that means slaves
> + * can supply several groups configurations (each configuration represents one
> + * DMA transfer) saved in memory, and DMA controller will link these groups
> + * configurations by writing the physical address of each configuration into the
> + * link-list register.
> + *
> + * Just as shown below, the link-list pointer register will be pointed to the
> + * physical address of 'configuration 1', and the 'configuration 1' link-list
> + * pointer will be pointed to 'configuration 2', and so on.
> + * Once trigger the DMA transfer, the DMA controller will load 'configuration
> + * 1' to its registers automatically, after 'configuration 1' transaction is
> + * done, DMA controller will load 'configuration 2' automatically, until all
> + * DMA transactions are done.
> + *
> + * Note: The last link-list pointer should point to the physical address
> + * of 'configuration 1', which can avoid DMA controller loads incorrect
> + * configuration when the last configuration transaction is done.
> + *
> + *     DMA controller                    linklist memory
> + * ======================             -----------------------
> + *|                      |           |    configuration 1    |<---
> + *|   DMA controller     |   ------->|                       |   |
> + *|                      |   |       |                       |   |
> + *|                      |   |       |                       |   |
> + *|                      |   |       |                       |   |
> + *| linklist pointer reg |----   ----|    linklist pointer   |   |
> + * ======================        |    -----------------------    |
> + *                               |                               |
> + *                               |    -----------------------    |
> + *                               |   |    configuration 2    |   |
> + *                               --->|                       |   |
> + *                                   |                       |   |
> + *                                   |                       |   |
> + *                                   |                       |   |
> + *                               ----|    linklist pointer   |   |
> + *                               |    -----------------------    |
> + *                               |                               |
> + *                               |    -----------------------    |
> + *                               |   |    configuration 3    |   |
> + *                               --->|                       |   |
> + *                                   |                       |   |
> + *                                   |           .           |   |
> + *                                               .               |
> + *                                               .               |
> + *                                               .               |
> + *                               |               .               |
> + *                               |    -----------------------    |
> + *                               |   |    configuration n    |   |
> + *                               --->|                       |   |
> + *                                   |                       |   |
> + *                                   |                       |   |
> + *                                   |                       |   |
> + *                                   |    linklist pointer   |----
> + *                                    -----------------------
> + *
> + * To support the link-list mode, DMA slaves should allocate one segment memory
> + * from always-on IRAM or dma coherent memory to store these groups of DMA
> + * configuration, and pass the virtual and physical address to DMA controller.
> + */
> +struct sprd_dma_linklist {
> +       unsigned long virt_addr;
> +       phys_addr_t phy_addr;
> +};
> +
>  #endif
> --
> 1.7.9.5
>

^ permalink raw reply

* [02/11] dmaengine: use SPDX identifier for Renesas drivers
From: Wolfram Sang @ 2018-08-22  6:32 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: Wolfram Sang, linux-renesas-soc, Kuninori Morimoto, Vinod Koul,
	Dan Williams, dmaengine, linux-kernel

> Fabio already indicated samethings on [05/11] but, we want
> 
> 	- GPL-2.0-or-later
> 	+ GPL-2.0+

As I mentioned there, too, https://spdx.org/licenses/ wants "-or-later".

> And, we need to care about MODULE_LICENSE() too,
> because sometimes header license and MODULE_LICENSE() are mismatched.
> # I didn't check detail of this patch-set...

I did check this twice and modified where MODULE_LICENSE was wrong.
Another look may not hurt, though...

^ permalink raw reply

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Masahiro Yamada @ 2018-08-23  5:18 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Vinod Koul, dmaengine, Masami Hiramatsu, Rob Herring, DTML,
	Linux Kernel Mailing List

Hi Jassi,


2018-08-21 19:44 GMT+09:00 Jassi Brar <jaswinder.singh@linaro.org>:
> On 21 August 2018 at 15:17, Masahiro Yamada
> <yamada.masahiro@socionext.com> wrote:
>> (+CC Rob, DT, LKML)
>>
>> I forgot to CC this to DT community...
>>
>>
>> 2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
>>> The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
>>> Pro4, and sLD8 SoCs.
>>>
>>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>>> ---
>>>
>>>  .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
>>>  1 file changed, 28 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>> new file mode 100644
>>> index 0000000..a9e969e
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>> @@ -0,0 +1,28 @@
>>> +UniPhier Media IO DMA controller
>>> +
>>> +This works as an external DMA engine for SD/eMMC controllers etc.
>>> +found in UniPhier LD4, Pro4, sLD8 SoCs.
>>> +
>>> +Required properties:
>>> +- compatible: should be "socionext,uniphier-mio-dmac".
>>> +- reg: offset and length of the register set for the device.
>>> +- interrupts: a list of interrupt specifiers associated with the DMA channels.
>>> +- clocks: a single clock specifier
>>> +- #dma-cells: should be <1>. The single cell represents the channel number.
>>> +- dma-channels: specify the number of the DMA channels. This should match to
>>> +  the number of tuples in the interrupts property.
>>> +
> Can we not infer the number of channels from interrupt tuples? After
> all the driver assumes they are same.


It would be possible to count the number of tuples
in "interrupts".



I know of_irq_count(), but I do not see any driver
in drivers/dma/ that calls it.


I guess the reason is that of_irq_count() is not exported,
so tristate drivers like this cannot use it.


I checked Documentation/devicetree/bindings/dma/,
and some controllers specify _redundant_ dma-channels property.

fsl-mxs-dma.txt
renesas,rcar-dmac.txt
renesas,usb-dmac.txt



I also see counter-implementation.


bcm2835-dma.c hard-codes the number of channels in the driver.
tegra210-adma.c associates nr_channels with compatible string.



I will wait for comments from the maintainers.

If desired, I will export of_irq_count()
and use it from my driver.



Thanks.

^ permalink raw reply

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Jassi Brar @ 2018-08-23  5:38 UTC (permalink / raw)
  To: Masahiro Yamada
  Cc: Vinod Koul, dmaengine, Masami Hiramatsu, Rob Herring, DTML,
	Linux Kernel Mailing List

On 23 August 2018 at 10:48, Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
> Hi Jassi,
>
>
> 2018-08-21 19:44 GMT+09:00 Jassi Brar <jaswinder.singh@linaro.org>:
>> On 21 August 2018 at 15:17, Masahiro Yamada
>> <yamada.masahiro@socionext.com> wrote:
>>> (+CC Rob, DT, LKML)
>>>
>>> I forgot to CC this to DT community...
>>>
>>>
>>> 2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
>>>> The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
>>>> Pro4, and sLD8 SoCs.
>>>>
>>>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>>>> ---
>>>>
>>>>  .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
>>>>  1 file changed, 28 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>>> new file mode 100644
>>>> index 0000000..a9e969e
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
>>>> @@ -0,0 +1,28 @@
>>>> +UniPhier Media IO DMA controller
>>>> +
>>>> +This works as an external DMA engine for SD/eMMC controllers etc.
>>>> +found in UniPhier LD4, Pro4, sLD8 SoCs.
>>>> +
>>>> +Required properties:
>>>> +- compatible: should be "socionext,uniphier-mio-dmac".
>>>> +- reg: offset and length of the register set for the device.
>>>> +- interrupts: a list of interrupt specifiers associated with the DMA channels.
>>>> +- clocks: a single clock specifier
>>>> +- #dma-cells: should be <1>. The single cell represents the channel number.
>>>> +- dma-channels: specify the number of the DMA channels. This should match to
>>>> +  the number of tuples in the interrupts property.
>>>> +
>> Can we not infer the number of channels from interrupt tuples? After
>> all the driver assumes they are same.
>
>
> It would be possible to count the number of tuples
> in "interrupts".
>
>
>
> I know of_irq_count(), but I do not see any driver
> in drivers/dma/ that calls it.
>
>
> I guess the reason is that of_irq_count() is not exported,
> so tristate drivers like this cannot use it.
>
>
> I checked Documentation/devicetree/bindings/dma/,
> and some controllers specify _redundant_ dma-channels property.
>
> fsl-mxs-dma.txt
> renesas,rcar-dmac.txt
> renesas,usb-dmac.txt
>
:) I am not sure "because others are doing it" is a good reason to
introduce redundancy.


> I also see counter-implementation.
>
>
> bcm2835-dma.c hard-codes the number of channels in the driver.
> tegra210-adma.c associates nr_channels with compatible string.
>
>
>
> I will wait for comments from the maintainers.
>
> If desired, I will export of_irq_count()
> and use it from my driver.
>
If you don't want to leave too much footprint, you could do

  count = 0;
  while (of_irq_parse_one(dev, count, &irq) == 0) count++

of_irq_parse_one() is already exported.

A good side-effect is you wouldn't have to hardcode the count in the
driver (like bcm and tegra examples you quote).

Having said that, I wouldn't lose sleep over it. So ....

Cheers!

^ permalink raw reply

* dmaengine: Add metadata_ops for dma_async_tx_descriptor
From: Peter Ujfalusi @ 2018-08-23 13:07 UTC (permalink / raw)
  To: dan.j.williams, vkoul; +Cc: dmaengine, linux-kernel, lars, radheys

The metadata is best described as side band data or parameters traveling
alongside the data DMAd by the DMA engine. It is data
which is understood by the peripheral and the peripheral driver only, the
DMA engine see it only as data block and it is not interpreting it in any
way.

The metadata can be different per descriptor as it is a parameter for the
data being transferred.

If the DMA supports per descriptor metadata it can implement the attach,
get_ptr/set_len callbacks.

Client drivers must only use either attach or get_ptr/set_len to avoid
miss configuration.

Client driver can check if a given metadata mode is supported by the
channel during probe time with
dmaengine_is_metadata_mode_supported(chan, DESC_METADATA_CLIENT);
dmaengine_is_metadata_mode_supported(chan, DESC_METADATA_ENGINE);

and based on this information can use either mode.

Wrappers are also added for the metadata_ops.

To be used in DESC_METADATA_CLIENT mode:
dmaengine_desc_attach_metadata()

To be used in DESC_METADATA_ENGINE mode:
dmaengine_desc_get_metadata_ptr()
dmaengine_desc_set_metadata_len()

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
Hi,

Changes since rfc:
- DESC_METADATA_EMBEDDED renamed to DESC_METADATA_ENGINE
- Use flow is added for both CLIENT and ENGINE metadata modes

Regards,
Peter

 include/linux/dmaengine.h | 144 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 3db833a8c542..f809635cfeaa 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -231,6 +231,57 @@ typedef struct { DECLARE_BITMAP(bits, DMA_TX_TYPE_END); } dma_cap_mask_t;
  * @bytes_transferred: byte counter
  */
 
+/**
+ * enum dma_desc_metadata_mode - per descriptor metadata mode types supported
+ * @DESC_METADATA_CLIENT - the metadata buffer is allocated/provided by the
+ *  client driver and it is attached (via the dmaengine_desc_attach_metadata()
+ *  helper) to the descriptor.
+ *
+ * Client drivers interested to use this mode can follow:
+ * - DMA_MEM_TO_DEV:
+ *   1. prepare the descriptor (dmaengine_prep_*)
+ *	construct the metadata in the clinet's buffer
+ *   2. use dmaengine_desc_attach_metadata() to attach the buffer to the
+ *	descriptor
+ *   3. submit the transfer
+ * - DMA_DEV_TO_MEM:
+ *   1. prepare the descriptor (dmaengine_prep_*)
+ *   2. use dmaengine_desc_attach_metadata() to attach the buffer to the
+ *	descriptor
+ *   3. submit the transfer
+ *   4. when the transfer is completed, the metadata should be available in the
+ *	attached buffer
+ *
+ * @DESC_METADATA_ENGINE - the metadata buffer is allocated/managed by the DMA
+ *  driver. The client driver can ask for the pointer, maximum size and the
+ *  currently used size of the metadata and can directly update or read it.
+ *  dmaengine_desc_get_metadata_ptr() and dmaengine_desc_set_metadata_len() is
+ *  provided as helper functions.
+ *
+ * Client drivers interested to use this mode can follow:
+ * - DMA_MEM_TO_DEV:
+ *   1. prepare the descriptor (dmaengine_prep_*)
+ *   2. use dmaengine_desc_get_metadata_ptr() to get the pointer to the engine's
+ *	metadata area
+ *   3. update the metadata at the pointer
+ *   4. use dmaengine_desc_set_metadata_len()  to tell the DMA engine the amount
+ *	of data the client has placed into the metadata buffer
+ *   5. submit the transfer
+ * - DMA_DEV_TO_MEM:
+ *   1. prepare the descriptor (dmaengine_prep_*)
+ *   2. submit the transfer
+ *   3. on transfer completion, use dmaengine_desc_get_metadata_ptr() to get the
+ *	pointer to the engine's metadata are
+ *   4. Read out the metadate from the pointer
+ *
+ * Note: the two mode is not compatible and clients must use one mode for a
+ * descriptor.
+ */
+enum dma_desc_metadata_mode {
+	DESC_METADATA_CLIENT = (1 << 0),
+	DESC_METADATA_ENGINE = (1 << 1),
+};
+
 struct dma_chan_percpu {
 	/* stats */
 	unsigned long memcpy_count;
@@ -494,6 +545,18 @@ struct dmaengine_unmap_data {
 	dma_addr_t addr[0];
 };
 
+struct dma_async_tx_descriptor;
+
+struct dma_descriptor_metadata_ops {
+	int (*attach)(struct dma_async_tx_descriptor *desc, void *data,
+		      size_t len);
+
+	void *(*get_ptr)(struct dma_async_tx_descriptor *desc,
+			 size_t *payload_len, size_t *max_len);
+	int (*set_len)(struct dma_async_tx_descriptor *desc,
+		       size_t payload_len);
+};
+
 /**
  * struct dma_async_tx_descriptor - async transaction descriptor
  * ---dma generic offload fields---
@@ -523,6 +586,8 @@ struct dma_async_tx_descriptor {
 	dma_async_tx_callback_result callback_result;
 	void *callback_param;
 	struct dmaengine_unmap_data *unmap;
+	enum dma_desc_metadata_mode desc_metadata_mode;
+	struct dma_descriptor_metadata_ops *metadata_ops;
 #ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	struct dma_async_tx_descriptor *next;
 	struct dma_async_tx_descriptor *parent;
@@ -685,6 +750,7 @@ struct dma_filter {
  * @global_node: list_head for global dma_device_list
  * @filter: information for device/slave to filter function/param mapping
  * @cap_mask: one or more dma_capability flags
+ * @desc_metadata_modes: supported metadata modes by the DMA device
  * @max_xor: maximum number of xor sources, 0 if no capability
  * @max_pq: maximum number of PQ sources and PQ-continue capability
  * @copy_align: alignment shift for memcpy operations
@@ -749,6 +815,7 @@ struct dma_device {
 	struct list_head global_node;
 	struct dma_filter filter;
 	dma_cap_mask_t  cap_mask;
+	enum dma_desc_metadata_mode desc_metadata_modes;
 	unsigned short max_xor;
 	unsigned short max_pq;
 	enum dmaengine_alignment copy_align;
@@ -935,6 +1002,83 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
 						    len, flags);
 }
 
+static inline bool dmaengine_is_metadata_mode_supported(struct dma_chan *chan,
+		enum dma_desc_metadata_mode mode)
+{
+	return !!(chan->device->desc_metadata_modes & mode);
+}
+
+static inline int _desc_check_and_set_metadata_mode(
+	struct dma_async_tx_descriptor *desc, enum dma_desc_metadata_mode mode)
+{
+	/* Make sure that the metadata mode is not mixed */
+	if (!desc->desc_metadata_mode) {
+		if (dmaengine_is_metadata_mode_supported(desc->chan, mode))
+			desc->desc_metadata_mode = mode;
+		else
+			return -ENOTSUPP;
+	} else if (desc->desc_metadata_mode != mode) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int dmaengine_desc_attach_metadata(
+		struct dma_async_tx_descriptor *desc, void *data, size_t len)
+{
+	int ret;
+
+	if (!desc)
+		return -EINVAL;
+
+	ret = _desc_check_and_set_metadata_mode(desc, DESC_METADATA_CLIENT);
+	if (ret)
+		return ret;
+
+	if (!desc->metadata_ops || !desc->metadata_ops->attach)
+		return -ENOTSUPP;
+
+	return desc->metadata_ops->attach(desc, data, len);
+}
+
+static inline void *dmaengine_desc_get_metadata_ptr(
+		struct dma_async_tx_descriptor *desc, size_t *payload_len,
+		size_t *max_len)
+{
+	int ret;
+
+	if (!desc)
+		return ERR_PTR(-EINVAL);
+
+	ret = _desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE);
+	if (ret)
+		return ERR_PTR(ret);
+
+	if (!desc->metadata_ops || !desc->metadata_ops->get_ptr)
+		return ERR_PTR(-ENOTSUPP);
+
+	return desc->metadata_ops->get_ptr(desc, payload_len, max_len);
+}
+
+static inline int dmaengine_desc_set_metadata_len(
+		struct dma_async_tx_descriptor *desc, size_t payload_len)
+{
+	int ret;
+
+	if (!desc)
+		return -EINVAL;
+
+	ret = _desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE);
+	if (ret)
+		return ret;
+
+	if (!desc->metadata_ops || !desc->metadata_ops->set_len)
+		return -ENOTSUPP;
+
+	return desc->metadata_ops->set_len(desc, payload_len);
+}
+
 /**
  * dmaengine_terminate_all() - Terminate all active DMA transfers
  * @chan: The channel for which to terminate the transfers

^ permalink raw reply related

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Rob Herring @ 2018-08-23 13:21 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Masahiro Yamada, Vinod,
	open list:DMA GENERIC OFFLOAD ENGINE SUBSYSTEM, Masami Hiramatsu,
	devicetree, linux-kernel@vger.kernel.org

On Thu, Aug 23, 2018 at 12:38 AM Jassi Brar <jaswinder.singh@linaro.org> wrote:
>
> On 23 August 2018 at 10:48, Masahiro Yamada
> <yamada.masahiro@socionext.com> wrote:
> > Hi Jassi,
> >
> >
> > 2018-08-21 19:44 GMT+09:00 Jassi Brar <jaswinder.singh@linaro.org>:
> >> On 21 August 2018 at 15:17, Masahiro Yamada
> >> <yamada.masahiro@socionext.com> wrote:
> >>> (+CC Rob, DT, LKML)
> >>>
> >>> I forgot to CC this to DT community...
> >>>
> >>>
> >>> 2018-08-21 18:30 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
> >>>> The MIO DMAC (Media IO DMA Controller) is used in UniPhier LD4,
> >>>> Pro4, and sLD8 SoCs.
> >>>>
> >>>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
> >>>> ---
> >>>>
> >>>>  .../devicetree/bindings/dma/uniphier-mio-dmac.txt  | 28 ++++++++++++++++++++++
> >>>>  1 file changed, 28 insertions(+)
> >>>>  create mode 100644 Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> >>>>
> >>>> diff --git a/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> >>>> new file mode 100644
> >>>> index 0000000..a9e969e
> >>>> --- /dev/null
> >>>> +++ b/Documentation/devicetree/bindings/dma/uniphier-mio-dmac.txt
> >>>> @@ -0,0 +1,28 @@
> >>>> +UniPhier Media IO DMA controller
> >>>> +
> >>>> +This works as an external DMA engine for SD/eMMC controllers etc.
> >>>> +found in UniPhier LD4, Pro4, sLD8 SoCs.
> >>>> +
> >>>> +Required properties:
> >>>> +- compatible: should be "socionext,uniphier-mio-dmac".
> >>>> +- reg: offset and length of the register set for the device.
> >>>> +- interrupts: a list of interrupt specifiers associated with the DMA channels.
> >>>> +- clocks: a single clock specifier
> >>>> +- #dma-cells: should be <1>. The single cell represents the channel number.
> >>>> +- dma-channels: specify the number of the DMA channels. This should match to
> >>>> +  the number of tuples in the interrupts property.
> >>>> +
> >> Can we not infer the number of channels from interrupt tuples? After
> >> all the driver assumes they are same.
> >
> >
> > It would be possible to count the number of tuples
> > in "interrupts".
> >
> >
> >
> > I know of_irq_count(), but I do not see any driver
> > in drivers/dma/ that calls it.
> >
> >
> > I guess the reason is that of_irq_count() is not exported,
> > so tristate drivers like this cannot use it.
> >
> >
> > I checked Documentation/devicetree/bindings/dma/,
> > and some controllers specify _redundant_ dma-channels property.
> >
> > fsl-mxs-dma.txt
> > renesas,rcar-dmac.txt
> > renesas,usb-dmac.txt
> >
> :) I am not sure "because others are doing it" is a good reason to
> introduce redundancy.
>
>
> > I also see counter-implementation.
> >
> >
> > bcm2835-dma.c hard-codes the number of channels in the driver.
> > tegra210-adma.c associates nr_channels with compatible string.
> >
> >
> >
> > I will wait for comments from the maintainers.
> >
> > If desired, I will export of_irq_count()
> > and use it from my driver.
> >
> If you don't want to leave too much footprint, you could do
>
>   count = 0;
>   while (of_irq_parse_one(dev, count, &irq) == 0) count++
>
> of_irq_parse_one() is already exported.

Yes, but we really don't more users and drivers shouldn't be using it.
Grepping DT functions and when the only users are pretty much powerpc,
that's a good indication not to use the function.

And you don't want to use of_irq_count either. platform_irq_count is
what should be used here. It's already exported.

Rob

^ permalink raw reply

* [v2,1/2] dmaengine: use SPDX identifier for Renesas drivers
From: Wolfram Sang @ 2018-08-23 13:34 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: Kuninori Morimoto, Wolfram Sang, Dan Williams, Vinod Koul,
	dmaengine, linux-kernel

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---

Change since V1: s/GPL-2.0-or-later/GPL-2.0+/

 drivers/dma/nbpfaxi.c          | 5 +----
 drivers/dma/sh/shdma-arm.h     | 5 +----
 drivers/dma/sh/shdma-base.c    | 5 +----
 drivers/dma/sh/shdma-of.c      | 5 +----
 drivers/dma/sh/shdma-r8a73a4.c | 5 +----
 drivers/dma/sh/shdma.h         | 6 +-----
 drivers/dma/sh/shdmac.c        | 6 +-----
 drivers/dma/sh/sudmac.c        | 5 +----
 drivers/dma/sh/usb-dmac.c      | 5 +----
 9 files changed, 9 insertions(+), 38 deletions(-)

diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 8c7b2e8703da..38d251b198b8 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
  * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/bitmap.h>
diff --git a/drivers/dma/sh/shdma-arm.h b/drivers/dma/sh/shdma-arm.h
index a1b0ef45d6a2..7459f9a13b5b 100644
--- a/drivers/dma/sh/shdma-arm.h
+++ b/drivers/dma/sh/shdma-arm.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Renesas SuperH DMA Engine support
  *
  * Copyright (C) 2013 Renesas Electronics, Inc.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of version 2 the GNU General Public License as published by the Free
- * Software Foundation.
  */
 
 #ifndef SHDMA_ARM_H
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 6b5626e299b2..c51de498b5b4 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Dmaengine driver base library for DMA controllers, found on SH-based SoCs
  *
@@ -7,10 +8,6 @@
  * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/delay.h>
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
index f999f9b0d314..be89dd894328 100644
--- a/drivers/dma/sh/shdma-of.c
+++ b/drivers/dma/sh/shdma-of.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * SHDMA Device Tree glue
  *
  * Copyright (C) 2013 Renesas Electronics Inc.
  * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/dmaengine.h>
diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c
index 96ea3828c3eb..ddc9a3578353 100644
--- a/drivers/dma/sh/shdma-r8a73a4.c
+++ b/drivers/dma/sh/shdma-r8a73a4.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
  *
  * Copyright (C) 2013 Renesas Electronics, Inc.
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of version 2 the GNU General Public License as published by the Free
- * Software Foundation.
  */
 #include <linux/sh_dma.h>
 
diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h
index 2c0a969adc9f..bfb69909bd19 100644
--- a/drivers/dma/sh/shdma.h
+++ b/drivers/dma/sh/shdma.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Renesas SuperH DMA Engine support
  *
  * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
  */
 #ifndef __DMA_SHDMA_H
 #define __DMA_SHDMA_H
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
index 04a74e0a95b7..7971ea275387 100644
--- a/drivers/dma/sh/shdmac.c
+++ b/drivers/dma/sh/shdmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Renesas SuperH DMA Engine support
  *
@@ -8,11 +9,6 @@
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
  *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
  * - DMA of SuperH does not have Hardware DMA chain mode.
  * - MAX DMA size is 16MB.
  *
diff --git a/drivers/dma/sh/sudmac.c b/drivers/dma/sh/sudmac.c
index 69b9564dc9d9..30cc3553cb8b 100644
--- a/drivers/dma/sh/sudmac.c
+++ b/drivers/dma/sh/sudmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Renesas SUDMAC support
  *
@@ -8,10 +9,6 @@
  * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
  * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
  * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/dmaengine.h>
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 1bb1a8e09025..7f7184c3cf95 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Renesas USB DMA Controller Driver
  *
@@ -6,10 +7,6 @@
  * based on rcar-dmac.c
  * Copyright (C) 2014 Renesas Electronics Inc.
  * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
  */
 
 #include <linux/delay.h>

^ permalink raw reply related

* [1/2] dt-bindings: dmaengine: add DT binding for UniPhier MIO DMAC
From: Jassi Brar @ 2018-08-23 14:12 UTC (permalink / raw)
  To: Rob Herring
  Cc: Masahiro Yamada, Vinod,
	open list:DMA GENERIC OFFLOAD ENGINE SUBSYSTEM, Masami Hiramatsu,
	Devicetree List, linux-kernel@vger.kernel.org

On 23 August 2018 at 18:51, Rob Herring <robh+dt@kernel.org> wrote:
> On Thu, Aug 23, 2018 at 12:38 AM Jassi Brar <jaswinder.singh@linaro.org> wrote:
>> On 23 August 2018 at 10:48, Masahiro Yamada

>> >
>> > If desired, I will export of_irq_count()
>> > and use it from my driver.
>> >
>> If you don't want to leave too much footprint, you could do
>>
>>   count = 0;
>>   while (of_irq_parse_one(dev, count, &irq) == 0) count++
>>
>> of_irq_parse_one() is already exported.
>
> Yes, but we really don't more users and drivers shouldn't be using it.
> Grepping DT functions and when the only users are pretty much powerpc,
> that's a good indication not to use the function.
>
> And you don't want to use of_irq_count either. platform_irq_count is
> what should be used here. It's already exported.
>
Thanks, platform_irq_count() is definitely better.

Yamada-san, for example, gpio-tegra.c infers the number of banks from
platform_irq_count() rather than the 'gpio-banks' property.

^ permalink raw reply


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