[PATCH v2] OMAP: PM: DMA: Enable runtime pm
G, Manjunath Kondaiah
manjugk at ti.com
Sat Feb 19 08:39:52 EST 2011
On Mon, Feb 14, 2011 at 02:06:53PM -0800, Kevin Hilman wrote:
> "G, Manjunath Kondaiah" <manjugk at ti.com> writes:
>
> > From: Manjunath G Kondaiah <manjugk at ti.com>
> >
> > Enable runtime pm and use pm_runtime_get_sync and pm_runtime_put_autosuspend
> > for OMAP DMA driver.
> >
> > The DMA driver uses auto suspend feature of runtime pm framework through
> > which the clock gets disabled automatically if there is no activity for
> > more than one second.
> >
> > Testing:
> > Compile: omap1_defconfig and omap2plus_defconfig
> > Boot: OMAP1710(H3), OMAP2420(H4), OMAP3630(Zoom3), OMAP4(Blaze)
>
> The normal DMA tests should also be run on these platforms. Based on
> the above, I can't tell any DMA tests were run. Based on my tests,
> this isn't working for chained xfers.
>
> Using the runtime PM sysfs interface, you can check the runtime status
> of the device:
>
> # cat /sys/devices/platform/omap/omap_dma_system.0/power/runtime_status
>
> It should show 'active' during transfer, and after timeout expires it
> will show 'suspended'.
>
> Doing some tests using my dmatest module:
>
> git://gitorious.org/omap-test/dmatest.git
>
> I noticed that it gets stuck in 'active' and never gets suspended when I
> used DMA channel linking (load module using 'linking=1' as load-time option)
>
> I'm not sure exactly why, but I will guess that the reason is that there
> is an imbalance in get/put calls when using chaining, since 'get' is
> only called once upon omap_start_dma() but 'put' is called for every
> channel in the callback.
found this issue and fixed. It was due to chain handling in interrupt
handler. Since get_sync used only in omap_start_dma for 1st transfer and there
will be no omap_start_dma for second transfer onwards since it will be linked
through chaining in interrupt handler. Here is the fix.
@@ -1895,8 +2002,11 @@ static int omap2_dma_handle_ch(int ch)
OMAP_DMA_DYNAMIC_CHAIN)
disable_lnk(ch);
- if (!OMAP_DMA_CHAIN_QEMPTY(chain_id))
+ if (!OMAP_DMA_CHAIN_QEMPTY(chain_id)) {
OMAP_DMA_CHAIN_INCQHEAD(chain_id);
+ pm_runtime_get_sync(dev);
+ }
+
status = p->dma_read(CSR, ch);
p->dma_write(status, CSR, ch);
-Manjunath
>
> > On zoom3 core retention is tested with following steps:
> > echo 1 > /debug/pm_debug/sleep_while_idle
> > echo 1 > /debug/pm_debug/enable_off_mode
> > echo 5 > /sys/devices/platform/omap/omap_uart.0/sleep_timeout
> > echo 5 > /sys/devices/platform/omap/omap_uart.1/sleep_timeout
> > echo 5 > /sys/devices/platform/omap/omap_uart.2/sleep_timeout
> > echo 5 > /sys/devices/platform/omap/omap_uart.3/sleep_timeout
> >
> > It is observed that(on pm branch), core retention count gets increasing if the
> > board is left idle for more than 5 seconds. However, it doesnot enter off mode
> > (even without DMA runtime changes).
>
> What silicon rev is on your Zoom3? Mainline kernels now disable core
> off-mode for 3630 revs < ES2.1 due to erratum i583.
>
> If this happens, you should see something like this on the console:
>
> Core OFF disabled due to errata i583
>
> Kevin
>
> > Signed-off-by: G, Manjunath Kondaiah <manjugk at ti.com>
> > ---
> > arch/arm/plat-omap/dma.c | 27 +++++++++++++++++++++++++++
> > 1 files changed, 27 insertions(+), 0 deletions(-)
> >
> > diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
> > index 2ec3b5d..6bfe25c 100644
> > --- a/arch/arm/plat-omap/dma.c
> > +++ b/arch/arm/plat-omap/dma.c
> > @@ -35,6 +35,7 @@
> > #include <linux/io.h>
> > #include <linux/slab.h>
> > #include <linux/delay.h>
> > +#include <linux/pm_runtime.h>
> >
> > #include <asm/system.h>
> > #include <mach/hardware.h>
> > @@ -59,6 +60,7 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED };
> >
> > static struct omap_system_dma_plat_info *p;
> > static struct omap_dma_dev_attr *d;
> > +static struct device *dev;
> >
> > static int enable_1510_mode;
> > static u32 errata;
> > @@ -676,6 +678,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
> > unsigned long flags;
> > struct omap_dma_lch *chan;
> >
> > + pm_runtime_get_sync(dev);
> > spin_lock_irqsave(&dma_chan_lock, flags);
> > for (ch = 0; ch < dma_chan_count; ch++) {
> > if (free_ch == -1 && dma_chan[ch].dev_id == -1) {
> > @@ -686,6 +689,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
> > }
> > if (free_ch == -1) {
> > spin_unlock_irqrestore(&dma_chan_lock, flags);
> > + pm_runtime_put_autosuspend(dev);
> > return -EBUSY;
> > }
> > chan = dma_chan + free_ch;
> > @@ -743,6 +747,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
> > }
> >
> > *dma_ch_out = free_ch;
> > + pm_runtime_put_autosuspend(dev);
> >
> > return 0;
> > }
> > @@ -871,6 +876,8 @@ void omap_start_dma(int lch)
> > {
> > u32 l;
> >
> > + pm_runtime_get_sync(dev);
> > +
> > /*
> > * The CPC/CDAC register needs to be initialized to zero
> > * before starting dma transfer.
> > @@ -1805,6 +1812,8 @@ static int omap1_dma_handle_ch(int ch)
> > if (likely(dma_chan[ch].callback != NULL))
> > dma_chan[ch].callback(ch, csr, dma_chan[ch].data);
> >
> > + pm_runtime_mark_last_busy(dev);
> > + pm_runtime_put_autosuspend(dev);
> > return 1;
> > }
> >
> > @@ -1899,6 +1908,8 @@ static int omap2_dma_handle_ch(int ch)
> > if (likely(dma_chan[ch].callback != NULL))
> > dma_chan[ch].callback(ch, status, dma_chan[ch].data);
> >
> > + pm_runtime_mark_last_busy(dev);
> > + pm_runtime_put_autosuspend(dev);
> > return 0;
> > }
> >
> > @@ -1978,6 +1989,7 @@ static int __devinit omap_system_dma_probe(struct platform_device *pdev)
> > return -EINVAL;
> > }
> >
> > + dev = &pdev->dev;
> > d = p->dma_attr;
> > errata = p->errata;
> >
> > @@ -1999,6 +2011,11 @@ static int __devinit omap_system_dma_probe(struct platform_device *pdev)
> > }
> > }
> >
> > + pm_runtime_use_autosuspend(dev);
> > + pm_runtime_set_autosuspend_delay(dev, 1000);
> > + pm_runtime_enable(dev);
> > + pm_runtime_get_sync(dev);
> > +
> > spin_lock_init(&dma_chan_lock);
> > for (ch = 0; ch < dma_chan_count; ch++) {
> > omap_clear_dma(ch);
> > @@ -2064,6 +2081,16 @@ static int __devinit omap_system_dma_probe(struct platform_device *pdev)
> > dma_chan[1].dev_id = 1;
> > }
> > p->show_dma_caps();
> > +
> > + /*
> > + * Note: If dma channels are reserved through boot paramters,
> > + * then dma device is always enabled.
> > + */
> > + if (omap_dma_reserve_channels)
> > + pm_runtime_get(dev);
> > +
> > + pm_runtime_put_autosuspend(dev);
> > +
> > return 0;
> >
> > exit_dma_irq_fail:
More information about the linux-arm-kernel
mailing list