All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
@ 2011-03-28 14:26 ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:26 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: khilman, paul, tony

Patch series to support mstandby mode handling and enabling runtime PM
support for DMA driver.

Change History:
v4:
Fixed Paul's comment:
http://www.mail-archive.com/linux-omap@vger.kernel.org/msg47359.html

v3:
Warning fix:
http://thread.gmane.org/gmane.linux.ports.arm.omap/54753/focus=55097

v2:
 - fixed runtime_status issue if channel linking feature is used.
 - fixed context restore issue during off mode.
 - removed sysconfig register access during DMA context/restore

The review comments and alignment can be found at:
http://thread.gmane.org/gmane.linux.ports.arm.omap/53150

Applies cleanly on top of:
git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git
Branch: omap-for-linus
commit  05f689400ea5fa3d71af82f910c8b140f87ad1f3
Merge branches 'devel-mux' and 'devel-misc' into omap-for-linus

Boot testing and dma test cases are executed on OMAP4430(Blaze).
More details on testing is available at:
http://article.gmane.org/gmane.linux.ports.arm.omap/54753

G, Manjunath Kondaiah (4):
  OMAP2+: PM: omap device: API's for handling mstandby mode
  OMAP2+: DMA: prevent races while setting M idle mode to nostandby
  OMAP: PM: DMA: Enable runtime pm
  OMAP: DMA: Fix: context restore during off mode

 arch/arm/mach-omap1/dma.c                     |    1 +
 arch/arm/mach-omap2/dma.c                     |   16 ++
 arch/arm/mach-omap2/omap_hwmod.c              |   42 ++++++
 arch/arm/plat-omap/dma.c                      |  196 +++++++++++++++++++++----
 arch/arm/plat-omap/include/plat/dma.h         |    1 +
 arch/arm/plat-omap/include/plat/omap_device.h |    2 +
 arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
 arch/arm/plat-omap/omap_device.c              |   62 ++++++++
 8 files changed, 291 insertions(+), 33 deletions(-)


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

* [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
@ 2011-03-28 14:26 ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:26 UTC (permalink / raw)
  To: linux-arm-kernel

Patch series to support mstandby mode handling and enabling runtime PM
support for DMA driver.

Change History:
v4:
Fixed Paul's comment:
http://www.mail-archive.com/linux-omap at vger.kernel.org/msg47359.html

v3:
Warning fix:
http://thread.gmane.org/gmane.linux.ports.arm.omap/54753/focus=55097

v2:
 - fixed runtime_status issue if channel linking feature is used.
 - fixed context restore issue during off mode.
 - removed sysconfig register access during DMA context/restore

The review comments and alignment can be found at:
http://thread.gmane.org/gmane.linux.ports.arm.omap/53150

Applies cleanly on top of:
git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git
Branch: omap-for-linus
commit  05f689400ea5fa3d71af82f910c8b140f87ad1f3
Merge branches 'devel-mux' and 'devel-misc' into omap-for-linus

Boot testing and dma test cases are executed on OMAP4430(Blaze).
More details on testing is available at:
http://article.gmane.org/gmane.linux.ports.arm.omap/54753

G, Manjunath Kondaiah (4):
  OMAP2+: PM: omap device: API's for handling mstandby mode
  OMAP2+: DMA: prevent races while setting M idle mode to nostandby
  OMAP: PM: DMA: Enable runtime pm
  OMAP: DMA: Fix: context restore during off mode

 arch/arm/mach-omap1/dma.c                     |    1 +
 arch/arm/mach-omap2/dma.c                     |   16 ++
 arch/arm/mach-omap2/omap_hwmod.c              |   42 ++++++
 arch/arm/plat-omap/dma.c                      |  196 +++++++++++++++++++++----
 arch/arm/plat-omap/include/plat/dma.h         |    1 +
 arch/arm/plat-omap/include/plat/omap_device.h |    2 +
 arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
 arch/arm/plat-omap/omap_device.c              |   62 ++++++++
 8 files changed, 291 insertions(+), 33 deletions(-)

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

* [PATCH v4 1/4] OMAP2+: PM: omap device: API's for handling mstandby mode
  2011-03-28 14:26 ` G, Manjunath Kondaiah
@ 2011-03-28 14:26   ` G, Manjunath Kondaiah
  -1 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:26 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: khilman, paul, tony

Certain errata in OMAP2+ processors will require forcing
master standby to "no standby" mode before completing on going
operation. Without this, the results will be unpredictable.

Since current implementation of PM run time framework does not support
changing sysconfig settings during middle of the on going operation,
these API's will support the same. One API will force the device's
sysconfig mstandby mode settings to "no standby" and other API will
release "no standby" mode and sets it to "smart standby" or "no
standby? depending on HWMOD_SWSUP_MSTANDBY value.

These API's should be used by device drivers only incase of
erratum applicable to their modules if there is no other methods
to resolve.

These API's are required for multiple DMA errata which require
putting DMA controller in no mstandby mode before stopping dma.

The applicable errata:
1. Erratum ID: i557(Applicable for omap36xx all ES versions)
The channel hangs when the Pause bit (DMA4_CDPi [7] ) is cleared
through config port while in Standby.

2. Erratum ID: i541
sDMA FIFO draining does not finish. Applicable to all omap2+ except
omap4.

3. Erratum ID:i88
The sDMA to be put in no mstandby mode before disabling the channel
after completing the data transfer operation.
Applicable only for OMAP3430 ES1.0

Also fixes typo HWMOD_SWSUP_MSTDBY to HWMOD_SWSUP_MSTANDBY in
omap_hwmod.h

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod.c              |   42 +++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_device.h |    2 +
 arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
 arch/arm/plat-omap/omap_device.c              |   62 +++++++++++++++++++++++++
 4 files changed, 109 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e034294..7966cc0 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1594,6 +1594,48 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode)
 }
 
 /**
+ * omap_hwmod_set_master_standbymode - set the hwmod's OCP mstandby mode
+ * @oh: struct omap_hwmod *
+ * @midlemode: flag to set mstandby to either "no standby" or "smart standby"
+ *
+ * Sets the IP block's OCP mstandby mode in hardware, and updates our
+ * local copy.  Intended to be used by drivers that have some erratum
+ * that requires direct manipulation of the MIDLEMODE bits.  Returns
+ * -EINVAL if @oh is null, or passes along the return value from
+ * _set_master_standbymode().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode)
+{
+	u32 v;
+	u8 sf;
+	int retval = 0;
+
+	if (!oh)
+		return -EINVAL;
+
+	if (!oh->class->sysc)
+		return -EINVAL;
+
+	v = oh->_sysc_cache;
+	sf = oh->class->sysc->sysc_flags;
+
+	if (sf & SYSC_HAS_MIDLEMODE) {
+		if (idlemode)
+			idlemode = HWMOD_IDLEMODE_NO;
+		else
+			idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ?
+				HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
+	}
+	retval = _set_master_standbymode(oh, idlemode, &v);
+	if (!retval)
+		_write_sysconfig(v, oh);
+
+	return retval;
+}
+
+/**
  * omap_hwmod_lookup - look up a registered omap_hwmod by name
  * @name: name of the omap_hwmod to look up
  *
diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index e4c349f..42e0186 100644
--- a/arch/arm/plat-omap/include/plat/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -117,6 +117,8 @@ int omap_device_enable_hwmods(struct omap_device *od);
 int omap_device_disable_clocks(struct omap_device *od);
 int omap_device_enable_clocks(struct omap_device *od);
 
+int omap_device_require_no_mstandby(struct platform_device *pdev);
+int omap_device_release_no_mstandby(struct platform_device *pdev);
 
 /*
  * Entries should be kept in latency order ascending
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1adea9c..2437f10 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -373,7 +373,7 @@ struct omap_hwmod_omap4_prcm {
  *
  * HWMOD_SWSUP_SIDLE: omap_hwmod code should manually bring module in and out
  *     of idle, rather than relying on module smart-idle
- * HWMOD_SWSUP_MSTDBY: omap_hwmod code should manually bring module in and out
+ * HWMOD_SWSUP_MSTANDBY: omap_hwmod code should manually bring module in and out
  *     of standby, rather than relying on module smart-standby
  * HWMOD_INIT_NO_RESET: don't reset this module at boot - important for
  *     SDRAM controller, etc. XXX probably belongs outside the main hwmod file
@@ -567,6 +567,8 @@ int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
 int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
 int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle);
 
+int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode);
+
 int omap_hwmod_reset(struct omap_hwmod *oh);
 void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 9bbda9a..257c835 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -628,6 +628,68 @@ int omap_device_idle(struct platform_device *pdev)
 }
 
 /**
+ * omap_device_require_no_mstandby - set no mstandby mode of an omap_device
+ * @od: struct omap_device * to idle
+ *
+ * Sets the IP block's OCP master standby to no mstandby mode in hardware.
+ *
+ * Intended to be used by drivers that have some erratum that requires direct
+ * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the
+ * omap_device is not currently enabled or passes along the return value
+ * of omap_hwmod_set_master_standbymode().
+ */
+int omap_device_require_no_mstandby(struct platform_device *pdev)
+{
+	int ret  = 0, i;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+
+	od = _find_by_pdev(pdev);
+	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+		WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
+		     od->pdev.name, od->pdev.id, __func__, od->_state);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < od->hwmods_cnt; i++)
+		ret = omap_hwmod_set_master_standbymode(od->hwmods[i], true);
+
+	return ret;
+}
+
+/**
+ * omap_device_release_no_mstandby - releases no mstandby mode of an omap_device
+ * @od: struct omap_device * to idle
+ *
+ * Release no mstandby mode and sets the master standby to either no standby or
+ * smart standby in IP block's OCP in hardware depending on status of the flag
+ * HWMOD_SWSUP_MSTANDBY.
+ *
+ * Intended to be used by drivers that have some erratum that requires direct
+ * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the
+ * omap_device is not currently enabled or passes along the return value
+ * of omap_hwmod_set_master_standbymode().
+ */
+int omap_device_release_no_mstandby(struct platform_device *pdev)
+{
+	int ret  = 0, i;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+
+	od = _find_by_pdev(pdev);
+	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+		WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
+		     od->pdev.name, od->pdev.id, __func__, od->_state);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < od->hwmods_cnt; i++)
+		ret = omap_hwmod_set_master_standbymode(od->hwmods[i], false);
+
+	return ret;
+}
+
+/**
  * omap_device_shutdown - shut down an omap_device
  * @od: struct omap_device * to shut down
  *
-- 
1.7.1


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

* [PATCH v4 1/4] OMAP2+: PM: omap device: API's for handling mstandby mode
@ 2011-03-28 14:26   ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:26 UTC (permalink / raw)
  To: linux-arm-kernel

Certain errata in OMAP2+ processors will require forcing
master standby to "no standby" mode before completing on going
operation. Without this, the results will be unpredictable.

Since current implementation of PM run time framework does not support
changing sysconfig settings during middle of the on going operation,
these API's will support the same. One API will force the device's
sysconfig mstandby mode settings to "no standby" and other API will
release "no standby" mode and sets it to "smart standby" or "no
standby? depending on HWMOD_SWSUP_MSTANDBY value.

These API's should be used by device drivers only incase of
erratum applicable to their modules if there is no other methods
to resolve.

These API's are required for multiple DMA errata which require
putting DMA controller in no mstandby mode before stopping dma.

The applicable errata:
1. Erratum ID: i557(Applicable for omap36xx all ES versions)
The channel hangs when the Pause bit (DMA4_CDPi [7] ) is cleared
through config port while in Standby.

2. Erratum ID: i541
sDMA FIFO draining does not finish. Applicable to all omap2+ except
omap4.

3. Erratum ID:i88
The sDMA to be put in no mstandby mode before disabling the channel
after completing the data transfer operation.
Applicable only for OMAP3430 ES1.0

Also fixes typo HWMOD_SWSUP_MSTDBY to HWMOD_SWSUP_MSTANDBY in
omap_hwmod.h

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
---
 arch/arm/mach-omap2/omap_hwmod.c              |   42 +++++++++++++++++
 arch/arm/plat-omap/include/plat/omap_device.h |    2 +
 arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
 arch/arm/plat-omap/omap_device.c              |   62 +++++++++++++++++++++++++
 4 files changed, 109 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e034294..7966cc0 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1594,6 +1594,48 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode)
 }
 
 /**
+ * omap_hwmod_set_master_standbymode - set the hwmod's OCP mstandby mode
+ * @oh: struct omap_hwmod *
+ * @midlemode: flag to set mstandby to either "no standby" or "smart standby"
+ *
+ * Sets the IP block's OCP mstandby mode in hardware, and updates our
+ * local copy.  Intended to be used by drivers that have some erratum
+ * that requires direct manipulation of the MIDLEMODE bits.  Returns
+ * -EINVAL if @oh is null, or passes along the return value from
+ * _set_master_standbymode().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode)
+{
+	u32 v;
+	u8 sf;
+	int retval = 0;
+
+	if (!oh)
+		return -EINVAL;
+
+	if (!oh->class->sysc)
+		return -EINVAL;
+
+	v = oh->_sysc_cache;
+	sf = oh->class->sysc->sysc_flags;
+
+	if (sf & SYSC_HAS_MIDLEMODE) {
+		if (idlemode)
+			idlemode = HWMOD_IDLEMODE_NO;
+		else
+			idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ?
+				HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
+	}
+	retval = _set_master_standbymode(oh, idlemode, &v);
+	if (!retval)
+		_write_sysconfig(v, oh);
+
+	return retval;
+}
+
+/**
  * omap_hwmod_lookup - look up a registered omap_hwmod by name
  * @name: name of the omap_hwmod to look up
  *
diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h
index e4c349f..42e0186 100644
--- a/arch/arm/plat-omap/include/plat/omap_device.h
+++ b/arch/arm/plat-omap/include/plat/omap_device.h
@@ -117,6 +117,8 @@ int omap_device_enable_hwmods(struct omap_device *od);
 int omap_device_disable_clocks(struct omap_device *od);
 int omap_device_enable_clocks(struct omap_device *od);
 
+int omap_device_require_no_mstandby(struct platform_device *pdev);
+int omap_device_release_no_mstandby(struct platform_device *pdev);
 
 /*
  * Entries should be kept in latency order ascending
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1adea9c..2437f10 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -373,7 +373,7 @@ struct omap_hwmod_omap4_prcm {
  *
  * HWMOD_SWSUP_SIDLE: omap_hwmod code should manually bring module in and out
  *     of idle, rather than relying on module smart-idle
- * HWMOD_SWSUP_MSTDBY: omap_hwmod code should manually bring module in and out
+ * HWMOD_SWSUP_MSTANDBY: omap_hwmod code should manually bring module in and out
  *     of standby, rather than relying on module smart-standby
  * HWMOD_INIT_NO_RESET: don't reset this module at boot - important for
  *     SDRAM controller, etc. XXX probably belongs outside the main hwmod file
@@ -567,6 +567,8 @@ int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
 int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
 int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle);
 
+int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode);
+
 int omap_hwmod_reset(struct omap_hwmod *oh);
 void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 9bbda9a..257c835 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -628,6 +628,68 @@ int omap_device_idle(struct platform_device *pdev)
 }
 
 /**
+ * omap_device_require_no_mstandby - set no mstandby mode of an omap_device
+ * @od: struct omap_device * to idle
+ *
+ * Sets the IP block's OCP master standby to no mstandby mode in hardware.
+ *
+ * Intended to be used by drivers that have some erratum that requires direct
+ * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the
+ * omap_device is not currently enabled or passes along the return value
+ * of omap_hwmod_set_master_standbymode().
+ */
+int omap_device_require_no_mstandby(struct platform_device *pdev)
+{
+	int ret  = 0, i;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+
+	od = _find_by_pdev(pdev);
+	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+		WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
+		     od->pdev.name, od->pdev.id, __func__, od->_state);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < od->hwmods_cnt; i++)
+		ret = omap_hwmod_set_master_standbymode(od->hwmods[i], true);
+
+	return ret;
+}
+
+/**
+ * omap_device_release_no_mstandby - releases no mstandby mode of an omap_device
+ * @od: struct omap_device * to idle
+ *
+ * Release no mstandby mode and sets the master standby to either no standby or
+ * smart standby in IP block's OCP in hardware depending on status of the flag
+ * HWMOD_SWSUP_MSTANDBY.
+ *
+ * Intended to be used by drivers that have some erratum that requires direct
+ * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the
+ * omap_device is not currently enabled or passes along the return value
+ * of omap_hwmod_set_master_standbymode().
+ */
+int omap_device_release_no_mstandby(struct platform_device *pdev)
+{
+	int ret  = 0, i;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+
+	od = _find_by_pdev(pdev);
+	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
+		WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n",
+		     od->pdev.name, od->pdev.id, __func__, od->_state);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < od->hwmods_cnt; i++)
+		ret = omap_hwmod_set_master_standbymode(od->hwmods[i], false);
+
+	return ret;
+}
+
+/**
  * omap_device_shutdown - shut down an omap_device
  * @od: struct omap_device * to shut down
  *
-- 
1.7.1

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

* [PATCH v4 2/4] OMAP2+: DMA: prevent races while setting M idle mode to nostandby
  2011-03-28 14:26 ` G, Manjunath Kondaiah
@ 2011-03-28 14:27   ` G, Manjunath Kondaiah
  -1 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:27 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: khilman, paul, tony

If two DMA users tries to set no mstandby mode at the same time, a race
condition would arise. Prevent that by using a spin lock and counting
up/down the number of times nostandby is set/reset.

Initial patch is created by Adrian Hunter <adrian.hunter@nokia.com>
https://patchwork.kernel.org/patch/366831/

Patch reworked to use API implemented at hwmod layer.

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
---
 arch/arm/mach-omap1/dma.c             |    1 +
 arch/arm/mach-omap2/dma.c             |   16 +++++++++++++
 arch/arm/plat-omap/dma.c              |   40 +++++++++++++++++++--------------
 arch/arm/plat-omap/include/plat/dma.h |    1 +
 4 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
index d855934..fa2d1b0 100644
--- a/arch/arm/mach-omap1/dma.c
+++ b/arch/arm/mach-omap1/dma.c
@@ -351,6 +351,7 @@ static int __init omap1_system_dma_init(void)
 	p->dma_write		= dma_write;
 	p->dma_read		= dma_read;
 	p->disable_irq_lch	= NULL;
+	p->midlemode		= NULL;
 
 	p->errata = configure_dma_errata();
 
diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c
index 34922b2..6e12e71 100644
--- a/arch/arm/mach-omap2/dma.c
+++ b/arch/arm/mach-omap2/dma.c
@@ -36,7 +36,9 @@
 
 static u32 errata;
 static u8 dma_stride;
+static u32 midlemode_save_cnt;
 
+static struct platform_device *pdev;
 static struct omap_dma_dev_attr *d;
 
 static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end;
@@ -117,6 +119,18 @@ static inline u32 dma_read(int reg, int lch)
 	return val;
 }
 
+static void midlemode_nostandby(bool nostandby)
+{
+	/* TODO: midlemode_save_cnt can be moved to hwmod layer? */
+	if (nostandby) {
+		omap_device_require_no_mstandby(pdev);
+		midlemode_save_cnt += 1;
+	} else {
+		omap_device_release_no_mstandby(pdev);
+		midlemode_save_cnt -= 1;
+	}
+}
+
 static inline void omap2_disable_irq_lch(int lch)
 {
 	u32 val;
@@ -253,6 +267,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
 	p->clear_dma		= omap2_clear_dma;
 	p->dma_write		= dma_write;
 	p->dma_read		= dma_read;
+	p->midlemode		= midlemode_nostandby;
 
 	p->clear_lch_regs	= NULL;
 
@@ -286,6 +301,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
 		dev_err(&od->pdev.dev, "%s: kzalloc fail\n", __func__);
 		return -ENOMEM;
 	}
