Skip to contentSkip to conversation

To use DMA generic APIs for Samsung DMA

PATCH Superseded Boojin Kim 10 participants 44 messages Jul 27, 2011 – Aug 25, 2011

Subsystems (9)

v5 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

Boojin Kim

author
#0 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

This patchset adds support DMA generic APIs for Samsung DMA.

The changes from V4 are following:
- Change DMA cyclic capability operation on '04 patch'
- Remove cyclic_task
- Initialize 'cyclic' variable on channel request.
- Change pl330 data structure on '02, 07, 08, 09, 10 patches'

	- Move 'fifo_addr' and 'burst_sz' variables from 'struct dma_pl330_peri'
	  to 'struct dma_pl330_chan'

- Change some names on '02, 05 patch'
- Change DMADEV_PL330 configuration to SAMSUNG_DMA_PL330
- Add comment for 'burst_sz' variable
- Consider 'xxx_maxburst' on '03, 06 patch'
- Modify pl330_filter() function on '06 patch'
- Merge DMA control code on SPI driver on '13 patch'

[PATCH V5 01/15] DMA: PL330: Add support runtime PM for PL330 DMAC [PATCH V5 02/15] DMA: PL330: Update PL330 DMA API driver
[PATCH V5 03/15] DMA: PL330: Support DMA_SLAVE_CONFIG command
[PATCH V5 04/15] DMA: PL330: Add DMA_CYCLIC capability
[PATCH V5 05/15] ARM: SAMSUNG: Update to use PL330-DMA driver
[PATCH V5 06/15] ARM: SAMSUNG: Add common DMA operations
[PATCH V5 07/15] ARM: EXYNOS4: Use generic DMA PL330 driver
[PATCH V5 08/15] ARM: S5PV210: Use generic DMA PL330 driver
[PATCH V5 09/15] ARM: S5PC100: Use generic DMA PL330 driver
[PATCH V5 10/15] ARM: S5P64X0: Use generic DMA PL330 driver
[PATCH V5 11/15] ARM: SAMSUNG: Remove S3C-PL330-DMA driver
[PATCH V5 12/15] spi/s3c64xx: Add support DMA engine API
[PATCH V5 13/15] spi/s3c64xx: Merge dma control code
[PATCH V5 14/15] ASoC: Samsung: Update DMA interface
[PATCH V5 15/15] ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

author
#1 lore raw

PATCH v5 1/15 DMA: PL330: Add support runtime PM for PL330 DMAC

---
 drivers/dma/pl330.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 73 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +73 -2
index 6abe1ec..b7ecf47 100644
@@ -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 {
@@ -696,6 +699,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 +790,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 +850,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 +870,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,
Signature · 1 line
1.7.1
#2 lore raw

RFC PATCH 1/1 DMA: PL330: Update PL330 DMAC to support runtime PM

This patch update runtime PM for PL330 DMAC to reduce power consumption.

---
The following patch support runtime PM for PL330 DMAC, but the clock of PL330 is always on. If the clock of PL330 is always on, additional power (10mA) is consumed.

"[PATCH 01/15] DMA: PL330: Add support runtime PM for PL330 DMAC"
http://permalink.gmane.org/gmane.linux.kernel.samsung-soc/5931

 arch/arm/plat-samsung/dma-ops.c |   21 +++++++++++
 drivers/dma/pl330.c             |   76 +++++++++++++--------------------------
 include/linux/amba/pl330.h      |   54 +++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 51 deletions(-)
arch/arm/plat-samsung/dma-ops.c +21 -0
index 9053433..b726e4a 100644
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/amba/pl330.h>
+#include <linux/pm_runtime.h>
 
 #include <mach/dma.h>
 
@@ -33,12 +34,23 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
 	struct dma_chan *chan;
 	dma_cap_mask_t mask;
 	struct dma_slave_config slave_config;
+#ifdef CONFIG_PM_RUNTIME
+	struct dma_pl330_chan *pch;
+	struct dma_pl330_dmac *pdmac;
+#endif
 
 	dma_cap_zero(mask);
 	dma_cap_set(info->cap, mask);
 
 	chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
 
+#ifdef CONFIG_PM_RUNTIME
+	pch = container_of(chan, struct dma_pl330_chan, chan);
+	pdmac = pch->dmac;
+
+	pm_runtime_get_sync(pdmac->pif.dev);
+#endif
+
 	if (info->direction == DMA_FROM_DEVICE) {
 		memset(&slave_config, 0, sizeof(struct dma_slave_config));
 		slave_config.direction = info->direction;
@@ -59,8 +71,17 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
 static int samsung_dmadev_release(unsigned ch,
 			struct s3c2410_dma_client *client)
 {
+#ifdef CONFIG_PM_RUNTIME
+	struct dma_pl330_chan *pch =
+		container_of((struct dma_chan *)ch, struct dma_pl330_chan, chan);
+	struct dma_pl330_dmac *pdmac = pdmac = pch->dmac;;
+#endif
+
 	dma_release_channel((struct dma_chan *)ch);
 
+#ifdef CONFIG_PM_RUNTIME
+	pm_runtime_put(pdmac->pif.dev);
+#endif
 	return 0;
 }
 
drivers/dma/pl330.c +25 -51

100 lines not on this page · raw message

include/linux/amba/pl330.h +54 -0

64 lines not on this page · raw message

#3 lore raw

RFC PATCH 1/1 DMA: PL330: Update PL330 DMAC to support runtime PM

Quoted 8 lines · Chanwoo Choi

This patch update runtime PM for PL330 DMAC to reduce power consumption.

---
The following patch support runtime PM for PL330 DMAC, but the clock of PL330 is always on. If the clock of PL330 is always on, additional power (10mA) is consumed.

Yes, we need to do this, but please do it in drivers/dma/pl330.c so that every platform benefits.

Quoted 69 lines
include/linux/amba/pl330.h +0 -0
index 17b0ada..d9a63fd 100644
@@ -12,6 +12,9 @@

?#ifndef ? ? ? ?__AMBA_PL330_H_
?#define ? ? ? ?__AMBA_PL330_H_

include/linux/amba/pl330.h +3 -0
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+

?#include <asm/hardware/pl330.h>

?struct dma_pl330_peri {

include/linux/amba/pl330.h +51 -0
@@ -42,4 +45,55 @@ struct dma_pl330_platdata {
 ? ? ? ?unsigned mcbuf_sz;
 ?};
 
+struct dma_pl330_chan {
+ ? ? ? /* Schedule desc completion */
+ ? ? ? struct tasklet_struct task;
+
+ ? ? ? /* DMA-Engine Channel */
+ ? ? ? struct dma_chan chan;
+
+ ? ? ? /* Last completed cookie */
+ ? ? ? dma_cookie_t completed;
+
+ ? ? ? /* List of to be xfered descriptors */
+ ? ? ? struct list_head work_list;
+
+ ? ? ? /* Pointer to the DMAC that manages this channel,
+ ? ? ? ?* NULL if the channel is available to be acquired.
+ ? ? ? ?* As the parent, this DMAC also provides descriptors
+ ? ? ? ?* to the channel.
+ ? ? ? ?*/
+ ? ? ? struct dma_pl330_dmac *dmac;
+
+ ? ? ? /* To protect channel manipulation */
+ ? ? ? spinlock_t lock;
+
+ ? ? ? /* Token of a hardware channel thread of PL330 DMAC
+ ? ? ? ?* NULL if the channel is available to be acquired.
+ ? ? ? ?*/
+ ? ? ? void *pl330_chid;
+
+ ? ? ? /* taks for cyclic capability */
+ ? ? ? struct tasklet_struct *cyclic_task;
+
+ ? ? ? bool cyclic;
+};
+
+struct dma_pl330_dmac {
+ ? ? ? struct pl330_info pif;
+
+ ? ? ? /* DMA-Engine Device */
+ ? ? ? struct dma_device ddma;
+
+ ? ? ? /* Pool of descriptors available for the DMAC's channels */
+ ? ? ? struct list_head desc_pool;
+ ? ? ? /* To protect desc_pool manipulation */
+ ? ? ? spinlock_t pool_lock;
+
+ ? ? ? /* Peripheral channels connected to this DMAC */
+ ? ? ? struct dma_pl330_chan peripherals[0]; /* keep at end */
+
+ ? ? ? struct clk *clk;
+};
+
Quoted 1 line

?#endif /* __AMBA_PL330_H_ */

struct dma_pl330_dmac and struct dma_pl330_chan are internal to the pl330 dmac driver. Nobody from outside should ever need them.

Thanks,
Jassi

#4 lore raw

RFC PATCH 1/1 DMA: PL330: Update PL330 DMAC to support runtime PM

In reply to Chanwoo Choi
Quoted 6 lines · Chanwoo Choi
arch/arm/plat-samsung/dma-ops.c +4 -0
+#ifdef CONFIG_PM_RUNTIME
+	struct dma_pl330_chan *pch;
+	struct dma_pl330_dmac *pdmac;
+#endif
 
 	dma_cap_zero(mask);

arch/arm/plat-samsung/dma-ops.c static unsigned samsung_dmadev_request(enum dma_ch dma_ch, · line 52

Quoted 10 lines
arch/arm/plat-samsung/dma-ops.c +6 -0
 	dma_cap_set(info->cap, mask);
 
 	chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
 
+#ifdef CONFIG_PM_RUNTIME
+	pch = container_of(chan, struct dma_pl330_chan, chan);
+	pdmac = pch->dmac;
+
+	pm_runtime_get_sync(pdmac->pif.dev);
+#endif

This is not the right way to do this. The pm runtime stuff should be internal to the PL330 driver. Take a moment to think about this:

You need to wake it up just before a transfer starts. You need to put it back to sleep just after the last transfer has finished. That gives you a hint where the calls need to be.

That can only be done from within the PL330 driver.

#5 lore raw

RFC PATCH 1/1 DMA: PL330: Update PL330 DMAC to support runtime PM

Quoted 21 lines · Russell King - ARM Linux
Quoted 6 lines · Chanwoo Choi
arch/arm/plat-samsung/dma-ops.c +4 -0
+#ifdef CONFIG_PM_RUNTIME
+	struct dma_pl330_chan *pch;
+	struct dma_pl330_dmac *pdmac;
+#endif
 
 	dma_cap_zero(mask);

arch/arm/plat-samsung/dma-ops.c static unsigned samsung_dmadev_request(enum dma_ch dma_ch, · line 52

Quoted 10 lines
arch/arm/plat-samsung/dma-ops.c +6 -0
 	dma_cap_set(info->cap, mask);
 
 	chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
 
+#ifdef CONFIG_PM_RUNTIME
+	pch = container_of(chan, struct dma_pl330_chan, chan);
+	pdmac = pch->dmac;
+
+	pm_runtime_get_sync(pdmac->pif.dev);
+#endif

This is not the right way to do this. The pm runtime stuff should be internal to the PL330 driver. Take a moment to think about this:

Quoted 6 lines

You need to wake it up just before a transfer starts. You need to put it back to sleep just after the last transfer has finished. That gives you a hint where the calls need to be.

That can only be done from within the PL330 driver.

Thanks for your comment&hint.

I will repost the patch which support runtime pm of PL330 in internal to the PL330 driver.

Regards,
Chanwoo Choi

author
#7 lore raw

PATCH v5 2/15 DMA: PL330: Update PL330 DMA API driver

In reply to Boojin Kim

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.

---
 drivers/dma/Kconfig        |    3 ++-
 drivers/dma/pl330.c        |   13 ++++++++-----
 include/linux/amba/pl330.h |    6 +-----
 3 files changed, 11 insertions(+), 11 deletions(-)
drivers/dma/Kconfig +2 -1
index 25cf327..569cb14 100644
@@ -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
drivers/dma/pl330.c +8 -5
index b7ecf47..5a10df9 100644
@@ -69,6 +69,10 @@ struct dma_pl330_chan {
 	 * NULL if the channel is available to be acquired.
 	 */
 	void *pl330_chid;
+
+	/* For D-to-M and M-to-D channels */
+	int burst_sz; /* the peripheral fifo width */
+	dma_addr_t fifo_addr;
 };
 
 struct dma_pl330_dmac {
@@ -455,7 +459,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 +581,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))
@@ -593,8 +597,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		return NULL;
 	}
 
-	addr = peri->fifo_addr;
-	burst_size = peri->burst_sz;
+	addr = pch->fifo_addr;
 
 	first = NULL;
 
@@ -642,7 +645,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 = pch->burst_sz;
 		desc->rqcfg.brst_len = 1;
 	}
 
include/linux/amba/pl330.h +1 -5
index cbee7de..d12f077 100644
@@ -19,12 +19,8 @@ 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 */
-	int burst_sz; /* in power of 2 */
-	dma_addr_t fifo_addr;
 };
 
 struct dma_pl330_platdata {
Signature · 1 line
1.7.1
author
#8 lore raw

PATCH v5 3/15 DMA: PL330: Support DMA_SLAVE_CONFIG command

In reply to Boojin Kim
---
 drivers/dma/pl330.c |   56 ++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 42 insertions(+), 14 deletions(-)
drivers/dma/pl330.c +42 -14
index 5a10df9..a4c4b62 100644
@@ -72,6 +72,7 @@ struct dma_pl330_chan {
 
 	/* For D-to-M and M-to-D channels */
 	int burst_sz; /* the peripheral fifo width */
+	int burst_len; /* the number of burst */
 	dma_addr_t fifo_addr;
 };
 
@@ -260,25 +261,52 @@ 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;
+	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;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				pch->fifo_addr = slave_config->dst_addr;
+			if (slave_config->dst_addr_width)
+				pch->burst_sz = __ffs(slave_config->dst_addr_width);
+			if (slave_config->dst_maxburst)
+				pch->burst_len = slave_config->dst_maxburst;
+		} else if (slave_config->direction == DMA_FROM_DEVICE) {
+			if (slave_config->src_addr)
+				pch->fifo_addr = slave_config->src_addr;
+			if (slave_config->src_addr_width)
+				pch->burst_sz = __ffs(slave_config->src_addr_width);
+			if (slave_config->src_maxburst)
+				pch->burst_len = slave_config->src_maxburst;
+		}
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "Not supported command.\n");
+		return -ENXIO;
+	}
 
 	return 0;
 }
