Skip to contentSkip to conversation

ARM: OMAP2+: PM: introduce the power domains functional states

PATCH Superseded Jean Pihet 3 participants 22 messages Jun 14, 2012 – Jul 19, 2012

Subsystems (4)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Jean Pihet

author
#0 lore raw

v4 cover ARM: OMAP2+: PM: introduce the power domains functional states

Here is a re-spin after some comments after an internal review and some testing on OMAP4 with device OFF support.

Implement the functional states for the power domains:
- unify the API to use the functional states,
- protect the power domain state change by a mutex in omap_set_pwrdm_state,
- introduce the functional states for power domains power states and logic power states, and the conversion functions between the functional and internal states,
- program the logic power state of power domains from the functional states, in omap_set_pwrdm_state
- convert the OMAP2/3/4 PM code to use the updated API,
- provide the power domains statistics by functional states,
- provide ftrace tracepoints with the functional state.

Based on mainline kernel 3.5.0-rc2.

Tested on OMAP3 Beagleboard, with suspend and cpuidle in RET and OFF modes.

History:
v4:
- reworked the code after internal review and testing with OMAP3&4 device OFF,
- fixed the tracepoints generation code,
- introduce a function that returns power domains achievable functional states, in order to return a valid state for power domains that only support some of the power states. Although it has been tested OK the code is in RFC state.

v3:
- fix a bug in OMAP3 cpuidle which prevented the IO wake-ups in PER

v2:
- add the logic power states,
- provide the power domains statistics by functional states

v1:
- initial implementation, in RFC state

Jean Pihet (8):
ARM: OMAP2+: PM: protect the power domain state change by a mutex
ARM: OMAP2+: PM: introduce power domains functional states
ARM: OMAP2+: PM: use the functional power states API
ARM: OMAP2+: PM: introduce power domains logic and memory functional
states
ARM: OMAP2+: PM: introduce power domains achievable functional states
ARM: OMAP2+: PM: use the functional power states API for logic and
memory
ARM: OMAP2+: PM: use power domain functional state in stats counters
ARM: OMAP2+: PM debug: trace the functional power domains states

 arch/arm/mach-omap2/cpuidle34xx.c          |   61 +++---
 arch/arm/mach-omap2/cpuidle44xx.c          |   28 +--
 arch/arm/mach-omap2/omap-hotplug.c         |    2 +-
 arch/arm/mach-omap2/omap-mpuss-lowpower.c  |   39 ++--
 arch/arm/mach-omap2/pm-debug.c             |   15 +-
 arch/arm/mach-omap2/pm.c                   |   62 -----
 arch/arm/mach-omap2/pm.h                   |    1 -
 arch/arm/mach-omap2/pm24xx.c               |   15 +-
 arch/arm/mach-omap2/pm34xx.c               |   78 +++---
 arch/arm/mach-omap2/pm44xx.c               |   18 +-
 arch/arm/mach-omap2/powerdomain-common.c   |  100 ++++++++
 arch/arm/mach-omap2/powerdomain.c          |  367 ++++++++++++++++++++++++++--
 arch/arm/mach-omap2/powerdomain.h          |  101 ++++++--
 arch/arm/mach-omap2/powerdomain2xxx_3xxx.c |    7 +
 arch/arm/mach-omap2/powerdomain44xx.c      |    3 +
 15 files changed, 653 insertions(+), 244 deletions(-)
Signature · 1 line
1.7.7.6
author
#1 lore raw

PATCH v4 1/8 ARM: OMAP2+: PM: protect the power domain state change by a mutex

omap_set_pwrdm_state is intented to be the only API for changing a power domain state.
This patch protects the power domains settings and structs from concurrent accesses to the function by using a mutex.

---
 arch/arm/mach-omap2/pm.c          |    8 ++++++--
 arch/arm/mach-omap2/powerdomain.c |    1 +
 arch/arm/mach-omap2/powerdomain.h |    3 ++-
 3 files changed, 9 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/pm.c +6 -2
index 9cb5ced..a05f00c 100644
@@ -100,15 +100,17 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
 	if (!pwrdm || IS_ERR(pwrdm))
 		return -EINVAL;
 
+	mutex_lock(&pwrdm->lock);
+
 	while (!(pwrdm->pwrsts & (1 << pwrst))) {
 		if (pwrst == PWRDM_POWER_OFF)
-			return ret;
+			goto out;
 		pwrst--;
 	}
 
 	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
 	if (next_pwrst == pwrst)
-		return ret;
+		goto out;
 
 	curr_pwrst = pwrdm_read_pwrst(pwrdm);
 	if (curr_pwrst < PWRDM_POWER_ON) {
@@ -141,6 +143,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
 		break;
 	}
 
+out:
+	mutex_unlock(&pwrdm->lock);
 	return ret;
 }
 
arch/arm/mach-omap2/powerdomain.c +1 -0
index 9611490..1641e72 100644
@@ -102,6 +102,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	INIT_LIST_HEAD(&pwrdm->voltdm_node);
 	voltdm_add_pwrdm(voltdm, pwrdm);
 
+	mutex_init(&pwrdm->lock);
 	list_add(&pwrdm->node, &pwrdm_list);
 
 	/* Initialize the powerdomain's state counter */
arch/arm/mach-omap2/powerdomain.h +2 -1
index 8f88d65..bab84fc 100644
@@ -19,7 +19,7 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
-
+#include <linux/mutex.h>
 #include <linux/atomic.h>
 
 #include <plat/cpu.h>
@@ -116,6 +116,7 @@ struct powerdomain {
 	struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
 	struct list_head node;
 	struct list_head voltdm_node;
+	struct mutex lock;
 	int state;
 	unsigned state_counter[PWRDM_MAX_PWRSTS];
 	unsigned ret_logic_off_counter;
Signature · 1 line
1.7.7.6
#2 lore raw

PATCH 1/8 ARM: OMAP2+: PM: protect the power domain state change by a mutex

Quoted 2 lines · Jean Pihet

omap_set_pwrdm_state is intented to be the only API for changing a power domain state.

Yes, but there are others which are used to _read_ the power domain state. Shouldn't those be protected too?

Quoted 76 lines

This patch protects the power domains settings and structs from concurrent accesses to the function by using a mutex.

---
  arch/arm/mach-omap2/pm.c          |    8 ++++++--
  arch/arm/mach-omap2/powerdomain.c |    1 +
  arch/arm/mach-omap2/powerdomain.h |    3 ++-
  3 files changed, 9 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/pm.c +6 -2
index 9cb5ced..a05f00c 100644
@@ -100,15 +100,17 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
  	if (!pwrdm || IS_ERR(pwrdm))
  		return -EINVAL;
 
+	mutex_lock(&pwrdm->lock);
+
  	while (!(pwrdm->pwrsts&  (1<<  pwrst))) {
  		if (pwrst == PWRDM_POWER_OFF)
-			return ret;
+			goto out;
  		pwrst--;
  	}
 
  	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
  	if (next_pwrst == pwrst)
-		return ret;
+		goto out;
 
  	curr_pwrst = pwrdm_read_pwrst(pwrdm);
  	if (curr_pwrst<  PWRDM_POWER_ON) {
@@ -141,6 +143,8 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
  		break;
  	}
 
+out:
+	mutex_unlock(&pwrdm->lock);
  	return ret;
  }
 
arch/arm/mach-omap2/powerdomain.c +1 -0
index 9611490..1641e72 100644
@@ -102,6 +102,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
  	INIT_LIST_HEAD(&pwrdm->voltdm_node);
  	voltdm_add_pwrdm(voltdm, pwrdm);
 
+	mutex_init(&pwrdm->lock);
  	list_add(&pwrdm->node,&pwrdm_list);
 
  	/* Initialize the powerdomain's state counter */
arch/arm/mach-omap2/powerdomain.h +2 -1
index 8f88d65..bab84fc 100644
@@ -19,7 +19,7 @@
 
  #include<linux/types.h>
  #include<linux/list.h>
-
+#include<linux/mutex.h>
  #include<linux/atomic.h>
 
  #include<plat/cpu.h>
@@ -116,6 +116,7 @@ struct powerdomain {
  	struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
  	struct list_head node;
  	struct list_head voltdm_node;
+	struct mutex lock;
  	int state;
  	unsigned state_counter[PWRDM_MAX_PWRSTS];
  	unsigned ret_logic_off_counter;
author
#3 lore raw

PATCH v4 2/8 ARM: OMAP2+: PM: introduce power domains functional states

In reply to Jean Pihet

Introduce functional (or logical) states for power domains and the API functions to read the power domains settings and to convert between the functional (i.e. logical) and the internal (or registers) values.

OMAP2, OMAP3 and OMAP4 platforms are defining a conversion routine.

In the new API only the function omap_set_pwrdm_state shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters.
While at it the function is moved to the power domains code.

The power domain API in powerdomain.h is split in the external and the internal parts; only the external API functions and defines shall be used by external code, the internal API is only to be used in powerdomain*.[ch] files.

The memory and logic states are not using the functional states, this comes as a subsequent patch.

---
 arch/arm/mach-omap2/pm.c                   |   66 -----------
 arch/arm/mach-omap2/pm.h                   |    1 -
 arch/arm/mach-omap2/powerdomain-common.c   |   71 +++++++++++
 arch/arm/mach-omap2/powerdomain.c          |  174 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h          |   77 +++++++++----
 arch/arm/mach-omap2/powerdomain2xxx_3xxx.c |    5 +
 arch/arm/mach-omap2/powerdomain44xx.c      |    2 +
 7 files changed, 306 insertions(+), 90 deletions(-)
arch/arm/mach-omap2/pm.c +0 -66
index a05f00c..dfe702b 100644
@@ -74,10 +74,6 @@ static void __init omap2_init_processor_devices(void)
 	}
 }
 
-/* Types of sleep_switch used in omap_set_pwrdm_state */
-#define FORCEWAKEUP_SWITCH	0
-#define LOWPOWERSTATE_SWITCH	1
-
 int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
 {
 	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
@@ -89,68 +85,6 @@ int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
 }
 
 /*
- * This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported.
- */
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
-{
-	u8 curr_pwrst, next_pwrst;
-	int sleep_switch = -1, ret = 0, hwsup = 0;
-
-	if (!pwrdm || IS_ERR(pwrdm))
-		return -EINVAL;
-
-	mutex_lock(&pwrdm->lock);
-
-	while (!(pwrdm->pwrsts & (1 << pwrst))) {
-		if (pwrst == PWRDM_POWER_OFF)
-			goto out;
-		pwrst--;
-	}
-
-	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
-	if (next_pwrst == pwrst)
-		goto out;
-
-	curr_pwrst = pwrdm_read_pwrst(pwrdm);
-	if (curr_pwrst < PWRDM_POWER_ON) {
-		if ((curr_pwrst > pwrst) &&
-			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
-			sleep_switch = LOWPOWERSTATE_SWITCH;
-		} else {
-			hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
-			clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
-			sleep_switch = FORCEWAKEUP_SWITCH;
-		}
-	}
-
-	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
-	if (ret)
-		pr_err("%s: unable to set power state of powerdomain: %s\n",
-		       __func__, pwrdm->name);
-
-	switch (sleep_switch) {
-	case FORCEWAKEUP_SWITCH:
-		if (hwsup)
-			clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
-		else
-			clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
-		break;
-	case LOWPOWERSTATE_SWITCH:
-		pwrdm_set_lowpwrstchange(pwrdm);
-		pwrdm_wait_transition(pwrdm);
-		pwrdm_state_switch(pwrdm);
-		break;
-	}
-
-out:
-	mutex_unlock(&pwrdm->lock);
-	return ret;
-}
-
-
-
-/*
  * This API is to be called during init to set the various voltage
  * domains to the voltage as per the opp table. Typically we boot up
  * at the nominal voltage. So this function finds out the rate of
arch/arm/mach-omap2/pm.h +0 -1
index 7856489..5bc0848 100644
@@ -18,7 +18,6 @@
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
-extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 extern int omap4_idle_init(void);
 extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
arch/arm/mach-omap2/powerdomain-common.c +71 -0

74 lines not on this page · raw message

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

198 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.h +54 -23

136 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +5 -0
index 0f0a9f1..79c1293 100644
@@ -26,6 +26,7 @@
 
 
 /* Common functions across OMAP2 and OMAP3 */
+
 static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 {
 	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
@@ -210,6 +211,8 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap2_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
@@ -222,6 +225,8 @@ struct pwrdm_ops omap2_pwrdm_operations = {
 };
 
 struct pwrdm_ops omap3_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
arch/arm/mach-omap2/powerdomain44xx.c +2 -0
index 601325b..538b528 100644
@@ -209,6 +209,8 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap4_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap4_pwrdm_read_pwrst,
Signature · 1 line
1.7.7.6
author
#4 lore raw

PATCH v4 2/8 ARM: OMAP2+: PM: introduce power domains functional states

Hi,

Here are some remarks I got after an internal review. I think those points need to be discussed with a broader audience.

Quoted 434 lines · Jean Pihet

Introduce functional (or logical) states for power domains and the API functions to read the power domains settings and to convert between the functional (i.e. logical) and the internal (or registers) values.

OMAP2, OMAP3 and OMAP4 platforms are defining a conversion routine.

In the new API only the function omap_set_pwrdm_state shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters.
While at it the function is moved to the power domains code.

The power domain API in powerdomain.h is split in the external and the internal parts; only the external API functions and defines shall be used by external code, the internal API is only to be used in powerdomain*.[ch] files.

The memory and logic states are not using the functional states, this comes as a subsequent patch.

---

?arch/arm/mach-omap2/pm.c ? ? ? ? ? ? ? ? ? | ? 66 -----------
?arch/arm/mach-omap2/pm.h ? ? ? ? ? ? ? ? ? | ? ?1 -
?arch/arm/mach-omap2/powerdomain-common.c ? | ? 71 +++++++++++
?arch/arm/mach-omap2/powerdomain.c ? ? ? ? ?| ?174 ++++++++++++++++++++++++++++
?arch/arm/mach-omap2/powerdomain.h ? ? ? ? ?| ? 77 +++++++++----
?arch/arm/mach-omap2/powerdomain2xxx_3xxx.c | ? ?5 +
?arch/arm/mach-omap2/powerdomain44xx.c ? ? ?| ? ?2 +

?7 files changed, 306 insertions(+), 90 deletions(-)

arch/arm/mach-omap2/pm.c +0 -4
index a05f00c..dfe702b 100644
@@ -74,10 +74,6 @@ static void __init omap2_init_processor_devices(void)
 ? ? ? ?}
 ?}
 
-/* Types of sleep_switch used in omap_set_pwrdm_state */
-#define FORCEWAKEUP_SWITCH ? ? 0
-#define LOWPOWERSTATE_SWITCH ? 1
-
 ?int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
 ?{
 ? ? ? ?if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
@@ -89,68 +85,6 @@ int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
 ?}
 

?/*
- * This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported.
- */

