Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] dmaengine: i.MX DMA series.
@ 2012-02-10 14:31 Javier Martin
  2012-02-10 14:31 ` [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma Javier Martin
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Javier Martin @ 2012-02-10 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

Patches 1-3 have already been sent to the list (not merged yet) 
but they are submitted so that everyone can get the whole picture
of what we're trying to do here.

A new patch(4) has been added which adds support for multiple 
descriptors.

[PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma.
[PATCH 2/4] i.MX DMA: Add support for 2D transfers.
[PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers.
[PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma.

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

* [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma.
  2012-02-10 14:31 [PATCH 0/4] dmaengine: i.MX DMA series Javier Martin
@ 2012-02-10 14:31 ` Javier Martin
  2012-02-10 14:31 ` [PATCH 2/4] i.MX DMA: Add support for 2D transfers Javier Martin
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Javier Martin @ 2012-02-10 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

MEMCPY transfers allow DMA copies from memory to
memory. This patch has been tested with dmatest
device driver.

Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
 drivers/dma/imx-dma.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)

diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 3296a73..9aa6e85 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -196,7 +196,8 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan)
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imx_dma_data *data = chan->private;
 
-	imxdmac->dma_request = data->dma_request;
+	if (data != NULL)
+		imxdmac->dma_request = data->dma_request;
 
 	dma_async_tx_descriptor_init(&imxdmac->desc, chan);
 	imxdmac->desc.tx_submit = imxdma_tx_submit;
@@ -328,6 +329,36 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
 	return &imxdmac->desc;
 }
 
+static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
+	struct dma_chan *chan, dma_addr_t dest,
+	dma_addr_t src, size_t len, unsigned long flags)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	int ret;
+
+	dev_dbg(imxdma->dev, "%s channel: %d src=0x%x dst=0x%x len=%d\n",
+			__func__, imxdmac->channel, src, dest, len);
+
+	if (imxdmac->status == DMA_IN_PROGRESS)
+		return NULL;
+	imxdmac->status = DMA_IN_PROGRESS;
+
+	ret = imx_dma_config_channel(imxdmac->imxdma_channel,
+			       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+			       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+			       0, 0);
+	if (ret)
+		return NULL;
+
+	ret = imx_dma_setup_single(imxdmac->imxdma_channel, src, len,
+				   dest, DMA_MODE_WRITE);
+	if (ret)
+		return NULL;
+
+	return &imxdmac->desc;
+}
+
 static void imxdma_issue_pending(struct dma_chan *chan)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
@@ -349,6 +380,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
 
 	dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
 	dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+	dma_cap_set(DMA_MEMCPY, imxdma->dma_device.cap_mask);
 
 	/* Initialize channel parameters */
 	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
@@ -382,11 +414,13 @@ static int __init imxdma_probe(struct platform_device *pdev)
 	imxdma->dma_device.device_tx_status = imxdma_tx_status;
 	imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
 	imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
+	imxdma->dma_device.device_prep_dma_memcpy = imxdma_prep_dma_memcpy;
 	imxdma->dma_device.device_control = imxdma_control;
 	imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
 
 	platform_set_drvdata(pdev, imxdma);
 
+	imxdma->dma_device.copy_align = 2; /* 2^2 = 4 bytes alignment */
 	imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
 	dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);
 
-- 
1.7.0.4

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

* [PATCH 2/4] i.MX DMA: Add support for 2D transfers.
  2012-02-10 14:31 [PATCH 0/4] dmaengine: i.MX DMA series Javier Martin
  2012-02-10 14:31 ` [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma Javier Martin
@ 2012-02-10 14:31 ` Javier Martin
  2012-02-22 13:18   ` Vinod Koul
  2012-02-10 14:31 ` [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers Javier Martin
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Javier Martin @ 2012-02-10 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

DMAC present in i.MX2 and i.MX1 chips have two
2D configuration slots that any DMA channel can
use to make 2D DMA transfers.

Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
 arch/arm/mach-imx/dma-v1.c              |   86 +++++++++++++++++++++++++++++++
 arch/arm/mach-imx/include/mach/dma-v1.h |    7 +++
 2 files changed, 93 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-imx/dma-v1.c b/arch/arm/mach-imx/dma-v1.c
index 42afc29..7401138 100644
--- a/arch/arm/mach-imx/dma-v1.c
+++ b/arch/arm/mach-imx/dma-v1.c
@@ -121,6 +121,9 @@ struct imx_dma_channel {
 
 	int in_use;
 
+	bool enabled_2d;
+	int slot_2d;
+
 	u32 ccr_from_device;
 	u32 ccr_to_device;
 
@@ -129,6 +132,13 @@ struct imx_dma_channel {
 	int hw_chaining;
 };
 
+struct imx_dma_2d_config {
+	u16		xsr;
+	u16		ysr;
+	u16		wsr;
+	int		count;
+};
+
 static void __iomem *imx_dmav1_baseaddr;
 
 static void imx_dmav1_writel(unsigned val, unsigned offset)
@@ -143,6 +153,9 @@ static unsigned imx_dmav1_readl(unsigned offset)
 
 static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
 
+static struct imx_dma_2d_config imx_dma_2d_slots[IMX_DMA_2D_SLOTS];
+static spinlock_t lock_2d;
+
 static struct clk *dma_clk;
 
 static int imx_dma_hw_chain(struct imx_dma_channel *imxdma)
@@ -369,6 +382,11 @@ imx_dma_config_channel(int channel, unsigned int config_port,
 	imxdma->ccr_from_device = config_port | (config_mem << 2) | dreq;
 	imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq;
 
+	if (imxdma->enabled_2d && (imxdma->slot_2d == IMX_DMA_2D_SLOT_B)) {
+		imxdma->ccr_from_device |= CCR_MSEL_B;
+		imxdma->ccr_to_device |= CCR_MSEL_B;
+	}
+
 	imx_dmav1_writel(dmareq, DMA_RSSR(channel));
 
 	return 0;
@@ -382,6 +400,63 @@ void imx_dma_config_burstlen(int channel, unsigned int burstlen)
 EXPORT_SYMBOL(imx_dma_config_burstlen);
 
 /**
+ * imx_dma_config_2d - prepare i.MX DMA channel for a 2D transfer.
+ * @channel: i.MX DMA channel number
+ * @x: x-size of the 2D window.
+ * @y: number of rows that make up the 2D window.
+ * @w: display size of the 2D window
+ */
+int imx_dma_config_2d(int channel, unsigned int x, unsigned int y,
+		      unsigned int w)
+{
+	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+	int slot = -1;
+	int i;
+
+	spin_lock(&lock_2d);
+	/* If the channel already owns a slot, free it first */
+	if (imxdma->enabled_2d) {
+		imx_dma_2d_slots[imxdma->slot_2d].count--;
+		imxdma->enabled_2d = false;
+	}
+	/* Try to get free 2D slot */
+	for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
+		if ((imx_dma_2d_slots[i].count > 0) &&
+		    ((imx_dma_2d_slots[i].xsr != x) ||
+		     (imx_dma_2d_slots[i].ysr != y) ||
+		     (imx_dma_2d_slots[i].wsr != w)))
+			continue;
+		slot = i;
+		break;
+	}
+	if (slot < 0)
+		return -EBUSY;
+
+	imx_dma_2d_slots[slot].xsr = x;
+	imx_dma_2d_slots[slot].ysr = y;
+	imx_dma_2d_slots[slot].wsr = w;
+	imx_dma_2d_slots[slot].count++;
+
+	spin_unlock(&lock_2d);
+
+	imxdma->slot_2d = slot;
+	imxdma->enabled_2d = true;
+
+	if (slot == IMX_DMA_2D_SLOT_A) {
+		imx_dmav1_writel(x, DMA_XSRA);
+		imx_dmav1_writel(y, DMA_YSRA);
+		imx_dmav1_writel(w, DMA_WSRA);
+	} else {
+		imx_dmav1_writel(x, DMA_XSRB);
+		imx_dmav1_writel(y, DMA_YSRB);
+		imx_dmav1_writel(w, DMA_WSRB);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(imx_dma_config_2d);
+
+/**
  * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification
  * handlers
  * @channel: i.MX DMA channel number
@@ -732,6 +807,13 @@ void imx_dma_free(int channel)
 		return;
 	}
 
+	spin_lock(&lock_2d);
+	if (imxdma->enabled_2d) {
+		imx_dma_2d_slots[imxdma->slot_2d].count--;
+		imxdma->enabled_2d = false;
+	}
+	spin_unlock(&lock_2d);
+
 	local_irq_save(flags);
 	/* Disable interrupts */
 	imx_dma_disable(channel);
@@ -840,6 +922,10 @@ static int __init imx_dma_init(void)
 		imx_dma_channels[i].dma_num = i;
 	}
 
+	for (i = 0; i < IMX_DMA_2D_SLOTS; i++)
+		imx_dma_2d_slots[i].count = 0;
+	spin_lock_init(&lock_2d);
+
 	return ret;
 }
 
diff --git a/arch/arm/mach-imx/include/mach/dma-v1.h b/arch/arm/mach-imx/include/mach/dma-v1.h
index ac6fd71..bab9183 100644
--- a/arch/arm/mach-imx/include/mach/dma-v1.h
+++ b/arch/arm/mach-imx/include/mach/dma-v1.h
@@ -30,6 +30,10 @@
 #include <mach/dma.h>
 
 #define IMX_DMA_CHANNELS  16
+#define IMX_DMA_2D_SLOTS   2
+
+#define IMX_DMA_2D_SLOT_A  0
+#define IMX_DMA_2D_SLOT_B  1
 
 #define DMA_MODE_READ		0
 #define DMA_MODE_WRITE		1
@@ -64,6 +68,9 @@ void
 imx_dma_config_burstlen(int channel, unsigned int burstlen);
 
 int
+imx_dma_config_2d(int channel, unsigned int x, unsigned int y, unsigned int w);
+
+int
 imx_dma_setup_single(int channel, dma_addr_t dma_address,
 		unsigned int dma_length, unsigned int dev_addr,
 		unsigned int dmamode);
-- 
1.7.0.4

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

* [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers.
  2012-02-10 14:31 [PATCH 0/4] dmaengine: i.MX DMA series Javier Martin
  2012-02-10 14:31 ` [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma Javier Martin
  2012-02-10 14:31 ` [PATCH 2/4] i.MX DMA: Add support for 2D transfers Javier Martin
@ 2012-02-10 14:31 ` Javier Martin
  2012-02-10 14:31 ` [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma Javier Martin
  2012-02-14 11:51 ` [PATCH 0/4] dmaengine: i.MX DMA series javier Martin
  4 siblings, 0 replies; 10+ messages in thread
From: Javier Martin @ 2012-02-10 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

i.MX2 and i.MX1 chips have the possibility to do
interleaved transfers with one constraint: only one
chunk can be used (i.e. only 2D transfers are allowed).

Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
 drivers/dma/imx-dma.c |   53 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 9aa6e85..366a248 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -359,6 +359,57 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
 	return &imxdmac->desc;
 }
 
+static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
+	struct dma_chan *chan, struct dma_interleaved_template *xt,
+	unsigned long flags)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	unsigned int src_config, dst_config;
+	unsigned int x, y, w;
+	int ret;
+
+	dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%x dst_start=0x%x\n"
+		"   src_sgl=%s dst_sgl=%s numf=%d frame_size=%d\n", __func__,
+		imxdmac->channel, xt->src_start, xt->dst_start,
+		xt->src_sgl ? "true" : "false", xt->dst_sgl ? "true" : "false",
+		xt->numf, xt->frame_size);
+
+	if (imxdmac->status == DMA_IN_PROGRESS)
+		return NULL;
+	imxdmac->status = DMA_IN_PROGRESS;
+
+
+	if (xt->frame_size != 1 || xt->numf <= 0 || xt->dir != DMA_MEM_TO_MEM)
+		return NULL;
+
+	y = xt->numf;
+	x = xt->sgl[0].size;
+	w = xt->sgl[0].icg + x;
+	ret = imx_dma_config_2d(imxdmac->imxdma_channel, x, y, w);
+	if (ret)
+		return NULL;
+
+	src_config = IMX_DMA_MEMSIZE_32;
+	dst_config = IMX_DMA_MEMSIZE_32;
+	if (xt->src_sgl)
+		src_config |= IMX_DMA_TYPE_2D;
+	if (xt->dst_sgl)
+		dst_config |= IMX_DMA_TYPE_2D;
+
+	ret = imx_dma_config_channel(imxdmac->imxdma_channel,
+				     dst_config, src_config, 0, 0);
+	if (ret)
+		return NULL;
+
+	ret = imx_dma_setup_single(imxdmac->imxdma_channel, xt->src_start,
+				   x * y, xt->dst_start, DMA_MODE_WRITE);
+	if (ret)
+		return NULL;
+
+	return &imxdmac->desc;
+}
+
 static void imxdma_issue_pending(struct dma_chan *chan)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
