Skip to contentSkip to conversation

ARM: OMAP2+: powerdomain updates after the functional power state conversion

PATCH New Paul Walmsley 6 participants 21 messages Dec 9, 2012 – Jan 4, 2013

Subsystems (6)
lore
Share & tools
lore

Paul Walmsley

author maintainer
#0 lore raw

cover ARM: OMAP2+: powerdomain updates after the functional power state conversion

OMAP powerdomain code updates, implemented on top of the functional power state conversion series. This series fixes the powerdomain handling for OMAP2xxx, adds caching for the powerdomain next-power-state and previous-power-state register bitfields, and some cleanup that's intended to make it easier to move the powerdomain code out to drivers/.

- Paul

---

vmlinux object size
(delta in bytes from TEST_func_powerstates_devel_3.9 (6d8345f4177c976eca1a1368cdd68e95f80c3f27)):

   text     data      bss    total  kernel
    -68      +48        0      -20  am33xx_only
   -136      +48        0      -88  n800_multi_omap2xxx
   -128      +48        0      -80  n800_only_a
      0        0        0        0  omap1_defconfig
      0        0        0        0  omap1_defconfig_1510innovator_only
      0        0        0        0  omap1_defconfig_5912osk_only
    -32     +368        0     +336  omap2plus_defconfig
    +20      +16        0      +36  omap2plus_defconfig_2430sdp_only
    -32     +432        0     +400  omap2plus_defconfig_cpupm
   +572     +192        0     +764  omap2plus_defconfig_no_pm
    -20     +208        0     +188  omap2plus_defconfig_omap2_4_only
    -84     +304        0     +220  omap2plus_defconfig_omap3_4_only
   +708     +200     -104     +804  rmk_omap3430_ldp_allnoconfig
   +352     +128        0     +480  rmk_omap3430_ldp_oldconfig
   +708     +200     -104     +804  rmk_omap4430_sdp_allnoconfig
   -164       +8        0     -156  rmk_omap4430_sdp_oldconfig

Paul Walmsley (12):
ARM: OMAP2+: powerdomain: consolidate arch_pwrdm check code
ARM: OMAP2+: PM/powerdomain: move the power state time tracking into the powerdomain code
ARM: OMAP2+: powerdomain: split pwrdm_state_switch()
ARM: OMAP2+: PM: clean up some debugfs functions
ARM: OMAP2+: powerdomain: remove some redundant checks; add some notes
ARM: OMAP2+: CM: use the cached copy of the clockdomain's hwsup state
ARM: OMAP2+: powerdomain: cache the powerdomain next power state
ARM: OMAP2+: powerdomain: cache the powerdomain's previous power state
ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
ARM: OMAP2+: powerdomain: skip previous-power-state read if next_pwrst is ON
ARM: OMAP2xxx: powerdomain: add previous power state tracking
ARM: OMAP2xxx: PM: add pwrdm_(pre|post)_transition() calls to the 2xxx PM code

 arch/arm/mach-omap2/clockdomain.c           |   18 +
 arch/arm/mach-omap2/clockdomain.h           |    2 
 arch/arm/mach-omap2/cm2xxx.c                |   19 -
 arch/arm/mach-omap2/cm3xxx.c                |   14 -
 arch/arm/mach-omap2/pm-debug.c              |  101 --------
 arch/arm/mach-omap2/pm.h                    |    6 
 arch/arm/mach-omap2/pm24xx.c                |    8 +
 arch/arm/mach-omap2/powerdomain.c           |  352 +++++++++++++++++++--------
 arch/arm/mach-omap2/powerdomain.h           |   40 +++
 arch/arm/mach-omap2/powerdomains2xxx_data.c |    2 
 arch/arm/mach-omap2/powerdomains33xx_data.c |    3 
 arch/arm/mach-omap2/powerdomains3xxx_data.c |    9 -
 arch/arm/mach-omap2/powerdomains44xx_data.c |    5 
 arch/arm/mach-omap2/prm2xxx.c               |   12 +
 14 files changed, 347 insertions(+), 244 deletions(-)
author maintainer
#1 lore raw

PATCH 1/12 ARM: OMAP2+: powerdomain: consolidate arch_pwrdm check code

Check for the presence of some of the arch_pwrdm function pointers during powerdomain setup, rather than in the individual functions. The primary motivation is to make the code slightly easier to read, but it also should avoid a few instructions in some hot paths.

---
 arch/arm/mach-omap2/powerdomain.c |   43 +++++++++++++++----------------------
 1 file changed, 18 insertions(+), 25 deletions(-)
arch/arm/mach-omap2/powerdomain.c +18 -25
index f81aee1..b67d721 100644
@@ -385,9 +385,6 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
 	if (!_pwrdm_pwrst_is_controllable(pwrdm))
 		return 0;
 
-	if (!arch_pwrdm || !arch_pwrdm->pwrdm_set_next_pwrst)
-		return -EINVAL;
-
 	if (!(pwrdm->pwrsts & (1 << pwrst)))
 		return -EINVAL;
 
@@ -395,13 +392,11 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
 		if (!(pwrdm->pwrsts_logic_ret & (1 << logic)))
 			return -EINVAL;
 
-		if (arch_pwrdm->pwrdm_set_logic_retst) {
-			ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic);
-			if (ret) {
-				pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
-				       __func__, logic, pwrdm->name);
-				return ret;
-			}
+		ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic);
+		if (ret) {
+			pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
+			       __func__, logic, pwrdm->name);
+			return ret;
 		}
 	}
 
@@ -426,9 +421,6 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 	int next_pwrst, next_logic, ret;
 	u8 fpwrst;
 
-	if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst)
-		return -EINVAL;
-
 	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
 	if (next_pwrst < 0)
 		return next_pwrst;
@@ -653,9 +645,12 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
  *
  * Register the list of function pointers used to implement the
  * powerdomain functions on different OMAP SoCs.  Should be called
- * before any other pwrdm_register*() function.  Returns -EINVAL if
- * @po is null, -EEXIST if platform functions have already been
- * registered, or 0 upon success.
+ * before any other pwrdm_register*() function.  Several function
+ * pointers in @po are required to be non-null for the powerdomain
+ * code to function: pwrdm_wait_transition, pwrdm_read_next_pwrst,
+ * pwrdm_read_pwrst, pwrdm_set_next_pwrst, pwrdm_set_logic_retst, and
+ * pwrdm_read_prev_pwrst.  Returns -EINVAL if @po is null, -EEXIST if
+ * platform functions have already been registered, or 0 upon success.
  */
 int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
 {
@@ -665,6 +660,11 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
 	if (arch_pwrdm)
 		return -EEXIST;
 
+	if (!po->pwrdm_wait_transition || !po->pwrdm_read_next_pwrst ||
+	    !po->pwrdm_read_pwrst || !po->pwrdm_set_next_pwrst ||
+	    !po->pwrdm_set_logic_retst || !po->pwrdm_read_prev_pwrst)
+		return -ENOENT;
+
 	arch_pwrdm = po;
 
 	return 0;
@@ -1221,7 +1221,7 @@ int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 	int next_pwrst, next_logic, ret;
 	u8 fpwrst;
 
-	if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst)
+	if (!arch_pwrdm)
 		return -EINVAL;
 
 	pwrdm_lock(pwrdm);
@@ -1264,8 +1264,7 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 	int ret = 0;
 	bool hwsup = false;
 