+	pdev = &od->pdev;
 	return 0;
 }
 
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 2ec3b5d..5af9bb2 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -38,8 +38,9 @@
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <plat/dma.h>
 
+#include <plat/dma.h>
+#include <plat/omap_device.h>
 #include <plat/tc.h>
 
 #undef DEBUG
@@ -924,6 +925,7 @@ EXPORT_SYMBOL(omap_start_dma);
 void omap_stop_dma(int lch)
 {
 	u32 l;
+	unsigned long flags;
 
 	/* Disable all interrupts on the channel */
 	if (cpu_class_is_omap1())
@@ -933,14 +935,13 @@ void omap_stop_dma(int lch)
 	if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
 			(l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
 		int i = 0;
-		u32 sys_cf;
 
 		/* Configure No-Standby */
-		l = p->dma_read(OCP_SYSCONFIG, lch);
-		sys_cf = l;
-		l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
-		l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
-		p->dma_write(l , OCP_SYSCONFIG, 0);
+		if (p->midlemode) {
+			spin_lock_irqsave(&dma_chan_lock, flags);
+			p->midlemode(true);
+			spin_unlock_irqrestore(&dma_chan_lock, flags);
+		}
 
 		l = p->dma_read(CCR, lch);
 		l &= ~OMAP_DMA_CCR_EN;
@@ -958,7 +959,11 @@ void omap_stop_dma(int lch)
 			printk(KERN_ERR "DMA drain did not complete on "
 					"lch %d\n", lch);
 		/* Restore OCP_SYSCONFIG */
-		p->dma_write(sys_cf, OCP_SYSCONFIG, lch);
+		if (p->midlemode) {
+			spin_lock_irqsave(&dma_chan_lock, flags);
+			p->midlemode(false);
+			spin_unlock_irqrestore(&dma_chan_lock, flags);
+		}
 	} else {
 		l &= ~OMAP_DMA_CCR_EN;
 		p->dma_write(l, CCR, lch);
@@ -1610,7 +1615,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
 {
 	int *channels;
 	u32 l, i;
-	u32 sys_cf = 0;
+	unsigned long flags;
 
 	/* Check for input params */
 	if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
@@ -1625,12 +1630,10 @@ int omap_stop_dma_chain_transfers(int chain_id)
 	}
 	channels = dma_linked_lch[chain_id].linked_dmach_q;
 
-	if (IS_DMA_ERRATA(DMA_ERRATA_i88)) {
-		sys_cf = p->dma_read(OCP_SYSCONFIG, 0);
-		l = sys_cf;
-		/* Middle mode reg set no Standby */
-		l &= ~((1 << 12)|(1 << 13));
-		p->dma_write(l, OCP_SYSCONFIG, 0);
+	if (IS_DMA_ERRATA(DMA_ERRATA_i88) && p->midlemode) {
+		spin_lock_irqsave(&dma_chan_lock, flags);
+		p->midlemode(true);
+		spin_unlock_irqrestore(&dma_chan_lock, flags);
 	}
 
 	for (i = 0; i < dma_linked_lch[chain_id].no_of_lchs_linked; i++) {
@@ -1650,8 +1653,11 @@ int omap_stop_dma_chain_transfers(int chain_id)
 	/* Reset the Queue pointers */
 	OMAP_DMA_CHAIN_QINIT(chain_id);
 
-	if (IS_DMA_ERRATA(DMA_ERRATA_i88))
-		p->dma_write(sys_cf, OCP_SYSCONFIG, 0);
+	if (IS_DMA_ERRATA(DMA_ERRATA_i88 && p->midlemode)) {
+		spin_lock_irqsave(&dma_chan_lock, flags);
+		p->midlemode(false);
+		spin_unlock_irqrestore(&dma_chan_lock, flags);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index d1c916f..b20dc5e 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -435,6 +435,7 @@ struct omap_system_dma_plat_info {
 	void (*clear_dma)(int lch);
 	void (*dma_write)(u32 val, int reg, int lch);
 	u32 (*dma_read)(int reg, int lch);
+	void (*midlemode)(bool nostandby);
 };
 
 extern void omap_set_dma_priority(int lch, int dst_port, int priority);
-- 
1.7.1


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

* [PATCH v4 2/4] OMAP2+: DMA: prevent races while setting M idle mode to nostandby
@ 2011-03-28 14:27   ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:27 UTC (permalink / raw)
  To: linux-arm-kernel

If two DMA users tries to set no mstandby mode at the same time, a race
condition would arise. Prevent that by using a spin lock and counting
up/down the number of times nostandby is set/reset.

Initial patch is created by Adrian Hunter <adrian.hunter@nokia.com>
https://patchwork.kernel.org/patch/366831/

Patch reworked to use API implemented at hwmod layer.

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
---
 arch/arm/mach-omap1/dma.c             |    1 +
 arch/arm/mach-omap2/dma.c             |   16 +++++++++++++
 arch/arm/plat-omap/dma.c              |   40 +++++++++++++++++++--------------
 arch/arm/plat-omap/include/plat/dma.h |    1 +
 4 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
index d855934..fa2d1b0 100644
--- a/arch/arm/mach-omap1/dma.c
+++ b/arch/arm/mach-omap1/dma.c
@@ -351,6 +351,7 @@ static int __init omap1_system_dma_init(void)
 	p->dma_write		= dma_write;
 	p->dma_read		= dma_read;
 	p->disable_irq_lch	= NULL;
+	p->midlemode		= NULL;
 
 	p->errata = configure_dma_errata();
 
diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c
index 34922b2..6e12e71 100644
--- a/arch/arm/mach-omap2/dma.c
+++ b/arch/arm/mach-omap2/dma.c
@@ -36,7 +36,9 @@
 
 static u32 errata;
 static u8 dma_stride;
+static u32 midlemode_save_cnt;
 
+static struct platform_device *pdev;
 static struct omap_dma_dev_attr *d;
 
 static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end;
@@ -117,6 +119,18 @@ static inline u32 dma_read(int reg, int lch)
 	return val;
 }
 
+static void midlemode_nostandby(bool nostandby)
+{
+	/* TODO: midlemode_save_cnt can be moved to hwmod layer? */
+	if (nostandby) {
+		omap_device_require_no_mstandby(pdev);
+		midlemode_save_cnt += 1;
+	} else {
+		omap_device_release_no_mstandby(pdev);
+		midlemode_save_cnt -= 1;
+	}
+}
+
 static inline void omap2_disable_irq_lch(int lch)
 {
 	u32 val;
@@ -253,6 +267,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
 	p->clear_dma		= omap2_clear_dma;
 	p->dma_write		= dma_write;
 	p->dma_read		= dma_read;
+	p->midlemode		= midlemode_nostandby;
 
 	p->clear_lch_regs	= NULL;
 
@@ -286,6 +301,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
 		dev_err(&od->pdev.dev, "%s: kzalloc fail\n", __func__);
 		return -ENOMEM;
 	}
+	pdev = &od->pdev;
 	return 0;
 }
 
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 2ec3b5d..5af9bb2 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -38,8 +38,9 @@
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <plat/dma.h>
 
+#include <plat/dma.h>
+#include <plat/omap_device.h>
 #include <plat/tc.h>
 
 #undef DEBUG
@@ -924,6 +925,7 @@ EXPORT_SYMBOL(omap_start_dma);
 void omap_stop_dma(int lch)
 {
 	u32 l;
+	unsigned long flags;
 
 	/* Disable all interrupts on the channel */
 	if (cpu_class_is_omap1())
@@ -933,14 +935,13 @@ void omap_stop_dma(int lch)
 	if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
 			(l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
 		int i = 0;
-		u32 sys_cf;
 
 		/* Configure No-Standby */
-		l = p->dma_read(OCP_SYSCONFIG, lch);
-		sys_cf = l;
-		l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
-		l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
-		p->dma_write(l , OCP_SYSCONFIG, 0);
+		if (p->midlemode) {
+			spin_lock_irqsave(&dma_chan_lock, flags);
+			p->midlemode(true);
+			spin_unlock_irqrestore(&dma_chan_lock, flags);
+		}
 
 		l = p->dma_read(CCR, lch);
 		l &= ~OMAP_DMA_CCR_EN;
@@ -958,7 +959,11 @@ void omap_stop_dma(int lch)
 			printk(KERN_ERR "DMA drain did not complete on "
 					"lch %d\n", lch);
 		/* Restore OCP_SYSCONFIG */
-		p->dma_write(sys_cf, OCP_SYSCONFIG, lch);
+		if (p->midlemode) {
+			spin_lock_irqsave(&dma_chan_lock, flags);
+			p->midlemode(false);
+			spin_unlock_irqrestore(&dma_chan_lock, flags);
+		}
 	} else {
 		l &= ~OMAP_DMA_CCR_EN;
 		p->dma_write(l, CCR, lch);
@@ -1610,7 +1615,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
 {
 	int *channels;
 	u32 l, i;
-	u32 sys_cf = 0;
+	unsigned long flags;
 
 	/* Check for input params */
 	if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
@@ -1625,12 +1630,10 @@ int omap_stop_dma_chain_transfers(int chain_id)
 	}
 	channels = dma_linked_lch[chain_id].linked_dmach_q;
 
-	if (IS_DMA_ERRATA(DMA_ERRATA_i88)) {
-		sys_cf = p->dma_read(OCP_SYSCONFIG, 0);
-		l = sys_cf;
-		/* Middle mode reg set no Standby */
-		l &= ~((1 << 12)|(1 << 13));
-		p->dma_write(l, OCP_SYSCONFIG, 0);
+	if (IS_DMA_ERRATA(DMA_ERRATA_i88) && p->midlemode) {
+		spin_lock_irqsave(&dma_chan_lock, flags);
+		p->midlemode(true);
+		spin_unlock_irqrestore(&dma_chan_lock, flags);
 	}
 
 	for (i = 0; i < dma_linked_lch[chain_id].no_of_lchs_linked; i++) {
@@ -1650,8 +1653,11 @@ int omap_stop_dma_chain_transfers(int chain_id)
 	/* Reset the Queue pointers */
 	OMAP_DMA_CHAIN_QINIT(chain_id);
 
-	if (IS_DMA_ERRATA(DMA_ERRATA_i88))
-		p->dma_write(sys_cf, OCP_SYSCONFIG, 0);
+	if (IS_DMA_ERRATA(DMA_ERRATA_i88 && p->midlemode)) {
+		spin_lock_irqsave(&dma_chan_lock, flags);
+		p->midlemode(false);
+		spin_unlock_irqrestore(&dma_chan_lock, flags);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index d1c916f..b20dc5e 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -435,6 +435,7 @@ struct omap_system_dma_plat_info {
 	void (*clear_dma)(int lch);
 	void (*dma_write)(u32 val, int reg, int lch);
 	u32 (*dma_read)(int reg, int lch);
+	void (*midlemode)(bool nostandby);
 };
 
 extern void omap_set_dma_priority(int lch, int dst_port, int priority);
-- 
1.7.1

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

* [PATCH v4 3/4] OMAP: PM: DMA: Enable runtime pm
  2011-03-28 14:26 ` G, Manjunath Kondaiah
@ 2011-03-28 14:27   ` G, Manjunath Kondaiah
  -1 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:27 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: khilman, paul, tony

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), OMAP3430LDP(Zoom2), OMAP3630(Zoom3), OMAP4(Blaze)

The DMA tests(including chaining) are executed and tested for suspend state
after each test cases.

On zoom2 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

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
---
 arch/arm/plat-omap/dma.c |  147 ++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 141 insertions(+), 6 deletions(-)

diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 5af9bb2..3c39794 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>
@@ -60,6 +61,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;
@@ -172,6 +174,7 @@ void omap_set_dma_priority(int lch, int dst_port, int priority)
 	unsigned long reg;
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1()) {
 		switch (dst_port) {
 		case OMAP_DMA_PORT_OCP_T1:	/* FFFECC00 */
@@ -188,6 +191,7 @@ void omap_set_dma_priority(int lch, int dst_port, int priority)
 			break;
 		default:
 			BUG();
+			pm_runtime_put_autosuspend(dev);
 			return;
 		}
 		l = omap_readl(reg);
@@ -206,6 +210,7 @@ void omap_set_dma_priority(int lch, int dst_port, int priority)
 			ccr &= ~(1 << 6);
 		p->dma_write(ccr, CCR, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_priority);
 
@@ -215,6 +220,8 @@ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
+
 	l = p->dma_read(CSDP, lch);
 	l &= ~0x03;
 	l |= data_type;
@@ -269,6 +276,7 @@ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
 
 	p->dma_write(elem_count, CEN, lch);
 	p->dma_write(frame_count, CFN, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_transfer_params);
 
@@ -276,6 +284,7 @@ void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 {
 	BUG_ON(omap_dma_in_1510_mode());
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1()) {
 		u16 w;
 
@@ -329,11 +338,13 @@ void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 		color &= 0xffffff;
 		p->dma_write(color, COLOR, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_color_mode);
 
 void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode)
 {
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap2()) {
 		u32 csdp;
 
@@ -342,11 +353,13 @@ void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode)
 		csdp |= (mode << 16);
 		p->dma_write(csdp, CSDP, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_write_mode);
 
 void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode)
 {
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1() && !cpu_is_omap15xx()) {
 		u32 l;
 
@@ -355,6 +368,7 @@ void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode)
 		l |= mode;
 		p->dma_write(l, LCH_CTRL, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_channel_mode);
 
@@ -365,6 +379,8 @@ void omap_set_dma_src_params(int lch, int src_port, int src_amode,
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
+
 	if (cpu_class_is_omap1()) {
 		u16 w;
 
@@ -383,11 +399,13 @@ void omap_set_dma_src_params(int lch, int src_port, int src_amode,
 
 	p->dma_write(src_ei, CSEI, lch);
 	p->dma_write(src_fi, CSFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_params);
 
 void omap_set_dma_params(int lch, struct omap_dma_channel_params *params)
 {
+	pm_runtime_get_sync(dev);
 	omap_set_dma_transfer_params(lch, params->data_type,
 				     params->elem_count, params->frame_count,
 				     params->sync_mode, params->trigger,
@@ -402,6 +420,7 @@ void omap_set_dma_params(int lch, struct omap_dma_channel_params *params)
 	if (params->read_prio || params->write_prio)
 		omap_dma_set_prio_lch(lch, params->read_prio,
 				      params->write_prio);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_params);
 
@@ -410,8 +429,10 @@ void omap_set_dma_src_index(int lch, int eidx, int fidx)
 	if (cpu_class_is_omap2())
 		return;
 
+	pm_runtime_get_sync(dev);
 	p->dma_write(eidx, CSEI, lch);
 	p->dma_write(fidx, CSFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_index);
 
@@ -419,11 +440,13 @@ void omap_set_dma_src_data_pack(int lch, int enable)
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CSDP, lch);
 	l &= ~(1 << 6);
 	if (enable)
 		l |= (1 << 6);
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_data_pack);
 
@@ -432,6 +455,7 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 	unsigned int burst = 0;
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CSDP, lch);
 	l &= ~(0x03 << 7);
 
@@ -469,6 +493,7 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 
 	l |= (burst << 7);
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_burst_mode);
 
@@ -478,6 +503,7 @@ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
 			      int dst_ei, int dst_fi)
 {
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	if (cpu_class_is_omap1()) {
 		l = p->dma_read(CSDP, lch);
@@ -495,6 +521,7 @@ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
 
 	p->dma_write(dst_ei, CDEI, lch);
 	p->dma_write(dst_fi, CDFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_params);
 
@@ -502,21 +529,25 @@ void omap_set_dma_dest_index(int lch, int eidx, int fidx)
 {
 	if (cpu_class_is_omap2())
 		return;
+	pm_runtime_get_sync(dev);
 
 	p->dma_write(eidx, CDEI, lch);
 	p->dma_write(fidx, CDFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_index);
 
 void omap_set_dma_dest_data_pack(int lch, int enable)
 {
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	l = p->dma_read(CSDP, lch);
 	l &= ~(1 << 13);
 	if (enable)
 		l |= 1 << 13;
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_data_pack);
 
@@ -524,6 +555,7 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 {
 	unsigned int burst = 0;
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	l = p->dma_read(CSDP, lch);
 	l &= ~(0x03 << 14);
@@ -555,10 +587,12 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 	default:
 		printk(KERN_ERR "Invalid DMA burst mode\n");
 		BUG();
+		pm_runtime_put_autosuspend(dev);
 		return;
 	}
 	l |= (burst << 14);
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
 
@@ -566,6 +600,7 @@ static inline void omap_enable_channel_irq(int lch)
 {
 	u32 status;
 
+	pm_runtime_get_sync(dev);
 	/* Clear CSR */
 	if (cpu_class_is_omap1())
 		status = p->dma_read(CSR, lch);
@@ -574,12 +609,15 @@ static inline void omap_enable_channel_irq(int lch)
 
 	/* Enable some nice interrupts. */
 	p->dma_write(dma_chan[lch].enabled_irqs, CICR, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static void omap_disable_channel_irq(int lch)
 {
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap2())
 		p->dma_write(0, CICR, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 void omap_enable_dma_irq(int lch, u16 bits)
@@ -597,6 +635,7 @@ EXPORT_SYMBOL(omap_disable_dma_irq);
 static inline void enable_lnk(int lch)
 {
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	l = p->dma_read(CLNK_CTRL, lch);
 
@@ -614,12 +653,14 @@ static inline void enable_lnk(int lch)
 #endif
 
 	p->dma_write(l, CLNK_CTRL, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static inline void disable_lnk(int lch)
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CLNK_CTRL, lch);
 
 	/* Disable interrupts */
@@ -637,6 +678,7 @@ static inline void disable_lnk(int lch)
 
 	p->dma_write(l, CLNK_CTRL, lch);
 	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+	pm_runtime_put_autosuspend(dev);
 }
 
 static inline void omap2_enable_irq_lch(int lch)
@@ -647,11 +689,13 @@ static inline void omap2_enable_irq_lch(int lch)
 	if (!cpu_class_is_omap2())
 		return;
 
+	pm_runtime_get_sync(dev);
 	spin_lock_irqsave(&dma_chan_lock, flags);
 	val = p->dma_read(IRQENABLE_L0, lch);
 	val |= 1 << lch;
 	p->dma_write(val, IRQENABLE_L0, lch);
 	spin_unlock_irqrestore(&dma_chan_lock, flags);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static inline void omap2_disable_irq_lch(int lch)
@@ -662,11 +706,13 @@ static inline void omap2_disable_irq_lch(int lch)
 	if (!cpu_class_is_omap2())
 		return;
 
+	pm_runtime_get_sync(dev);
 	spin_lock_irqsave(&dma_chan_lock, flags);
 	val = p->dma_read(IRQENABLE_L0, lch);
 	val &= ~(1 << lch);
 	p->dma_write(val, IRQENABLE_L0, lch);
 	spin_unlock_irqrestore(&dma_chan_lock, flags);
+	pm_runtime_put_autosuspend(dev);
 }
 
 int omap_request_dma(int dev_id, const char *dev_name,
@@ -677,6 +723,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) {
@@ -687,6 +734,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;
@@ -744,6 +792,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
 	}
 
 	*dma_ch_out = free_ch;
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -759,6 +808,7 @@ void omap_free_dma(int lch)
 		return;
 	}
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1()) {
 		/* Disable all DMA interrupts for the channel. */
 		p->dma_write(0, CICR, lch);
@@ -781,6 +831,7 @@ void omap_free_dma(int lch)
 		omap_clear_dma(lch);
 	}
 
+	pm_runtime_put_autosuspend(dev);
 	spin_lock_irqsave(&dma_chan_lock, flags);
 	dma_chan[lch].dev_id = -1;
 	dma_chan[lch].next_lch = -1;
@@ -818,7 +869,9 @@ omap_dma_set_global_params(int arb_rate, int max_fifo_depth, int tparams)
 	reg |= (0x3 & tparams) << 12;
 	reg |= (arb_rate & 0xff) << 16;
 
+	pm_runtime_get_sync(dev);
 	p->dma_write(reg, GCR, 0);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_dma_set_global_params);
 
@@ -841,6 +894,7 @@ omap_dma_set_prio_lch(int lch, unsigned char read_prio,
 		printk(KERN_ERR "Invalid channel id\n");
 		return -EINVAL;
 	}
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CCR, lch);
 	l &= ~((1 << 6) | (1 << 26));
 	if (cpu_is_omap2430() || cpu_is_omap34xx() ||  cpu_is_omap44xx())
@@ -849,6 +903,7 @@ omap_dma_set_prio_lch(int lch, unsigned char read_prio,
 		l |= ((read_prio & 0x1) << 6);
 
 	p->dma_write(l, CCR, lch);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -862,9 +917,11 @@ void omap_clear_dma(int lch)
 {
 	unsigned long flags;
 
+	pm_runtime_get_sync(dev);
 	local_irq_save(flags);
 	p->clear_dma(lch);
 	local_irq_restore(flags);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_clear_dma);
 
@@ -872,6 +929,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.
@@ -903,6 +962,7 @@ void omap_start_dma(int lch)
 			enable_lnk(cur_lch);
 			omap_enable_channel_irq(cur_lch);
 
+			pm_runtime_get_sync(dev);
 			cur_lch = next_lch;
 		} while (next_lch != -1);
 	} else if (IS_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS))
@@ -927,6 +987,7 @@ void omap_stop_dma(int lch)
 	u32 l;
 	unsigned long flags;
 
+	pm_runtime_get_sync(dev);
 	/* Disable all interrupts on the channel */
 	if (cpu_class_is_omap1())
 		p->dma_write(0, CICR, lch);
@@ -989,6 +1050,7 @@ void omap_stop_dma(int lch)
 	}
 
 	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_stop_dma);
 
@@ -1031,6 +1093,7 @@ dma_addr_t omap_get_dma_src_pos(int lch)
 {
 	dma_addr_t offset = 0;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_is_omap15xx())
 		offset = p->dma_read(CPC, lch);
 	else
@@ -1042,6 +1105,7 @@ dma_addr_t omap_get_dma_src_pos(int lch)
 	if (cpu_class_is_omap1())
 		offset |= (p->dma_read(CSSA, lch) & 0xFFFF0000);
 
+	pm_runtime_put_autosuspend(dev);
 	return offset;
 }
 EXPORT_SYMBOL(omap_get_dma_src_pos);
@@ -1058,6 +1122,7 @@ dma_addr_t omap_get_dma_dst_pos(int lch)
 {
 	dma_addr_t offset = 0;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_is_omap15xx())
 		offset = p->dma_read(CPC, lch);
 	else
@@ -1073,13 +1138,20 @@ dma_addr_t omap_get_dma_dst_pos(int lch)
 	if (cpu_class_is_omap1())
 		offset |= (p->dma_read(CDSA, lch) & 0xFFFF0000);
 
+	pm_runtime_put_autosuspend(dev);
 	return offset;
 }
 EXPORT_SYMBOL(omap_get_dma_dst_pos);
 
 int omap_get_dma_active_status(int lch)
 {
-	return (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN) != 0;
+	u32 reg_data;
+
+	pm_runtime_get_sync(dev);
+	reg_data = p->dma_read(CCR, lch);
+	pm_runtime_put_autosuspend(dev);
+	reg_data &= reg_data & OMAP_DMA_CCR_EN;
+	return ((reg_data != 0) ? 1 : 0);
 }
 EXPORT_SYMBOL(omap_get_dma_active_status);
 