@@ -381,6 +432,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
 	dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
 	dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
 	dma_cap_set(DMA_MEMCPY, imxdma->dma_device.cap_mask);
+	dma_cap_set(DMA_INTERLEAVE, imxdma->dma_device.cap_mask);
 
 	/* Initialize channel parameters */
 	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
@@ -415,6 +467,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
 	imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
 	imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
 	imxdma->dma_device.device_prep_dma_memcpy = imxdma_prep_dma_memcpy;
+	imxdma->dma_device.device_prep_interleaved_dma = imxdma_prep_dma_interleaved;
 	imxdma->dma_device.device_control = imxdma_control;
 	imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
 
-- 
1.7.0.4

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

* [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma.
  2012-02-10 14:31 [PATCH 0/4] dmaengine: i.MX DMA series Javier Martin
                   ` (2 preceding siblings ...)
  2012-02-10 14:31 ` [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers Javier Martin
@ 2012-02-10 14:31 ` Javier Martin
  2012-02-14 11:51 ` [PATCH 0/4] dmaengine: i.MX DMA series javier Martin
  4 siblings, 0 replies; 10+ messages in thread
From: Javier Martin @ 2012-02-10 14:31 UTC (permalink / raw)
  To: linux-arm-kernel

dmaengine specifies the possibility that several descriptors
can be queued for transfer. It also indicates that tasklets
must be used for DMA callbacks.

Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
 drivers/dma/imx-dma.c |  385 ++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 281 insertions(+), 104 deletions(-)

diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 366a248..006f271 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -5,6 +5,7 @@
  * found on i.MX1/21/27
  *
  * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com>
  *
  * The code contained herein is licensed under the GNU General Public
  * License. You may obtain a copy of the GNU General Public License
@@ -13,6 +14,7 @@
  * http://www.opensource.org/licenses/gpl-license.html
  * http://www.gnu.org/copyleft/gpl.html
  */
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -30,19 +32,52 @@
 #include <mach/dma-v1.h>
 #include <mach/hardware.h>
 
+#define IMXDMA_MAX_CHAN_DESCRIPTORS	16
+
+enum  imxdma_prep_type {
+	IMXDMA_DESC_MEMCPY,
+	IMXDMA_DESC_INTERLEAVED,
+	IMXDMA_DESC_SLAVE_SG,
+	IMXDMA_DESC_CYCLIC,
+};
+
+struct imxdma_desc {
+	struct list_head		node;
+	struct dma_async_tx_descriptor	desc;
+	enum dma_status			status;
+	dma_addr_t			src;
+	dma_addr_t			dest;
+	size_t				len;
+	unsigned int			dmamode;
+	enum imxdma_prep_type		type;
+	/* For memcpy and interleaved */
+	unsigned int			config_port;
+	unsigned int			config_mem;
+	/* For interleaved transfers */
+	unsigned int			x;
+	unsigned int			y;
+	unsigned int			w;
+	/* For slave sg and cyclic */
+	struct scatterlist		*sg;
+	unsigned int			sgcount;
+};
+
 struct imxdma_channel {
 	struct imxdma_engine		*imxdma;
 	unsigned int			channel;
 	unsigned int			imxdma_channel;
 
+	struct tasklet_struct		dma_tasklet;
+	struct list_head		ld_free;
+	struct list_head		ld_queue;
+	struct list_head		ld_active;
+	int				descs_allocated;
 	enum dma_slave_buswidth		word_size;
 	dma_addr_t			per_address;
 	u32				watermark_level;
 	struct dma_chan			chan;
 	spinlock_t			lock;
-	struct dma_async_tx_descriptor	desc;
 	dma_cookie_t			last_completed;
-	enum dma_status			status;
 	int				dma_request;
 	struct scatterlist		*sg_list;
 };
@@ -61,27 +96,31 @@ static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
 	return container_of(chan, struct imxdma_channel, chan);
 }
 
-static void imxdma_handle(struct imxdma_channel *imxdmac)
+static inline bool imxdma_chan_is_doing_cyclic(struct imxdma_channel *imxdmac)
 {
-	if (imxdmac->desc.callback)
-		imxdmac->desc.callback(imxdmac->desc.callback_param);
-	imxdmac->last_completed = imxdmac->desc.cookie;
+	struct imxdma_desc *desc;
+
+	if (!list_empty(&imxdmac->ld_active)) {
+		desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc,
+					node);
+		if (desc->type == IMXDMA_DESC_CYCLIC)
+			return true;
+	}
+	return false;
 }
 
 static void imxdma_irq_handler(int channel, void *data)
 {
 	struct imxdma_channel *imxdmac = data;
 
-	imxdmac->status = DMA_SUCCESS;
-	imxdma_handle(imxdmac);
+	tasklet_schedule(&imxdmac->dma_tasklet);
 }
 
 static void imxdma_err_handler(int channel, void *data, int error)
 {
 	struct imxdma_channel *imxdmac = data;
 
-	imxdmac->status = DMA_ERROR;
-	imxdma_handle(imxdmac);
+	tasklet_schedule(&imxdmac->dma_tasklet);
 }
 
 static void imxdma_progression(int channel, void *data,
@@ -89,8 +128,88 @@ static void imxdma_progression(int channel, void *data,
 {
 	struct imxdma_channel *imxdmac = data;
 
-	imxdmac->status = DMA_SUCCESS;
-	imxdma_handle(imxdmac);
+	tasklet_schedule(&imxdmac->dma_tasklet);
+}
+
+static int imxdma_xfer_desc(struct imxdma_desc *d)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
+	int ret;
+
+	/* Configure and enable */
+	switch (d->type) {
+	case IMXDMA_DESC_INTERLEAVED:
+		ret = imx_dma_config_2d(imxdmac->imxdma_channel,
+					d->x, d->y, d->w);
+		if (ret < 0)
+			return ret;
+	case IMXDMA_DESC_MEMCPY:
+		ret = imx_dma_config_channel(imxdmac->imxdma_channel,
+					  d->config_port, d->config_mem, 0, 0);
+		if (ret < 0)
+			return ret;
+		ret = imx_dma_setup_single(imxdmac->imxdma_channel, d->src,
+					   d->len, d->dest, d->dmamode);
+		if (ret < 0)
+			return ret;
+		break;
+	case IMXDMA_DESC_CYCLIC:
+		ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
+							imxdma_progression);
+		if (ret < 0)
+			return ret;
+	case IMXDMA_DESC_SLAVE_SG:
+		if (d->dmamode == DMA_MODE_READ)
+			ret = imx_dma_setup_sg(imxdmac->imxdma_channel, d->sg,
+				       d->sgcount, d->len, d->src, d->dmamode);
+		else
+			ret = imx_dma_setup_sg(imxdmac->imxdma_channel, d->sg,
+				      d->sgcount, d->len, d->dest, d->dmamode);
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		return -EINVAL;
+	}
+	imx_dma_enable(imxdmac->imxdma_channel);
+	return 0;
+}
+
+static void imxdma_tasklet(unsigned long data)
+{
+	struct imxdma_channel *imxdmac = (void *)data;
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc;
+
+	spin_lock(&imxdmac->lock);
+
+	if (list_empty(&imxdmac->ld_active)) {
+		/* Someone might have called terminate all */
+		goto out;
+	}
+	desc = list_first_entry(&imxdmac->ld_active, struct imxdma_desc, node);
+
+	if (desc->desc.callback)
+		desc->desc.callback(desc->desc.callback_param);
+
+	imxdmac->last_completed = desc->desc.cookie;
+
+	/* If we are dealing with a cyclic descriptor keep it on ld_active */
+	if (imxdma_chan_is_doing_cyclic(imxdmac))
+		goto out;
+
+	list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
+
+	if (!list_empty(&imxdmac->ld_queue)) {
+		desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
+					node);
+		list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
+		if (imxdma_xfer_desc(desc) < 0)
+			dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc\n",
+				 __func__, imxdmac->channel);
+	}
+out:
+	spin_unlock(&imxdmac->lock);
 }
 
 static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -99,12 +218,17 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct dma_slave_config *dmaengine_cfg = (void *)arg;
 	int ret;