-	if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm ||
-	    !arch_pwrdm->pwrdm_read_pwrst)
+	if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm)
 		return -EINVAL;
 
 	/*
@@ -1334,9 +1333,6 @@ int pwrdm_read_fpwrst(struct powerdomain *pwrdm)
 	if (!_pwrdm_pwrst_can_change(pwrdm))
 		return PWRDM_FUNC_PWRST_ON;
 
-	if (!arch_pwrdm->pwrdm_read_pwrst)
-		return -EINVAL;
-
 	pwrdm_lock(pwrdm);
 	ret = _pwrdm_read_fpwrst(pwrdm);
 	pwrdm_unlock(pwrdm);
@@ -1362,9 +1358,6 @@ int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
 	if (!_pwrdm_pwrst_can_change(pwrdm))
 		return PWRDM_FUNC_PWRST_ON;
 
-	if (!arch_pwrdm->pwrdm_read_prev_pwrst)
-		return -EINVAL;
-
 	pwrdm_lock(pwrdm);
 	ret = _pwrdm_read_prev_fpwrst(pwrdm);
 	pwrdm_unlock(pwrdm);
author maintainer
#2 lore raw

PATCH 2/12 ARM: OMAP2+: PM/powerdomain: move the power state time tracking into the powerdomain code

In reply to Paul Walmsley

Move the power state time tracking code into the powerdomain code. This code accesses internal powerdomain state, so this change will allow us to reduce what is exported from the powerdomain code.

Cc Tero Kristo <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/pm-debug.c    |   24 ------------------------
 arch/arm/mach-omap2/pm.h          |    6 ------
 arch/arm/mach-omap2/powerdomain.c |   22 +++++++++++++++++++++-
 3 files changed, 21 insertions(+), 31 deletions(-)
arch/arm/mach-omap2/pm-debug.c +0 -24
index 03da2e3..80c001a 100644
@@ -53,21 +53,6 @@ enum {
 	DEBUG_FILE_TIMERS,
 };
 
-void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
-{
-	s64 t;
-
-	if (!pm_dbg_init_done)
-		return ;
-
-	/* Update timer for previous state */
-	t = sched_clock();
-
-	pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer;
-
-	pwrdm->timer = t;
-}
-
 static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
 {
 	struct seq_file *s = (struct seq_file *)user;
@@ -197,17 +182,8 @@ DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
 
 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
 {
-	int i;
-	s64 t;
 	struct dentry *d;
 
-	t = sched_clock();
-
-	for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
-		pwrdm->fpwrst_timer[i] = 0;
-
-	pwrdm->timer = t;
-
 	if (strncmp(pwrdm->name, "dpll", 4) == 0)
 		return 0;
 
arch/arm/mach-omap2/pm.h +0 -6
index 19ef376..c496f27 100644
@@ -59,12 +59,6 @@ extern u32 enable_off_mode;
 #define enable_off_mode 0
 #endif
 
-#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
-extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev);
-#else
-#define pm_dbg_update_time(pwrdm, prev) do {} while (0);
-#endif /* CONFIG_PM_DEBUG */
-
 /* 24xx */
 extern void omap24xx_idle_loop_suspend(void);
 extern unsigned int omap24xx_idle_loop_suspend_sz;
arch/arm/mach-omap2/powerdomain.c +21 -1
index b67d721..53bc852 100644
@@ -20,6 +20,8 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
+#include <linux/sched.h>
+
 #include <trace/events/power.h>
 
 #include "cm2xxx_3xxx.h"
@@ -126,6 +128,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	arch_pwrdm->pwrdm_wait_transition(pwrdm);
 	pwrdm->fpwrst = pwrdm_read_fpwrst(pwrdm);
 	pwrdm->fpwrst_counter[pwrdm->fpwrst - PWRDM_FPWRST_OFFSET] = 1;
+#ifdef CONFIG_PM_DEBUG
+	pwrdm->timer = sched_clock();
+#endif
 
 	return 0;
 }
@@ -579,6 +584,21 @@ static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 	return ret;
 }
 
+/* XXX prev is wrong type */
+/* XXX is sched_clock() correct to use here? */
+/* Update timer for previous state */
+static void _pwrdm_update_pwrst_time(struct powerdomain *pwrdm, int prev)
+{
+#ifdef CONFIG_PM_DEBUG
+	s64 t;
+
+	t = sched_clock();
+
+	pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer;
+
+	pwrdm->timer = t;
+#endif
+}
 
 /* XXX Caller must hold pwrdm->_lock */
 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
@@ -617,7 +637,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 	if (fpwrst != prev)
 		pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++;
 
-	pm_dbg_update_time(pwrdm, prev);
+	_pwrdm_update_pwrst_time(pwrdm, prev);
 
 	pwrdm->fpwrst = fpwrst;
 
author maintainer
#3 lore raw

PATCH 3/12 ARM: OMAP2+: powerdomain: split pwrdm_state_switch()

In reply to Paul Walmsley

Move the pwrdm_state_switch() code that deals with previous power states into the post-transition callback. This improves the clarity of pwrdm_state_switch() considerably. Add some sorely-needed kerneldoc for these functions.

It should be possible to drop pwrdm_state_switch() completely during 3.9.

---
 arch/arm/mach-omap2/powerdomain.c |  118 ++++++++++++++++++++++++-------------
 arch/arm/mach-omap2/powerdomain.h |    1 
 2 files changed, 76 insertions(+), 43 deletions(-)
arch/arm/mach-omap2/powerdomain.c +75 -43
index 53bc852..d38f493 100644
@@ -40,11 +40,6 @@
 
 #define PWRDM_TRACE_STATES_FLAG	(1<<31)
 
-enum {
-	PWRDM_STATE_NOW = 0,
-	PWRDM_STATE_PREV,
-};
-
 /* Types of sleep_switch used in pwrdm_set_fpwrst() */
 #define ALREADYACTIVE_SWITCH		0
 #define FORCEWAKEUP_SWITCH		1
@@ -600,60 +595,97 @@ static void _pwrdm_update_pwrst_time(struct powerdomain *pwrdm, int prev)
 #endif
 }
 