@@ -1087,14 +1159,20 @@ int omap_dma_running(void)
 {
 	int lch;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1())
-		if (omap_lcd_dma_running())
+		if (omap_lcd_dma_running()) {
+			pm_runtime_put_autosuspend(dev);
 			return 1;
+		}
 
 	for (lch = 0; lch < dma_chan_count; lch++)
-		if (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN)
+		if (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN) {
+			pm_runtime_put_autosuspend(dev);
 			return 1;
+		}
 
+	pm_runtime_put_autosuspend(dev);
 	return 0;
 }
 
@@ -1105,12 +1183,15 @@ int omap_dma_running(void)
  */
 void omap_dma_link_lch(int lch_head, int lch_queue)
 {
+	pm_runtime_get_sync(dev);
 	if (omap_dma_in_1510_mode()) {
 		if (lch_head == lch_queue) {
 			p->dma_write(p->dma_read(CCR, lch_head) | (3 << 8),
 								CCR, lch_head);
+			pm_runtime_put_autosuspend(dev);
 			return;
 		}
+		pm_runtime_put_autosuspend(dev);
 		printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
 		BUG();
 		return;
@@ -1124,6 +1205,7 @@ void omap_dma_link_lch(int lch_head, int lch_queue)
 	}
 
 	dma_chan[lch_head].next_lch = lch_queue;
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_dma_link_lch);
 
