linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA
@ 2011-07-13  8:47 Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim
                   ` (11 more replies)
  0 siblings, 12 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

Following is diagram of this changes

+---------------------------------------------------------------------+
| Each drivers which uses DMA                                         |
+---------------------------------------------------------------------+
| S3C DMA API (such as s3c2410_dma_xxxx)                              |
+-------------------------------+-------------------------------------+
| DMA driver for S3C24XX        | S3C PL330 DMA API driver            |
| PL080 DMA driver for S3C64XX  | (arch/arm/plat-samsung/s3c-pl330.c) |
|                               +-------------------------------------+
| (arch/arm/plat-s3c24xx/dma.c) | Common DMA core driver              |
| (arch/arm/mach-s3c64xx/dma.c) | (arch/arm/common/pl330.c)           |
+-------------------------------+-------------------------------------+
                               ||
                (removing S3C DMA API for PL330)
                               ||
                               \/
+---------------------------------------------------------------------+
| Each drivers which uses DMA                                         |
+-------------------------------+-------------------------------------+
| S3C DMA API(s3c2410_dma_xxx)  | DMA generic API for PL330           |
+-------------------------------+-------------------------------------+
| DMA driver for S3C24XX        | PL330 DMA API driver                |
| PL080 DMA driver for S3C64XX  | (drivers/dma/pl330.c)               |
|                               +-------------------------------------+
| (arch/arm/plat-s3c24xx/dma.c) | Common DMA core driver              |
| (arch/arm/mach-s3c64xx/dma.c) | (arch/arm/common/pl330.c)           |
+-------------------------------+-------------------------------------+

Changes since V1:
- removed s3c-pl330 dma driver
- to support multiple platform
- to support this dma on s5p64x0, s5pc100 and s5pv210 as well as exynos4
- addressed comments from Russell King, Grant Likely, Jassi Brar,
  Mark Brown and many developrs...Thanks all.

[PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC
[PATCH V2 02/12] DMA: PL330: Update PL330 DMA API driver
[PATCH V2 03/12] DMA: PL330: Add DMA capabilities
[PATCH V2 04/12] ARM: SAMSUNG: Update to use PL330-DMA driver
[PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations
[PATCH V2 06/12] ARM: EXYNOS4: Use generic DMA PL330 driver
[PATCH V2 07/12] ARM: S5PV210: Use generic DMA PL330 driver
[PATCH V2 08/12] ARM: S5PC100: Use generic DMA PL330 driver
[PATCH V2 09/12] ARM: S5P64X0: Use generic DMA PL330 driver
[PATCH V2 10/12] ARM: SAMSUNG: Remove S3C-PL330-DMA driver
[PATCH V2 11/12] spi/s3c64xx: Add support DMA engine API
[PATCH V2 12/12] ASoC: Samsung: Update DMA interface

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

* [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  9:07   ` Russell King - ARM Linux
  2011-07-13  8:47 ` [PATCH V2 02/12] DMA: PL330: Update PL330 DMA API driver Kukjin Kim
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 drivers/dma/pl330.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 6abe1ec..39e9ffd 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/pl330.h>
+#include <linux/pm_runtime.h>
 
 #define NR_DEFAULT_DESC	16
 
@@ -83,6 +84,8 @@ struct dma_pl330_dmac {
 
 	/* Peripheral channels connected to this DMAC */
 	struct dma_pl330_chan peripherals[0]; /* keep at end */
+
+	struct clk *clk;
 };
 
 struct dma_pl330_desc {
@@ -688,7 +691,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 	pi->mcbufsz = pdat->mcbuf_sz;
 
 	res = &adev->res;
-	request_mem_region(res->start, resource_size(res), "dma-pl330");
+	request_mem_region(res->start,
+		resource_size(res), dev_name(&adev->dev));
 
 	pi->base = ioremap(res->start, resource_size(res));
 	if (!pi->base) {
@@ -696,6 +700,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		goto probe_err1;
 	}
 
+	pdmac->clk = clk_get(&adev->dev, "dma");
+	if (IS_ERR(pdmac->clk)) {
+		dev_err(&adev->dev, "Cannot get operation clock.\n");
+		ret = -EINVAL;
+		goto probe_err1;
+	}
+
+	amba_set_drvdata(adev, pdmac);
+
+#ifdef CONFIG_PM_RUNTIME
+	/* to use the runtime PM helper functions */
+	pm_runtime_enable(&adev->dev);
+
+	/* enable the power domain */
+	if (pm_runtime_get_sync(&adev->dev)) {
+		dev_err(&adev->dev, "failed to get runtime pm\n");
+		ret = -ENODEV;
+		goto probe_err1;
+	}
+#else
+	/* enable dma clk */
+	clk_enable(pdmac->clk);
+#endif
+
 	irq = adev->irq[0];
 	ret = request_irq(irq, pl330_irq_handler, 0,
 			dev_name(&adev->dev), pi);
@@ -763,8 +791,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		goto probe_err4;
 	}
 
-	amba_set_drvdata(adev, pdmac);
-
 	dev_info(&adev->dev,
 		"Loaded driver for PL330 DMAC-%d\n", adev->periphid);
 	dev_info(&adev->dev,
@@ -825,6 +851,13 @@ static int __devexit pl330_remove(struct amba_device *adev)
 	res = &adev->res;
 	release_mem_region(res->start, resource_size(res));
 
+#ifdef CONFIG_PM_RUNTIME
+	pm_runtime_put(&adev->dev);
+	pm_runtime_disable(&adev->dev);
+#else
+	clk_disable(pdmac->clk);
+#endif
+
 	kfree(pdmac);
 
 	return 0;
@@ -838,10 +871,49 @@ static struct amba_id pl330_ids[] = {
 	{ 0, 0 },
 };
 
+#ifdef CONFIG_PM_RUNTIME
+static int pl330_runtime_suspend(struct device *dev)
+{
+	struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
+
+	if (!pdmac) {
+		dev_err(dev, "failed to get dmac\n");
+		return -ENODEV;
+	}
+
+	clk_disable(pdmac->clk);
+
+	return 0;
+}
+
+static int pl330_runtime_resume(struct device *dev)
+{
+	struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
+
+	if (!pdmac) {
+		dev_err(dev, "failed to get dmac\n");
+		return -ENODEV;
+	}
+
+	clk_enable(pdmac->clk);
+
+	return 0;
+}
+#else
+#define pl330_runtime_suspend	NULL
+#define pl330_runtime_resume	NULL
+#endif /* CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops pl330_pm_ops = {
+	.runtime_suspend = pl330_runtime_suspend,
+	.runtime_resume = pl330_runtime_resume,
+};
+
 static struct amba_driver pl330_driver = {
 	.drv = {
 		.owner = THIS_MODULE,
 		.name = "dma-pl330",
+		.pm = &pl330_pm_ops,
 	},
 	.id_table = pl330_ids,
 	.probe = pl330_probe,
-- 
1.7.1

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

* [PATCH V2 02/12] DMA: PL330: Update PL330 DMA API driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 03/12] DMA: PL330: Add DMA capabilities Kukjin Kim
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch updates following 3 items.
1. Removes unneccessary code.
2. Add AMBA, PL330 configuration
3. Change the meaning of 'peri_id' variable
   from PL330 event number to specific dma id by user.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 drivers/dma/Kconfig        |    3 ++-
 drivers/dma/pl330.c        |   31 ++++++++++++++++---------------
 include/linux/amba/pl330.h |    2 +-
 3 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 25cf327..569cb14 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
 config PL330_DMA
 	tristate "DMA API Driver for PL330"
 	select DMA_ENGINE
-	depends on PL330
+	depends on ARM_AMBA
+	select PL330
 	help
 	  Select if your platform has one or more PL330 DMACs.
 	  You need to provide platform specific settings via
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 39e9ffd..9bdda7b 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -455,7 +455,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 	async_tx_ack(&desc->txd);
 
 	desc->req.rqtype = peri->rqtype;
-	desc->req.peri = peri->peri_id;
+	desc->req.peri = pch->chan.chan_id;
 
 	dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
 
@@ -577,7 +577,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	struct dma_pl330_peri *peri = chan->private;
 	struct scatterlist *sg;
 	unsigned long flags;
-	int i, burst_size;
+	int i;
 	dma_addr_t addr;
 
 	if (unlikely(!pch || !sgl || !sg_len))
@@ -594,7 +594,6 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	}
 
 	addr = peri->fifo_addr;
-	burst_size = peri->burst_sz;
 
 	first = NULL;
 
@@ -642,7 +641,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 				sg_dma_address(sg), addr, sg_dma_len(sg));
 		}
 
-		desc->rqcfg.brst_size = burst_size;
+		desc->rqcfg.brst_size = peri->burst_sz;
 		desc->rqcfg.brst_len = 1;
 	}
 
@@ -749,17 +748,19 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		struct dma_pl330_peri *peri = &pdat->peri[i];
 		pch = &pdmac->peripherals[i];
 
-		switch (peri->rqtype) {
-		case MEMTOMEM:
-			dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-			break;
-		case MEMTODEV:
-		case DEVTOMEM:
-			dma_cap_set(DMA_SLAVE, pd->cap_mask);
-			break;
-		default:
-			dev_err(&adev->dev, "DEVTODEV Not Supported\n");
-			continue;
+		if (peri) {
+			switch (peri->rqtype) {
+			case MEMTOMEM:
+				dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+				break;
+			case MEMTODEV:
+			case DEVTOMEM:
+				dma_cap_set(DMA_SLAVE, pd->cap_mask);
+				break;
+			default:
+				dev_err(&adev->dev, "DEVTODEV Not Supported\n");
+				continue;
+			}
 		}
 
 		INIT_LIST_HEAD(&pch->work_list);
diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
index cbee7de..17b0ada 100644
--- a/include/linux/amba/pl330.h
+++ b/include/linux/amba/pl330.h
@@ -19,7 +19,7 @@ struct dma_pl330_peri {
 	 * Peri_Req i/f of the DMAC that is
 	 * peripheral could be reached from.
 	 */
-	u8 peri_id; /* {0, 31} */
+	u8 peri_id; /* specific dma id */
 	enum pl330_reqtype rqtype;
 
 	/* For M->D and D->M Channels */
-- 
1.7.1

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

* [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 02/12] DMA: PL330: Update PL330 DMA API driver Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  9:14   ` Russell King - ARM Linux
  2011-07-15  4:45   ` Chanho Park
  2011-07-13  8:47 ` [PATCH V2 04/12] ARM: SAMSUNG: Update to use PL330-DMA driver Kukjin Kim
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch adds DMA_CYCLIC capability that is used for audio driver
and SLAVE_CONFIG capability for transmit between device and memory.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 drivers/dma/pl330.c |  187 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 173 insertions(+), 14 deletions(-)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 9bdda7b..2162ac5 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -69,6 +69,9 @@ struct dma_pl330_chan {
 	 * NULL if the channel is available to be acquired.
 	 */
 	void *pl330_chid;
+
+	/* taks for cyclic capability */
+	struct tasklet_struct *cyclic_task;
 };
 
 struct dma_pl330_dmac {
@@ -105,6 +108,7 @@ struct dma_pl330_desc {
 
 	/* The channel which currently holds this desc */
 	struct dma_pl330_chan *pchan;
+	bool cyclic;
 };
 
 static inline struct dma_pl330_chan *
@@ -184,6 +188,60 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
 	}
 }
 
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);
+
+	/* Pick up ripe tomatoes */
+	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
+		if ((desc->status == DONE) && desc->cyclic) {
+			dma_async_tx_callback callback;
+
+			list_move_tail(&desc->node, &pch->work_list);
+			pch->completed = desc->txd.cookie;
+
+			desc->status = PREP;
+
+			/* Try to submit a req imm.
+			next to the last completed cookie */
+			fill_queue(pch);
+
+			/* Make sure the PL330 Channel thread is active */
+			pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
+
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);
+
+		}
+
+	spin_unlock_irqrestore(&pch->lock, flags);
+}
+
+static void pl330_cyclic_free(struct dma_pl330_chan *pch)
+{
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
+	if (desc->cyclic)
+		list_move_tail(&desc->node, &list);
+
+	list_splice_tail_init(&list, &pdmac->desc_pool);
+
+	spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+	pch->cyclic_task = NULL;
+}
+
 static void pl330_tasklet(unsigned long data)
 {
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
@@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
 
 	spin_unlock_irqrestore(&pch->lock, flags);
 
+	if (pch->cyclic_task)
+		tasklet_schedule(pch->cyclic_task);
+	else
 	tasklet_schedule(&pch->task);
 }
 
@@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_slave_config *slave_config;
+	struct dma_pl330_peri *peri;
+	int i;
+	LIST_HEAD(list);
 
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
-
-	spin_lock_irqsave(&pch->lock, flags);
-
-	/* FLUSH the PL330 Channel thread */
-	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&pch->lock, flags);
 
-	/* Mark all desc done */
-	list_for_each_entry(desc, &pch->work_list, node)
-		desc->status = DONE;
+		/* FLUSH the PL330 Channel thread */
+		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+		/* Mark all desc done */
+		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
+			desc->status = DONE;
+			pch->completed = desc->txd.cookie;
+			list_move_tail(&desc->node, &list);
+		}
 
-	pl330_tasklet((unsigned long) pch);
+		list_splice_tail_init(&list, &pdmac->desc_pool);
+		spin_unlock_irqrestore(&pch->lock, flags);
+		break;
+	case DMA_SLAVE_CONFIG:
+		slave_config = (struct dma_slave_config *)arg;
+		peri = pch->chan.private;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				peri->fifo_addr = slave_config->dst_addr;
+			if (slave_config->dst_addr_width) {
+				i = 0;
+				while (slave_config->dst_addr_width != (1 << i))
+					i++;
+				peri->burst_sz = i;
+			}
+		} else if (slave_config->direction == DMA_FROM_DEVICE) {
+			if (slave_config->src_addr)
+				peri->fifo_addr = slave_config->src_addr;
+			if (slave_config->src_addr_width) {
+				i = 0;
+				while (slave_config->src_addr_width != (1 << i))
+					i++;
+				peri->burst_sz = i;
+			}
+		}
+		break;
+	default:
+		return -ENXIO;
+	}
 
 	return 0;
 }
@@ -291,6 +385,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 	pl330_release_channel(pch->pl330_chid);
 	pch->pl330_chid = NULL;
 
+	if (pch->cyclic_task)
+		pl330_cyclic_free(pch);
+
 	spin_unlock_irqrestore(&pch->lock, flags);
 }
 
@@ -522,6 +619,66 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
 	return burst_len;
 }
 
+static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
+		size_t period_len, enum dma_data_direction direction)
+{
+	struct dma_pl330_desc *desc;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	struct dma_pl330_peri *peri = chan->private;
+	dma_addr_t dst;
+	dma_addr_t src;
+
+	pch = to_pchan(chan);
+	if (!pch) {
+		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+			__func__, __LINE__);
+		return NULL;
+	}
+
+	desc = pl330_get_desc(pch);
+	if (!desc) {
+		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+			__func__, __LINE__);
+		return NULL;
+	}
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		desc->rqcfg.src_inc = 1;
+		desc->rqcfg.dst_inc = 0;
+		src = dma_addr;
+		dst = peri->fifo_addr;
+		break;
+	case DMA_FROM_DEVICE:
+		desc->rqcfg.src_inc = 0;
+		desc->rqcfg.dst_inc = 1;
+		src = peri->fifo_addr;
+		dst = dma_addr;
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
+		__func__, __LINE__);
+		return NULL;
+	}
+
+	desc->rqcfg.brst_size = peri->burst_sz;
+	desc->rqcfg.brst_len = 1;
+
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);
+	}
+
+	desc->cyclic = true;
+
+	fill_px(&desc->px, dst, src, period_len);
+
+	return &desc->txd;
+}
+
 static struct dma_async_tx_descriptor *
 pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
 		dma_addr_t src, size_t len, unsigned long flags)
@@ -756,6 +913,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 			case MEMTODEV:
 			case DEVTOMEM:
 				dma_cap_set(DMA_SLAVE, pd->cap_mask);
+				dma_cap_set(DMA_CYCLIC, pd->cap_mask);
 				break;
 			default:
 				dev_err(&adev->dev, "DEVTODEV Not Supported\n");
@@ -781,6 +939,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 	pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
 	pd->device_free_chan_resources = pl330_free_chan_resources;
 	pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
+	pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
 	pd->device_tx_status = pl330_tx_status;
 	pd->device_prep_slave_sg = pl330_prep_slave_sg;
 	pd->device_control = pl330_control;
-- 
1.7.1

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

* [PATCH V2 04/12] ARM: SAMSUNG: Update to use PL330-DMA driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (2 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 03/12] DMA: PL330: Add DMA capabilities Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations Kukjin Kim
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch adds to support PL330-DMA driver on DMADEVICE for S5P SoCs.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-exynos4/include/mach/dma.h           |    4 +-
 arch/arm/mach-s5p64x0/include/mach/dma.h           |    2 +-
 arch/arm/mach-s5pc100/include/mach/dma.h           |    2 +-
 arch/arm/mach-s5pv210/include/mach/dma.h           |    2 +-
 arch/arm/plat-samsung/Kconfig                      |    8 +++++++
 .../include/plat/{s3c-dma-pl330.h => dma-pl330.h}  |   21 +++++++++++++------
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |    2 +-
 7 files changed, 28 insertions(+), 13 deletions(-)
 rename arch/arm/plat-samsung/include/plat/{s3c-dma-pl330.h => dma-pl330.h} (84%)

diff --git a/arch/arm/mach-exynos4/include/mach/dma.h b/arch/arm/mach-exynos4/include/mach/dma.h
index 81209eb..201842a 100644
--- a/arch/arm/mach-exynos4/include/mach/dma.h
+++ b/arch/arm/mach-exynos4/include/mach/dma.h
@@ -20,7 +20,7 @@
 #ifndef __MACH_DMA_H
 #define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+/* This platform uses the common DMA API driver for PL330 */
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/dma.h b/arch/arm/mach-s5p64x0/include/mach/dma.h
index 81209eb..1beae2c 100644
--- a/arch/arm/mach-s5p64x0/include/mach/dma.h
+++ b/arch/arm/mach-s5p64x0/include/mach/dma.h
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-s5pc100/include/mach/dma.h b/arch/arm/mach-s5pc100/include/mach/dma.h
index 81209eb..1beae2c 100644
--- a/arch/arm/mach-s5pc100/include/mach/dma.h
+++ b/arch/arm/mach-s5pc100/include/mach/dma.h
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/dma.h b/arch/arm/mach-s5pv210/include/mach/dma.h
index 81209eb..1beae2c 100644
--- a/arch/arm/mach-s5pv210/include/mach/dma.h
+++ b/arch/arm/mach-s5pv210/include/mach/dma.h
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 4d79519..cb170a6 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -300,6 +300,14 @@ config S3C_PL330_DMA
 	help
 	  S3C DMA API Driver for PL330 DMAC.
 
+config DMADEV_PL330
+	bool
+	select DMADEVICES
+	select PL330_DMA
+	select ARM_AMBA
+	help
+	  Use DMA device engine for PL330 DMAC.
+
 comment "Power management"
 
 config SAMSUNG_PM_DEBUG
diff --git a/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
similarity index 84%
rename from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
rename to arch/arm/plat-samsung/include/plat/dma-pl330.h
index 8107442..c402719 100644
--- a/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -8,19 +8,18 @@
  * (at your option) any later version.
  */
 
-#ifndef	__S3C_DMA_PL330_H_
-#define	__S3C_DMA_PL330_H_
-
-#define S3C2410_DMAF_AUTOSTART		(1 << 0)
-#define S3C2410_DMAF_CIRCULAR		(1 << 1)
+#ifndef __DMA_PL330_H_
+#define __DMA_PL330_H_ __FILE__
 
+#define S3C2410_DMAF_AUTOSTART	(1 << 0)
+#define S3C2410_DMAF_CIRCULAR	(1 << 1)
 /*
  * PL330 can assign any channel to communicate with
  * any of the peripherals attched to the DMAC.
  * For the sake of consistency across client drivers,
  * We keep the channel names unchanged and only add
  * missing peripherals are added.
- * Order is not important since S3C PL330 API driver
+ * Order is not important since DMA PL330 API driver
  * use these just as IDs.
  */
 enum dma_ch {
@@ -84,6 +83,14 @@ enum dma_ch {
 	DMACH_SLIMBUS4_TX,
 	DMACH_SLIMBUS5_RX,
 	DMACH_SLIMBUS5_TX,
+	DMACH_MTOM_0,
+	DMACH_MTOM_1,
+	DMACH_MTOM_2,
+	DMACH_MTOM_3,
+	DMACH_MTOM_4,
+	DMACH_MTOM_5,
+	DMACH_MTOM_6,
+	DMACH_MTOM_7,
 	/* END Marker, also used to denote a reserved channel */
 	DMACH_MAX,
 };
@@ -95,4 +102,4 @@ static inline bool s3c_dma_has_circular(void)
 
 #include <plat/dma.h>
 
-#endif	/* __S3C_DMA_PL330_H_ */
+#endif	/* __DMA_PL330_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
index bf5e2a9..64fdf66 100644
--- a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
+++ b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
@@ -12,7 +12,7 @@
 #ifndef __S3C_PL330_PDATA_H
 #define __S3C_PL330_PDATA_H
 
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 /*
  * Every PL330 DMAC has max 32 peripheral interfaces,
-- 
1.7.1

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

* [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (3 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 04/12] ARM: SAMSUNG: Update to use PL330-DMA driver Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-15  2:53   ` Grant Likely
  2011-07-13  8:47 ` [PATCH V2 06/12] ARM: EXYNOS4: Use generic DMA PL330 driver Kukjin Kim
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch adds common DMA operations which are used for Samsung DMA
drivers. Currently there are two types of DMA driver for Samsung SoCs.
The one is S3C-DMA for S3C SoCs and the other is PL330-DMA for S5P SoCs.
This patch provides funcion pointers for common DMA operations to DMA
client driver like SPI and Audio. It makes DMA client drivers support
multi-platform.
In addition, this common DMA operations implement the shared actions
that are needed for DMA client driver. For example shared actions are
filter() function for dma_request_channel() and parameter passing for
device_prep_slave_sg().

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-s3c2410/include/mach/dma.h       |    3 +-
 arch/arm/plat-samsung/Makefile                 |    6 +-
 arch/arm/plat-samsung/dma-ops.c                |  131 +++++++++++++++++++++++
 arch/arm/plat-samsung/include/plat/dma-ops.h   |   47 +++++++++
 arch/arm/plat-samsung/include/plat/dma-pl330.h |    3 +
 arch/arm/plat-samsung/include/plat/dma.h       |    2 +-
 arch/arm/plat-samsung/s3c-dma-ops.c            |  132 ++++++++++++++++++++++++
 7 files changed, 320 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/plat-samsung/dma-ops.c
 create mode 100644 arch/arm/plat-samsung/include/plat/dma-ops.h
 create mode 100644 arch/arm/plat-samsung/s3c-dma-ops.c

diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
index b2b2a5b..71a662d 100644
--- a/arch/arm/mach-s3c2410/include/mach/dma.h
+++ b/arch/arm/mach-s3c2410/include/mach/dma.h
@@ -13,7 +13,6 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
-#include <plat/dma.h>
 #include <linux/sysdev.h>
 
 #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
@@ -51,6 +50,8 @@ enum dma_ch {
 	DMACH_MAX,		/* the end entry */
 };
 
+#include <plat/dma.h>
+
 #define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */
 
 /* we have 4 dma channels */
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 53eb15b..9ecf2aa 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -62,9 +62,11 @@ obj-$(CONFIG_SAMSUNG_DEV_PWM)	+= dev-pwm.o
 
 # DMA support
 
-obj-$(CONFIG_S3C_DMA)		+= dma.o
+obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
 
-obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o
+obj-$(CONFIG_DMADEV_PL330)	+= dma-ops.o
+
+obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
 
 # PM support
 
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
new file mode 100644
index 0000000..94a9d33
--- /dev/null
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -0,0 +1,131 @@
+/* linux/arch/arm/plat-samsung/dma-ops.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung DMA Operations
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/dmaengine.h>
+#include <linux/amba/pl330.h>
+
+#include <mach/dma.h>
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private;
+	unsigned dma_ch = (unsigned)param;
+
+	if (peri->peri_id != dma_ch)
+		return false;
+
+	return true;
+}
+
+static unsigned dma_request(enum dma_ch dma_ch, struct samsung_dma_info *info)
+{
+	struct dma_chan *chan;
+	dma_cap_mask_t mask;
+	struct dma_slave_config slave_config;
+
+	dma_cap_zero(mask);
+	dma_cap_set(info->cap, mask);
+
+	chan = dma_request_channel(mask, filter, (void *)dma_ch);
+
+	if (info->direction == DMA_FROM_DEVICE) {
+		memset(&slave_config, 0, sizeof(struct dma_slave_config));
+		slave_config.direction = info->direction;
+		slave_config.src_addr = info->fifo;
+		slave_config.src_addr_width = info->width;
+		dmaengine_slave_config(chan, &slave_config);
+	} else if (info->direction == DMA_TO_DEVICE) {
+		memset(&slave_config, 0, sizeof(struct dma_slave_config));
+		slave_config.direction = info->direction;
+		slave_config.dst_addr = info->fifo;
+		slave_config.dst_addr_width = info->width;
+		dmaengine_slave_config(chan, &slave_config);
+	}
+
+	return (unsigned)chan;
+}
+
+static int dma_release(unsigned ch, struct s3c2410_dma_client *client)
+{
+	dma_release_channel((struct dma_chan *)ch);
+
+	return 0;
+}
+
+static int dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
+{
+	struct scatterlist sg;
+	struct dma_chan *chan = (struct dma_chan *)ch;
+	struct dma_async_tx_descriptor *desc;
+
+	switch (info->cap) {
+	case DMA_SLAVE:
+		sg_init_table(&sg, 1);
+		sg_dma_len(&sg) = info->len;
+		sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
+			    info->len, offset_in_page(info->buf));
+		sg_dma_address(&sg) = info->buf;
+
+		desc = chan->device->device_prep_slave_sg(chan,
+			&sg, 1, info->direction, DMA_PREP_INTERRUPT);
+		break;
+	case DMA_CYCLIC:
+		desc = chan->device->device_prep_dma_cyclic(chan,
+			info->buf, info->len, info->period, info->direction);
+		break;
+	default:
+		dev_err(&chan->dev->device, "unsupported format\n");
+		return -EFAULT;
+	}
+
+	if (!desc) {
+		dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
+		return -EFAULT;
+	}
+
+	desc->callback = info->fp;
+	desc->callback_param = info->fp_param;
+
+	dmaengine_submit((struct dma_async_tx_descriptor *)desc);
+
+	return 0;
+}
+
+static inline int dma_trigger(unsigned ch)
+{
+	dma_async_issue_pending((struct dma_chan *)ch);
+
+	return 0;
+}
+
+static inline int dma_flush(unsigned ch)
+{
+	return dmaengine_terminate_all((struct dma_chan *)ch);
+}
+
+static struct samsung_dma_ops dmaeng_ops = {
+	.request	= dma_request,
+	.release	= dma_release,
+	.prepare	= dma_prepare,
+	.trigger	= dma_trigger,
+	.started	= NULL,
+	.flush		= dma_flush,
+	.stop		= dma_flush,
+};
+
+void *samsung_dma_get_ops(void)
+{
+	return (void *)&dmaeng_ops;
+}
+EXPORT_SYMBOL(samsung_dma_get_ops);
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
new file mode 100644
index 0000000..eea4130
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
@@ -0,0 +1,47 @@
+/* arch/arm/plat-samsung/include/plat/dma-ops.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung DMA support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/dmaengine.h>
+
+struct samsung_dma_prep_info {
+	enum dma_transaction_type cap;
+	enum dma_data_direction direction;
+	unsigned buf;
+	unsigned long period;
+	unsigned long len;
+	void (*fp)(void *data);
+	void *fp_param;
+};
+
+struct samsung_dma_info {
+	enum dma_transaction_type cap;
+	enum dma_data_direction direction;
+	enum dma_slave_buswidth width;
+	unsigned fifo;
+	struct s3c2410_dma_client *client;
+};
+
+struct samsung_dma_ops {
+	unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
+	int (*release)(unsigned ch, struct s3c2410_dma_client *client);
+	int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
+	int (*trigger)(unsigned ch);
+	int (*started)(unsigned ch);
+	int (*flush)(unsigned ch);
+	int (*stop)(unsigned ch);
+};
+
+/*
+ * samsung_dma_get_ops
+ * get the set of dma operations
+ */
+extern void *samsung_dma_get_ops(void);
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
index c402719..be84bec 100644
--- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -1,4 +1,7 @@
 /*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
  * Copyright (C) 2010 Samsung Electronics Co. Ltd.
  *	Jaswinder Singh <jassi.brar@samsung.com>
  *
diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h
index 2e8f8c6..90da162 100644
--- a/arch/arm/plat-samsung/include/plat/dma.h
+++ b/arch/arm/plat-samsung/include/plat/dma.h
@@ -124,4 +124,4 @@ extern int s3c2410_dma_getposition(unsigned int channel,
 extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
 extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
 
-
+#include <plat/dma-ops.h>
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
new file mode 100644
index 0000000..17b1be0
--- /dev/null
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -0,0 +1,132 @@
+/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung S3C-DMA Operations
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <mach/dma.h>
+
+struct cb_data {
+	void (*fp) (void *);
+	void *fp_param;
+	unsigned ch;
+	struct list_head node;
+};
+
+static LIST_HEAD(dma_list);
+
+static void dma_cb(struct s3c2410_dma_chan *channel,
+		   void *param, int size, enum s3c2410_dma_buffresult res)
+{
+	struct cb_data *data = (struct cb_data *)param;
+
+	data->fp(data->fp_param);
+}
+
+static unsigned dma_request(enum dma_ch dma_ch, struct samsung_dma_info *info)
+{
+	struct cb_data *data;
+
+	if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
+		s3c2410_dma_free(dma_ch, info->client);
+		return 0;
+	}
+
+	data = kmalloc(sizeof(struct cb_data), GFP_KERNEL);
+	data->fp = NULL;
+	data->ch = (unsigned)dma_ch;
+	list_add_tail(&data->node, &dma_list);
+
+	if (info->direction == DMA_FROM_DEVICE)
+		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, info->fifo);
+	else
+		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info->fifo);
+
+	if (info->cap == DMA_CYCLIC)
+		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
+
+	s3c2410_dma_config(dma_ch, info->width);
+
+	return (unsigned)dma_ch;
+}
+
+static int dma_release(unsigned ch, struct s3c2410_dma_client *client)
+{
+	struct cb_data *data;
+
+	list_for_each_entry(data, &dma_list, node)
+	    if (data->ch == ch)
+		break;
+	list_del(&data->node);
+
+	s3c2410_dma_free((enum dma_ch)ch, client);
+	kfree(data);
+
+	return 0;
+}
+
+static int dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
+{
+	struct cb_data *data;
+
+	list_for_each_entry(data, &dma_list, node)
+	    if (data->ch == ch)
+		break;
+
+	if (!data->fp) {
+		s3c2410_dma_set_buffdone_fn((enum dma_ch)ch, dma_cb);
+		data->fp = info->fp;
+		data->fp_param = info->fp_param;
+	}
+	s3c2410_dma_enqueue((enum dma_ch)ch, (void *)data, info->buf,
+			    info->period);
+
+	return 0;
+}
+
+static inline int dma_trigger(unsigned ch)
+{
+	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int dma_started(unsigned ch)
+{
+	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int dma_flush(unsigned ch)
+{
+	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int dma_stop(unsigned ch)
+{
+	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+	.request	= dma_request,
+	.release	= dma_release,
+	.prepare	= dma_prepare,
+	.trigger	= dma_trigger,
+	.started	= dma_started,
+	.flush		= dma_flush,
+	.stop		= dma_stop,
+};
+
+void *samsung_dma_get_ops(void)
+{
+	return (void *)&s3c_dma_ops;
+}
+EXPORT_SYMBOL(samsung_dma_get_ops);
-- 
1.7.1

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

* [PATCH V2 06/12] ARM: EXYNOS4: Use generic DMA PL330 driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (4 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 07/12] ARM: S5PV210: " Kukjin Kim
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch makes Samsung EXYNOS4 to use DMA PL330 driver
on DMADEVICE. The EXYNOS4 uses DMA generic APIs instead of
SAMSUNG specific S3C-PL330 APIs.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-exynos4/Kconfig |    2 +-
 arch/arm/mach-exynos4/clock.c |   16 +-
 arch/arm/mach-exynos4/dma.c   |  323 +++++++++++++++++++++++++++--------------
 3 files changed, 221 insertions(+), 120 deletions(-)

diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index 1435fc3..5cc9b7a 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -11,7 +11,7 @@ if ARCH_EXYNOS4
 
 config CPU_EXYNOS4210
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	help
 	  Enable EXYNOS4210 CPU support
 
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index 871f9d5..1b2e78c 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -47,6 +47,11 @@ static struct clk clk_sclk_usbphy1 = {
 	.id		= -1,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
@@ -485,16 +490,11 @@ static struct clk init_clocks_off[] = {
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 10),
 	}, {
-		.name		= "pdma",
-		.id		= 0,
+		.name		= "dma",
+		.id		= -1,
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 0),
 	}, {
-		.name		= "pdma",
-		.id		= 1,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
 		.name		= "adc",
 		.id		= -1,
 		.enable		= exynos4_clk_ip_peril_ctrl,
@@ -1212,5 +1212,7 @@ void __init exynos4_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
diff --git a/arch/arm/mach-exynos4/dma.c b/arch/arm/mach-exynos4/dma.c
index 564bb53..e1c00cf 100644
--- a/arch/arm/mach-exynos4/dma.c
+++ b/arch/arm/mach-exynos4/dma.c
@@ -21,151 +21,250 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
 
+#include <asm/irq.h>
 #include <plat/devs.h>
 #include <plat/irqs.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
-
-#include <plat/s3c-pl330-pdata.h>
+#include <mach/dma.h>
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-static struct resource exynos4_pdma0_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_PDMA0,
-		.end	= EXYNOS4_PA_PDMA0 + SZ_4K,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_PDMA0,
-		.end	= IRQ_PDMA0,
-		.flags	= IORESOURCE_IRQ,
+struct dma_pl330_peri pdma0_peri[32] = {
+	{
+		.peri_id = (u8)DMACH_PCM0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_PCM0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_PCM2_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_PCM2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_MSM_REQ0,
+	}, {
+		.peri_id = (u8)DMACH_MSM_REQ2,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI2_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_I2S0S_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART2_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART4_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART4_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS2_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS2_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS4_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS4_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_AC97_MICIN,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_AC97_PCMIN,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_AC97_PCMOUT,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
 	},
 };
 
-static struct s3c_pl330_platdata exynos4_pdma0_pdata = {
-	.peri = {
-		[0] = DMACH_PCM0_RX,
-		[1] = DMACH_PCM0_TX,
-		[2] = DMACH_PCM2_RX,
-		[3] = DMACH_PCM2_TX,
-		[4] = DMACH_MSM_REQ0,
-		[5] = DMACH_MSM_REQ2,
-		[6] = DMACH_SPI0_RX,
-		[7] = DMACH_SPI0_TX,
-		[8] = DMACH_SPI2_RX,
-		[9] = DMACH_SPI2_TX,
-		[10] = DMACH_I2S0S_TX,
-		[11] = DMACH_I2S0_RX,
-		[12] = DMACH_I2S0_TX,
-		[13] = DMACH_I2S2_RX,
-		[14] = DMACH_I2S2_TX,
-		[15] = DMACH_UART0_RX,
-		[16] = DMACH_UART0_TX,
-		[17] = DMACH_UART2_RX,
-		[18] = DMACH_UART2_TX,
-		[19] = DMACH_UART4_RX,
-		[20] = DMACH_UART4_TX,
-		[21] = DMACH_SLIMBUS0_RX,
-		[22] = DMACH_SLIMBUS0_TX,
-		[23] = DMACH_SLIMBUS2_RX,
-		[24] = DMACH_SLIMBUS2_TX,
-		[25] = DMACH_SLIMBUS4_RX,
-		[26] = DMACH_SLIMBUS4_TX,
-		[27] = DMACH_AC97_MICIN,
-		[28] = DMACH_AC97_PCMIN,
-		[29] = DMACH_AC97_PCMOUT,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
+struct dma_pl330_platdata exynos4_pdma0_pdata = {
+	.nr_valid_peri = 32,
+	.peri = pdma0_peri,
 };
 
-static struct platform_device exynos4_device_pdma0 = {
-	.name		= "s3c-pl330",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(exynos4_pdma0_resource),
-	.resource	= exynos4_pdma0_resource,
-	.dev		= {
+struct amba_device exynos4_device_pdma0 = {
+	.dev = {
+		.init_name = "dma-pl330.0",
 		.dma_mask = &dma_dmamask,
 		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = &exynos4_pdma0_pdata,
-	},
+		},
+	.res = {
+		.start = EXYNOS4_PA_PDMA0,
+		.end = EXYNOS4_PA_PDMA0 + SZ_4K,
+		.flags = IORESOURCE_MEM,
+		},
+	.irq = {IRQ_PDMA0, NO_IRQ},
+	.periphid = 0x00041330,
 };
 
-static struct resource exynos4_pdma1_resource[] = {
-	[0] = {
-		.start	= EXYNOS4_PA_PDMA1,
-		.end	= EXYNOS4_PA_PDMA1 + SZ_4K,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_PDMA1,
-		.end	= IRQ_PDMA1,
-		.flags	= IORESOURCE_IRQ,
+struct dma_pl330_peri pdma1_peri[32] = {
+	{
+		.peri_id = (u8)DMACH_PCM0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_PCM0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_PCM1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_PCM1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_MSM_REQ1,
+	}, {
+		.peri_id = (u8)DMACH_MSM_REQ3,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_I2S0S_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART3_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_UART3_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS3_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS3_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS5_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_SLIMBUS5_TX,
+		.rqtype = MEMTODEV,
 	},
 };
 
-static struct s3c_pl330_platdata exynos4_pdma1_pdata = {
-	.peri = {
-		[0] = DMACH_PCM0_RX,
-		[1] = DMACH_PCM0_TX,
-		[2] = DMACH_PCM1_RX,
-		[3] = DMACH_PCM1_TX,
-		[4] = DMACH_MSM_REQ1,
-		[5] = DMACH_MSM_REQ3,
-		[6] = DMACH_SPI1_RX,
-		[7] = DMACH_SPI1_TX,
-		[8] = DMACH_I2S0S_TX,
-		[9] = DMACH_I2S0_RX,
-		[10] = DMACH_I2S0_TX,
-		[11] = DMACH_I2S1_RX,
-		[12] = DMACH_I2S1_TX,
-		[13] = DMACH_UART0_RX,
-		[14] = DMACH_UART0_TX,
-		[15] = DMACH_UART1_RX,
-		[16] = DMACH_UART1_TX,
-		[17] = DMACH_UART3_RX,
-		[18] = DMACH_UART3_TX,
-		[19] = DMACH_SLIMBUS1_RX,
-		[20] = DMACH_SLIMBUS1_TX,
-		[21] = DMACH_SLIMBUS3_RX,
-		[22] = DMACH_SLIMBUS3_TX,
-		[23] = DMACH_SLIMBUS5_RX,
-		[24] = DMACH_SLIMBUS5_TX,
-		[25] = DMACH_SLIMBUS0AUX_RX,
-		[26] = DMACH_SLIMBUS0AUX_TX,
-		[27] = DMACH_SPDIF,
-		[28] = DMACH_MAX,
-		[29] = DMACH_MAX,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
+struct dma_pl330_platdata exynos4_pdma1_pdata = {
+	.nr_valid_peri = 32,
+	.peri = pdma1_peri,
 };
 
-static struct platform_device exynos4_device_pdma1 = {
-	.name		= "s3c-pl330",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(exynos4_pdma1_resource),
-	.resource	= exynos4_pdma1_resource,
-	.dev		= {
+struct amba_device exynos4_device_pdma1 = {
+	.dev = {
+		.init_name = "dma-pl330.1",
 		.dma_mask = &dma_dmamask,
 		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = &exynos4_pdma1_pdata,
 	},
-};
-
-static struct platform_device *exynos4_dmacs[] __initdata = {
-	&exynos4_device_pdma0,
-	&exynos4_device_pdma1,
+	.res = {
+		.start = EXYNOS4_PA_PDMA1,
+		.end = EXYNOS4_PA_PDMA1 + SZ_4K,
+		.flags = IORESOURCE_MEM,
+	},
+	.irq = {IRQ_PDMA1, NO_IRQ},
+	.periphid = 0x00041330,
 };
 
 static int __init exynos4_dma_init(void)
 {
-	platform_add_devices(exynos4_dmacs, ARRAY_SIZE(exynos4_dmacs));
+	amba_device_register(&exynos4_device_pdma0, &iomem_resource);
 
 	return 0;
 }
-- 
1.7.1

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

* [PATCH V2 07/12] ARM: S5PV210: Use generic DMA PL330 driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (5 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 06/12] ARM: EXYNOS4: Use generic DMA PL330 driver Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 08/12] ARM: S5PC100: " Kukjin Kim
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch makes Samsung S5PV210 to use DMA PL330 driver
on DMADEVICE. The S5PV210 uses DMA generic APIs instead of
SAMSUNG specific S3C-PL330 APIs.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-s5pv210/Kconfig |    2 +-
 arch/arm/mach-s5pv210/clock.c |   16 ++--
 arch/arm/mach-s5pv210/dma.c   |  232 +++++++++++++++++++----------------------
 3 files changed, 118 insertions(+), 132 deletions(-)

diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 37b5a97..fb11e38 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -11,7 +11,7 @@ if ARCH_S5PV210
 
 config CPU_S5PV210
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	select S5P_EXT_INT
 	select S5P_HRT
 	select S5PV210_PM if PM
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index 2d59949..dbe7285 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -221,6 +221,11 @@ static struct clk clk_pcmcdclk2 = {
 	.id		= -1,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 static struct clk *clkset_vpllsrc_list[] = {
 	[0] = &clk_fin_vpll,
 	[1] = &clk_sclk_hdmi27m,
@@ -311,18 +316,12 @@ static struct clk_ops clk_fout_apll_ops = {
 
 static struct clk init_clocks_off[] = {
 	{
-		.name		= "pdma",
-		.id		= 0,
+		.name		= "dma",
+		.id		= -1,
 		.parent		= &clk_hclk_psys.clk,
 		.enable		= s5pv210_clk_ip0_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
-		.name		= "pdma",
-		.id		= 1,
-		.parent		= &clk_hclk_psys.clk,
-		.enable		= s5pv210_clk_ip0_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
 		.name		= "rot",
 		.id		= -1,
 		.parent		= &clk_hclk_dsys.clk,
@@ -1239,5 +1238,6 @@ void __init s5pv210_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
 	s3c_pwmclk_init();
 }
diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c
index 497d343..1042f42 100644
--- a/arch/arm/mach-s5pv210/dma.c
+++ b/arch/arm/mach-s5pv210/dma.c
@@ -1,4 +1,8 @@
-/*
+/* linux/arch/arm/mach-s5pv210/dma.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
  * Copyright (C) 2010 Samsung Electronics Co. Ltd.
  *	Jaswinder Singh <jassi.brar@samsung.com>
  *
@@ -17,151 +21,133 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
 
+#include <asm/irq.h>
 #include <plat/devs.h>
 #include <plat/irqs.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
-
-#include <plat/s3c-pl330-pdata.h>
+#include <mach/dma.h>
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-static struct resource s5pv210_pdma0_resource[] = {
-	[0] = {
-		.start  = S5PV210_PA_PDMA0,
-		.end    = S5PV210_PA_PDMA0 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_PDMA0,
-		.end	= IRQ_PDMA0,
-		.flags	= IORESOURCE_IRQ,
+struct dma_pl330_peri pdma0_peri[32] = {
+	{
+		.peri_id = (u8)DMACH_UART0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART2_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART2_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART3_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART3_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0S_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_AC97_MICIN,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_AC97_PCMIN,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_AC97_PCMOUT,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_PWM,
+	}, {
+		.peri_id = (u8)DMACH_SPDIF,
 	},
 };
 
-static struct s3c_pl330_platdata s5pv210_pdma0_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_MAX,
-		[9] = DMACH_I2S0_RX,
-		[10] = DMACH_I2S0_TX,
-		[11] = DMACH_I2S0S_TX,
-		[12] = DMACH_I2S1_RX,
-		[13] = DMACH_I2S1_TX,
-		[14] = DMACH_MAX,
-		[15] = DMACH_MAX,
-		[16] = DMACH_SPI0_RX,
-		[17] = DMACH_SPI0_TX,
-		[18] = DMACH_SPI1_RX,
-		[19] = DMACH_SPI1_TX,
-		[20] = DMACH_MAX,
-		[21] = DMACH_MAX,
-		[22] = DMACH_AC97_MICIN,
-		[23] = DMACH_AC97_PCMIN,
-		[24] = DMACH_AC97_PCMOUT,
-		[25] = DMACH_MAX,
-		[26] = DMACH_PWM,
-		[27] = DMACH_SPDIF,
-		[28] = DMACH_MAX,
-		[29] = DMACH_MAX,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
+struct dma_pl330_platdata s5pv210_pdma0_pdata = {
+	.nr_valid_peri = 32,
+	.peri = pdma0_peri,
 };
 
-static struct platform_device s5pv210_device_pdma0 = {
-	.name		= "s3c-pl330",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(s5pv210_pdma0_resource),
-	.resource	= s5pv210_pdma0_resource,
-	.dev		= {
+struct amba_device s5pv210_device_pdma0 = {
+	.dev = {
+		.init_name = "dma-pl330.0",
 		.dma_mask = &dma_dmamask,
 		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = &s5pv210_pdma0_pdata,
-	},
-};
-
-static struct resource s5pv210_pdma1_resource[] = {
-	[0] = {
-		.start  = S5PV210_PA_PDMA1,
-		.end    = S5PV210_PA_PDMA1 + SZ_4K,
+		},
+	.res = {
+		.start = S5PV210_PA_PDMA0,
+		.end = S5PV210_PA_PDMA0 + SZ_4K,
 		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_PDMA1,
-		.end	= IRQ_PDMA1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct s3c_pl330_platdata s5pv210_pdma1_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_MAX,
-		[9] = DMACH_I2S0_RX,
-		[10] = DMACH_I2S0_TX,
-		[11] = DMACH_I2S0S_TX,
-		[12] = DMACH_I2S1_RX,
-		[13] = DMACH_I2S1_TX,
-		[14] = DMACH_I2S2_RX,
-		[15] = DMACH_I2S2_TX,
-		[16] = DMACH_SPI0_RX,
-		[17] = DMACH_SPI0_TX,
-		[18] = DMACH_SPI1_RX,
-		[19] = DMACH_SPI1_TX,
-		[20] = DMACH_MAX,
-		[21] = DMACH_MAX,
-		[22] = DMACH_PCM0_RX,
-		[23] = DMACH_PCM0_TX,
-		[24] = DMACH_PCM1_RX,
-		[25] = DMACH_PCM1_TX,
-		[26] = DMACH_MSM_REQ0,
-		[27] = DMACH_MSM_REQ1,
-		[28] = DMACH_MSM_REQ2,
-		[29] = DMACH_MSM_REQ3,
-		[30] = DMACH_PCM2_RX,
-		[31] = DMACH_PCM2_TX,
-	},
-};
-
-static struct platform_device s5pv210_device_pdma1 = {
-	.name		= "s3c-pl330",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(s5pv210_pdma1_resource),
-	.resource	= s5pv210_pdma1_resource,
-	.dev		= {
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5pv210_pdma1_pdata,
-	},
-};
-
-static struct platform_device *s5pv210_dmacs[] __initdata = {
-	&s5pv210_device_pdma0,
-	&s5pv210_device_pdma1,
+		},
+	.irq = {IRQ_PDMA0, NO_IRQ},
+	.periphid = 0x00041330,
 };
 
 static int __init s5pv210_dma_init(void)
 {
-	platform_add_devices(s5pv210_dmacs, ARRAY_SIZE(s5pv210_dmacs));
+	amba_device_register(&s5pv210_device_pdma0, &iomem_resource);
 
 	return 0;
 }
-- 
1.7.1

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

* [PATCH V2 08/12] ARM: S5PC100: Use generic DMA PL330 driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (6 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 07/12] ARM: S5PV210: " Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 09/12] ARM: S5P64X0: " Kukjin Kim
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch makes Samsung S5PC100 to use DMA PL330 driver
on DMADEVICE. The S5PC100 uses DMA generic APIs instead of
SAMSUNG specific S3C-PL330 APIs.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-s5pc100/Kconfig |    2 +-
 arch/arm/mach-s5pc100/clock.c |   23 ++---
 arch/arm/mach-s5pc100/dma.c   |  249 +++++++++++++++++++++--------------------
 3 files changed, 136 insertions(+), 138 deletions(-)

diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index 608722f..379fadc 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -10,7 +10,7 @@ if ARCH_S5PC100
 config CPU_S5PC100
 	bool
 	select S5P_EXT_INT
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	help
 	  Enable S5PC100 CPU support
 
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index 0305e9b..891acfe 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -34,6 +34,11 @@ static struct clk s5p_clk_otgphy = {
 	.id		= -1,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 static struct clk *clk_src_mout_href_list[] = {
 	[0] = &s5p_clk_27m,
 	[1] = &clk_fin_hpll,
@@ -416,12 +421,6 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5pc100_d0_0_ctrl,
 		.ctrlbit	= (1 << 4),
 	}, {
-		.name		= "mdma",
-		.id		= -1,
-		.parent		= &clk_div_d0_bus.clk,
-		.enable		= s5pc100_d0_0_ctrl,
-		.ctrlbit	= (1 << 3),
-	}, {
 		.name		= "cfcon",
 		.id		= -1,
 		.parent		= &clk_div_d0_bus.clk,
@@ -488,14 +487,8 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5pc100_d1_0_ctrl,
 		.ctrlbit	= (1 << 2),
 	}, {
-		.name		= "pdma",
-		.id		= 1,
-		.parent		= &clk_div_d1_bus.clk,
-		.enable		= s5pc100_d1_0_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
-		.name		= "pdma",
-		.id		= 0,
+		.name		= "dma",
+		.id		= -1,
 		.parent		= &clk_div_d1_bus.clk,
 		.enable		= s5pc100_d1_0_ctrl,
 		.ctrlbit	= (1 << 0),
@@ -1394,5 +1387,7 @@ void __init s5pc100_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
diff --git a/arch/arm/mach-s5pc100/dma.c b/arch/arm/mach-s5pc100/dma.c
index bf4cd0f..405048d 100644
--- a/arch/arm/mach-s5pc100/dma.c
+++ b/arch/arm/mach-s5pc100/dma.c
@@ -1,4 +1,8 @@
-/*
+/* linux/arch/arm/mach-s5pc100/dma.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
  * Copyright (C) 2010 Samsung Electronics Co. Ltd.
  *	Jaswinder Singh <jassi.brar@samsung.com>
  *
@@ -17,150 +21,149 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
 
+#include <asm/irq.h>
 #include <plat/devs.h>
+#include <plat/irqs.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
-
-#include <plat/s3c-pl330-pdata.h>
+#include <mach/dma.h>
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-static struct resource s5pc100_pdma0_resource[] = {
-	[0] = {
-		.start  = S5PC100_PA_PDMA0,
-		.end    = S5PC100_PA_PDMA0 + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_PDMA0,
-		.end	= IRQ_PDMA0,
-		.flags	= IORESOURCE_IRQ,
+struct dma_pl330_peri pdma0_peri[32] = {
+	{
+		.peri_id = (u8)DMACH_UART0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART2_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART2_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART3_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART3_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = DMACH_IRDA,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0S_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S2_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI2_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_AC97_MICIN,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_AC97_PCMIN,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_AC97_PCMOUT,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_EXTERNAL,
+	}, {
+		.peri_id = (u8)DMACH_PWM,
+	}, {
+		.peri_id = (u8)DMACH_SPDIF,
+	}, {
+		.peri_id = (u8)DMACH_HSI_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_HSI_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_SPDIF,
 	},
 };
 
-static struct s3c_pl330_platdata s5pc100_pdma0_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_IRDA,
-		[9] = DMACH_I2S0_RX,
-		[10] = DMACH_I2S0_TX,
-		[11] = DMACH_I2S0S_TX,
-		[12] = DMACH_I2S1_RX,
-		[13] = DMACH_I2S1_TX,
-		[14] = DMACH_I2S2_RX,
-		[15] = DMACH_I2S2_TX,
-		[16] = DMACH_SPI0_RX,
-		[17] = DMACH_SPI0_TX,
-		[18] = DMACH_SPI1_RX,
-		[19] = DMACH_SPI1_TX,
-		[20] = DMACH_SPI2_RX,
-		[21] = DMACH_SPI2_TX,
-		[22] = DMACH_AC97_MICIN,
-		[23] = DMACH_AC97_PCMIN,
-		[24] = DMACH_AC97_PCMOUT,
-		[25] = DMACH_EXTERNAL,
-		[26] = DMACH_PWM,
-		[27] = DMACH_SPDIF,
-		[28] = DMACH_HSI_RX,
-		[29] = DMACH_HSI_TX,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
+struct dma_pl330_platdata s5pc100_pdma0_pdata = {
+	.nr_valid_peri = 32,
+	.peri = pdma0_peri,
 };
 
-static struct platform_device s5pc100_device_pdma0 = {
-	.name		= "s3c-pl330",
-	.id		= 0,
-	.num_resources	= ARRAY_SIZE(s5pc100_pdma0_resource),
-	.resource	= s5pc100_pdma0_resource,
-	.dev		= {
+struct amba_device s5pc100_device_pdma0 = {
+	.dev = {
+		.init_name = "dma-pl330.0",
 		.dma_mask = &dma_dmamask,
 		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.platform_data = &s5pc100_pdma0_pdata,
-	},
-};
-
-static struct resource s5pc100_pdma1_resource[] = {
-	[0] = {
-		.start  = S5PC100_PA_PDMA1,
-		.end    = S5PC100_PA_PDMA1 + SZ_4K,
+		},
+	.res = {
+		.start = S5PC100_PA_PDMA0,
+		.end = S5PC100_PA_PDMA0 + SZ_4K,
 		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_PDMA1,
-		.end	= IRQ_PDMA1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct s3c_pl330_platdata s5pc100_pdma1_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_IRDA,
-		[9] = DMACH_I2S0_RX,
-		[10] = DMACH_I2S0_TX,
-		[11] = DMACH_I2S0S_TX,
-		[12] = DMACH_I2S1_RX,
-		[13] = DMACH_I2S1_TX,
-		[14] = DMACH_I2S2_RX,
-		[15] = DMACH_I2S2_TX,
-		[16] = DMACH_SPI0_RX,
-		[17] = DMACH_SPI0_TX,
-		[18] = DMACH_SPI1_RX,
-		[19] = DMACH_SPI1_TX,
-		[20] = DMACH_SPI2_RX,
-		[21] = DMACH_SPI2_TX,
-		[22] = DMACH_PCM0_RX,
-		[23] = DMACH_PCM0_TX,
-		[24] = DMACH_PCM1_RX,
-		[25] = DMACH_PCM1_TX,
-		[26] = DMACH_MSM_REQ0,
-		[27] = DMACH_MSM_REQ1,
-		[28] = DMACH_MSM_REQ2,
-		[29] = DMACH_MSM_REQ3,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
-};
-
-static struct platform_device s5pc100_device_pdma1 = {
-	.name		= "s3c-pl330",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(s5pc100_pdma1_resource),
-	.resource	= s5pc100_pdma1_resource,
-	.dev		= {
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5pc100_pdma1_pdata,
-	},
-};
-
-static struct platform_device *s5pc100_dmacs[] __initdata = {
-	&s5pc100_device_pdma0,
-	&s5pc100_device_pdma1,
+		},
+	.irq = {IRQ_PDMA0, NO_IRQ},
+	.periphid = 0x00041330,
 };
 
 static int __init s5pc100_dma_init(void)
 {
-	platform_add_devices(s5pc100_dmacs, ARRAY_SIZE(s5pc100_dmacs));
+	amba_device_register(&s5pc100_device_pdma0, &iomem_resource);
 
 	return 0;
 }
-- 
1.7.1

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

* [PATCH V2 09/12] ARM: S5P64X0: Use generic DMA PL330 driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (7 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 08/12] ARM: S5PC100: " Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 10/12] ARM: SAMSUNG: Remove S3C-PL330-DMA driver Kukjin Kim
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch makes Samsung S5P64X0 to use DMA PL330 driver
on DMADEVICE. The S5P64X0 uses DMA generic APIs instead of
SAMSUNG specific S3C-PL330 APIs.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-s5p64x0/Kconfig         |    4 +-
 arch/arm/mach-s5p64x0/clock-s5p6440.c |    9 +-
 arch/arm/mach-s5p64x0/clock-s5p6450.c |    9 +-
 arch/arm/mach-s5p64x0/dma.c           |  303 +++++++++++++++++++++++----------
 4 files changed, 228 insertions(+), 97 deletions(-)

diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index 017af4c..7108e7e 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -9,14 +9,14 @@ if ARCH_S5P64X0
 
 config CPU_S5P6440
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	select S5P_HRT
 	help
 	  Enable S5P6440 CPU support
 
 config CPU_S5P6450
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	select S5P_HRT
 	help
 	  Enable S5P6450 CPU support
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index 9f12c2e..5f7ad9e 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -153,7 +153,7 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5p64x0_hclk0_ctrl,
 		.ctrlbit	= (1 << 8),
 	}, {
-		.name		= "pdma",
+		.name		= "dma",
 		.id		= -1,
 		.parent		= &clk_hclk_low.clk,
 		.enable		= s5p64x0_hclk0_ctrl,
@@ -533,6 +533,11 @@ static struct clksrc_clk *sysclks[] = {
 	&clk_pclk_low,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 void __init_or_cpufreq s5p6440_setup_clocks(void)
 {
 	struct clk *xtal_clk;
@@ -615,5 +620,7 @@ void __init s5p6440_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index 4eec457..62d4707 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -189,7 +189,7 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5p64x0_hclk0_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
-		.name		= "pdma",
+		.name		= "dma",
 		.id		= -1,
 		.parent		= &clk_hclk_low.clk,
 		.enable		= s5p64x0_hclk0_ctrl,
@@ -583,6 +583,11 @@ static struct clksrc_clk *sysclks[] = {
 	&clk_sclk_audio0,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 void __init_or_cpufreq s5p6450_setup_clocks(void)
 {
 	struct clk *xtal_clk;
@@ -662,5 +667,7 @@ void __init s5p6450_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
diff --git a/arch/arm/mach-s5p64x0/dma.c b/arch/arm/mach-s5p64x0/dma.c
index d7ad944..4295657 100644
--- a/arch/arm/mach-s5p64x0/dma.c
+++ b/arch/arm/mach-s5p64x0/dma.c
@@ -19,130 +19,247 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+ */
 