-/* XXX Caller must hold pwrdm->_lock */
-static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
+/**
+ * _pwrdm_state_switch - record powerdomain usage data; track power state
+ * (before powerdomain state transition)
+ * @pwrdm: struct powerdomain * to observe
+ *
+ * If the powerdomain @pwrdm's current power state is not what we last
+ * observed it to be, then increment the counter for that power state.
+ * This is used to track context loss events, and for debugging.  Also
+ * if CONFIG_PM_DEBUG=y, track the amount of time the powerdomain has
+ * spent in the current power state.  Caller must hold pwrdm->_lock.
+ * Intended to be called immediately before the powerdomain's power
+ * state is likely to change.  XXX Note that the counts and durations
+ * observed by this function may be inaccurate.  Powerdomains can
+ * transition power states automatically, without the kernel being
+ * involved -- for example, a device can DMA data from memory while
+ * the MPU is asleep.  This function does not attempt to account for
+ * that.  XXX It may be possible to skip this function completely if
+ * PM debugging is not needed and off-mode and OSWR is disabled (e.g.,
+ * no context loss events).  No return value.
+ */
+static void _pwrdm_state_switch(struct powerdomain *pwrdm)
 {
-	int prev, next, fpwrst, trace_state = 0;
-
-	if (pwrdm == NULL)
-		return -EINVAL;
+	int fpwrst;
 
 	fpwrst = _pwrdm_read_fpwrst(pwrdm);
-
-	switch (flag) {
-	case PWRDM_STATE_NOW:
-		prev = pwrdm->fpwrst;
-		break;
-	case PWRDM_STATE_PREV:
-		prev = _pwrdm_read_prev_fpwrst(pwrdm);
-		if (pwrdm->fpwrst != prev)
-			pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++;
-		/*
-		 * If the power domain did not hit the desired state,
-		 * generate a trace event with both the desired and hit states
-		 */
-		next = _pwrdm_read_next_fpwrst(pwrdm);
-		if (next != prev) {
-			trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 |
-				       prev);
-			trace_power_domain_target(pwrdm->name, trace_state,
-						  smp_processor_id());
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (fpwrst != prev)
+	if (fpwrst != pwrdm->fpwrst)
 		pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++;
 
-	_pwrdm_update_pwrst_time(pwrdm, prev);
+	_pwrdm_update_pwrst_time(pwrdm, pwrdm->fpwrst);
 
 	pwrdm->fpwrst = fpwrst;
-
-	return 0;
 }
 
 static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
 {
 	pwrdm_clear_all_prev_pwrst(pwrdm);
-	_pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+	_pwrdm_state_switch(pwrdm);
 	return 0;
 }
 
+/**
+ * _pwrdm_post_transition_cb - record powerdomain usage data; track power state
+ * (after powerdomain power state transition)
+ * @pwrdm: struct powerdomain * to observe
+ *
+ * If the powerdomain @pwrdm's previous power state doesn't match our
+ * recollection of the powerdomain's current power state, then
+ * increment the counter for the previous power state.  And if the
+ * powerdomain's previous power state doesn't match the current power
+ * state, increment the counter for the current power state.  This
+ * function is used to track context loss events, and for debugging.
+ * Also if CONFIG_PM_DEBUG=y, track the approximate amount of time the
+ * powerdomain has spent in the previous power state.  Caller must
+ * hold pwrdm->_lock.  XXX Note that the counts and durations observed
+ * by this function may be inaccurate.  Powerdomains can transition
+ * power states automatically, without the kernel being involved --
+ * for example, a device can DMA data from memory while the MPU is
+ * asleep.  This function does not attempt to account for that.  XXX
+ * It may be possible to skip this function completely if PM debugging
+ * is not needed and off-mode and OSWR is disabled (e.g., no context
+ * loss events).  No return value.
+ */
 static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 {
-	_pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
+	int prev, next, fpwrst;
+	int trace_state = 0;
+
+	prev = _pwrdm_read_prev_fpwrst(pwrdm);
+	if (pwrdm->fpwrst != prev)
+		pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++;
+
+	_pwrdm_update_pwrst_time(pwrdm, prev);
+
+	/*
+	 * If the power domain did not hit the desired state,
+	 * generate a trace event with both the desired and hit states
+	 */
+	next = _pwrdm_read_next_fpwrst(pwrdm);
+	if (next != prev) {
+		trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 |
+			       prev);
+		trace_power_domain_target(pwrdm->name, trace_state,
+					  smp_processor_id());
+	}
+
+	fpwrst = _pwrdm_read_fpwrst(pwrdm);
+	if (fpwrst != prev)
+		pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++;
+
+	pwrdm->fpwrst = fpwrst;
+
 	return 0;
 }
 
@@ -1055,7 +1087,7 @@ int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
 
 	ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
 	if (!ret)
-		ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+		_pwrdm_state_switch(pwrdm);
 
 	return ret;
 }
arch/arm/mach-omap2/powerdomain.h +1 -0
index 48bb325..ef51987b 100644
@@ -237,6 +237,7 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
 
 int pwrdm_state_switch_nolock(struct powerdomain *pwrdm);
 int pwrdm_state_switch(struct powerdomain *pwrdm);
+int pwrdm_state_switch_nolock(struct powerdomain *pwrdm);
 int pwrdm_pre_transition(struct powerdomain *pwrdm);
 int pwrdm_post_transition(struct powerdomain *pwrdm);
 int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
author maintainer
#4 lore raw

PATCH 4/12 ARM: OMAP2+: PM: clean up some debugfs functions

In reply to Paul Walmsley

Move some debugfs functions into the powerdomain and clockdomain code; the ultimate goal is to stop exporting some of the powerdomain/clockdomain functions. Get rid of the nasty hacks that avoid executing some of the debug functions based on string comparisons on powerdomain and clockdomain names. Lock the powerdomain for the duration of these functions so that the debug information doesn't change during execution. Also, while here, fix a whitespace issue in mach-omap2/pm-debug.c.

Cc Tero Kristo <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/clockdomain.c |   18 +++++++-
 arch/arm/mach-omap2/clockdomain.h |    2 +
 arch/arm/mach-omap2/pm-debug.c    |   77 ++--------------------------------
 arch/arm/mach-omap2/powerdomain.c |   85 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |    4 ++
 5 files changed, 111 insertions(+), 75 deletions(-)
arch/arm/mach-omap2/clockdomain.c +16 -2
index a90c0c8..bc9b79e 100644
@@ -22,9 +22,8 @@
 #include <linux/clk.h>
 #include <linux/limits.h>
 #include <linux/err.h>
-
+#include <linux/seq_file.h>
 #include <linux/io.h>
-
 #include <linux/bitops.h>
 
 #include "soc.h"
@@ -1281,3 +1280,18 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
 	return _clkdm_clk_hwmod_disable(clkdm);
 }
 
+/* Clockdomain debugfs functions */
+
+int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *seq_file)
+{
+	struct seq_file *s = (struct seq_file *)seq_file;
+
+	if (!clkdm->flags)
+		return 0;
+
+	seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name,
+		   clkdm->usecount);
+
+	return 0;
+}
+
arch/arm/mach-omap2/clockdomain.h +2 -0
index 2da3765..95e473b 100644
@@ -229,4 +229,6 @@ extern struct clkdm_dep gfx_24xx_wkdeps[];
 extern struct clkdm_dep dsp_24xx_wkdeps[];
 extern struct clockdomain wkup_common_clkdm;
 
+extern int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *seq_file);
+
 #endif
arch/arm/mach-omap2/pm-debug.c +4 -73

89 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.c +85 -0

100 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.h +4 -0
index ef51987b..c19bdc3 100644
@@ -276,4 +276,8 @@ extern struct powerdomain gfx_omap2_pwrdm;
 extern void pwrdm_lock(struct powerdomain *pwrdm);
 extern void pwrdm_unlock(struct powerdomain *pwrdm);
 
+/* Debugfs functions */
+extern int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *seq_file);
+extern int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *seq_file);
+
 #endif
author maintainer
#5 lore raw

PATCH 5/12 ARM: OMAP2+: powerdomain: remove some redundant checks; add some notes

In reply to Paul Walmsley

Remove some redundant tests in static functions, and add some comments to some code that should have future attention.

---
 arch/arm/mach-omap2/powerdomain.c |   18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/powerdomain.c +11 -7
index 658f4ed..62e2f75 100644
@@ -95,7 +95,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	int i;
 	struct voltagedomain *voltdm;
 