@@ -1132,12 +1214,15 @@ EXPORT_SYMBOL(omap_dma_link_lch);
  */
 void omap_dma_unlink_lch(int lch_head, int lch_queue)
 {
+	pm_runtime_get_sync(dev);
 	if (omap_dma_in_1510_mode()) {
 		if (lch_head == lch_queue) {
 			p->dma_write(p->dma_read(CCR, lch_head) & ~(3 << 8),
 								CCR, lch_head);
+			pm_runtime_put_autosuspend(dev);
 			return;
 		}
+		pm_runtime_put_autosuspend(dev);
 		printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
 		BUG();
 		return;
@@ -1158,6 +1243,7 @@ void omap_dma_unlink_lch(int lch_head, int lch_queue)
 	}
 
 	dma_chan[lch_head].next_lch = -1;
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_dma_unlink_lch);
 
@@ -1167,6 +1253,7 @@ static void create_dma_lch_chain(int lch_head, int lch_queue)
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	/* Check if this is the first link in chain */
 	if (dma_chan[lch_head].next_linked_ch == -1) {
 		dma_chan[lch_head].next_linked_ch = lch_queue;
@@ -1194,6 +1281,7 @@ static void create_dma_lch_chain(int lch_head, int lch_queue)
 	l &= ~(0x1f);
 	l |= (dma_chan[lch_queue].next_linked_ch);
 	p->dma_write(l, CLNK_CTRL, lch_queue);
+	pm_runtime_put_autosuspend(dev);
 }
 
 /**
@@ -1467,6 +1555,7 @@ int omap_dma_chain_a_transfer(int chain_id, int src_start, int dest_start,
 	/* Increment the q_tail */
 	OMAP_DMA_CHAIN_INCQTAIL(chain_id);
 