-#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
+
+#include <asm/irq.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
 #include <mach/regs-clock.h>
+#include <mach/dma.h>
 
 #include <plat/devs.h>
-#include <plat/s3c-pl330-pdata.h>
+#include <plat/irqs.h>
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-static struct resource s5p64x0_pdma_resource[] = {
-	[0] = {
-		.start	= S5P64X0_PA_PDMA,
-		.end	= S5P64X0_PA_PDMA + SZ_4K,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_DMA0,
-		.end	= IRQ_DMA0,
-		.flags	= IORESOURCE_IRQ,
+struct dma_pl330_peri s5p6440_pdma_peri[32] = {
+	{
+		.peri_id = (u8)DMACH_UART0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART2_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART2_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART3_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART3_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = DMACH_MAX,
+	}, {
+		.peri_id = DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_PCM0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_PCM0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
 	},
 };
 
-static struct s3c_pl330_platdata s5p6440_pdma_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_MAX,
-		[9] = DMACH_MAX,
-		[10] = DMACH_PCM0_TX,
-		[11] = DMACH_PCM0_RX,
-		[12] = DMACH_I2S0_TX,
-		[13] = DMACH_I2S0_RX,
-		[14] = DMACH_SPI0_TX,
-		[15] = DMACH_SPI0_RX,
-		[16] = DMACH_MAX,
-		[17] = DMACH_MAX,
-		[18] = DMACH_MAX,
-		[19] = DMACH_MAX,
-		[20] = DMACH_SPI1_TX,
-		[21] = DMACH_SPI1_RX,
-		[22] = DMACH_MAX,
-		[23] = DMACH_MAX,
-		[24] = DMACH_MAX,
-		[25] = DMACH_MAX,
-		[26] = DMACH_MAX,
-		[27] = DMACH_MAX,
-		[28] = DMACH_MAX,
-		[29] = DMACH_PWM,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
+struct dma_pl330_platdata s5p6440_pdma_pdata = {
+	.nr_valid_peri = 32,
+	.peri = s5p6440_pdma_peri,
 };
 
-static struct s3c_pl330_platdata s5p6450_pdma_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_UART4_RX,
-		[9] = DMACH_UART4_TX,
-		[10] = DMACH_PCM0_TX,
-		[11] = DMACH_PCM0_RX,
-		[12] = DMACH_I2S0_TX,
-		[13] = DMACH_I2S0_RX,
-		[14] = DMACH_SPI0_TX,
-		[15] = DMACH_SPI0_RX,
-		[16] = DMACH_PCM1_TX,
-		[17] = DMACH_PCM1_RX,
-		[18] = DMACH_PCM2_TX,
-		[19] = DMACH_PCM2_RX,
-		[20] = DMACH_SPI1_TX,
-		[21] = DMACH_SPI1_RX,
-		[22] = DMACH_USI_TX,
-		[23] = DMACH_USI_RX,
-		[24] = DMACH_MAX,
-		[25] = DMACH_I2S1_TX,
-		[26] = DMACH_I2S1_RX,
-		[27] = DMACH_I2S2_TX,
-		[28] = DMACH_I2S2_RX,
-		[29] = DMACH_PWM,
-		[30] = DMACH_UART5_RX,
-		[31] = DMACH_UART5_TX,
+struct dma_pl330_peri s5p6450_pdma_peri[32] = {
+	{
+		.peri_id = (u8)DMACH_UART0_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART0_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART1_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART1_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART2_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART2_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART3_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART3_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_UART4_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART4_TX,
+		.rqtype = MEMTODEV,
+	}, {
+		.peri_id = (u8)DMACH_PCM0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_PCM0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI0_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_PCM1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_PCM1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_PCM2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_PCM2_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_SPI1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_USI_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_USI_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 1,
+	}, {
+		.peri_id = (u8)DMACH_MAX,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S1_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S2_TX,
+		.rqtype = MEMTODEV,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_I2S2_RX,
+		.rqtype = DEVTOMEM,
+		.burst_sz = 4,
+	}, {
+		.peri_id = (u8)DMACH_PWM,
+	}, {
+		.peri_id = (u8)DMACH_UART5_RX,
+		.rqtype = DEVTOMEM,
+	}, {
+		.peri_id = (u8)DMACH_UART5_TX,
+		.rqtype = MEMTODEV,
 	},
 };
 
-static struct platform_device s5p64x0_device_pdma = {
-	.name		= "s3c-pl330",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(s5p64x0_pdma_resource),
-	.resource	= s5p64x0_pdma_resource,
-	.dev		= {
+struct dma_pl330_platdata s5p6450_pdma_pdata = {
+	.nr_valid_peri = 32,
+	.peri = s5p6450_pdma_peri,
+};
+
+struct amba_device s5p64x0_device_pdma = {
+	.dev = {
+		.init_name = "dma-pl330",
 		.dma_mask = &dma_dmamask,
 		.coherent_dma_mask = DMA_BIT_MASK(32),
-	},
+		},
+	.res = {
+		.start = S5P64X0_PA_PDMA,
+		.end = S5P64X0_PA_PDMA + SZ_4K,
+		.flags = IORESOURCE_MEM,
+		},
+	.irq = {IRQ_DMA0, NO_IRQ},
+	.periphid = 0x00041330,
 };
 
 static int __init s5p64x0_dma_init(void)
 {
-	unsigned int id;
-
-	id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
+	unsigned int id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
 
 	if (id == 0x50000)
 		s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata;
 	else
 		s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
 
-	platform_device_register(&s5p64x0_device_pdma);
+	amba_device_register(&s5p64x0_device_pdma, &iomem_resource);
 
 	return 0;
 }
-- 
1.7.1

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

* [PATCH V2 10/12] ARM: SAMSUNG: Remove S3C-PL330-DMA driver
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (8 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 09/12] ARM: S5P64X0: " Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 11/12] spi/s3c64xx: Add support DMA engine API Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 12/12] ASoC: Samsung: Update DMA interface Kukjin Kim
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

Since DMA generic APIs can be used for Samsung DMA now so that
the s3c-pl330 which includes Samsung specific DMA APIs can be
removed.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Cc: Jassi Brar <jassisinghbrar@gmail.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/plat-samsung/Kconfig                      |    6 -
 arch/arm/plat-samsung/Makefile                     |    2 -
 arch/arm/plat-samsung/include/plat/dma-pl330.h     |    8 +-
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |   32 -
 arch/arm/plat-samsung/s3c-pl330.c                  | 1244 --------------------
 5 files changed, 5 insertions(+), 1287 deletions(-)
 delete mode 100644 arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
 delete mode 100644 arch/arm/plat-samsung/s3c-pl330.c

diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index cb170a6..db789d7 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -294,12 +294,6 @@ config S3C_DMA
 	help
 	  Internal configuration for S3C DMA core
 
-config S3C_PL330_DMA
-	bool
-	select PL330
-	help
-	  S3C DMA API Driver for PL330 DMAC.
-
 config DMADEV_PL330
 	bool
 	select DMADEVICES
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 9ecf2aa..ea98621 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -66,8 +66,6 @@ obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
 
 obj-$(CONFIG_DMADEV_PL330)	+= dma-ops.o
 
-obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
-
 # PM support
 
 obj-$(CONFIG_PM)		+= pm.o
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
index be84bec..dbc1288 100644
--- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -14,8 +14,6 @@
 #ifndef __DMA_PL330_H_
 #define __DMA_PL330_H_ __FILE__
 
-#define S3C2410_DMAF_AUTOSTART	(1 << 0)
-#define S3C2410_DMAF_CIRCULAR	(1 << 1)
 /*
  * PL330 can assign any channel to communicate with
  * any of the peripherals attched to the DMAC.
@@ -98,11 +96,15 @@ enum dma_ch {
 	DMACH_MAX,
 };
 
+struct s3c2410_dma_client {
+	char	*name;
+};
+
 static inline bool s3c_dma_has_circular(void)
 {
 	return true;
 }
 
-#include <plat/dma.h>
+#include <plat/dma-ops.h>
 
 #endif	/* __DMA_PL330_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h b/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
deleted file mode 100644
index 64fdf66..0000000
--- a/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program 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 __S3C_PL330_PDATA_H
-#define __S3C_PL330_PDATA_H
-
-#include <plat/dma-pl330.h>
-
-/*
- * Every PL330 DMAC has max 32 peripheral interfaces,
- * of which some may be not be really used in your
- * DMAC's configuration.
- * Populate this array of 32 peri i/fs with relevant
- * channel IDs for used peri i/f and DMACH_MAX for
- * those unused.
- *
- * The platforms just need to provide this info
- * to the S3C DMA API driver for PL330.
- */
-struct s3c_pl330_platdata {
-	enum dma_ch peri[32];
-};
-
-#endif /* __S3C_PL330_PDATA_H */
diff --git a/arch/arm/plat-samsung/s3c-pl330.c b/arch/arm/plat-samsung/s3c-pl330.c
deleted file mode 100644
index f85638c..0000000
--- a/arch/arm/plat-samsung/s3c-pl330.c
+++ /dev/null
@@ -1,1244 +0,0 @@
-/* linux/arch/arm/plat-samsung/s3c-pl330.c
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-
-#include <asm/hardware/pl330.h>
-
-#include <plat/s3c-pl330-pdata.h>
-
-/**
- * struct s3c_pl330_dmac - Logical representation of a PL330 DMAC.
- * @busy_chan: Number of channels currently busy.
- * @peri: List of IDs of peripherals this DMAC can work with.
- * @node: To attach to the global list of DMACs.
- * @pi: PL330 configuration info for the DMAC.
- * @kmcache: Pool to quickly allocate xfers for all channels in the dmac.
- * @clk: Pointer of DMAC operation clock.
- */
-struct s3c_pl330_dmac {
-	unsigned		busy_chan;
-	enum dma_ch		*peri;
-	struct list_head	node;
-	struct pl330_info	*pi;
-	struct kmem_cache	*kmcache;
-	struct clk		*clk;
-};
-
-/**
- * struct s3c_pl330_xfer - A request submitted by S3C DMA clients.
- * @token: Xfer ID provided by the client.
- * @node: To attach to the list of xfers on a channel.
- * @px: Xfer for PL330 core.
- * @chan: Owner channel of this xfer.
- */
-struct s3c_pl330_xfer {
-	void			*token;
-	struct list_head	node;
-	struct pl330_xfer	px;
-	struct s3c_pl330_chan	*chan;
-};
-
-/**
- * struct s3c_pl330_chan - Logical channel to communicate with
- * 	a Physical peripheral.
- * @pl330_chan_id: Token of a hardware channel thread of PL330 DMAC.
- * 	NULL if the channel is available to be acquired.
- * @id: ID of the peripheral that this channel can communicate with.
- * @options: Options specified by the client.
- * @sdaddr: Address provided via s3c2410_dma_devconfig.
- * @node: To attach to the global list of channels.
- * @lrq: Pointer to the last submitted pl330_req to PL330 core.
- * @xfer_list: To manage list of xfers enqueued.
- * @req: Two requests to communicate with the PL330 engine.
- * @callback_fn: Callback function to the client.
- * @rqcfg: Channel configuration for the xfers.
- * @xfer_head: Pointer to the xfer to be next executed.
- * @dmac: Pointer to the DMAC that manages this channel, NULL if the
- * 	channel is available to be acquired.
- * @client: Client of this channel. NULL if the
- * 	channel is available to be acquired.
- */
-struct s3c_pl330_chan {
-	void				*pl330_chan_id;
-	enum dma_ch			id;
-	unsigned int			options;
-	unsigned long			sdaddr;
-	struct list_head		node;
-	struct pl330_req		*lrq;
-	struct list_head		xfer_list;
-	struct pl330_req		req[2];
-	s3c2410_dma_cbfn_t		callback_fn;
-	struct pl330_reqcfg		rqcfg;
-	struct s3c_pl330_xfer		*xfer_head;
-	struct s3c_pl330_dmac		*dmac;
-	struct s3c2410_dma_client	*client;
-};
-
-/* All DMACs in the platform */
-static LIST_HEAD(dmac_list);
-
-/* All channels to peripherals in the platform */
-static LIST_HEAD(chan_list);
-
-/*
- * Since we add resources(DMACs and Channels) to the global pool,
- * we need to guard access to the resources using a global lock
- */
-static DEFINE_SPINLOCK(res_lock);
-
-/* Returns the channel with ID 'id' in the chan_list */
-static struct s3c_pl330_chan *id_to_chan(const enum dma_ch id)
-{
-	struct s3c_pl330_chan *ch;
-
-	list_for_each_entry(ch, &chan_list, node)
-		if (ch->id == id)
-			return ch;
-
-	return NULL;
-}
-
-/* Allocate a new channel with ID 'id' and add to chan_list */
-static void chan_add(const enum dma_ch id)
-{
-	struct s3c_pl330_chan *ch = id_to_chan(id);
-
-	/* Return if the channel already exists */
-	if (ch)
-		return;
-
-	ch = kmalloc(sizeof(*ch), GFP_KERNEL);
-	/* Return silently to work with other channels */
-	if (!ch)
-		return;
-
-	ch->id = id;
-	ch->dmac = NULL;
-
-	list_add_tail(&ch->node, &chan_list);
-}
-
-/* If the channel is not yet acquired by any client */
-static bool chan_free(struct s3c_pl330_chan *ch)
-{
-	if (!ch)
-		return false;
-
-	/* Channel points to some DMAC only when it's acquired */
-	return ch->dmac ? false : true;
-}
-
-/*
- * Returns 0 is peripheral i/f is invalid or not present on the dmac.
- * Index + 1, otherwise.
- */
-static unsigned iface_of_dmac(struct s3c_pl330_dmac *dmac, enum dma_ch ch_id)
-{
-	enum dma_ch *id = dmac->peri;
-	int i;
-
-	/* Discount invalid markers */
-	if (ch_id == DMACH_MAX)
-		return 0;
-
-	for (i = 0; i < PL330_MAX_PERI; i++)
-		if (id[i] == ch_id)
-			return i + 1;
-
-	return 0;
-}
-
-/* If all channel threads of the DMAC are busy */
-static inline bool dmac_busy(struct s3c_pl330_dmac *dmac)
-{
-	struct pl330_info *pi = dmac->pi;
-
-	return (dmac->busy_chan < pi->pcfg.num_chan) ? false : true;
-}
-
-/*
- * Returns the number of free channels that
- * can be handled by this dmac only.
- */
-static unsigned ch_onlyby_dmac(struct s3c_pl330_dmac *dmac)
-{
-	enum dma_ch *id = dmac->peri;
-	struct s3c_pl330_dmac *d;
-	struct s3c_pl330_chan *ch;
-	unsigned found, count = 0;
-	enum dma_ch p;
-	int i;
-
-	for (i = 0; i < PL330_MAX_PERI; i++) {
-		p = id[i];
-		ch = id_to_chan(p);
-
-		if (p == DMACH_MAX || !chan_free(ch))
-			continue;
-
-		found = 0;
-		list_for_each_entry(d, &dmac_list, node) {
-			if (d != dmac && iface_of_dmac(d, ch->id)) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			count++;
-	}
-
-	return count;
-}
-
-/*
- * Measure of suitability of 'dmac' handling 'ch'
- *
- * 0 indicates 'dmac' can not handle 'ch' either
- * because it is not supported by the hardware or
- * because all dmac channels are currently busy.
- *
- * >0 vlaue indicates 'dmac' has the capability.
- * The bigger the value the more suitable the dmac.
- */
-#define MAX_SUIT	UINT_MAX
-#define MIN_SUIT	0
-
-static unsigned suitablility(struct s3c_pl330_dmac *dmac,
-		struct s3c_pl330_chan *ch)
-{
-	struct pl330_info *pi = dmac->pi;
-	enum dma_ch *id = dmac->peri;
-	struct s3c_pl330_dmac *d;
-	unsigned s;
-	int i;
-
-	s = MIN_SUIT;
-	/* If all the DMAC channel threads are busy */
-	if (dmac_busy(dmac))
-		return s;
-
-	for (i = 0; i < PL330_MAX_PERI; i++)
-		if (id[i] == ch->id)
-			break;
-
-	/* If the 'dmac' can't talk to 'ch' */
-	if (i == PL330_MAX_PERI)
-		return s;
-
-	s = MAX_SUIT;
-	list_for_each_entry(d, &dmac_list, node) {
-		/*
-		 * If some other dmac can talk to this
-		 * peri and has some channel free.
-		 */
-		if (d != dmac && iface_of_dmac(d, ch->id) && !dmac_busy(d)) {
-			s = 0;
-			break;
-		}
-	}
-	if (s)
-		return s;
-
-	s = 100;
-
-	/* Good if free chans are more, bad otherwise */
-	s += (pi->pcfg.num_chan - dmac->busy_chan) - ch_onlyby_dmac(dmac);
-
-	return s;
-}
-
-/* More than one DMAC may have capability to transfer data with the
- * peripheral. This function assigns most suitable DMAC to manage the
- * channel and hence communicate with the peripheral.
- */
-static struct s3c_pl330_dmac *map_chan_to_dmac(struct s3c_pl330_chan *ch)
-{
-	struct s3c_pl330_dmac *d, *dmac = NULL;
-	unsigned sn, sl = MIN_SUIT;
-
-	list_for_each_entry(d, &dmac_list, node) {
-		sn = suitablility(d, ch);
-
-		if (sn == MAX_SUIT)
-			return d;
-
-		if (sn > sl)
-			dmac = d;
-	}
-
-	return dmac;
-}
-
-/* Acquire the channel for peripheral 'id' */
-static struct s3c_pl330_chan *chan_acquire(const enum dma_ch id)
-{
-	struct s3c_pl330_chan *ch = id_to_chan(id);
-	struct s3c_pl330_dmac *dmac;
-
-	/* If the channel doesn't exist or is already acquired */
-	if (!ch || !chan_free(ch)) {
-		ch = NULL;
-		goto acq_exit;
-	}
-
-	dmac = map_chan_to_dmac(ch);
-	/* If couldn't map */
-	if (!dmac) {
-		ch = NULL;
-		goto acq_exit;
-	}
-
-	dmac->busy_chan++;
-	ch->dmac = dmac;
-
-acq_exit:
-	return ch;
-}
-
-/* Delete xfer from the queue */
-static inline void del_from_queue(struct s3c_pl330_xfer *xfer)
-{
-	struct s3c_pl330_xfer *t;
-	struct s3c_pl330_chan *ch;
-	int found;
-
-	if (!xfer)
-		return;
-
-	ch = xfer->chan;
-
-	/* Make sure xfer is in the queue */
-	found = 0;
-	list_for_each_entry(t, &ch->xfer_list, node)
-		if (t == xfer) {
-			found = 1;
-			break;
-		}
-
-	if (!found)
-		return;
-
-	/* If xfer is last entry in the queue */
-	if (xfer->node.next == &ch->xfer_list)
-		t = list_entry(ch->xfer_list.next,
-				struct s3c_pl330_xfer, node);
-	else
-		t = list_entry(xfer->node.next,
-				struct s3c_pl330_xfer, node);
-
-	/* If there was only one node left */
-	if (t == xfer)
-		ch->xfer_head = NULL;
-	else if (ch->xfer_head == xfer)
-		ch->xfer_head = t;
-
-	list_del(&xfer->node);
-}
-
-/* Provides pointer to the next xfer in the queue.
- * If CIRCULAR option is set, the list is left intact,
- * otherwise the xfer is removed from the list.
- * Forced delete 'pluck' can be set to override the CIRCULAR option.
- */
-static struct s3c_pl330_xfer *get_from_queue(struct s3c_pl330_chan *ch,
-		int pluck)
-{
-	struct s3c_pl330_xfer *xfer = ch->xfer_head;
-
-	if (!xfer)
-		return NULL;
-
-	/* If xfer is last entry in the queue */
-	if (xfer->node.next == &ch->xfer_list)
-		ch->xfer_head = list_entry(ch->xfer_list.next,
-					struct s3c_pl330_xfer, node);
-	else
-		ch->xfer_head = list_entry(xfer->node.next,
-					struct s3c_pl330_xfer, node);
-
-	if (pluck || !(ch->options & S3C2410_DMAF_CIRCULAR))
-		del_from_queue(xfer);
-
-	return xfer;
-}
-
-static inline void add_to_queue(struct s3c_pl330_chan *ch,
-		struct s3c_pl330_xfer *xfer, int front)
-{
-	struct pl330_xfer *xt;
-
-	/* If queue empty */
-	if (ch->xfer_head == NULL)
-		ch->xfer_head = xfer;
-
-	xt = &ch->xfer_head->px;
-	/* If the head already submitted (CIRCULAR head) */
-	if (ch->options & S3C2410_DMAF_CIRCULAR &&
-		(xt == ch->req[0].x || xt == ch->req[1].x))
-		ch->xfer_head = xfer;
-
-	/* If this is a resubmission, it should go at the head */
-	if (front) {
-		ch->xfer_head = xfer;
-		list_add(&xfer->node, &ch->xfer_list);
-	} else {
-		list_add_tail(&xfer->node, &ch->xfer_list);
-	}
-}
-
-static inline void _finish_off(struct s3c_pl330_xfer *xfer,
-		enum s3c2410_dma_buffresult res, int ffree)
-{
-	struct s3c_pl330_chan *ch;
-
-	if (!xfer)
-		return;
-
-	ch = xfer->chan;
-
-	/* Do callback */
-	if (ch->callback_fn)
-		ch->callback_fn(NULL, xfer->token, xfer->px.bytes, res);
-
-	/* Force Free or if buffer is not needed anymore */
-	if (ffree || !(ch->options & S3C2410_DMAF_CIRCULAR))
-		kmem_cache_free(ch->dmac->kmcache, xfer);
-}
-
-static inline int s3c_pl330_submit(struct s3c_pl330_chan *ch,
-		struct pl330_req *r)
-{
-	struct s3c_pl330_xfer *xfer;
-	int ret = 0;
-
-	/* If already submitted */
-	if (r->x)
-		return 0;
-
-	xfer = get_from_queue(ch, 0);
-	if (xfer) {
-		r->x = &xfer->px;
-
-		/* Use max bandwidth for M<->M xfers */
-		if (r->rqtype == MEMTOMEM) {
-			struct pl330_info *pi = xfer->chan->dmac->pi;
-			int burst = 1 << ch->rqcfg.brst_size;
-			u32 bytes = r->x->bytes;
-			int bl;
-
-			bl = pi->pcfg.data_bus_width / 8;
-			bl *= pi->pcfg.data_buf_dep;
-			bl /= burst;
-
-			/* src/dst_burst_len can't be more than 16 */
-			if (bl > 16)
-				bl = 16;
-
-			while (bl > 1) {
-				if (!(bytes % (bl * burst)))
-					break;
-				bl--;
-			}
-
-			ch->rqcfg.brst_len = bl;
-		} else {
-			ch->rqcfg.brst_len = 1;
-		}
-
-		ret = pl330_submit_req(ch->pl330_chan_id, r);
-
-		/* If submission was successful */
-		if (!ret) {
-			ch->lrq = r; /* latest submitted req */
-			return 0;
-		}
-
-		r->x = NULL;
-
-		/* If both of the PL330 ping-pong buffers filled */
-		if (ret == -EAGAIN) {
-			dev_err(ch->dmac->pi->dev, "%s:%d!\n",
-				__func__, __LINE__);
-			/* Queue back again */
-			add_to_queue(ch, xfer, 1);
-			ret = 0;
-		} else {
-			dev_err(ch->dmac->pi->dev, "%s:%d!\n",
-				__func__, __LINE__);
-			_finish_off(xfer, S3C2410_RES_ERR, 0);
-		}
-	}
-
-	return ret;
-}
-
-static void s3c_pl330_rq(struct s3c_pl330_chan *ch,
-	struct pl330_req *r, enum pl330_op_err err)
-{
-	unsigned long flags;
-	struct s3c_pl330_xfer *xfer;
-	struct pl330_xfer *xl = r->x;
-	enum s3c2410_dma_buffresult res;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	r->x = NULL;
-
-	s3c_pl330_submit(ch, r);
-
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	/* Map result to S3C DMA API */
-	if (err == PL330_ERR_NONE)
-		res = S3C2410_RES_OK;
-	else if (err == PL330_ERR_ABORT)
-		res = S3C2410_RES_ABORT;
-	else
-		res = S3C2410_RES_ERR;
-
-	/* If last request had some xfer */
-	if (xl) {
-		xfer = container_of(xl, struct s3c_pl330_xfer, px);
-		_finish_off(xfer, res, 0);
-	} else {
-		dev_info(ch->dmac->pi->dev, "%s:%d No Xfer?!\n",
-			__func__, __LINE__);
-	}
-}
-
-static void s3c_pl330_rq0(void *token, enum pl330_op_err err)
-{
-	struct pl330_req *r = token;
-	struct s3c_pl330_chan *ch = container_of(r,
-					struct s3c_pl330_chan, req[0]);
-	s3c_pl330_rq(ch, r, err);
-}
-
-static void s3c_pl330_rq1(void *token, enum pl330_op_err err)
-{
-	struct pl330_req *r = token;
-	struct s3c_pl330_chan *ch = container_of(r,
-					struct s3c_pl330_chan, req[1]);
-	s3c_pl330_rq(ch, r, err);
-}
-
-/* Release an acquired channel */
-static void chan_release(struct s3c_pl330_chan *ch)
-{
-	struct s3c_pl330_dmac *dmac;
-
-	if (chan_free(ch))
-		return;
-
-	dmac = ch->dmac;
-	ch->dmac = NULL;
-	dmac->busy_chan--;
-}
-
-int s3c2410_dma_ctrl(enum dma_ch id, enum s3c2410_chan_op op)
-{
-	struct s3c_pl330_xfer *xfer;
-	enum pl330_chan_op pl330op;
-	struct s3c_pl330_chan *ch;
-	unsigned long flags;
-	int idx, ret;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	if (!ch || chan_free(ch)) {
-		ret = -EINVAL;
-		goto ctrl_exit;
-	}
-
-	switch (op) {
-	case S3C2410_DMAOP_START:
-		/* Make sure both reqs are enqueued */
-		idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
-		s3c_pl330_submit(ch, &ch->req[idx]);
-		s3c_pl330_submit(ch, &ch->req[1 - idx]);
-		pl330op = PL330_OP_START;
-		break;
-
-	case S3C2410_DMAOP_STOP:
-		pl330op = PL330_OP_ABORT;
-		break;
-
-	case S3C2410_DMAOP_FLUSH:
-		pl330op = PL330_OP_FLUSH;
-		break;
-
-	case S3C2410_DMAOP_PAUSE:
-	case S3C2410_DMAOP_RESUME:
-	case S3C2410_DMAOP_TIMEOUT:
-	case S3C2410_DMAOP_STARTED:
-		spin_unlock_irqrestore(&res_lock, flags);
-		return 0;
-
-	default:
-		spin_unlock_irqrestore(&res_lock, flags);
-		return -EINVAL;
-	}
-
-	ret = pl330_chan_ctrl(ch->pl330_chan_id, pl330op);
-
-	if (pl330op == PL330_OP_START) {
-		spin_unlock_irqrestore(&res_lock, flags);
-		return ret;
-	}
-
-	idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
-
-	/* Abort the current xfer */
-	if (ch->req[idx].x) {
-		xfer = container_of(ch->req[idx].x,
-				struct s3c_pl330_xfer, px);
-
-		/* Drop xfer during FLUSH */
-		if (pl330op == PL330_OP_FLUSH)
-			del_from_queue(xfer);
-
-		ch->req[idx].x = NULL;
-
-		spin_unlock_irqrestore(&res_lock, flags);
-		_finish_off(xfer, S3C2410_RES_ABORT,
-				pl330op == PL330_OP_FLUSH ? 1 : 0);
-		spin_lock_irqsave(&res_lock, flags);
-	}
-
-	/* Flush the whole queue */
-	if (pl330op == PL330_OP_FLUSH) {
-
-		if (ch->req[1 - idx].x) {
-			xfer = container_of(ch->req[1 - idx].x,
-					struct s3c_pl330_xfer, px);
-
-			del_from_queue(xfer);
-
-			ch->req[1 - idx].x = NULL;
-
-			spin_unlock_irqrestore(&res_lock, flags);
-			_finish_off(xfer, S3C2410_RES_ABORT, 1);
-			spin_lock_irqsave(&res_lock, flags);
-		}
-
-		/* Finish off the remaining in the queue */
-		xfer = ch->xfer_head;
-		while (xfer) {
-
-			del_from_queue(xfer);
-
-			spin_unlock_irqrestore(&res_lock, flags);
-			_finish_off(xfer, S3C2410_RES_ABORT, 1);
-			spin_lock_irqsave(&res_lock, flags);
-
-			xfer = ch->xfer_head;
-		}
-	}
-
-ctrl_exit:
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_ctrl);
-
-int s3c2410_dma_enqueue(enum dma_ch id, void *token,
-			dma_addr_t addr, int size)
-{
-	struct s3c_pl330_chan *ch;
-	struct s3c_pl330_xfer *xfer;
-	unsigned long flags;
-	int idx, ret = 0;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	/* Error if invalid or free channel */
-	if (!ch || chan_free(ch)) {
-		ret = -EINVAL;
-		goto enq_exit;
-	}
-
-	/* Error if size is unaligned */
-	if (ch->rqcfg.brst_size && size % (1 << ch->rqcfg.brst_size)) {
-		ret = -EINVAL;
-		goto enq_exit;
-	}
-
-	xfer = kmem_cache_alloc(ch->dmac->kmcache, GFP_ATOMIC);
-	if (!xfer) {
-		ret = -ENOMEM;
-		goto enq_exit;
-	}
-
-	xfer->token = token;
-	xfer->chan = ch;
-	xfer->px.bytes = size;
-	xfer->px.next = NULL; /* Single request */
-
-	/* For S3C DMA API, direction is always fixed for all xfers */
-	if (ch->req[0].rqtype == MEMTODEV) {
-		xfer->px.src_addr = addr;
-		xfer->px.dst_addr = ch->sdaddr;
-	} else {
-		xfer->px.src_addr = ch->sdaddr;
-		xfer->px.dst_addr = addr;
-	}
-
-	add_to_queue(ch, xfer, 0);
-
-	/* Try submitting on either request */
-	idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
-
-	if (!ch->req[idx].x)
-		s3c_pl330_submit(ch, &ch->req[idx]);
-	else
-		s3c_pl330_submit(ch, &ch->req[1 - idx]);
-
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	if (ch->options & S3C2410_DMAF_AUTOSTART)
-		s3c2410_dma_ctrl(id, S3C2410_DMAOP_START);
-
-	return 0;
-
-enq_exit:
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_enqueue);
-
-int s3c2410_dma_request(enum dma_ch id,
-			struct s3c2410_dma_client *client,
-			void *dev)
-{
-	struct s3c_pl330_dmac *dmac;
-	struct s3c_pl330_chan *ch;
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = chan_acquire(id);
-	if (!ch) {
-		ret = -EBUSY;
-		goto req_exit;
-	}
-
-	dmac = ch->dmac;
-
-	ch->pl330_chan_id = pl330_request_channel(dmac->pi);
-	if (!ch->pl330_chan_id) {
-		chan_release(ch);
-		ret = -EBUSY;
-		goto req_exit;
-	}
-
-	ch->client = client;
-	ch->options = 0; /* Clear any option */
-	ch->callback_fn = NULL; /* Clear any callback */
-	ch->lrq = NULL;
-
-	ch->rqcfg.brst_size = 2; /* Default word size */
-	ch->rqcfg.swap = SWAP_NO;
-	ch->rqcfg.scctl = SCCTRL0; /* Noncacheable and nonbufferable */
-	ch->rqcfg.dcctl = DCCTRL0; /* Noncacheable and nonbufferable */
-	ch->rqcfg.privileged = 0;
-	ch->rqcfg.insnaccess = 0;
-
-	/* Set invalid direction */
-	ch->req[0].rqtype = DEVTODEV;
-	ch->req[1].rqtype = ch->req[0].rqtype;
-
-	ch->req[0].cfg = &ch->rqcfg;
-	ch->req[1].cfg = ch->req[0].cfg;
-
-	ch->req[0].peri = iface_of_dmac(dmac, id) - 1; /* Original index */
-	ch->req[1].peri = ch->req[0].peri;
-
-	ch->req[0].token = &ch->req[0];
-	ch->req[0].xfer_cb = s3c_pl330_rq0;
-	ch->req[1].token = &ch->req[1];
-	ch->req[1].xfer_cb = s3c_pl330_rq1;
-
-	ch->req[0].x = NULL;
-	ch->req[1].x = NULL;
-
-	/* Reset xfer list */
-	INIT_LIST_HEAD(&ch->xfer_list);
-	ch->xfer_head = NULL;
-
-req_exit:
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_request);
-
-int s3c2410_dma_free(enum dma_ch id, struct s3c2410_dma_client *client)
-{
-	struct s3c_pl330_chan *ch;
-	struct s3c_pl330_xfer *xfer;
-	unsigned long flags;
-	int ret = 0;
-	unsigned idx;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	if (!ch || chan_free(ch))
-		goto free_exit;
-
-	/* Refuse if someone else wanted to free the channel */
-	if (ch->client != client) {
-		ret = -EBUSY;
-		goto free_exit;
-	}
-
-	/* Stop any active xfer, Flushe the queue and do callbacks */
-	pl330_chan_ctrl(ch->pl330_chan_id, PL330_OP_FLUSH);
-
-	/* Abort the submitted requests */
-	idx = (ch->lrq == &ch->req[0]) ? 1 : 0;
-
-	if (ch->req[idx].x) {
-		xfer = container_of(ch->req[idx].x,
-				struct s3c_pl330_xfer, px);
-
-		ch->req[idx].x = NULL;
-		del_from_queue(xfer);
-
-		spin_unlock_irqrestore(&res_lock, flags);
-		_finish_off(xfer, S3C2410_RES_ABORT, 1);
-		spin_lock_irqsave(&res_lock, flags);
-	}
-
-	if (ch->req[1 - idx].x) {
-		xfer = container_of(ch->req[1 - idx].x,
-				struct s3c_pl330_xfer, px);
-
-		ch->req[1 - idx].x = NULL;
-		del_from_queue(xfer);
-
-		spin_unlock_irqrestore(&res_lock, flags);
-		_finish_off(xfer, S3C2410_RES_ABORT, 1);
-		spin_lock_irqsave(&res_lock, flags);
-	}
-
-	/* Pluck and Abort the queued requests in order */
-	do {
-		xfer = get_from_queue(ch, 1);
-
-		spin_unlock_irqrestore(&res_lock, flags);
-		_finish_off(xfer, S3C2410_RES_ABORT, 1);
-		spin_lock_irqsave(&res_lock, flags);
-	} while (xfer);
-
-	ch->client = NULL;
-
-	pl330_release_channel(ch->pl330_chan_id);
-
-	ch->pl330_chan_id = NULL;
-
-	chan_release(ch);
-
-free_exit:
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_free);
-
-int s3c2410_dma_config(enum dma_ch id, int xferunit)
-{
-	struct s3c_pl330_chan *ch;
-	struct pl330_info *pi;
-	unsigned long flags;
-	int i, dbwidth, ret = 0;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	if (!ch || chan_free(ch)) {
-		ret = -EINVAL;
-		goto cfg_exit;
-	}
-
-	pi = ch->dmac->pi;
-	dbwidth = pi->pcfg.data_bus_width / 8;
-
-	/* Max size of xfer can be pcfg.data_bus_width */
-	if (xferunit > dbwidth) {
-		ret = -EINVAL;
-		goto cfg_exit;
-	}
-
-	i = 0;
-	while (xferunit != (1 << i))
-		i++;
-
-	/* If valid value */
-	if (xferunit == (1 << i))
-		ch->rqcfg.brst_size = i;
-	else
-		ret = -EINVAL;
-
-cfg_exit:
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_config);
-
-/* Options that are supported by this driver */
-#define S3C_PL330_FLAGS (S3C2410_DMAF_CIRCULAR | S3C2410_DMAF_AUTOSTART)
-
-int s3c2410_dma_setflags(enum dma_ch id, unsigned int options)
-{
-	struct s3c_pl330_chan *ch;
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	if (!ch || chan_free(ch) || options & ~(S3C_PL330_FLAGS))
-		ret = -EINVAL;
-	else
-		ch->options = options;
-
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_setflags);
-
-int s3c2410_dma_set_buffdone_fn(enum dma_ch id, s3c2410_dma_cbfn_t rtn)
-{
-	struct s3c_pl330_chan *ch;
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	if (!ch || chan_free(ch))
-		ret = -EINVAL;
-	else
-		ch->callback_fn = rtn;
-
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
-
-int s3c2410_dma_devconfig(enum dma_ch id, enum s3c2410_dmasrc source,
-			  unsigned long address)
-{
-	struct s3c_pl330_chan *ch;
-	unsigned long flags;
-	int ret = 0;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	ch = id_to_chan(id);
-
-	if (!ch || chan_free(ch)) {
-		ret = -EINVAL;
-		goto devcfg_exit;
-	}
-
-	switch (source) {
-	case S3C2410_DMASRC_HW: /* P->M */
-		ch->req[0].rqtype = DEVTOMEM;
-		ch->req[1].rqtype = DEVTOMEM;
-		ch->rqcfg.src_inc = 0;
-		ch->rqcfg.dst_inc = 1;
-		break;
-	case S3C2410_DMASRC_MEM: /* M->P */
-		ch->req[0].rqtype = MEMTODEV;
-		ch->req[1].rqtype = MEMTODEV;
-		ch->rqcfg.src_inc = 1;
-		ch->rqcfg.dst_inc = 0;
-		break;
-	default:
-		ret = -EINVAL;
-		goto devcfg_exit;
-	}
-
-	ch->sdaddr = address;
-
-devcfg_exit:
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(s3c2410_dma_devconfig);
-
-int s3c2410_dma_getposition(enum dma_ch id, dma_addr_t *src, dma_addr_t *dst)
-{
-	struct s3c_pl330_chan *ch = id_to_chan(id);
-	struct pl330_chanstatus status;
-	int ret;
-
-	if (!ch || chan_free(ch))
-		return -EINVAL;
-
-	ret = pl330_chan_status(ch->pl330_chan_id, &status);
-	if (ret < 0)
-		return ret;
-
-	*src = status.src_addr;
-	*dst = status.dst_addr;
-
-	return 0;
-}
-EXPORT_SYMBOL(s3c2410_dma_getposition);
-
-static irqreturn_t pl330_irq_handler(int irq, void *data)
-{
-	if (pl330_update(data))
-		return IRQ_HANDLED;
-	else
-		return IRQ_NONE;
-}
-
-static int pl330_probe(struct platform_device *pdev)
-{
-	struct s3c_pl330_dmac *s3c_pl330_dmac;
-	struct s3c_pl330_platdata *pl330pd;
-	struct pl330_info *pl330_info;
-	struct resource *res;
-	int i, ret, irq;
-
-	pl330pd = pdev->dev.platform_data;
-
-	/* Can't do without the list of _32_ peripherals */
-	if (!pl330pd || !pl330pd->peri) {
-		dev_err(&pdev->dev, "platform data missing!\n");
-		return -ENODEV;
-	}
-
-	pl330_info = kzalloc(sizeof(*pl330_info), GFP_KERNEL);
-	if (!pl330_info)
-		return -ENOMEM;
-
-	pl330_info->pl330_data = NULL;
-	pl330_info->dev = &pdev->dev;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		ret = -ENODEV;
-		goto probe_err1;
-	}
-
-	request_mem_region(res->start, resource_size(res), pdev->name);
-
-	pl330_info->base = ioremap(res->start, resource_size(res));
-	if (!pl330_info->base) {
-		ret = -ENXIO;
-		goto probe_err2;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		ret = irq;
-		goto probe_err3;
-	}
-
-	ret = request_irq(irq, pl330_irq_handler, 0,
-			dev_name(&pdev->dev), pl330_info);
-	if (ret)
-		goto probe_err4;
-
-	/* Allocate a new DMAC */
-	s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL);
-	if (!s3c_pl330_dmac) {
-		ret = -ENOMEM;
-		goto probe_err5;
-	}
-
-	/* Get operation clock and enable it */
-	s3c_pl330_dmac->clk = clk_get(&pdev->dev, "pdma");
-	if (IS_ERR(s3c_pl330_dmac->clk)) {
-		dev_err(&pdev->dev, "Cannot get operation clock.\n");
-		ret = -EINVAL;
-		goto probe_err6;
-	}
-	clk_enable(s3c_pl330_dmac->clk);
-
-	ret = pl330_add(pl330_info);
-	if (ret)
-		goto probe_err7;
-
-	/* Hook the info */
-	s3c_pl330_dmac->pi = pl330_info;
-
-	/* No busy channels */
-	s3c_pl330_dmac->busy_chan = 0;
-
-	s3c_pl330_dmac->kmcache = kmem_cache_create(dev_name(&pdev->dev),
-				sizeof(struct s3c_pl330_xfer), 0, 0, NULL);
-
-	if (!s3c_pl330_dmac->kmcache) {
-		ret = -ENOMEM;
-		goto probe_err8;
-	}
-
-	/* Get the list of peripherals */
-	s3c_pl330_dmac->peri = pl330pd->peri;
-
-	/* Attach to the list of DMACs */
-	list_add_tail(&s3c_pl330_dmac->node, &dmac_list);
-
-	/* Create a channel for each peripheral in the DMAC
-	 * that is, if it doesn't already exist
-	 */
-	for (i = 0; i < PL330_MAX_PERI; i++)
-		if (s3c_pl330_dmac->peri[i] != DMACH_MAX)
-			chan_add(s3c_pl330_dmac->peri[i]);
-
-	printk(KERN_INFO
-		"Loaded driver for PL330 DMAC-%d %s\n",	pdev->id, pdev->name);
-	printk(KERN_INFO
-		"\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
-		pl330_info->pcfg.data_buf_dep,
-		pl330_info->pcfg.data_bus_width / 8, pl330_info->pcfg.num_chan,
-		pl330_info->pcfg.num_peri, pl330_info->pcfg.num_events);
-
-	return 0;
-
-probe_err8:
-	pl330_del(pl330_info);
-probe_err7:
-	clk_disable(s3c_pl330_dmac->clk);
-	clk_put(s3c_pl330_dmac->clk);
-probe_err6:
-	kfree(s3c_pl330_dmac);
-probe_err5:
-	free_irq(irq, pl330_info);
-probe_err4:
-probe_err3:
-	iounmap(pl330_info->base);
-probe_err2:
-	release_mem_region(res->start, resource_size(res));
-probe_err1:
-	kfree(pl330_info);
-
-	return ret;
-}
-
-static int pl330_remove(struct platform_device *pdev)
-{
-	struct s3c_pl330_dmac *dmac, *d;
-	struct s3c_pl330_chan *ch;
-	unsigned long flags;
-	int del, found;
-
-	if (!pdev->dev.platform_data)
-		return -EINVAL;
-
-	spin_lock_irqsave(&res_lock, flags);
-
-	found = 0;
-	list_for_each_entry(d, &dmac_list, node)
-		if (d->pi->dev == &pdev->dev) {
-			found = 1;
-			break;
-		}
-
-	if (!found) {
-		spin_unlock_irqrestore(&res_lock, flags);
-		return 0;
-	}
-
-	dmac = d;
-
-	/* Remove all Channels that are managed only by this DMAC */
-	list_for_each_entry(ch, &chan_list, node) {
-
-		/* Only channels that are handled by this DMAC */
-		if (iface_of_dmac(dmac, ch->id))
-			del = 1;
-		else
-			continue;
-
-		/* Don't remove if some other DMAC has it too */
-		list_for_each_entry(d, &dmac_list, node)
-			if (d != dmac && iface_of_dmac(d, ch->id)) {
-				del = 0;
-				break;
-			}
-
-		if (del) {
-			spin_unlock_irqrestore(&res_lock, flags);
-			s3c2410_dma_free(ch->id, ch->client);
-			spin_lock_irqsave(&res_lock, flags);
-			list_del(&ch->node);
-			kfree(ch);
-		}
-	}
-
-	/* Disable operation clock */
-	clk_disable(dmac->clk);
-	clk_put(dmac->clk);
-
-	/* Remove the DMAC */
-	list_del(&dmac->node);
-	kfree(dmac);
-
-	spin_unlock_irqrestore(&res_lock, flags);
-
-	return 0;
-}
-
-static struct platform_driver pl330_driver = {
-	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "s3c-pl330",
-	},
-	.probe		= pl330_probe,
-	.remove		= pl330_remove,
-};
-
-static int __init pl330_init(void)
-{
-	return platform_driver_register(&pl330_driver);
-}
-module_init(pl330_init);
-
-static void __exit pl330_exit(void)
-{
-	platform_driver_unregister(&pl330_driver);
-	return;
-}
-module_exit(pl330_exit);
-
-MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
-MODULE_DESCRIPTION("Driver for PL330 DMA Controller");
-MODULE_LICENSE("GPL");
-- 
1.7.1

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

* [PATCH V2 11/12] spi/s3c64xx: Add support DMA engine API
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (9 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 10/12] ARM: SAMSUNG: Remove S3C-PL330-DMA driver Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13  8:47 ` [PATCH V2 12/12] ASoC: Samsung: Update DMA interface Kukjin Kim
  11 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch adds to support DMA generic API to transfer raw
SPI data. Basiclly the spi driver uses DMA generic API if
architecture supports it. Otherwise, uses Samsung specific
S3C-PL330 APIs.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-----------------------
 1 files changed, 69 insertions(+), 72 deletions(-)

diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c
index 8945e20..a4cf76a 100644
--- a/drivers/spi/spi_s3c64xx.c
+++ b/drivers/spi/spi_s3c64xx.c
@@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
+	unsigned			rx_ch;
+	unsigned			tx_ch;
+	struct samsung_dma_ops		*ops;
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -227,6 +230,38 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~RXBUSY;
+	/* If the other done */
+	if (!(sdd->state & TXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+static void s3c64xx_spi_dma_txcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~TXBUSY;
+	/* If the other done */
+	if (!(sdd->state & RXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 				struct spi_device *spi,
 				struct spi_transfer *xfer, int dma_mode)
@@ -234,6 +269,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
 	void __iomem *regs = sdd->regs;
 	u32 modecfg, chcfg;
+	struct samsung_dma_prep_info info;
 
 	modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
 	modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
@@ -259,10 +295,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 		chcfg |= S3C64XX_SPI_CH_TXCH_ON;
 		if (dma_mode) {
 			modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-			s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
-						xfer->tx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_TO_DEVICE;
+			info.buf = xfer->tx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_txcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->tx_ch, &info);
+			sdd->ops->trigger(sdd->tx_ch);
 		} else {
 			switch (sdd->cur_bpw) {
 			case 32:
@@ -294,10 +334,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 			writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
 					| S3C64XX_SPI_PACKET_CNT_EN,
 					regs + S3C64XX_SPI_PACKET_CNT);
-			s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
-						xfer->rx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_FROM_DEVICE;
+			info.buf = xfer->rx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_rxcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->rx_ch, &info);
+			sdd->ops->trigger(sdd->rx_ch);
 		}
 	}
 
@@ -483,46 +527,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 	}
 }
 
-static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~RXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
-
-	/* If the other done */
-	if (!(sdd->state & TXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
-static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~TXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
-
-	/* If the other done */
-	if (!(sdd->state & RXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
 #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
 
 static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
@@ -697,12 +701,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
 			if (use_dma) {
 				if (xfer->tx_buf != NULL
 						&& (sdd->state & TXBUSY))
-					s3c2410_dma_ctrl(sdd->tx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->tx_ch);
 				if (xfer->rx_buf != NULL
 						&& (sdd->state & RXBUSY))
-					s3c2410_dma_ctrl(sdd->rx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->rx_ch);
 			}
 
 			goto out;
@@ -742,24 +744,19 @@ out:
 
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
-	if (s3c2410_dma_request(sdd->rx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
-	s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
-					sdd->sfr_start + S3C64XX_SPI_RX_DATA);
-
-	if (s3c2410_dma_request(sdd->tx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
-		s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
-	s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
-					sdd->sfr_start + S3C64XX_SPI_TX_DATA);
+
+	struct samsung_dma_info info;
+	sdd->ops = samsung_dma_get_ops();
+
+	info.cap = DMA_SLAVE;
+	info.client = &s3c64xx_spi_dma_client;
+	info.direction = DMA_FROM_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+	info.width = sdd->cur_bpw / 8;
+	sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
+	info.direction = DMA_TO_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+	sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
 
 	return 1;
 }
@@ -800,8 +797,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
 	spin_unlock_irqrestore(&sdd->lock, flags);
 
 	/* Free DMA channels */
-	s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
-	s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client);
 }
 
 static int s3c64xx_spi_transfer(struct spi_device *spi,
-- 
1.7.1

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

* [PATCH V2 12/12] ASoC: Samsung: Update DMA interface
  2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
                   ` (10 preceding siblings ...)
  2011-07-13  8:47 ` [PATCH V2 11/12] spi/s3c64xx: Add support DMA engine API Kukjin Kim
@ 2011-07-13  8:47 ` Kukjin Kim
  2011-07-13 23:57   ` Mark Brown
  11 siblings, 1 reply; 23+ messages in thread
From: Kukjin Kim @ 2011-07-13  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boojin Kim <boojin.kim@samsung.com>

This patch adds to support the DMA PL330 driver that uses
DMA generic API. Samsung sound driver uses DMA generic API
if architecture supports it. Otherwise, use samsung specific
S3C-PL330 API driver to transfer PCM data.

Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Cc: Jassi Brar <jassisinghbrar@gmail.com>
Cc: Liam Girdwood <lrg@ti.com>
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
---
 arch/arm/mach-s3c2410/include/mach/dma.h       |    2 +-
 arch/arm/mach-s3c64xx/include/mach/dma.h       |    2 +-
 arch/arm/plat-samsung/include/plat/dma-pl330.h |    2 +-
 sound/soc/samsung/ac97.c                       |    8 +-
 sound/soc/samsung/dma.c                        |  158 ++++++++++--------------
 sound/soc/samsung/dma.h                        |    4 +-
 6 files changed, 79 insertions(+), 97 deletions(-)

diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
index 71a662d..c69d60a 100644
--- a/arch/arm/mach-s3c2410/include/mach/dma.h
+++ b/arch/arm/mach-s3c2410/include/mach/dma.h
@@ -197,7 +197,7 @@ struct s3c2410_dma_chan {
 
 typedef unsigned long dma_device_t;
 
-static inline bool s3c_dma_has_circular(void)
+static inline bool dma_has_circular(void)
 {
 	return false;
 }
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h
index 0a5d926..d752e27 100644
--- a/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -58,7 +58,7 @@ enum dma_ch {
 	DMACH_MAX		/* the end */
 };
 
-static __inline__ bool s3c_dma_has_circular(void)
+static inline bool dma_has_circular(void)
 {
 	return true;
 }
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
index dbc1288..4bd0e49 100644
--- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -100,7 +100,7 @@ struct s3c2410_dma_client {
 	char	*name;
 };
 
-static inline bool s3c_dma_has_circular(void)
+static inline bool dma_has_circular(void)
 {
 	return true;
 }
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index f97110e..e09cb9d 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -271,7 +271,9 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
 
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
-	s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+	if (!dma_data->ops)
+		dma_data->ops = samsung_dma_get_ops();
+	dma_data->ops->started(dma_data->channel);
 
 	return 0;
 }
@@ -317,7 +319,9 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
 
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
-	s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+	if (!dma_data->ops)
+		dma_data->ops = samsung_dma_get_ops();
+	dma_data->ops->started(dma_data->channel);
 
 	return 0;
 }
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 5cb3b88..b5f5f6b 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -17,6 +17,9 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 
+#include <linux/dmaengine.h>
+#include <linux/amba/pl330.h>
+
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
@@ -62,77 +65,80 @@ struct runtime_data {
 	struct s3c_dma_params *params;
 };
 
+static void audio_buffdone(void *data);
+
 /* dma_enqueue
  *
  * place a dma buffer onto the queue for the dma system
  * to handle.
-*/
+ */
 static void dma_enqueue(struct snd_pcm_substream *substream)
 {
 	struct runtime_data *prtd = substream->runtime->private_data;
 	dma_addr_t pos = prtd->dma_pos;
 	unsigned int limit;
-	int ret;
+	struct samsung_dma_prep_info dma_info;
 
 	pr_debug("Entered %s\n", __func__);
 
-	if (s3c_dma_has_circular())
-		limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+	limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+
+	if (dma_has_circular())
+		dma_info.cap = DMA_CYCLIC;
 	else
-		limit = prtd->dma_limit;
+		dma_info.cap = DMA_SLAVE;
 
-	pr_debug("%s: loaded %d, limit %d\n",
-				__func__, prtd->dma_loaded, limit);
+	dma_info.direction =
+		(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+		? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	dma_info.fp = audio_buffdone;
+	dma_info.fp_param = substream;
+	dma_info.period = prtd->dma_period;
+	dma_info.len = prtd->dma_period*limit;
 
 	while (prtd->dma_loaded < limit) {
-		unsigned long len = prtd->dma_period;
-
 		pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
 
-		if ((pos + len) > prtd->dma_end) {
-			len  = prtd->dma_end - pos;
-			pr_debug("%s: corrected dma len %ld\n", __func__, len);
+		if ((pos + dma_info.period) > prtd->dma_end) {
+			dma_info.period  = prtd->dma_end - pos;
+			pr_debug("%s: corrected dma len %ld\n",
+					__func__, dma_info.period);
 		}
 
-		ret = s3c2410_dma_enqueue(prtd->params->channel,
-			substream, pos, len);
+		dma_info.buf = pos;
+		prtd->params->ops->prepare(prtd->params->ch, &dma_info);
 
-		if (ret == 0) {
-			prtd->dma_loaded++;
-			pos += prtd->dma_period;
-			if (pos >= prtd->dma_end)
-				pos = prtd->dma_start;
-		} else
-			break;
+		prtd->dma_loaded++;
+		pos += prtd->dma_period;
+		if (pos >= prtd->dma_end)
+			pos = prtd->dma_start;
 	}
 
 	prtd->dma_pos = pos;
 }
 
-static void audio_buffdone(struct s3c2410_dma_chan *channel,
-				void *dev_id, int size,
-				enum s3c2410_dma_buffresult result)
+static void audio_buffdone(void *data)
 {
-	struct snd_pcm_substream *substream = dev_id;
-	struct runtime_data *prtd;
+	struct snd_pcm_substream *substream = data;
+	struct runtime_data *prtd = substream->runtime->private_data;
 
 	pr_debug("Entered %s\n", __func__);
 
-	if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
-		return;
+	if (prtd->state & ST_RUNNING) {
+		prtd->dma_pos += prtd->dma_period;
+		if (prtd->dma_pos >= prtd->dma_end)
+			prtd->dma_pos = prtd->dma_start;
 
-	prtd = substream->runtime->private_data;
+		if (substream)
+			snd_pcm_period_elapsed(substream);
 
-	if (substream)
-		snd_pcm_period_elapsed(substream);
-
-	spin_lock(&prtd->lock);
-	if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
-		prtd->dma_loaded--;
-		dma_enqueue(substream);
+		spin_lock(&prtd->lock);
+		if (!dma_has_circular()) {
+			prtd->dma_loaded--;
+			dma_enqueue(substream);
+		}
+		spin_unlock(&prtd->lock);
 	}
-
-	spin_unlock(&prtd->lock);
 }
 
 static int dma_hw_params(struct snd_pcm_substream *substream,
@@ -144,8 +150,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
 	unsigned long totbytes = params_buffer_bytes(params);
 	struct s3c_dma_params *dma =
 		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	int ret = 0;
-
+	struct samsung_dma_info dma_info;
 
 	pr_debug("Entered %s\n", __func__);
 
@@ -154,32 +159,26 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
 	if (!dma)
 		return 0;
 
-	/* this may get called several times by oss emulation
-	 * with different params -HW */
 	if (prtd->params == NULL) {
-		/* prepare DMA */
 		prtd->params = dma;
 
-		pr_debug("params %p, client %p, channel %d\n", prtd->params,
-			prtd->params->client, prtd->params->channel);
-
-		ret = s3c2410_dma_request(prtd->params->channel,
-					  prtd->params->client, NULL);
-
-		if (ret < 0) {
-			printk(KERN_ERR "failed to get dma channel\n");
-			return ret;
-		}
-
-		/* use the circular buffering if we have it available. */
-		if (s3c_dma_has_circular())
-			s3c2410_dma_setflags(prtd->params->channel,
-					     S3C2410_DMAF_CIRCULAR);
+		prtd->params->ops = samsung_dma_get_ops();
+
+		/* request channel */
+		if (dma_has_circular())
+			dma_info.cap = DMA_CYCLIC;
+		else
+			dma_info.cap = DMA_SLAVE;
+		dma_info.client = prtd->params->client;
+		dma_info.direction =
+			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+			? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		dma_info.width = prtd->params->dma_size;
+		dma_info.fifo = prtd->params->dma_addr;
+		prtd->params->ch = prtd->params->ops->request(
+				prtd->params->channel, &dma_info);
 	}
 
-	s3c2410_dma_set_buffdone_fn(prtd->params->channel,
-				    audio_buffdone);
-
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
 	runtime->dma_bytes = totbytes;
@@ -206,7 +205,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream)
 	snd_pcm_set_runtime_buffer(substream, NULL);
 
 	if (prtd->params) {
-		s3c2410_dma_free(prtd->params->channel, prtd->params->client);
+		prtd->params->ops->release(prtd->params->ch,
+					prtd->params->client);
 		prtd->params = NULL;
 	}
 
@@ -225,23 +225,8 @@ static int dma_prepare(struct snd_pcm_substream *substream)
 	if (!prtd->params)
 		return 0;
 
-	/* channel needs configuring for mem=>device, increment memory addr,
-	 * sync to pclk, half-word transfers to the IIS-FIFO. */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		s3c2410_dma_devconfig(prtd->params->channel,
-				      S3C2410_DMASRC_MEM,
-				      prtd->params->dma_addr);
-	} else {
-		s3c2410_dma_devconfig(prtd->params->channel,
-				      S3C2410_DMASRC_HW,
-				      prtd->params->dma_addr);
-	}
+	prtd->params->ops->flush(prtd->params->ch);
 
-	s3c2410_dma_config(prtd->params->channel,
-			   prtd->params->dma_size);
-
-	/* flush the DMA channel */
-	s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
 	prtd->dma_loaded = 0;
 	prtd->dma_pos = prtd->dma_start;
 
@@ -265,14 +250,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		prtd->state |= ST_RUNNING;
-		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
+		prtd->params->ops->trigger(prtd->params->ch);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		prtd->state &= ~ST_RUNNING;
-		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
+		prtd->params->ops->stop(prtd->params->ch);
 		break;
 
 	default:
@@ -291,21 +276,12 @@ dma_pointer(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct runtime_data *prtd = runtime->private_data;
 	unsigned long res;
-	dma_addr_t src, dst;
 
 	pr_debug("Entered %s\n", __func__);
 
-	spin_lock(&prtd->lock);
-	s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
-
-	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		res = dst - prtd->dma_start;
-	else
-		res = src - prtd->dma_start;
-
-	spin_unlock(&prtd->lock);
+	res = prtd->dma_pos - prtd->dma_start;
 
-	pr_debug("Pointer %x %x\n", src, dst);
+	pr_debug("Pointer offset: %lu\n", res);
 
 	/* we seem to be getting the odd error from the pcm library due
 	 * to out-of-bounds pointers. this is maybe due to the dma engine
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index c506592..7d1ead7 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -6,7 +6,7 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  ALSA PCM interface for the Samsung S3C24xx CPU
+ *  ALSA PCM interface for the Samsung SoC
  */
 
 #ifndef _S3C_AUDIO_H
@@ -17,6 +17,8 @@ struct s3c_dma_params {
 	int channel;				/* Channel ID */
 	dma_addr_t dma_addr;
 	int dma_size;			/* Size of the DMA transfer */
+	unsigned ch;
+	struct samsung_dma_ops *ops;
 };
 
 #endif
-- 
1.7.1

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

* [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC
  2011-07-13  8:47 ` [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim
@ 2011-07-13  9:07   ` Russell King - ARM Linux
  0 siblings, 0 replies; 23+ messages in thread
From: Russell King - ARM Linux @ 2011-07-13  9:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 13, 2011 at 05:47:26PM +0900, Kukjin Kim wrote:
> @@ -688,7 +691,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
>  	pi->mcbufsz = pdat->mcbuf_sz;
>  
>  	res = &adev->res;
> -	request_mem_region(res->start, resource_size(res), "dma-pl330");
> +	request_mem_region(res->start,
> +		resource_size(res), dev_name(&adev->dev));

The convention that we've been using is:

10004000-10004fff : mb:aaci
  10004000-10004fff : aaci-pl041
10005000-10005fff : mb:mmci
  10005000-10005fff : mmci-pl18x
10006000-10006fff : mb:kmi0
  10006000-10006fff : kmi-pl050
10007000-10007fff : mb:kmi1
  10007000-10007fff : kmi-pl050
10009000-10009fff : mb:uart0
  10009000-10009fff : uart-pl011
1000a000-1000afff : mb:uart1
  1000a000-1000afff : uart-pl011
1000b000-1000bfff : mb:uart2
  1000b000-1000bfff : uart-pl011
1000c000-1000cfff : mb:uart3
  1000c000-1000cfff : uart-pl011

The parent resource uses the device name.  The child resource is the
driver name.  That (a) avoids useless duplication of data in /proc/iomem
and (b) is more informative when you look at /proc/iomem about what's
where.

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

* [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
  2011-07-13  8:47 ` [PATCH V2 03/12] DMA: PL330: Add DMA capabilities Kukjin Kim
@ 2011-07-13  9:14   ` Russell King - ARM Linux
  2011-07-13 11:04     ` boojin
  2011-07-15  4:45   ` Chanho Park
  1 sibling, 1 reply; 23+ messages in thread
From: Russell King - ARM Linux @ 2011-07-13  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 13, 2011 at 05:47:28PM +0900, Kukjin Kim wrote:
> +static void pl330_tasklet_cyclic(unsigned long data)
> +{
> +	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> +	struct dma_pl330_desc *desc, *_dt;
> +	unsigned long flags;
> +	LIST_HEAD(list);
> +
> +	spin_lock_irqsave(&pch->lock, flags);
> +
> +	/* Pick up ripe tomatoes */
> +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> +		if ((desc->status == DONE) && desc->cyclic) {
> +			dma_async_tx_callback callback;
> +
> +			list_move_tail(&desc->node, &pch->work_list);
> +			pch->completed = desc->txd.cookie;
> +
> +			desc->status = PREP;
> +
> +			/* Try to submit a req imm.
> +			next to the last completed cookie */
> +			fill_queue(pch);
> +
> +			/* Make sure the PL330 Channel thread is active */
> +			pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
> +
> +			callback = desc->txd.callback;
> +			if (callback)
> +				callback(desc->txd.callback_param);

How does this work when callbacks are allowed to queue new requests?
Aren't you going to deadlock on the spinlock?

I don't see 'list' being used in this function either.

> +
> +		}
> +
> +	spin_unlock_irqrestore(&pch->lock, flags);
> +}
> +
> +static void pl330_cyclic_free(struct dma_pl330_chan *pch)
> +{
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	struct dma_pl330_desc *desc, *_dt;
> +	unsigned long flags;
> +	LIST_HEAD(list);
> +
> +	spin_lock_irqsave(&pdmac->pool_lock, flags);
> +
> +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> +	if (desc->cyclic)
> +		list_move_tail(&desc->node, &list);
> +
> +	list_splice_tail_init(&list, &pdmac->desc_pool);

As you're not using 'list' after this point, would 'list_splice_tail'
do here?

> +
> +	spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> +	pch->cyclic_task = NULL;
> +}
> +
>  static void pl330_tasklet(unsigned long data)
>  {
>  	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> @@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
>  
>  	spin_unlock_irqrestore(&pch->lock, flags);
>  
> +	if (pch->cyclic_task)
> +		tasklet_schedule(pch->cyclic_task);
> +	else
>  	tasklet_schedule(&pch->task);

This 'tasklet_schedule' wants to be indented.

>  }
>  
> @@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>  static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
>  {
>  	struct dma_pl330_chan *pch = to_pchan(chan);
> -	struct dma_pl330_desc *desc;
> +	struct dma_pl330_desc *desc, *_dt;
>  	unsigned long flags;
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	struct dma_slave_config *slave_config;
> +	struct dma_pl330_peri *peri;
> +	int i;
> +	LIST_HEAD(list);
>  
> -	/* Only supports DMA_TERMINATE_ALL */
> -	if (cmd != DMA_TERMINATE_ALL)
> -		return -ENXIO;
> -
> -	spin_lock_irqsave(&pch->lock, flags);
> -
> -	/* FLUSH the PL330 Channel thread */
> -	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> +	switch (cmd) {
> +	case DMA_TERMINATE_ALL:
> +		spin_lock_irqsave(&pch->lock, flags);
>  
> -	/* Mark all desc done */
> -	list_for_each_entry(desc, &pch->work_list, node)
> -		desc->status = DONE;
> +		/* FLUSH the PL330 Channel thread */
> +		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
>  
> -	spin_unlock_irqrestore(&pch->lock, flags);
> +		/* Mark all desc done */
> +		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
> +			desc->status = DONE;
> +			pch->completed = desc->txd.cookie;
> +			list_move_tail(&desc->node, &list);
> +		}
>  
> -	pl330_tasklet((unsigned long) pch);
> +		list_splice_tail_init(&list, &pdmac->desc_pool);

Again, would list_splice_tail() do here?

> +		spin_unlock_irqrestore(&pch->lock, flags);
> +		break;
> +	case DMA_SLAVE_CONFIG:
> +		slave_config = (struct dma_slave_config *)arg;
> +		peri = pch->chan.private;
> +
> +		if (slave_config->direction == DMA_TO_DEVICE) {
> +			if (slave_config->dst_addr)
> +				peri->fifo_addr = slave_config->dst_addr;
> +			if (slave_config->dst_addr_width) {
> +				i = 0;
> +				while (slave_config->dst_addr_width != (1 << i))
> +					i++;
> +				peri->burst_sz = i;
> +			}
> +		} else if (slave_config->direction == DMA_FROM_DEVICE) {
> +			if (slave_config->src_addr)
> +				peri->fifo_addr = slave_config->src_addr;
> +			if (slave_config->src_addr_width) {
> +				i = 0;
> +				while (slave_config->src_addr_width != (1 << i))
> +					i++;
> +				peri->burst_sz = i;
> +			}
> +		}

It would make more sense to store the M2P and P2M address/width/burst size
separately, so you don't have to make DMA_SLAVE_CONFIG calls before every
transfer.

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

* [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
  2011-07-13  9:14   ` Russell King - ARM Linux
@ 2011-07-13 11:04     ` boojin
  0 siblings, 0 replies; 23+ messages in thread
From: boojin @ 2011-07-13 11:04 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds DMA cyclic capability and Slave configuration.
DMA cyclic capability is only used for audio circular buffer.

Russell king wrote:
> On Wed, Jul 13, 2011 at 05:47:28PM +0900, Kukjin Kim wrote:
> > +static void pl330_tasklet_cyclic(unsigned long data)
> > +{
> > +	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> > +	struct dma_pl330_desc *desc, *_dt;
> > +	unsigned long flags;
> > +	LIST_HEAD(list);
> > +
> > +	spin_lock_irqsave(&pch->lock, flags);
> > +
> > +	/* Pick up ripe tomatoes */
> > +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> > +		if ((desc->status == DONE) && desc->cyclic) {
> > +			dma_async_tx_callback callback;
> > +
> > +			list_move_tail(&desc->node, &pch->work_list);
> > +			pch->completed = desc->txd.cookie;
> > +
> > +			desc->status = PREP;
> > +
> > +			/* Try to submit a req imm.
> > +			next to the last completed cookie */
> > +			fill_queue(pch);
> > +
> > +			/* Make sure the PL330 Channel thread is active */
> > +			pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
> > +
> > +			callback = desc->txd.callback;
> > +			if (callback)
> > +				callback(desc->txd.callback_param);
> 
> How does this work when callbacks are allowed to queue new requests?
> Aren't you going to deadlock on the spinlock?
> 
> I don't see 'list' being used in this function either.
> 
>
Cyclic capability re-uses the requests that were submitted through
tx_submit().
It's possible because Cyclic capability uses same DMA configuration.
This pl330_tasklet_cyclic() makes the status of the done request into
'PREP'. 
And, re-submit it to PL330.
There are no deadlock because callback function just gathers transmit
position.
And Cyclic capability doesn't use 'list' for queue new requests.

> > +
> > +		}
> > +
> > +	spin_unlock_irqrestore(&pch->lock, flags);
> > +}
> > +
> > +static void pl330_cyclic_free(struct dma_pl330_chan *pch)
> > +{
> > +	struct dma_pl330_dmac *pdmac = pch->dmac;
> > +	struct dma_pl330_desc *desc, *_dt;
> > +	unsigned long flags;
> > +	LIST_HEAD(list);
> > +
> > +	spin_lock_irqsave(&pdmac->pool_lock, flags);
> > +
> > +	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> > +	if (desc->cyclic)
> > +		list_move_tail(&desc->node, &list);
> > +
> > +	list_splice_tail_init(&list, &pdmac->desc_pool);
> 
> As you're not using 'list' after this point, would 'list_splice_tail'
> do here?
Yes, You're right. the 'list' isn't used after device_free_chan_resources().
So, I release it to desc_pool by using 'list_splice_tail'

> 
> > +
> > +	spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> > +	pch->cyclic_task = NULL;
> > +}
> > +
> >  static void pl330_tasklet(unsigned long data)
> >  {
> >  	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> > @@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum
> pl330_op_err err)
> >
> >  	spin_unlock_irqrestore(&pch->lock, flags);
> >
> > +	if (pch->cyclic_task)
> > +		tasklet_schedule(pch->cyclic_task);
> > +	else
> >  	tasklet_schedule(&pch->task);
> 
> This 'tasklet_schedule' wants to be indented.
I will address your guide. Thanks

> 
> >  }
> >
> > @@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct
> dma_chan *chan)
> >  static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> unsigned long arg)
> >  {
> >  	struct dma_pl330_chan *pch = to_pchan(chan);
> > -	struct dma_pl330_desc *desc;
> > +	struct dma_pl330_desc *desc, *_dt;
> >  	unsigned long flags;
> > +	struct dma_pl330_dmac *pdmac = pch->dmac;
> > +	struct dma_slave_config *slave_config;
> > +	struct dma_pl330_peri *peri;
> > +	int i;
> > +	LIST_HEAD(list);
> >
> > -	/* Only supports DMA_TERMINATE_ALL */
> > -	if (cmd != DMA_TERMINATE_ALL)
> > -		return -ENXIO;
> > -
> > -	spin_lock_irqsave(&pch->lock, flags);
> > -
> > -	/* FLUSH the PL330 Channel thread */
> > -	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> > +	switch (cmd) {
> > +	case DMA_TERMINATE_ALL:
> > +		spin_lock_irqsave(&pch->lock, flags);
> >
> > -	/* Mark all desc done */
> > -	list_for_each_entry(desc, &pch->work_list, node)
> > -		desc->status = DONE;
> > +		/* FLUSH the PL330 Channel thread */
> > +		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> >
> > -	spin_unlock_irqrestore(&pch->lock, flags);
> > +		/* Mark all desc done */
> > +		list_for_each_entry_safe(desc, _dt, &pch->work_list , node)
> {
> > +			desc->status = DONE;
> > +			pch->completed = desc->txd.cookie;
> > +			list_move_tail(&desc->node, &list);
> > +		}
> >
> > -	pl330_tasklet((unsigned long) pch);
> > +		list_splice_tail_init(&list, &pdmac->desc_pool);
> 
> Again, would list_splice_tail() do here?
This code is for 'flush' operation that releases all of the pre-loaded
requests.
I uses 'list_splice_tail_init' for it instead of 'pl330_tasklet' that also
calls 'list_splice_tail_init'.

> 
> > +		spin_unlock_irqrestore(&pch->lock, flags);
> > +		break;
> > +	case DMA_SLAVE_CONFIG:
> > +		slave_config = (struct dma_slave_config *)arg;
> > +		peri = pch->chan.private;
> > +
> > +		if (slave_config->direction == DMA_TO_DEVICE) {
> > +			if (slave_config->dst_addr)
> > +				peri->fifo_addr = slave_config->dst_addr;
> > +			if (slave_config->dst_addr_width) {
> > +				i = 0;
> > +				while (slave_config->dst_addr_width != (1 <<
i))
> > +					i++;
> > +				peri->burst_sz = i;
> > +			}
> > +		} else if (slave_config->direction == DMA_FROM_DEVICE) {
> > +			if (slave_config->src_addr)
> > +				peri->fifo_addr = slave_config->src_addr;
> > +			if (slave_config->src_addr_width) {
> > +				i = 0;
> > +				while (slave_config->src_addr_width != (1 <<
i))
> > +					i++;
> > +				peri->burst_sz = i;
> > +			}
> > +		}
> 
> It would make more sense to store the M2P and P2M address/width/burst size
> separately, so you don't have to make DMA_SLAVE_CONFIG calls before every
> transfer.
DMA_SLAVE_CONFIG is called the first time that DMA client driver requests
DMA channel.

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

* [PATCH V2 12/12] ASoC: Samsung: Update DMA interface
  2011-07-13  8:47 ` [PATCH V2 12/12] ASoC: Samsung: Update DMA interface Kukjin Kim
@ 2011-07-13 23:57   ` Mark Brown
  2011-07-16  0:01     ` Kukjin Kim
  0 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2011-07-13 23:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 13, 2011 at 05:47:37PM +0900, Kukjin Kim wrote:

> -static inline bool s3c_dma_has_circular(void)
> +static inline bool dma_has_circular(void)
>  {
>  	return false;
>  }

The namespacing here doesn't look great, this is still a Samsung
specific internal API.

Otherwise this looks good.

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

* [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations
  2011-07-13  8:47 ` [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations Kukjin Kim
@ 2011-07-15  2:53   ` Grant Likely
  2011-07-16  0:39     ` Boojin Kim
  0 siblings, 1 reply; 23+ messages in thread
From: Grant Likely @ 2011-07-15  2:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 13, 2011 at 05:47:30PM +0900, Kukjin Kim wrote:
> From: Boojin Kim <boojin.kim@samsung.com>
> 
> This patch adds common DMA operations which are used for Samsung DMA
> drivers. Currently there are two types of DMA driver for Samsung SoCs.
> The one is S3C-DMA for S3C SoCs and the other is PL330-DMA for S5P SoCs.
> This patch provides funcion pointers for common DMA operations to DMA
> client driver like SPI and Audio. It makes DMA client drivers support
> multi-platform.
> In addition, this common DMA operations implement the shared actions
> that are needed for DMA client driver. For example shared actions are
> filter() function for dma_request_channel() and parameter passing for
> device_prep_slave_sg().
> 
> Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
> ---
>  arch/arm/mach-s3c2410/include/mach/dma.h       |    3 +-
>  arch/arm/plat-samsung/Makefile                 |    6 +-
>  arch/arm/plat-samsung/dma-ops.c                |  131 +++++++++++++++++++++++
>  arch/arm/plat-samsung/include/plat/dma-ops.h   |   47 +++++++++
>  arch/arm/plat-samsung/include/plat/dma-pl330.h |    3 +
>  arch/arm/plat-samsung/include/plat/dma.h       |    2 +-
>  arch/arm/plat-samsung/s3c-dma-ops.c            |  132 ++++++++++++++++++++++++
>  7 files changed, 320 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm/plat-samsung/dma-ops.c
>  create mode 100644 arch/arm/plat-samsung/include/plat/dma-ops.h
>  create mode 100644 arch/arm/plat-samsung/s3c-dma-ops.c
> 
> diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
> index b2b2a5b..71a662d 100644
> --- a/arch/arm/mach-s3c2410/include/mach/dma.h
> +++ b/arch/arm/mach-s3c2410/include/mach/dma.h
> @@ -13,7 +13,6 @@
>  #ifndef __ASM_ARCH_DMA_H
>  #define __ASM_ARCH_DMA_H __FILE__
>  
> -#include <plat/dma.h>
>  #include <linux/sysdev.h>
>  
>  #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
> @@ -51,6 +50,8 @@ enum dma_ch {
>  	DMACH_MAX,		/* the end entry */
>  };
>  
> +#include <plat/dma.h>
> +
>  #define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */
>  
>  /* we have 4 dma channels */
> diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
> index 53eb15b..9ecf2aa 100644
> --- a/arch/arm/plat-samsung/Makefile
> +++ b/arch/arm/plat-samsung/Makefile
> @@ -62,9 +62,11 @@ obj-$(CONFIG_SAMSUNG_DEV_PWM)	+= dev-pwm.o
>  
>  # DMA support
>  
> -obj-$(CONFIG_S3C_DMA)		+= dma.o
> +obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
>  
> -obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o
> +obj-$(CONFIG_DMADEV_PL330)	+= dma-ops.o
> +
> +obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
>  
>  # PM support
>  
> diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
> new file mode 100644
> index 0000000..94a9d33
> --- /dev/null
> +++ b/arch/arm/plat-samsung/dma-ops.c
> @@ -0,0 +1,131 @@
> +/* linux/arch/arm/plat-samsung/dma-ops.c
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Samsung DMA Operations
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/dmaengine.h>
> +#include <linux/amba/pl330.h>
> +
> +#include <mach/dma.h>
> +
> +static bool filter(struct dma_chan *chan, void *param)
> +{
> +	struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private;

Is this code pl330 specific?  If so, 'pl330' should probably be
referenced in the function name.

> +	unsigned dma_ch = (unsigned)param;
> +
> +	if (peri->peri_id != dma_ch)
> +		return false;
> +
> +	return true;
> +}
> +
> +static unsigned dma_request(enum dma_ch dma_ch, struct samsung_dma_info *info)
> +{
> +	struct dma_chan *chan;
> +	dma_cap_mask_t mask;
> +	struct dma_slave_config slave_config;
> +
> +	dma_cap_zero(mask);
> +	dma_cap_set(info->cap, mask);
> +
> +	chan = dma_request_channel(mask, filter, (void *)dma_ch);
> +
> +	if (info->direction == DMA_FROM_DEVICE) {
> +		memset(&slave_config, 0, sizeof(struct dma_slave_config));
> +		slave_config.direction = info->direction;
> +		slave_config.src_addr = info->fifo;
> +		slave_config.src_addr_width = info->width;
> +		dmaengine_slave_config(chan, &slave_config);
> +	} else if (info->direction == DMA_TO_DEVICE) {
> +		memset(&slave_config, 0, sizeof(struct dma_slave_config));
> +		slave_config.direction = info->direction;
> +		slave_config.dst_addr = info->fifo;
> +		slave_config.dst_addr_width = info->width;
> +		dmaengine_slave_config(chan, &slave_config);
> +	}
> +
> +	return (unsigned)chan;
> +}
> +
> +static int dma_release(unsigned ch, struct s3c2410_dma_client *client)
> +{
> +	dma_release_channel((struct dma_chan *)ch);
> +
> +	return 0;
> +}
> +
> +static int dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
> +{
> +	struct scatterlist sg;
> +	struct dma_chan *chan = (struct dma_chan *)ch;
> +	struct dma_async_tx_descriptor *desc;
> +
> +	switch (info->cap) {
> +	case DMA_SLAVE:
> +		sg_init_table(&sg, 1);
> +		sg_dma_len(&sg) = info->len;
> +		sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
> +			    info->len, offset_in_page(info->buf));
> +		sg_dma_address(&sg) = info->buf;
> +
> +		desc = chan->device->device_prep_slave_sg(chan,
> +			&sg, 1, info->direction, DMA_PREP_INTERRUPT);
> +		break;
> +	case DMA_CYCLIC:
> +		desc = chan->device->device_prep_dma_cyclic(chan,
> +			info->buf, info->len, info->period, info->direction);
> +		break;
> +	default:
> +		dev_err(&chan->dev->device, "unsupported format\n");
> +		return -EFAULT;
> +	}
> +
> +	if (!desc) {
> +		dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
> +		return -EFAULT;
> +	}
> +
> +	desc->callback = info->fp;
> +	desc->callback_param = info->fp_param;
> +
> +	dmaengine_submit((struct dma_async_tx_descriptor *)desc);
> +
> +	return 0;
> +}
> +
> +static inline int dma_trigger(unsigned ch)
> +{
> +	dma_async_issue_pending((struct dma_chan *)ch);
> +
> +	return 0;
> +}
> +
> +static inline int dma_flush(unsigned ch)
> +{
> +	return dmaengine_terminate_all((struct dma_chan *)ch);
> +}
> +
> +static struct samsung_dma_ops dmaeng_ops = {
> +	.request	= dma_request,
> +	.release	= dma_release,
> +	.prepare	= dma_prepare,
> +	.trigger	= dma_trigger,
> +	.started	= NULL,
> +	.flush		= dma_flush,
> +	.stop		= dma_flush,
> +};

Even though these function are all local statics, you should use a
samsung prefix to avoid namespace collisions.  So, they should be
named something like: samsung_dmaeng_ops, samsung_dmaeng_request(),
samsung_dmaeng_release(), etc.  The ops structure and the functions
should have the same prefix.

> +
> +void *samsung_dma_get_ops(void)
> +{
> +	return (void *)&dmaeng_ops;
> +}
> +EXPORT_SYMBOL(samsung_dma_get_ops);

If all that is needed is a reference to the dma ops, then you could
simply export samsung_dmaeng_ops() without a separate function.

> diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
> new file mode 100644
> index 0000000..eea4130
> --- /dev/null
> +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
> @@ -0,0 +1,47 @@
> +/* arch/arm/plat-samsung/include/plat/dma-ops.h
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Samsung DMA support
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/dmaengine.h>
> +
> +struct samsung_dma_prep_info {
> +	enum dma_transaction_type cap;
> +	enum dma_data_direction direction;
> +	unsigned buf;
> +	unsigned long period;
> +	unsigned long len;
> +	void (*fp)(void *data);
> +	void *fp_param;
> +};
> +
> +struct samsung_dma_info {
> +	enum dma_transaction_type cap;
> +	enum dma_data_direction direction;
> +	enum dma_slave_buswidth width;
> +	unsigned fifo;
> +	struct s3c2410_dma_client *client;
> +};
> +
> +struct samsung_dma_ops {
> +	unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
> +	int (*release)(unsigned ch, struct s3c2410_dma_client *client);
> +	int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
> +	int (*trigger)(unsigned ch);
> +	int (*started)(unsigned ch);
> +	int (*flush)(unsigned ch);
> +	int (*stop)(unsigned ch);
> +};
> +
> +/*
> + * samsung_dma_get_ops
> + * get the set of dma operations
> + */
> +extern void *samsung_dma_get_ops(void);
> diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
> index c402719..be84bec 100644
> --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
> +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
> @@ -1,4 +1,7 @@
>  /*
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
>   * Copyright (C) 2010 Samsung Electronics Co. Ltd.
>   *	Jaswinder Singh <jassi.brar@samsung.com>
>   *


Heh, this patch doesn't make any changes to this file, and samsung
already has a copyright notice on it anyway.  You should probably drop
this hunk.

> diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-samsung/include/plat/dma.h
> index 2e8f8c6..90da162 100644
> --- a/arch/arm/plat-samsung/include/plat/dma.h
> +++ b/arch/arm/plat-samsung/include/plat/dma.h
> @@ -124,4 +124,4 @@ extern int s3c2410_dma_getposition(unsigned int channel,
>  extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
>  extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
>  
> -

nitpick: Unrelated whitespace change.  One blank line of whitespace is
sufficient anyway.

> +#include <plat/dma-ops.h>
> diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
> new file mode 100644
> index 0000000..17b1be0
> --- /dev/null
> +++ b/arch/arm/plat-samsung/s3c-dma-ops.c
> @@ -0,0 +1,132 @@
> +/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Samsung S3C-DMA Operations
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <mach/dma.h>
> +
> +struct cb_data {

struct s3c2410_cb_data {

> +	void (*fp) (void *);
> +	void *fp_param;
> +	unsigned ch;
> +	struct list_head node;
> +};
> +
> +static LIST_HEAD(dma_list);
> +
> +static void dma_cb(struct s3c2410_dma_chan *channel,
> +		   void *param, int size, enum s3c2410_dma_buffresult res)
> +{
> +	struct cb_data *data = (struct cb_data *)param;

param is a void*.  The (struct cb_data*) cast is not needed.

> +
> +	data->fp(data->fp_param);
> +}
> +
> +static unsigned dma_request(enum dma_ch dma_ch, struct samsung_dma_info *info)

These functions should *definitely* be named differently from the
dma_* ops in the other file so that you can differentiate between
them, and to make them grep-friendly.  This goes for *all* file-scope
symbols.

> +{
> +	struct cb_data *data;
> +
> +	if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
> +		s3c2410_dma_free(dma_ch, info->client);
> +		return 0;
> +	}
> +
> +	data = kmalloc(sizeof(struct cb_data), GFP_KERNEL);

kzalloc()

> +	data->fp = NULL;

Drop this line after converting to kzalloc()

> +	data->ch = (unsigned)dma_ch;

Is the cast necessary?

> +	list_add_tail(&data->node, &dma_list);
> +
> +	if (info->direction == DMA_FROM_DEVICE)
> +		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, info->fifo);
> +	else
> +		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info->fifo);

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

* [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
  2011-07-13  8:47 ` [PATCH V2 03/12] DMA: PL330: Add DMA capabilities Kukjin Kim
  2011-07-13  9:14   ` Russell King - ARM Linux
@ 2011-07-15  4:45   ` Chanho Park
  2011-07-16  1:11     ` Boojin Kim
  1 sibling, 1 reply; 23+ messages in thread
From: Chanho Park @ 2011-07-15  4:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

2011/7/13 Kukjin Kim <kgene.kim@samsung.com>:
> From: Boojin Kim <boojin.kim@samsung.com>
>
> This patch adds DMA_CYCLIC capability that is used for audio driver
> and SLAVE_CONFIG capability for transmit between device and memory.
>
> Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
> Cc: Vinod Koul <vinod.koul@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
> ---
> ?drivers/dma/pl330.c | ?187 +++++++++++++++++++++++++++++++++++++++++++++++----
> ?1 files changed, 173 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 9bdda7b..2162ac5 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -69,6 +69,9 @@ struct dma_pl330_chan {
> ? ? ? ? * NULL if the channel is available to be acquired.
> ? ? ? ? */
> ? ? ? ?void *pl330_chid;
> +
> + ? ? ? /* taks for cyclic capability */
> + ? ? ? struct tasklet_struct *cyclic_task;
> ?};
>
> ?struct dma_pl330_dmac {
> @@ -105,6 +108,7 @@ struct dma_pl330_desc {
>
> ? ? ? ?/* The channel which currently holds this desc */
> ? ? ? ?struct dma_pl330_chan *pchan;
> + ? ? ? bool cyclic;
> ?};
>
> ?static inline struct dma_pl330_chan *
> @@ -184,6 +188,60 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
> ? ? ? ?}
> ?}
>
> +static void pl330_tasklet_cyclic(unsigned long data)
> +{
> + ? ? ? struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> + ? ? ? struct dma_pl330_desc *desc, *_dt;
> + ? ? ? unsigned long flags;
> + ? ? ? LIST_HEAD(list);
> +
> + ? ? ? spin_lock_irqsave(&pch->lock, flags);
> +
> + ? ? ? /* Pick up ripe tomatoes */
> + ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> + ? ? ? ? ? ? ? if ((desc->status == DONE) && desc->cyclic) {
> + ? ? ? ? ? ? ? ? ? ? ? dma_async_tx_callback callback;
> +
> + ? ? ? ? ? ? ? ? ? ? ? list_move_tail(&desc->node, &pch->work_list);
> + ? ? ? ? ? ? ? ? ? ? ? pch->completed = desc->txd.cookie;
> +
> + ? ? ? ? ? ? ? ? ? ? ? desc->status = PREP;
> +
> + ? ? ? ? ? ? ? ? ? ? ? /* Try to submit a req imm.
> + ? ? ? ? ? ? ? ? ? ? ? next to the last completed cookie */
> + ? ? ? ? ? ? ? ? ? ? ? fill_queue(pch);
> +
> + ? ? ? ? ? ? ? ? ? ? ? /* Make sure the PL330 Channel thread is active */
> + ? ? ? ? ? ? ? ? ? ? ? pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
> +
> + ? ? ? ? ? ? ? ? ? ? ? callback = desc->txd.callback;
> + ? ? ? ? ? ? ? ? ? ? ? if (callback)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? callback(desc->txd.callback_param);
> +
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
> +}
> +
> +static void pl330_cyclic_free(struct dma_pl330_chan *pch)
> +{
> + ? ? ? struct dma_pl330_dmac *pdmac = pch->dmac;
> + ? ? ? struct dma_pl330_desc *desc, *_dt;
> + ? ? ? unsigned long flags;
> + ? ? ? LIST_HEAD(list);
> +
> + ? ? ? spin_lock_irqsave(&pdmac->pool_lock, flags);
> +
> + ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> + ? ? ? if (desc->cyclic)
> + ? ? ? ? ? ? ? list_move_tail(&desc->node, &list);

nitpick: indentation will be required after for_each

> +
> + ? ? ? list_splice_tail_init(&list, &pdmac->desc_pool);
> +
> + ? ? ? spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> + ? ? ? pch->cyclic_task = NULL;
> +}
> +
> ?static void pl330_tasklet(unsigned long data)
> ?{
> ? ? ? ?struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> @@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
>
> ? ? ? ?spin_unlock_irqrestore(&pch->lock, flags);
>
> + ? ? ? if (pch->cyclic_task)
> + ? ? ? ? ? ? ? tasklet_schedule(pch->cyclic_task);
> + ? ? ? else
> ? ? ? ?tasklet_schedule(&pch->task);
> ?}
>
> @@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
> ?static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
> ?{
> ? ? ? ?struct dma_pl330_chan *pch = to_pchan(chan);
> - ? ? ? struct dma_pl330_desc *desc;
> + ? ? ? struct dma_pl330_desc *desc, *_dt;
> ? ? ? ?unsigned long flags;
> + ? ? ? struct dma_pl330_dmac *pdmac = pch->dmac;
> + ? ? ? struct dma_slave_config *slave_config;
> + ? ? ? struct dma_pl330_peri *peri;
> + ? ? ? int i;
> + ? ? ? LIST_HEAD(list);
>
> - ? ? ? /* Only supports DMA_TERMINATE_ALL */
> - ? ? ? if (cmd != DMA_TERMINATE_ALL)
> - ? ? ? ? ? ? ? return -ENXIO;
> -
> - ? ? ? spin_lock_irqsave(&pch->lock, flags);
> -
> - ? ? ? /* FLUSH the PL330 Channel thread */
> - ? ? ? pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> + ? ? ? switch (cmd) {
> + ? ? ? case DMA_TERMINATE_ALL:
> + ? ? ? ? ? ? ? spin_lock_irqsave(&pch->lock, flags);
>
> - ? ? ? /* Mark all desc done */
> - ? ? ? list_for_each_entry(desc, &pch->work_list, node)
> - ? ? ? ? ? ? ? desc->status = DONE;
> + ? ? ? ? ? ? ? /* FLUSH the PL330 Channel thread */
> + ? ? ? ? ? ? ? pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
>
> - ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
> + ? ? ? ? ? ? ? /* Mark all desc done */
> + ? ? ? ? ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
> + ? ? ? ? ? ? ? ? ? ? ? desc->status = DONE;
> + ? ? ? ? ? ? ? ? ? ? ? pch->completed = desc->txd.cookie;
> + ? ? ? ? ? ? ? ? ? ? ? list_move_tail(&desc->node, &list);
> + ? ? ? ? ? ? ? }
>
> - ? ? ? pl330_tasklet((unsigned long) pch);
> + ? ? ? ? ? ? ? list_splice_tail_init(&list, &pdmac->desc_pool);
> + ? ? ? ? ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
> + ? ? ? ? ? ? ? break;
> + ? ? ? case DMA_SLAVE_CONFIG:
> + ? ? ? ? ? ? ? slave_config = (struct dma_slave_config *)arg;
> + ? ? ? ? ? ? ? peri = pch->chan.private;
> +
> + ? ? ? ? ? ? ? if (slave_config->direction == DMA_TO_DEVICE) {
> + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->dst_addr)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->fifo_addr = slave_config->dst_addr;
> + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->dst_addr_width) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i = 0;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? while (slave_config->dst_addr_width != (1 << i))
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i++;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->burst_sz = i;
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? } else if (slave_config->direction == DMA_FROM_DEVICE) {
> + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->src_addr)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->fifo_addr = slave_config->src_addr;
> + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->src_addr_width) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i = 0;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? while (slave_config->src_addr_width != (1 << i))
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i++;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->burst_sz = i;
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? break;
> + ? ? ? default:
> + ? ? ? ? ? ? ? return -ENXIO;

To print error message in the default case will be better.

> + ? ? ? }
>
> ? ? ? ?return 0;
> ?}
> @@ -291,6 +385,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
> ? ? ? ?pl330_release_channel(pch->pl330_chid);
> ? ? ? ?pch->pl330_chid = NULL;
>
> + ? ? ? if (pch->cyclic_task)
> + ? ? ? ? ? ? ? pl330_cyclic_free(pch);
> +
> ? ? ? ?spin_unlock_irqrestore(&pch->lock, flags);
> ?}
>
> @@ -522,6 +619,66 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
> ? ? ? ?return burst_len;
> ?}
>
> +static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
> + ? ? ? ? ? ? ? struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
> + ? ? ? ? ? ? ? size_t period_len, enum dma_data_direction direction)
> +{
> + ? ? ? struct dma_pl330_desc *desc;
> + ? ? ? struct dma_pl330_chan *pch = to_pchan(chan);
> + ? ? ? struct dma_pl330_peri *peri = chan->private;
> + ? ? ? dma_addr_t dst;
> + ? ? ? dma_addr_t src;
> +
> + ? ? ? pch = to_pchan(chan);
> + ? ? ? if (!pch) {
> + ? ? ? ? ? ? ? dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
> + ? ? ? ? ? ? ? ? ? ? ? __func__, __LINE__);
> + ? ? ? ? ? ? ? return NULL;
> + ? ? ? }

'pch' is already acquired when defined. It's duplicated.
dev_err has a incorrect parameter because pch is NULL.
Accessing pch->dmac will be failed.

> +
> + ? ? ? desc = pl330_get_desc(pch);
> + ? ? ? if (!desc) {
> + ? ? ? ? ? ? ? dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
> + ? ? ? ? ? ? ? ? ? ? ? __func__, __LINE__);
> + ? ? ? ? ? ? ? return NULL;
> + ? ? ? }
> +
> + ? ? ? switch (direction) {
> + ? ? ? case DMA_TO_DEVICE:
> + ? ? ? ? ? ? ? desc->rqcfg.src_inc = 1;
> + ? ? ? ? ? ? ? desc->rqcfg.dst_inc = 0;
> + ? ? ? ? ? ? ? src = dma_addr;
> + ? ? ? ? ? ? ? dst = peri->fifo_addr;
> + ? ? ? ? ? ? ? break;
> + ? ? ? case DMA_FROM_DEVICE:
> + ? ? ? ? ? ? ? desc->rqcfg.src_inc = 0;
> + ? ? ? ? ? ? ? desc->rqcfg.dst_inc = 1;
> + ? ? ? ? ? ? ? src = peri->fifo_addr;
> + ? ? ? ? ? ? ? dst = dma_addr;
> + ? ? ? ? ? ? ? break;
> + ? ? ? default:
> + ? ? ? ? ? ? ? dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
> + ? ? ? ? ? ? ? __func__, __LINE__);
> + ? ? ? ? ? ? ? return NULL;
> + ? ? ? }
> +
> + ? ? ? desc->rqcfg.brst_size = peri->burst_sz;
> + ? ? ? desc->rqcfg.brst_len = 1;
> +
> + ? ? ? if (!pch->cyclic_task) {
> + ? ? ? ? ? ? ? pch->cyclic_task =
> + ? ? ? ? ? ? ? ? ? ? ? kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
> + ? ? ? ? ? ? ? tasklet_init(pch->cyclic_task,
> + ? ? ? ? ? ? ? ? ? ? ? pl330_tasklet_cyclic, (unsigned int)pch);
> + ? ? ? }
> +
> + ? ? ? desc->cyclic = true;
> +
> + ? ? ? fill_px(&desc->px, dst, src, period_len);
> +
> + ? ? ? return &desc->txd;
> +}
> +
> ?static struct dma_async_tx_descriptor *
> ?pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
> ? ? ? ? ? ? ? ?dma_addr_t src, size_t len, unsigned long flags)
> @@ -756,6 +913,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
> ? ? ? ? ? ? ? ? ? ? ? ?case MEMTODEV:
> ? ? ? ? ? ? ? ? ? ? ? ?case DEVTOMEM:
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?dma_cap_set(DMA_SLAVE, pd->cap_mask);
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dma_cap_set(DMA_CYCLIC, pd->cap_mask);
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?break;
> ? ? ? ? ? ? ? ? ? ? ? ?default:
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?dev_err(&adev->dev, "DEVTODEV Not Supported\n");
> @@ -781,6 +939,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
> ? ? ? ?pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
> ? ? ? ?pd->device_free_chan_resources = pl330_free_chan_resources;
> ? ? ? ?pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
> + ? ? ? pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
> ? ? ? ?pd->device_tx_status = pl330_tx_status;
> ? ? ? ?pd->device_prep_slave_sg = pl330_prep_slave_sg;
> ? ? ? ?pd->device_control = pl330_control;
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>



-- 
Best Regards,
Chanho Park

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

* [PATCH V2 12/12] ASoC: Samsung: Update DMA interface
  2011-07-13 23:57   ` Mark Brown
@ 2011-07-16  0:01     ` Kukjin Kim
  0 siblings, 0 replies; 23+ messages in thread
From: Kukjin Kim @ 2011-07-16  0:01 UTC (permalink / raw)
  To: linux-arm-kernel

Mark Brown wrote:
> 
> On Wed, Jul 13, 2011 at 05:47:37PM +0900, Kukjin Kim wrote:
> 
> > -static inline bool s3c_dma_has_circular(void)
> > +static inline bool dma_has_circular(void)
> >  {
> >  	return false;
> >  }
> 
> The namespacing here doesn't look great, this is still a Samsung
> specific internal API.
> 

OK, will keep it.

> Otherwise this looks good.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

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

* [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations
  2011-07-15  2:53   ` Grant Likely
@ 2011-07-16  0:39     ` Boojin Kim
  2011-07-16  0:50       ` Grant Likely
  0 siblings, 1 reply; 23+ messages in thread
From: Boojin Kim @ 2011-07-16  0:39 UTC (permalink / raw)
  To: linux-arm-kernel

Grant Likely wrote:

> On Wed, Jul 13, 2011 at 05:47:30PM +0900, Kukjin Kim wrote:
> > From: Boojin Kim <boojin.kim@samsung.com>
> >
> > This patch adds common DMA operations which are used for Samsung DMA
> > drivers. Currently there are two types of DMA driver for Samsung SoCs.
> > The one is S3C-DMA for S3C SoCs and the other is PL330-DMA for S5P SoCs.
> > This patch provides funcion pointers for common DMA operations to DMA
> > client driver like SPI and Audio. It makes DMA client drivers support
> > multi-platform.
> > In addition, this common DMA operations implement the shared actions
> > that are needed for DMA client driver. For example shared actions are
> > filter() function for dma_request_channel() and parameter passing for
> > device_prep_slave_sg().
> >
> > Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
> > Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
> > ---
> >  arch/arm/mach-s3c2410/include/mach/dma.h       |    3 +-
> >  arch/arm/plat-samsung/Makefile                 |    6 +-
> >  arch/arm/plat-samsung/dma-ops.c                |  131
> +++++++++++++++++++++++
> >  arch/arm/plat-samsung/include/plat/dma-ops.h   |   47 +++++++++
> >  arch/arm/plat-samsung/include/plat/dma-pl330.h |    3 +
> >  arch/arm/plat-samsung/include/plat/dma.h       |    2 +-
> >  arch/arm/plat-samsung/s3c-dma-ops.c            |  132
> ++++++++++++++++++++++++
> >  7 files changed, 320 insertions(+), 4 deletions(-)
> >  create mode 100644 arch/arm/plat-samsung/dma-ops.c
> >  create mode 100644 arch/arm/plat-samsung/include/plat/dma-ops.h
> >  create mode 100644 arch/arm/plat-samsung/s3c-dma-ops.c
> >
> > diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-
> s3c2410/include/mach/dma.h
> > index b2b2a5b..71a662d 100644
> > --- a/arch/arm/mach-s3c2410/include/mach/dma.h
> > +++ b/arch/arm/mach-s3c2410/include/mach/dma.h
> > @@ -13,7 +13,6 @@
> >  #ifndef __ASM_ARCH_DMA_H
> >  #define __ASM_ARCH_DMA_H __FILE__
> >
> > -#include <plat/dma.h>
> >  #include <linux/sysdev.h>
> >
> >  #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
> > @@ -51,6 +50,8 @@ enum dma_ch {
> >  	DMACH_MAX,		/* the end entry */
> >  };
> >
> > +#include <plat/dma.h>
> > +
> >  #define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware
> ch no */
> >
> >  /* we have 4 dma channels */
> > diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-
> samsung/Makefile
> > index 53eb15b..9ecf2aa 100644
> > --- a/arch/arm/plat-samsung/Makefile
> > +++ b/arch/arm/plat-samsung/Makefile
> > @@ -62,9 +62,11 @@ obj-$(CONFIG_SAMSUNG_DEV_PWM)	+= dev-pwm.o
> >
> >  # DMA support
> >
> > -obj-$(CONFIG_S3C_DMA)		+= dma.o
> > +obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
> >
> > -obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o
> > +obj-$(CONFIG_DMADEV_PL330)	+= dma-ops.o
> > +
> > +obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
> >
> >  # PM support
> >
> > diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-
> samsung/dma-ops.c
> > new file mode 100644
> > index 0000000..94a9d33
> > --- /dev/null
> > +++ b/arch/arm/plat-samsung/dma-ops.c
> > @@ -0,0 +1,131 @@
> > +/* linux/arch/arm/plat-samsung/dma-ops.c
> > + *
> > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > + *		http://www.samsung.com
> > + *
> > + * Samsung DMA Operations
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > +*/
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/dmaengine.h>
> > +#include <linux/amba/pl330.h>
> > +
> > +#include <mach/dma.h>
> > +
> > +static bool filter(struct dma_chan *chan, void *param)
> > +{
> > +	struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan-
> >private;
> 
> Is this code pl330 specific?  If so, 'pl330' should probably be
> referenced in the function name.

I will address your comment.

> 
> > +	unsigned dma_ch = (unsigned)param;
> > +
> > +	if (peri->peri_id != dma_ch)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> > +static unsigned dma_request(enum dma_ch dma_ch, struct samsung_dma_info
> *info)
> > +{
> > +	struct dma_chan *chan;
> > +	dma_cap_mask_t mask;
> > +	struct dma_slave_config slave_config;
> > +
> > +	dma_cap_zero(mask);
> > +	dma_cap_set(info->cap, mask);
> > +
> > +	chan = dma_request_channel(mask, filter, (void *)dma_ch);
> > +
> > +	if (info->direction == DMA_FROM_DEVICE) {
> > +		memset(&slave_config, 0, sizeof(struct dma_slave_config));
> > +		slave_config.direction = info->direction;
> > +		slave_config.src_addr = info->fifo;
> > +		slave_config.src_addr_width = info->width;
> > +		dmaengine_slave_config(chan, &slave_config);
> > +	} else if (info->direction == DMA_TO_DEVICE) {
> > +		memset(&slave_config, 0, sizeof(struct dma_slave_config));
> > +		slave_config.direction = info->direction;
> > +		slave_config.dst_addr = info->fifo;
> > +		slave_config.dst_addr_width = info->width;
> > +		dmaengine_slave_config(chan, &slave_config);
> > +	}
> > +
> > +	return (unsigned)chan;
> > +}
> > +
> > +static int dma_release(unsigned ch, struct s3c2410_dma_client *client)
> > +{
> > +	dma_release_channel((struct dma_chan *)ch);
> > +
> > +	return 0;
> > +}
> > +
> > +static int dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
> > +{
> > +	struct scatterlist sg;
> > +	struct dma_chan *chan = (struct dma_chan *)ch;
> > +	struct dma_async_tx_descriptor *desc;
> > +
> > +	switch (info->cap) {
> > +	case DMA_SLAVE:
> > +		sg_init_table(&sg, 1);
> > +		sg_dma_len(&sg) = info->len;
> > +		sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
> > +			    info->len, offset_in_page(info->buf));
> > +		sg_dma_address(&sg) = info->buf;
> > +
> > +		desc = chan->device->device_prep_slave_sg(chan,
> > +			&sg, 1, info->direction, DMA_PREP_INTERRUPT);
> > +		break;
> > +	case DMA_CYCLIC:
> > +		desc = chan->device->device_prep_dma_cyclic(chan,
> > +			info->buf, info->len, info->period,
info->direction);
> > +		break;
> > +	default:
> > +		dev_err(&chan->dev->device, "unsupported format\n");
> > +		return -EFAULT;
> > +	}
> > +
> > +	if (!desc) {
> > +		dev_err(&chan->dev->device, "cannot prepare cyclic dma\n");
> > +		return -EFAULT;
> > +	}
> > +
> > +	desc->callback = info->fp;
> > +	desc->callback_param = info->fp_param;
> > +
> > +	dmaengine_submit((struct dma_async_tx_descriptor *)desc);
> > +
> > +	return 0;
> > +}
> > +
> > +static inline int dma_trigger(unsigned ch)
> > +{
> > +	dma_async_issue_pending((struct dma_chan *)ch);
> > +
> > +	return 0;
> > +}
> > +
> > +static inline int dma_flush(unsigned ch)
> > +{
> > +	return dmaengine_terminate_all((struct dma_chan *)ch);
> > +}
> > +
> > +static struct samsung_dma_ops dmaeng_ops = {
> > +	.request	= dma_request,
> > +	.release	= dma_release,
> > +	.prepare	= dma_prepare,
> > +	.trigger	= dma_trigger,
> > +	.started	= NULL,
> > +	.flush		= dma_flush,
> > +	.stop		= dma_flush,
> > +};
> 
> Even though these function are all local statics, you should use a
> samsung prefix to avoid namespace collisions.  So, they should be
> named something like: samsung_dmaeng_ops, samsung_dmaeng_request(),
> samsung_dmaeng_release(), etc.  The ops structure and the functions
> should have the same prefix.

I will address your comment.

> 
> > +
> > +void *samsung_dma_get_ops(void)
> > +{
> > +	return (void *)&dmaeng_ops;
> > +}
> > +EXPORT_SYMBOL(samsung_dma_get_ops);
> 
> If all that is needed is a reference to the dma ops, then you could
> simply export samsung_dmaeng_ops() without a separate function.

Grant, Thanks for your comments. I can't understand this comment well.
Do you mean to change function name from 'samsung_dma_get_ops()' to
'samsung_dmaeng_ops()' ?
Or export 'dmaeng_ops' variable instead of making this
'samsung_dma_get_ops()' function

> 
> > diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h
> b/arch/arm/plat-samsung/include/plat/dma-ops.h
> > new file mode 100644
> > index 0000000..eea4130
> > --- /dev/null
> > +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
> > @@ -0,0 +1,47 @@
> > +/* arch/arm/plat-samsung/include/plat/dma-ops.h
> > + *
> > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > + *		http://www.samsung.com
> > + *
> > + * Samsung DMA support
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > +*/
> > +
> > +#include <linux/dmaengine.h>
> > +
> > +struct samsung_dma_prep_info {
> > +	enum dma_transaction_type cap;
> > +	enum dma_data_direction direction;
> > +	unsigned buf;
> > +	unsigned long period;
> > +	unsigned long len;
> > +	void (*fp)(void *data);
> > +	void *fp_param;
> > +};
> > +
> > +struct samsung_dma_info {
> > +	enum dma_transaction_type cap;
> > +	enum dma_data_direction direction;
> > +	enum dma_slave_buswidth width;
> > +	unsigned fifo;
> > +	struct s3c2410_dma_client *client;
> > +};
> > +
> > +struct samsung_dma_ops {
> > +	unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
> > +	int (*release)(unsigned ch, struct s3c2410_dma_client *client);
> > +	int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
> > +	int (*trigger)(unsigned ch);
> > +	int (*started)(unsigned ch);
> > +	int (*flush)(unsigned ch);
> > +	int (*stop)(unsigned ch);
> > +};
> > +
> > +/*
> > + * samsung_dma_get_ops
> > + * get the set of dma operations
> > + */
> > +extern void *samsung_dma_get_ops(void);
> > diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h
> b/arch/arm/plat-samsung/include/plat/dma-pl330.h
> > index c402719..be84bec 100644
> > --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
> > +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
> > @@ -1,4 +1,7 @@
> >  /*
> > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > + *		http://www.samsung.com
> > + *
> >   * Copyright (C) 2010 Samsung Electronics Co. Ltd.
> >   *	Jaswinder Singh <jassi.brar@samsung.com>
> >   *
> 
> 
> Heh, this patch doesn't make any changes to this file, and samsung
> already has a copyright notice on it anyway.  You should probably drop
> this hunk.

I will address your comment.

> 
> > diff --git a/arch/arm/plat-samsung/include/plat/dma.h b/arch/arm/plat-
> samsung/include/plat/dma.h
> > index 2e8f8c6..90da162 100644
> > --- a/arch/arm/plat-samsung/include/plat/dma.h
> > +++ b/arch/arm/plat-samsung/include/plat/dma.h
> > @@ -124,4 +124,4 @@ extern int s3c2410_dma_getposition(unsigned int
> channel,
> >  extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
> >  extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t
> rtn);
> >
> > -
> 
> nitpick: Unrelated whitespace change.  One blank line of whitespace is
> sufficient anyway.
 
I will address your comment.

> > +#include <plat/dma-ops.h>
> > diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-
> samsung/s3c-dma-ops.c
> > new file mode 100644
> > index 0000000..17b1be0
> > --- /dev/null
> > +++ b/arch/arm/plat-samsung/s3c-dma-ops.c
> > @@ -0,0 +1,132 @@
> > +/* linux/arch/arm/plat-samsung/s3c-dma-ops.c
> > + *
> > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > + *		http://www.samsung.com
> > + *
> > + * Samsung S3C-DMA Operations
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > +*/
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/slab.h>
> > +#include <linux/types.h>
> > +
> > +#include <mach/dma.h>
> > +
> > +struct cb_data {
> 
> struct s3c2410_cb_data {
> 
> > +	void (*fp) (void *);
> > +	void *fp_param;
> > +	unsigned ch;
> > +	struct list_head node;
> > +};
> > +
> > +static LIST_HEAD(dma_list);
> > +
> > +static void dma_cb(struct s3c2410_dma_chan *channel,
> > +		   void *param, int size, enum s3c2410_dma_buffresult res)
> > +{
> > +	struct cb_data *data = (struct cb_data *)param;
> 
> param is a void*.  The (struct cb_data*) cast is not needed.
> 
> > +
> > +	data->fp(data->fp_param);
> > +}
> > +
> > +static unsigned dma_request(enum dma_ch dma_ch, struct samsung_dma_info
> *info)
> 
> These functions should *definitely* be named differently from the
> dma_* ops in the other file so that you can differentiate between
> them, and to make them grep-friendly.  This goes for *all* file-scope
> symbols.

I will address your comment.

> 
> > +{
> > +	struct cb_data *data;
> > +
> > +	if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
> > +		s3c2410_dma_free(dma_ch, info->client);
> > +		return 0;
> > +	}
> > +
> > +	data = kmalloc(sizeof(struct cb_data), GFP_KERNEL);
> 
> kzalloc()
> 
> > +	data->fp = NULL;
> 
> Drop this line after converting to kzalloc()

I will address your comment.

> 
> > +	data->ch = (unsigned)dma_ch;
> 
> Is the cast necessary?
> 
> > +	list_add_tail(&data->node, &dma_list);
> > +
> > +	if (info->direction == DMA_FROM_DEVICE)
> > +		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW,
info->fifo);
> > +	else
> > +		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info-
> >fifo);
> 
> From arch/arm/plat-samsung/include/plat/dma.h:
> 	enum s3c2410_dmasrc {
> 		S3C2410_DMASRC_HW,	/* source is memory */
> 		S3C2410_DMASRC_MEM	/* source is hardware */
> 	};
> 
> from dma-mapping.h:
> 	enum dma_data_direction {
> 		DMA_BIDIRECTIONAL = 0,
> 		DMA_TO_DEVICE = 1,
> 		DMA_FROM_DEVICE = 2,
> 		DMA_NONE = 3,
> 	};
> 
> /me thinks it would all look nicer if s3c2410 dma just replaced
> s3c2410_dmasrc to dma_data_direction, and from what I can tell it
> would just be a simple search and replace.  :-)
> 

I will address your comment.

> > +
> > +	if (info->cap == DMA_CYCLIC)
> > +		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
> > +
> > +	s3c2410_dma_config(dma_ch, info->width);
> > +
> > +	return (unsigned)dma_ch;
> > +}
> > +
> > +static int dma_release(unsigned ch, struct s3c2410_dma_client *client)
> 
> unsigned int
> 
> > +{
> > +	struct cb_data *data;
> > +
> > +	list_for_each_entry(data, &dma_list, node)
> > +	    if (data->ch == ch)
> > +		break;
> 
> nit: incorrect indentation.  Use tab characters instead of spaces.
> I've got "set list" and "set listchars=tab:\|-,trail:-" in my ~/.vimrc
> so I can see the difference between tabs and spaces.
> 


I will address your comment.

> > +	list_del(&data->node);
> 
> What happens if the channel isn't found in the list?  Can that
> situation happen?
> 
> What happens if two drivers call dma_release simultaneously?  It
> looks like a mutex is needed to protext the dma_list.
> 
> > +
> > +	s3c2410_dma_free((enum dma_ch)ch, client);
> 
> All the casting in this patch makes me nervous.  When a lot of casting
> is required, I wonder if the API needs to be changed.

I will remove casting to "enum dma_ch"

> 
> > +	kfree(data);
> > +
> > +	return 0;
> > +}
> > +
> > +static int dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
> > +{
> > +	struct cb_data *data;
> > +
> > +	list_for_each_entry(data, &dma_list, node)
> > +	    if (data->ch == ch)
> > +		break;
> > +
> > +	if (!data->fp) {
> > +		s3c2410_dma_set_buffdone_fn((enum dma_ch)ch, dma_cb);
> > +		data->fp = info->fp;
> > +		data->fp_param = info->fp_param;
> > +	}
> > +	s3c2410_dma_enqueue((enum dma_ch)ch, (void *)data, info->buf,
> > +			    info->period);
> > +
> > +	return 0;
> > +}
> > +
> > +static inline int dma_trigger(unsigned ch)
> > +{
> > +	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
> > +}
> > +
> > +static inline int dma_started(unsigned ch)
> > +{
> > +	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
> > +}
> > +
> > +static inline int dma_flush(unsigned ch)
> > +{
> > +	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
> > +}
> > +
> > +static inline int dma_stop(unsigned ch)
> > +{
> > +	return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
> > +}
> > +
> > +static struct samsung_dma_ops s3c_dma_ops = {
> > +	.request	= dma_request,
> > +	.release	= dma_release,
> > +	.prepare	= dma_prepare,
> > +	.trigger	= dma_trigger,
> > +	.started	= dma_started,
> > +	.flush		= dma_flush,
> > +	.stop		= dma_stop,
> > +};
> > +
> > +void *samsung_dma_get_ops(void)
> > +{
> > +	return (void *)&s3c_dma_ops;
> > +}
> > +EXPORT_SYMBOL(samsung_dma_get_ops);
> 
> This is a problem.  This patch adds two implementations of
> samsung_dma_get_ops(). New code needs to be multiplatform friendly.
> That means that the code nees to handle both dma-ops.c and
> s3c-dma-ops.c compiled into the kernel at the same time and select the
> correct one at runtime.
> 


I will address your comment.

> g.
> 
> > --
> > 1.7.1
> >

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

* [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations
  2011-07-16  0:39     ` Boojin Kim
@ 2011-07-16  0:50       ` Grant Likely
  0 siblings, 0 replies; 23+ messages in thread
From: Grant Likely @ 2011-07-16  0:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jul 16, 2011 at 09:39:31AM +0900, Boojin Kim wrote:
> Grant Likely wrote:
> > > +void *samsung_dma_get_ops(void)
> > > +{
> > > +	return (void *)&dmaeng_ops;
> > > +}
> > > +EXPORT_SYMBOL(samsung_dma_get_ops);
> > 
> > If all that is needed is a reference to the dma ops, then you could
> > simply export samsung_dmaeng_ops() without a separate function.
> 
> Grant, Thanks for your comments. I can't understand this comment well.
> Do you mean to change function name from 'samsung_dma_get_ops()' to
> 'samsung_dmaeng_ops()' ?
> Or export 'dmaeng_ops' variable instead of making this
> 'samsung_dma_get_ops()' function

I mean export dmaeng_ops instead of using a function.  You also get
some type checking by not casting it into a (void*).

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

* [PATCH V2 03/12] DMA: PL330: Add DMA capabilities
  2011-07-15  4:45   ` Chanho Park
@ 2011-07-16  1:11     ` Boojin Kim
  0 siblings, 0 replies; 23+ messages in thread
From: Boojin Kim @ 2011-07-16  1:11 UTC (permalink / raw)
  To: linux-arm-kernel



Chanho Park wrote:

> 2011/7/13 Kukjin Kim <kgene.kim@samsung.com>:
> > From: Boojin Kim <boojin.kim@samsung.com>
> >
> > This patch adds DMA_CYCLIC capability that is used for audio driver
> > and SLAVE_CONFIG capability for transmit between device and memory.
> >
> > Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
> > Cc: Vinod Koul <vinod.koul@intel.com>
> > Cc: Dan Williams <dan.j.williams@intel.com>
> > Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
> > ---
> > ?drivers/dma/pl330.c | ?187
> +++++++++++++++++++++++++++++++++++++++++++++++----
> > ?1 files changed, 173 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> > index 9bdda7b..2162ac5 100644
> > --- a/drivers/dma/pl330.c
> > +++ b/drivers/dma/pl330.c
> > @@ -69,6 +69,9 @@ struct dma_pl330_chan {
> > ? ? ? ? * NULL if the channel is available to be acquired.
> > ? ? ? ? */
> > ? ? ? ?void *pl330_chid;
> > +
> > + ? ? ? /* taks for cyclic capability */
> > + ? ? ? struct tasklet_struct *cyclic_task;
> > ?};
> >
> > ?struct dma_pl330_dmac {
> > @@ -105,6 +108,7 @@ struct dma_pl330_desc {
> >
> > ? ? ? ?/* The channel which currently holds this desc */
> > ? ? ? ?struct dma_pl330_chan *pchan;
> > + ? ? ? bool cyclic;
> > ?};
> >
> > ?static inline struct dma_pl330_chan *
> > @@ -184,6 +188,60 @@ static inline void fill_queue(struct dma_pl330_chan
> *pch)
> > ? ? ? ?}
> > ?}
> >
> > +static void pl330_tasklet_cyclic(unsigned long data)
> > +{
> > + ? ? ? struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> > + ? ? ? struct dma_pl330_desc *desc, *_dt;
> > + ? ? ? unsigned long flags;
> > + ? ? ? LIST_HEAD(list);
> > +
> > + ? ? ? spin_lock_irqsave(&pch->lock, flags);
> > +
> > + ? ? ? /* Pick up ripe tomatoes */
> > + ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> > + ? ? ? ? ? ? ? if ((desc->status == DONE) && desc->cyclic) {
> > + ? ? ? ? ? ? ? ? ? ? ? dma_async_tx_callback callback;
> > +
> > + ? ? ? ? ? ? ? ? ? ? ? list_move_tail(&desc->node, &pch->work_list);
> > + ? ? ? ? ? ? ? ? ? ? ? pch->completed = desc->txd.cookie;
> > +
> > + ? ? ? ? ? ? ? ? ? ? ? desc->status = PREP;
> > +
> > + ? ? ? ? ? ? ? ? ? ? ? /* Try to submit a req imm.
> > + ? ? ? ? ? ? ? ? ? ? ? next to the last completed cookie */
> > + ? ? ? ? ? ? ? ? ? ? ? fill_queue(pch);
> > +
> > + ? ? ? ? ? ? ? ? ? ? ? /* Make sure the PL330 Channel thread is active
*/
> > + ? ? ? ? ? ? ? ? ? ? ? pl330_chan_ctrl(pch->pl330_chid,
PL330_OP_START);
> > +
> > + ? ? ? ? ? ? ? ? ? ? ? callback = desc->txd.callback;
> > + ? ? ? ? ? ? ? ? ? ? ? if (callback)
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? callback(desc->txd.callback_param);
> > +
> > + ? ? ? ? ? ? ? }
> > +
> > + ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
> > +}
> > +
> > +static void pl330_cyclic_free(struct dma_pl330_chan *pch)
> > +{
> > + ? ? ? struct dma_pl330_dmac *pdmac = pch->dmac;
> > + ? ? ? struct dma_pl330_desc *desc, *_dt;
> > + ? ? ? unsigned long flags;
> > + ? ? ? LIST_HEAD(list);
> > +
> > + ? ? ? spin_lock_irqsave(&pdmac->pool_lock, flags);
> > +
> > + ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
> > + ? ? ? if (desc->cyclic)
> > + ? ? ? ? ? ? ? list_move_tail(&desc->node, &list);
> 
> nitpick: indentation will be required after for_each
> 

I will address your comment.

> > +
> > + ? ? ? list_splice_tail_init(&list, &pdmac->desc_pool);
> > +
> > + ? ? ? spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> > + ? ? ? pch->cyclic_task = NULL;
> > +}
> > +
> > ?static void pl330_tasklet(unsigned long data)
> > ?{
> > ? ? ? ?struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
> > @@ -227,6 +285,9 @@ static void dma_pl330_rqcb(void *token, enum
> pl330_op_err err)
> >
> > ? ? ? ?spin_unlock_irqrestore(&pch->lock, flags);
> >
> > + ? ? ? if (pch->cyclic_task)
> > + ? ? ? ? ? ? ? tasklet_schedule(pch->cyclic_task);
> > + ? ? ? else
> > ? ? ? ?tasklet_schedule(&pch->task);
> > ?}
> >
> > @@ -256,25 +317,58 @@ static int pl330_alloc_chan_resources(struct
> dma_chan *chan)
> > ?static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> unsigned long arg)
> > ?{
> > ? ? ? ?struct dma_pl330_chan *pch = to_pchan(chan);
> > - ? ? ? struct dma_pl330_desc *desc;
> > + ? ? ? struct dma_pl330_desc *desc, *_dt;
> > ? ? ? ?unsigned long flags;
> > + ? ? ? struct dma_pl330_dmac *pdmac = pch->dmac;
> > + ? ? ? struct dma_slave_config *slave_config;
> > + ? ? ? struct dma_pl330_peri *peri;
> > + ? ? ? int i;
> > + ? ? ? LIST_HEAD(list);
> >
> > - ? ? ? /* Only supports DMA_TERMINATE_ALL */
> > - ? ? ? if (cmd != DMA_TERMINATE_ALL)
> > - ? ? ? ? ? ? ? return -ENXIO;
> > -
> > - ? ? ? spin_lock_irqsave(&pch->lock, flags);
> > -
> > - ? ? ? /* FLUSH the PL330 Channel thread */
> > - ? ? ? pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> > + ? ? ? switch (cmd) {
> > + ? ? ? case DMA_TERMINATE_ALL:
> > + ? ? ? ? ? ? ? spin_lock_irqsave(&pch->lock, flags);
> >
> > - ? ? ? /* Mark all desc done */
> > - ? ? ? list_for_each_entry(desc, &pch->work_list, node)
> > - ? ? ? ? ? ? ? desc->status = DONE;
> > + ? ? ? ? ? ? ? /* FLUSH the PL330 Channel thread */
> > + ? ? ? ? ? ? ? pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
> >
> > - ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
> > + ? ? ? ? ? ? ? /* Mark all desc done */
> > + ? ? ? ? ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list ,
node)
> {
> > + ? ? ? ? ? ? ? ? ? ? ? desc->status = DONE;
> > + ? ? ? ? ? ? ? ? ? ? ? pch->completed = desc->txd.cookie;
> > + ? ? ? ? ? ? ? ? ? ? ? list_move_tail(&desc->node, &list);
> > + ? ? ? ? ? ? ? }
> >
> > - ? ? ? pl330_tasklet((unsigned long) pch);
> > + ? ? ? ? ? ? ? list_splice_tail_init(&list, &pdmac->desc_pool);
> > + ? ? ? ? ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
> > + ? ? ? ? ? ? ? break;
> > + ? ? ? case DMA_SLAVE_CONFIG:
> > + ? ? ? ? ? ? ? slave_config = (struct dma_slave_config *)arg;
> > + ? ? ? ? ? ? ? peri = pch->chan.private;
> > +
> > + ? ? ? ? ? ? ? if (slave_config->direction == DMA_TO_DEVICE) {
> > + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->dst_addr)
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->fifo_addr =
slave_config->dst_addr;
> > + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->dst_addr_width) {
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i = 0;
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? while (slave_config->dst_addr_width !=
(1 <<
> i))
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i++;
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->burst_sz = i;
> > + ? ? ? ? ? ? ? ? ? ? ? }
> > + ? ? ? ? ? ? ? } else if (slave_config->direction == DMA_FROM_DEVICE) {
> > + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->src_addr)
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->fifo_addr =
slave_config->src_addr;
> > + ? ? ? ? ? ? ? ? ? ? ? if (slave_config->src_addr_width) {
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i = 0;
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? while (slave_config->src_addr_width !=
(1 <<
> i))
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i++;
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peri->burst_sz = i;
> > + ? ? ? ? ? ? ? ? ? ? ? }
> > + ? ? ? ? ? ? ? }
> > + ? ? ? ? ? ? ? break;
> > + ? ? ? default:
> > + ? ? ? ? ? ? ? return -ENXIO;
> 
> To print error message in the default case will be better.
> 

