* [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 [not found] ` <1364746680-6564-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org> 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: [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
[parent not found: <1364746680-6564-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org>]
* Re: [PATCH 1/2] dmaengine: mpc512x_dma: use generic DMA DT bindings [not found] ` <1364746680-6564-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org> @ 2013-04-02 18:22 ` Vinod Koul 2013-04-02 19:01 ` Arnd Bergmann 0 siblings, 1 reply; 7+ messages in thread From: Vinod Koul @ 2013-04-02 18:22 UTC (permalink / raw) To: Anatolij Gustschin, Arnd Bergmann Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, linux-kernel-u79uwXL29TY76Z2rM5mHXA 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-ynQEQJNshbs@public.gmane.org> > --- > 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 [not found] ` <1364746680-6564-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org> @ 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
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 [not found] ` <1364746680-6564-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org> 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).