+	pm_runtime_get_sync(dev);
 	/* Set the params to the free channel */
 	if (src_start != 0)
 		p->dma_write(src_start, CSSA, lch);
@@ -1546,6 +1635,7 @@ int omap_dma_chain_a_transfer(int chain_id, int src_start, int dest_start,
 			dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
 		}
 	}
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -1586,6 +1676,7 @@ int omap_start_dma_chain_transfers(int chain_id)
 		omap_enable_channel_irq(channels[0]);
 	}
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CCR, channels[0]);
 	l |= (1 << 7);
 	dma_linked_lch[chain_id].chain_state = DMA_CHAIN_STARTED;
@@ -1599,6 +1690,7 @@ int omap_start_dma_chain_transfers(int chain_id)
 
 	dma_chan[channels[0]].flags |= OMAP_DMA_ACTIVE;
 
+	pm_runtime_put_autosuspend(dev);
 	return 0;
 }
 EXPORT_SYMBOL(omap_start_dma_chain_transfers);
@@ -1630,6 +1722,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
 	}
 	channels = dma_linked_lch[chain_id].linked_dmach_q;
 
+	pm_runtime_get_sync(dev);
 	if (IS_DMA_ERRATA(DMA_ERRATA_i88) && p->midlemode) {
 		spin_lock_irqsave(&dma_chan_lock, flags);
 		p->midlemode(true);
@@ -1658,6 +1751,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
 		p->midlemode(false);
 		spin_unlock_irqrestore(&dma_chan_lock, flags);
 	}
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -1699,8 +1793,10 @@ int omap_get_dma_chain_index(int chain_id, int *ei, int *fi)
 	/* Get the current channel */
 	lch = channels[dma_linked_lch[chain_id].q_head];
 
+	pm_runtime_get_sync(dev);
 	*ei = p->dma_read(CCEN, lch);
 	*fi = p->dma_read(CCFN, lch);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -1719,6 +1815,7 @@ int omap_get_dma_chain_dst_pos(int chain_id)
 {
 	int lch;
 	int *channels;
+	int reg_data;
 
 	/* Check for input params */
 	if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
@@ -1737,7 +1834,10 @@ int omap_get_dma_chain_dst_pos(int chain_id)
 	/* Get the current channel */
 	lch = channels[dma_linked_lch[chain_id].q_head];
 
-	return p->dma_read(CDAC, lch);
+	pm_runtime_get_sync(dev);
+	reg_data = p->dma_read(CDAC, lch);
+	pm_runtime_put_autosuspend(dev);
+	return reg_data;
 }
 EXPORT_SYMBOL(omap_get_dma_chain_dst_pos);
 
@@ -1753,6 +1853,7 @@ int omap_get_dma_chain_src_pos(int chain_id)
 {
 	int lch;
 	int *channels;
+	int reg_data;
 
 	/* Check for input params */
 	if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
@@ -1771,7 +1872,10 @@ int omap_get_dma_chain_src_pos(int chain_id)
 	/* Get the current channel */
 	lch = channels[dma_linked_lch[chain_id].q_head];
 
-	return p->dma_read(CSAC, lch);
+	pm_runtime_get_sync(dev);
+	reg_data = p->dma_read(CSAC, lch);
+	pm_runtime_put_autosuspend(dev);
+	return reg_data;
 }
 EXPORT_SYMBOL(omap_get_dma_chain_src_pos);
 #endif	/* ifndef CONFIG_ARCH_OMAP1 */
@@ -1811,6 +1915,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;
 }
 
@@ -1895,8 +2001,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);
@@ -1905,6 +2014,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;
 }
 
@@ -1945,17 +2056,20 @@ static struct irqaction omap24xx_dma_irq;
 
 void omap_dma_global_context_save(void)
 {
+	pm_runtime_get_sync(dev);
 	omap_dma_global_context.dma_irqenable_l0 =
 		p->dma_read(IRQENABLE_L0, 0);
 	omap_dma_global_context.dma_ocp_sysconfig =
 		p->dma_read(OCP_SYSCONFIG, 0);
 	omap_dma_global_context.dma_gcr = p->dma_read(GCR, 0);
+	pm_runtime_put_autosuspend(dev);
 }
 
 void omap_dma_global_context_restore(void)
 {
 	int ch;
 
+	pm_runtime_get_sync(dev);
 	p->dma_write(omap_dma_global_context.dma_gcr, GCR, 0);
 	p->dma_write(omap_dma_global_context.dma_ocp_sysconfig,
 		OCP_SYSCONFIG, 0);
@@ -1968,6 +2082,7 @@ void omap_dma_global_context_restore(void)
 	for (ch = 0; ch < dma_chan_count; ch++)
 		if (dma_chan[ch].dev_id != -1)
 			omap_clear_dma(ch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static int __devinit omap_system_dma_probe(struct platform_device *pdev)
@@ -1984,6 +2099,7 @@ static int __devinit omap_system_dma_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+	dev			= &pdev->dev;
 	d			= p->dma_attr;
 	errata			= p->errata;
 
@@ -2005,6 +2121,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);
@@ -2070,6 +2191,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:
@@ -2091,6 +2222,9 @@ static int __devexit omap_system_dma_remove(struct platform_device *pdev)
 {
 	int dma_irq;
 
+	if (omap_dma_reserve_channels)
+		pm_runtime_put_autosuspend(dev);
+
 	if (cpu_class_is_omap2()) {
 		char irq_name[4];
 		strcpy(irq_name, "0");
@@ -2125,6 +2259,7 @@ arch_initcall(omap_system_dma_init);
 
 static void __exit omap_system_dma_exit(void)
 {
+	pm_runtime_disable(dev);
 	platform_driver_unregister(&omap_system_dma_driver);
 }
 
-- 
1.7.1


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

* [PATCH v4 3/4] OMAP: PM: DMA: Enable runtime pm
@ 2011-03-28 14:27   ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:27 UTC (permalink / raw)
  To: linux-arm-kernel

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), OMAP3430LDP(Zoom2), OMAP3630(Zoom3), OMAP4(Blaze)

The DMA tests(including chaining) are executed and tested for suspend state
after each test cases.

On zoom2 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

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
---
 arch/arm/plat-omap/dma.c |  147 ++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 141 insertions(+), 6 deletions(-)

diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 5af9bb2..3c39794 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>
@@ -60,6 +61,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;
@@ -172,6 +174,7 @@ void omap_set_dma_priority(int lch, int dst_port, int priority)
 	unsigned long reg;
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1()) {
 		switch (dst_port) {
 		case OMAP_DMA_PORT_OCP_T1:	/* FFFECC00 */
@@ -188,6 +191,7 @@ void omap_set_dma_priority(int lch, int dst_port, int priority)
 			break;
 		default:
 			BUG();
+			pm_runtime_put_autosuspend(dev);
 			return;
 		}
 		l = omap_readl(reg);
@@ -206,6 +210,7 @@ void omap_set_dma_priority(int lch, int dst_port, int priority)
 			ccr &= ~(1 << 6);
 		p->dma_write(ccr, CCR, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_priority);
 
@@ -215,6 +220,8 @@ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
+
 	l = p->dma_read(CSDP, lch);
 	l &= ~0x03;
 	l |= data_type;
@@ -269,6 +276,7 @@ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
 
 	p->dma_write(elem_count, CEN, lch);
 	p->dma_write(frame_count, CFN, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_transfer_params);
 
@@ -276,6 +284,7 @@ void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 {
 	BUG_ON(omap_dma_in_1510_mode());
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1()) {
 		u16 w;
 
@@ -329,11 +338,13 @@ void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 		color &= 0xffffff;
 		p->dma_write(color, COLOR, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_color_mode);
 
 void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode)
 {
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap2()) {
 		u32 csdp;
 
@@ -342,11 +353,13 @@ void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode)
 		csdp |= (mode << 16);
 		p->dma_write(csdp, CSDP, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_write_mode);
 
 void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode)
 {
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1() && !cpu_is_omap15xx()) {
 		u32 l;
 
@@ -355,6 +368,7 @@ void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode)
 		l |= mode;
 		p->dma_write(l, LCH_CTRL, lch);
 	}
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_channel_mode);
 
@@ -365,6 +379,8 @@ void omap_set_dma_src_params(int lch, int src_port, int src_amode,
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
+
 	if (cpu_class_is_omap1()) {
 		u16 w;
 
@@ -383,11 +399,13 @@ void omap_set_dma_src_params(int lch, int src_port, int src_amode,
 
 	p->dma_write(src_ei, CSEI, lch);
 	p->dma_write(src_fi, CSFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_params);
 
 void omap_set_dma_params(int lch, struct omap_dma_channel_params *params)
 {
+	pm_runtime_get_sync(dev);
 	omap_set_dma_transfer_params(lch, params->data_type,
 				     params->elem_count, params->frame_count,
 				     params->sync_mode, params->trigger,
@@ -402,6 +420,7 @@ void omap_set_dma_params(int lch, struct omap_dma_channel_params *params)
 	if (params->read_prio || params->write_prio)
 		omap_dma_set_prio_lch(lch, params->read_prio,
 				      params->write_prio);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_params);
 
@@ -410,8 +429,10 @@ void omap_set_dma_src_index(int lch, int eidx, int fidx)
 	if (cpu_class_is_omap2())
 		return;
 
+	pm_runtime_get_sync(dev);
 	p->dma_write(eidx, CSEI, lch);
 	p->dma_write(fidx, CSFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_index);
 
@@ -419,11 +440,13 @@ void omap_set_dma_src_data_pack(int lch, int enable)
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CSDP, lch);
 	l &= ~(1 << 6);
 	if (enable)
 		l |= (1 << 6);
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_data_pack);
 
@@ -432,6 +455,7 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 	unsigned int burst = 0;
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CSDP, lch);
 	l &= ~(0x03 << 7);
 
@@ -469,6 +493,7 @@ void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 
 	l |= (burst << 7);
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_src_burst_mode);
 