+	unsigned long flags;
 	unsigned int mode = 0;
 
 	switch (cmd) {
 	case DMA_TERMINATE_ALL:
-		imxdmac->status = DMA_ERROR;
 		imx_dma_disable(imxdmac->imxdma_channel);
+
+		spin_lock_irqsave(&imxdmac->lock, flags);
+		list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+		list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
+		spin_unlock_irqrestore(&imxdmac->lock, flags);
 		return 0;
 	case DMA_SLAVE_CONFIG:
 		if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
@@ -155,11 +279,14 @@ static enum dma_status imxdma_tx_status(struct dma_chan *chan,
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	dma_cookie_t last_used;
 	enum dma_status ret;
+	unsigned long flags;
 
+	spin_lock_irqsave(&imxdmac->lock, flags);
 	last_used = chan->cookie;
 
 	ret = dma_async_is_complete(cookie, imxdmac->last_completed, last_used);
 	dma_set_tx_state(txstate, imxdmac->last_completed, last_used, 0);
+	spin_unlock_irqrestore(&imxdmac->lock, flags);
 
 	return ret;
 }
@@ -172,7 +299,6 @@ static dma_cookie_t imxdma_assign_cookie(struct imxdma_channel *imxdma)
 		cookie = 1;
 
 	imxdma->chan.cookie = cookie;
-	imxdma->desc.cookie = cookie;
 
 	return cookie;
 }