-	if (!pwrdm || !pwrdm->name)
+	if (!pwrdm->name)
 		return -EINVAL;
 
 	if (cpu_is_omap44xx() &&
@@ -528,9 +528,6 @@ static int _pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 {
 	int ret = -EINVAL;
 
-	if (!pwrdm)
-		return -EINVAL;
-
 	if (pwrdm->banks < (bank + 1))
 		return -EEXIST;
 
@@ -566,9 +563,6 @@ static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 {
 	int ret = -EINVAL;
 
-	if (!pwrdm)
-		return -EINVAL;
-
 	if (pwrdm->banks < (bank + 1))
 		return -EEXIST;
 
@@ -635,6 +629,11 @@ static void _pwrdm_state_switch(struct powerdomain *pwrdm)
 
 static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
 {
+	/*
+	 * XXX It should be possible to avoid the clear_all_prev_pwrst
+	 * call for powerdomains if we are programming them to stay on,
+	 * for example.
+	 */
 	pwrdm_clear_all_prev_pwrst(pwrdm);
 	_pwrdm_state_switch(pwrdm);
 	return 0;
@@ -1000,6 +999,11 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
 		return ret;
 
 	/*
+	 * XXX Is there some way for us to skip powerdomains that
+	 * don't have a prev pwrst register?
+	 */
+
+	/*
 	 * XXX should get the powerdomain's current state here;
 	 * warn & fail if it is not ON.
 	 */
author maintainer
#6 lore raw

PATCH 6/12 ARM: OMAP2+: CM: use the cached copy of the clockdomain's hwsup state

In reply to Paul Walmsley

Avoid some unnecessary CM IP block reads by using the cached copy of the clockdomain's hardware-supervised idle state. This should simplify the code slightly and save a few hundred nanoseconds in these paths.

---
 arch/arm/mach-omap2/cm2xxx.c |   19 ++-----------------
 arch/arm/mach-omap2/cm3xxx.c |   14 ++------------
 2 files changed, 4 insertions(+), 29 deletions(-)
arch/arm/mach-omap2/cm2xxx.c +2 -17
index 6774a53..8ca13cd 100644
@@ -285,14 +285,7 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)
 
 static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
 {
-	bool hwsup = false;
-
-	if (!clkdm->clktrctrl_mask)
-		return 0;
-
-	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
-					      clkdm->clktrctrl_mask);
-	if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+	if (!clkdm_in_hwsup(clkdm) && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
 		omap2xxx_clkdm_wakeup(clkdm);
 
 	return 0;
@@ -300,15 +293,7 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)
 
 static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm)
 {
-	bool hwsup = false;
-
-	if (!clkdm->clktrctrl_mask)
-		return 0;
-
-	hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
-					      clkdm->clktrctrl_mask);
-
-	if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
+	if (!clkdm_in_hwsup(clkdm) && clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
 		omap2xxx_clkdm_sleep(clkdm);
 
 	return 0;
arch/arm/mach-omap2/cm3xxx.c +2 -12
index 9061c30..75872134 100644
@@ -227,8 +227,6 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm)
 
 static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
 {
-	bool hwsup = false;
-
 	if (!clkdm->clktrctrl_mask)
 		return 0;
 
@@ -243,10 +241,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
 		return 0;
 	}
 
-	hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
-					      clkdm->clktrctrl_mask);
-
-	if (hwsup) {
+	if (clkdm_in_hwsup(clkdm)) {
 		/* Disable HW transitions when we are changing deps */
 		omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 						clkdm->clktrctrl_mask);
@@ -263,8 +258,6 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
 
 static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
 {
-	bool hwsup = false;
-
 	if (!clkdm->clktrctrl_mask)
 		return 0;
 
@@ -280,10 +273,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
 		return 0;
 	}
 
-	hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
-					      clkdm->clktrctrl_mask);
-
-	if (hwsup) {
+	if (clkdm_in_hwsup(clkdm)) {
 		/* Disable HW transitions when we are changing deps */
 		omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
 						clkdm->clktrctrl_mask);
author maintainer
#7 lore raw

PATCH 7/12 ARM: OMAP2+: powerdomain: cache the powerdomain next power state

In reply to Paul Walmsley

Cache the powerdomain next power state registers. The objective here is to avoid unneeded reads and writes to the next power state registers, which are slow compared to RAM & CPU cache.

---
 arch/arm/mach-omap2/powerdomain.c |   64 +++++++++++++++++--------------------
 arch/arm/mach-omap2/powerdomain.h |   17 ++++++++++
 2 files changed, 46 insertions(+), 35 deletions(-)
arch/arm/mach-omap2/powerdomain.c +29 -35
index 62e2f75..425c868 100644
@@ -376,7 +376,7 @@ static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,
  * software-controllable, returns 0; otherwise, passes along the
  * return value from pwrdm_set_logic_retst() if there is an error
  * returned by that function, otherwise, passes along the return value
- * from pwrdm_set_next_pwrst()
+ * from pwrdm_set_next_fpwrst()
  */
 static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
 					    u8 logic, u8 pwrst)
@@ -426,6 +426,9 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 	int next_pwrst, next_logic, ret;
 	u8 fpwrst;
 
+	if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID)
+		return pwrdm->next_fpwrst;
+
 	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
 	if (next_pwrst < 0)
 		return next_pwrst;
@@ -438,6 +441,10 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 			return next_logic;
 	}
 	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+	if (!ret) {
+		pwrdm->next_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+	}
 
 	return (ret) ? ret : fpwrst;
 }
@@ -663,7 +670,7 @@ static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
  */
 static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 {
-	int prev, next, fpwrst;
+	int prev, fpwrst;
 	int trace_state = 0;
 
 	prev = _pwrdm_read_prev_fpwrst(pwrdm);
@@ -676,10 +683,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 	 * If the power domain did not hit the desired state,
 	 * generate a trace event with both the desired and hit states
 	 */
-	next = _pwrdm_read_next_fpwrst(pwrdm);
-	if (next != prev) {
-		trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 |
-			       prev);
+	if (pwrdm->next_fpwrst != prev) {
+		trace_state = (PWRDM_TRACE_STATES_FLAG |
+			       pwrdm->next_fpwrst << 8 | prev);
 		trace_power_domain_target(pwrdm->name, trace_state,
 					  smp_processor_id());
 	}
@@ -1256,6 +1262,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
 	if (ret)
 		return ret;
 
+	if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID &&
+	    pwrdm->next_fpwrst == fpwrst)
+		return 0;
+
 	pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst,
 		 pwrdm->name);
 
@@ -1264,6 +1274,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
 
 	pwrdm_lock(pwrdm);
 	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+	if (!ret) {
+		pwrdm->next_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+	}
 	pwrdm_unlock(pwrdm);
 
 	return ret;
@@ -1279,36 +1293,16 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
  */
 int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
 {
-	int next_pwrst, next_logic, ret;
-	u8 fpwrst;
+	int ret;
 
-	if (!arch_pwrdm)
+	if (!pwrdm)
 		return -EINVAL;
 
 	pwrdm_lock(pwrdm);
-
-	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
-	if (next_pwrst < 0) {
-		ret = next_pwrst;
-		goto prnf_out;
-	}
-
-	next_logic = next_pwrst;
-	if (_pwrdm_logic_retst_can_change(pwrdm) &&
-	    arch_pwrdm->pwrdm_read_logic_pwrst) {
-		next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
-		if (next_logic < 0) {
-			ret = next_logic;
-			goto prnf_out;
-		}
-	}
-
-	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
-
-prnf_out:
+	ret = _pwrdm_read_next_fpwrst(pwrdm);
 	pwrdm_unlock(pwrdm);
 
-	return (ret) ? ret : fpwrst;
+	return ret;
 }
 
 /**
@@ -1344,10 +1338,6 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 
 	pwrdm_lock(pwrdm);
 
-	/*
-	 * XXX quite heavyweight for what this is intended to do; the
-	 * next fpwrst should simply be cached
-	 */
 	next_fpwrst = _pwrdm_read_next_fpwrst(pwrdm);
 	if (next_fpwrst == fpwrst)
 		goto psf_out;
