linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings
@ 2013-03-31 16:17 Anatolij Gustschin
  2013-03-31 16:18 ` [PATCH 2/2] dmaengine: mpc512x: add slave sg and device control operations Anatolij Gustschin
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-03-31 16:17 UTC (permalink / raw)
  To: linux-kernel; +Cc: devicetree-discuss, Vinod Koul, Anatolij Gustschin

Add generic DMA bindings and register the DMA controller
to DT DMA helpers.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 arch/powerpc/boot/dts/mpc5121.dtsi |    5 ++-
 drivers/dma/mpc512x_dma.c          |   63 ++++++++++++++++++++++++++++++++++--
 2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 723e292..d1fe070 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -384,10 +384,13 @@
 			interrupts = <40 0x8>;
 		};
 
-		dma@14000 {
+		dma0: dma@14000 {
 			compatible = "fsl,mpc5121-dma";
 			reg = <0x14000 0x1800>;
 			interrupts = <65 0x8>;
+			#dma-cells = <1>;
+			#dma-channels = <64>;
+			#dma-requests = <64>;
 		};
 	};
 
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 2d95673..bc6c356 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -40,6 +40,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
+#include <linux/of_dma.h>
 #include <linux/of_platform.h>
 
 #include <linux/random.h>
@@ -641,6 +642,44 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
 	return &mdesc->desc;
 }
 
+struct mpc_dma_filter_args {
+	struct mpc_dma *mdma;
+	unsigned int chan_id;
+};
+
+static bool mpc_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct mpc_dma_filter_args *fargs = param;
+
+	if (chan->device != &fargs->mdma->dma)
+		return false;
+
+	return (chan->chan_id == fargs->chan_id);
+}
+
+static struct dma_chan *mpc_dma_xlate(struct of_phandle_args *dma_spec,
+						struct of_dma *ofdma)
+{
+	int count = dma_spec->args_count;
+	struct mpc_dma *mdma = ofdma->of_dma_data;
+	struct mpc_dma_filter_args fargs;
+	dma_cap_mask_t cap;
+
+	if (!mdma)
+		return NULL;
+
+	if (count != 1)
+		return NULL;
+
+	fargs.mdma = mdma;
+	fargs.chan_id = dma_spec->args[0];
+
+	dma_cap_zero(cap);
+	dma_cap_set(DMA_SLAVE, cap);
+
+	return dma_request_channel(cap, mpc_dma_filter, &fargs);
+}
+
 static int mpc_dma_probe(struct platform_device *op)
 {
 	struct device_node *dn = op->dev.of_node;
@@ -791,11 +830,26 @@ static int mpc_dma_probe(struct platform_device *op)
 	/* Register DMA engine */
 	dev_set_drvdata(dev, mdma);
 	retval = dma_async_device_register(dma);
-	if (retval) {
-		devm_free_irq(dev, mdma->irq, mdma);
-		irq_dispose_mapping(mdma->irq);
+	if (retval)
+		goto reg_err;
+
+	if (dev->of_node) {
+		retval = of_dma_controller_register(dev->of_node,
+						    mpc_dma_xlate, mdma);
+		if (retval) {
+			dev_err(&op->dev,
+				"could not register of_dma_controller\n");
+			goto of_err;
+		}
 	}
 
+	return 0;
+
+of_err:
+	dma_async_device_unregister(&mdma->dma);
+reg_err:
+	devm_free_irq(dev, mdma->irq, mdma);
+	irq_dispose_mapping(mdma->irq);
 	return retval;
 }
 
@@ -804,6 +858,9 @@ static int mpc_dma_remove(struct platform_device *op)
 	struct device *dev = &op->dev;
 	struct mpc_dma *mdma = dev_get_drvdata(dev);
 
+	if (dev->of_node)
+		of_dma_controller_free(dev->of_node);
+
 	dma_async_device_unregister(&mdma->dma);
 	devm_free_irq(dev, mdma->irq, mdma);
 	irq_dispose_mapping(mdma->irq);
-- 
1.7.5.4


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

* [PATCH 2/2] dmaengine: mpc512x: add slave sg and device control operations
  2013-03-31 16:17 [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Anatolij Gustschin
@ 2013-03-31 16:18 ` Anatolij Gustschin
  2013-05-16 13:04   ` [2/2] " Alexander Popov
  2013-04-02 18:22 ` [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Vinod Koul
  2013-04-08 10:46 ` Lars-Peter Clausen
  2 siblings, 1 reply; 7+ messages in thread
From: Anatolij Gustschin @ 2013-03-31 16:18 UTC (permalink / raw)
  To: linux-kernel; +Cc: devicetree-discuss, Vinod Koul, Anatolij Gustschin

Prepare the driver to support slave sg operation.

For memory to memory transfers mpc_dma_execute() used to start
the transfer explicitely, for peripheral transfers the dma transfer
will be started on peripheral's request, so we only need to enable
peripheral's channel request in mpc_dma_execute().

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 drivers/dma/mpc512x_dma.c |  150 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 148 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index bc6c356..1c822b1 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -194,6 +194,9 @@ struct mpc_dma_chan {
 
 	/* Lock for this structure */
 	spinlock_t			lock;
+
+	/* Channel's peripheral fifo address */
+	dma_addr_t			per_paddr;
 };
 
 struct mpc_dma {
@@ -257,7 +260,9 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
 
 		prev->tcd->dlast_sga = mdesc->tcd_paddr;
 		prev->tcd->e_sg = 1;
-		mdesc->tcd->start = 1;
+		/* only start explicitly on MDDRC channel */
+		if (cid == 32)
+			mdesc->tcd->start = 1;
 
 		prev = mdesc;
 	}
@@ -269,7 +274,15 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
 
 	if (first != prev)
 		mdma->tcd[cid].e_sg = 1;
-	out_8(&mdma->regs->dmassrt, cid);
+
+	switch (cid) {
+	case 30:
+		out_8(&mdma->regs->dmaserq, cid);
+		break;
+	case 32:
+		out_8(&mdma->regs->dmassrt, cid);
+		break;
+	}
 }
 
 /* Handle interrupt on one half of DMA controller (32 channels) */
@@ -642,6 +655,136 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
 	return &mdesc->desc;
 }
 
+static struct dma_async_tx_descriptor *mpc_dma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction direction,
+		unsigned long flags, void *context)
+{
+	struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	struct mpc_dma_desc *mdesc = NULL;
+	struct mpc_dma_tcd *tcd;
+	unsigned long flags;
+	struct scatterlist *sg;
+	dma_addr_t dst, src;
+	size_t len;
+	int iter, i;
+
+	if (!list_empty(&mchan->active))
+		return NULL;
+
+	for_each_sg(sgl, sg, sg_len, i) {
+		spin_lock_irqsave(&mchan->lock, flags);
+
+		mdesc = list_first_entry(&mchan->free, struct mpc_dma_desc,
+					 node);
+		if (!mdesc) {
+			spin_unlock_irqrestore(&mchan->lock, flags);
+			/* try to free completed descriptors */
+			mpc_dma_process_completed(mdma);
+			return NULL;
+		}
+
+		list_del(&mdesc->node);
+
+		spin_unlock_irqrestore(&mchan->lock, flags);
+
+		mdesc->error = 0;
+		tcd = mdesc->tcd;
+
+		/* Prepare Transfer Control Descriptor for this transaction */
+		memset(tcd, 0, sizeof(struct mpc_dma_tcd));
+
+		if (direction == DMA_DEV_TO_MEM) {
+			dst = sg_dma_address(sg);
+			src = mchan->per_paddr;
+		} else if (direction == DMA_MEM_TO_DEV) {
+			dst = mchan->per_paddr;
+			src = sg_dma_address(sg);
+		} else {
+			return NULL;
+		}
+
+		len = sg_dma_len(sg);
+
+		if (direction == DMA_MEM_TO_DEV) {
+			tcd->saddr = sg_dma_address(sg);
+			tcd->daddr = mchan->per_paddr;
+			tcd->soff = 4;
+			tcd->doff = 0;
+		} else {
+			tcd->saddr = mchan->per_paddr;
+			tcd->daddr = sg_dma_address(sg);
+			tcd->soff = 0;
+			tcd->doff = 4;
+		}
+
+		tcd->ssize = MPC_DMA_TSIZE_4;
+		tcd->dsize = MPC_DMA_TSIZE_4;
+		tcd->nbytes = 64;
+
+		iter = sg_dma_len(sg) / 64;
+
+		/* citer_linkch contains the high bits of iter */
+		tcd->citer_linkch = iter >> 9;
+		tcd->biter_linkch = iter >> 9;
+		tcd->citer = iter & 0x1ff;
+		tcd->biter = iter & 0x1ff;
+
+		tcd->e_sg = 0;
+
+		if (i != (sg_len - 1)) {
+			struct scatterlist *s = sg_next(sg);
+
+			if (!s)
+				tcd->dlast_sga = sg_dma_address(s);
+			tcd->e_sg = 1;
+		} else {
+			tcd->d_req = 1;
+		}
+	}
+
+	/* Place descriptor in prepared list */
+	spin_lock_irqsave(&mchan->lock, flags);
+	list_add_tail(&mdesc->node, &mchan->prepared);
+	spin_unlock_irqrestore(&mchan->lock, flags);
+
+	return &mdesc->desc;
+}
+
+static int mpc_dma_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+				  unsigned long arg)
+{
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+	struct dma_slave_config *cfg = (void *)arg;
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		/* disable channel requests */
+		out_8(&mdma->regs->dmaserq, chan->chan_id);
+		list_splice_tail_init(&mchan->prepared, &mchan->free);
+		list_splice_tail_init(&mchan->queued, &mchan->free);
+		list_splice_tail_init(&mchan->active, &mchan->free);
+		return 0;
+	case DMA_SLAVE_CONFIG:
+		if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES &&
+		    cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+			return -EINVAL;
+
+		if (cfg->direction == DMA_DEV_TO_MEM)
+			mchan->per_paddr = cfg->src_addr;
+		else
+			mchan->per_paddr = cfg->dst_addr;
+
+		return 0;
+	default:
+		return -ENOSYS;
+	}
+
+	return -EINVAL;
+}
+
 struct mpc_dma_filter_args {
 	struct mpc_dma *mdma;
 	unsigned int chan_id;
@@ -764,9 +907,12 @@ static int mpc_dma_probe(struct platform_device *op)
 	dma->device_issue_pending = mpc_dma_issue_pending;
 	dma->device_tx_status = mpc_dma_tx_status;
 	dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
+	dma->device_prep_slave_sg = mpc_dma_prep_slave_sg;
+	dma->device_control = mpc_dma_device_control;
 
 	INIT_LIST_HEAD(&dma->channels);
 	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+	dma_cap_set(DMA_SLAVE, dma->cap_mask);
 
 	for (i = 0; i < dma->chancnt; i++) {
 		mchan = &mdma->channels[i];
-- 
1.7.5.4


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

* Re: [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings
  2013-03-31 16:17 [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Anatolij Gustschin
  2013-03-31 16:18 ` [PATCH 2/2] dmaengine: mpc512x: add slave sg and device control operations Anatolij Gustschin
@ 2013-04-02 18:22 ` Vinod Koul
  2013-04-02 19:01   ` Arnd Bergmann
  2013-04-08 10:46 ` Lars-Peter Clausen
  2 siblings, 1 reply; 7+ messages in thread
From: Vinod Koul @ 2013-04-02 18:22 UTC (permalink / raw)
  To: Anatolij Gustschin, Arnd Bergmann; +Cc: linux-kernel, devicetree-discuss

On Sun, Mar 31, 2013 at 06:17:59PM +0200, Anatolij Gustschin wrote:
> Add generic DMA bindings and register the DMA controller
> to DT DMA helpers.
I need someone who understands DT better than me to comment/ack...
Arnd...?

> 
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> ---
>  arch/powerpc/boot/dts/mpc5121.dtsi |    5 ++-
>  drivers/dma/mpc512x_dma.c          |   63 ++++++++++++++++++++++++++++++++++--
>  2 files changed, 64 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
> index 723e292..d1fe070 100644
> --- a/arch/powerpc/boot/dts/mpc5121.dtsi
> +++ b/arch/powerpc/boot/dts/mpc5121.dtsi
> @@ -384,10 +384,13 @@
>  			interrupts = <40 0x8>;
>  		};
>  
> -		dma@14000 {
> +		dma0: dma@14000 {
>  			compatible = "fsl,mpc5121-dma";
>  			reg = <0x14000 0x1800>;
>  			interrupts = <65 0x8>;
> +			#dma-cells = <1>;
> +			#dma-channels = <64>;
> +			#dma-requests = <64>;
>  		};
>  	};
>  
> diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
> index 2d95673..bc6c356 100644
> --- a/drivers/dma/mpc512x_dma.c
> +++ b/drivers/dma/mpc512x_dma.c
> @@ -40,6 +40,7 @@
>  #include <linux/io.h>
>  #include <linux/slab.h>
>  #include <linux/of_device.h>
> +#include <linux/of_dma.h>
>  #include <linux/of_platform.h>
>  
>  #include <linux/random.h>
> @@ -641,6 +642,44 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
>  	return &mdesc->desc;
>  }
>  
> +struct mpc_dma_filter_args {
> +	struct mpc_dma *mdma;
> +	unsigned int chan_id;
> +};
> +
> +static bool mpc_dma_filter(struct dma_chan *chan, void *param)
> +{
> +	struct mpc_dma_filter_args *fargs = param;
> +
> +	if (chan->device != &fargs->mdma->dma)
> +		return false;
> +
> +	return (chan->chan_id == fargs->chan_id);
> +}
> +
> +static struct dma_chan *mpc_dma_xlate(struct of_phandle_args *dma_spec,
> +						struct of_dma *ofdma)
> +{
> +	int count = dma_spec->args_count;
> +	struct mpc_dma *mdma = ofdma->of_dma_data;
> +	struct mpc_dma_filter_args fargs;
> +	dma_cap_mask_t cap;
> +
> +	if (!mdma)
> +		return NULL;
> +
> +	if (count != 1)
> +		return NULL;
> +
> +	fargs.mdma = mdma;
> +	fargs.chan_id = dma_spec->args[0];
> +
> +	dma_cap_zero(cap);
> +	dma_cap_set(DMA_SLAVE, cap);
> +
> +	return dma_request_channel(cap, mpc_dma_filter, &fargs);
> +}
> +
>  static int mpc_dma_probe(struct platform_device *op)
>  {
>  	struct device_node *dn = op->dev.of_node;
> @@ -791,11 +830,26 @@ static int mpc_dma_probe(struct platform_device *op)
>  	/* Register DMA engine */
>  	dev_set_drvdata(dev, mdma);
>  	retval = dma_async_device_register(dma);
> -	if (retval) {
> -		devm_free_irq(dev, mdma->irq, mdma);
> -		irq_dispose_mapping(mdma->irq);
> +	if (retval)
> +		goto reg_err;
> +
> +	if (dev->of_node) {
> +		retval = of_dma_controller_register(dev->of_node,
> +						    mpc_dma_xlate, mdma);
> +		if (retval) {
> +			dev_err(&op->dev,
> +				"could not register of_dma_controller\n");
> +			goto of_err;
> +		}
>  	}
>  
> +	return 0;
> +
> +of_err:
> +	dma_async_device_unregister(&mdma->dma);
> +reg_err:
> +	devm_free_irq(dev, mdma->irq, mdma);
> +	irq_dispose_mapping(mdma->irq);
>  	return retval;
>  }
>  
> @@ -804,6 +858,9 @@ static int mpc_dma_remove(struct platform_device *op)
>  	struct device *dev = &op->dev;
>  	struct mpc_dma *mdma = dev_get_drvdata(dev);
>  
> +	if (dev->of_node)
> +		of_dma_controller_free(dev->of_node);
> +
>  	dma_async_device_unregister(&mdma->dma);
>  	devm_free_irq(dev, mdma->irq, mdma);
>  	irq_dispose_mapping(mdma->irq);
> -- 
> 1.7.5.4
> 

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

* Re: [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings
  2013-04-02 18:22 ` [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Vinod Koul
@ 2013-04-02 19:01   ` Arnd Bergmann
  0 siblings, 0 replies; 7+ messages in thread
From: Arnd Bergmann @ 2013-04-02 19:01 UTC (permalink / raw)
  To: Vinod Koul; +Cc: Anatolij Gustschin, linux-kernel, devicetree-discuss

On Tuesday 02 April 2013, Vinod Koul wrote:
> On Sun, Mar 31, 2013 at 06:17:59PM +0200, Anatolij Gustschin wrote:
> > Add generic DMA bindings and register the DMA controller
> > to DT DMA helpers.
> I need someone who understands DT better than me to comment/ack...
> Arnd...?

> >  
> > +struct mpc_dma_filter_args {
> > +	struct mpc_dma *mdma;
> > +	unsigned int chan_id;
> > +};
> > +
> > +static bool mpc_dma_filter(struct dma_chan *chan, void *param)
> > +{
> > +	struct mpc_dma_filter_args *fargs = param;
> > +
> > +	if (chan->device != &fargs->mdma->dma)
> > +		return false;
> > +
> > +	return (chan->chan_id == fargs->chan_id);
> > +}

This assumes that there is a 1:1 mapping between channels and request lines,
which is unusual, but I assume it's correct for the hardware.

> > @@ -791,11 +830,26 @@ static int mpc_dma_probe(struct platform_device *op)
> >  	/* Register DMA engine */
> >  	dev_set_drvdata(dev, mdma);
> >  	retval = dma_async_device_register(dma);
> > -	if (retval) {
> > -		devm_free_irq(dev, mdma->irq, mdma);
> > -		irq_dispose_mapping(mdma->irq);
> > +	if (retval)
> > +		goto reg_err;
> > +
> > +	if (dev->of_node) {
> > +		retval = of_dma_controller_register(dev->of_node,
> > +						    mpc_dma_xlate, mdma);
> > +		if (retval) {
> > +			dev_err(&op->dev,
> > +				"could not register of_dma_controller\n");
> > +			goto of_err;
> > +		}
> >  	}

Here we rely on the fact that all device trees including this dma engine
have a correct representation of the device, which breaks backwards
compatibility with old device trees, which don't yet follow the binding
or don't need to because they only use memory-to-memory channels.

You can easily make it backwards compatible by making the above a
non-fatal error and just continuing here even if of_dma_controller_register
failed. If compatiblity is not a concern, the above is good.

The main thing missing is a binding file in
Documentation/devicetree/bindings/dma/mpc512x-dma.txt

	Arnd

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

* Re: [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings
  2013-03-31 16:17 [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Anatolij Gustschin
  2013-03-31 16:18 ` [PATCH 2/2] dmaengine: mpc512x: add slave sg and device control operations Anatolij Gustschin
  2013-04-02 18:22 ` [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Vinod Koul
@ 2013-04-08 10:46 ` Lars-Peter Clausen
  2013-04-09 11:42   ` Anatolij Gustschin
  2 siblings, 1 reply; 7+ messages in thread
From: Lars-Peter Clausen @ 2013-04-08 10:46 UTC (permalink / raw)
  To: Anatolij Gustschin, Vinod Koul; +Cc: linux-kernel, devicetree-discuss

On 03/31/2013 06:17 PM, Anatolij Gustschin wrote:
> Add generic DMA bindings and register the DMA controller
> to DT DMA helpers.
> 
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> ---
>  arch/powerpc/boot/dts/mpc5121.dtsi |    5 ++-
>  drivers/dma/mpc512x_dma.c          |   63 ++++++++++++++++++++++++++++++++++--
>  2 files changed, 64 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
> index 723e292..d1fe070 100644
> --- a/arch/powerpc/boot/dts/mpc5121.dtsi
> +++ b/arch/powerpc/boot/dts/mpc5121.dtsi
> @@ -384,10 +384,13 @@
>  			interrupts = <40 0x8>;
>  		};
>  
> -		dma@14000 {
> +		dma0: dma@14000 {
>  			compatible = "fsl,mpc5121-dma";
>  			reg = <0x14000 0x1800>;
>  			interrupts = <65 0x8>;
> +			#dma-cells = <1>;
> +			#dma-channels = <64>;
> +			#dma-requests = <64>;
>  		};
>  	};
>  
> diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
> index 2d95673..bc6c356 100644
> --- a/drivers/dma/mpc512x_dma.c
> +++ b/drivers/dma/mpc512x_dma.c
> @@ -40,6 +40,7 @@
>  #include <linux/io.h>
>  #include <linux/slab.h>
>  #include <linux/of_device.h>
> +#include <linux/of_dma.h>
>  #include <linux/of_platform.h>
>  
>  #include <linux/random.h>
> @@ -641,6 +642,44 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
>  	return &mdesc->desc;
>  }
>  
> +struct mpc_dma_filter_args {
> +	struct mpc_dma *mdma;
> +	unsigned int chan_id;
> +};
> +
> +static bool mpc_dma_filter(struct dma_chan *chan, void *param)
> +{
> +	struct mpc_dma_filter_args *fargs = param;
> +
> +	if (chan->device != &fargs->mdma->dma)
> +		return false;
> +
> +	return (chan->chan_id == fargs->chan_id);
> +}
> +
> +static struct dma_chan *mpc_dma_xlate(struct of_phandle_args *dma_spec,
> +						struct of_dma *ofdma)
> +{
> +	int count = dma_spec->args_count;
> +	struct mpc_dma *mdma = ofdma->of_dma_data;
> +	struct mpc_dma_filter_args fargs;
> +	dma_cap_mask_t cap;
> +
> +	if (!mdma)
> +		return NULL;
> +
> +	if (count != 1)
> +		return NULL;
> +
> +	fargs.mdma = mdma;
> +	fargs.chan_id = dma_spec->args[0];
> +
> +	dma_cap_zero(cap);
> +	dma_cap_set(DMA_SLAVE, cap);
> +
> +	return dma_request_channel(cap, mpc_dma_filter, &fargs);
> +}
> +

This is more or less the same as the generic of_dma_xlate_by_chan_id
function I posted about two weeks ago:
https://patchwork.kernel.org/patch/2331091/

Vinod, can you take a look at that patch again? I'm not quite sure what you
meant by your question 'how will the client know which "id" to request?'.

- Lars

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

* Re: [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings
  2013-04-08 10:46 ` Lars-Peter Clausen
@ 2013-04-09 11:42   ` Anatolij Gustschin
  0 siblings, 0 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-09 11:42 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: Vinod Koul, linux-kernel, devicetree-discuss

On Mon, 08 Apr 2013 12:46:47 +0200
Lars-Peter Clausen <lars@metafoo.de> wrote:
...
> > +static struct dma_chan *mpc_dma_xlate(struct of_phandle_args *dma_spec,
> > +						struct of_dma *ofdma)
> > +{
> > +	int count = dma_spec->args_count;
> > +	struct mpc_dma *mdma = ofdma->of_dma_data;
> > +	struct mpc_dma_filter_args fargs;
> > +	dma_cap_mask_t cap;
> > +
> > +	if (!mdma)
> > +		return NULL;
> > +
> > +	if (count != 1)
> > +		return NULL;
> > +
> > +	fargs.mdma = mdma;
> > +	fargs.chan_id = dma_spec->args[0];
> > +
> > +	dma_cap_zero(cap);
> > +	dma_cap_set(DMA_SLAVE, cap);
> > +
> > +	return dma_request_channel(cap, mpc_dma_filter, &fargs);
> > +}
> > +
> 
> This is more or less the same as the generic of_dma_xlate_by_chan_id
> function I posted about two weeks ago:
> https://patchwork.kernel.org/patch/2331091/

Thanks. I can use the generic of_dma_xlate_by_chan_id() when above patch
will be accepted.

Anatolij

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

* Re: [2/2] dmaengine: mpc512x: add slave sg and device control operations
  2013-03-31 16:18 ` [PATCH 2/2] dmaengine: mpc512x: add slave sg and device control operations Anatolij Gustschin
@ 2013-05-16 13:04   ` Alexander Popov
  0 siblings, 0 replies; 7+ messages in thread
From: Alexander Popov @ 2013-05-16 13:04 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linux-kernel, devicetree-discuss, Vinod Koul

Hello Anatolij,

I've made SCLPC device driver use .device_prep_slave_sg() from your patch
and before I send the second version of it I would like to propose
some improvements:


diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 1c822b1..80d8633 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -28,11 +28,6 @@
  * file called COPYING.
  */

-/*
- * This is initial version of MPC5121 DMA driver. Only memory to memory
- * transfers are supported (tested using dmatest module).
- */
-
 #include <linux/module.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
@@ -191,6 +186,7 @@ struct mpc_dma_chan {
     struct list_head        completed;
     struct mpc_dma_tcd        *tcd;
     dma_addr_t            tcd_paddr;
+    u32                tcd_nunits;

     /* Lock for this structure */
     spinlock_t            lock;
@@ -276,6 +272,7 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
         mdma->tcd[cid].e_sg = 1;

     switch (cid) {
+    case 26:
     case 30:
         out_8(&mdma->regs->dmaserq, cid);
         break;
@@ -664,9 +661,8 @@ static struct dma_async_tx_descriptor
*mpc_dma_prep_slave_sg(
     struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
     struct mpc_dma_desc *mdesc = NULL;
     struct mpc_dma_tcd *tcd;
-    unsigned long flags;
+    unsigned long iflags;
     struct scatterlist *sg;
-    dma_addr_t dst, src;
     size_t len;
     int iter, i;

@@ -674,12 +670,12 @@ static struct dma_async_tx_descriptor
*mpc_dma_prep_slave_sg(
         return NULL;

     for_each_sg(sgl, sg, sg_len, i) {
-        spin_lock_irqsave(&mchan->lock, flags);
+        spin_lock_irqsave(&mchan->lock, iflags);

         mdesc = list_first_entry(&mchan->free, struct mpc_dma_desc,
                      node);
         if (!mdesc) {
-            spin_unlock_irqrestore(&mchan->lock, flags);
+            spin_unlock_irqrestore(&mchan->lock, iflags);
             /* try to free completed descriptors */
             mpc_dma_process_completed(mdma);
             return NULL;
@@ -687,7 +683,7 @@ static struct dma_async_tx_descriptor
*mpc_dma_prep_slave_sg(

         list_del(&mdesc->node);

-        spin_unlock_irqrestore(&mchan->lock, flags);
+        spin_unlock_irqrestore(&mchan->lock, iflags);

         mdesc->error = 0;
         tcd = mdesc->tcd;
@@ -696,40 +692,43 @@ static struct dma_async_tx_descriptor
*mpc_dma_prep_slave_sg(
         memset(tcd, 0, sizeof(struct mpc_dma_tcd));

         if (direction == DMA_DEV_TO_MEM) {
-            dst = sg_dma_address(sg);
-            src = mchan->per_paddr;
+            tcd->saddr = mchan->per_paddr;
+            tcd->daddr = sg_dma_address(sg);
+            tcd->soff = 0;
+            tcd->doff = 4;
         } else if (direction == DMA_MEM_TO_DEV) {
-            dst = mchan->per_paddr;
-            src = sg_dma_address(sg);
-        } else {
-            return NULL;
-        }
-
-        len = sg_dma_len(sg);
-
-        if (direction == DMA_MEM_TO_DEV) {
             tcd->saddr = sg_dma_address(sg);
             tcd->daddr = mchan->per_paddr;
             tcd->soff = 4;
             tcd->doff = 0;
         } else {
-            tcd->saddr = mchan->per_paddr;
-            tcd->daddr = sg_dma_address(sg);
-            tcd->soff = 0;
-            tcd->doff = 4;
+            return NULL;
         }
-
         tcd->ssize = MPC_DMA_TSIZE_4;
         tcd->dsize = MPC_DMA_TSIZE_4;
-        tcd->nbytes = 64;

-        iter = sg_dma_len(sg) / 64;
+        if (!IS_ALIGNED(sg_dma_address(sg), 4))
+            return NULL;
+
+        len = sg_dma_len(sg);
+        if (mchan->tcd_nunits)
+            tcd->nbytes = mchan->tcd_nunits * 4;
+        else
+            tcd->nbytes = 64;

-        /* citer_linkch contains the high bits of iter */
-        tcd->citer_linkch = iter >> 9;
-        tcd->biter_linkch = iter >> 9;
-        tcd->citer = iter & 0x1ff;
-        tcd->biter = iter & 0x1ff;
+        if (!IS_ALIGNED(len, tcd->nbytes))
+            return NULL;
+
+        iter = len / tcd->nbytes;
+        if (iter > ((1 << 15) - 1)) {   /* maximum biter */
+            return NULL; /* len is too big */
+        } else {
+            /* citer_linkch contains the high bits of iter */
+            tcd->biter = iter & 0x1ff;
+            tcd->biter_linkch = iter >> 9;
+            tcd->citer = tcd->biter;
+            tcd->citer_linkch = tcd->biter_linkch;
+        }

         tcd->e_sg = 0;

@@ -745,9 +744,9 @@ static struct dma_async_tx_descriptor
*mpc_dma_prep_slave_sg(
     }

     /* Place descriptor in prepared list */
-    spin_lock_irqsave(&mchan->lock, flags);
+    spin_lock_irqsave(&mchan->lock, iflags);
     list_add_tail(&mdesc->node, &mchan->prepared);
-    spin_unlock_irqrestore(&mchan->lock, flags);
+    spin_unlock_irqrestore(&mchan->lock, iflags);

     return &mdesc->desc;
 }
@@ -772,10 +771,13 @@ static int mpc_dma_device_control(struct
dma_chan *chan, enum dma_ctrl_cmd cmd,
             cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
             return -EINVAL;

-        if (cfg->direction == DMA_DEV_TO_MEM)
+        if (cfg->direction == DMA_DEV_TO_MEM) {
             mchan->per_paddr = cfg->src_addr;
-        else
+            mchan->tcd_nunits = cfg->src_maxburst;
+        } else {
             mchan->per_paddr = cfg->dst_addr;
+            mchan->tcd_nunits = cfg->dst_maxburst;
+        }

         return 0;
     default:

2013/3/31 Anatolij Gustschin <agust@denx.de>:
> Prepare the driver to support slave sg operation.
>

Thanks.

Best regards,
Alexander

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

end of thread, other threads:[~2013-05-16 13:04 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-31 16:17 [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Anatolij Gustschin
2013-03-31 16:18 ` [PATCH 2/2] dmaengine: mpc512x: add slave sg and device control operations Anatolij Gustschin
2013-05-16 13:04   ` [2/2] " Alexander Popov
2013-04-02 18:22 ` [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings Vinod Koul
2013-04-02 19:01   ` Arnd Bergmann
2013-04-08 10:46 ` Lars-Peter Clausen
2013-04-09 11:42   ` Anatolij Gustschin

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