@@ -181,12 +307,15 @@ static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
 	dma_cookie_t cookie;
+	unsigned long flags;
 
-	spin_lock_irq(&imxdmac->lock);
+	spin_lock_irqsave(&imxdmac->lock, flags);
 
+	list_move_tail(imxdmac->ld_free.next, &imxdmac->ld_queue);
 	cookie = imxdma_assign_cookie(imxdmac);
+	tx->cookie = cookie;
 
-	spin_unlock_irq(&imxdmac->lock);
+	spin_unlock_irqrestore(&imxdmac->lock, flags);
 
 	return cookie;
 }
@@ -199,21 +328,48 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan)
 	if (data != NULL)
 		imxdmac->dma_request = data->dma_request;
 
-	dma_async_tx_descriptor_init(&imxdmac->desc, chan);
-	imxdmac->desc.tx_submit = imxdma_tx_submit;
-	/* txd.flags will be overwritten in prep funcs */
-	imxdmac->desc.flags = DMA_CTRL_ACK;
+	while (imxdmac->descs_allocated < IMXDMA_MAX_CHAN_DESCRIPTORS) {
+		struct imxdma_desc *desc;
+
+		desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+		if (!desc)
+			break;
+		__memzero(&desc->desc, sizeof(struct dma_async_tx_descriptor));
+		dma_async_tx_descriptor_init(&desc->desc, chan);
+		desc->desc.tx_submit = imxdma_tx_submit;
+		/* txd.flags will be overwritten in prep funcs */
+		desc->desc.flags = DMA_CTRL_ACK;
+		desc->status = DMA_SUCCESS;
+
+		list_add_tail(&desc->node, &imxdmac->ld_free);
+		imxdmac->descs_allocated++;
+	}
 
-	imxdmac->status = DMA_SUCCESS;
+	if (!imxdmac->descs_allocated)
+		return -ENOMEM;
 