@@ -1364,9 +1354,13 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 	}
 
 	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
-	if (ret)
+	if (ret) {
 		pr_err("%s: unable to set power state of powerdomain: %s\n",
 		       __func__, pwrdm->name);
+	} else {
+		pwrdm->next_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID;
+	}
 
 	_pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
 
arch/arm/mach-omap2/powerdomain.h +17 -0
index c19bdc3..1fb21f5 100644
@@ -84,6 +84,16 @@ enum pwrdm_func_state {
 #define PWRDM_HAS_LOWPOWERSTATECHANGE	BIT(2)
 
 /*
+ * Powerdomain internal flags (struct powerdomain._flags)
+ *
+ * _PWRDM_NEXT_FPWRST_IS_VALID: the locally-cached copy of the
+ *    powerdomain's next-functional-power-state -- struct
+ *    powerdomain.next_fpwrst -- is valid.  If this bit is not set,
+ *    the code needs to load the current value from the hardware.
+ */
+#define _PWRDM_NEXT_FPWRST_IS_VALID	BIT(0)
+
+/*
  * Number of memory banks that are power-controllable.	On OMAP4430, the
  * maximum is 5.
  */
@@ -127,12 +137,17 @@ struct powerdomain;
  *	in @pwrstctrl_offs
  * @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans)
  * @fpwrst_counter: estimated number of times the pwrdm entered the power states
+ * @next_fpwrst: cache of the powerdomain's next-power-state
  * @timer: sched_clock() timestamp of last pwrdm_state_switch()
  * @fpwrst_timer: estimated nanoseconds of residency in the various power states
  * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
  * @_lock_flags: stored flags when @_lock is taken
+ * @_flags: flags (for internal use only)
  *
  * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
+ *
+ * Possible values for @_flags are documented above in the
+ * "Powerdomain internal flags (struct powerdomain._flags)" comments.
  */
 struct powerdomain {
 	const char *name;
@@ -149,6 +164,8 @@ struct powerdomain {
 	const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
 	const u8 prcm_partition;
 	u8 fpwrst;
+	u8 next_fpwrst;
+	u8 _flags;
 	struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
 	struct list_head node;
 	struct list_head voltdm_node;
author maintainer
#8 lore raw

PATCH 8/12 ARM: OMAP2+: powerdomain: cache the powerdomain's previous power state

In reply to Paul Walmsley

Cache the powerdomain previous power state registers. The objective here is to avoid unneeded reads from the previous power state registers. Reads from these registers can be extremely slow, even by I/O device standards. I no longer recall the exact measurements, but my recollection was that they cost several microseconds.

The cache is invalidated as part of the powerdomain pre-transition code, which runs shortly before WFI/WFE.

---
 arch/arm/mach-omap2/powerdomain.c |    9 +++++++++
 arch/arm/mach-omap2/powerdomain.h |   14 ++++++++++++++
 2 files changed, 23 insertions(+)
arch/arm/mach-omap2/powerdomain.c +9 -0
index 425c868..f5e2727 100644
@@ -499,6 +499,9 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
 	if (!_pwrdm_pwrst_can_change(pwrdm))
 		return PWRDM_FUNC_PWRST_ON;
 
+	if (pwrdm->_flags & _PWRDM_PREV_FPWRST_IS_VALID)
+		return pwrdm->prev_fpwrst;
+
 	pwrst = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
 	if (pwrst < 0)
 		return pwrst;
@@ -512,6 +515,10 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
 	}
 
 	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+	if (!ret) {
+		pwrdm->prev_fpwrst = fpwrst;
+		pwrdm->_flags |= _PWRDM_PREV_FPWRST_IS_VALID;
+	}
 
 	return (ret) ? ret : fpwrst;
 }
@@ -1017,6 +1024,8 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
 	pr_debug("powerdomain: %s: clearing previous power state reg\n",
 		 pwrdm->name);
 
+	pwrdm->_flags &= ~_PWRDM_PREV_FPWRST_IS_VALID;
+
 	if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
 		ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
 