@@ -478,6 +503,7 @@ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
 			      int dst_ei, int dst_fi)
 {
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	if (cpu_class_is_omap1()) {
 		l = p->dma_read(CSDP, lch);
@@ -495,6 +521,7 @@ void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
 
 	p->dma_write(dst_ei, CDEI, lch);
 	p->dma_write(dst_fi, CDFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_params);
 
@@ -502,21 +529,25 @@ void omap_set_dma_dest_index(int lch, int eidx, int fidx)
 {
 	if (cpu_class_is_omap2())
 		return;
+	pm_runtime_get_sync(dev);
 
 	p->dma_write(eidx, CDEI, lch);
 	p->dma_write(fidx, CDFI, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_index);
 
 void omap_set_dma_dest_data_pack(int lch, int enable)
 {
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	l = p->dma_read(CSDP, lch);
 	l &= ~(1 << 13);
 	if (enable)
 		l |= 1 << 13;
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_data_pack);
 
@@ -524,6 +555,7 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 {
 	unsigned int burst = 0;
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	l = p->dma_read(CSDP, lch);
 	l &= ~(0x03 << 14);
@@ -555,10 +587,12 @@ void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 	default:
 		printk(KERN_ERR "Invalid DMA burst mode\n");
 		BUG();
+		pm_runtime_put_autosuspend(dev);
 		return;
 	}
 	l |= (burst << 14);
 	p->dma_write(l, CSDP, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
 
@@ -566,6 +600,7 @@ static inline void omap_enable_channel_irq(int lch)
 {
 	u32 status;
 
+	pm_runtime_get_sync(dev);
 	/* Clear CSR */
 	if (cpu_class_is_omap1())
 		status = p->dma_read(CSR, lch);
@@ -574,12 +609,15 @@ static inline void omap_enable_channel_irq(int lch)
 
 	/* Enable some nice interrupts. */
 	p->dma_write(dma_chan[lch].enabled_irqs, CICR, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static void omap_disable_channel_irq(int lch)
 {
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap2())
 		p->dma_write(0, CICR, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 void omap_enable_dma_irq(int lch, u16 bits)
@@ -597,6 +635,7 @@ EXPORT_SYMBOL(omap_disable_dma_irq);
 static inline void enable_lnk(int lch)
 {
 	u32 l;
+	pm_runtime_get_sync(dev);
 
 	l = p->dma_read(CLNK_CTRL, lch);
 
@@ -614,12 +653,14 @@ static inline void enable_lnk(int lch)
 #endif
 
 	p->dma_write(l, CLNK_CTRL, lch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static inline void disable_lnk(int lch)
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CLNK_CTRL, lch);
 
 	/* Disable interrupts */
@@ -637,6 +678,7 @@ static inline void disable_lnk(int lch)
 
 	p->dma_write(l, CLNK_CTRL, lch);
 	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+	pm_runtime_put_autosuspend(dev);
 }
 
 static inline void omap2_enable_irq_lch(int lch)
@@ -647,11 +689,13 @@ static inline void omap2_enable_irq_lch(int lch)
 	if (!cpu_class_is_omap2())
 		return;
 
+	pm_runtime_get_sync(dev);
 	spin_lock_irqsave(&dma_chan_lock, flags);
 	val = p->dma_read(IRQENABLE_L0, lch);
 	val |= 1 << lch;
 	p->dma_write(val, IRQENABLE_L0, lch);
 	spin_unlock_irqrestore(&dma_chan_lock, flags);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static inline void omap2_disable_irq_lch(int lch)
@@ -662,11 +706,13 @@ static inline void omap2_disable_irq_lch(int lch)
 	if (!cpu_class_is_omap2())
 		return;
 
+	pm_runtime_get_sync(dev);
 	spin_lock_irqsave(&dma_chan_lock, flags);
 	val = p->dma_read(IRQENABLE_L0, lch);
 	val &= ~(1 << lch);
 	p->dma_write(val, IRQENABLE_L0, lch);
 	spin_unlock_irqrestore(&dma_chan_lock, flags);
+	pm_runtime_put_autosuspend(dev);
 }
 
 int omap_request_dma(int dev_id, const char *dev_name,
@@ -677,6 +723,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) {
@@ -687,6 +734,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;
@@ -744,6 +792,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
 	}
 
 	*dma_ch_out = free_ch;
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -759,6 +808,7 @@ void omap_free_dma(int lch)
 		return;
 	}
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1()) {
 		/* Disable all DMA interrupts for the channel. */
 		p->dma_write(0, CICR, lch);
@@ -781,6 +831,7 @@ void omap_free_dma(int lch)
 		omap_clear_dma(lch);
 	}
 
+	pm_runtime_put_autosuspend(dev);
 	spin_lock_irqsave(&dma_chan_lock, flags);
 	dma_chan[lch].dev_id = -1;
 	dma_chan[lch].next_lch = -1;
@@ -818,7 +869,9 @@ omap_dma_set_global_params(int arb_rate, int max_fifo_depth, int tparams)
 	reg |= (0x3 & tparams) << 12;
 	reg |= (arb_rate & 0xff) << 16;
 
+	pm_runtime_get_sync(dev);
 	p->dma_write(reg, GCR, 0);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_dma_set_global_params);
 
@@ -841,6 +894,7 @@ omap_dma_set_prio_lch(int lch, unsigned char read_prio,
 		printk(KERN_ERR "Invalid channel id\n");
 		return -EINVAL;
 	}
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CCR, lch);
 	l &= ~((1 << 6) | (1 << 26));
 	if (cpu_is_omap2430() || cpu_is_omap34xx() ||  cpu_is_omap44xx())
@@ -849,6 +903,7 @@ omap_dma_set_prio_lch(int lch, unsigned char read_prio,
 		l |= ((read_prio & 0x1) << 6);
 
 	p->dma_write(l, CCR, lch);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -862,9 +917,11 @@ void omap_clear_dma(int lch)
 {
 	unsigned long flags;
 
+	pm_runtime_get_sync(dev);
 	local_irq_save(flags);
 	p->clear_dma(lch);
 	local_irq_restore(flags);
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_clear_dma);
 
@@ -872,6 +929,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.
@@ -903,6 +962,7 @@ void omap_start_dma(int lch)
 			enable_lnk(cur_lch);
 			omap_enable_channel_irq(cur_lch);
 
+			pm_runtime_get_sync(dev);
 			cur_lch = next_lch;
 		} while (next_lch != -1);
 	} else if (IS_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS))
@@ -927,6 +987,7 @@ void omap_stop_dma(int lch)
 	u32 l;
 	unsigned long flags;
 
+	pm_runtime_get_sync(dev);
 	/* Disable all interrupts on the channel */
 	if (cpu_class_is_omap1())
 		p->dma_write(0, CICR, lch);
@@ -989,6 +1050,7 @@ void omap_stop_dma(int lch)
 	}
 
 	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_stop_dma);
 
@@ -1031,6 +1093,7 @@ dma_addr_t omap_get_dma_src_pos(int lch)
 {
 	dma_addr_t offset = 0;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_is_omap15xx())
 		offset = p->dma_read(CPC, lch);
 	else
@@ -1042,6 +1105,7 @@ dma_addr_t omap_get_dma_src_pos(int lch)
 	if (cpu_class_is_omap1())
 		offset |= (p->dma_read(CSSA, lch) & 0xFFFF0000);
 
+	pm_runtime_put_autosuspend(dev);
 	return offset;
 }
 EXPORT_SYMBOL(omap_get_dma_src_pos);
@@ -1058,6 +1122,7 @@ dma_addr_t omap_get_dma_dst_pos(int lch)
 {
 	dma_addr_t offset = 0;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_is_omap15xx())
 		offset = p->dma_read(CPC, lch);
 	else
@@ -1073,13 +1138,20 @@ dma_addr_t omap_get_dma_dst_pos(int lch)
 	if (cpu_class_is_omap1())
 		offset |= (p->dma_read(CDSA, lch) & 0xFFFF0000);
 
+	pm_runtime_put_autosuspend(dev);
 	return offset;
 }
 EXPORT_SYMBOL(omap_get_dma_dst_pos);
 
 int omap_get_dma_active_status(int lch)
 {
-	return (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN) != 0;
+	u32 reg_data;
+
+	pm_runtime_get_sync(dev);
+	reg_data = p->dma_read(CCR, lch);
+	pm_runtime_put_autosuspend(dev);
+	reg_data &= reg_data & OMAP_DMA_CCR_EN;
+	return ((reg_data != 0) ? 1 : 0);
 }
 EXPORT_SYMBOL(omap_get_dma_active_status);
 
@@ -1087,14 +1159,20 @@ int omap_dma_running(void)
 {
 	int lch;
 
+	pm_runtime_get_sync(dev);
 	if (cpu_class_is_omap1())
-		if (omap_lcd_dma_running())
+		if (omap_lcd_dma_running()) {
+			pm_runtime_put_autosuspend(dev);
 			return 1;
+		}
 
 	for (lch = 0; lch < dma_chan_count; lch++)
-		if (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN)
+		if (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN) {
+			pm_runtime_put_autosuspend(dev);
 			return 1;
+		}
 
+	pm_runtime_put_autosuspend(dev);
 	return 0;
 }
 
@@ -1105,12 +1183,15 @@ int omap_dma_running(void)
  */
 void omap_dma_link_lch(int lch_head, int lch_queue)
 {
+	pm_runtime_get_sync(dev);
 	if (omap_dma_in_1510_mode()) {
 		if (lch_head == lch_queue) {
 			p->dma_write(p->dma_read(CCR, lch_head) | (3 << 8),
 								CCR, lch_head);
+			pm_runtime_put_autosuspend(dev);
 			return;
 		}
+		pm_runtime_put_autosuspend(dev);
 		printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
 		BUG();
 		return;
@@ -1124,6 +1205,7 @@ void omap_dma_link_lch(int lch_head, int lch_queue)
 	}
 
 	dma_chan[lch_head].next_lch = lch_queue;
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_dma_link_lch);
 
@@ -1132,12 +1214,15 @@ EXPORT_SYMBOL(omap_dma_link_lch);
  */
 void omap_dma_unlink_lch(int lch_head, int lch_queue)
 {
+	pm_runtime_get_sync(dev);
 	if (omap_dma_in_1510_mode()) {
 		if (lch_head == lch_queue) {
 			p->dma_write(p->dma_read(CCR, lch_head) & ~(3 << 8),
 								CCR, lch_head);
+			pm_runtime_put_autosuspend(dev);
 			return;
 		}
+		pm_runtime_put_autosuspend(dev);
 		printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
 		BUG();
 		return;
@@ -1158,6 +1243,7 @@ void omap_dma_unlink_lch(int lch_head, int lch_queue)
 	}
 
 	dma_chan[lch_head].next_lch = -1;
+	pm_runtime_put_autosuspend(dev);
 }
 EXPORT_SYMBOL(omap_dma_unlink_lch);
 