arch/arm/mach-omap2/pm.c +0 -59
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
-{
- ? ? ? u8 curr_pwrst, next_pwrst;
- ? ? ? int sleep_switch = -1, ret = 0, hwsup = 0;
-
- ? ? ? if (!pwrdm || IS_ERR(pwrdm))
- ? ? ? ? ? ? ? return -EINVAL;
-
- ? ? ? mutex_lock(&pwrdm->lock);
-
- ? ? ? while (!(pwrdm->pwrsts & (1 << pwrst))) {
- ? ? ? ? ? ? ? if (pwrst == PWRDM_POWER_OFF)
- ? ? ? ? ? ? ? ? ? ? ? goto out;
- ? ? ? ? ? ? ? pwrst--;
- ? ? ? }
-
- ? ? ? next_pwrst = pwrdm_read_next_pwrst(pwrdm);
- ? ? ? if (next_pwrst == pwrst)
- ? ? ? ? ? ? ? goto out;
-
- ? ? ? curr_pwrst = pwrdm_read_pwrst(pwrdm);
- ? ? ? if (curr_pwrst < PWRDM_POWER_ON) {
- ? ? ? ? ? ? ? if ((curr_pwrst > pwrst) &&
- ? ? ? ? ? ? ? ? ? ? ? (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
- ? ? ? ? ? ? ? ? ? ? ? sleep_switch = LOWPOWERSTATE_SWITCH;
- ? ? ? ? ? ? ? } else {
- ? ? ? ? ? ? ? ? ? ? ? hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
- ? ? ? ? ? ? ? ? ? ? ? clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
- ? ? ? ? ? ? ? ? ? ? ? sleep_switch = FORCEWAKEUP_SWITCH;
- ? ? ? ? ? ? ? }
- ? ? ? }
-
- ? ? ? ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
- ? ? ? if (ret)
- ? ? ? ? ? ? ? pr_err("%s: unable to set power state of powerdomain: %s\n",
- ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm->name);
-
- ? ? ? switch (sleep_switch) {
- ? ? ? case FORCEWAKEUP_SWITCH:
- ? ? ? ? ? ? ? if (hwsup)
- ? ? ? ? ? ? ? ? ? ? ? clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
- ? ? ? ? ? ? ? else
- ? ? ? ? ? ? ? ? ? ? ? clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
- ? ? ? ? ? ? ? break;
- ? ? ? case LOWPOWERSTATE_SWITCH:
- ? ? ? ? ? ? ? pwrdm_set_lowpwrstchange(pwrdm);
- ? ? ? ? ? ? ? pwrdm_wait_transition(pwrdm);
- ? ? ? ? ? ? ? pwrdm_state_switch(pwrdm);
- ? ? ? ? ? ? ? break;
- ? ? ? }
-
-out:
- ? ? ? mutex_unlock(&pwrdm->lock);
- ? ? ? return ret;
-}
-
-
-
-/*

?* This API is to be called during init to set the various voltage ?* domains to the voltage as per the opp table. Typically we boot up ?* at the nominal voltage. So this function finds out the rate of

arch/arm/mach-omap2/pm.h +0 -1
index 7856489..5bc0848 100644
@@ -18,7 +18,6 @@
 ?extern void *omap3_secure_ram_storage;
 ?extern void omap3_pm_off_mode_enable(int);
 ?extern void omap_sram_idle(void);
-extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 ?extern int omap3_idle_init(void);
 ?extern int omap4_idle_init(void);
 ?extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
arch/arm/mach-omap2/powerdomain-common.c +71 -0
index c0aeabf..2973be7 100644
@@ -108,3 +108,74 @@ u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank)
 ? ? ? ?return 0;
 ?}
 
+/**
+ * omap2_pwrdm_func_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @func_pwrst: functional power state
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
+{
+ ? ? ? int ret;
+
+ ? ? ? switch (func_pwrst) {
+ ? ? ? case PWRDM_FUNC_PWRST_ON:
+ ? ? ? ? ? ? ? ret = PWRDM_POWER_ON;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case PWRDM_FUNC_PWRST_INACTIVE:
+ ? ? ? ? ? ? ? ret = PWRDM_POWER_INACTIVE;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case PWRDM_FUNC_PWRST_CSWR:
+ ? ? ? case PWRDM_FUNC_PWRST_OSWR:
+ ? ? ? ? ? ? ? ret = PWRDM_POWER_RET;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case PWRDM_FUNC_PWRST_OFF:
+ ? ? ? ? ? ? ? ret = PWRDM_POWER_OFF;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? ret = -EINVAL;
+ ? ? ? }
+
+ ? ? ? return ret;
+}
+
+/**
+ * omap2_pwrdm_pwrst_to_func - Convert internal (i.e. registers) to
+ * functional (i.e. logical) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @pwrst: internal power state
+ *
+ * Returns the functional power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)
+{
+ ? ? ? int ret;
+
+ ? ? ? switch (pwrst) {
+ ? ? ? case PWRDM_POWER_ON:
+ ? ? ? ? ? ? ? ret = PWRDM_FUNC_PWRST_ON;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case PWRDM_POWER_INACTIVE:
+ ? ? ? ? ? ? ? ret = PWRDM_FUNC_PWRST_INACTIVE;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case PWRDM_POWER_RET:
+ ? ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ? ?* XXX warning: return OSWR in case of pd in RET and
+ ? ? ? ? ? ? ? ?* logic in OFF
+ ? ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? ? ret = PWRDM_FUNC_PWRST_CSWR;
+ ? ? ? ? ? ? ? break;
+ ? ? ? case PWRDM_POWER_OFF:
+ ? ? ? ? ? ? ? ret = PWRDM_FUNC_PWRST_OFF;
+ ? ? ? ? ? ? ? break;
+ ? ? ? default:
+ ? ? ? ? ? ? ? ret = -EINVAL;
+ ? ? ? }
+
+ ? ? ? return ret;
+}
+
arch/arm/mach-omap2/powerdomain.c +0 -0
index 1641e72..e79b5ae 100644
@@ -466,6 +466,135 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
 ?}
 

?/**
+ * pwrdm_func_to_pwrst - get the internal (i.e. registers) value mapped
+ * to the functional state
+ * @pwrdm: struct powerdomain * to query
+ * @func_pwrst: functional power state
+ *
+ * Convert the functional power state to the platform specific power
+ * domain state value.
+ * Returns the internal power domain state value or -EINVAL in case
+ * of invalid parameters passed in.
+ */

arch/arm/mach-omap2/powerdomain.c +119 -0
+int pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
+{
+ ? ? ? int ret = func_pwrst;
+
+ ? ? ? if ((!pwrdm) || (func_pwrst >= PWRDM_MAX_FUNC_PWRSTS))
+ ? ? ? ? ? ? ? return -EINVAL;
+
+ ? ? ? if (arch_pwrdm && arch_pwrdm->pwrdm_func_to_pwrst)
+ ? ? ? ? ? ? ? ret = arch_pwrdm->pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+
+ ? ? ? pr_debug("powerdomain: convert func %0x to pwrst %0x for %s\n",
+ ? ? ? ? ? ? ? ?func_pwrst, ret, pwrdm->name);
+
+ ? ? ? return ret;
+}
+
+/**
+ * pwrdm_pwrst_to_func - get the functional (i.e. logical) value mapped
+ * to the internal state
+ * @pwrdm: struct powerdomain * to query
+ * @pwrst: internal power state
+ *
+ * Convert the internal power state to the power domain functional value.
+ * Returns the functional power domain state value or -EINVAL in case
+ * of invalid parameters passed in.
+ */
+int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)
+{
+ ? ? ? int ret = pwrst;
+
+ ? ? ? if ((!pwrdm) || (pwrst >= PWRDM_MAX_PWRSTS))
+ ? ? ? ? ? ? ? return -EINVAL;
+
+ ? ? ? pr_debug("powerdomain: convert %0x pwrst to func for %s\n",
+ ? ? ? ? ? ? ? ?pwrst, pwrdm->name);
+
+ ? ? ? if (arch_pwrdm && arch_pwrdm->pwrdm_pwrst_to_func)
+ ? ? ? ? ? ? ? ret = arch_pwrdm->pwrdm_pwrst_to_func(pwrdm, pwrst);
+
+ ? ? ? return ret;
+}
+
+/* Types of sleep_switch used in omap_set_pwrdm_state */
+#define FORCEWAKEUP_SWITCH ? ? 0
+#define LOWPOWERSTATE_SWITCH ? 1
+
+/**
+ * omap_set_pwrdm_state - program next powerdomain power state
+ * @pwrdm: struct powerdomain * to set
+ * @func_pwrst: power domain functional state, one of the PWRDM_FUNC_* macros
+ *
+ * This programs the pwrdm next functional state, sets the dependencies
+ * and waits for the state to be applied.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm,
+ ? ? ? ? ? ? ? ? ? ? ? ?enum pwrdm_func_state func_pwrst)
+{
+ ? ? ? u8 curr_pwrst, next_pwrst;
+ ? ? ? int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+ ? ? ? int sleep_switch = -1, ret = 0, hwsup = 0;
+
+ ? ? ? if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0)) {
+ ? ? ? ? ? ? ? pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
+ ? ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm, func_pwrst);
+ ? ? ? ? ? ? ? return -EINVAL;
+ ? ? ? }
+
+ ? ? ? pr_debug("%s: set func_pwrst %0x to pwrdm %s\n",
+ ? ? ? ? ? ? ? ?__func__, func_pwrst, pwrdm->name);
+
+ ? ? ? mutex_lock(&pwrdm->lock);
+
+ ? ? ? while (!(pwrdm->pwrsts & (1 << pwrst))) {
+ ? ? ? ? ? ? ? if (pwrst == PWRDM_POWER_OFF)
+ ? ? ? ? ? ? ? ? ? ? ? goto out;
+ ? ? ? ? ? ? ? pwrst--;
+ ? ? ? }
+
+ ? ? ? next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+ ? ? ? if (next_pwrst == pwrst)
+ ? ? ? ? ? ? ? goto out;
+
+ ? ? ? curr_pwrst = pwrdm_read_pwrst(pwrdm);
+ ? ? ? if (curr_pwrst < PWRDM_POWER_ON) {
+ ? ? ? ? ? ? ? if ((curr_pwrst > pwrst) &&
+ ? ? ? ? ? ? ? ? ? ? ? (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
+ ? ? ? ? ? ? ? ? ? ? ? sleep_switch = LOWPOWERSTATE_SWITCH;
+ ? ? ? ? ? ? ? } else {
+ ? ? ? ? ? ? ? ? ? ? ? hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
+ ? ? ? ? ? ? ? ? ? ? ? clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+ ? ? ? ? ? ? ? ? ? ? ? sleep_switch = FORCEWAKEUP_SWITCH;
+ ? ? ? ? ? ? ? }
+ ? ? ? }
+
+ ? ? ? ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+ ? ? ? if (ret)
+ ? ? ? ? ? ? ? pr_err("%s: unable to set power state of powerdomain: %s\n",
+ ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm->name);
+
+ ? ? ? switch (sleep_switch) {
+ ? ? ? case FORCEWAKEUP_SWITCH:
+ ? ? ? ? ? ? ? if (hwsup)
+ ? ? ? ? ? ? ? ? ? ? ? clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+ ? ? ? ? ? ? ? else
+ ? ? ? ? ? ? ? ? ? ? ? clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
+ ? ? ? ? ? ? ? break;
+ ? ? ? case LOWPOWERSTATE_SWITCH:
+ ? ? ? ? ? ? ? pwrdm_set_lowpwrstchange(pwrdm);
+ ? ? ? ? ? ? ? pwrdm_wait_transition(pwrdm);
+ ? ? ? ? ? ? ? pwrdm_state_switch(pwrdm);
+ ? ? ? ? ? ? ? break;
+ ? ? ? }
+
+out:
+ ? ? ? mutex_unlock(&pwrdm->lock);
+ ? ? ? return ret;
+}
+
+/**

?* pwrdm_set_next_pwrst - set next powerdomain power state ?* @pwrdm: struct powerdomain * to set
?* @pwrst: one of the PWRDM_POWER_* macros

arch/arm/mach-omap2/powerdomain.c +0 -0
@@ -522,6 +651,21 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 ?}
 

?/**
+ * pwrdm_read_next_func_pwrst - get next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the next power state upon success.
+ */

arch/arm/mach-omap2/powerdomain.c +8 -0
+int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)
+{
+ ? ? ? int ret = pwrdm_read_next_pwrst(pwrdm);
+
+ ? ? ? return pwrdm_pwrst_to_func(pwrdm, ret);
+}
+
+/**

?* pwrdm_read_pwrst - get current powerdomain power state ?* @pwrdm: struct powerdomain * to get power state ?*

arch/arm/mach-omap2/powerdomain.c +0 -0
@@ -543,6 +687,21 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 ?}
 

?/**
+ * pwrdm_read_func_pwrst - get current powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's current functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the current power state upon success.
+ */

arch/arm/mach-omap2/powerdomain.c +8 -0
+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm)
+{
+ ? ? ? int ret = pwrdm_read_pwrst(pwrdm);
+
+ ? ? ? return pwrdm_pwrst_to_func(pwrdm, ret);
+}
+
+/**

?* pwrdm_read_prev_pwrst - get previous powerdomain power state ?* @pwrdm: struct powerdomain * to get previous power state ?*

arch/arm/mach-omap2/powerdomain.c +0 -0
@@ -564,6 +723,21 @@ int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 ?}
 

?/**
+ * pwrdm_read_prev_func_pwrst - get previous powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous power state upon success.
+ */

arch/arm/mach-omap2/powerdomain.c +8 -0
+int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm)
+{
+ ? ? ? int ret = pwrdm_read_prev_pwrst(pwrdm);
+
+ ? ? ? return pwrdm_pwrst_to_func(pwrdm, ret);
+}
+
+/**

?* pwrdm_set_logic_retst - set powerdomain logic power state upon retention ?* @pwrdm: struct powerdomain * to set
?* @pwrst: one of the PWRDM_POWER_* macros

arch/arm/mach-omap2/powerdomain.h +0 -0
index bab84fc..0404f9f 100644
@@ -9,9 +9,6 @@

?* This program is free software; you can redistribute it and/or modify ?* it under the terms of the GNU General Public License version 2 as ?* published by the Free Software Foundation.
- *
- * XXX This should be moved to the mach-omap2/ directory at the earliest
- * opportunity.
?*/

?#ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H

arch/arm/mach-omap2/powerdomain.h +0 -0
@@ -26,7 +23,51 @@
 

?#include "voltage.h"

arch/arm/mach-omap2/powerdomain.h +3 -1
-/* Powerdomain basic power states */
+/***************************************************************
+ * External API
+ ***************************************************************/

arch/arm/mach-omap2/powerdomain.h line 38

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.h +10 -0
+
+/* Powerdomain functional power states, used by the external API functions */
+enum pwrdm_func_state {
+ ? ? ? PWRDM_FUNC_PWRST_OFF ? ? ? ? ? ?= 0x0,
+ ? ? ? PWRDM_FUNC_PWRST_OSWR,
+ ? ? ? PWRDM_FUNC_PWRST_CSWR,
+ ? ? ? PWRDM_FUNC_PWRST_INACTIVE,
+ ? ? ? PWRDM_FUNC_PWRST_ON,
+ ? ? ? PWRDM_MAX_FUNC_PWRSTS ? ? ? ? ? /* Last value, used as the max value */
+};

"
There could be potential driver issues using wrong values etc. To be on a safe side, those could probably define as:
/* Powerdomain functional power states, used by the external API functions */ #define PWRDM_FUNC_PWRST_OFF 0x10
#define PWRDM_FUNC_PWRST_OSWR 0x11
#define PWRDM_FUNC_PWRST_CSWR 0x12
#define PWRDM_FUNC_PWRST_INACTIVE 0x13
#define PWRDM_FUNC_PWRST_ON 0x14
This should expose any wrong handling in code and any cross assumptions It is highly critical to ensure that PWRDM_FUNC is different from PWRDM_POWER
"
The argument is valid regarding the API definition (internal vs external) and its usage.
The possible options are described in the thread at
http://marc.info/?l=linux-omap&m=133975893730191&w=2

Any feedback is appreciated.

Regards,
Jean

Quoted 163 lines
arch/arm/mach-omap2/powerdomain.h +32 -0
+
+struct clockdomain;
+struct powerdomain;
+
+struct powerdomain *pwrdm_lookup(const char *name);
+
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+ ? ? ? ? ? ? ? ? ? ? ? void *user);
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+ ? ? ? ? ? ? ? ? ? ? ? void *user);
+
+struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
+
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
+
+int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? enum pwrdm_func_state func_pwrst);
+
+extern void omap242x_powerdomains_init(void);
+extern void omap243x_powerdomains_init(void);
+extern void omap3xxx_powerdomains_init(void);
+extern void omap44xx_powerdomains_init(void);
+
+
+/***************************************************************
+ * Internal code, only used in powerdomain*.[ch]
+ ***************************************************************/
+
+/* Powerdomain internal power states, internal use only */

?#define PWRDM_POWER_OFF ? ? ? ? ? ? ? ?0x0
?#define PWRDM_POWER_RET ? ? ? ? ? ? ? ?0x1
?#define PWRDM_POWER_INACTIVE ? 0x2

arch/arm/mach-omap2/powerdomain.h +0 -1
@@ -45,7 +86,6 @@
 ?#define PWRSTS_RET_ON ? ? ? ? ?(PWRSTS_RET | PWRSTS_ON)
 ?#define PWRSTS_OFF_RET_ON ? ? ?(PWRSTS_OFF_RET | PWRSTS_ON)
 
-

?/* Powerdomain flags */
?#define PWRDM_HAS_HDWR_SAR ? ? (1 << 0) /* hardware save-and-restore support */ ?#define PWRDM_HAS_MPU_QUIRK ? ?(1 << 1) /* MPU pwr domain has MEM bank 0 bits

arch/arm/mach-omap2/powerdomain.h +0 -0
@@ -74,9 +114,6 @@

?/* XXX A completely arbitrary number. What is reasonable here? */ ?#define PWRDM_TRANSITION_BAILOUT 100000

arch/arm/mach-omap2/powerdomain.h +0 -3
-struct clockdomain;
-struct powerdomain;
-

?/**
?* struct powerdomain - OMAP powerdomain
?* @name: Powerdomain name

arch/arm/mach-omap2/powerdomain.h +0 -0
@@ -130,6 +167,10 @@ struct powerdomain {
 

?/**
?* struct pwrdm_ops - Arch specific function implementations
+ * @pwrdm_func_to_pwrst: Convert the pd functional power state to
+ * ?the internal state
+ * @pwrdm_pwrst_to_func: Convert the pd internal power state to
+ * ?the functional state
?* @pwrdm_set_next_pwrst: Set the target power state for a pd ?* @pwrdm_read_next_pwrst: Read the target power state set for a pd ?* @pwrdm_read_pwrst: Read the current power state of a pd

arch/arm/mach-omap2/powerdomain.h +0 -0
@@ -150,6 +191,8 @@ struct powerdomain {

?* @pwrdm_wait_transition: Wait for a pd state transition to complete ?*/
?struct pwrdm_ops {
+ ? ? ? int ? ? (*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);
+ ? ? ? int ? ? (*pwrdm_pwrst_to_func)(struct powerdomain *pwrdm, u8 func_pwrst); ? ? ? ?int ? ? (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); ? ? ? ?int ? ? (*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm); ? ? ? ?int ? ? (*pwrdm_read_pwrst)(struct powerdomain *pwrdm);

arch/arm/mach-omap2/powerdomain.h +3 -15
@@ -174,21 +217,11 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
 ?int pwrdm_register_pwrdms(struct powerdomain **pwrdm_list);
 ?int pwrdm_complete_init(void);
 
-struct powerdomain *pwrdm_lookup(const char *name);
-
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
- ? ? ? ? ? ? ? ? ? ? ? void *user);
-int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
- ? ? ? ? ? ? ? ? ? ? ? void *user);
-
 ?int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 ?int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 ?int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
 ? ? ? ? ? ? ? ? ? ? ? ? int (*fn)(struct powerdomain *pwrdm,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clockdomain *clkdm));
-struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
-
-int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
 
 ?int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
 ?int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
@@ -196,6 +229,9 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm);
 ?int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
 ?int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 
+int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst);
+
 ?int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
 ?int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
 ?int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
@@ -220,11 +256,6 @@ int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
 ?int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
 ?bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
 
-extern void omap242x_powerdomains_init(void);
-extern void omap243x_powerdomains_init(void);
-extern void omap3xxx_powerdomains_init(void);
-extern void omap44xx_powerdomains_init(void);
-
 ?extern struct pwrdm_ops omap2_pwrdm_operations;
 ?extern struct pwrdm_ops omap3_pwrdm_operations;
 ?extern struct pwrdm_ops omap4_pwrdm_operations;
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +0 -0
index 0f0a9f1..79c1293 100644
@@ -26,6 +26,7 @@
 
 