arch/arm/mach-omap2/powerdomain.h +14 -0
index 1fb21f5..f4a189a 100644
@@ -90,8 +90,17 @@ enum pwrdm_func_state {
  *    powerdomain's next-functional-power-state -- struct
  *    powerdomain.next_fpwrst -- is valid.  If this bit is not set,
  *    the code needs to load the current value from the hardware.
+ *
+ * _PWRDM_PREV_FPWRST_IS_VALID: the locally-cached copy of the
+ *    powerdomain's previous-functional-power-state -- struct
+ *    powerdomain.prev_fpwrst -- is valid.  If this bit is not set,
+ *    the code needs to load the current value from the hardware.  The
+ *    previous-functional-power-state cache for the CORE and MPU needs
+ *    to be invalidated right before WFI, unless they were not programmed
+ *    to change power states.
  */
 #define _PWRDM_NEXT_FPWRST_IS_VALID	BIT(0)
+#define _PWRDM_PREV_FPWRST_IS_VALID	BIT(1)
 
 /*
  * Number of memory banks that are power-controllable.	On OMAP4430, the
@@ -138,6 +147,7 @@ struct powerdomain;
  * @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans)
  * @fpwrst_counter: estimated number of times the pwrdm entered the power states
  * @next_fpwrst: cache of the powerdomain's next-power-state
+ * @prev_fpwrst: cache of the powerdomain's previous-power-state bitfield
  * @timer: sched_clock() timestamp of last pwrdm_state_switch()
  * @fpwrst_timer: estimated nanoseconds of residency in the various power states
  * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
@@ -146,6 +156,9 @@ struct powerdomain;
  *
  * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
  *
+ * @prev_fpwrst is updated during pwrdm_pre_transition(), but presumably
+ * should also be updated upon clock/IP block idle transitions.
+ *
  * Possible values for @_flags are documented above in the
  * "Powerdomain internal flags (struct powerdomain._flags)" comments.
  */
@@ -165,6 +178,7 @@ struct powerdomain {
 	const u8 prcm_partition;
 	u8 fpwrst;
 	u8 next_fpwrst;
+	u8 prev_fpwrst;
 	u8 _flags;
 	struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
 	struct list_head node;
author maintainer
#9 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

In reply to Paul Walmsley

There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.

---
 arch/arm/mach-omap2/powerdomain.c           |    9 ++++++---
 arch/arm/mach-omap2/powerdomain.h           |    4 ++++
 arch/arm/mach-omap2/powerdomains2xxx_data.c |    2 ++
 arch/arm/mach-omap2/powerdomains33xx_data.c |    3 ++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c |    9 ++++++---
 arch/arm/mach-omap2/powerdomains44xx_data.c |    5 ++++-
 6 files changed, 24 insertions(+), 8 deletions(-)
arch/arm/mach-omap2/powerdomain.c +6 -3
index f5e2727..a4bb0bb 100644
@@ -462,7 +462,8 @@ static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)
 	int pwrst, logic_pwrst, ret;
 	u8 fpwrst;
 
-	if (!_pwrdm_pwrst_can_change(pwrdm))
+	if (!_pwrdm_pwrst_can_change(pwrdm) ||
+	    pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL)
 		return PWRDM_FUNC_PWRST_ON;
 
 	pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
@@ -1104,12 +1105,14 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
 
 int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
 {
-	int ret;
+	int ret = 0;
 
 	if (!pwrdm || !arch_pwrdm)
 		return -EINVAL;
 
-	ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
+	if (!(pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL))
+		ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
+
 	if (!ret)
 		_pwrdm_state_switch(pwrdm);
 
arch/arm/mach-omap2/powerdomain.h +4 -0
index f4a189a..10941fd 100644
@@ -78,10 +78,14 @@ enum pwrdm_func_state {
  *
  * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state
  * to a lower sleep state without waking up the powerdomain
+ *
+ * PWRDM_ACTIVE_WITH_KERNEL - this powerdomain's current power state is
+ * guaranteed to be ON whenever the kernel is running
  */
 #define PWRDM_HAS_HDWR_SAR		BIT(0)
 #define PWRDM_HAS_MPU_QUIRK		BIT(1)
 #define PWRDM_HAS_LOWPOWERSTATECHANGE	BIT(2)
+#define PWRDM_ACTIVE_WITH_KERNEL	BIT(3)
 
 /*
  * Powerdomain internal flags (struct powerdomain._flags)
arch/arm/mach-omap2/powerdomains2xxx_data.c +2 -0
index 578eef8..112927f 100644
@@ -54,6 +54,7 @@ static struct powerdomain mpu_24xx_pwrdm = {
 		[0] = PWRSTS_ON,
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 static struct powerdomain core_24xx_pwrdm = {
@@ -73,6 +74,7 @@ static struct powerdomain core_24xx_pwrdm = {
 		[2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 
arch/arm/mach-omap2/powerdomains33xx_data.c +2 -1
index 869adb8..acb148a 100644
@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = {
 	.pwrstst_offs		= AM33XX_PM_MPU_PWRSTST_OFFSET,
 	.pwrsts			= PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret	= PWRSTS_OFF_RET,
-	.flags			= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags			= (PWRDM_HAS_LOWPOWERSTATECHANGE |
+				   PWRDM_ACTIVE_WITH_KERNEL),
 	.banks			= 3,
 	.logicretstate_mask	= AM33XX_LOGICRETSTATE_MASK,
 	.mem_on_mask		= {
arch/arm/mach-omap2/powerdomains3xxx_data.c +6 -3
index f0e14e9ef..ade93d3 100644
@@ -58,7 +58,7 @@ static struct powerdomain mpu_3xxx_pwrdm = {
 	.prcm_offs	  = MPU_MOD,
 	.pwrsts		  = PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
-	.flags		  = PWRDM_HAS_MPU_QUIRK,
+	.flags		  = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL),
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,
@@ -74,7 +74,7 @@ static struct powerdomain mpu_am35x_pwrdm = {
 	.prcm_offs	  = MPU_MOD,
 	.pwrsts		  = PWRSTS_ON,
 	.pwrsts_logic_ret = PWRSTS_ON,
-	.flags		  = PWRDM_HAS_MPU_QUIRK,
+	.flags		  = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL),
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_ON,
@@ -110,6 +110,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = {
 		[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,7 +122,8 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
 	 * Setting the SAR flag for errata ID i478 which applies
 	 *  to 3430 <= ES3.1
 	 */
-	.flags		  = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
+	.flags		  = (PWRDM_HAS_HDWR_SAR |  /* for USBTLL only */
+			     PWRDM_ACTIVE_WITH_KERNEL),
 	.banks		  = 2,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,	 /* MEM1RETSTATE */
@@ -149,6 +151,7 @@ static struct powerdomain core_am35x_pwrdm = {
 		[1] = PWRSTS_ON, /* MEM2ONSTATE */
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 static struct powerdomain dss_pwrdm = {
arch/arm/mach-omap2/powerdomains44xx_data.c +4 -1
index 704664c..b64213c 100644
@@ -53,7 +53,8 @@ static struct powerdomain core_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* ducati_l2ram */
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
-	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags		  = (PWRDM_HAS_LOWPOWERSTATECHANGE |
+			     PWRDM_ACTIVE_WITH_KERNEL),
 };
 
 /* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -164,6 +165,7 @@ static struct powerdomain cpu0_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* cpu0_l1 */
 	},
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 /* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
@@ -218,6 +220,7 @@ static struct powerdomain mpu_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* mpu_l2 */
 		[2] = PWRSTS_ON,	/* mpu_ram */
 	},
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 /* ivahd_44xx_pwrdm: IVA-HD power domain */
#10 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

Quoted 92 lines · Paul Walmsley

There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.

---
 arch/arm/mach-omap2/powerdomain.c           |    9 ++++++---
 arch/arm/mach-omap2/powerdomain.h           |    4 ++++
 arch/arm/mach-omap2/powerdomains2xxx_data.c |    2 ++
 arch/arm/mach-omap2/powerdomains33xx_data.c |    3 ++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c |    9 ++++++---
 arch/arm/mach-omap2/powerdomains44xx_data.c |    5 ++++-
 6 files changed, 24 insertions(+), 8 deletions(-)
arch/arm/mach-omap2/powerdomain.c +6 -3
index f5e2727..a4bb0bb 100644
@@ -462,7 +462,8 @@ static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)
 	int pwrst, logic_pwrst, ret;
 	u8 fpwrst;
 
-	if (!_pwrdm_pwrst_can_change(pwrdm))
+	if (!_pwrdm_pwrst_can_change(pwrdm) ||
+	    pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL)
 		return PWRDM_FUNC_PWRST_ON;
 
 	pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
@@ -1104,12 +1105,14 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
 
 int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
 {
-	int ret;
+	int ret = 0;
 
 	if (!pwrdm || !arch_pwrdm)
 		return -EINVAL;
 
-	ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
+	if (!(pwrdm->flags & PWRDM_ACTIVE_WITH_KERNEL))
+		ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
+
 	if (!ret)
 		_pwrdm_state_switch(pwrdm);
 
arch/arm/mach-omap2/powerdomain.h +4 -0
index f4a189a..10941fd 100644
@@ -78,10 +78,14 @@ enum pwrdm_func_state {
  *
  * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state
  * to a lower sleep state without waking up the powerdomain
+ *
+ * PWRDM_ACTIVE_WITH_KERNEL - this powerdomain's current power state is
+ * guaranteed to be ON whenever the kernel is running
  */
 #define PWRDM_HAS_HDWR_SAR		BIT(0)
 #define PWRDM_HAS_MPU_QUIRK		BIT(1)
 #define PWRDM_HAS_LOWPOWERSTATECHANGE	BIT(2)
+#define PWRDM_ACTIVE_WITH_KERNEL	BIT(3)
 
 /*
  * Powerdomain internal flags (struct powerdomain._flags)
arch/arm/mach-omap2/powerdomains2xxx_data.c +2 -0
index 578eef8..112927f 100644
@@ -54,6 +54,7 @@ static struct powerdomain mpu_24xx_pwrdm = {
 		[0] = PWRSTS_ON,
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 static struct powerdomain core_24xx_pwrdm = {
@@ -73,6 +74,7 @@ static struct powerdomain core_24xx_pwrdm = {
 		[2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 
arch/arm/mach-omap2/powerdomains33xx_data.c +0 -0
index 869adb8..acb148a 100644

arch/arm/mach-omap2/powerdomains33xx_data.c static struct powerdomain mpu_33xx_pwrdm = { · line 127

Quoted 6 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +2 -1
@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = {
 	.pwrstst_offs		= AM33XX_PM_MPU_PWRSTST_OFFSET,
 	.pwrsts			= PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret	= PWRSTS_OFF_RET,
-	.flags			= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags			= (PWRDM_HAS_LOWPOWERSTATECHANGE |
+				   PWRDM_ACTIVE_WITH_KERNEL),

This needs to be applicable for "wkup_pwrdm" as well.

Thanks,
Vaibhav

Quoted 89 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +0 -0
 	.banks			= 3,
 	.logicretstate_mask	= AM33XX_LOGICRETSTATE_MASK,
 	.mem_on_mask		= {
arch/arm/mach-omap2/powerdomains3xxx_data.c +6 -3
index f0e14e9ef..ade93d3 100644
@@ -58,7 +58,7 @@ static struct powerdomain mpu_3xxx_pwrdm = {
 	.prcm_offs	  = MPU_MOD,
 	.pwrsts		  = PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
-	.flags		  = PWRDM_HAS_MPU_QUIRK,
+	.flags		  = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL),
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,
@@ -74,7 +74,7 @@ static struct powerdomain mpu_am35x_pwrdm = {
 	.prcm_offs	  = MPU_MOD,
 	.pwrsts		  = PWRSTS_ON,
 	.pwrsts_logic_ret = PWRSTS_ON,
-	.flags		  = PWRDM_HAS_MPU_QUIRK,
+	.flags		  = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL),
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_ON,
@@ -110,6 +110,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = {
 		[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,7 +122,8 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
 	 * Setting the SAR flag for errata ID i478 which applies
 	 *  to 3430 <= ES3.1
 	 */
-	.flags		  = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
+	.flags		  = (PWRDM_HAS_HDWR_SAR |  /* for USBTLL only */
+			     PWRDM_ACTIVE_WITH_KERNEL),
 	.banks		  = 2,
 	.pwrsts_mem_ret	  = {
 		[0] = PWRSTS_OFF_RET,	 /* MEM1RETSTATE */
@@ -149,6 +151,7 @@ static struct powerdomain core_am35x_pwrdm = {
 		[1] = PWRSTS_ON, /* MEM2ONSTATE */
 	},
 	.voltdm		  = { .name = "core" },
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 static struct powerdomain dss_pwrdm = {
arch/arm/mach-omap2/powerdomains44xx_data.c +4 -1
index 704664c..b64213c 100644
@@ -53,7 +53,8 @@ static struct powerdomain core_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* ducati_l2ram */
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
-	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags		  = (PWRDM_HAS_LOWPOWERSTATECHANGE |
+			     PWRDM_ACTIVE_WITH_KERNEL),
 };
 
 /* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -164,6 +165,7 @@ static struct powerdomain cpu0_44xx_pwrdm = {
 	.pwrsts_mem_on	= {
 		[0] = PWRSTS_ON,	/* cpu0_l1 */
 	},
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 /* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
@@ -218,6 +220,7 @@ static struct powerdomain mpu_44xx_pwrdm = {
 		[1] = PWRSTS_ON,	/* mpu_l2 */
 		[2] = PWRSTS_ON,	/* mpu_ram */
 	},
+	.flags		  = PWRDM_ACTIVE_WITH_KERNEL,
 };
 
 /* ivahd_44xx_pwrdm: IVA-HD power domain */

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#11 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

In reply to Paul Walmsley

Hi Paul,

Quoted 16 lines · Paul Walmsley

There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.

---
 arch/arm/mach-omap2/powerdomain.c           |    9 ++++++---
 arch/arm/mach-omap2/powerdomain.h           |    4 ++++
 arch/arm/mach-omap2/powerdomains2xxx_data.c |    2 ++
 arch/arm/mach-omap2/powerdomains33xx_data.c |    3 ++-
 arch/arm/mach-omap2/powerdomains3xxx_data.c |    9 ++++++---
 arch/arm/mach-omap2/powerdomains44xx_data.c |    5 ++++-
 6 files changed, 24 insertions(+), 8 deletions(-)

[snip]

arch/arm/mach-omap2/powerdomains44xx_data.c static struct powerdomain core_44xx_pwrdm = { · line 58

Quoted 12 lines
arch/arm/mach-omap2/powerdomains44xx_data.c +2 -1
index 704664c..b64213c 100644
@@ -53,7 +53,8 @@ static struct powerdomain core_44xx_pwrdm = {
 		[3] = PWRSTS_ON,	/* ducati_l2ram */
 		[4] = PWRSTS_ON,	/* ducati_unicache */
 	},
-	.flags		  = PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags		  = (PWRDM_HAS_LOWPOWERSTATECHANGE |
+			     PWRDM_ACTIVE_WITH_KERNEL),
 };

My understanding is that for OMAP4 devices, the core power domain may not be active the same time as the MPU power domain. The Cortex-A9 has the ability to access some peripherals (such as timer, McBSP) via a private bus that does not require the core domain to be active. This is a difference from OMAP3 devices, where the core would always be on with the MPU power domain.

Hopefully, Benoit will chime in if I have gotten this wrong ;-)