@@ -1167,6 +1253,7 @@ static void create_dma_lch_chain(int lch_head, int lch_queue)
 {
 	u32 l;
 
+	pm_runtime_get_sync(dev);
 	/* Check if this is the first link in chain */
 	if (dma_chan[lch_head].next_linked_ch == -1) {
 		dma_chan[lch_head].next_linked_ch = lch_queue;
@@ -1194,6 +1281,7 @@ static void create_dma_lch_chain(int lch_head, int lch_queue)
 	l &= ~(0x1f);
 	l |= (dma_chan[lch_queue].next_linked_ch);
 	p->dma_write(l, CLNK_CTRL, lch_queue);
+	pm_runtime_put_autosuspend(dev);
 }
 
 /**
@@ -1467,6 +1555,7 @@ int omap_dma_chain_a_transfer(int chain_id, int src_start, int dest_start,
 	/* Increment the q_tail */
 	OMAP_DMA_CHAIN_INCQTAIL(chain_id);
 
+	pm_runtime_get_sync(dev);
 	/* Set the params to the free channel */
 	if (src_start != 0)
 		p->dma_write(src_start, CSSA, lch);
@@ -1546,6 +1635,7 @@ int omap_dma_chain_a_transfer(int chain_id, int src_start, int dest_start,
 			dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
 		}
 	}
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -1586,6 +1676,7 @@ int omap_start_dma_chain_transfers(int chain_id)
 		omap_enable_channel_irq(channels[0]);
 	}
 
+	pm_runtime_get_sync(dev);
 	l = p->dma_read(CCR, channels[0]);
 	l |= (1 << 7);
 	dma_linked_lch[chain_id].chain_state = DMA_CHAIN_STARTED;
@@ -1599,6 +1690,7 @@ int omap_start_dma_chain_transfers(int chain_id)
 
 	dma_chan[channels[0]].flags |= OMAP_DMA_ACTIVE;
 
+	pm_runtime_put_autosuspend(dev);
 	return 0;
 }
 EXPORT_SYMBOL(omap_start_dma_chain_transfers);
@@ -1630,6 +1722,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
 	}
 	channels = dma_linked_lch[chain_id].linked_dmach_q;
 
+	pm_runtime_get_sync(dev);
 	if (IS_DMA_ERRATA(DMA_ERRATA_i88) && p->midlemode) {
 		spin_lock_irqsave(&dma_chan_lock, flags);
 		p->midlemode(true);
@@ -1658,6 +1751,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
 		p->midlemode(false);
 		spin_unlock_irqrestore(&dma_chan_lock, flags);
 	}
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -1699,8 +1793,10 @@ int omap_get_dma_chain_index(int chain_id, int *ei, int *fi)
 	/* Get the current channel */
 	lch = channels[dma_linked_lch[chain_id].q_head];
 
+	pm_runtime_get_sync(dev);
 	*ei = p->dma_read(CCEN, lch);
 	*fi = p->dma_read(CCFN, lch);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 }
@@ -1719,6 +1815,7 @@ int omap_get_dma_chain_dst_pos(int chain_id)
 {
 	int lch;
 	int *channels;
+	int reg_data;
 
 	/* Check for input params */
 	if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
@@ -1737,7 +1834,10 @@ int omap_get_dma_chain_dst_pos(int chain_id)
 	/* Get the current channel */
 	lch = channels[dma_linked_lch[chain_id].q_head];
 
-	return p->dma_read(CDAC, lch);
+	pm_runtime_get_sync(dev);
+	reg_data = p->dma_read(CDAC, lch);
+	pm_runtime_put_autosuspend(dev);
+	return reg_data;
 }
 EXPORT_SYMBOL(omap_get_dma_chain_dst_pos);
 
@@ -1753,6 +1853,7 @@ int omap_get_dma_chain_src_pos(int chain_id)
 {
 	int lch;
 	int *channels;
+	int reg_data;
 
 	/* Check for input params */
 	if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
@@ -1771,7 +1872,10 @@ int omap_get_dma_chain_src_pos(int chain_id)
 	/* Get the current channel */
 	lch = channels[dma_linked_lch[chain_id].q_head];
 
-	return p->dma_read(CSAC, lch);
+	pm_runtime_get_sync(dev);
+	reg_data = p->dma_read(CSAC, lch);
+	pm_runtime_put_autosuspend(dev);
+	return reg_data;
 }
 EXPORT_SYMBOL(omap_get_dma_chain_src_pos);
 #endif	/* ifndef CONFIG_ARCH_OMAP1 */
@@ -1811,6 +1915,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;
 }
 
@@ -1895,8 +2001,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);
@@ -1905,6 +2014,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;
 }
 
@@ -1945,17 +2056,20 @@ static struct irqaction omap24xx_dma_irq;
 
 void omap_dma_global_context_save(void)
 {
+	pm_runtime_get_sync(dev);
 	omap_dma_global_context.dma_irqenable_l0 =
 		p->dma_read(IRQENABLE_L0, 0);
 	omap_dma_global_context.dma_ocp_sysconfig =
 		p->dma_read(OCP_SYSCONFIG, 0);
 	omap_dma_global_context.dma_gcr = p->dma_read(GCR, 0);
+	pm_runtime_put_autosuspend(dev);
 }
 
 void omap_dma_global_context_restore(void)
 {
 	int ch;
 
+	pm_runtime_get_sync(dev);
 	p->dma_write(omap_dma_global_context.dma_gcr, GCR, 0);
 	p->dma_write(omap_dma_global_context.dma_ocp_sysconfig,
 		OCP_SYSCONFIG, 0);
@@ -1968,6 +2082,7 @@ void omap_dma_global_context_restore(void)
 	for (ch = 0; ch < dma_chan_count; ch++)
 		if (dma_chan[ch].dev_id != -1)
 			omap_clear_dma(ch);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static int __devinit omap_system_dma_probe(struct platform_device *pdev)
@@ -1984,6 +2099,7 @@ static int __devinit omap_system_dma_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+	dev			= &pdev->dev;
 	d			= p->dma_attr;
 	errata			= p->errata;
 
@@ -2005,6 +2121,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);
@@ -2070,6 +2191,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:
@@ -2091,6 +2222,9 @@ static int __devexit omap_system_dma_remove(struct platform_device *pdev)
 {
 	int dma_irq;
 
+	if (omap_dma_reserve_channels)
+		pm_runtime_put_autosuspend(dev);
+
 	if (cpu_class_is_omap2()) {
 		char irq_name[4];
 		strcpy(irq_name, "0");
@@ -2125,6 +2259,7 @@ arch_initcall(omap_system_dma_init);
 
 static void __exit omap_system_dma_exit(void)
 {
+	pm_runtime_disable(dev);
 	platform_driver_unregister(&omap_system_dma_driver);
 }
 
-- 
1.7.1

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

* [PATCH v4 4/4] OMAP: DMA: Fix: context restore during off mode
  2011-03-28 14:26 ` G, Manjunath Kondaiah
@ 2011-03-28 14:27   ` G, Manjunath Kondaiah
  -1 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:27 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: khilman, paul, tony

The current DMA context restore clears all the DMA channel registers
even if the channels are in use. This will result in transfer failures
if repeated DMA transfers are initiated with one time DMA channel
configuration.

Also, remove access to sysconfig register during context save/restore
since it will be handled through hwmod layer.

Tested on OMAP3430 Zoom2 with
 - off mode enabled
 - one time DMA channel configuration
 - repeated DMA transfers

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
---
 arch/arm/plat-omap/dma.c |    9 ---------
 1 files changed, 0 insertions(+), 9 deletions(-)

diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 3c39794..5c4ae7d 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -2059,29 +2059,20 @@ void omap_dma_global_context_save(void)
 	pm_runtime_get_sync(dev);
 	omap_dma_global_context.dma_irqenable_l0 =
 		p->dma_read(IRQENABLE_L0, 0);
-	omap_dma_global_context.dma_ocp_sysconfig =
-		p->dma_read(OCP_SYSCONFIG, 0);
 	omap_dma_global_context.dma_gcr = p->dma_read(GCR, 0);
 	pm_runtime_put_autosuspend(dev);
 }
 
 void omap_dma_global_context_restore(void)
 {
-	int ch;
-
 	pm_runtime_get_sync(dev);
 	p->dma_write(omap_dma_global_context.dma_gcr, GCR, 0);
-	p->dma_write(omap_dma_global_context.dma_ocp_sysconfig,
-		OCP_SYSCONFIG, 0);
 	p->dma_write(omap_dma_global_context.dma_irqenable_l0,
 		IRQENABLE_L0, 0);
 
 	if (IS_DMA_ERRATA(DMA_ROMCODE_BUG))
 		p->dma_write(0x3 , IRQSTATUS_L0, 0);
 
-	for (ch = 0; ch < dma_chan_count; ch++)
-		if (dma_chan[ch].dev_id != -1)
-			omap_clear_dma(ch);
 	pm_runtime_put_autosuspend(dev);
 }
 
-- 
1.7.1


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

* [PATCH v4 4/4] OMAP: DMA: Fix: context restore during off mode
@ 2011-03-28 14:27   ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-03-28 14:27 UTC (permalink / raw)
  To: linux-arm-kernel

The current DMA context restore clears all the DMA channel registers
even if the channels are in use. This will result in transfer failures
if repeated DMA transfers are initiated with one time DMA channel
configuration.

Also, remove access to sysconfig register during context save/restore
since it will be handled through hwmod layer.

Tested on OMAP3430 Zoom2 with
 - off mode enabled
 - one time DMA channel configuration
 - repeated DMA transfers

Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
---
 arch/arm/plat-omap/dma.c |    9 ---------
 1 files changed, 0 insertions(+), 9 deletions(-)

diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 3c39794..5c4ae7d 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -2059,29 +2059,20 @@ void omap_dma_global_context_save(void)
 	pm_runtime_get_sync(dev);
 	omap_dma_global_context.dma_irqenable_l0 =
 		p->dma_read(IRQENABLE_L0, 0);
-	omap_dma_global_context.dma_ocp_sysconfig =
-		p->dma_read(OCP_SYSCONFIG, 0);
 	omap_dma_global_context.dma_gcr = p->dma_read(GCR, 0);
 	pm_runtime_put_autosuspend(dev);
 }
 
 void omap_dma_global_context_restore(void)
 {
-	int ch;
-
 	pm_runtime_get_sync(dev);
 	p->dma_write(omap_dma_global_context.dma_gcr, GCR, 0);
-	p->dma_write(omap_dma_global_context.dma_ocp_sysconfig,
-		OCP_SYSCONFIG, 0);
 	p->dma_write(omap_dma_global_context.dma_irqenable_l0,
 		IRQENABLE_L0, 0);
 
 	if (IS_DMA_ERRATA(DMA_ROMCODE_BUG))
 		p->dma_write(0x3 , IRQSTATUS_L0, 0);
 
-	for (ch = 0; ch < dma_chan_count; ch++)
-		if (dma_chan[ch].dev_id != -1)
-			omap_clear_dma(ch);
 	pm_runtime_put_autosuspend(dev);
 }
 