-	return 0;
+	return imxdmac->descs_allocated;
 }
 
 static void imxdma_free_chan_resources(struct dma_chan *chan)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_desc *desc, *_desc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imxdmac->lock, flags);
 
 	imx_dma_disable(imxdmac->imxdma_channel);
+	list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+	list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
+
+	spin_unlock_irqrestore(&imxdmac->lock, flags);
+
+	list_for_each_entry_safe(desc, _desc, &imxdmac->ld_free, node) {
+		kfree(desc);
+		imxdmac->descs_allocated--;
+	}
+	INIT_LIST_HEAD(&imxdmac->ld_free);
 
 	if (imxdmac->sg_list) {
 		kfree(imxdmac->sg_list);
@@ -228,23 +384,19 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct scatterlist *sg;
-	int i, ret, dma_length = 0;
-	unsigned int dmamode;
+	int i, dma_length = 0;
+	struct imxdma_desc *desc;
 
-	if (imxdmac->status == DMA_IN_PROGRESS)
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
 
-	imxdmac->status = DMA_IN_PROGRESS;
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
 
 	for_each_sg(sgl, sg, sg_len, i) {
 		dma_length += sg->length;
 	}
 
-	if (direction == DMA_DEV_TO_MEM)
-		dmamode = DMA_MODE_READ;
-	else
-		dmamode = DMA_MODE_WRITE;
-
 	switch (imxdmac->word_size) {
 	case DMA_SLAVE_BUSWIDTH_4_BYTES:
 		if (sgl->length & 3 || sgl->dma_address & 3)
@@ -260,12 +412,21 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
 		return NULL;
 	}
 
-	ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
-		 dma_length, imxdmac->per_address, dmamode);
-	if (ret)
-		return NULL;
+	desc->type = IMXDMA_DESC_SLAVE_SG;
+	desc->sg = sgl;
+	desc->sgcount = sg_len;
+	desc->len = dma_length;
+	if (direction == DMA_DEV_TO_MEM) {
+		desc->dmamode = DMA_MODE_READ;
+		desc->src = imxdmac->per_address;
+	} else {
+		desc->dmamode = DMA_MODE_WRITE;
+		desc->dest = imxdmac->per_address;
+	}
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
 
-	return &imxdmac->desc;
+	return &desc->desc;
 }
 
 static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
@@ -274,23 +435,18 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imxdma_engine *imxdma = imxdmac->imxdma;
-	int i, ret;
+	struct imxdma_desc *desc;
+	int i;
 	unsigned int periods = buf_len / period_len;
-	unsigned int dmamode;
 
 	dev_dbg(imxdma->dev, "%s channel: %d buf_len=%d period_len=%d\n",
 			__func__, imxdmac->channel, buf_len, period_len);
 
-	if (imxdmac->status == DMA_IN_PROGRESS)
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
-	imxdmac->status = DMA_IN_PROGRESS;
 
-	ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
-			imxdma_progression);
-	if (ret) {
-		dev_err(imxdma->dev, "Failed to setup the DMA handler\n");
-		return NULL;
-	}
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
 
 	if (imxdmac->sg_list)
 		kfree(imxdmac->sg_list);