Cheers
Jon

author maintainer
#12 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

Quoted 6 lines · Jon Hunter

My understanding is that for OMAP4 devices, the core power domain may not be active the same time as the MPU power domain. The Cortex-A9 has the ability to access some peripherals (such as timer, McBSP) via a private bus that does not require the core domain to be active. This is a difference from OMAP3 devices, where the core would always be on with the MPU power domain.

You are absolutely right and I will drop that part from this patch.

- Paul

#13 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

Quoted 11 lines · Paul Walmsley
Quoted 6 lines · Jon Hunter

My understanding is that for OMAP4 devices, the core power domain may not be active the same time as the MPU power domain. The Cortex-A9 has the ability to access some peripherals (such as timer, McBSP) via a private bus that does not require the core domain to be active. This is a difference from OMAP3 devices, where the core would always be on with the MPU power domain.

You are absolutely right and I will drop that part from this patch.

Just to be clear, MPU has direct path to ABE domain peripherals on OMAP4. As Jon pointed out MCBSP and few timers are put under this domain can be directly accessed by MPU without L3. ABE also can be accessed via L3 by MPU. ABE has a dual map with MPU.

Regards
Santosh

#14 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

In reply to Paul Walmsley

Hi Paul,

Quoted 5 lines · Paul Walmsley

There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.

[...]