I will address your comment.

> > + ? ? ? }
> >
> > ? ? ? ?return 0;
> > ?}
> > @@ -291,6 +385,9 @@ static void pl330_free_chan_resources(struct
> dma_chan *chan)
> > ? ? ? ?pl330_release_channel(pch->pl330_chid);
> > ? ? ? ?pch->pl330_chid = NULL;
> >
> > + ? ? ? if (pch->cyclic_task)
> > + ? ? ? ? ? ? ? pl330_cyclic_free(pch);
> > +
> > ? ? ? ?spin_unlock_irqrestore(&pch->lock, flags);
> > ?}
> >
> > @@ -522,6 +619,66 @@ static inline int get_burst_len(struct
> dma_pl330_desc *desc, size_t len)
> > ? ? ? ?return burst_len;
> > ?}
> >
> > +static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
> > + ? ? ? ? ? ? ? struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
> > + ? ? ? ? ? ? ? size_t period_len, enum dma_data_direction direction)
> > +{
> > + ? ? ? struct dma_pl330_desc *desc;
> > + ? ? ? struct dma_pl330_chan *pch = to_pchan(chan);
> > + ? ? ? struct dma_pl330_peri *peri = chan->private;
> > + ? ? ? dma_addr_t dst;
> > + ? ? ? dma_addr_t src;
> > +
> > + ? ? ? pch = to_pchan(chan);
> > + ? ? ? if (!pch) {
> > + ? ? ? ? ? ? ? dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch
desc\n",
> > + ? ? ? ? ? ? ? ? ? ? ? __func__, __LINE__);
> > + ? ? ? ? ? ? ? return NULL;
> > + ? ? ? }
> 
> 'pch' is already acquired when defined. It's duplicated.
> dev_err has a incorrect parameter because pch is NULL.
> Accessing pch->dmac will be failed.