@@ -316,17 +472,21 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
 	imxdmac->sg_list[periods].page_link =
 		((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
 
-	if (direction == DMA_DEV_TO_MEM)
-		dmamode = DMA_MODE_READ;
-	else
-		dmamode = DMA_MODE_WRITE;
-
-	ret = imx_dma_setup_sg(imxdmac->imxdma_channel, imxdmac->sg_list, periods,
-		 IMX_DMA_LENGTH_LOOP, imxdmac->per_address, dmamode);
-	if (ret)
-		return NULL;
+	desc->type = IMXDMA_DESC_CYCLIC;
+	desc->sg = imxdmac->sg_list;
+	desc->sgcount = periods;
+	desc->len = IMX_DMA_LENGTH_LOOP;
+	if (direction == DMA_DEV_TO_MEM) {
+		desc->dmamode = DMA_MODE_READ;
+		desc->src = imxdmac->per_address;
+	} else {
+		desc->dmamode = DMA_MODE_WRITE;
+		desc->dest = imxdmac->per_address;
+	}
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
 
-	return &imxdmac->desc;
+	return &desc->desc;
 }
 
 static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
@@ -335,28 +495,28 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_memcpy(
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imxdma_engine *imxdma = imxdmac->imxdma;
-	int ret;
+	struct imxdma_desc *desc;
 
 	dev_dbg(imxdma->dev, "%s channel: %d src=0x%x dst=0x%x len=%d\n",
 			__func__, imxdmac->channel, src, dest, len);
 
-	if (imxdmac->status == DMA_IN_PROGRESS)
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
-	imxdmac->status = DMA_IN_PROGRESS;
 
-	ret = imx_dma_config_channel(imxdmac->imxdma_channel,
-			       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-			       IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
-			       0, 0);
-	if (ret)
-		return NULL;
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
 
-	ret = imx_dma_setup_single(imxdmac->imxdma_channel, src, len,
-				   dest, DMA_MODE_WRITE);
-	if (ret)
-		return NULL;
+	desc->type = IMXDMA_DESC_MEMCPY;
+	desc->src = src;
+	desc->dest = dest;
+	desc->len = len;
+	desc->dmamode = DMA_MODE_WRITE;
+	desc->config_port = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
+	desc->config_mem = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR;
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
 
-	return &imxdmac->desc;
+	return &desc->desc;
 }
 
 static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
@@ -365,57 +525,67 @@ static struct dma_async_tx_descriptor *imxdma_prep_dma_interleaved(
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
 	struct imxdma_engine *imxdma = imxdmac->imxdma;
-	unsigned int src_config, dst_config;
-	unsigned int x, y, w;
-	int ret;
+	struct imxdma_desc *desc;
 
 	dev_dbg(imxdma->dev, "%s channel: %d src_start=0x%x dst_start=0x%x\n"
-		"   src_sgl=%s dst_sgl=%s numf=%d frame_size=%d\n", __func__,
+		"   src_sgl=%s dst_sgl=%s numf=%d frame_size=%d\n"
+		"   chunk size=%hu, chunk icg=%hu\n", __func__,
 		imxdmac->channel, xt->src_start, xt->dst_start,
 		xt->src_sgl ? "true" : "false", xt->dst_sgl ? "true" : "false",
-		xt->numf, xt->frame_size);
+		xt->numf, xt->frame_size, xt->sgl[0].size, xt->sgl[0].icg);
 
-	if (imxdmac->status == DMA_IN_PROGRESS)
+	if (list_empty(&imxdmac->ld_free) ||
+	    imxdma_chan_is_doing_cyclic(imxdmac))
 		return NULL;
-	imxdmac->status = DMA_IN_PROGRESS;
-
 
 	if (xt->frame_size != 1 || xt->numf <= 0 || xt->dir != DMA_MEM_TO_MEM)
 		return NULL;
 
-	y = xt->numf;
-	x = xt->sgl[0].size;
-	w = xt->sgl[0].icg + x;
-	ret = imx_dma_config_2d(imxdmac->imxdma_channel, x, y, w);
-	if (ret)
-		return NULL;
+	desc = list_first_entry(&imxdmac->ld_free, struct imxdma_desc, node);
 
-	src_config = IMX_DMA_MEMSIZE_32;
-	dst_config = IMX_DMA_MEMSIZE_32;
+	desc->type = IMXDMA_DESC_INTERLEAVED;
+	desc->y = xt->numf;
+	desc->x = xt->sgl[0].size;
+	desc->w = xt->sgl[0].icg + desc->x;
+	desc->config_mem = IMX_DMA_MEMSIZE_32;
+	desc->config_port = IMX_DMA_MEMSIZE_32;
 	if (xt->src_sgl)
-		src_config |= IMX_DMA_TYPE_2D;
+		desc->config_mem |= IMX_DMA_TYPE_2D;
 	if (xt->dst_sgl)
-		dst_config |= IMX_DMA_TYPE_2D;
-
-	ret = imx_dma_config_channel(imxdmac->imxdma_channel,
-				     dst_config, src_config, 0, 0);
-	if (ret)
-		return NULL;
-
-	ret = imx_dma_setup_single(imxdmac->imxdma_channel, xt->src_start,
-				   x * y, xt->dst_start, DMA_MODE_WRITE);
-	if (ret)
-		return NULL;
-
-	return &imxdmac->desc;
+		desc->config_port |= IMX_DMA_TYPE_2D;
+	desc->src = xt->src_start;
+	desc->dest = xt->dst_start;
+	desc->len = desc->x * desc->y;
+	desc->dmamode = DMA_MODE_WRITE;
+	desc->desc.callback = NULL;
+	desc->desc.callback_param = NULL;
+
+	return &desc->desc;
 }
 
 static void imxdma_issue_pending(struct dma_chan *chan)
 {
 	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
-
-	if (imxdmac->status == DMA_IN_PROGRESS)
-		imx_dma_enable(imxdmac->imxdma_channel);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	struct imxdma_desc *desc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imxdmac->lock, flags);
+	if (list_empty(&imxdmac->ld_active) &&
+	    !list_empty(&imxdmac->ld_queue)) {
+		desc = list_first_entry(&imxdmac->ld_queue,
+					struct imxdma_desc, node);
+
+		if (imxdma_xfer_desc(desc) < 0) {
+			dev_warn(imxdma->dev,
+				 "%s: channel: %d couldn't issue DMA xfer\n",
+				 __func__, imxdmac->channel);
+		} else {
+			list_move_tail(imxdmac->ld_queue.next,
+				       &imxdmac->ld_active);
+		}
+	}
+	spin_unlock_irqrestore(&imxdmac->lock, flags);
 }
 
 static int __init imxdma_probe(struct platform_device *pdev)
@@ -451,11 +621,18 @@ static int __init imxdma_probe(struct platform_device *pdev)
 		imxdmac->imxdma = imxdma;
 		spin_lock_init(&imxdmac->lock);
 
+		INIT_LIST_HEAD(&imxdmac->ld_queue);
+		INIT_LIST_HEAD(&imxdmac->ld_free);
+		INIT_LIST_HEAD(&imxdmac->ld_active);
+
+		tasklet_init(&imxdmac->dma_tasklet, imxdma_tasklet,
+			     (unsigned long)imxdmac);
 		imxdmac->chan.device = &imxdma->dma_device;
 		imxdmac->channel = i;
 
 		/* Add the channel to the DMAC list */
-		list_add_tail(&imxdmac->chan.device_node, &imxdma->dma_device.channels);
+		list_add_tail(&imxdmac->chan.device_node,
+			      &imxdma->dma_device.channels);
 	}
 
 	imxdma->dev = &pdev->dev;
-- 
1.7.0.4

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