-- 
1.7.1

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

* Re: [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
  2011-03-28 14:26 ` G, Manjunath Kondaiah
@ 2011-04-07  0:45   ` G, Manjunath Kondaiah
  -1 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-04-07  0:45 UTC (permalink / raw)
  To: linux-omap, linux-arm-kernel; +Cc: khilman, paul, tony

Kevin/Paul,

On Mon, Mar 28, 2011 at 07:56:58PM +0530, G, Manjunath Kondaiah wrote:
> Patch series to support mstandby mode handling and enabling runtime PM
> support for DMA driver.
If you don't have further comments, can you pls ack these patches for
merging?

-Manjunath

[...]

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

* [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
@ 2011-04-07  0:45   ` G, Manjunath Kondaiah
  0 siblings, 0 replies; 18+ messages in thread
From: G, Manjunath Kondaiah @ 2011-04-07  0:45 UTC (permalink / raw)
  To: linux-arm-kernel

Kevin/Paul,

On Mon, Mar 28, 2011 at 07:56:58PM +0530, G, Manjunath Kondaiah wrote:
> Patch series to support mstandby mode handling and enabling runtime PM
> support for DMA driver.
If you don't have further comments, can you pls ack these patches for
merging?

-Manjunath

[...]

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

* Re: [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
  2011-03-28 14:26 ` G, Manjunath Kondaiah
@ 2011-04-19 11:05   ` Tony Lindgren
  -1 siblings, 0 replies; 18+ messages in thread
From: Tony Lindgren @ 2011-04-19 11:05 UTC (permalink / raw)
  To: G, Manjunath Kondaiah; +Cc: linux-omap, linux-arm-kernel, khilman, paul

* G, Manjunath Kondaiah <manjugk@ti.com> [110328 07:29]:
> 
> G, Manjunath Kondaiah (4):
>   OMAP2+: PM: omap device: API's for handling mstandby mode
>   OMAP2+: DMA: prevent races while setting M idle mode to nostandby
>   OMAP: PM: DMA: Enable runtime pm
>   OMAP: DMA: Fix: context restore during off mode
> 
>  arch/arm/mach-omap1/dma.c                     |    1 +
>  arch/arm/mach-omap2/dma.c                     |   16 ++
>  arch/arm/mach-omap2/omap_hwmod.c              |   42 ++++++
>  arch/arm/plat-omap/dma.c                      |  196 +++++++++++++++++++++----
>  arch/arm/plat-omap/include/plat/dma.h         |    1 +
>  arch/arm/plat-omap/include/plat/omap_device.h |    2 +
>  arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
>  arch/arm/plat-omap/omap_device.c              |   62 ++++++++
>  8 files changed, 291 insertions(+), 33 deletions(-)

With the DMA code too we need to do the cleanup to move it
to drivers/dma before adding new features.

Tony
 

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

* [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
@ 2011-04-19 11:05   ` Tony Lindgren
  0 siblings, 0 replies; 18+ messages in thread
From: Tony Lindgren @ 2011-04-19 11:05 UTC (permalink / raw)
  To: linux-arm-kernel

* G, Manjunath Kondaiah <manjugk@ti.com> [110328 07:29]:
> 
> G, Manjunath Kondaiah (4):
>   OMAP2+: PM: omap device: API's for handling mstandby mode
>   OMAP2+: DMA: prevent races while setting M idle mode to nostandby
>   OMAP: PM: DMA: Enable runtime pm
>   OMAP: DMA: Fix: context restore during off mode
> 
>  arch/arm/mach-omap1/dma.c                     |    1 +
>  arch/arm/mach-omap2/dma.c                     |   16 ++
>  arch/arm/mach-omap2/omap_hwmod.c              |   42 ++++++
>  arch/arm/plat-omap/dma.c                      |  196 +++++++++++++++++++++----
>  arch/arm/plat-omap/include/plat/dma.h         |    1 +
>  arch/arm/plat-omap/include/plat/omap_device.h |    2 +
>  arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
>  arch/arm/plat-omap/omap_device.c              |   62 ++++++++
>  8 files changed, 291 insertions(+), 33 deletions(-)

With the DMA code too we need to do the cleanup to move it
to drivers/dma before adding new features.

Tony
 

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

* Re: [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
  2011-04-19 11:05   ` Tony Lindgren
@ 2011-04-28 13:56     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 18+ messages in thread
From: Russell King - ARM Linux @ 2011-04-28 13:56 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: G, Manjunath Kondaiah, khilman, paul, linux-omap, linux-arm-kernel

On Tue, Apr 19, 2011 at 04:05:17AM -0700, Tony Lindgren wrote:
> * G, Manjunath Kondaiah <manjugk@ti.com> [110328 07:29]:
> > 
> > G, Manjunath Kondaiah (4):
> >   OMAP2+: PM: omap device: API's for handling mstandby mode
> >   OMAP2+: DMA: prevent races while setting M idle mode to nostandby
> >   OMAP: PM: DMA: Enable runtime pm
> >   OMAP: DMA: Fix: context restore during off mode
> > 
> >  arch/arm/mach-omap1/dma.c                     |    1 +
> >  arch/arm/mach-omap2/dma.c                     |   16 ++
> >  arch/arm/mach-omap2/omap_hwmod.c              |   42 ++++++
> >  arch/arm/plat-omap/dma.c                      |  196 +++++++++++++++++++++----
> >  arch/arm/plat-omap/include/plat/dma.h         |    1 +
> >  arch/arm/plat-omap/include/plat/omap_device.h |    2 +
> >  arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
> >  arch/arm/plat-omap/omap_device.c              |   62 ++++++++
> >  8 files changed, 291 insertions(+), 33 deletions(-)
> 
> With the DMA code too we need to do the cleanup to move it
> to drivers/dma before adding new features.

It also needs to conform to the DMA engine API, which is not well
documented.  The points to watch out for are:

1. it passes lockdep.
2. drivers _can_ submit new slave transactions during a previous slave
   transaction callback.
3. callbacks must be made from tasklet context.
4. terminating a transaction dma dma_terminate_all() should not call any
   callbacks (as they may submit new transactions, causing DMA to restart.)

I think that's about it, but there may be more.

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

* [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support
@ 2011-04-28 13:56     ` Russell King - ARM Linux
  0 siblings, 0 replies; 18+ messages in thread
From: Russell King - ARM Linux @ 2011-04-28 13:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 19, 2011 at 04:05:17AM -0700, Tony Lindgren wrote:
> * G, Manjunath Kondaiah <manjugk@ti.com> [110328 07:29]:
> > 
> > G, Manjunath Kondaiah (4):
> >   OMAP2+: PM: omap device: API's for handling mstandby mode
> >   OMAP2+: DMA: prevent races while setting M idle mode to nostandby
> >   OMAP: PM: DMA: Enable runtime pm
> >   OMAP: DMA: Fix: context restore during off mode
> > 
> >  arch/arm/mach-omap1/dma.c                     |    1 +
> >  arch/arm/mach-omap2/dma.c                     |   16 ++
> >  arch/arm/mach-omap2/omap_hwmod.c              |   42 ++++++
> >  arch/arm/plat-omap/dma.c                      |  196 +++++++++++++++++++++----
> >  arch/arm/plat-omap/include/plat/dma.h         |    1 +
> >  arch/arm/plat-omap/include/plat/omap_device.h |    2 +
> >  arch/arm/plat-omap/include/plat/omap_hwmod.h  |    4 +-
> >  arch/arm/plat-omap/omap_device.c              |   62 ++++++++
> >  8 files changed, 291 insertions(+), 33 deletions(-)
> 
> With the DMA code too we need to do the cleanup to move it
> to drivers/dma before adding new features.

It also needs to conform to the DMA engine API, which is not well
documented.  The points to watch out for are:

1. it passes lockdep.
2. drivers _can_ submit new slave transactions during a previous slave
   transaction callback.
3. callbacks must be made from tasklet context.
4. terminating a transaction dma dma_terminate_all() should not call any
   callbacks (as they may submit new transactions, causing DMA to restart.)

I think that's about it, but there may be more.

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

* Re: [PATCH v4 1/4] OMAP2+: PM: omap device: API's for handling mstandby mode
  2011-03-28 14:26   ` G, Manjunath Kondaiah
@ 2011-05-06 20:24     ` Paul Walmsley
  -1 siblings, 0 replies; 18+ messages in thread
From: Paul Walmsley @ 2011-05-06 20:24 UTC (permalink / raw)
  To: G, Manjunath Kondaiah; +Cc: linux-omap, linux-arm-kernel, khilman, tony

On Mon, 28 Mar 2011, G, Manjunath Kondaiah wrote:

> Certain errata in OMAP2+ processors will require forcing
> master standby to "no standby" mode before completing on going
> operation. Without this, the results will be unpredictable.

Thanks, I've queued this one (provisionally) for 2.6.40, assuming we have 
the diffstat budget for it.


- Paul

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

* [PATCH v4 1/4] OMAP2+: PM: omap device: API's for handling mstandby mode
@ 2011-05-06 20:24     ` Paul Walmsley
  0 siblings, 0 replies; 18+ messages in thread
From: Paul Walmsley @ 2011-05-06 20:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 28 Mar 2011, G, Manjunath Kondaiah wrote:

> Certain errata in OMAP2+ processors will require forcing
> master standby to "no standby" mode before completing on going
> operation. Without this, the results will be unpredictable.

Thanks, I've queued this one (provisionally) for 2.6.40, assuming we have 
the diffstat budget for it.


- Paul

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

end of thread, other threads:[~2011-05-06 20:24 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-28 14:26 [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support G, Manjunath Kondaiah
2011-03-28 14:26 ` G, Manjunath Kondaiah
2011-03-28 14:26 ` [PATCH v4 1/4] OMAP2+: PM: omap device: API's for handling mstandby mode G, Manjunath Kondaiah
2011-03-28 14:26   ` G, Manjunath Kondaiah
2011-05-06 20:24   ` Paul Walmsley
2011-05-06 20:24     ` Paul Walmsley
2011-03-28 14:27 ` [PATCH v4 2/4] OMAP2+: DMA: prevent races while setting M idle mode to nostandby G, Manjunath Kondaiah
2011-03-28 14:27   ` G, Manjunath Kondaiah
2011-03-28 14:27 ` [PATCH v4 3/4] OMAP: PM: DMA: Enable runtime pm G, Manjunath Kondaiah
2011-03-28 14:27   ` G, Manjunath Kondaiah
2011-03-28 14:27 ` [PATCH v4 4/4] OMAP: DMA: Fix: context restore during off mode G, Manjunath Kondaiah
2011-03-28 14:27   ` G, Manjunath Kondaiah
2011-04-07  0:45 ` [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support G, Manjunath Kondaiah
2011-04-07  0:45   ` G, Manjunath Kondaiah
2011-04-19 11:05 ` Tony Lindgren
2011-04-19 11:05   ` Tony Lindgren
2011-04-28 13:56   ` Russell King - ARM Linux
2011-04-28 13:56     ` Russell King - ARM Linux

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.