Signature · 1 line
1.7.1
author
#9 lore raw

PATCH v5 4/15 DMA: PL330: Add DMA_CYCLIC capability

In reply to Boojin Kim

This patch adds DMA_CYCLIC capability that is used for audio driver. DMA driver activated with it reuses the dma requests that were submitted through tx_submit().

---
 drivers/dma/pl330.c |   97 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 95 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +95 -2
index a4c4b62..996b2e9 100644
@@ -42,6 +42,12 @@ enum desc_status {
 	DONE,
 };
 
+enum cyclic_mode {
+	NO_CYCLIC,
+	CYCLIC_PREP,
+	CYCLIC_TRIGGER,
+};
+
 struct dma_pl330_chan {
 	/* Schedule desc completion */
 	struct tasklet_struct task;
@@ -74,6 +80,9 @@ struct dma_pl330_chan {
 	int burst_sz; /* the peripheral fifo width */
 	int burst_len; /* the number of burst */
 	dma_addr_t fifo_addr;
+
+	/* for cyclic capability */
+	enum cyclic_mode cyclic;
 };
 
 struct dma_pl330_dmac {
@@ -160,6 +169,31 @@ static inline void free_desc_list(struct list_head *list)
 	spin_unlock_irqrestore(&pdmac->pool_lock, flags);
 }
 
+static inline void handle_cyclic_desc_list(struct list_head *list)
+{
+	struct dma_pl330_desc *desc;
+	struct dma_pl330_chan *pch;
+	unsigned long flags;
+
+	if (list_empty(list))
+		return;
+
+	list_for_each_entry(desc, list, node) {
+		dma_async_tx_callback callback;
+
+		/* Change status to reload it */
+		desc->status = PREP;
+		pch = desc->pchan;
+		callback = desc->txd.callback;
+		if (callback)
+			callback(desc->txd.callback_param);
+	}
+
+	spin_lock_irqsave(&pch->lock, flags);
+	list_splice_tail_init(list, &pch->work_list);
+	spin_unlock_irqrestore(&pch->lock, flags);
+}
+
 static inline void fill_queue(struct dma_pl330_chan *pch)
 {
 	struct dma_pl330_desc *desc;
@@ -213,7 +247,10 @@ static void pl330_tasklet(unsigned long data)
 
 	spin_unlock_irqrestore(&pch->lock, flags);
 
-	free_desc_list(&list);
+	if (pch->cyclic == CYCLIC_TRIGGER)
+		handle_cyclic_desc_list(&list);
+	else
+		free_desc_list(&list);
 }
 
 static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
@@ -244,6 +281,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 	spin_lock_irqsave(&pch->lock, flags);
 
 	pch->completed = chan->cookie = 1;
+	pch->cyclic = NO_CYCLIC;
 
 	pch->pl330_chid = pl330_request_channel(&pdmac->pif);
 	if (!pch->pl330_chid) {
@@ -323,6 +361,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 	pl330_release_channel(pch->pl330_chid);
 	pch->pl330_chid = NULL;
 
+	if (pch->cyclic)
+		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
+
 	spin_unlock_irqrestore(&pch->lock, flags);
 }
 
@@ -346,7 +387,11 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 
 static void pl330_issue_pending(struct dma_chan *chan)
 {
-	pl330_tasklet((unsigned long) to_pchan(chan));
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	pl330_tasklet((unsigned long) pch);
+
+	if (pch->cyclic == CYCLIC_PREP)
+		pch->cyclic = CYCLIC_TRIGGER;
 }
 
 /*
@@ -554,6 +599,52 @@ 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);
+	dma_addr_t dst;
+	dma_addr_t src;
+
+	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 = pch->fifo_addr;
+		break;
+	case DMA_FROM_DEVICE:
+		desc->rqcfg.src_inc = 0;
+		desc->rqcfg.dst_inc = 1;
+		src = pch->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 = pch->burst_sz;
+	desc->rqcfg.brst_len = 1;
+
+	if (!pch->cyclic)
+		pch->cyclic = CYCLIC_PREP;
+
+	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)
@@ -786,6 +877,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");
@@ -810,6 +902,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;
Signature · 1 line
1.7.1
author
#10 lore raw

PATCH v5 5/15 ARM: SAMSUNG: Update to use PL330-DMA driver

In reply to Boojin Kim

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

---
 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}  |    8 ++++----
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |    2 +-
 7 files changed, 18 insertions(+), 10 deletions(-)
 rename arch/arm/plat-samsung/include/plat/{s3c-dma-pl330.h => dma-pl330.h} (93%)
arch/arm/mach-exynos4/include/mach/dma.h +2 -2
index 81209eb..201842a 100644
@@ -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 */
arch/arm/mach-s5p64x0/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -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 */
arch/arm/mach-s5pc100/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -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 */
arch/arm/mach-s5pv210/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -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 */
arch/arm/plat-samsung/Kconfig +8 -0
index 4d79519..8b4e63f 100644
@@ -300,6 +300,14 @@ config S3C_PL330_DMA
 	help
 	  S3C DMA API Driver for PL330 DMAC.
 
+config SAMSUNG_DMA_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
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +4 -4
similarity index 93%
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..0a5dade 100644
@@ -8,8 +8,8 @@
  * (at your option) any later version.
  */
 
-#ifndef	__S3C_DMA_PL330_H_
-#define	__S3C_DMA_PL330_H_
+#ifndef __DMA_PL330_H_
+#define __DMA_PL330_H_ __FILE__
 
 #define S3C2410_DMAF_AUTOSTART		(1 << 0)
 #define S3C2410_DMAF_CIRCULAR		(1 << 1)
@@ -20,7 +20,7 @@
  * 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 {
@@ -95,4 +95,4 @@ static inline bool s3c_dma_has_circular(void)
 
 #include <plat/dma.h>
 
-#endif	/* __S3C_DMA_PL330_H_ */
+#endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h +1 -1
index bf5e2a9..64fdf66 100644
@@ -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,
Signature · 1 line
1.7.1
author
#11 lore raw

PATCH v5 6/15 ARM: SAMSUNG: Add common DMA operations

In reply to Boojin Kim

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().

---
 arch/arm/mach-s3c2410/include/mach/dma.h       |    8 ++-
 arch/arm/mach-s3c64xx/include/mach/dma.h       |    4 +
 arch/arm/plat-samsung/Makefile                 |    6 +-
 arch/arm/plat-samsung/dma-ops.c                |  130 +++++++++++++++++++++++
 arch/arm/plat-samsung/include/plat/dma-ops.h   |   63 +++++++++++
 arch/arm/plat-samsung/include/plat/dma-pl330.h |    4 +
 arch/arm/plat-samsung/include/plat/dma.h       |    1 +
 arch/arm/plat-samsung/s3c-dma-ops.c            |  133 ++++++++++++++++++++++++
 8 files changed, 346 insertions(+), 3 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
arch/arm/mach-s3c2410/include/mach/dma.h +7 -1
index b2b2a5b..e61a91f 100644
@@ -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,13 @@ enum dma_ch {
 	DMACH_MAX,		/* the end entry */
 };
 
+static inline bool samsung_dma_is_dmadev(void)
+{
+	return false;
+}
+
+#include <plat/dma.h>
+
 #define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */
 
 /* we have 4 dma channels */
arch/arm/mach-s3c64xx/include/mach/dma.h +4 -0
index 0a5d926..49c3a53 100644
@@ -63,6 +63,10 @@ static __inline__ bool s3c_dma_has_circular(void)
 	return true;
 }
 
+static inline bool samsung_dma_is_dmadev(void)
+{
+	return false;
+}
 #define S3C2410_DMAF_CIRCULAR		(1 << 0)
 
 #include <plat/dma.h>
arch/arm/plat-samsung/Makefile +4 -2
index 53eb15b..5083797 100644
@@ -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_SAMSUNG_DMA_PL330)	+= dma-ops.o
+
+obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
 
 # PM support
 
arch/arm/plat-samsung/dma-ops.c new file +130 -0

130 lines not on this page · raw message

arch/arm/plat-samsung/include/plat/dma-ops.h new file +63 -0

63 lines not on this page · raw message

