From ccffa3870a7ec2b59cf051b745220c56f423d182 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Sep 2012 15:05:44 +0300 Subject: dmaengine: omap: Support for element mode in cyclic DMA When src_maxburst/dst_maxburst is set to 0 by the users of cyclic DMA (mostly audio) indicates that we should configure the omap DMA to element sync mode instead of packet mode. Signed-off-by: Peter Ujfalusi Acked-by: Vinod Koul Tested-by: Janusz Krzysztofik Signed-off-by: Mark Brown --- drivers/dma/omap-dma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/dma/omap-dma.c') diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index ae0561826137..b77a40db2856 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -413,7 +413,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic( d->dev_addr = dev_addr; d->fi = burst; d->es = es; - d->sync_mode = OMAP_DMA_SYNC_PACKET; + if (burst) + d->sync_mode = OMAP_DMA_SYNC_PACKET; + else + d->sync_mode = OMAP_DMA_SYNC_ELEMENT; d->sync_type = sync_type; d->periph_port = OMAP_DMA_PORT_MPUI; d->sg[0].addr = buf_addr; -- cgit v1.2.3 From 2dcdf570936168d488acf90be9b04a3d32dafce7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Sep 2012 15:05:45 +0300 Subject: dmaengine: omap: Add support for pause/resume in cyclic dma mode The audio stack used omap_stop_dma/omap_start_dma to pause/resume the DMA. This method has been used for years on OMAP based products. We only allow pause/resume when the DMA has been configured in cyclic mode which is used by the audio stack. Signed-off-by: Peter Ujfalusi Acked-by: Vinod Koul Tested-by: Janusz Krzysztofik Signed-off-by: Mark Brown --- drivers/dma/omap-dma.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers/dma/omap-dma.c') diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index b77a40db2856..71d786973dfd 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -34,6 +34,7 @@ struct omap_chan { struct dma_slave_config cfg; unsigned dma_sig; bool cyclic; + bool paused; int dma_ch; struct omap_desc *desc; @@ -470,11 +471,14 @@ static int omap_dma_terminate_all(struct omap_chan *c) */ if (c->desc) { c->desc = NULL; - omap_stop_dma(c->dma_ch); + /* Avoid stopping the dma twice */ + if (!c->paused) + omap_stop_dma(c->dma_ch); } if (c->cyclic) { c->cyclic = false; + c->paused = false; omap_dma_unlink_lch(c->dma_ch, c->dma_ch); } @@ -487,14 +491,30 @@ static int omap_dma_terminate_all(struct omap_chan *c) static int omap_dma_pause(struct omap_chan *c) { - /* FIXME: not supported by platform private API */ - return -EINVAL; + /* Pause/Resume only allowed with cyclic mode */ + if (!c->cyclic) + return -EINVAL; + + if (!c->paused) { + omap_stop_dma(c->dma_ch); + c->paused = true; + } + + return 0; } static int omap_dma_resume(struct omap_chan *c) { - /* FIXME: not supported by platform private API */ - return -EINVAL; + /* Pause/Resume only allowed with cyclic mode */ + if (!c->cyclic) + return -EINVAL; + + if (c->paused) { + omap_start_dma(c->dma_ch); + c->paused = false; + } + + return 0; } static int omap_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, -- cgit v1.2.3 From ec8b5e48c03790a68cb875fe5064007a9cbdfdd0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Sep 2012 15:05:47 +0300 Subject: dmaengine: Pass flags via device_prep_dma_cyclic() callback Change the parameter list of device_prep_dma_cyclic() so the DMA drivers can receive the flags coming from clients. This feature can be used during audio operation to disable all audio related interrupts when the DMA_PREP_INTERRUPT is cleared from the flags. Signed-off-by: Peter Ujfalusi Acked-by: Nicolas Ferre Acked-by: Shawn Guo Acked-by: Vinod Koul Signed-off-by: Mark Brown --- drivers/dma/at_hdmac.c | 3 ++- drivers/dma/ep93xx_dma.c | 4 +++- drivers/dma/imx-dma.c | 2 +- drivers/dma/imx-sdma.c | 2 +- drivers/dma/mmp_tdma.c | 2 +- drivers/dma/mxs-dma.c | 2 +- drivers/dma/omap-dma.c | 3 ++- drivers/dma/pl330.c | 2 +- drivers/dma/sa11x0-dma.c | 2 +- drivers/dma/sirf-dma.c | 2 +- drivers/dma/ste_dma40.c | 3 ++- drivers/dma/tegra20-apb-dma.c | 2 +- include/linux/dmaengine.h | 4 ++-- 13 files changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers/dma/omap-dma.c') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 3934fcc4e00b..7e5f6b65c651 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -841,12 +841,13 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, * @buf_len: total number of bytes for the entire buffer * @period_len: number of bytes for each period * @direction: transfer direction, to or from device + * @flags: tx descriptor status flags * @context: transfer context (ignored) */ static struct dma_async_tx_descriptor * atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma_slave *atslave = chan->private; diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index c64917ec313d..493735b9b2c9 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -1120,6 +1120,7 @@ fail: * @buf_len: length of the buffer (in bytes) * @period_len: lenght of a single period * @dir: direction of the operation + * @flags: tx descriptor status flags * @context: operation context (ignored) * * Prepares a descriptor for cyclic DMA operation. This means that once the @@ -1133,7 +1134,8 @@ fail: static struct dma_async_tx_descriptor * ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction dir, void *context) + enum dma_transfer_direction dir, unsigned long flags, + void *context) { struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan); struct ep93xx_dma_desc *desc, *first; diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 5084975d793c..41b4376eb614 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -801,7 +801,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg( static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct imxdma_channel *imxdmac = to_imxdma_chan(chan); struct imxdma_engine *imxdma = imxdmac->imxdma; diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 1dc2a4ad0026..2c5fd3e9880c 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1012,7 +1012,7 @@ err_out: static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_engine *sdma = sdmac->sdma; diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 8a15cf2163dc..6d52bd43a527 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -358,7 +358,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac) static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan); struct mmp_tdma_desc *desc; diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 7f41b25805fa..734a4eb84d65 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -531,7 +531,7 @@ err_out: static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 71d786973dfd..4d2650f4202c 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -366,7 +366,8 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction dir, void *context) + size_t period_len, enum dma_transfer_direction dir, unsigned long flags, + void *context) { struct omap_chan *c = to_omap_dma_chan(chan); enum dma_slave_buswidth dev_width; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index e4feba6b03c0..00356458e399 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2683,7 +2683,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t dma_addr, size_t len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct dma_pl330_desc *desc; struct dma_pl330_chan *pch = to_pchan(chan); diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index f5a73606217e..b893159c1ecb 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -614,7 +614,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg( static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period, - enum dma_transfer_direction dir, void *context) + enum dma_transfer_direction dir, unsigned long flags, void *context) { struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan); struct sa11x0_dma_desc *txd; diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 434ad31174f2..3eed8b35b0f1 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -489,7 +489,7 @@ err_dir: static struct dma_async_tx_descriptor * sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction direction, void *context) + enum dma_transfer_direction direction, unsigned long flags, void *context) { struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); struct sirfsoc_dma_desc *sdesc = NULL; diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 000d309602b2..eee8d9b9a20b 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2347,7 +2347,8 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, static struct dma_async_tx_descriptor * dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, size_t period_len, - enum dma_transfer_direction direction, void *context) + enum dma_transfer_direction direction, unsigned long flags, + void *context) { unsigned int periods = buf_len / period_len; struct dma_async_tx_descriptor *txd; diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 24acd711e032..b42b6ffb75ad 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -990,7 +990,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context) + unsigned long flags, void *context) { struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); struct tegra_dma_desc *dma_desc = NULL; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 9c02a4508b25..09da4e565297 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -591,7 +591,7 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_transfer_direction direction, - void *context); + unsigned long flags, void *context); struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)( struct dma_chan *chan, struct dma_interleaved_template *xt, unsigned long flags); @@ -656,7 +656,7 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( size_t period_len, enum dma_transfer_direction dir) { return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len, - period_len, dir, NULL); + period_len, dir, flags, NULL); } static inline int dmaengine_terminate_all(struct dma_chan *chan) -- cgit v1.2.3 From 2dde5b909e117cc95a5e31604f9bfd043e78ad9d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Sep 2012 15:05:48 +0300 Subject: dmaengine: omap-dma: Add support to suppress interrupts in cyclic mode When requested (DMA_PREP_INTERRUPT is cleared in flags) disable all DMA interrupts for the channel. In this mode user space does not expect periodic reports from kernel about the progress of the audio stream. PulseAudio for example support this type of mode. Signed-off-by: Peter Ujfalusi Acked-by: Vinod Koul Tested-by: Janusz Krzysztofik Signed-off-by: Mark Brown --- drivers/dma/omap-dma.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/dma/omap-dma.c') diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 4d2650f4202c..f59f244f60fc 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -429,7 +429,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic( if (!c->cyclic) { c->cyclic = true; omap_dma_link_lch(c->dma_ch, c->dma_ch); - omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ); + + if (flags & DMA_PREP_INTERRUPT) + omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ); + omap_disable_dma_irq(c->dma_ch, OMAP_DMA_BLOCK_IRQ); } @@ -438,7 +441,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic( omap_set_dma_dest_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16); } - return vchan_tx_prep(&c->vc, &d->vd, DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + return vchan_tx_prep(&c->vc, &d->vd, flags); } static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg) -- cgit v1.2.3