?/* Common functions across OMAP2 and OMAP3 */
+
?static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) ?{
? ? ? ?omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,

arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +4 -0
@@ -210,6 +211,8 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 ?}
 
 ?struct pwrdm_ops omap2_pwrdm_operations = {
+ ? ? ? .pwrdm_func_to_pwrst ? ?= omap2_pwrdm_func_to_pwrst,
+ ? ? ? .pwrdm_pwrst_to_func ? ?= omap2_pwrdm_pwrst_to_func,
 ? ? ? ?.pwrdm_set_next_pwrst ? = omap2_pwrdm_set_next_pwrst,
 ? ? ? ?.pwrdm_read_next_pwrst ?= omap2_pwrdm_read_next_pwrst,
 ? ? ? ?.pwrdm_read_pwrst ? ? ? = omap2_pwrdm_read_pwrst,
@@ -222,6 +225,8 @@ struct pwrdm_ops omap2_pwrdm_operations = {
 ?};
 
 ?struct pwrdm_ops omap3_pwrdm_operations = {
+ ? ? ? .pwrdm_func_to_pwrst ? ?= omap2_pwrdm_func_to_pwrst,
+ ? ? ? .pwrdm_pwrst_to_func ? ?= omap2_pwrdm_pwrst_to_func,
 ? ? ? ?.pwrdm_set_next_pwrst ? = omap2_pwrdm_set_next_pwrst,
 ? ? ? ?.pwrdm_read_next_pwrst ?= omap2_pwrdm_read_next_pwrst,
 ? ? ? ?.pwrdm_read_pwrst ? ? ? = omap2_pwrdm_read_pwrst,
arch/arm/mach-omap2/powerdomain44xx.c +2 -1
index 601325b..538b528 100644
@@ -209,6 +209,8 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 ?}
 
 ?struct pwrdm_ops omap4_pwrdm_operations = {
+ ? ? ? .pwrdm_func_to_pwrst ? ?= omap2_pwrdm_func_to_pwrst,
+ ? ? ? .pwrdm_pwrst_to_func ? ?= omap2_pwrdm_pwrst_to_func,
 ? ? ? ?.pwrdm_set_next_pwrst ? = omap4_pwrdm_set_next_pwrst,
 ? ? ? ?.pwrdm_read_next_pwrst ?= omap4_pwrdm_read_next_pwrst,
 ? ? ? ?.pwrdm_read_pwrst ? ? ? = omap4_pwrdm_read_pwrst,
--

1.7.7.6

#5 lore raw

PATCH 2/8 ARM: OMAP2+: PM: introduce power domains functional states

In reply to Jean Pihet

On Thu, Jun 14, 2012 at 9:53 AM, Jean Pihet <[email protected]> wrote:
[..]

Quoted 6 lines
arch/arm/mach-omap2/powerdomain-common.c +0 -0
@@ -108,3 +108,74 @@ u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank)
        return 0;
 }
 

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 120

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+/**
+ * omap2_pwrdm_func_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @func_pwrst: functional power state
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)

Unless we handle logicpwst and pwst here, it makes it hard for non arch/arm/mach-omap2/powerdomain* files to use this properly.

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 133

Quoted 13 lines
arch/arm/mach-omap2/powerdomain-common.c +13 -0
+{
+       int ret;
+
+       switch (func_pwrst) {
+       case PWRDM_FUNC_PWRST_ON:
+               ret = PWRDM_POWER_ON;
+               break;
+       case PWRDM_FUNC_PWRST_INACTIVE:
+               ret = PWRDM_POWER_INACTIVE;
+               break;
+       case PWRDM_FUNC_PWRST_CSWR:
+       case PWRDM_FUNC_PWRST_OSWR:
+               ret = PWRDM_POWER_RET;

logic power state?

Quoted 11 lines
arch/arm/mach-omap2/powerdomain-common.c +11 -0
+               break;
+       case PWRDM_FUNC_PWRST_OFF:
+               ret = PWRDM_POWER_OFF;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 154

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+/**
+ * omap2_pwrdm_pwrst_to_func - Convert internal (i.e. registers) to
+ * functional (i.e. logical) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @pwrst: internal power state
+ *
+ * Returns the functional power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)

Same here as well..

Quoted 5 lines
arch/arm/mach-omap2/powerdomain-common.c +5 -0
+{
+       int ret;
+
+       switch (pwrst) {
+       case PWRDM_POWER_ON:

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 169

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+               ret = PWRDM_FUNC_PWRST_ON;
+               break;
+       case PWRDM_POWER_INACTIVE:
+               ret = PWRDM_FUNC_PWRST_INACTIVE;
+               break;
+       case PWRDM_POWER_RET:
+               /*
+                * XXX warning: return OSWR in case of pd in RET and
+                * logic in OFF
+                */

We need to be able to pass in logic pwst to be able to make that determination.

Quoted 21 lines
arch/arm/mach-omap2/powerdomain-common.c +12 -0
+               ret = PWRDM_FUNC_PWRST_CSWR;
+               break;
+       case PWRDM_POWER_OFF:
+               ret = PWRDM_FUNC_PWRST_OFF;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
arch/arm/mach-omap2/powerdomain.c +1 -0
index 1641e72..e79b5ae 100644
@@ -466,6 +466,135 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
 }
 
 /**
+ * pwrdm_func_to_pwrst - get the internal (i.e. registers) value mapped

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 479

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+ * to the functional state
+ * @pwrdm: struct powerdomain * to query
+ * @func_pwrst: functional power state
+ *
+ * Convert the functional power state to the platform specific power
+ * domain state value.
+ * Returns the internal power domain state value or -EINVAL in case
+ * of invalid parameters passed in.
+ */
+int pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)

should take enum pwrdm_func_state func_pwrst

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 487

Quoted 8 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
+{
+       int ret = func_pwrst;
+
+       if ((!pwrdm) || (func_pwrst >= PWRDM_MAX_FUNC_PWRSTS))
+               return -EINVAL;
+
+       if (arch_pwrdm && arch_pwrdm->pwrdm_func_to_pwrst)
+               ret = arch_pwrdm->pwrdm_func_to_pwrst(pwrdm, func_pwrst);

Should we not return an error if the function pointer is not available for the arch?
on platforms without func_pwrst pointer converter routing hooked on, we return func_pwrst back to caller, which expects pwrst!

Quoted 8 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
+
+       pr_debug("powerdomain: convert func %0x to pwrst %0x for %s\n",
+                func_pwrst, ret, pwrdm->name);
+
+       return ret;
+}
+
+/**

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 505

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+ * pwrdm_pwrst_to_func - get the functional (i.e. logical) value mapped
+ * to the internal state
+ * @pwrdm: struct powerdomain * to query
+ * @pwrst: internal power state
+ *
+ * Convert the internal power state to the power domain functional value.
+ * Returns the functional power domain state value or -EINVAL in case
+ * of invalid parameters passed in.
+ */
+int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)

should return enum pwrdm_func_state

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 516

Quoted 11 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
+{
+       int ret = pwrst;
+
+       if ((!pwrdm) || (pwrst >= PWRDM_MAX_PWRSTS))
+               return -EINVAL;
+
+       pr_debug("powerdomain: convert %0x pwrst to func for %s\n",
+                pwrst, pwrdm->name);
+
+       if (arch_pwrdm && arch_pwrdm->pwrdm_pwrst_to_func)
+               ret = arch_pwrdm->pwrdm_pwrst_to_func(pwrdm, pwrst);

same in reverse here.

Quoted 23 lines
arch/arm/mach-omap2/powerdomain.c +23 -0
+
+       return ret;
+}
+
+/* Types of sleep_switch used in omap_set_pwrdm_state */
+#define FORCEWAKEUP_SWITCH     0
+#define LOWPOWERSTATE_SWITCH   1
+
+/**
+ * omap_set_pwrdm_state - program next powerdomain power state
+ * @pwrdm: struct powerdomain * to set
+ * @func_pwrst: power domain functional state, one of the PWRDM_FUNC_* macros
+ *
+ * This programs the pwrdm next functional state, sets the dependencies
+ * and waits for the state to be applied.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm,
+                        enum pwrdm_func_state func_pwrst)
+{
+       u8 curr_pwrst, next_pwrst;
+       int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+       int sleep_switch = -1, ret = 0, hwsup = 0;
+

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 549

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+       if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0)) {
+               pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
+                        __func__, pwrdm, func_pwrst);
+               return -EINVAL;
+       }
+
+       pr_debug("%s: set func_pwrst %0x to pwrdm %s\n",
+                __func__, func_pwrst, pwrdm->name);
+
+       mutex_lock(&pwrdm->lock);

This should be a spinlock (previous patch i believe) - hurts cpuidle otherwise.

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 556

Quoted 7 lines
arch/arm/mach-omap2/powerdomain.c +7 -0
+
+       while (!(pwrdm->pwrsts & (1 << pwrst))) {
+               if (pwrst == PWRDM_POWER_OFF)
+                       goto out;
+               pwrst--;
+       }
+

if we like to handle a single API for OSWR and CSWR, then it needs to handle logic power state as well here.

Quoted 46 lines
arch/arm/mach-omap2/powerdomain.c +41 -0
+       next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+       if (next_pwrst == pwrst)
+               goto out;
+
+       curr_pwrst = pwrdm_read_pwrst(pwrdm);
+       if (curr_pwrst < PWRDM_POWER_ON) {
+               if ((curr_pwrst > pwrst) &&
+                       (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
+                       sleep_switch = LOWPOWERSTATE_SWITCH;
+               } else {
+                       hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
+                       clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+                       sleep_switch = FORCEWAKEUP_SWITCH;
+               }
+       }
+
+       ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+       if (ret)
+               pr_err("%s: unable to set power state of powerdomain: %s\n",
+                      __func__, pwrdm->name);
+
+       switch (sleep_switch) {
+       case FORCEWAKEUP_SWITCH:
+               if (hwsup)
+                       clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+               else
+                       clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
+               break;
+       case LOWPOWERSTATE_SWITCH:
+               pwrdm_set_lowpwrstchange(pwrdm);
+               pwrdm_wait_transition(pwrdm);
+               pwrdm_state_switch(pwrdm);
+               break;
+       }
+
+out:
+       mutex_unlock(&pwrdm->lock);
+       return ret;
+}
+
+/**
  * pwrdm_set_next_pwrst - set next powerdomain power state
  * @pwrdm: struct powerdomain * to set
  * @pwrst: one of the PWRDM_POWER_* macros
@@ -522,6 +651,21 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 }

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) · line 661

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
 
 /**
+ * pwrdm_read_next_func_pwrst - get next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the next power state upon success.
+ */
+int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +7 -0
+{
+       int ret = pwrdm_read_next_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}
+
+/**
  * pwrdm_read_pwrst - get current powerdomain power state
  * @pwrdm: struct powerdomain * to get power state
  *
@@ -543,6 +687,21 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 }

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_pwrst(struct powerdomain *pwrdm) · line 697

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
 
 /**
+ * pwrdm_read_func_pwrst - get current powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's current functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the current power state upon success.
+ */
+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_pwrst(struct powerdomain *pwrdm) · line 702

Quoted 5 lines
arch/arm/mach-omap2/powerdomain.c +5 -0
+{
+       int ret = pwrdm_read_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}

my Crib about the above apis are lack of logic power state handling :( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

Quoted 7 lines
arch/arm/mach-omap2/powerdomain.c +2 -0
+
+/**
  * pwrdm_read_prev_pwrst - get previous powerdomain power state
  * @pwrdm: struct powerdomain * to get previous power state
  *
@@ -564,6 +723,21 @@ int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 }

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) · line 733

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
 
 /**
+ * pwrdm_read_prev_func_pwrst - get previous powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous power state upon success.
+ */
+int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) · line 738

Quoted 5 lines
arch/arm/mach-omap2/powerdomain.c +5 -0
+{
+       int ret = pwrdm_read_prev_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}

again here.

Quoted 54 lines
arch/arm/mach-omap2/powerdomain.c +2 -0
+
+/**
  * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
  * @pwrdm: struct powerdomain * to set
  * @pwrst: one of the PWRDM_POWER_* macros
arch/arm/mach-omap2/powerdomain.h +30 -4
index bab84fc..0404f9f 100644
@@ -9,9 +9,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * XXX This should be moved to the mach-omap2/ directory at the earliest
- * opportunity.
  */
 
 #ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H
@@ -26,7 +23,51 @@
 
 #include "voltage.h"
 
-/* Powerdomain basic power states */
+/***************************************************************
+ * External API
+ ***************************************************************/
+
+/* Powerdomain functional power states, used by the external API functions */
+enum pwrdm_func_state {
+       PWRDM_FUNC_PWRST_OFF            = 0x0,
+       PWRDM_FUNC_PWRST_OSWR,
+       PWRDM_FUNC_PWRST_CSWR,
+       PWRDM_FUNC_PWRST_INACTIVE,
+       PWRDM_FUNC_PWRST_ON,
+       PWRDM_MAX_FUNC_PWRSTS           /* Last value, used as the max value */
+};
+
+struct clockdomain;
+struct powerdomain;
+
+struct powerdomain *pwrdm_lookup(const char *name);
+
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+                       void *user);
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+                       void *user);
+
+struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
+
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
+
+int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm);

arch/arm/mach-omap2/powerdomain.h line 65

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.h +10 -0
+int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm,
+                               enum pwrdm_func_state func_pwrst);
+
+extern void omap242x_powerdomains_init(void);
+extern void omap243x_powerdomains_init(void);
+extern void omap3xxx_powerdomains_init(void);
+extern void omap44xx_powerdomains_init(void);
+
+

We should split the following out to a separate header which is not to be used by anyone else other than powerdomain*.[ch]

Quoted 38 lines
arch/arm/mach-omap2/powerdomain.h +9 -4
+/***************************************************************
+ * Internal code, only used in powerdomain*.[ch]
+ ***************************************************************/
+
+/* Powerdomain internal power states, internal use only */
 #define PWRDM_POWER_OFF                0x0
 #define PWRDM_POWER_RET                0x1
 #define PWRDM_POWER_INACTIVE   0x2
@@ -45,7 +86,6 @@
 #define PWRSTS_RET_ON          (PWRSTS_RET | PWRSTS_ON)
 #define PWRSTS_OFF_RET_ON      (PWRSTS_OFF_RET | PWRSTS_ON)
 
-
 /* Powerdomain flags */
 #define PWRDM_HAS_HDWR_SAR     (1 << 0) /* hardware save-and-restore support */
 #define PWRDM_HAS_MPU_QUIRK    (1 << 1) /* MPU pwr domain has MEM bank 0 bits
@@ -74,9 +114,6 @@
 /* XXX A completely arbitrary number. What is reasonable here? */
 #define PWRDM_TRANSITION_BAILOUT 100000
 
-struct clockdomain;
-struct powerdomain;
-
 /**
  * struct powerdomain - OMAP powerdomain
  * @name: Powerdomain name
@@ -130,6 +167,10 @@ struct powerdomain {
 
 /**
  * struct pwrdm_ops - Arch specific function implementations
+ * @pwrdm_func_to_pwrst: Convert the pd functional power state to
+ *  the internal state
+ * @pwrdm_pwrst_to_func: Convert the pd internal power state to
+ *  the functional state
  * @pwrdm_set_next_pwrst: Set the target power state for a pd
  * @pwrdm_read_next_pwrst: Read the target power state set for a pd
  * @pwrdm_read_pwrst: Read the current power state of a pd

arch/arm/mach-omap2/powerdomain.h struct powerdomain { · line 194

Quoted 4 lines
arch/arm/mach-omap2/powerdomain.h +1 -0
@@ -150,6 +191,8 @@ struct powerdomain {
  * @pwrdm_wait_transition: Wait for a pd state transition to complete
  */
 struct pwrdm_ops {
+       int     (*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);

should take in enum pwrdm_func_state

arch/arm/mach-omap2/powerdomain.h struct powerdomain { · line 195

Quoted 1 line
arch/arm/mach-omap2/powerdomain.h +1 -0
+       int     (*pwrdm_pwrst_to_func)(struct powerdomain *pwrdm, u8 func_pwrst);

should return enum pwrdm_func_state

Quoted 82 lines
arch/arm/mach-omap2/powerdomain.h +3 -15
        int     (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst);
        int     (*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm);
        int     (*pwrdm_read_pwrst)(struct powerdomain *pwrdm);
@@ -174,21 +217,11 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
 int pwrdm_register_pwrdms(struct powerdomain **pwrdm_list);
 int pwrdm_complete_init(void);
 
-struct powerdomain *pwrdm_lookup(const char *name);
-
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
-                       void *user);
-int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
-                       void *user);
-
 int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
                         int (*fn)(struct powerdomain *pwrdm,
                                   struct clockdomain *clkdm));
-struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
-
-int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
 
 int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
@@ -196,6 +229,9 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
 int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 
+int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst);
+
 int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
 int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
@@ -220,11 +256,6 @@ int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
 int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
 bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
 
-extern void omap242x_powerdomains_init(void);
-extern void omap243x_powerdomains_init(void);
-extern void omap3xxx_powerdomains_init(void);
-extern void omap44xx_powerdomains_init(void);
-
 extern struct pwrdm_ops omap2_pwrdm_operations;
 extern struct pwrdm_ops omap3_pwrdm_operations;
 extern struct pwrdm_ops omap4_pwrdm_operations;
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +5 -0
index 0f0a9f1..79c1293 100644
@@ -26,6 +26,7 @@
 
 
 /* Common functions across OMAP2 and OMAP3 */