arch/arm/plat-samsung/include/plat/dma-pl330.h +4 -0
index 0a5dade..2916920 100644
@@ -93,6 +93,10 @@ static inline bool s3c_dma_has_circular(void)
 	return true;
 }
 
+static inline bool samsung_dma_is_dmadev(void)
+{
+	return true;
+}
 #include <plat/dma.h>
 
 #endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/dma.h +1 -0
index 2e8f8c6..e87c6be 100644
@@ -125,3 +125,4 @@ 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>
arch/arm/plat-samsung/s3c-dma-ops.c new file +133 -0

133 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#12 lore raw

PATCH v5 7/15 ARM: EXYNOS4: Use generic DMA PL330 driver

In reply to Boojin Kim

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.

---
 arch/arm/mach-exynos4/Kconfig |    2 +-
 arch/arm/mach-exynos4/clock.c |   16 ++-
 arch/arm/mach-exynos4/dma.c   |  299 ++++++++++++++++++++++++++---------------
 3 files changed, 198 insertions(+), 119 deletions(-)
arch/arm/mach-exynos4/Kconfig +1 -1
index 1435fc3..0c006c5 100644
@@ -11,7 +11,7 @@ if ARCH_EXYNOS4
 
 config CPU_EXYNOS4210
 	bool
-	select S3C_PL330_DMA
+	select SAMSUNG_DMA_PL330
 	help
 	  Enable EXYNOS4210 CPU support
 
arch/arm/mach-exynos4/clock.c +9 -7
index 871f9d5..1b2e78c 100644
@@ -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();
 }
arch/arm/mach-exynos4/dma.c +188 -111

339 lines not on this page · raw message

Signature · 1 line
1.7.1
#13 lore raw

PATCH 7/15 ARM: EXYNOS4: Use generic DMA PL330 driver

Hi Boojin,

Quoted 12 lines · Boojin Kim

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.

---

?arch/arm/mach-exynos4/Kconfig | ? ?2 +-
?arch/arm/mach-exynos4/clock.c | ? 16 ++-
?arch/arm/mach-exynos4/dma.c ? | ?299 ++++++++++++++++++++++++++---------------

?3 files changed, 198 insertions(+), 119 deletions(-)

[...]

Quoted 2 lines
arch/arm/mach-exynos4/dma.c +0 -0
index 564bb53..d57d662 100644

[...]

Quoted 16 lines

+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,
?};

[...]

Quoted 21 lines

+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, ? ? ? ?},

arch/arm/mach-exynos4/dma.c +7 -5
-};
-
-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,

?};

Quoted 4 lines