arch/arm/mach-omap2/powerdomains33xx_data.c static struct powerdomain mpu_33xx_pwrdm = { · line 127

Quoted 11 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +2 -1
index 869adb8..acb148a 100644
@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = {
 	.pwrstst_offs		= AM33XX_PM_MPU_PWRSTST_OFFSET,
 	.pwrsts			= PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret	= PWRSTS_OFF_RET,
-	.flags			= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags			= (PWRDM_HAS_LOWPOWERSTATECHANGE |
+				   PWRDM_ACTIVE_WITH_KERNEL),

In case of AM33xx, this flag should be set for PER and WKUP pwrdms also. EMIF, L3, L4 etc come under PER so this domain can't transition on an active system. PRCM and Control module come under WKUP, so the WKUP should the kernel should attempt to transition WKUP domain also.

Regards,
Vaibhav

#15 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

Quoted 9 lines · Vaibhav

Hi Paul,

Quoted 5 lines · Paul Walmsley

There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.

[...]

Quoted 15 lines

arch/arm/mach-omap2/powerdomains33xx_data.c static struct powerdomain mpu_33xx_pwrdm = { · line 127

Quoted 11 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +2 -1
index 869adb8..acb148a 100644
@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = {
 	.pwrstst_offs		= AM33XX_PM_MPU_PWRSTST_OFFSET,
 	.pwrsts			= PWRSTS_OFF_RET_ON,
 	.pwrsts_logic_ret	= PWRSTS_OFF_RET,
-	.flags			= PWRDM_HAS_LOWPOWERSTATECHANGE,
+	.flags			= (PWRDM_HAS_LOWPOWERSTATECHANGE |
+				   PWRDM_ACTIVE_WITH_KERNEL),

In case of AM33xx, this flag should be set for PER and WKUP pwrdms also. EMIF, L3, L4 etc come under PER so this domain can't transition on an active system. PRCM and Control module come under WKUP, so

... the kernel should not attempt to change the WKUP power domain state.

Regards,
Vaibhav

author maintainer
#16 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on

In reply to Bedia, Vaibhav
Quoted 4 lines · Vaibhav

In case of AM33xx, this flag should be set for PER and WKUP pwrdms also. EMIF, L3, L4 etc come under PER so this domain can't transition on an active system. PRCM and Control module come under WKUP, so the WKUP should the kernel should attempt to transition WKUP domain also.

Thanks - the patch has been updated to reflect this.

- Paul

author maintainer
#17 lore raw

PATCH 10/12 ARM: OMAP2+: powerdomain: skip previous-power-state read if next_pwrst is ON

In reply to Paul Walmsley

If the powerdomain's next-power-state is set to ON, then we can skip the powerdomain previous-power-state read during pwrdm_post_transition(). This is both an optimization (for all OMAPs) and a fix (for OMAP2xxx). It turns out the OMAP2xxx previous power state mechanism is slightly different than the OMAP3+ mechanism. The bitfield can't be cleared, and it's only updated after a powerdomain power state transition. So reading this value before any powerdomain power state transition occurred will always return OFF (the reset value). After this patch, if the power domain was programmed to stay ON before pwrdm_pre_transition() is called, the previous power state code will return ON during pwrdm_post_transition().

---
 arch/arm/mach-omap2/powerdomain.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/powerdomain.c +3 -1
index a4bb0bb..72d6ce0 100644
@@ -681,7 +681,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 	int prev, fpwrst;
 	int trace_state = 0;
 
-	prev = _pwrdm_read_prev_fpwrst(pwrdm);
+	prev = (pwrdm->next_fpwrst == PWRDM_FUNC_PWRST_ON) ?
+		PWRDM_FUNC_PWRST_ON : _pwrdm_read_prev_fpwrst(pwrdm);
+
 	if (pwrdm->fpwrst != prev)
 		pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++;
 
author maintainer
#18 lore raw

PATCH 11/12 ARM: OMAP2xxx: powerdomain: add previous power state tracking

In reply to Paul Walmsley

The OMAP2xxx PRM does support a form of powerdomain previous-power-state tracking; so add it. This allows the power state tracking and debugging code to do something useful on this platform.

---
 arch/arm/mach-omap2/prm2xxx.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)
arch/arm/mach-omap2/prm2xxx.c +12 -0
index e4cdb69..2d3c905 100644
@@ -180,10 +180,22 @@ static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
 	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
 }
 
+static int omap2xxx_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
+{
+	u8 omap2xxx_pwrst;
+
+	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
+						       OMAP2_PM_PWSTST,
+						       OMAP24XX_LASTSTATEENTERED_MASK);
+
+	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
+}
+
 struct pwrdm_ops omap2_pwrdm_operations = {
 	.pwrdm_set_next_pwrst	= omap2xxx_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2xxx_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap2xxx_pwrdm_read_pwrst,
+	.pwrdm_read_prev_pwrst	= omap2xxx_pwrdm_read_prev_pwrst,
 	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
 	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
 	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
author maintainer
#19 lore raw

PATCH 12/12 ARM: OMAP2xxx: PM: add pwrdm_(pre|post)_transition() calls to the 2xxx PM code

In reply to Paul Walmsley

The OMAP2xxx PM code was missing calls to pwrdm_pre_transition() and pwrdm_post_transition(). This prevented the power state debugging from working correctly, and also violated some assumptions that are used in future power state caching patches.

---
 arch/arm/mach-omap2/pm24xx.c |    8 ++++++++
 1 file changed, 8 insertions(+)
arch/arm/mach-omap2/pm24xx.c +8 -0
index 99c16c2..896727c 100644
@@ -98,6 +98,8 @@ static int omap2_enter_full_retention(void)
 
 	omap2_gpio_prepare_for_idle(0);
 
+	pwrdm_pre_transition(NULL);
+
 	/* One last check for pending IRQs to avoid extra latency due
 	 * to sleeping unnecessarily. */
 	if (omap_irq_pending())
@@ -109,6 +111,8 @@ static int omap2_enter_full_retention(void)
 			   OMAP_SDRC_REGADDR(SDRC_POWER));
 
 no_sleep:
+	pwrdm_post_transition(NULL);
+
 	omap2_gpio_resume_after_idle();
 
 	clk_enable(osc_ck);
@@ -191,8 +195,12 @@ static void omap2_enter_mpu_retention(void)
 		WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON));
 	}
 
+	pwrdm_pre_transition(mpu_pwrdm);
+
 	omap2_sram_idle();
 
+	pwrdm_post_transition(mpu_pwrdm);
+
 	WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON));
 }
 
#20 lore raw

cover ARM: OMAP2+: powerdomain updates after the functional power state conversion

In reply to Paul Walmsley

Hi Paul,

Tested this whole set on omap3beagle and omap4panda. The only regression I noticed was that cpu0 debug counters do not increment on omap4 after this set. The patch at the end fixes this problem. Other than that, you can add acked-by tag from me if you want, I went the code through quickly and don't have any comments to it.

-Tero

From: Tero Kristo <[email protected]>
Date: Thu, 3 Jan 2013 20:07:27 +0200
Subject: [PATCH] ARM: OMAP4: PM: fix cpu0 statistics update during idle

Cpu0 PM counters do not update, as the cpu0 fpwrst is set to ON before calling pwrdm_post_transition. The optimized code checks whether the fpwrst is ON, and skips any further checks if this is the case. Fixed by re-ordering the code within omap4_mpuss_enter_lowpower function.

---
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)
(quoted diff) +0 -0

b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 9acd52a..1bdd59e 100644

arch/arm/mach-omap2/omap-mpuss-lowpower.c +0 -0
@@ -269,10 +269,16 @@ int omap4_mpuss_enter_lowpower(unsigned int cpu,

u8 fpwrst)
* domain transition
*/
wakeup_cpu = smp_processor_id();
- WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));

+ /*
+ * Due to optimizations to the code, pwrdm_post_transition
+ * must be called prior to resetting cpu0 pwrst to ON,
+ * otherwise cpu0 powerstate statistics don't update properly
+ */
pwrdm_post_transition(NULL);

+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
+
return 0;
}

Signature · 1 line
1.7.4.1