I will address your comment.

> 
> > +
> > + ? ? ? desc = pl330_get_desc(pch);
> > + ? ? ? if (!desc) {
> > + ? ? ? ? ? ? ? dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch
desc\n",
> > + ? ? ? ? ? ? ? ? ? ? ? __func__, __LINE__);
> > + ? ? ? ? ? ? ? return NULL;
> > + ? ? ? }
> > +
> > + ? ? ? switch (direction) {
> > + ? ? ? case DMA_TO_DEVICE:
> > + ? ? ? ? ? ? ? desc->rqcfg.src_inc = 1;
> > + ? ? ? ? ? ? ? desc->rqcfg.dst_inc = 0;
> > + ? ? ? ? ? ? ? src = dma_addr;
> > + ? ? ? ? ? ? ? dst = peri->fifo_addr;
> > + ? ? ? ? ? ? ? break;
> > + ? ? ? case DMA_FROM_DEVICE:
> > + ? ? ? ? ? ? ? desc->rqcfg.src_inc = 0;
> > + ? ? ? ? ? ? ? desc->rqcfg.dst_inc = 1;
> > + ? ? ? ? ? ? ? src = peri->fifo_addr;
> > + ? ? ? ? ? ? ? dst = dma_addr;
> > + ? ? ? ? ? ? ? break;
> > + ? ? ? default:
> > + ? ? ? ? ? ? ? dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma
> direction\n",
> > + ? ? ? ? ? ? ? __func__, __LINE__);
> > + ? ? ? ? ? ? ? return NULL;
> > + ? ? ? }
> > +
> > + ? ? ? desc->rqcfg.brst_size = peri->burst_sz;
> > + ? ? ? desc->rqcfg.brst_len = 1;
> > +
> > + ? ? ? if (!pch->cyclic_task) {
> > + ? ? ? ? ? ? ? pch->cyclic_task =
> > + ? ? ? ? ? ? ? ? ? ? ? kmalloc(sizeof(struct tasklet_struct),
GFP_KERNEL);
> > + ? ? ? ? ? ? ? tasklet_init(pch->cyclic_task,
> > + ? ? ? ? ? ? ? ? ? ? ? pl330_tasklet_cyclic, (unsigned int)pch);
> > + ? ? ? }
> > +
> > + ? ? ? desc->cyclic = true;
> > +
> > + ? ? ? fill_px(&desc->px, dst, src, period_len);
> > +
> > + ? ? ? return &desc->txd;
> > +}
> > +
> > ?static struct dma_async_tx_descriptor *
> > ?pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
> > ? ? ? ? ? ? ? ?dma_addr_t src, size_t len, unsigned long flags)
> > @@ -756,6 +913,7 @@ pl330_probe(struct amba_device *adev, const struct
> amba_id *id)
> > ? ? ? ? ? ? ? ? ? ? ? ?case MEMTODEV:
> > ? ? ? ? ? ? ? ? ? ? ? ?case DEVTOMEM:
> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?dma_cap_set(DMA_SLAVE, pd->cap_mask);
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dma_cap_set(DMA_CYCLIC, pd->cap_mask);
> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?break;
> > ? ? ? ? ? ? ? ? ? ? ? ?default:
> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?dev_err(&adev->dev, "DEVTODEV Not
> Supported\n");
> > @@ -781,6 +939,7 @@ pl330_probe(struct amba_device *adev, const struct
> amba_id *id)
> > ? ? ? ?pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
> > ? ? ? ?pd->device_free_chan_resources = pl330_free_chan_resources;
> > ? ? ? ?pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
> > + ? ? ? pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
> > ? ? ? ?pd->device_tx_status = pl330_tx_status;
> > ? ? ? ?pd->device_prep_slave_sg = pl330_prep_slave_sg;
> > ? ? ? ?pd->device_control = pl330_control;
> > --
> > 1.7.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-samsung-
> soc" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> >
> 
> 
> 
> --
> Best Regards,
> Chanho Park

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

end of thread, other threads:[~2011-07-16  1:11 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-13  8:47 [PATCH V2 00/12] To use DMA generic APIs for Samsung DMA Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 01/12] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim
2011-07-13  9:07   ` Russell King - ARM Linux
2011-07-13  8:47 ` [PATCH V2 02/12] DMA: PL330: Update PL330 DMA API driver Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 03/12] DMA: PL330: Add DMA capabilities Kukjin Kim
2011-07-13  9:14   ` Russell King - ARM Linux
2011-07-13 11:04     ` boojin
2011-07-15  4:45   ` Chanho Park
2011-07-16  1:11     ` Boojin Kim
2011-07-13  8:47 ` [PATCH V2 04/12] ARM: SAMSUNG: Update to use PL330-DMA driver Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 05/12] ARM: SAMSUNG: Add common DMA operations Kukjin Kim
2011-07-15  2:53   ` Grant Likely
2011-07-16  0:39     ` Boojin Kim
2011-07-16  0:50       ` Grant Likely
2011-07-13  8:47 ` [PATCH V2 06/12] ARM: EXYNOS4: Use generic DMA PL330 driver Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 07/12] ARM: S5PV210: " Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 08/12] ARM: S5PC100: " Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 09/12] ARM: S5P64X0: " Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 10/12] ARM: SAMSUNG: Remove S3C-PL330-DMA driver Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 11/12] spi/s3c64xx: Add support DMA engine API Kukjin Kim
2011-07-13  8:47 ` [PATCH V2 12/12] ASoC: Samsung: Update DMA interface Kukjin Kim
2011-07-13 23:57   ` Mark Brown
2011-07-16  0:01     ` Kukjin Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).