?static int __init exynos4_dma_init(void)
?{
- ? ? ? platform_add_devices(exynos4_dmacs, ARRAY_SIZE(exynos4_dmacs));
+ ? ? ? amba_device_register(&exynos4_device_pdma0, &iomem_resource);

How would the 'exynos4_device_pdma1' instance get registered? Should there be a amba_device_register call for 'exynos4_device_pdma1' instance as well?

Thanks,
Thomas.

#14 lore raw

PATCH 7/15 ARM: EXYNOS4: Use generic DMA PL330 driver

In reply to Boojin Kim

Hi Boojin,

Quoted 12 lines · Boojin Kim

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.

---

?arch/arm/mach-exynos4/Kconfig | ? ?2 +-
?arch/arm/mach-exynos4/clock.c | ? 16 ++-
?arch/arm/mach-exynos4/dma.c ? | ?299 ++++++++++++++++++++++++++---------------

?3 files changed, 198 insertions(+), 119 deletions(-)

[...]

Quoted 2 lines
arch/arm/mach-exynos4/dma.c +0 -0
index 564bb53..d57d662 100644

[...]

Quoted 5 lines

+struct dma_pl330_peri pdma0_peri[28] = {
+ ? ? ? {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_PCM0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {

The client driver specifies the direction of the transfer (DMA_TO_DEVICE or DMA_FROM_DEVICE) when requesting for a dma channel. So, is the rqtype parameter required in the platform data for the dma driver?

Thanks,
Thomas.

#15 lore raw

PATCH 7/15 ARM: EXYNOS4: Use generic DMA PL330 driver

Quoted 10 lines · Thomas Abraham
Quoted 5 lines

+struct dma_pl330_peri pdma0_peri[28] = {
+ ? ? ? {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_PCM0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {

The client driver specifies the direction of the transfer (DMA_TO_DEVICE or DMA_FROM_DEVICE) when requesting for a dma channel. So, is the rqtype parameter required in the platform data for the dma driver?

That was done initially too with PL080, which has 8 uncommitted DMA channels. Peripheral drivers still had to pass the DMA direction. So it turned out to be entirely redundant information, so it got killed off, along with other channel specific configuration which drivers should've been doing via the slave configuration callback.

Passing lots of information via platform data which should come via other routes makes dmaengine users fragile - you can't tell whether they are passing the correct and full information necessary to work with other dmaengine drivers. So, the DMA engine platform data should only contain the absolute _minimum_ of information.

author
#16 lore raw

PATCH v5 8/15 ARM: S5PV210: Use generic DMA PL330 driver

In reply to Boojin Kim

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.

---
 arch/arm/mach-s5pv210/Kconfig            |    2 +-
 arch/arm/mach-s5pv210/clock.c            |   16 +-
 arch/arm/mach-s5pv210/dma.c              |  316 +++++++++++++++++++-----------
 arch/arm/mach-s5pv210/include/mach/dma.h |    2 +-
 4 files changed, 214 insertions(+), 122 deletions(-)
arch/arm/mach-s5pv210/Kconfig +1 -1
index 37b5a97..855d4b4 100644
@@ -11,7 +11,7 @@ if ARCH_S5PV210
 
 config CPU_S5PV210
 	bool
-	select S3C_PL330_DMA
+	select SAMSUNG_DMA_PL330
 	select S5P_EXT_INT
 	select S5P_HRT
 	select S5PV210_PM if PM
arch/arm/mach-s5pv210/clock.c +8 -8
index 2d59949..dbe7285 100644
@@ -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();
 }
arch/arm/mach-s5pv210/dma.c +204 -112

359 lines not on this page · raw message

arch/arm/mach-s5pv210/include/mach/dma.h +1 -1
index 1beae2c..201842a 100644
@@ -20,7 +20,7 @@
 #ifndef __MACH_DMA_H
 #define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
+/* This platform uses the common DMA API driver for PL330 */
 #include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
Signature · 1 line
1.7.1
author
#17 lore raw

PATCH v5 9/15 ARM: S5PC100: Use generic DMA PL330 driver

In reply to Boojin Kim

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.

---
 arch/arm/mach-s5pc100/Kconfig            |    2 +-
 arch/arm/mach-s5pc100/clock.c            |   23 +--
 arch/arm/mach-s5pc100/dma.c              |  323 +++++++++++++++++++----------
 arch/arm/mach-s5pc100/include/mach/dma.h |    2 +-
 4 files changed, 222 insertions(+), 128 deletions(-)
arch/arm/mach-s5pc100/Kconfig +1 -1
index 608722f..1d7e2b1 100644
@@ -10,7 +10,7 @@ if ARCH_S5PC100
 config CPU_S5PC100
 	bool
 	select S5P_EXT_INT
-	select S3C_PL330_DMA
+	select SAMSUNG_DMA_PL330
 	help
 	  Enable S5PC100 CPU support
 
arch/arm/mach-s5pc100/clock.c +9 -14
index 0305e9b..891acfe 100644
@@ -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();
 }
arch/arm/mach-s5pc100/dma.c +211 -112

365 lines not on this page · raw message

arch/arm/mach-s5pc100/include/mach/dma.h +1 -1
index 1beae2c..201842a 100644
@@ -20,7 +20,7 @@
 #ifndef __MACH_DMA_H
 #define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
+/* This platform uses the common DMA API driver for PL330 */
 #include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
Signature · 1 line
1.7.1
author
#18 lore raw

PATCH v5 10/15 ARM: S5P64X0: Use generic DMA PL330 driver

In reply to Boojin Kim

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.

---
 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              |  273 ++++++++++++++++++++----------
 arch/arm/mach-s5p64x0/include/mach/dma.h |    2 +-
 5 files changed, 201 insertions(+), 96 deletions(-)
arch/arm/mach-s5p64x0/Kconfig +2 -2
index 017af4c..bbf3487 100644
@@ -9,14 +9,14 @@ if ARCH_S5P64X0
 
 config CPU_S5P6440
 	bool
-	select S3C_PL330_DMA
+	select SAMSUNG_DMA_PL330
 	select S5P_HRT
 	help
 	  Enable S5P6440 CPU support
 
 config CPU_S5P6450
 	bool
-	select S3C_PL330_DMA
+	select SAMSUNG_DMA_PL330
 	select S5P_HRT
 	help
 	  Enable S5P6450 CPU support
arch/arm/mach-s5p64x0/clock-s5p6440.c +8 -1
index 9f12c2e..5f7ad9e 100644
@@ -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();
 }
arch/arm/mach-s5p64x0/clock-s5p6450.c +8 -1
index 4eec457..62d4707 100644
@@ -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();
 }
arch/arm/mach-s5p64x0/dma.c +182 -91

310 lines not on this page · raw message

arch/arm/mach-s5p64x0/include/mach/dma.h +1 -1
index 1beae2c..5a622af 100644
@@ -20,7 +20,7 @@
 #ifndef __MACH_DMA_H
 #define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
+/* This platform uses the common common DMA API driver for PL330 */
 #include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
Signature · 1 line
1.7.1
author
#19 lore raw

PATCH v5 11/15 ARM: SAMSUNG: Remove S3C-PL330-DMA driver

In reply to Boojin Kim

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.

---
 arch/arm/plat-samsung/Kconfig                      |    6 -
 arch/arm/plat-samsung/Makefile                     |    2 -
 arch/arm/plat-samsung/include/plat/dma-pl330.h     |   10 +-
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |   32 -
 arch/arm/plat-samsung/s3c-pl330.c                  | 1244 --------------------
 5 files changed, 6 insertions(+), 1288 deletions(-)
 delete mode 100644 arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
 delete mode 100644 arch/arm/plat-samsung/s3c-pl330.c
arch/arm/plat-samsung/Kconfig +0 -6
index 8b4e63f..a81fd80 100644
@@ -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 SAMSUNG_DMA_PL330
 	bool
 	select DMADEVICES
arch/arm/plat-samsung/Makefile +0 -2
index 5083797..530b546 100644
@@ -66,8 +66,6 @@ obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
 
 obj-$(CONFIG_SAMSUNG_DMA_PL330)	+= dma-ops.o
 
-obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
-
 # PM support
 
 obj-$(CONFIG_PM)		+= pm.o
arch/arm/plat-samsung/include/plat/dma-pl330.h +6 -4
index 2916920..9a1dadb 100644
@@ -11,9 +11,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.
@@ -88,6 +85,10 @@ enum dma_ch {
 	DMACH_MAX,
 };
 
+struct s3c2410_dma_client {
+	char	*name;
+};
+
 static inline bool s3c_dma_has_circular(void)
 {
 	return true;
@@ -97,6 +98,7 @@ static inline bool samsung_dma_is_dmadev(void)
 {
 	return true;
 }
-#include <plat/dma.h>
+
+#include <plat/dma-ops.h>
 
 #endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h deleted +0 -32
deleted file mode 100644
index 64fdf66..0000000
@@ -1,32 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <[email protected]>
- *
- * 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 */
arch/arm/plat-samsung/s3c-pl330.c deleted +0 -1244

1,244 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#20 lore raw

PATCH v5 12/15 spi/s3c64xx: Add support DMA engine API

In reply to Boojin Kim

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.

---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-----------------------
 1 files changed, 69 insertions(+), 72 deletions(-)
drivers/spi/spi_s3c64xx.c +69 -72
index 8945e20..a4cf76a 100644
@@ -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,
Signature · 1 line
1.7.1
#21 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

Quoted 27 lines · Boojin Kim

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.

---
?drivers/spi/spi_s3c64xx.c | ?141 ++++++++++++++++++++++----------------------- ?1 files changed, 69 insertions(+), 72 deletions(-)

drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -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 = {

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 236

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +4 -0
@@ -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;

void* doesn't need typecasting (same for all such occurances) IIRC someone already pointed it out?

Quoted 180 lines
drivers/spi/spi_s3c64xx.c +37 -4
+ ? ? ? 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:

drivers/spi/spi_s3c64xx.c +8 -44
@@ -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;

drivers/spi/spi_s3c64xx.c +13 -18
@@ -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);
 
Quoted 6 lines

? ? ? ?/* 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); ?}

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

#22 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

Am Montag 08 August 2011, 19:47:58 schrieb Jassi Brar:

Quoted 221 lines · Boojin Kim
Quoted 28 lines

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.

---
 drivers/spi/spi_s3c64xx.c |  141

++++++++++++++++++++++----------------------- 1 files changed, 69 insertions(+), 72 deletions(-)

drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -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 = {

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct · line 236

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +4 -0
@@ -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;

void* doesn't need typecasting (same for all such occurances) IIRC someone already pointed it out?

Quoted 181 lines
drivers/spi/spi_s3c64xx.c +28 -0
+       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;

drivers/spi/spi_s3c64xx.c +7 -0
+                       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);
drivers/spi/spi_s3c64xx.c +0 -2
-                       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;

drivers/spi/spi_s3c64xx.c +7 -19
+                       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) -{

drivers/spi/spi_s3c64xx.c +0 -19
-       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))
drivers/spi/spi_s3c64xx.c +0 -2
-                                       s3c2410_dma_ctrl(sdd->rx_dmach,
-                                                      

S3C2410_DMAOP_FLUSH); +
sdd->ops->stop(sdd->rx_ch); }

                       goto out;
drivers/spi/spi_s3c64xx.c +0 -7
@@ -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); -

drivers/spi/spi_s3c64xx.c +0 -2
-       if (s3c2410_dma_request(sdd->tx_dmach,
-                                       &s3c64xx_spi_dma_client, NULL) <

0) { - dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");

drivers/spi/spi_s3c64xx.c +0 -6
-               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); +

drivers/spi/spi_s3c64xx.c +12 -0
+       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);
 
Quoted 13 lines

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_work(struct work_struct *work) · line 802

Quoted 6 lines
drivers/spi/spi_s3c64xx.c +2 -2
       /* 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);
 }

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

yep, at least the S3C2416/2450 HSSPI which should use this driver.

Heiko

#23 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

Quoted 9 lines · Heiko St?bner

Am Montag 08 August 2011, 19:47:58 schrieb Jassi Brar:

Quoted 6 lines

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

yep, at least the S3C2416/2450 HSSPI which should use this driver.

Seems you keep some patches private ;) the spi driver isn't enabled for 2416 in mainline.

#24 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

Am Montag 08 August 2011, 20:16:58 schrieben Sie:

Quoted 9 lines · Heiko St?bner
Quoted 8 lines

Am Montag 08 August 2011, 19:47:58 schrieb Jassi Brar:

Quoted 6 lines

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

Quoted 4 lines
Quoted 1 line

yep, at least the S3C2416/2450 HSSPI which should use this driver.

Seems you keep some patches private ;) the spi driver isn't enabled for 2416 in mainline.

It's not so private [1], but isn't working yet :-). I'm still new to the whole kernel development stuff and seem to be the only one working on this device family.

I know from comparing s3c2416 and s3c64xx manuals that the hsspi part is the same but still have some learning to do to get it to work and also need drivers for the other side of the spi connection.

The Asus eeeReader DR-900 uses a wlan chip supported by libertas. So having a "verified" driver on the other side might help me in getting the spi driver to work.

Heiko

[1] https://gitorious.org/oyo-hack every e-book reader with Sipix display seems to be made from the same model line.

#25 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

In reply to Jassi Brar
Quoted 219 lines · Jassi Brar
Quoted 27 lines · Boojin Kim

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.

---
?drivers/spi/spi_s3c64xx.c | ?141 ++++++++++++++++++++++----------------------- ?1 files changed, 69 insertions(+), 72 deletions(-)

drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -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 = {

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 236

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +4 -0
@@ -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;

void* doesn't need typecasting (same for all such occurances) IIRC someone already pointed it out?

Quoted 180 lines
drivers/spi/spi_s3c64xx.c +37 -4
+ ? ? ? 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:

drivers/spi/spi_s3c64xx.c +8 -44
@@ -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;

drivers/spi/spi_s3c64xx.c +13 -18
@@ -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);
 
Quoted 13 lines
Quoted 6 lines

? ? ? ?/* 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); ?}

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

Exactly, spi_s3c64xx.c (including Sound driver) can not be used with pl080 and pl330 (DMAENGINE drivers) as it is.
Recently I was trying to use PL080 DMAENGINE driver, and i was ended up using some #ifdef in the spi driver.
something like
#ifdef CONFIG_PL080
sdd->tx_dmac.bus_id = dmatx_res->name; sdd->rx_dmac.bus_id = dmarx_res->name;
#else
sdd->tx_dmac.bus_id = dmatx_res->start; sdd->tx_dmac.bus_id = dmatx_res->start;
#endif

This is because, Pl080 handle the channel as a char *(name) and pl330 expect the channel to be enum (a number).

I think the solution could be changes in the either of these drivers to follow some symmetry or we will be ending up with
two client driver for the same device or writing up some unnecessary warper code or finally using some #ifdef.

Please suggest if you guys have any other idea/approach to handle such kind of situation.

Below is the git diff of spi_s3c64xx driver using with PL080 DMAENGINE driver. This patch is against kgene's next-samsung-dma-v4
------------------------------------------------------------------------------------------------------------------

drivers/spi/spi_s3c64xx.c +6 -0
index a4cf76a..f7b9c37 100644
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
+#include <linux/amba/pl08x.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 
@@ -165,8 +166,13 @@ struct s3c64xx_spi_driver_data {
 	struct work_struct              work;
 	struct list_head                queue;
 	spinlock_t                      lock;
+#ifdef CONFIG_DMADEV_PL080
+	struct pl08x_channel_data	rx_dmach;
+	struct pl08x_channel_data	tx_dmach;
+#else
 	enum dma_ch                     rx_dmach;
 	enum dma_ch                     tx_dmach;
+#endif
 	unsigned long                   sfr_start;
 	struct completion               xfer_completion;
 	unsigned                        state;
@@ -753,10 +759,18 @@ static int acquire_dma(struct

s3c64xx_spi_driver_data *sdd)
info.direction = DMA_FROM_DEVICE;
info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; info.width = sdd->cur_bpw / 8;
+#ifdef CONFIG_DMADEV_PL080
+ sdd->rx_ch = sdd->ops->request(sdd->rx_dmach.bus_id, &info);
+#else
sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
+#endif
info.direction = DMA_TO_DEVICE;
info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
- sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
+#ifdef CONFIG_DMADEV_PL080
+ sdd->tx_ch = sdd->ops->request(sdd->tx_dmach.bus_id, &info);
+#else
+ sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
+#endif

return 1;
}
@@ -982,7 +996,6 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
}

/* Check for availability of necessary resource */
-
dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (dmatx_res == NULL) {
dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
@@ -1015,9 +1028,13 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
sdd->cntrlr_info = sci;
sdd->pdev = pdev;
sdd->sfr_start = mem_res->start;
+#ifdef CONFIG_DMADEV_PL080
+ sdd->tx_dmach.bus_id = dmatx_res->name;
+ sdd->rx_dmach.bus_id = dmarx_res->name;
+#else
sdd->tx_dmach = dmatx_res->start;
sdd->rx_dmach = dmarx_res->start;
-
+#endif
sdd->cur_bpw = 8;

master->bus_num = pdev->id;
@@ -1105,7 +1122,6 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
mem_res->end, mem_res->start, sdd->rx_dmach, sdd->tx_dmach);
-
return 0;

err8:
----------------------------------------------------------------------------------------------------------------------

Regards,
Alim

Quoted 5 lines

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#26 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

Quoted 340 lines · Alim Akhtar
Quoted 219 lines · Jassi Brar
Quoted 27 lines · Boojin Kim

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.

---
?drivers/spi/spi_s3c64xx.c | ?141 ++++++++++++++++++++++----------------------- ?1 files changed, 69 insertions(+), 72 deletions(-)

drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -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 = {

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 236

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +4 -0
@@ -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;

void* doesn't need typecasting (same for all such occurances) IIRC someone already pointed it out?

Quoted 180 lines
drivers/spi/spi_s3c64xx.c +37 -4
+ ? ? ? 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:

drivers/spi/spi_s3c64xx.c +8 -44
@@ -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;

drivers/spi/spi_s3c64xx.c +13 -18
@@ -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);
 
Quoted 13 lines
Quoted 6 lines

? ? ? ?/* 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); ?}

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

Exactly, spi_s3c64xx.c (including Sound driver) can not be used with pl080 and pl330 (DMAENGINE drivers) as it is.
Recently I was trying to use PL080 DMAENGINE driver, and i was ended up using some #ifdef in the spi driver.
something like
#ifdef CONFIG_PL080
sdd->tx_dmac.bus_id = dmatx_res->name; sdd->rx_dmac.bus_id = dmarx_res->name;
#else
sdd->tx_dmac.bus_id = dmatx_res->start; sdd->tx_dmac.bus_id = dmatx_res->start;
#endif

This is because, Pl080 handle the channel as a char *(name) and pl330 expect the channel to be enum (a number).

I think the solution could be changes in the either of these drivers to follow some symmetry or we will be ending up with
two client driver for the same device or writing up some unnecessary warper code or finally using some #ifdef.

Please suggest if you guys have any other idea/approach to handle such kind of situation.

Below is the git diff of spi_s3c64xx driver using with PL080 DMAENGINE driver. This patch is against kgene's next-samsung-dma-v4
------------------------------------------------------------------------------------------------------------------

drivers/spi/spi_s3c64xx.c +0 -0
index a4cf76a..f7b9c37 100644
@@ -24,6 +24,7 @@

?#include <linux/delay.h>
?#include <linux/clk.h>
?#include <linux/dma-mapping.h>
+#include <linux/amba/pl08x.h>
?#include <linux/platform_device.h>
?#include <linux/spi/spi.h>

drivers/spi/spi_s3c64xx.c +14 -1
@@ -165,8 +166,13 @@ struct s3c64xx_spi_driver_data {
 ? ? ? ?struct work_struct ? ? ? ? ? ? ?work;
 ? ? ? ?struct list_head ? ? ? ? ? ? ? ?queue;
 ? ? ? ?spinlock_t ? ? ? ? ? ? ? ? ? ? ?lock;
+#ifdef CONFIG_DMADEV_PL080
+ ? ? ? struct pl08x_channel_data ? ? ? rx_dmach;
+ ? ? ? struct pl08x_channel_data ? ? ? tx_dmach;
+#else
 ? ? ? ?enum dma_ch ? ? ? ? ? ? ? ? ? ? rx_dmach;
 ? ? ? ?enum dma_ch ? ? ? ? ? ? ? ? ? ? tx_dmach;
+#endif
 ? ? ? ?unsigned long ? ? ? ? ? ? ? ? ? sfr_start;
 ? ? ? ?struct completion ? ? ? ? ? ? ? xfer_completion;
 ? ? ? ?unsigned ? ? ? ? ? ? ? ? ? ? ? ?state;
@@ -753,10 +759,18 @@ static int acquire_dma(struct
 s3c64xx_spi_driver_data *sdd)
 ? ? ? ?info.direction = DMA_FROM_DEVICE;
 ? ? ? ?info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
 ? ? ? ?info.width = sdd->cur_bpw / 8;
+#ifdef CONFIG_DMADEV_PL080
+ ? ? ? sdd->rx_ch = sdd->ops->request(sdd->rx_dmach.bus_id, &info);
+#else
 ? ? ? ?sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
+#endif
 ? ? ? ?info.direction = DMA_TO_DEVICE;
 ? ? ? ?info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
- ? ? ? sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
+#ifdef CONFIG_DMADEV_PL080
+ ? ? ? sdd->tx_ch = sdd->ops->request(sdd->tx_dmach.bus_id, &info);
+#else
+ ? ? ? ? ? ? ? sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
+#endif
 
 ? ? ? ?return 1;

?}

drivers/spi/spi_s3c64xx.c +0 -0
@@ -982,7 +996,6 @@ static int __init s3c64xx_spi_probe(struct
 platform_device *pdev)
 ? ? ? ?}
 

? ? ? ?/* Check for availability of necessary resource */
-
? ? ? ?dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); ? ? ? ?if (dmatx_res == NULL) {
? ? ? ? ? ? ? ?dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");

drivers/spi/spi_s3c64xx.c +5 -1
@@ -1015,9 +1028,13 @@ static int __init s3c64xx_spi_probe(struct
 platform_device *pdev)
 ? ? ? ?sdd->cntrlr_info = sci;
 ? ? ? ?sdd->pdev = pdev;
 ? ? ? ?sdd->sfr_start = mem_res->start;
+#ifdef CONFIG_DMADEV_PL080
+ ? ? ? sdd->tx_dmach.bus_id = dmatx_res->name;
+ ? ? ? sdd->rx_dmach.bus_id = dmarx_res->name;
+#else
 ? ? ? ?sdd->tx_dmach = dmatx_res->start;
 ? ? ? ?sdd->rx_dmach = dmarx_res->start;
-
+#endif
 ? ? ? ?sdd->cur_bpw = 8;
 

? ? ? ?master->bus_num = pdev->id;

drivers/spi/spi_s3c64xx.c +0 -1
@@ -1105,7 +1122,6 @@ static int __init s3c64xx_spi_probe(struct
 platform_device *pdev)
 ? ? ? ?dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?mem_res->end, mem_res->start,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sdd->rx_dmach, sdd->tx_dmach);
-
 ? ? ? ?return 0;
 
Quoted 3 lines

?err8:
----------------------------------------------------------------------------------------------------------------------

Hi All,
Any suggestions/comments on my concerns?

Thanks!

Quoted 11 lines

Regards,
Alim

Quoted 5 lines

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#27 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

In reply to Alim Akhtar
Quoted 13 lines · Alim Akhtar

Exactly, spi_s3c64xx.c (including Sound driver) can not be used with pl080 and pl330 (DMAENGINE drivers) as it is.
Recently I was trying to use PL080 DMAENGINE driver, and i was ended up using some #ifdef in the spi driver.
something like
#ifdef CONFIG_PL080
sdd->tx_dmac.bus_id = dmatx_res->name; sdd->rx_dmac.bus_id = dmarx_res->name;
#else
sdd->tx_dmac.bus_id = dmatx_res->start; sdd->tx_dmac.bus_id = dmatx_res->start;
#endif

Quoted 2 lines

This is because, Pl080 handle the channel as a char *(name) and pl330 expect the channel to be enum (a number).

The alternative is that you do as the Primecell drivers do (which was designed from the outset to be independent of the specific dmaengine), and pass the DMA filter parameters as pointers via platform data.

#28 lore raw

PATCH 12/15 spi/s3c64xx: Add support DMA engine API

Quoted 14 lines · Russell King - ARM Linux
Quoted 13 lines · Alim Akhtar

Exactly, spi_s3c64xx.c (including Sound driver) can not be used with pl080 and pl330 (DMAENGINE drivers) as it is.
Recently I was trying to use PL080 DMAENGINE driver, and i was ended up using some #ifdef in the spi driver.
something like
#ifdef CONFIG_PL080
sdd->tx_dmac.bus_id = dmatx_res->name; sdd->rx_dmac.bus_id = dmarx_res->name;
#else
sdd->tx_dmac.bus_id = dmatx_res->start; sdd->tx_dmac.bus_id = dmatx_res->start;
#endif

Quoted 7 lines
Quoted 2 lines

This is because, Pl080 handle the channel as a char *(name) and pl330 expect the channel to be enum (a number).

The alternative is that you do as the Primecell drivers do (which was designed from the outset to be independent of the specific dmaengine), and pass the DMA filter parameters as pointers via platform data.

Thanks Russell for your suggestion and pointer.
I will Look into this alternative solution.

Regards,
Alim

author
#29 lore raw

PATCH v5 12/15 spi/s3c64xx: Add support DMA engine API

In reply to Jassi Brar

Jassi Brar Wrote:

Quoted 41 lines

Sent: Tuesday, August 09, 2011 2:48 AM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Mark Brown; Grant Likely; Russell King
Subject: Re: [PATCH 12/15] spi/s3c64xx: Add support DMA engine API

Quoted 10 lines · Boojin Kim

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.

---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-------------

----------

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct

Quoted 17 lines
 1 files changed, 69 insertions(+), 72 deletions(-)
drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -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)

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +0 -0
       writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
Quoted 6 lines

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 236

Quoted 4 lines
drivers/spi/spi_s3c64xx.c +4 -0
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+       struct s3c64xx_spi_driver_data *sdd
+               = (struct s3c64xx_spi_driver_data *)data;

void* doesn't need typecasting (same for all such occurances) IIRC someone already pointed it out?

I'm sorry for late response. (I was in vacation.)
This comment was reflected on 13/15 patch.

Quoted 213 lines

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct

Quoted 34 lines
drivers/spi/spi_s3c64xx.c +28 -0
+       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,

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +1 -0
       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);

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct

Quoted 1 line
drivers/spi/spi_s3c64xx.c +0 -0
@@ -259,10 +295,14 @@ static void enable_datapath(struct

s3c64xx_spi_driver_data *sdd,

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 4 lines
drivers/spi/spi_s3c64xx.c +0 -1
               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);

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +0 -3
-                       s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
-                                               xfer->tx_dma, xfer->len);
-                       s3c2410_dma_ctrl(sdd->tx_dmach,

S3C2410_DMAOP_START);

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct

Quoted 12 lines
drivers/spi/spi_s3c64xx.c +8 -0
+                       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,

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 4 lines
drivers/spi/spi_s3c64xx.c +0 -1
                       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);

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +0 -3
-                       s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
-                                               xfer->rx_dma, xfer->len);
-                       s3c2410_dma_ctrl(sdd->rx_dmach,

S3C2410_DMAOP_START);

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct

Quoted 12 lines
drivers/spi/spi_s3c64xx.c +8 -0
+                       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)

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct · line 486

Quoted 4 lines
drivers/spi/spi_s3c64xx.c +0 -1
       }
 }
 
-static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan,

void *buf_id,

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct · line 487

Quoted 1 line
drivers/spi/spi_s3c64xx.c +0 -1
-                                int size, enum s3c2410_dma_buffresult

res)

Quoted 9 lines
drivers/spi/spi_s3c64xx.c +0 -9
-{
-       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

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)

Quoted 10 lines
drivers/spi/spi_s3c64xx.c +0 -10
-               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,

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct · line 507

Quoted 1 line
drivers/spi/spi_s3c64xx.c +0 -1
-                                int size, enum s3c2410_dma_buffresult

res)

drivers/spi/spi_s3c64xx.c static void handle_msg(struct

Quoted 22 lines
drivers/spi/spi_s3c64xx.c +0 -18
-{
-       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,

drivers/spi/spi_s3c64xx.c static void handle_msg(struct s3c64xx_spi_driver_data *sdd,

Quoted 5 lines
drivers/spi/spi_s3c64xx.c +0 -2
                       if (use_dma) {
                               if (xfer->tx_buf != NULL
                                               && (sdd->state & TXBUSY))
-                                       s3c2410_dma_ctrl(sdd->tx_dmach,
-
                                                       S3C2410_DMAOP_FLUSH);

drivers/spi/spi_s3c64xx.c static void handle_msg(struct s3c64xx_spi_driver_data *sdd,

Quoted 5 lines
drivers/spi/spi_s3c64xx.c +1 -2
+                                       sdd->ops->stop(sdd->tx_ch);
                               if (xfer->rx_buf != NULL
                                               && (sdd->state & RXBUSY))
-                                       s3c2410_dma_ctrl(sdd->rx_dmach,
-
                                                       S3C2410_DMAOP_FLUSH);

drivers/spi/spi_s3c64xx.c out: · line 746

Quoted 10 lines
drivers/spi/spi_s3c64xx.c +1 -2
+                                       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) {

drivers/spi/spi_s3c64xx.c out:

Quoted 4 lines
drivers/spi/spi_s3c64xx.c +0 -4
-               dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
-               return 0;
-       }
-       s3c2410_dma_set_buffdone_fn(sdd->rx_dmach,

s3c64xx_spi_dma_rxcb);

drivers/spi/spi_s3c64xx.c out: · line 752

Quoted 2 lines
drivers/spi/spi_s3c64xx.c +0 -2
-       s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
-                                       sdd->sfr_start +

S3C64XX_SPI_RX_DATA);

drivers/spi/spi_s3c64xx.c out:

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +0 -3
-
-       if (s3c2410_dma_request(sdd->tx_dmach,
-                                       &s3c64xx_spi_dma_client, NULL) <

0) {

drivers/spi/spi_s3c64xx.c out: · line 757

Quoted 2 lines
drivers/spi/spi_s3c64xx.c +0 -2
-               dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
-               s3c2410_dma_free(sdd->rx_dmach,

&s3c64xx_spi_dma_client);

drivers/spi/spi_s3c64xx.c out:

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +0 -3
-               return 0;
-       }
-       s3c2410_dma_set_buffdone_fn(sdd->tx_dmach,

s3c64xx_spi_dma_txcb);

drivers/spi/spi_s3c64xx.c out: · line 762

Quoted 2 lines
drivers/spi/spi_s3c64xx.c +0 -2
-       s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
-                                       sdd->sfr_start +

S3C64XX_SPI_TX_DATA);

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_work(struct work_struct

Quoted 17 lines
drivers/spi/spi_s3c64xx.c +13 -0
+
+       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)

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_work(struct work_struct *work) · line 802

Quoted 8 lines
drivers/spi/spi_s3c64xx.c +2 -2
       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);
 }