+
 static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 {
        omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
@@ -210,6 +211,8 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap2_pwrdm_operations = {
+       .pwrdm_func_to_pwrst    = omap2_pwrdm_func_to_pwrst,
+       .pwrdm_pwrst_to_func    = omap2_pwrdm_pwrst_to_func,
        .pwrdm_set_next_pwrst   = omap2_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap2_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst       = omap2_pwrdm_read_pwrst,
@@ -222,6 +225,8 @@ struct pwrdm_ops omap2_pwrdm_operations = {
 };
 
 struct pwrdm_ops omap3_pwrdm_operations = {
+       .pwrdm_func_to_pwrst    = omap2_pwrdm_func_to_pwrst,
+       .pwrdm_pwrst_to_func    = omap2_pwrdm_pwrst_to_func,
        .pwrdm_set_next_pwrst   = omap2_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap2_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst       = omap2_pwrdm_read_pwrst,
arch/arm/mach-omap2/powerdomain44xx.c +0 -0
index 601325b..538b528 100644

arch/arm/mach-omap2/powerdomain44xx.c static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) · line 216

Quoted 8 lines
arch/arm/mach-omap2/powerdomain44xx.c +2 -0
@@ -209,6 +209,8 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap4_pwrdm_operations = {
+       .pwrdm_func_to_pwrst    = omap2_pwrdm_func_to_pwrst,
+       .pwrdm_pwrst_to_func    = omap2_pwrdm_pwrst_to_func,
        .pwrdm_set_next_pwrst   = omap4_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap4_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst       = omap4_pwrdm_read_pwrst,

otherwise, this is a nice concept
--
Regards,
Nishanth Menon

#6 lore raw

PATCH 2/8 ARM: OMAP2+: PM: introduce power domains functional states

Quoted 14 lines · Nishanth

On Thu, Jun 14, 2012 at 9:53 AM, Jean Pihet <[email protected]> wrote:
[..]

Quoted 1 line

+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

Review

Quoted 5 lines
(quoted diff) +5 -0
+{
+       int ret = pwrdm_read_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}

my Crib about the above apis are lack of logic power state handling :( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

[..]

Quoted 9 lines

Review

Quoted 6 lines
(quoted diff) +6 -0
+extern void omap242x_powerdomains_init(void);
+extern void omap243x_powerdomains_init(void);
+extern void omap3xxx_powerdomains_init(void);
+extern void omap44xx_powerdomains_init(void);
+
+

We should split the following out to a separate header which is not to be used by anyone else other than powerdomain*.[ch]

without doing this..
[..]

Quoted 7 lines
Quoted 3 lines

*/
struct pwrdm_ops {
+ int (*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);

should take in enum pwrdm_func_state

Quoted 1 line

+ int (*pwrdm_pwrst_to_func)(struct powerdomain *pwrdm, u8 func_pwrst);

should return enum pwrdm_func_state

[...]

Quoted 1 line

otherwise, this is a nice concept

Here is how it might look like: (baseline internal tree)

arch/arm/mach-omap2/pm.c +0 -66
index c426dc4..30a4bb1 100644
@@ -129,10 +129,6 @@ static void __init omap2_init_processor_devices(void)
 	}
 }
 
-/* Types of sleep_switch used in omap_set_pwrdm_state */
-#define FORCEWAKEUP_SWITCH	0
-#define LOWPOWERSTATE_SWITCH	1
-
 int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
 {
 	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
@@ -144,68 +140,6 @@ int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
 }
 
 /*
- * This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported.
- */
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
-{
-	u8 curr_pwrst, next_pwrst;
-	int sleep_switch = -1, ret = 0, hwsup = 0;
-
-	if (!pwrdm || IS_ERR(pwrdm))
-		return -EINVAL;
-
-	spin_lock(&pwrdm->lock);
-
-	while (!(pwrdm->pwrsts & (1 << pwrst))) {
-		if (pwrst == PWRDM_POWER_OFF)
-			goto out;
-		pwrst--;
-	}
-
-	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
-	if (next_pwrst == pwrst)
-		goto out;
-
-	curr_pwrst = pwrdm_read_pwrst(pwrdm);
-	if (curr_pwrst < PWRDM_POWER_ON) {
-		if ((curr_pwrst > pwrst) &&
-			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
-			sleep_switch = LOWPOWERSTATE_SWITCH;
-		} else {
-			hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
-			clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
-			sleep_switch = FORCEWAKEUP_SWITCH;
-		}
-	}
-
-	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
-	if (ret)
-		pr_err("%s: unable to set power state of powerdomain: %s\n",
-		       __func__, pwrdm->name);
-
-	switch (sleep_switch) {
-	case FORCEWAKEUP_SWITCH:
-		if (hwsup)
-			clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
-		else
-			clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
-		break;
-	case LOWPOWERSTATE_SWITCH:
-		pwrdm_set_lowpwrstchange(pwrdm);
-		pwrdm_wait_transition(pwrdm);
-		pwrdm_state_switch(pwrdm);
-		break;
-	}
-
-out:
-	spin_unlock(&pwrdm->lock);
-	return ret;
-}
-
-
-
-/*
  * This API is to be called during init to set the various voltage
  * domains to the voltage as per the opp table. Typically we boot up
  * at the nominal voltage. So this function finds out the rate of
arch/arm/mach-omap2/pm.h +0 -1
index 2741a9b..5f255c5 100644
@@ -18,7 +18,6 @@
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
-extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 extern int omap4_idle_init(void);
 extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
arch/arm/mach-omap2/powerdomain-common.c +90 -0

93 lines not on this page · raw message

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

231 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.h +62 -22

137 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +5 -0
index 0f0a9f1..79c1293 100644
@@ -26,6 +26,7 @@
 
 
 /* Common functions across OMAP2 and OMAP3 */
+
 static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 {
 	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
@@ -210,6 +211,8 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap2_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
@@ -222,6 +225,8 @@ struct pwrdm_ops omap2_pwrdm_operations = {
 };
 
 struct pwrdm_ops omap3_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap2_pwrdm_read_pwrst,
arch/arm/mach-omap2/powerdomain4xxx_5xxx.c +4 -0
index e1e7d44..ad32f70 100644
@@ -229,6 +229,8 @@ static int omap5_pwrdm_disable_force_off(struct powerdomain *pwrdm)
 
 
 struct pwrdm_ops omap4_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap4_pwrdm_read_pwrst,
@@ -246,6 +248,8 @@ struct pwrdm_ops omap4_pwrdm_operations = {
 };
 
 struct pwrdm_ops omap5_pwrdm_operations = {
+	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
 	.pwrdm_read_pwrst	= omap4_pwrdm_read_pwrst,
Signature · 5 lines
1.7.9.5

-- 
Regards,
Nishanth Menon
#7 lore raw

PATCH 2/8 ARM: OMAP2+: PM: introduce power domains functional states

In reply to Menon, Nishanth
Quoted 3 lines · Nishanth

my Crib about the above apis are lack of logic power state handling:( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

Have you looked at an alternate approach that was proposed here..
https://patchwork.kernel.org/patch/1160431/

#8 lore raw

PATCH 2/8 ARM: OMAP2+: PM: introduce power domains functional states

Quoted 10 lines · Rajendra Nayak
Quoted 4 lines · Nishanth

my Crib about the above apis are lack of logic power state handling:( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

Have you looked at an alternate approach that was proposed here..
https://patchwork.kernel.org/patch/1160431/

Santosh pointed me to the thread offline. This is indeed a much better approach IMHO than having 3 conflicting options inside powerdomain framework.

Regards,
Nishanth Menon

author
#9 lore raw

PATCH v4 2/8 ARM: OMAP2+: PM: introduce power domains functional states

Hi!

Quoted 8 lines · Nishanth
Quoted 7 lines · Rajendra Nayak
Quoted 4 lines · Nishanth

my Crib about the above apis are lack of logic power state handling:( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

Quoted 6 lines
Quoted 3 lines

Have you looked at an alternate approach that was proposed here..
https://patchwork.kernel.org/patch/1160431/

Santosh pointed me to the thread offline. This is indeed a much better approach IMHO than having 3 conflicting options inside powerdomain framework.

After looking at the code and having sent my comments, I like it ... mainly because it is really similar to my proposal ;-p Can you elaborate more on 'having 3 conflicting options inside powerdomain framework'?

Here are the main differences in the implementation:
- the RFC code provides a _private header file, which forces the external users (cpuidle, pmXXXX.c etc.),
- the RFC code still uses the same function names while my code renames them to '*_func_*'. This makes the code look more complicated than it really is.

Quoted 2 lines

Regards,
Nishanth Menon

We are having a discussion on the best way to have the feature in. More to come!

Thanks!
Jean

#10 lore raw

PATCH 2/8 ARM: OMAP2+: PM: introduce power domains functional states

On Fri, Jul 13, 2012 at 2:18 AM, Jean Pihet <[email protected]> wrote:
[..]

Quoted 7 lines
Quoted 3 lines

Santosh pointed me to the thread offline. This is indeed a much better approach IMHO than having 3 conflicting options inside powerdomain framework.

After looking at the code and having sent my comments, I like it ... mainly because it is really similar to my proposal ;-p Can you elaborate more on 'having 3 conflicting options inside powerdomain framework'?

Current code has:
a) PWRDM_POWER_XYZ -> describe power state
b) PWRSTS_XYZ ->meant to describe supported states for each pwrdm

this patch introduces:
a) PWRDM_POWER_XYZ -> describe power state (only for powerdomain*.[ch])
b) PWRSTS_XYZ ->meant to describe supported states for each pwrdm
c) PWRDM_FUNC_XYZ -> for files other than powerdomain*.[ch]

https://patchwork.kernel.org/patch/1160431/
maintains
a) PWRDM_POWER_XYZ -> describe power state
b) PWRSTS_XYZ ->meant to describe supported states for each pwrdm

i) reduces code churn
ii) supports logic pwr handling within existing framework iii) no conflicting usage beyond known definition and usage. (though personally, I;d like to see PWRSTS_XYZ dissappear into private header..

Quoted 3 lines

Here are the main differences in the implementation:
- the RFC code provides a _private header file, which forces the external users (cpuidle, pmXXXX.c etc.),

That is one of the reasons I like it. I need to have a code which will be maintained beyond the original code creators - reduced ability to mess up the code by "not-well-informed" developers is paramount importance for me.

Quoted 3 lines

- the RFC code still uses the same function names while my code renames them to '*_func_*'. This makes the code look more complicated than it really is.

True. But, it paves the way to move all functions that is not intended to be used beyond powerdomain files to a private power domain header - which achieves the same objective without code churn.

Regards,
Nishanth Menon

author
#11 lore raw

PATCH v4 2/8 ARM: OMAP2+: PM: introduce power domains functional states

In reply to Menon, Nishanth

Hi Nishant,

Quoted 8 lines · Nishanth

On Thu, Jun 14, 2012 at 9:53 AM, Jean Pihet <[email protected]> wrote:
[..]

Quoted 6 lines
arch/arm/mach-omap2/powerdomain-common.c +0 -0
@@ -108,3 +108,74 @@ u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank)
        return 0;
 }
 
Quoted 13 lines

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 120

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+/**
+ * omap2_pwrdm_func_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @func_pwrst: functional power state
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)

Unless we handle logicpwst and pwst here, it makes it hard for non arch/arm/mach-omap2/powerdomain* files to use this properly.

The logic and mem states support is coming in another patch in the series. I think I should merge the patches together since I got the same remarks a few times already

Quoted 75 lines
Quoted 4 lines
arch/arm/mach-omap2/powerdomain-common.c +3 -0
+{
+       int ret;
+

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 133

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+       switch (func_pwrst) {
+       case PWRDM_FUNC_PWRST_ON:
+               ret = PWRDM_POWER_ON;
+               break;
+       case PWRDM_FUNC_PWRST_INACTIVE:
+               ret = PWRDM_POWER_INACTIVE;
+               break;
+       case PWRDM_FUNC_PWRST_CSWR:
+       case PWRDM_FUNC_PWRST_OSWR:
+               ret = PWRDM_POWER_RET;

logic power state?

Quoted 11 lines
arch/arm/mach-omap2/powerdomain-common.c +11 -0
+               break;
+       case PWRDM_FUNC_PWRST_OFF:
+               ret = PWRDM_POWER_OFF;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 154

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+/**
+ * omap2_pwrdm_pwrst_to_func - Convert internal (i.e. registers) to
+ * functional (i.e. logical) values for the power domains states.
+ * @struct powerdomain * to convert the values for
+ * @pwrst: internal power state
+ *
+ * Returns the functional power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)

Same here as well..

Quoted 5 lines
arch/arm/mach-omap2/powerdomain-common.c +5 -0
+{
+       int ret;
+
+       switch (pwrst) {
+       case PWRDM_POWER_ON:

arch/arm/mach-omap2/powerdomain-common.c u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank) · line 169

Quoted 10 lines
arch/arm/mach-omap2/powerdomain-common.c +10 -0
+               ret = PWRDM_FUNC_PWRST_ON;
+               break;
+       case PWRDM_POWER_INACTIVE:
+               ret = PWRDM_FUNC_PWRST_INACTIVE;
+               break;
+       case PWRDM_POWER_RET:
+               /*
+                * XXX warning: return OSWR in case of pd in RET and
+                * logic in OFF
+                */

We need to be able to pass in logic pwst to be able to make that determination.

Quoted 19 lines
arch/arm/mach-omap2/powerdomain-common.c +12 -0
+               ret = PWRDM_FUNC_PWRST_CSWR;
+               break;
+       case PWRDM_POWER_OFF:
+               ret = PWRDM_FUNC_PWRST_OFF;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
arch/arm/mach-omap2/powerdomain.c +0 -0
index 1641e72..e79b5ae 100644
@@ -466,6 +466,135 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
 }
 
Quoted 13 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 479

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
 /**
+ * pwrdm_func_to_pwrst - get the internal (i.e. registers) value mapped
+ * to the functional state
+ * @pwrdm: struct powerdomain * to query
+ * @func_pwrst: functional power state
+ *
+ * Convert the functional power state to the platform specific power
+ * domain state value.
+ * Returns the internal power domain state value or -EINVAL in case
+ * of invalid parameters passed in.
+ */
+int pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)

should take enum pwrdm_func_state func_pwrst

Ok

Quoted 14 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 487

Quoted 9 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
+{
+       int ret = func_pwrst;
+
+       if ((!pwrdm) || (func_pwrst >= PWRDM_MAX_FUNC_PWRSTS))
+               return -EINVAL;
+
+       if (arch_pwrdm && arch_pwrdm->pwrdm_func_to_pwrst)
+               ret = arch_pwrdm->pwrdm_func_to_pwrst(pwrdm, func_pwrst);

Should we not return an error if the function pointer is not available for the arch?
on platforms without func_pwrst pointer converter routing hooked on, we return func_pwrst back to caller, which expects pwrst!

This is what the code does, cf. the first line of the function 'int ret = func_pwrst;'. Is that what you mean?

Quoted 12 lines
Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
+
+       pr_debug("powerdomain: convert func %0x to pwrst %0x for %s\n",
+                func_pwrst, ret, pwrdm->name);
+
+       return ret;
+}
+
+/**
+ * pwrdm_pwrst_to_func - get the functional (i.e. logical) value mapped
+ * to the internal state
+ * @pwrdm: struct powerdomain * to query
Quoted 8 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 505

Quoted 7 lines
arch/arm/mach-omap2/powerdomain.c +7 -0
+ * @pwrst: internal power state
+ *
+ * Convert the internal power state to the power domain functional value.
+ * Returns the functional power domain state value or -EINVAL in case
+ * of invalid parameters passed in.
+ */
+int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)

should return enum pwrdm_func_state

Ok

Quoted 41 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 516

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
+{
+       int ret = pwrst;
+
+       if ((!pwrdm) || (pwrst >= PWRDM_MAX_PWRSTS))
+               return -EINVAL;
+
+       pr_debug("powerdomain: convert %0x pwrst to func for %s\n",
+                pwrst, pwrdm->name);
+
+       if (arch_pwrdm && arch_pwrdm->pwrdm_pwrst_to_func)
+               ret = arch_pwrdm->pwrdm_pwrst_to_func(pwrdm, pwrst);

same in reverse here.

Quoted 26 lines
arch/arm/mach-omap2/powerdomain.c +26 -0
+
+       return ret;
+}
+
+/* Types of sleep_switch used in omap_set_pwrdm_state */
+#define FORCEWAKEUP_SWITCH     0
+#define LOWPOWERSTATE_SWITCH   1
+
+/**
+ * omap_set_pwrdm_state - program next powerdomain power state
+ * @pwrdm: struct powerdomain * to set
+ * @func_pwrst: power domain functional state, one of the PWRDM_FUNC_* macros
+ *
+ * This programs the pwrdm next functional state, sets the dependencies
+ * and waits for the state to be applied.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm,
+                        enum pwrdm_func_state func_pwrst)
+{
+       u8 curr_pwrst, next_pwrst;
+       int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+       int sleep_switch = -1, ret = 0, hwsup = 0;
+
+       if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0)) {
+               pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
+                        __func__, pwrdm, func_pwrst);
Quoted 8 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 549

Quoted 7 lines
arch/arm/mach-omap2/powerdomain.c +7 -0
+               return -EINVAL;
+       }
+
+       pr_debug("%s: set func_pwrst %0x to pwrdm %s\n",
+                __func__, func_pwrst, pwrdm->name);
+
+       mutex_lock(&pwrdm->lock);

This should be a spinlock (previous patch i believe) - hurts cpuidle otherwise.

Ok that had been reported by Ambresh. I have a fix ready for that.

Quoted 92 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm) · line 556

Quoted 8 lines
arch/arm/mach-omap2/powerdomain.c +7 -0
+
+       while (!(pwrdm->pwrsts & (1 << pwrst))) {
+               if (pwrst == PWRDM_POWER_OFF)
+                       goto out;
+               pwrst--;
+       }
+

if we like to handle a single API for OSWR and CSWR, then it needs to handle logic power state as well here.

Quoted 46 lines
arch/arm/mach-omap2/powerdomain.c +41 -0
+       next_pwrst = pwrdm_read_next_pwrst(pwrdm);
+       if (next_pwrst == pwrst)
+               goto out;
+
+       curr_pwrst = pwrdm_read_pwrst(pwrdm);
+       if (curr_pwrst < PWRDM_POWER_ON) {
+               if ((curr_pwrst > pwrst) &&
+                       (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
+                       sleep_switch = LOWPOWERSTATE_SWITCH;
+               } else {
+                       hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
+                       clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+                       sleep_switch = FORCEWAKEUP_SWITCH;
+               }
+       }
+
+       ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+       if (ret)
+               pr_err("%s: unable to set power state of powerdomain: %s\n",
+                      __func__, pwrdm->name);
+
+       switch (sleep_switch) {
+       case FORCEWAKEUP_SWITCH:
+               if (hwsup)
+                       clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+               else
+                       clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
+               break;
+       case LOWPOWERSTATE_SWITCH:
+               pwrdm_set_lowpwrstchange(pwrdm);
+               pwrdm_wait_transition(pwrdm);
+               pwrdm_state_switch(pwrdm);
+               break;
+       }
+
+out:
+       mutex_unlock(&pwrdm->lock);
+       return ret;
+}
+
+/**
  * pwrdm_set_next_pwrst - set next powerdomain power state
  * @pwrdm: struct powerdomain * to set
  * @pwrst: one of the PWRDM_POWER_* macros
@@ -522,6 +651,21 @@ int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 }

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_next_pwrst(struct powerdomain *pwrdm) · line 661

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
 
 /**
+ * pwrdm_read_next_func_pwrst - get next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the next power state upon success.
+ */
+int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +7 -0
+{
+       int ret = pwrdm_read_next_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}
+
+/**
  * pwrdm_read_pwrst - get current powerdomain power state
  * @pwrdm: struct powerdomain * to get power state
  *
@@ -543,6 +687,21 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 }

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_pwrst(struct powerdomain *pwrdm) · line 697

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
 
 /**
+ * pwrdm_read_func_pwrst - get current powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's current functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns
+ * the current power state upon success.
+ */
+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