* [PATCH 0/4] dmaengine: i.MX DMA series.
  2012-02-10 14:31 [PATCH 0/4] dmaengine: i.MX DMA series Javier Martin
                   ` (3 preceding siblings ...)
  2012-02-10 14:31 ` [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma Javier Martin
@ 2012-02-14 11:51 ` javier Martin
  2012-02-22 13:21   ` Vinod Koul
  4 siblings, 1 reply; 10+ messages in thread
From: javier Martin @ 2012-02-14 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

On 10 February 2012 15:31, Javier Martin
<javier.martin@vista-silicon.com> wrote:
> Patches 1-3 have already been sent to the list (not merged yet)
> but they are submitted so that everyone can get the whole picture
> of what we're trying to do here.
>
> A new patch(4) has been added which adds support for multiple
> descriptors.
>
> [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma.
> [PATCH 2/4] i.MX DMA: Add support for 2D transfers.
> [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers.
> [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma.

Hi,
what do you think of this series?

Vinod: your concern about patch 1 is solved in patch 4
Sascha: I know you are not comfortable with patch 2 since it adds code
to a file which is meant to be removed. However, is there a chance you
accept it without me having to rewrite the whole series?

Regards.
-- 
Javier Martin
Vista Silicon S.L.
CDTUC - FASE C - Oficina S-345
Avda de los Castros s/n
39005- Santander. Cantabria. Spain
+34 942 25 32 60
www.vista-silicon.com

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

* [PATCH 2/4] i.MX DMA: Add support for 2D transfers.
  2012-02-10 14:31 ` [PATCH 2/4] i.MX DMA: Add support for 2D transfers Javier Martin
@ 2012-02-22 13:18   ` Vinod Koul
  0 siblings, 0 replies; 10+ messages in thread
From: Vinod Koul @ 2012-02-22 13:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2012-02-10 at 15:31 +0100, Javier Martin wrote:
> DMAC present in i.MX2 and i.MX1 chips have two
> 2D configuration slots that any DMA channel can
> use to make 2D DMA transfers.
> 
> Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
> ---
>  arch/arm/mach-imx/dma-v1.c              |   86 +++++++++++++++++++++++++++++++
>  arch/arm/mach-imx/include/mach/dma-v1.h |    7 +++
>  2 files changed, 93 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-imx/dma-v1.c b/arch/arm/mach-imx/dma-v1.c
> index 42afc29..7401138 100644
> --- a/arch/arm/mach-imx/dma-v1.c
> +++ b/arch/arm/mach-imx/dma-v1.c
> @@ -121,6 +121,9 @@ struct imx_dma_channel {
>  
>  	int in_use;
>  
> +	bool enabled_2d;
> +	int slot_2d;
> +
>  	u32 ccr_from_device;
>  	u32 ccr_to_device;
>  
> @@ -129,6 +132,13 @@ struct imx_dma_channel {
>  	int hw_chaining;
>  };
>  
> +struct imx_dma_2d_config {
> +	u16		xsr;
> +	u16		ysr;
> +	u16		wsr;
> +	int		count;
> +};
> +
>  static void __iomem *imx_dmav1_baseaddr;
>  
>  static void imx_dmav1_writel(unsigned val, unsigned offset)
> @@ -143,6 +153,9 @@ static unsigned imx_dmav1_readl(unsigned offset)
>  
>  static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
>  
> +static struct imx_dma_2d_config imx_dma_2d_slots[IMX_DMA_2D_SLOTS];
> +static spinlock_t lock_2d;
> +
>  static struct clk *dma_clk;
>  
>  static int imx_dma_hw_chain(struct imx_dma_channel *imxdma)
> @@ -369,6 +382,11 @@ imx_dma_config_channel(int channel, unsigned int config_port,
>  	imxdma->ccr_from_device = config_port | (config_mem << 2) | dreq;
>  	imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq;
>  
> +	if (imxdma->enabled_2d && (imxdma->slot_2d == IMX_DMA_2D_SLOT_B)) {
> +		imxdma->ccr_from_device |= CCR_MSEL_B;
> +		imxdma->ccr_to_device |= CCR_MSEL_B;
> +	}
> +
>  	imx_dmav1_writel(dmareq, DMA_RSSR(channel));
>  
>  	return 0;
> @@ -382,6 +400,63 @@ void imx_dma_config_burstlen(int channel, unsigned int burstlen)
>  EXPORT_SYMBOL(imx_dma_config_burstlen);
>  
>  /**
> + * imx_dma_config_2d - prepare i.MX DMA channel for a 2D transfer.
> + * @channel: i.MX DMA channel number
> + * @x: x-size of the 2D window.
> + * @y: number of rows that make up the 2D window.
> + * @w: display size of the 2D window
> + */
> +int imx_dma_config_2d(int channel, unsigned int x, unsigned int y,
> +		      unsigned int w)
> +{
> +	struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
> +	int slot = -1;
> +	int i;
> +
> +	spin_lock(&lock_2d);
> +	/* If the channel already owns a slot, free it first */
> +	if (imxdma->enabled_2d) {
> +		imx_dma_2d_slots[imxdma->slot_2d].count--;
> +		imxdma->enabled_2d = false;
> +	}
> +	/* Try to get free 2D slot */
> +	for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
> +		if ((imx_dma_2d_slots[i].count > 0) &&
> +		    ((imx_dma_2d_slots[i].xsr != x) ||
> +		     (imx_dma_2d_slots[i].ysr != y) ||
> +		     (imx_dma_2d_slots[i].wsr != w)))
> +			continue;
> +		slot = i;
> +		break;
> +	}
> +	if (slot < 0)
> +		return -EBUSY;
> +
> +	imx_dma_2d_slots[slot].xsr = x;
> +	imx_dma_2d_slots[slot].ysr = y;
> +	imx_dma_2d_slots[slot].wsr = w;
> +	imx_dma_2d_slots[slot].count++;
> +
> +	spin_unlock(&lock_2d);
> +
> +	imxdma->slot_2d = slot;
> +	imxdma->enabled_2d = true;
> +
> +	if (slot == IMX_DMA_2D_SLOT_A) {
> +		imx_dmav1_writel(x, DMA_XSRA);
> +		imx_dmav1_writel(y, DMA_YSRA);
> +		imx_dmav1_writel(w, DMA_WSRA);
> +	} else {
> +		imx_dmav1_writel(x, DMA_XSRB);
> +		imx_dmav1_writel(y, DMA_YSRB);
> +		imx_dmav1_writel(w, DMA_WSRB);
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(imx_dma_config_2d);
why EXPORT?? This should be done using the interleaved API
> +
> +/**
>   * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification
>   * handlers
>   * @channel: i.MX DMA channel number
> @@ -732,6 +807,13 @@ void imx_dma_free(int channel)
>  		return;
>  	}
>  
> +	spin_lock(&lock_2d);
> +	if (imxdma->enabled_2d) {
> +		imx_dma_2d_slots[imxdma->slot_2d].count--;
> +		imxdma->enabled_2d = false;
> +	}
> +	spin_unlock(&lock_2d);
> +
>  	local_irq_save(flags);
>  	/* Disable interrupts */
>  	imx_dma_disable(channel);
> @@ -840,6 +922,10 @@ static int __init imx_dma_init(void)
>  		imx_dma_channels[i].dma_num = i;
>  	}
>  
> +	for (i = 0; i < IMX_DMA_2D_SLOTS; i++)
> +		imx_dma_2d_slots[i].count = 0;
> +	spin_lock_init(&lock_2d);
> +
>  	return ret;
>  }
>  
> diff --git a/arch/arm/mach-imx/include/mach/dma-v1.h b/arch/arm/mach-imx/include/mach/dma-v1.h
> index ac6fd71..bab9183 100644
> --- a/arch/arm/mach-imx/include/mach/dma-v1.h
> +++ b/arch/arm/mach-imx/include/mach/dma-v1.h
> @@ -30,6 +30,10 @@
>  #include <mach/dma.h>
>  
>  #define IMX_DMA_CHANNELS  16
> +#define IMX_DMA_2D_SLOTS   2
> +
> +#define IMX_DMA_2D_SLOT_A  0
> +#define IMX_DMA_2D_SLOT_B  1
>  
>  #define DMA_MODE_READ		0
>  #define DMA_MODE_WRITE		1
> @@ -64,6 +68,9 @@ void
>  imx_dma_config_burstlen(int channel, unsigned int burstlen);
>  
>  int
> +imx_dma_config_2d(int channel, unsigned int x, unsigned int y, unsigned int w);
> +
> +int
>  imx_dma_setup_single(int channel, dma_addr_t dma_address,
>  		unsigned int dma_length, unsigned int dev_addr,
>  		unsigned int dmamode);


-- 
~Vinod

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

* [PATCH 0/4] dmaengine: i.MX DMA series.
  2012-02-14 11:51 ` [PATCH 0/4] dmaengine: i.MX DMA series javier Martin
@ 2012-02-22 13:21   ` Vinod Koul
  2012-02-27  8:20     ` javier Martin
  0 siblings, 1 reply; 10+ messages in thread
From: Vinod Koul @ 2012-02-22 13:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2012-02-14 at 12:51 +0100, javier Martin wrote:
> On 10 February 2012 15:31, Javier Martin
> <javier.martin@vista-silicon.com> wrote:
> > Patches 1-3 have already been sent to the list (not merged yet)
> > but they are submitted so that everyone can get the whole picture
> > of what we're trying to do here.
> >
> > A new patch(4) has been added which adds support for multiple
> > descriptors.
> >
> > [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma.
> > [PATCH 2/4] i.MX DMA: Add support for 2D transfers.
> > [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers.
> > [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma.
> 
> Hi,
> what do you think of this series?
> 
> Vinod: your concern about patch 1 is solved in patch 4
> Sascha: I know you are not comfortable with patch 2 since it adds code
> to a file which is meant to be removed. However, is there a chance you
> accept it without me having to rewrite the whole series?
Without 2, I think this patch set looks okay. Sascha have you tested
this series, if so please let me know, I can apply the rest.


-- 
~Vinod

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

* [PATCH 0/4] dmaengine: i.MX DMA series.
  2012-02-22 13:21   ` Vinod Koul
@ 2012-02-27  8:20     ` javier Martin
  2012-02-27  9:16       ` Vinod Koul
  0 siblings, 1 reply; 10+ messages in thread
From: javier Martin @ 2012-02-27  8:20 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vinod,

On 22 February 2012 14:21, Vinod Koul <vinod.koul@intel.com> wrote:
> On Tue, 2012-02-14 at 12:51 +0100, javier Martin wrote:
>> On 10 February 2012 15:31, Javier Martin
>> <javier.martin@vista-silicon.com> wrote:
>> > Patches 1-3 have already been sent to the list (not merged yet)
>> > but they are submitted so that everyone can get the whole picture
>> > of what we're trying to do here.
>> >
>> > A new patch(4) has been added which adds support for multiple
>> > descriptors.
>> >
>> > [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma.
>> > [PATCH 2/4] i.MX DMA: Add support for 2D transfers.
>> > [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers.
>> > [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma.
>>
>> Hi,
>> what do you think of this series?
>>
>> Vinod: your concern about patch 1 is solved in patch 4
>> Sascha: I know you are not comfortable with patch 2 since it adds code
>> to a file which is meant to be removed. However, is there a chance you
>> accept it without me having to rewrite the whole series?
> Without 2, I think this patch set looks okay. Sascha have you tested
> this series, if so please let me know, I can apply the rest.

Please, note that if for whatever reason you don't apply patch 2 you
must not apply patch 3 either. Because, as I stated, it depends
completely on patch 2.

Regards.
-- 
Javier Martin
Vista Silicon S.L.
CDTUC - FASE C - Oficina S-345
Avda de los Castros s/n
39005- Santander. Cantabria. Spain
+34 942 25 32 60
www.vista-silicon.com

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

* [PATCH 0/4] dmaengine: i.MX DMA series.
  2012-02-27  8:20     ` javier Martin
@ 2012-02-27  9:16       ` Vinod Koul
  0 siblings, 0 replies; 10+ messages in thread
From: Vinod Koul @ 2012-02-27  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2012-02-27 at 09:20 +0100, javier Martin wrote:
> Please, note that if for whatever reason you don't apply patch 2 you
> must not apply patch 3 either. Because, as I stated, it depends
> completely on patch 2. 
Then you should resend teh series after dropping 2.
-- 
~Vinod

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

end of thread, other threads:[~2012-02-27  9:16 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-10 14:31 [PATCH 0/4] dmaengine: i.MX DMA series Javier Martin
2012-02-10 14:31 ` [PATCH 1/4] dmaengine: Add support for MEMCPY for imx-dma Javier Martin
2012-02-10 14:31 ` [PATCH 2/4] i.MX DMA: Add support for 2D transfers Javier Martin
2012-02-22 13:18   ` Vinod Koul
2012-02-10 14:31 ` [PATCH 3/4] dmaengine: i.MX: Add support for interleaved transfers Javier Martin
2012-02-10 14:31 ` [PATCH 4/4] dmaengine: Add support for multiple descriptors for imx-dma Javier Martin
2012-02-14 11:51 ` [PATCH 0/4] dmaengine: i.MX DMA series javier Martin
2012-02-22 13:21   ` Vinod Koul
2012-02-27  8:20     ` javier Martin
2012-02-27  9:16       ` Vinod Koul

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