Quoted 6 lines

Btw, this spi driver is for S3C64xx(with pl080) and S5P(with pl330) series, both of which
have DMAENGINE drivers. May be it could be directly switched to using those, rather than
via Samsung's wrapper driver.
Or am I overlooking something ?

Samsung is preparing to use PL080 with DMAENGINE. After this work is done, We will consider to using DMAENGINE API if required.

author
#30 lore raw

PATCH v5 13/15 spi/s3c64xx: Merge dma control code

In reply to Boojin Kim

This patch modifies to merge the dma control code.
Original s3c64xx spi driver has each dma control code for rx and tx channel. This patch merges these dma control codes into one.
With this patch, a dma setup function and callback function handle for both rx and tx channel.

---
 drivers/spi/spi_s3c64xx.c |  140 ++++++++++++++++++++++++--------------------
 1 files changed, 76 insertions(+), 64 deletions(-)
drivers/spi/spi_s3c64xx.c +76 -64
index a4cf76a..de71f55 100644
@@ -132,6 +132,12 @@
 #define RXBUSY    (1<<2)
 #define TXBUSY    (1<<3)
 
+struct s3c64xx_spi_dma_data {
+	unsigned		ch;
+	enum dma_data_direction direction;
+	enum dma_ch	dmach;
+};
+
 /**
  * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
  * @clk: Pointer to the spi clock.
@@ -165,15 +171,13 @@ struct s3c64xx_spi_driver_data {
 	struct work_struct              work;
 	struct list_head                queue;
 	spinlock_t                      lock;
-	enum dma_ch                     rx_dmach;
-	enum dma_ch                     tx_dmach;
 	unsigned long                   sfr_start;
 	struct completion               xfer_completion;
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
-	unsigned			rx_ch;
-	unsigned			tx_ch;
+	struct s3c64xx_spi_dma_data	rx_dma;
+	struct s3c64xx_spi_dma_data	tx_dma;
 	struct samsung_dma_ops		*ops;
 };
 
@@ -230,36 +234,76 @@ 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)
+static void s3c64xx_spi_dmacb(void *data)
 {
-	struct s3c64xx_spi_driver_data *sdd
-		= (struct s3c64xx_spi_driver_data *)data;
+	struct s3c64xx_spi_driver_data *sdd;
+	struct s3c64xx_spi_dma_data *dma = data;
 	unsigned long flags;
 
+	if (dma->direction == DMA_FROM_DEVICE)
+		sdd = container_of(data,
+			struct s3c64xx_spi_driver_data, rx_dma);
+	else
+		sdd = container_of(data,
+			struct s3c64xx_spi_driver_data, tx_dma);
+
 	spin_lock_irqsave(&sdd->lock, flags);
 
-	sdd->state &= ~RXBUSY;
-	/* If the other done */
-	if (!(sdd->state & TXBUSY))
-		complete(&sdd->xfer_completion);
+	if (dma->direction == DMA_FROM_DEVICE) {
+		sdd->state &= ~RXBUSY;
+		if (!(sdd->state & TXBUSY))
+			complete(&sdd->xfer_completion);
+	} else {
+		sdd->state &= ~TXBUSY;
+		if (!(sdd->state & RXBUSY))
+			complete(&sdd->xfer_completion);
+	}
 
 	spin_unlock_irqrestore(&sdd->lock, flags);
 }
 
-static void s3c64xx_spi_dma_txcb(void *data)
+static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
+					unsigned len, dma_addr_t buf)
 {
-	struct s3c64xx_spi_driver_data *sdd
-		= (struct s3c64xx_spi_driver_data *)data;
-	unsigned long flags;
+	struct s3c64xx_spi_driver_data *sdd;
+	struct samsung_dma_prep_info info;
 
-	spin_lock_irqsave(&sdd->lock, flags);
+	if (dma->direction == DMA_FROM_DEVICE)
+		sdd = container_of((void *)dma,
+			struct s3c64xx_spi_driver_data, rx_dma);
+	else
+		sdd = container_of((void *)dma,
+			struct s3c64xx_spi_driver_data, tx_dma);
 
-	sdd->state &= ~TXBUSY;
-	/* If the other done */
-	if (!(sdd->state & RXBUSY))
-		complete(&sdd->xfer_completion);
+	info.cap = DMA_SLAVE;
+	info.len = len;
+	info.fp = s3c64xx_spi_dmacb;
+	info.fp_param = dma;
+	info.direction = dma->direction;
+	info.buf = buf;
+
+	sdd->ops->prepare(dma->ch, &info);
+	sdd->ops->trigger(dma->ch);
+}
 
-	spin_unlock_irqrestore(&sdd->lock, flags);
+static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
+{
+	struct samsung_dma_info info;
+
+	sdd->ops = samsung_dma_get_ops();
+
+	info.cap = DMA_SLAVE;
+	info.client = &s3c64xx_spi_dma_client;
+	info.width = sdd->cur_bpw / 8;
+
+	info.direction = sdd->rx_dma.direction;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+	sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info);
+	info.direction =  sdd->tx_dma.direction;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+	sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info);
+
+	return 1;
 }
 
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
@@ -269,7 +313,6 @@ 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);
@@ -295,14 +338,7 @@ 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;
-			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);
+			prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
 		} else {
 			switch (sdd->cur_bpw) {
 			case 32:
@@ -334,14 +370,7 @@ 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);
-			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);
+			prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
 		}
 	}
 
@@ -701,10 +730,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
 			if (use_dma) {
 				if (xfer->tx_buf != NULL
 						&& (sdd->state & TXBUSY))
-					sdd->ops->stop(sdd->tx_ch);
+					sdd->ops->stop(sdd->tx_dma.ch);
 				if (xfer->rx_buf != NULL
 						&& (sdd->state & RXBUSY))
-					sdd->ops->stop(sdd->rx_ch);
+					sdd->ops->stop(sdd->rx_dma.ch);
 			}
 
 			goto out;
@@ -742,25 +771,6 @@ out:
 		msg->complete(msg->context);
 }
 
-static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
-{
-
-	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;
-}
-
 static void s3c64xx_spi_work(struct work_struct *work)
 {
 	struct s3c64xx_spi_driver_data *sdd = container_of(work,
@@ -797,8 +807,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
 	spin_unlock_irqrestore(&sdd->lock, flags);
 
 	/* Free DMA channels */
-	sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client);
-	sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
 }
 
 static int s3c64xx_spi_transfer(struct spi_device *spi,
@@ -1015,8 +1025,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 	sdd->cntrlr_info = sci;
 	sdd->pdev = pdev;
 	sdd->sfr_start = mem_res->start;
-	sdd->tx_dmach = dmatx_res->start;
-	sdd->rx_dmach = dmarx_res->start;
+	sdd->tx_dma.dmach = dmatx_res->start;
+	sdd->tx_dma.direction = DMA_TO_DEVICE;
+	sdd->rx_dma.dmach = dmarx_res->start;
+	sdd->rx_dma.direction = DMA_FROM_DEVICE;
 
 	sdd->cur_bpw = 8;
 
@@ -1104,7 +1116,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 					pdev->id, master->num_chipselect);
 	dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
 					mem_res->end, mem_res->start,
-					sdd->rx_dmach, sdd->tx_dmach);
+					sdd->rx_dma.dmach, sdd->tx_dma.dmach);
 
 	return 0;
 
Signature · 1 line
1.7.1
#31 lore raw

PATCH 13/15 spi/s3c64xx: Merge dma control code

Quoted 5 lines · Boojin Kim

This patch modifies to merge the dma control code.
Original s3c64xx spi driver has each dma control code for rx and tx channel. This patch merges these dma control codes into one.
With this patch, a dma setup function and callback function handle for both rx and tx channel.

This is nothing really to do with underlying DMAENGINE API.
And, apparently it actually bloats the driver ? 76 insertions(+), 64
deletions(-)
Yet, I am not very against the idea.

If you must do it, maybe It would have been better to move it early in the patchset,
which would have resulted in a smaller and cleaner "spi/s3c64xx: Add support DMA engine API"

author
#32 lore raw

PATCH v5 14/15 ASoC: Samsung: Update DMA interface

In reply to Boojin Kim

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.

---
 arch/arm/mach-s3c2410/include/mach/dma.h       |   10 +-
 arch/arm/mach-s3c64xx/include/mach/dma.h       |    2 +-
 arch/arm/plat-samsung/include/plat/dma-pl330.h |    2 +-
 sound/soc/samsung/ac97.c                       |   10 ++-
 sound/soc/samsung/dma.c                        |  144 ++++++++++--------------
 sound/soc/samsung/dma.h                        |    4 +-
 6 files changed, 78 insertions(+), 94 deletions(-)
arch/arm/mach-s3c2410/include/mach/dma.h +5 -5
index e61a91f..4e485ba 100644
@@ -50,6 +50,11 @@ enum dma_ch {
 	DMACH_MAX,		/* the end entry */
 };
 
+static inline bool samsung_dma_has_circular(void)
+{
+	return false;
+}
+
 static inline bool samsung_dma_is_dmadev(void)
 {
 	return false;
@@ -202,9 +207,4 @@ struct s3c2410_dma_chan {
 
 typedef unsigned long dma_device_t;
 
-static inline bool s3c_dma_has_circular(void)
-{
-	return false;
-}
-
 #endif /* __ASM_ARCH_DMA_H */
arch/arm/mach-s3c64xx/include/mach/dma.h +1 -1
index 49c3a53..74fdf25 100644
@@ -58,7 +58,7 @@ enum dma_ch {
 	DMACH_MAX		/* the end */
 };
 
-static __inline__ bool s3c_dma_has_circular(void)
+static inline bool samsung_dma_has_circular(void)
 {
 	return true;
 }
arch/arm/plat-samsung/include/plat/dma-pl330.h +1 -1
index 9a1dadb..2e55e59 100644
@@ -89,7 +89,7 @@ struct s3c2410_dma_client {
 	char	*name;
 };
 
-static inline bool s3c_dma_has_circular(void)
+static inline bool samsung_dma_has_circular(void)
 {
 	return true;
 }
sound/soc/samsung/ac97.c +8 -2
index f97110e..b4f9b00 100644
@@ -271,7 +271,10 @@ 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 +320,10 @@ 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;
 }
sound/soc/samsung/dma.c +60 -84

233 lines not on this page · raw message

sound/soc/samsung/dma.h +3 -1
index c506592..7d1ead7 100644
@@ -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
Signature · 1 line
1.7.1
#33 lore raw

PATCH 14/15 ASoC: Samsung: Update DMA interface

Quoted 8 lines · Boojin Kim

?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;

Quoted 7 lines

? ? ? ?pr_debug("Entered %s\n", __func__);

- ? ? ? if (s3c_dma_has_circular())
- ? ? ? ? ? ? ? limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
- ? ? ? else
- ? ? ? ? ? ? ? limit = prtd->dma_limit;
+ ? ? ? limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;

'dma_limit' is rendered useless, so you might want to remove it from 'struct runtime_data'
as well.

Quoted 73 lines

? ? ? ?pr_debug("%s: loaded %d, limit %d\n",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?__func__, prtd->dma_loaded, limit);

- ? ? ? while (prtd->dma_loaded < limit) {
- ? ? ? ? ? ? ? unsigned long len = prtd->dma_period;
+ ? ? ? dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);
+ ? ? ? 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) {
? ? ? ? ? ? ? ?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;
?}