Quoted 9 lines

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_pwrst(struct powerdomain *pwrdm) · line 702

Quoted 5 lines
arch/arm/mach-omap2/powerdomain.c +5 -0
+{
+       int ret = pwrdm_read_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}

my Crib about the above apis are lack of logic power state handling :( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

Please look at the rest of the series.

Quoted 223 lines
Quoted 7 lines
arch/arm/mach-omap2/powerdomain.c +2 -0
+
+/**
  * pwrdm_read_prev_pwrst - get previous powerdomain power state
  * @pwrdm: struct powerdomain * to get previous power state
  *
@@ -564,6 +723,21 @@ int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 }

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) · line 733

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
 
 /**
+ * pwrdm_read_prev_func_pwrst - get previous powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous power state upon success.
+ */
+int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm)

should return enum pwrdm_func_state

arch/arm/mach-omap2/powerdomain.c int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) · line 738

Quoted 5 lines
arch/arm/mach-omap2/powerdomain.c +5 -0
+{
+       int ret = pwrdm_read_prev_pwrst(pwrdm);
+
+       return pwrdm_pwrst_to_func(pwrdm, ret);
+}

again here.

Quoted 54 lines
arch/arm/mach-omap2/powerdomain.c +2 -0
+
+/**
  * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
  * @pwrdm: struct powerdomain * to set
  * @pwrst: one of the PWRDM_POWER_* macros
arch/arm/mach-omap2/powerdomain.h +30 -4
index bab84fc..0404f9f 100644
@@ -9,9 +9,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * XXX This should be moved to the mach-omap2/ directory at the earliest
- * opportunity.
  */
 
 #ifndef __ARCH_ARM_MACH_OMAP2_POWERDOMAIN_H
@@ -26,7 +23,51 @@
 
 #include "voltage.h"
 
-/* Powerdomain basic power states */
+/***************************************************************
+ * External API
+ ***************************************************************/
+
+/* Powerdomain functional power states, used by the external API functions */
+enum pwrdm_func_state {
+       PWRDM_FUNC_PWRST_OFF            = 0x0,
+       PWRDM_FUNC_PWRST_OSWR,
+       PWRDM_FUNC_PWRST_CSWR,
+       PWRDM_FUNC_PWRST_INACTIVE,
+       PWRDM_FUNC_PWRST_ON,
+       PWRDM_MAX_FUNC_PWRSTS           /* Last value, used as the max value */
+};
+
+struct clockdomain;
+struct powerdomain;
+
+struct powerdomain *pwrdm_lookup(const char *name);
+
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+                       void *user);
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+                       void *user);
+
+struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
+
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
+
+int pwrdm_read_prev_func_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_func_pwrst(struct powerdomain *pwrdm);

arch/arm/mach-omap2/powerdomain.h line 65

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.h +10 -0
+int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm,
+                               enum pwrdm_func_state func_pwrst);
+
+extern void omap242x_powerdomains_init(void);
+extern void omap243x_powerdomains_init(void);
+extern void omap3xxx_powerdomains_init(void);
+extern void omap44xx_powerdomains_init(void);
+
+

We should split the following out to a separate header which is not to be used by anyone else other than powerdomain*.[ch]

Quoted 38 lines
arch/arm/mach-omap2/powerdomain.h +9 -4
+/***************************************************************
+ * Internal code, only used in powerdomain*.[ch]
+ ***************************************************************/
+
+/* Powerdomain internal power states, internal use only */
 #define PWRDM_POWER_OFF                0x0
 #define PWRDM_POWER_RET                0x1
 #define PWRDM_POWER_INACTIVE   0x2
@@ -45,7 +86,6 @@
 #define PWRSTS_RET_ON          (PWRSTS_RET | PWRSTS_ON)
 #define PWRSTS_OFF_RET_ON      (PWRSTS_OFF_RET | PWRSTS_ON)
 
-
 /* Powerdomain flags */
 #define PWRDM_HAS_HDWR_SAR     (1 << 0) /* hardware save-and-restore support */
 #define PWRDM_HAS_MPU_QUIRK    (1 << 1) /* MPU pwr domain has MEM bank 0 bits
@@ -74,9 +114,6 @@
 /* XXX A completely arbitrary number. What is reasonable here? */
 #define PWRDM_TRANSITION_BAILOUT 100000
 
-struct clockdomain;
-struct powerdomain;
-
 /**
  * struct powerdomain - OMAP powerdomain
  * @name: Powerdomain name
@@ -130,6 +167,10 @@ struct powerdomain {
 
 /**
  * struct pwrdm_ops - Arch specific function implementations
+ * @pwrdm_func_to_pwrst: Convert the pd functional power state to
+ *  the internal state
+ * @pwrdm_pwrst_to_func: Convert the pd internal power state to
+ *  the functional state
  * @pwrdm_set_next_pwrst: Set the target power state for a pd
  * @pwrdm_read_next_pwrst: Read the target power state set for a pd
  * @pwrdm_read_pwrst: Read the current power state of a pd

arch/arm/mach-omap2/powerdomain.h struct powerdomain { · line 194

Quoted 4 lines
arch/arm/mach-omap2/powerdomain.h +1 -0
@@ -150,6 +191,8 @@ struct powerdomain {
  * @pwrdm_wait_transition: Wait for a pd state transition to complete
  */
 struct pwrdm_ops {
+       int     (*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);

should take in enum pwrdm_func_state

arch/arm/mach-omap2/powerdomain.h struct powerdomain { · line 195

Quoted 1 line
arch/arm/mach-omap2/powerdomain.h +1 -0
+       int     (*pwrdm_pwrst_to_func)(struct powerdomain *pwrdm, u8 func_pwrst);

should return enum pwrdm_func_state

Quoted 84 lines
arch/arm/mach-omap2/powerdomain.h +3 -15
        int     (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst);
        int     (*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm);
        int     (*pwrdm_read_pwrst)(struct powerdomain *pwrdm);
@@ -174,21 +217,11 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
 int pwrdm_register_pwrdms(struct powerdomain **pwrdm_list);
 int pwrdm_complete_init(void);
 
-struct powerdomain *pwrdm_lookup(const char *name);
-
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
-                       void *user);
-int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
-                       void *user);
-
 int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
                         int (*fn)(struct powerdomain *pwrdm,
                                   struct clockdomain *clkdm));
-struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm);
-
-int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
 
 int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
@@ -196,6 +229,9 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
 int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 
+int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst);
+
 int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
 int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
@@ -220,11 +256,6 @@ int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
 int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
 bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
 
-extern void omap242x_powerdomains_init(void);
-extern void omap243x_powerdomains_init(void);
-extern void omap3xxx_powerdomains_init(void);
-extern void omap44xx_powerdomains_init(void);
-
 extern struct pwrdm_ops omap2_pwrdm_operations;
 extern struct pwrdm_ops omap3_pwrdm_operations;
 extern struct pwrdm_ops omap4_pwrdm_operations;
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +5 -0
index 0f0a9f1..79c1293 100644
@@ -26,6 +26,7 @@
 
 
 /* Common functions across OMAP2 and OMAP3 */