sound/soc/samsung/dma.c +1 -3
-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;
-
- ? ? ? prtd = substream->runtime->private_data;
+ ? ? ? if (prtd->state & ST_RUNNING) {
+ ? ? ? ? ? ? ? prtd->dma_pos += prtd->dma_period;
+ ? ? ? ? ? ? ? if (prtd->dma_pos >= prtd->dma_end)
+ ? ? ? ? ? ? ? ? ? ? ? prtd->dma_pos = prtd->dma_start;

- ? ? ? if (substream)
- ? ? ? ? ? ? ? snd_pcm_period_elapsed(substream);
+ ? ? ? ? ? ? ? if (substream)
+ ? ? ? ? ? ? ? ? ? ? ? snd_pcm_period_elapsed(substream);

Quoted 14 lines

- ? ? ? spin_lock(&prtd->lock);
- ? ? ? if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
- ? ? ? ? ? ? ? prtd->dma_loaded--;
- ? ? ? ? ? ? ? dma_enqueue(substream);
+ ? ? ? ? ? ? ? spin_lock(&prtd->lock);
+ ? ? ? ? ? ? ? if (!samsung_dma_has_circular()) {
+ ? ? ? ? ? ? ? ? ? ? ? prtd->dma_loaded--;
+ ? ? ? ? ? ? ? ? ? ? ? dma_enqueue(substream);
+ ? ? ? ? ? ? ? }
+ ? ? ? ? ? ? ? spin_unlock(&prtd->lock);
? ? ? ?}
-
- ? ? ? spin_unlock(&prtd->lock);
?}

Since we set integer-constraint on number of periods, you could also discard bothering fractional boundaries. That would make things a lot simpler.

Quoted 8 lines
(quoted diff) +0 -0
@@ -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;

Quoted 7 lines

? ? ? ?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;

I wish you agreed and used

       prtd->params->ops->cmd(ch, enum some_cmd_options)
rather than having 4 separate callbacks
      prtd->params->ops->trigger(prtd->params->ch)
      prtd->params->ops->stop(prtd->params->ch)
     prtd->params->ops->flush(prtd->params->ch)
     prtd->params->ops->started(prtd->params->ch)
Quoted 22 lines
(quoted diff) +2 -11
@@ -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);
 
Quoted 2 lines

? ? ? ?/* 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

Isn't this a regression ?
dma_pointer() doesn't really return actual location of DMA activity anymore. Now it simply tells the last period done.
This would affect latencies in a bad way.

author
#34 lore raw

PATCH v5 14/15 ASoC: Samsung: Update DMA interface

Jassi Brar Wrote:

Quoted 27 lines

Sent: Tuesday, August 09, 2011 4:28 AM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Mark Brown; Grant Likely; Russell King; Liam Girdwood
Subject: Re: [PATCH 14/15] ASoC: Samsung: Update DMA interface

Quoted 13 lines · Boojin Kim

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;
sound/soc/samsung/dma.c +1 -3
-       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;

sound/soc/samsung/dma.c struct runtime_data { · line 81

Quoted 3 lines
sound/soc/samsung/dma.c +1 -2
-       else
-               limit = prtd->dma_limit;
+       limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
Quoted 3 lines

'dma_limit' is rendered useless, so you might want to remove it from 'struct runtime_data'
as well.

You're right. I will remove it in next cleanup patch

Quoted 151 lines

sound/soc/samsung/dma.c struct runtime_data {

Quoted 7 lines
       pr_debug("%s: loaded %d, limit %d\n",
                               __func__, prtd->dma_loaded, limit);
sound/soc/samsung/dma.c +1 -2
-       while (prtd->dma_loaded < limit) {
-               unsigned long len = prtd->dma_period;
+       dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC :

DMA_SLAVE);

Quoted 4 lines
sound/soc/samsung/dma.c +4 -0
+       dma_info.direction =
+               (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       dma_info.fp = audio_buffdone;

sound/soc/samsung/dma.c struct runtime_data {

Quoted 10 lines
sound/soc/samsung/dma.c +4 -3
+       dma_info.fp_param = substream;
+       dma_info.period = prtd->dma_period;
+       dma_info.len = prtd->dma_period*limit;
 
+       while (prtd->dma_loaded < limit) {
               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);

sound/soc/samsung/dma.c struct runtime_data {

Quoted 10 lines
sound/soc/samsung/dma.c +6 -2
+               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);

Quoted 47 lines
sound/soc/samsung/dma.c +13 -22
-               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;
-
-       prtd = substream->runtime->private_data;
+       if (prtd->state & ST_RUNNING) {
+               prtd->dma_pos += prtd->dma_period;
+               if (prtd->dma_pos >= prtd->dma_end)
+                       prtd->dma_pos = prtd->dma_start;
 
-       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);

sound/soc/samsung/dma.c struct runtime_data { · line 138

Quoted 10 lines
sound/soc/samsung/dma.c +6 -2
+               spin_lock(&prtd->lock);
+               if (!samsung_dma_has_circular()) {
+                       prtd->dma_loaded--;
+                       dma_enqueue(substream);
+               }
+               spin_unlock(&prtd->lock);
       }
-
-       spin_unlock(&prtd->lock);
 }

Since we set integer-constraint on number of periods, you could also discard bothering fractional boundaries. That would make things a lot simpler.

Review static int dma_trigger(struct

Quoted 1 line
(quoted diff) +0 -0
@@ -265,14 +250,14 @@ static int dma_trigger(struct

snd_pcm_substream *substream, int cmd)

sound/soc/samsung/dma.c static int dma_trigger(struct snd_pcm_substream *substream, int cmd)

Quoted 4 lines
sound/soc/samsung/dma.c +0 -1
       case SNDRV_PCM_TRIGGER_RESUME:
       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
               prtd->state |= ST_RUNNING;
-               s3c2410_dma_ctrl(prtd->params->channel,

S3C2410_DMAOP_START);

sound/soc/samsung/dma.c static int dma_trigger(struct snd_pcm_substream *substream, int cmd)

Quoted 8 lines
sound/soc/samsung/dma.c +1 -1
+               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);

sound/soc/samsung/dma.c static int dma_trigger(struct snd_pcm_substream *substream, int cmd) · line 261

Quoted 2 lines
sound/soc/samsung/dma.c +1 -0
+               prtd->params->ops->stop(prtd->params->ch);
               break;

I wish you agreed and used

       prtd->params->ops->cmd(ch, enum some_cmd_options)
rather than having 4 separate callbacks
      prtd->params->ops->trigger(prtd->params->ch)
      prtd->params->ops->stop(prtd->params->ch)
     prtd->params->ops->flush(prtd->params->ch)
     prtd->params->ops->started(prtd->params->ch)

Review dma_pointer(struct snd_pcm_substream

Quoted 1 line
(quoted diff) +0 -0
@@ -291,21 +276,12 @@ dma_pointer(struct snd_pcm_substream

*substream)

Quoted 12 lines
sound/soc/samsung/dma.c +0 -6
       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;

sound/soc/samsung/dma.c dma_pointer(struct snd_pcm_substream *substream)

Quoted 10 lines
sound/soc/samsung/dma.c +2 -5
-       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

Quoted 8 lines

Review dma_pointer(struct snd_pcm_substream · line 287

Quoted 1 line
(quoted diff) +0 -0
        * to out-of-bounds pointers. this is maybe due to the dma

engine

Isn't this a regression ?
dma_pointer() doesn't really return actual location of DMA activity anymore.
Now it simply tells the last period done.
This would affect latencies in a bad way.

Yes, This code makes the DMA position less accurately. But, This position is enough for audio DMA activity. Other drivers also use similar method to get the position.

author
#35 lore raw

PATCH v5 15/15 ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

In reply to Boojin Kim

This patch removes the samsung specific enum type 's3c2410_dmasrc' and uses 'dma_data_direction' instead.

---
 arch/arm/mach-s3c2410/include/mach/dma.h         |    2 +-
 arch/arm/mach-s3c2412/dma.c                      |    4 ++--
 arch/arm/mach-s3c64xx/dma.c                      |   10 +++++-----
 arch/arm/mach-s3c64xx/include/mach/dma.h         |    2 +-
 arch/arm/plat-s3c24xx/dma.c                      |   10 +++++-----
 arch/arm/plat-samsung/include/plat/dma-s3c24xx.h |    2 +-
 arch/arm/plat-samsung/include/plat/dma.h         |    9 +++------
 arch/arm/plat-samsung/s3c-dma-ops.c              |    5 +----
 drivers/mmc/host/s3cmci.c                        |    6 +++---
 9 files changed, 22 insertions(+), 28 deletions(-)
arch/arm/mach-s3c2410/include/mach/dma.h +1 -1
index 4e485ba..ae8e482 100644
@@ -174,7 +174,7 @@ struct s3c2410_dma_chan {
 	struct s3c2410_dma_client *client;
 
 	/* channel configuration */
-	enum s3c2410_dmasrc	 source;
+	enum dma_data_direction	 source;
 	enum dma_ch		 req_ch;
 	unsigned long		 dev_addr;
 	unsigned long		 load_timeout;
arch/arm/mach-s3c2412/dma.c +2 -2
index 7abecfc..b4fc3ba 100644
@@ -148,11 +148,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
 
 static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
 				  struct s3c24xx_dma_map *map,
-				  enum s3c2410_dmasrc dir)
+				  enum dma_data_direction dir)
 {
 	unsigned long chsel;
 
-	if (dir == S3C2410_DMASRC_HW)
+	if (dir == DMA_FROM_DEVICE)
 		chsel = map->channels_rx[0];
 	else
 		chsel = map->channels[0];
arch/arm/mach-s3c64xx/dma.c +5 -5
index b197171..d96ed4c 100644
@@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
 	u32 control0, control1;
 
 	switch (chan->source) {
-	case S3C2410_DMASRC_HW:
+	case DMA_FROM_DEVICE:
 		src = chan->dev_addr;
 		dst = data;
 		control0 = PL080_CONTROL_SRC_AHB2;
 		control0 |= PL080_CONTROL_DST_INCR;
 		break;
 
-	case S3C2410_DMASRC_MEM:
+	case DMA_TO_DEVICE:
 		src = data;
 		dst = chan->dev_addr;
 		control0 = PL080_CONTROL_DST_AHB2;
@@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue);
 
 
 int s3c2410_dma_devconfig(unsigned int channel,
-			  enum s3c2410_dmasrc source,
+			  enum dma_data_direction source,
 			  unsigned long devaddr)
 {
 	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(unsigned int channel,
 	pr_debug("%s: peripheral %d\n", __func__, peripheral);
 
 	switch (source) {
-	case S3C2410_DMASRC_HW:
+	case DMA_FROM_DEVICE:
 		config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
 		config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
 		break;
-	case S3C2410_DMASRC_MEM:
+	case DMA_TO_DEVICE:
 		config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
 		config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
 		break;
arch/arm/mach-s3c64xx/include/mach/dma.h +1 -1
index 74fdf25..fe1a98c 100644
@@ -99,7 +99,7 @@ struct s3c2410_dma_chan {
 	unsigned char		 peripheral;
 
 	unsigned int		 flags;
-	enum s3c2410_dmasrc	 source;
+	enum dma_data_direction	 source;
 
 
 	dma_addr_t		dev_addr;
arch/arm/plat-s3c24xx/dma.c +5 -5
index a79a8cc..036ff81 100644
@@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config);
  *
  * configure the dma source/destination hardware type and address
  *
- * source:    S3C2410_DMASRC_HW: source is hardware
- *            S3C2410_DMASRC_MEM: source is memory
+ * source:    DMA_FROM_DEVICE: source is hardware
+ *            DMA_TO_DEVICE: source is memory
  *
  * devaddr:   physical address of the source
 */
 
 int s3c2410_dma_devconfig(unsigned int channel,
-			  enum s3c2410_dmasrc source,
+			  enum dma_data_direction source,
 			  unsigned long devaddr)
 {
 	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(unsigned int channel,
 	 hwcfg |= S3C2410_DISRCC_INC;
 
 	switch (source) {
-	case S3C2410_DMASRC_HW:
+	case DMA_FROME_DEVICE:
 		/* source is hardware */
 		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
 			 __func__, devaddr, hwcfg);
@@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(unsigned int channel,
 		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
 		break;
 
-	case S3C2410_DMASRC_MEM:
+	case DMA_TO_DEVICE:
 		/* source is memory */
 		pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
 			 __func__, devaddr, hwcfg);
arch/arm/plat-samsung/include/plat/dma-s3c24xx.h +1 -1
index 336d5ac..1982829 100644
@@ -47,7 +47,7 @@ struct s3c24xx_dma_selection {
 
 	void	(*direction)(struct s3c2410_dma_chan *chan,
 			     struct s3c24xx_dma_map *map,
-			     enum s3c2410_dmasrc dir);
+			     enum dma_data_direction dir);
 };
 
 extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
arch/arm/plat-samsung/include/plat/dma.h +3 -6
index e87c6be..b395398 100644
@@ -10,17 +10,14 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/dma-mapping.h>
+
 enum s3c2410_dma_buffresult {
 	S3C2410_RES_OK,
 	S3C2410_RES_ERR,
 	S3C2410_RES_ABORT
 };
 
-enum s3c2410_dmasrc {
-	S3C2410_DMASRC_HW,		/* source is memory */
-	S3C2410_DMASRC_MEM		/* source is hardware */
-};
-
 /* enum s3c2410_chan_op
  *
  * operation codes passed to the DMA code by the user, and also used
@@ -111,7 +108,7 @@ extern int s3c2410_dma_config(unsigned int channel, int xferunit);
 */
 
 extern int s3c2410_dma_devconfig(unsigned int channel,
-		enum s3c2410_dmasrc source, unsigned long devaddr);
+		enum dma_data_direction source, unsigned long devaddr);
 
 /* s3c2410_dma_getposition
  *
arch/arm/plat-samsung/s3c-dma-ops.c +1 -4
index 33ab324..582333c 100644
@@ -48,10 +48,7 @@ static unsigned s3c_dma_request(enum dma_ch dma_ch,
 	data->ch = 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);
+	s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
 
 	if (info->cap == DMA_CYCLIC)
 		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
drivers/mmc/host/s3cmci.c +3 -3
index a04f87d..03cfdab 100644
@@ -913,9 +913,9 @@ request_done:
 }
 
 static void s3cmci_dma_setup(struct s3cmci_host *host,
-			     enum s3c2410_dmasrc source)
+			     enum dma_data_direction source)
 {
-	static enum s3c2410_dmasrc last_source = -1;
+	static enum dma_data_direction last_source = -1;
 	static int setup_ok;
 
 	if (last_source == source)
@@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
 
 	BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
 
-	s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);
+	s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
 
 	dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
Signature · 1 line
1.7.1
#36 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

In reply to Boojin Kim
Quoted 1 line · Boojin Kim

This patchset adds support DMA generic APIs for Samsung DMA.

Patches look good to me,

Are there any more users of the code in arch/arm/common/pl330.c? Else I think next step should be to move that file to drivers/dma/ and optionally merge it with the other pl330.c file there.

Thanks!
Linus Walleij

#38 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

Quoted 6 lines · Vinod
Quoted 4 lines · Linus Walleij
Quoted 1 line · Boojin Kim

This patchset adds support DMA generic APIs for Samsung DMA.

Quoted 7 lines
Quoted 2 lines

Patches look good to me,

Do you want these to go thru slave-dma tree or arm tree, I am okay with either...

Hi Vinod,

Thanks.

I'd like to keep its topic branch in my tree to avoid conflicts with other samsung stuff and I think, it should be merged into your slave-dma tree also for same reason.

git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git #next/topic-dma-pl330

Or if you want to make some branch for it in your tree, please let me know so that I can merge it in my tree also.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#39 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

Quoted 17 lines · Kukjin Kim
Quoted 6 lines · Vinod
Quoted 4 lines · Linus Walleij
Quoted 1 line · Boojin Kim

This patchset adds support DMA generic APIs for Samsung DMA.

Quoted 7 lines
Quoted 2 lines

Patches look good to me,

Do you want these to go thru slave-dma tree or arm tree, I am okay with either...

Hi Vinod,

Quoted 7 lines

Thanks.

I'd like to keep its topic branch in my tree to avoid conflicts with other samsung stuff and I think, it should be merged into your slave-dma tree also for same reason.

git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git #next/topic-dma-pl330

Or if you want to make some branch for it in your tree, please let me know so that I can merge it in my tree also.

Okay can you update this branch with latest patchset (I think there were few comments on last patchset). Once you add all acks let me know the branch, I will merge it to my next

Signature · 1 line
~Vinod
#40 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

Quoted 26 lines · Vinod
Quoted 4 lines · Kukjin Kim
Quoted 3 lines · Vinod
Quoted 1 line · Linus Walleij

On Wed, Jul 27, 2011 at 7:31 AM, Boojin Kim <[email protected]>

Quoted 8 lines · wrote:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

This patchset adds support DMA generic APIs for Samsung DMA.

Patches look good to me,

Quoted 8 lines
Quoted 2 lines

Do you want these to go thru slave-dma tree or arm tree, I am okay with either...

Hi Vinod,

Thanks.

I'd like to keep its topic branch in my tree to avoid conflicts with other samsung

stuff and I think, it should be merged into your slave-dma tree also for same reason.

Quoted 1 line
Quoted 8 lines
Quoted 1 line

git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git #next/topic-

dma-pl330

Quoted 2 lines

Or if you want to make some branch for it in your tree, please let me know so

that I can merge it in my tree also.
Okay can you update this branch with latest patchset (I think there were few comments on last patchset). Once you add all acks let me know the branch, I will merge it to my next

Hi,

I updated it so that you can merge it to yours.
I think, if any fixing is required on that, it should be small so can be fixed easily after this merging.

If any problems, please let me know :)

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#41 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

Quoted 36 lines · Kukjin Kim
Quoted 26 lines · Vinod
Quoted 4 lines · Kukjin Kim
Quoted 3 lines · Vinod
Quoted 1 line · Linus Walleij

On Wed, Jul 27, 2011 at 7:31 AM, Boojin Kim <[email protected]>

Quoted 8 lines · wrote:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

This patchset adds support DMA generic APIs for Samsung DMA.

Patches look good to me,

Quoted 8 lines
Quoted 2 lines

Do you want these to go thru slave-dma tree or arm tree, I am okay with either...

Hi Vinod,

Thanks.

I'd like to keep its topic branch in my tree to avoid conflicts with other samsung

stuff and I think, it should be merged into your slave-dma tree also for same reason.

Quoted 1 line
Quoted 8 lines
Quoted 1 line

git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git #next/topic-

dma-pl330

Quoted 2 lines

Or if you want to make some branch for it in your tree, please let me know so

that I can merge it in my tree also.
Okay can you update this branch with latest patchset (I think there were few comments on last patchset). Once you add all acks let me know the branch, I will merge it to my next

Quoted 7 lines

Hi,

I updated it so that you can merge it to yours.
I think, if any fixing is required on that, it should be small so can be fixed easily after this merging.

If any problems, please let me know :)

Well, that not how things are supposed to be done. Fixing an error introduced is not recommended, rather original patch set should be fixed.
Since you have already done 5 posting of your patch series, I am okay if you split things up, send me the parts that have already been reviewed and acked. I will host them on a branch for you. Once rest is reviewed and acked, I will merge this entire branch to my next.

Signature · 1 line
~Vinod
#42 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

Quoted 49 lines · Vinod
Quoted 7 lines · Kukjin Kim
Quoted 6 lines · Vinod
Quoted 4 lines · Kukjin Kim
Quoted 3 lines · Vinod
Quoted 1 line · Linus Walleij

On Wed, Jul 27, 2011 at 7:31 AM, Boojin Kim

<[email protected]>

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines · wrote:
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

This patchset adds support DMA generic APIs for Samsung DMA.

Patches look good to me,

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines

Do you want these to go thru slave-dma tree or arm tree, I am okay with either...

Hi Vinod,

Thanks.

I'd like to keep its topic branch in my tree to avoid conflicts with other

samsung

Quoted 4 lines
Quoted 4 lines

stuff and I think, it should be merged into your slave-dma tree also for same reason.

Quoted 2 lines

git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git

#next/topic-

Quoted 8 lines
Quoted 7 lines

dma-pl330

Quoted 2 lines

Or if you want to make some branch for it in your tree, please let me know so

that I can merge it in my tree also.
Okay can you update this branch with latest patchset (I think there were few comments on last patchset). Once you add all acks let me know the branch, I will merge it to my next

Quoted 4 lines

Hi,

I updated it so that you can merge it to yours.
I think, if any fixing is required on that, it should be small so can be fixed easily

after this merging.

Quoted 3 lines

If any problems, please let me know :)

Quoted 8 lines

Well, that not how things are supposed to be done. Fixing an error introduced is not recommended, rather original patch set should be fixed.
Since you have already done 5 posting of your patch series, I am okay if you split things up, send me the parts that have already been reviewed and acked. I will host them on a branch for you. Once rest is reviewed and acked, I will merge this entire branch to my next.

OK, Boojin will send whole series soon.
Then if you make a branch for me, I will merge it too.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#43 lore raw

v5 cover To use DMA generic APIs for Samsung DMA

Quoted 4 lines · Kukjin Kim
Quoted 1 line · Vinod

OK, Boojin will send whole series soon.
Then if you make a branch for me, I will merge it too.

Sure,
I have created a branh for you off my next

git://git.infradead.org/users/vkoul/slave-dma.git samsung_dma

I will apply your series after reviewing and once its acked by other maintainers will merge to my next

Signature · 1 line
~Vinod