+
 static int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 {
        omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
@@ -210,6 +211,8 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap2_pwrdm_operations = {
+       .pwrdm_func_to_pwrst    = omap2_pwrdm_func_to_pwrst,
+       .pwrdm_pwrst_to_func    = omap2_pwrdm_pwrst_to_func,
        .pwrdm_set_next_pwrst   = omap2_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap2_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst       = omap2_pwrdm_read_pwrst,
@@ -222,6 +225,8 @@ struct pwrdm_ops omap2_pwrdm_operations = {
 };
 
 struct pwrdm_ops omap3_pwrdm_operations = {
+       .pwrdm_func_to_pwrst    = omap2_pwrdm_func_to_pwrst,
+       .pwrdm_pwrst_to_func    = omap2_pwrdm_pwrst_to_func,
        .pwrdm_set_next_pwrst   = omap2_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap2_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst       = omap2_pwrdm_read_pwrst,
arch/arm/mach-omap2/powerdomain44xx.c +0 -0
index 601325b..538b528 100644
@@ -209,6 +209,8 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 }
 
Quoted 8 lines

arch/arm/mach-omap2/powerdomain44xx.c static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) · line 216

Quoted 6 lines
arch/arm/mach-omap2/powerdomain44xx.c +2 -0
 struct pwrdm_ops omap4_pwrdm_operations = {
+       .pwrdm_func_to_pwrst    = omap2_pwrdm_func_to_pwrst,
+       .pwrdm_pwrst_to_func    = omap2_pwrdm_pwrst_to_func,
        .pwrdm_set_next_pwrst   = omap4_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap4_pwrdm_read_next_pwrst,
        .pwrdm_read_pwrst       = omap4_pwrdm_read_pwrst,

otherwise, this is a nice concept

Great! Thanks for the review.

Quoted 3 lines

--
Regards,
Nishanth Menon

Regards,
Jean

#12 lore raw

PATCH 2/8 ARM: OMAP2+: PM: introduce power domains functional states

Quoted 4 lines · Jean Pihet
Quoted 3 lines

my Crib about the above apis are lack of logic power state handling :( which forces code like cpuidle to use different apis for logic power state and force them to use these apis just for pwrst.

Please look at the rest of the series.

Thanks for doing these, but with
https://patchwork.kernel.org/patch/1160431/ in context, my comments on this patch is redundant and i think we should go with Rajendra's patch instead of this. I am currently dropping this patch in my internal tree. Will comment further as i get to next set of patches in this series.

Regards,
Nishanth Menon

author
#13 lore raw

PATCH v4 3/8 ARM: OMAP2+: PM: use the functional power states API

In reply to Jean Pihet

Use the functional power states as the API to control power domains. The omap_set_pwrdm_state function shall be used instead of pwrdm_set_next_pwrst to control the power domains next states.

Note: the internal code for power domains state management still uses the internal power states.

---
 arch/arm/mach-omap2/cpuidle34xx.c         |   61 +++++++++++-----------
 arch/arm/mach-omap2/cpuidle44xx.c         |   25 +++++-----
 arch/arm/mach-omap2/omap-hotplug.c        |    2 +-
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   43 +++++++++-------
 arch/arm/mach-omap2/pm24xx.c              |   10 ++--
 arch/arm/mach-omap2/pm34xx.c              |   78 +++++++++++++++--------------
 arch/arm/mach-omap2/pm44xx.c              |    8 ++--
 arch/arm/mach-omap2/powerdomain.c         |    2 +-
 8 files changed, 119 insertions(+), 110 deletions(-)
arch/arm/mach-omap2/cpuidle34xx.c +30 -31
index 207bc1c..ef8d7d4 100644
@@ -46,32 +46,32 @@ struct omap3_idle_statedata {
 
 static struct omap3_idle_statedata omap3_idle_data[] = {
 	{
-		.mpu_state = PWRDM_POWER_ON,
-		.core_state = PWRDM_POWER_ON,
+		.mpu_state = PWRDM_FUNC_PWRST_ON,
+		.core_state = PWRDM_FUNC_PWRST_ON,
 	},
 	{
-		.mpu_state = PWRDM_POWER_ON,
-		.core_state = PWRDM_POWER_ON,
+		.mpu_state = PWRDM_FUNC_PWRST_ON,
+		.core_state = PWRDM_FUNC_PWRST_ON,
 	},
 	{
-		.mpu_state = PWRDM_POWER_RET,
-		.core_state = PWRDM_POWER_ON,
+		.mpu_state = PWRDM_FUNC_PWRST_CSWR,
+		.core_state = PWRDM_FUNC_PWRST_ON,
 	},
 	{
-		.mpu_state = PWRDM_POWER_OFF,
-		.core_state = PWRDM_POWER_ON,
+		.mpu_state = PWRDM_FUNC_PWRST_OFF,
+		.core_state = PWRDM_FUNC_PWRST_ON,
 	},
 	{
-		.mpu_state = PWRDM_POWER_RET,
-		.core_state = PWRDM_POWER_RET,
+		.mpu_state = PWRDM_FUNC_PWRST_CSWR,
+		.core_state = PWRDM_FUNC_PWRST_CSWR,
 	},
 	{
-		.mpu_state = PWRDM_POWER_OFF,
-		.core_state = PWRDM_POWER_RET,
+		.mpu_state = PWRDM_FUNC_PWRST_OFF,
+		.core_state = PWRDM_FUNC_PWRST_CSWR,
 	},
 	{
-		.mpu_state = PWRDM_POWER_OFF,
-		.core_state = PWRDM_POWER_OFF,
+		.mpu_state = PWRDM_FUNC_PWRST_OFF,
+		.core_state = PWRDM_FUNC_PWRST_OFF,
 	},
 };
 
@@ -100,8 +100,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
 
 	local_fiq_disable();
 
-	pwrdm_set_next_pwrst(mpu_pd, mpu_state);
-	pwrdm_set_next_pwrst(core_pd, core_state);
+	omap_set_pwrdm_state(mpu_pd, mpu_state);
+	omap_set_pwrdm_state(core_pd, core_state);
 
 	if (omap_irq_pending() || need_resched())
 		goto return_sleep_time;
@@ -116,7 +116,7 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
 	 * Call idle CPU PM enter notifier chain so that
 	 * VFP context is saved.
 	 */
-	if (mpu_state == PWRDM_POWER_OFF)
+	if (mpu_state == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_enter();
 
 	/* Execute ARM wfi */
@@ -126,7 +126,7 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
 	 * Call idle CPU PM enter notifier chain to restore
 	 * VFP context.
 	 */
-	if (pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
+	if (pwrdm_read_prev_func_pwrst(mpu_pd) == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_exit();
 
 	/* Re-allow idle for C1 */
@@ -175,20 +175,20 @@ static int next_valid_state(struct cpuidle_device *dev,
 			    struct cpuidle_driver *drv, int index)
 {
 	struct omap3_idle_statedata *cx = &omap3_idle_data[index];
-	u32 mpu_deepest_state = PWRDM_POWER_RET;
-	u32 core_deepest_state = PWRDM_POWER_RET;
+	u32 mpu_deepest_state = PWRDM_FUNC_PWRST_CSWR;
+	u32 core_deepest_state = PWRDM_FUNC_PWRST_CSWR;
 	int idx;
 	int next_index = -1;
 
 	if (enable_off_mode) {
-		mpu_deepest_state = PWRDM_POWER_OFF;
+		mpu_deepest_state = PWRDM_FUNC_PWRST_OFF;
 		/*
 		 * Erratum i583: valable for ES rev < Es1.2 on 3630.
 		 * CORE OFF mode is not supported in a stable form, restrict
 		 * instead the CORE state to RET.
 		 */
 		if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
-			core_deepest_state = PWRDM_POWER_OFF;
+			core_deepest_state = PWRDM_FUNC_PWRST_OFF;
 	}
 
 	/* Check if current state is valid */
@@ -232,7 +232,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 			       int index)
 {
 	int new_state_idx;
-	u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
+	u32 core_next_state, per_next_state = 0, per_saved_state = 0;
 	struct omap3_idle_statedata *cx;
 	int ret;
 
@@ -240,8 +240,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	 * Prevent idle completely if CAM is active.
 	 * CAM does not have wakeup capability in OMAP3.
 	 */
-	cam_state = pwrdm_read_pwrst(cam_pd);
-	if (cam_state == PWRDM_POWER_ON) {
+	if (pwrdm_read_func_pwrst(cam_pd) == PWRDM_FUNC_PWRST_ON) {
 		new_state_idx = drv->safe_state_index;
 		goto select_state;
 	}
@@ -260,14 +259,14 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	 */
 	cx = &omap3_idle_data[index];
 	core_next_state = cx->core_state;
-	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
-	if ((per_next_state == PWRDM_POWER_OFF) &&
-	    (core_next_state > PWRDM_POWER_RET))
-		per_next_state = PWRDM_POWER_RET;
+	per_next_state = per_saved_state = pwrdm_read_next_func_pwrst(per_pd);
+	if ((per_next_state == PWRDM_FUNC_PWRST_OFF) &&
+	    (core_next_state > PWRDM_FUNC_PWRST_CSWR))
+		per_next_state = PWRDM_FUNC_PWRST_CSWR;
 
 	/* Are we changing PER target state? */
 	if (per_next_state != per_saved_state)
-		pwrdm_set_next_pwrst(per_pd, per_next_state);
+		omap_set_pwrdm_state(per_pd, per_next_state);
 
 	new_state_idx = next_valid_state(dev, drv, index);
 
@@ -276,7 +275,7 @@ select_state:
 
 	/* Restore original PER state if it was modified */
 	if (per_next_state != per_saved_state)
-		pwrdm_set_next_pwrst(per_pd, per_saved_state);
+		omap_set_pwrdm_state(per_pd, per_saved_state);
 
 	return ret;
 }
arch/arm/mach-omap2/cpuidle44xx.c +13 -12
index be1617c..50c9082 100644
@@ -33,18 +33,18 @@ struct omap4_idle_statedata {
 
 static struct omap4_idle_statedata omap4_idle_data[] = {
 	{
-		.cpu_state = PWRDM_POWER_ON,
-		.mpu_state = PWRDM_POWER_ON,
+		.cpu_state = PWRDM_FUNC_PWRST_ON,
+		.mpu_state = PWRDM_FUNC_PWRST_ON,
 		.mpu_logic_state = PWRDM_POWER_RET,
 	},
 	{
-		.cpu_state = PWRDM_POWER_OFF,
-		.mpu_state = PWRDM_POWER_RET,
+		.cpu_state = PWRDM_FUNC_PWRST_OFF,
+		.mpu_state = PWRDM_FUNC_PWRST_CSWR,
 		.mpu_logic_state = PWRDM_POWER_RET,
 	},
 	{
-		.cpu_state = PWRDM_POWER_OFF,
-		.mpu_state = PWRDM_POWER_RET,
+		.cpu_state = PWRDM_FUNC_PWRST_OFF,
+		.mpu_state = PWRDM_FUNC_PWRST_CSWR,
 		.mpu_logic_state = PWRDM_POWER_OFF,
 	},
 };
@@ -79,8 +79,8 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
 	 * Update dev->last_state so that governor stats reflects right
 	 * data.
 	 */
-	cpu1_state = pwrdm_read_pwrst(cpu1_pd);
-	if (cpu1_state != PWRDM_POWER_OFF) {
+	cpu1_state = pwrdm_read_func_pwrst(cpu1_pd);
+	if (cpu1_state != PWRDM_FUNC_PWRST_OFF) {
 		index = drv->safe_state_index;
 		cx = &omap4_idle_data[index];
 	}
@@ -92,7 +92,7 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
 	 * Call idle CPU PM enter notifier chain so that
 	 * VFP and per CPU interrupt context is saved.
 	 */
-	if (cx->cpu_state == PWRDM_POWER_OFF)
+	if (cx->cpu_state == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_enter();
 
 	pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
@@ -102,8 +102,9 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
 	 * Call idle CPU cluster PM enter notifier chain
 	 * to save GIC and wakeupgen context.
 	 */
-	if ((cx->mpu_state == PWRDM_POWER_RET) &&
-		(cx->mpu_logic_state == PWRDM_POWER_OFF))
+	if (((cx->mpu_state == PWRDM_FUNC_PWRST_CSWR) ||
+	     (cx->mpu_state == PWRDM_FUNC_PWRST_OSWR)) &&
+	    (cx->mpu_logic_state == PWRDM_POWER_OFF))
 			cpu_cluster_pm_enter();
 
 	omap4_enter_lowpower(dev->cpu, cx->cpu_state);
@@ -113,7 +114,7 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
 	 * VFP and per CPU IRQ context. Only CPU0 state is
 	 * considered since CPU1 is managed by CPU hotplug.
 	 */
-	if (pwrdm_read_prev_pwrst(cpu0_pd) == PWRDM_POWER_OFF)
+	if (pwrdm_read_prev_func_pwrst(cpu0_pd) == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_exit();
 
 	/*
arch/arm/mach-omap2/omap-hotplug.c +1 -1
index 56c345b..cb7a7eb 100644
@@ -50,7 +50,7 @@ void __ref platform_cpu_die(unsigned int cpu)
 		/*
 		 * Enter into low power state
 		 */
-		omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF);
+		omap4_hotplug_cpu(cpu, PWRDM_FUNC_PWRST_OFF);
 		this_cpu = smp_processor_id();
 		if (omap_read_auxcoreboot0() == this_cpu) {
 			/*
arch/arm/mach-omap2/omap-mpuss-lowpower.c +24 -19

124 lines not on this page · raw message

arch/arm/mach-omap2/pm24xx.c +5 -5
index 2edeffc..0bed51e 100644
@@ -94,7 +94,7 @@ static int omap2_enter_full_retention(void)
 	 * preserve logic state during retention
 	 */
 	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
-	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+	omap_set_pwrdm_state(mpu_pwrdm, PWRDM_FUNC_PWRST_CSWR);
 
 	/* Workaround to kill USB */
 	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
@@ -251,23 +251,23 @@ static void __init prcm_setup_regs(void)
 		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
 
 	/* Set CORE powerdomain's next power state to RETENTION */
-	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+	omap_set_pwrdm_state(core_pwrdm, PWRDM_FUNC_PWRST_CSWR);
 
 	/*
 	 * Set MPU powerdomain's next power state to RETENTION;
 	 * preserve logic state during retention
 	 */
 	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
-	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+	omap_set_pwrdm_state(mpu_pwrdm, PWRDM_FUNC_PWRST_CSWR);
 
 	/* Force-power down DSP, GFX powerdomains */
 
 	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
-	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	omap_set_pwrdm_state(pwrdm, PWRDM_FUNC_PWRST_OFF);
 	clkdm_sleep(dsp_clkdm);
 
 	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
-	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	omap_set_pwrdm_state(pwrdm, PWRDM_FUNC_PWRST_OFF);
 	clkdm_sleep(gfx_clkdm);
 
 	/* Enable hardware-supervised idle for all clkdms */
arch/arm/mach-omap2/pm34xx.c +41 -37

184 lines not on this page · raw message

arch/arm/mach-omap2/pm44xx.c +4 -4
index ea24174..98bb699 100644
@@ -44,7 +44,7 @@ static int omap4_pm_suspend(void)
 
 	/* Save current powerdomain state */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
-		pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+		pwrst->saved_state = pwrdm_read_next_func_pwrst(pwrst->pwrdm);
 		pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm);
 	}
 
@@ -63,11 +63,11 @@ static int omap4_pm_suspend(void)
 	 * domain CSWR is not supported by hardware.
 	 * More details can be found in OMAP4430 TRM section 4.3.4.2.
 	 */
-	omap4_enter_lowpower(cpu_id, PWRDM_POWER_OFF);
+	omap4_enter_lowpower(cpu_id, PWRDM_FUNC_PWRST_OFF);
 
 	/* Restore next powerdomain state */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
-		state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+		state = pwrdm_read_prev_func_pwrst(pwrst->pwrdm);
 		if (state > pwrst->next_state) {
 			pr_info("Powerdomain (%s) didn't enter "
 			       "target state %d\n",
@@ -113,7 +113,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 		return -ENOMEM;
 
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_RET;
+	pwrst->next_state = PWRDM_FUNC_PWRST_CSWR;
 	list_add(&pwrst->node, &pwrst_list);
 
 	return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
arch/arm/mach-omap2/powerdomain.c +1 -1
index e79b5ae..ec2b21c 100644
@@ -270,7 +270,7 @@ int pwrdm_complete_init(void)
 		return -EACCES;
 
 	list_for_each_entry(temp_p, &pwrdm_list, node)
-		pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
+		omap_set_pwrdm_state(temp_p, PWRDM_FUNC_PWRST_ON);
 
 	return 0;
 }
Signature · 1 line
1.7.7.6
author
#14 lore raw

PATCH v4 4/8 ARM: OMAP2+: PM: introduce power domains logic and memory functional states

In reply to Jean Pihet

In the new API the functions pwrdm_*_logic_* and pwrdm_*_mem_* take the functional states as parameter.

OMAP2, OMAP3 and OMAP4 platforms are defining a conversion routine between the functional state and the logic power state.

The power domains logic state is now derived from the functional state and the logic state is programmed from omap_set_pwrdm_state.

---
 arch/arm/mach-omap2/powerdomain-common.c   |   41 ++++++++++++--
 arch/arm/mach-omap2/powerdomain.c          |   79 +++++++++++++++++++++------
 arch/arm/mach-omap2/powerdomain.h          |   22 +++++++-
 arch/arm/mach-omap2/powerdomain2xxx_3xxx.c |    2 +
 arch/arm/mach-omap2/powerdomain44xx.c      |    1 +
 5 files changed, 118 insertions(+), 27 deletions(-)
arch/arm/mach-omap2/powerdomain-common.c +35 -6
index 2973be7..1ae3659 100644
@@ -143,6 +143,36 @@ int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
 }
 
 /**
+ * omap2_pwrdm_func_to_logic_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains logic states.
+ * @struct powerdomain * to convert the values for
+ * @func_pwrst: functional power state
+ *
+ * Returns the internal logic state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+int omap2_pwrdm_func_to_logic_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
+{
+	int ret;
+
+	switch (func_pwrst) {
+	case PWRDM_FUNC_PWRST_ON:
+	case PWRDM_FUNC_PWRST_INACTIVE:
+	case PWRDM_FUNC_PWRST_CSWR:
+		ret = PWRDM_LOGIC_MEM_PWRST_RET;
+		break;
+	case PWRDM_FUNC_PWRST_OSWR:
+	case PWRDM_FUNC_PWRST_OFF:
+		ret = PWRDM_LOGIC_MEM_PWRST_OFF;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
  * omap2_pwrdm_pwrst_to_func - Convert internal (i.e. registers) to
  * functional (i.e. logical) values for the power domains states.
  * @struct powerdomain * to convert the values for
@@ -151,7 +181,7 @@ int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
  * Returns the functional power state value for the power domain, or
  * -EINVAL in case of invalid parameters passed in.
  */
-int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic)
 {
 	int ret;
 
@@ -163,11 +193,10 @@ int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst)
 		ret = PWRDM_FUNC_PWRST_INACTIVE;
 		break;
 	case PWRDM_POWER_RET:
-		/*
-		 * XXX warning: return OSWR in case of pd in RET and
-		 * logic in OFF
-		 */
-		ret = PWRDM_FUNC_PWRST_CSWR;
+		if (logic == PWRDM_LOGIC_MEM_PWRST_RET)
+			ret = PWRDM_FUNC_PWRST_CSWR;
+		else
+			ret = PWRDM_FUNC_PWRST_OSWR;
 		break;
 	case PWRDM_POWER_OFF:
 		ret = PWRDM_FUNC_PWRST_OFF;
arch/arm/mach-omap2/powerdomain.c +61 -18

164 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.h +19 -3
index 0404f9f..d08c25d 100644
@@ -37,6 +37,16 @@ enum pwrdm_func_state {
 	PWRDM_MAX_FUNC_PWRSTS		/* Last value, used as the max value */
 };
 
+/*
+ * Powerdomains logic and memory functional power states,
+ * used by the external API functions
+ */
+enum pwrdm_logic_mem_state {
+	PWRDM_LOGIC_MEM_PWRST_OFF	= 0x0,
+	PWRDM_LOGIC_MEM_PWRST_RET,
+	PWRDM_MAX_LOGIC_MEM_PWRST	/* Last value, used as the max value */
+};
+
 struct clockdomain;
 struct powerdomain;
 
@@ -169,7 +179,9 @@ struct powerdomain {
  * struct pwrdm_ops - Arch specific function implementations
  * @pwrdm_func_to_pwrst: Convert the pd functional power state to
  *  the internal state
- * @pwrdm_pwrst_to_func: Convert the pd internal power state to
+ * @pwrdm_func_to_logic_pwrst: Convert the pd functional power state
+ *  to the internal logic state
+ * @pwrdm_pwrst_to_func: Convert the pd internal and logic power state to
  *  the functional state
  * @pwrdm_set_next_pwrst: Set the target power state for a pd
  * @pwrdm_read_next_pwrst: Read the target power state set for a pd
@@ -192,7 +204,10 @@ struct powerdomain {
  */
 struct pwrdm_ops {
 	int	(*pwrdm_func_to_pwrst)(struct powerdomain *pwrdm, u8 func_pwrst);
-	int	(*pwrdm_pwrst_to_func)(struct powerdomain *pwrdm, u8 func_pwrst);
+	int	(*pwrdm_func_to_logic_pwrst)(struct powerdomain *pwrdm,
+					     u8 func_pwrst);
+	int	(*pwrdm_pwrst_to_func)(struct powerdomain *pwrdm, u8 func_pwrst,
+				       u8 logic);
 	int	(*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst);
 	int	(*pwrdm_read_next_pwrst)(struct powerdomain *pwrdm);
 	int	(*pwrdm_read_pwrst)(struct powerdomain *pwrdm);
@@ -230,7 +245,8 @@ int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
 int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 
 int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
-int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst);
+int omap2_pwrdm_func_to_logic_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
+int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic);
 
 int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
arch/arm/mach-omap2/powerdomain2xxx_3xxx.c +2 -0
index 79c1293..6a3ea3d 100644
@@ -212,6 +212,7 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 
 struct pwrdm_ops omap2_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
 	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
@@ -226,6 +227,7 @@ struct pwrdm_ops omap2_pwrdm_operations = {
 
 struct pwrdm_ops omap3_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
 	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap2_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap2_pwrdm_read_next_pwrst,
arch/arm/mach-omap2/powerdomain44xx.c +1 -0
index 538b528..030d10c 100644
@@ -210,6 +210,7 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
 
 struct pwrdm_ops omap4_pwrdm_operations = {
 	.pwrdm_func_to_pwrst	= omap2_pwrdm_func_to_pwrst,
+	.pwrdm_func_to_logic_pwrst	= omap2_pwrdm_func_to_logic_pwrst,
 	.pwrdm_pwrst_to_func	= omap2_pwrdm_pwrst_to_func,
 	.pwrdm_set_next_pwrst	= omap4_pwrdm_set_next_pwrst,
 	.pwrdm_read_next_pwrst	= omap4_pwrdm_read_next_pwrst,
Signature · 1 line
1.7.7.6
author
#15 lore raw

PATCH v4 5/8 ARM: OMAP2+: PM: introduce power domains achievable functional states

In reply to Jean Pihet

Note: the patch is in RFC state because the state machine for setting the next power domain states needs more discussion. Validated on OMAP3&4 with cpuidle and suspend/resume, though.

Power domains have varied capabilities. When attempting a low power state such as OFF/RET, a specific min requested state may not be supported on the power domain. This is because a combination of system power states where the parent PD's state is not in line with expectation can result in system instabilities.

This patch provides a function that returns the achievable functional power state for a power domain and its use by omap_set_pwrdm_state. The achievable power state is first looked for in the lower power states in order to maximize the power savings, then if not found in the higher power states.

Inspired from Tero's work on OMAP4 device OFF support and generalized to the functional power states.

---
 arch/arm/mach-omap2/powerdomain.c |  156 +++++++++++++++++++++++++++++++------
 arch/arm/mach-omap2/powerdomain.h |    1 +
 2 files changed, 134 insertions(+), 23 deletions(-)
arch/arm/mach-omap2/powerdomain.c +133 -23
index ce2685a..f94174b 100644
@@ -554,6 +554,108 @@ int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic)
 	return ret;
 }
 
+/**
+ * pwrdm_get_achievable_func_pwrst() - Provide achievable functional state
+ * @pwrdm: struct powerdomain * to set
+ * @func_pwrst: minimum functional state we would like to hit
+ * (one of the PWRDM_FUNC_* macros)
+ *
+ * Power domains have varied capabilities. When attempting a low power
+ * state such as OFF/RET, a specific min requested state may not be
+ * supported on the power domain. This is because a combination
+ * of system power states where the parent PD's state is not in line
+ * with expectation can result in system instabilities.
+ *
+ * The achievable power state is first looked for in the lower power
+ * states in order to maximize the power savings, then if not found
+ * in the higher power states.
+ *
+ * Returns the achievable functional power state, or -EINVAL in case of
+ * invalid parameters.
+ */
+int pwrdm_get_achievable_func_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
+{
+	int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+	int logic = pwrdm_func_to_logic_pwrst(pwrdm, func_pwrst);
+	int new_func_pwrst, new_pwrst, new_logic;
+	int found;
+
+	if (!pwrdm || IS_ERR(pwrdm)) {
+		pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
+			 __func__, pwrdm, func_pwrst);
+		return -EINVAL;
+	}
+
+	if ((pwrst < 0) || (logic < 0)) {
+		pr_debug("%s: invalid params for pwrdm %s, func_pwrst=%0x\n",
+			 __func__, pwrdm->name, func_pwrst);
+		return PWRDM_FUNC_PWRST_ON;
+	}
+
+	/*
+	 * Power state: if the requested state is not supported,
+	 * try the lower power states.
+	 */
+	found = 1;
+	new_pwrst = pwrst;
+	while (!(pwrdm->pwrsts & (1 << new_pwrst))) {
+		if (new_pwrst == PWRDM_POWER_OFF) {
+			found = 0;
+			break;
+		}
+		new_pwrst--;
+	}
+
+	/*
+	 * If no lower power state found, fallback to the higher
+	 * power states.
+	 * PWRDM_POWER_ON is always valid.
+	 */
+	if (!found) {
+		new_pwrst = pwrst;
+		while (!(pwrdm->pwrsts & (1 << new_pwrst))) {
+			if (new_pwrst == PWRDM_POWER_ON)
+				break;
+			new_pwrst++;
+		}
+	}
+
+	/*
+	 * Logic RET state: if the requested state is not supported,
+	 * try the lower logic states.
+	 */
+	found = 1;
+	new_logic = logic;
+	while (!(pwrdm->pwrsts_logic_ret & (1 << new_logic))) {
+		if (new_logic == PWRDM_LOGIC_MEM_PWRST_OFF) {
+			found = 0;
+			break;
+		}
+		new_logic--;
+	}
+
+	/*
+	 * If no lower logic state found, fallback to the higher
+	 * logic states.
+	 * PWRDM_LOGIC_MEM_PWRST_RET is always valid.
+	 */
+	if (!found) {
+		new_logic = logic;
+		while (!(pwrdm->pwrsts_logic_ret & (1 << new_logic))) {
+			if (new_logic == PWRDM_LOGIC_MEM_PWRST_RET)
+				break;
+			new_logic++;
+		}
+	}
+
+	new_func_pwrst = pwrdm_pwrst_to_func(pwrdm, new_pwrst, new_logic);
+
+	pr_debug("%s(%s, func_pwrst=%0x) returns %0x\n", __func__,
+		 pwrdm->name, func_pwrst, new_func_pwrst);
+
+	return new_func_pwrst;
+}
+
 /* Types of sleep_switch used in omap_set_pwrdm_state */
 #define FORCEWAKEUP_SWITCH	0
 #define LOWPOWERSTATE_SWITCH	1
@@ -563,36 +665,32 @@ int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic)
  * @pwrdm: struct powerdomain * to set
  * @func_pwrst: power domain functional state, one of the PWRDM_FUNC_* macros
  *
- * This programs the pwrdm next functional state, sets the dependencies
- * and waits for the state to be applied.
+ * This looks for the more suited (or achievable) next functional power
+ * state, programs it, sets the dependencies and waits for the state to
+ * be applied to the power domain.
  */
 int omap_set_pwrdm_state(struct powerdomain *pwrdm,
 			 enum pwrdm_func_state func_pwrst)
 {
-	u8 curr_pwrst, next_pwrst;
-	int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
-	int logic = pwrdm_func_to_logic_pwrst(pwrdm, func_pwrst);
 	int sleep_switch = -1, ret = 0, hwsup = 0;
+	int new_func_pwrst, next_func_pwrst, pwrst, logic;
+	u8 curr_pwrst;
 
-	if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0) || (logic < 0)) {
-		pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
-			 __func__, pwrdm, func_pwrst);
+	if (!pwrdm || IS_ERR(pwrdm)) {
+		pr_debug("%s: invalid params: pwrdm=%p\n", __func__, pwrdm);
 		return -EINVAL;
 	}
 
-	pr_debug("%s: set func_pwrst %0x to pwrdm %s\n",
-		 __func__, func_pwrst, pwrdm->name);
+	pr_debug("%s(%s, func_pwrst=%0x)\n", __func__, pwrdm->name, func_pwrst);
 
 	mutex_lock(&pwrdm->lock);
 
-	while (!(pwrdm->pwrsts & (1 << pwrst))) {
-		if (pwrst == PWRDM_POWER_OFF)
-			goto out;
-		pwrst--;
-	}
+	new_func_pwrst = pwrdm_get_achievable_func_pwrst(pwrdm, func_pwrst);
+	pwrst = pwrdm_func_to_pwrst(pwrdm, new_func_pwrst);
+	logic = pwrdm_func_to_logic_pwrst(pwrdm, new_func_pwrst);
 
-	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
-	if (next_pwrst == pwrst)
+	next_func_pwrst = pwrdm_read_next_func_pwrst(pwrdm);
+	if (new_func_pwrst == next_func_pwrst)
 		goto out;
 
 	curr_pwrst = pwrdm_read_pwrst(pwrdm);
@@ -607,13 +705,25 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm,
 		}
 	}
 
-	if (logic != pwrdm_read_logic_retst(pwrdm))
-		pwrdm_set_logic_retst(pwrdm, logic);
+	pr_debug("%s: set func_pwrst %0x (%0x,%0x) to pwrdm %s\n",
+		 __func__, new_func_pwrst, pwrst, logic, pwrdm->name);
+
+	/* Trace the pwrdm desired target state */
+	trace_power_domain_target(pwrdm->name, new_func_pwrst,
+				  smp_processor_id());
+
+	/* Program next power state */
+	if (pwrst != pwrdm_func_to_pwrst(pwrdm, next_func_pwrst)) {
+		ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+		if (ret)
+			pr_err("%s: unable to set power state of powerdomain: %s\n",
+			       __func__, pwrdm->name);
+	}
 
-	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
-	if (ret)
-		pr_err("%s: unable to set power state of powerdomain: %s\n",
-		       __func__, pwrdm->name);
+	/* Program RET logic state */
+	if ((pwrst == PWRDM_POWER_RET) &&
+	    (logic != pwrdm_func_to_logic_pwrst(pwrdm, next_func_pwrst)))
+		pwrdm_set_logic_retst(pwrdm, logic);
 
 	switch (sleep_switch) {
 	case FORCEWAKEUP_SWITCH:
arch/arm/mach-omap2/powerdomain.h +1 -0
index d08c25d..9dd68ab 100644
@@ -247,6 +247,7 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
 int omap2_pwrdm_func_to_logic_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
 int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic);
+int pwrdm_get_achievable_func_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
 
 int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
 int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
Signature · 1 line
1.7.7.6
author
#16 lore raw

PATCH v4 5/8 ARM: OMAP2+: PM: introduce power domains achievable functional states

Hi,

Here are some remarks I got after an internal review. I think those points need to be discussed with a broader audience.

Quoted 118 lines · Jean Pihet

Note: the patch is in RFC state because the state machine for setting the next power domain states needs more discussion. Validated on OMAP3&4 with cpuidle and suspend/resume, though.

Power domains have varied capabilities. When attempting a low power state such as OFF/RET, a specific min requested state may not be supported on the power domain. This is because a combination of system power states where the parent PD's state is not in line with expectation can result in system instabilities.

This patch provides a function that returns the achievable functional power state for a power domain and its use by omap_set_pwrdm_state. The achievable power state is first looked for in the lower power states in order to maximize the power savings, then if not found in the higher power states.

Inspired from Tero's work on OMAP4 device OFF support and generalized to the functional power states.

---
?arch/arm/mach-omap2/powerdomain.c | ?156 +++++++++++++++++++++++++++++++------ ?arch/arm/mach-omap2/powerdomain.h | ? ?1 +
?2 files changed, 134 insertions(+), 23 deletions(-)

arch/arm/mach-omap2/powerdomain.c +84 -0
index ce2685a..f94174b 100644
@@ -554,6 +554,108 @@ int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic)
 ? ? ? ?return ret;
 ?}
 
+/**
+ * pwrdm_get_achievable_func_pwrst() - Provide achievable functional state
+ * @pwrdm: struct powerdomain * to set
+ * @func_pwrst: minimum functional state we would like to hit
+ * (one of the PWRDM_FUNC_* macros)
+ *
+ * Power domains have varied capabilities. When attempting a low power
+ * state such as OFF/RET, a specific min requested state may not be
+ * supported on the power domain. This is because a combination
+ * of system power states where the parent PD's state is not in line
+ * with expectation can result in system instabilities.
+ *
+ * The achievable power state is first looked for in the lower power
+ * states in order to maximize the power savings, then if not found
+ * in the higher power states.
+ *
+ * Returns the achievable functional power state, or -EINVAL in case of
+ * invalid parameters.
+ */
+int pwrdm_get_achievable_func_pwrst(struct powerdomain *pwrdm, u8 func_pwrst)
+{
+ ? ? ? int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
+ ? ? ? int logic = pwrdm_func_to_logic_pwrst(pwrdm, func_pwrst);
+ ? ? ? int new_func_pwrst, new_pwrst, new_logic;
+ ? ? ? int found;
+
+ ? ? ? if (!pwrdm || IS_ERR(pwrdm)) {
+ ? ? ? ? ? ? ? pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
+ ? ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm, func_pwrst);
+ ? ? ? ? ? ? ? return -EINVAL;
+ ? ? ? }
+
+ ? ? ? if ((pwrst < 0) || (logic < 0)) {
+ ? ? ? ? ? ? ? pr_debug("%s: invalid params for pwrdm %s, func_pwrst=%0x\n",
+ ? ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm->name, func_pwrst);
+ ? ? ? ? ? ? ? return PWRDM_FUNC_PWRST_ON;
+ ? ? ? }
+
+ ? ? ? /*
+ ? ? ? ?* Power state: if the requested state is not supported,
+ ? ? ? ?* try the lower power states.
+ ? ? ? ?*/
+ ? ? ? found = 1;
+ ? ? ? new_pwrst = pwrst;
+ ? ? ? while (!(pwrdm->pwrsts & (1 << new_pwrst))) {
+ ? ? ? ? ? ? ? if (new_pwrst == PWRDM_POWER_OFF) {
+ ? ? ? ? ? ? ? ? ? ? ? found = 0;
+ ? ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? ? }
+ ? ? ? ? ? ? ? new_pwrst--;
+ ? ? ? }
+
+ ? ? ? /*
+ ? ? ? ?* If no lower power state found, fallback to the higher
+ ? ? ? ?* power states.
+ ? ? ? ?* PWRDM_POWER_ON is always valid.
+ ? ? ? ?*/
+ ? ? ? if (!found) {
+ ? ? ? ? ? ? ? new_pwrst = pwrst;
+ ? ? ? ? ? ? ? while (!(pwrdm->pwrsts & (1 << new_pwrst))) {
+ ? ? ? ? ? ? ? ? ? ? ? if (new_pwrst == PWRDM_POWER_ON)
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? ? ? ? ? ? new_pwrst++;
+ ? ? ? ? ? ? ? }
+ ? ? ? }
+
+ ? ? ? /*
+ ? ? ? ?* Logic RET state: if the requested state is not supported,
+ ? ? ? ?* try the lower logic states.
+ ? ? ? ?*/
+ ? ? ? found = 1;
+ ? ? ? new_logic = logic;
+ ? ? ? while (!(pwrdm->pwrsts_logic_ret & (1 << new_logic))) {
+ ? ? ? ? ? ? ? if (new_logic == PWRDM_LOGIC_MEM_PWRST_OFF) {
+ ? ? ? ? ? ? ? ? ? ? ? found = 0;
+ ? ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? ? }
+ ? ? ? ? ? ? ? new_logic--;
+ ? ? ? }
+
+ ? ? ? /*
+ ? ? ? ?* If no lower logic state found, fallback to the higher
+ ? ? ? ?* logic states.
+ ? ? ? ?* PWRDM_LOGIC_MEM_PWRST_RET is always valid.

arch/arm/mach-omap2/powerdomain.c int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic) · line 650

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+ ? ? ? ?*/
+ ? ? ? if (!found) {
+ ? ? ? ? ? ? ? new_logic = logic;
+ ? ? ? ? ? ? ? while (!(pwrdm->pwrsts_logic_ret & (1 << new_logic))) {
+ ? ? ? ? ? ? ? ? ? ? ? if (new_logic == PWRDM_LOGIC_MEM_PWRST_RET)
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? ? ? ? ? ? new_logic++;
+ ? ? ? ? ? ? ? }
+ ? ? ? }
+

"
1. The while loops need optimization. - This can definitely be simplified and made non-risky; this also needs some more error handling
2. About the power domains state machine: you have only one power state to move in and out of: it is called ON. If you do ON->CSWR->ON etc. attempting to program ON->CSWR->OSWR is NOT supported in OMAP and is an invitation for production team to sit and debug for a while before finding the use of invalid power states
"

Point 2 is a good point. The solution would be to implement a state machine in this function and/or omap_set_pwrdm_state, possibly using a platform specific handling function.

Any thought?

Regards,
Jean

Quoted 108 lines
arch/arm/mach-omap2/powerdomain.c +8 -0
+ ? ? ? new_func_pwrst = pwrdm_pwrst_to_func(pwrdm, new_pwrst, new_logic);
+
+ ? ? ? pr_debug("%s(%s, func_pwrst=%0x) returns %0x\n", __func__,
+ ? ? ? ? ? ? ? ?pwrdm->name, func_pwrst, new_func_pwrst);
+
+ ? ? ? return new_func_pwrst;
+}
+

?/* Types of sleep_switch used in omap_set_pwrdm_state */ ?#define FORCEWAKEUP_SWITCH ? ? 0
?#define LOWPOWERSTATE_SWITCH ? 1

arch/arm/mach-omap2/powerdomain.c +0 -0
@@ -563,36 +665,32 @@ int pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic)

?* @pwrdm: struct powerdomain * to set
?* @func_pwrst: power domain functional state, one of the PWRDM_FUNC_* macros ?*
- * This programs the pwrdm next functional state, sets the dependencies
- * and waits for the state to be applied.
+ * This looks for the more suited (or achievable) next functional power
+ * state, programs it, sets the dependencies and waits for the state to
+ * be applied to the power domain.
?*/
?int omap_set_pwrdm_state(struct powerdomain *pwrdm,
? ? ? ? ? ? ? ? ? ? ? ? enum pwrdm_func_state func_pwrst)
?{
- ? ? ? u8 curr_pwrst, next_pwrst;
- ? ? ? int pwrst = pwrdm_func_to_pwrst(pwrdm, func_pwrst);
- ? ? ? int logic = pwrdm_func_to_logic_pwrst(pwrdm, func_pwrst); ? ? ? ?int sleep_switch = -1, ret = 0, hwsup = 0;
+ ? ? ? int new_func_pwrst, next_func_pwrst, pwrst, logic;
+ ? ? ? u8 curr_pwrst;

- ? ? ? if (!pwrdm || IS_ERR(pwrdm) || (pwrst < 0) || (logic < 0)) {
- ? ? ? ? ? ? ? pr_debug("%s: invalid params: pwrdm=%p, func_pwrst=%0x\n",
- ? ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm, func_pwrst);
+ ? ? ? if (!pwrdm || IS_ERR(pwrdm)) {
+ ? ? ? ? ? ? ? pr_debug("%s: invalid params: pwrdm=%p\n", __func__, pwrdm); ? ? ? ? ? ? ? ?return -EINVAL;
? ? ? ?}

- ? ? ? pr_debug("%s: set func_pwrst %0x to pwrdm %s\n",
- ? ? ? ? ? ? ? ?__func__, func_pwrst, pwrdm->name);
+ ? ? ? pr_debug("%s(%s, func_pwrst=%0x)\n", __func__, pwrdm->name, func_pwrst);

? ? ? ?mutex_lock(&pwrdm->lock);

- ? ? ? while (!(pwrdm->pwrsts & (1 << pwrst))) {
- ? ? ? ? ? ? ? if (pwrst == PWRDM_POWER_OFF)
- ? ? ? ? ? ? ? ? ? ? ? goto out;
- ? ? ? ? ? ? ? pwrst--;
- ? ? ? }
+ ? ? ? new_func_pwrst = pwrdm_get_achievable_func_pwrst(pwrdm, func_pwrst);
+ ? ? ? pwrst = pwrdm_func_to_pwrst(pwrdm, new_func_pwrst);
+ ? ? ? logic = pwrdm_func_to_logic_pwrst(pwrdm, new_func_pwrst);

- ? ? ? next_pwrst = pwrdm_read_next_pwrst(pwrdm);
- ? ? ? if (next_pwrst == pwrst)
+ ? ? ? next_func_pwrst = pwrdm_read_next_func_pwrst(pwrdm);
+ ? ? ? if (new_func_pwrst == next_func_pwrst)
? ? ? ? ? ? ? ?goto out;

? ? ? ?curr_pwrst = pwrdm_read_pwrst(pwrdm);

arch/arm/mach-omap2/powerdomain.c +18 -6
@@ -607,13 +705,25 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm,
 ? ? ? ? ? ? ? ?}
 ? ? ? ?}
 
- ? ? ? if (logic != pwrdm_read_logic_retst(pwrdm))
- ? ? ? ? ? ? ? pwrdm_set_logic_retst(pwrdm, logic);
+ ? ? ? pr_debug("%s: set func_pwrst %0x (%0x,%0x) to pwrdm %s\n",
+ ? ? ? ? ? ? ? ?__func__, new_func_pwrst, pwrst, logic, pwrdm->name);
+
+ ? ? ? /* Trace the pwrdm desired target state */
+ ? ? ? trace_power_domain_target(pwrdm->name, new_func_pwrst,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? smp_processor_id());
+
+ ? ? ? /* Program next power state */
+ ? ? ? if (pwrst != pwrdm_func_to_pwrst(pwrdm, next_func_pwrst)) {
+ ? ? ? ? ? ? ? ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+ ? ? ? ? ? ? ? if (ret)
+ ? ? ? ? ? ? ? ? ? ? ? pr_err("%s: unable to set power state of powerdomain: %s\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm->name);
+ ? ? ? }
 
- ? ? ? ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
- ? ? ? if (ret)
- ? ? ? ? ? ? ? pr_err("%s: unable to set power state of powerdomain: %s\n",
- ? ? ? ? ? ? ? ? ? ? ?__func__, pwrdm->name);
+ ? ? ? /* Program RET logic state */
+ ? ? ? if ((pwrst == PWRDM_POWER_RET) &&
+ ? ? ? ? ? (logic != pwrdm_func_to_logic_pwrst(pwrdm, next_func_pwrst)))
+ ? ? ? ? ? ? ? pwrdm_set_logic_retst(pwrdm, logic);
 
 ? ? ? ?switch (sleep_switch) {

? ? ? ?case FORCEWAKEUP_SWITCH:

arch/arm/mach-omap2/powerdomain.h +1 -1
index d08c25d..9dd68ab 100644
@@ -247,6 +247,7 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 ?int omap2_pwrdm_func_to_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
 ?int omap2_pwrdm_func_to_logic_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
 ?int omap2_pwrdm_pwrst_to_func(struct powerdomain *pwrdm, u8 pwrst, u8 logic);
+int pwrdm_get_achievable_func_pwrst(struct powerdomain *pwrdm, u8 func_pwrst);
 
 ?int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
 ?int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
--

1.7.7.6

#17 lore raw

PATCH 5/8 ARM: OMAP2+: PM: introduce power domains achievable functional states

Quoted 5 lines · Jean Pihet

"
1. The while loops need optimization. - This can definitely be simplified and made non-risky; this also needs some more error handling

If you are interested using something like the following static int _match_pwrst(u32 pwrsts, u8 pwrst, u8 default_pwrst)

{
       bool found = true;
       int new_pwrst = pwrst;

       /* Search down */
       while (!(pwrsts & (1 << new_pwrst))) {
               if (new_pwrst == PWRDM_POWER_OFF) {
                       found = false;
                       break;
               }
               new_pwrst--;
       }

       if (found)
               goto done;

       /* Search up */
       new_pwrst = pwrst;
       while (!(pwrsts & (1 << new_pwrst))) {
               if (new_pwrst == default_pwrst)
                       break;
               new_pwrst++;
       }
done:
       return new_pwrst;
}

new_pwrst = _match_pwrst(pwrdm->pwrsts, pwrst,

                         PWRDM_POWER_ON);
new_logic = _match_pwrst(pwrdm->pwrsts_logic_ret, logic,
                         PWRDM_POWER_RET);

to achieve the same code..

Quoted 10 lines

2. About the power domains state machine: you have only one power state to move in and out of: it is called ON. If you do ON->CSWR->ON etc. attempting to program ON->CSWR->OSWR is NOT supported in OMAP and is an invitation for production team to sit and debug for a while before finding the use of invalid power states
"

Point 2 is a good point. The solution would be to implement a state machine in this function and/or omap_set_pwrdm_state, possibly using a platform specific handling function.

Point 2 is not completely accurate -> Lower pwr state transitions can indeed and is indeed
supported on OMAP4+. CSWR->OSWR->OFF is possible and omap_setpwrdm_state does indeed handle this. however going to OSWR->CSWR is possible only by OSWR->ON->CSWR.
this is again supported in code, however, in practice, we have found that certain IP blocks(in
personal experience, it was DSS) need IP specific additional work which is not easily doable..
so when we come out of suspend state, if the IP block has achieved a lower powerstate than
what was programmed, we just leave it as is.

Regards,
Nishanth Menon

author
#18 lore raw

PATCH v4 6/8 ARM: OMAP2+: PM: use the functional power states API for logic and memory

In reply to Jean Pihet

Since the power domains logic state is derived from the power domain functional state and is now programmed from omap_set_pwrdm_state, the calls to pwrdm_set_logic_retst are removed and the mpu_logic_state field is removed from the private data of the cpuidle and suspend code.

---
 arch/arm/mach-omap2/cpuidle44xx.c         |   11 ++---------
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |    6 +-----
 arch/arm/mach-omap2/pm24xx.c              |    5 +----
 arch/arm/mach-omap2/pm44xx.c              |   10 ++--------
 4 files changed, 6 insertions(+), 26 deletions(-)
arch/arm/mach-omap2/cpuidle44xx.c +2 -9
index 50c9082..221039a 100644
@@ -27,7 +27,6 @@
 /* Machine specific information */
 struct omap4_idle_statedata {
 	u32 cpu_state;
-	u32 mpu_logic_state;
 	u32 mpu_state;
 };
 
@@ -35,17 +34,14 @@ static struct omap4_idle_statedata omap4_idle_data[] = {
 	{
 		.cpu_state = PWRDM_FUNC_PWRST_ON,
 		.mpu_state = PWRDM_FUNC_PWRST_ON,
-		.mpu_logic_state = PWRDM_POWER_RET,
 	},
 	{
 		.cpu_state = PWRDM_FUNC_PWRST_OFF,
 		.mpu_state = PWRDM_FUNC_PWRST_CSWR,
-		.mpu_logic_state = PWRDM_POWER_RET,
 	},
 	{
 		.cpu_state = PWRDM_FUNC_PWRST_OFF,
-		.mpu_state = PWRDM_FUNC_PWRST_CSWR,
-		.mpu_logic_state = PWRDM_POWER_OFF,
+		.mpu_state = PWRDM_FUNC_PWRST_OSWR,
 	},
 };
 
@@ -95,16 +91,13 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
 	if (cx->cpu_state == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_enter();
 
-	pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
 	omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
 
 	/*
 	 * Call idle CPU cluster PM enter notifier chain
 	 * to save GIC and wakeupgen context.
 	 */
-	if (((cx->mpu_state == PWRDM_FUNC_PWRST_CSWR) ||
-	     (cx->mpu_state == PWRDM_FUNC_PWRST_OSWR)) &&
-	    (cx->mpu_logic_state == PWRDM_POWER_OFF))
+	if (cx->mpu_state == PWRDM_FUNC_PWRST_OSWR)
 			cpu_cluster_pm_enter();
 
 	omap4_enter_lowpower(dev->cpu, cx->cpu_state);
arch/arm/mach-omap2/omap-mpuss-lowpower.c +1 -5
index dd94a0e..c79cc0f 100644
@@ -232,7 +232,6 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 {
 	unsigned int save_state = 0;
 	unsigned int wakeup_cpu;
-	int mpuss_state;
 
 	if (omap_rev() == OMAP4430_REV_ES1_0)
 		return -ENXIO;
@@ -265,10 +264,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 	 * In MPUSS OSWR or device OFF, interrupt controller context is lost.
 	 */
 	mpuss_clear_prev_logic_pwrst();
-	mpuss_state = pwrdm_read_next_func_pwrst(mpuss_pd);
-	if (((mpuss_state == PWRDM_FUNC_PWRST_CSWR) ||
-	     (mpuss_state == PWRDM_FUNC_PWRST_OSWR)) &&
-	    (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
+	if (pwrdm_read_next_func_pwrst(mpuss_pd) == PWRDM_FUNC_PWRST_OSWR)
 		save_state = 2;
 
 	cpu_clear_prev_logic_pwrst(cpu);
arch/arm/mach-omap2/pm24xx.c +1 -4
index 0bed51e..fdb0767 100644
@@ -93,7 +93,6 @@ static int omap2_enter_full_retention(void)
 	 * Set MPU powerdomain's next power state to RETENTION;
 	 * preserve logic state during retention
 	 */
-	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
 	omap_set_pwrdm_state(mpu_pwrdm, PWRDM_FUNC_PWRST_CSWR);
 
 	/* Workaround to kill USB */
@@ -248,7 +247,7 @@ static void __init prcm_setup_regs(void)
 	 */
 	num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
 	for (i = 0; i < num_mem_banks; i++)
-		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
+		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_LOGIC_MEM_PWRST_RET);
 
 	/* Set CORE powerdomain's next power state to RETENTION */
 	omap_set_pwrdm_state(core_pwrdm, PWRDM_FUNC_PWRST_CSWR);
@@ -257,11 +256,9 @@ static void __init prcm_setup_regs(void)
 	 * Set MPU powerdomain's next power state to RETENTION;
 	 * preserve logic state during retention
 	 */
-	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
 	omap_set_pwrdm_state(mpu_pwrdm, PWRDM_FUNC_PWRST_CSWR);
 
 	/* Force-power down DSP, GFX powerdomains */
-
 	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
 	omap_set_pwrdm_state(pwrdm, PWRDM_FUNC_PWRST_OFF);
 	clkdm_sleep(dsp_clkdm);
arch/arm/mach-omap2/pm44xx.c +2 -8
index 98bb699..eb12d25 100644
@@ -28,7 +28,6 @@ struct power_state {
 	u32 next_state;
 #ifdef CONFIG_SUSPEND
 	u32 saved_state;
-	u32 saved_logic_state;
 #endif
 	struct list_head node;
 };
@@ -43,16 +42,12 @@ static int omap4_pm_suspend(void)
 	u32 cpu_id = smp_processor_id();
 
 	/* Save current powerdomain state */
-	list_for_each_entry(pwrst, &pwrst_list, node) {
+	list_for_each_entry(pwrst, &pwrst_list, node)
 		pwrst->saved_state = pwrdm_read_next_func_pwrst(pwrst->pwrdm);
-		pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm);
-	}
 
 	/* Set targeted power domain states by suspend */
-	list_for_each_entry(pwrst, &pwrst_list, node) {
+	list_for_each_entry(pwrst, &pwrst_list, node)
 		omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
-		pwrdm_set_logic_retst(pwrst->pwrdm, PWRDM_POWER_OFF);
-	}
 
 	/*
 	 * For MPUSS to hit power domain retention(CSWR or OSWR),
@@ -75,7 +70,6 @@ static int omap4_pm_suspend(void)
 			ret = -1;
 		}
 		omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
-		pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
 	}
 	if (ret)
 		pr_crit("Could not enter target state in pm_suspend\n");
Signature · 1 line
1.7.7.6
author
#19 lore raw

PATCH v4 7/8 ARM: OMAP2+: PM: use power domain functional state in stats counters

In reply to Jean Pihet

The PM code uses some counters to keep track of the power domains transitions, in order to provide the information to drivers (in pwrdm_get_context_loss_count) and to expose the information to sysfs for debug purpose.

This patch provides the information for each functional state.

---
 arch/arm/mach-omap2/pm-debug.c    |   15 ++++++++-------
 arch/arm/mach-omap2/powerdomain.c |   12 ++++++------
 arch/arm/mach-omap2/powerdomain.h |    4 ++--
 3 files changed, 16 insertions(+), 15 deletions(-)
arch/arm/mach-omap2/pm-debug.c +8 -7
index 814bcd9..13c00fb 100644
@@ -53,9 +53,10 @@ enum {
 	DEBUG_FILE_TIMERS,
 };
 
-static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
+static const char pwrdm_state_names[][PWRDM_MAX_FUNC_PWRSTS] = {
 	"OFF",
-	"RET",
+	"OSWR",
+	"CSWR",
 	"INA",
 	"ON"
 };
@@ -102,13 +103,13 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
 		strncmp(pwrdm->name, "dpll", 4) == 0)
 		return 0;
 
-	if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
+	if (pwrdm->state != pwrdm_read_func_pwrst(pwrdm))
 		printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
-			pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
+		       pwrdm->name, pwrdm->state, pwrdm_read_func_pwrst(pwrdm));
 
 	seq_printf(s, "%s (%s)", pwrdm->name,
 			pwrdm_state_names[pwrdm->state]);
-	for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
+	for (i = 0; i < PWRDM_MAX_FUNC_PWRSTS; i++)
 		seq_printf(s, ",%s:%d", pwrdm_state_names[i],
 			pwrdm->state_counter[i]);
 
@@ -137,7 +138,7 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
 	seq_printf(s, "%s (%s)", pwrdm->name,
 		pwrdm_state_names[pwrdm->state]);
 
-	for (i = 0; i < 4; i++)
+	for (i = 0; i < PWRDM_MAX_FUNC_PWRSTS; i++)
 		seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
 			pwrdm->state_timer[i]);
 
@@ -211,7 +212,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
 
 	t = sched_clock();
 
-	for (i = 0; i < 4; i++)
+	for (i = 0; i < PWRDM_MAX_FUNC_PWRSTS; i++)
 		pwrdm->state_timer[i] = 0;
 
 	pwrdm->timer = t;
arch/arm/mach-omap2/powerdomain.c +6 -6
index f94174b..875c6c4 100644
@@ -106,7 +106,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 	list_add(&pwrdm->node, &pwrdm_list);
 
 	/* Initialize the powerdomain's state counter */
-	for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
+	for (i = 0; i < PWRDM_MAX_FUNC_PWRSTS; i++)
 		pwrdm->state_counter[i] = 0;
 
 	pwrdm->ret_logic_off_counter = 0;
@@ -114,7 +114,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
 		pwrdm->ret_mem_off_counter[i] = 0;
 
 	pwrdm_wait_transition(pwrdm);
-	pwrdm->state = pwrdm_read_pwrst(pwrdm);
+	pwrdm->state = pwrdm_read_func_pwrst(pwrdm);
 	pwrdm->state_counter[pwrdm->state] = 1;
 
 	pr_debug("powerdomain: registered %s\n", pwrdm->name);
@@ -149,17 +149,17 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 	if (pwrdm == NULL)
 		return -EINVAL;
 
-	state = pwrdm_read_pwrst(pwrdm);
+	state = pwrdm_read_func_pwrst(pwrdm);
 
 	switch (flag) {
 	case PWRDM_STATE_NOW:
 		prev = pwrdm->state;
 		break;
 	case PWRDM_STATE_PREV:
-		prev = pwrdm_read_prev_pwrst(pwrdm);
+		prev = pwrdm_read_prev_func_pwrst(pwrdm);
 		if (pwrdm->state != prev)
 			pwrdm->state_counter[prev]++;
-		if (prev == PWRDM_POWER_RET)
+		if (prev == PWRDM_FUNC_PWRST_OSWR)
 			_update_logic_membank_counters(pwrdm);
 		/*
 		 * If the power domain did not hit the desired state,
@@ -1338,7 +1338,7 @@ int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
 		return -ENODEV;
 	}
 
-	count = pwrdm->state_counter[PWRDM_POWER_OFF];
+	count = pwrdm->state_counter[PWRDM_FUNC_PWRST_OFF];
 	count += pwrdm->ret_logic_off_counter;
 
 	for (i = 0; i < pwrdm->banks; i++)
arch/arm/mach-omap2/powerdomain.h +2 -2
index 9dd68ab..06fb396 100644
@@ -165,13 +165,13 @@ struct powerdomain {
 	struct list_head voltdm_node;
 	struct mutex lock;
 	int state;
-	unsigned state_counter[PWRDM_MAX_PWRSTS];
+	unsigned state_counter[PWRDM_MAX_FUNC_PWRSTS];
 	unsigned ret_logic_off_counter;
 	unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
 
 #ifdef CONFIG_PM_DEBUG
 	s64 timer;
-	s64 state_timer[PWRDM_MAX_PWRSTS];
+	s64 state_timer[PWRDM_MAX_FUNC_PWRSTS];
 #endif
 };
 
Signature · 1 line
1.7.7.6
author
#20 lore raw

PATCH v4 8/8 ARM: OMAP2+: PM debug: trace the functional power domains states

In reply to Jean Pihet

Trace the power domain transitions using the functional power states, which include the power and logic states.

While at it, fix the trace in the case a power domain did not hit the desired state, as reported by Paul Walmsley.

---
 arch/arm/mach-omap2/powerdomain.c |   15 +++++----------
 1 files changed, 5 insertions(+), 10 deletions(-)
arch/arm/mach-omap2/powerdomain.c +5 -10
index 875c6c4..f6885f9 100644
@@ -144,7 +144,7 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm)
 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 {
 
-	int prev, state, trace_state = 0;
+	int prev, next, state, trace_state;
 
 	if (pwrdm == NULL)
 		return -EINVAL;
@@ -165,10 +165,10 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 		 * If the power domain did not hit the desired state,
 		 * generate a trace event with both the desired and hit states
 		 */
-		if (state != prev) {
+		next = pwrdm_read_next_func_pwrst(pwrdm);
+		if (next != prev) {
 			trace_state = (PWRDM_TRACE_STATES_FLAG |
-				       ((state & OMAP_POWERSTATE_MASK) << 8) |
-				       ((prev & OMAP_POWERSTATE_MASK) << 0));
+				       (next << 8) | (prev << 0));
 			trace_power_domain_target(pwrdm->name, trace_state,
 						  smp_processor_id());
 		}
@@ -768,13 +768,8 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 	pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
 		 pwrdm->name, pwrst);
 
-	if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
-		/* Trace the pwrdm desired target state */
-		trace_power_domain_target(pwrdm->name, pwrst,
-					  smp_processor_id());
-		/* Program the pwrdm desired target state */
+	if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst)
 		ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
-	}
 
 	return ret;
 }
Signature · 1 line
1.7.7.6
author
#21 lore raw

v4 cover ARM: OMAP2+: PM: introduce the power domains functional states

In reply to Jean Pihet

Hi!

Quoted 16 lines · Jean Pihet

Here is a re-spin after some comments after an internal review and some testing on OMAP4 with device OFF support.

Implement the functional states for the power domains:
- unify the API to use the functional states,
- protect the power domain state change by a mutex in omap_set_pwrdm_state,
- introduce the functional states for power domains power states and logic power states, and the conversion functions between the functional and internal states,
- program the logic power state of power domains from the functional states, in omap_set_pwrdm_state
- convert the OMAP2/3/4 PM code to use the updated API,
- provide the power domains statistics by functional states,
- provide ftrace tracepoints with the functional state.

Quoted 4 lines

Based on mainline kernel 3.5.0-rc2.

Tested on OMAP3 Beagleboard, with suspend and cpuidle in RET and OFF modes.

Here is the latest version for anyone willing to look at it, or even better review and test it.

The latest code can be fetched from https://gitorious.org/jpihet/linux.
Please note that the tree also contains branches for the per-device PM QoS, OMAP4 device OFF and the misc fixes needed to allow OMAP4 to enter the low power modes.

Based on 3.5.0-rc6; tested with OMAP3&4 suspend/resume and OMAP3 cpuidle, using CSWR and OFF modes.

Here are the changes since the last version:
- changed the locking to a spinlock. Thanks to Ambresh K for reporting the issue,
- extended the locking to the next power state read (pwrdm_read_next_func_pwrst) and write (omap_set_pwrdm_state).

Regards,
Jean

Quoted 55 lines

History:
v4:
- reworked the code after internal review and testing with OMAP3&4 device OFF,
- fixed the tracepoints generation code,
- introduce a function that returns power domains achievable functional states, in order to return a valid state for power domains that only support some of the power states. Although it has been tested OK the code is in RFC state.

v3:
- fix a bug in OMAP3 cpuidle which prevented the IO wake-ups in PER

v2:
- add the logic power states,
- provide the power domains statistics by functional states

v1:
- initial implementation, in RFC state

Jean Pihet (8):
ARM: OMAP2+: PM: protect the power domain state change by a mutex
ARM: OMAP2+: PM: introduce power domains functional states
ARM: OMAP2+: PM: use the functional power states API
ARM: OMAP2+: PM: introduce power domains logic and memory functional
states
ARM: OMAP2+: PM: introduce power domains achievable functional states
ARM: OMAP2+: PM: use the functional power states API for logic and
memory
ARM: OMAP2+: PM: use power domain functional state in stats counters
ARM: OMAP2+: PM debug: trace the functional power domains states

 arch/arm/mach-omap2/cpuidle34xx.c          |   61 +++---
 arch/arm/mach-omap2/cpuidle44xx.c          |   28 +--
 arch/arm/mach-omap2/omap-hotplug.c         |    2 +-
 arch/arm/mach-omap2/omap-mpuss-lowpower.c  |   39 ++--
 arch/arm/mach-omap2/pm-debug.c             |   15 +-
 arch/arm/mach-omap2/pm.c                   |   62 -----
 arch/arm/mach-omap2/pm.h                   |    1 -
 arch/arm/mach-omap2/pm24xx.c               |   15 +-
 arch/arm/mach-omap2/pm34xx.c               |   78 +++---
 arch/arm/mach-omap2/pm44xx.c               |   18 +-
 arch/arm/mach-omap2/powerdomain-common.c   |  100 ++++++++
 arch/arm/mach-omap2/powerdomain.c          |  367 ++++++++++++++++++++++++++--
 arch/arm/mach-omap2/powerdomain.h          |  101 ++++++--
 arch/arm/mach-omap2/powerdomain2xxx_3xxx.c |    7 +
 arch/arm/mach-omap2/powerdomain44xx.c      |    3 +
 15 files changed, 653 insertions(+), 244 deletions(-)

--
1.7.7.6