Skip to contentSkip to conversation

ARM: OMAP2+: powerdomain/PM: convert to functional power states

PATCH New Paul Walmsley 5 participants 27 messages Dec 9, 2012 – Jan 29, 2013

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover ARM: OMAP2+: powerdomain/PM: convert to functional power states

Hi

This series converts the OMAP2+ powerdomain and PM code to use "functional power states" - high-level power states such as "OSWR", which reflect changes in multiple underlying registers, rather than expecting high-level PM code to program the registers directly. This is intended to reduce the complexity of the high-level PM code and to make it easier to implement register caching of the various powerdomain registers, some of which are quite slow to access.

- Paul

---

vmlinux object size
(delta in bytes from TEST_pm_cleanup_fixes_b_3.9 (2f8d7b1f0048df431ca226d81c5c27c4dd21953b)):

   text     data      bss    total  kernel
   +456      -56        0     +400  am33xx_only
   +448      -96        0     +352  n800_multi_omap2xxx
   +448      -96        0     +352  n800_only_a
      0        0        0        0  omap1_defconfig
      0        0        0        0  omap1_defconfig_1510innovator_only
      0        0        0        0  omap1_defconfig_5912osk_only
  +1180     -744        0     +436  omap2plus_defconfig
   +584      -72        0     +512  omap2plus_defconfig_2430sdp_only
  +1244     -808        0     +436  omap2plus_defconfig_cpupm
   +976    -1224        0     -248  omap2plus_defconfig_no_pm
   +844     -408        0     +436  omap2plus_defconfig_omap2_4_only
  +1088     -624        0     +464  omap2plus_defconfig_omap3_4_only
  +1292    -1232     -352     -292  rmk_omap3430_ldp_allnoconfig
   +916     -720        0     +196  rmk_omap3430_ldp_oldconfig
  +1292    -1232     -352     -292  rmk_omap4430_sdp_allnoconfig
   +840     -392        0     +448  rmk_omap4430_sdp_oldconfig

Boot-time memory difference
(delta in bytes from TEST_pm_cleanup_fixes_b_3.9 (2f8d7b1f0048df431ca226d81c5c27c4dd21953b))

  avail  rsrvd   high  freed  board          kconfig
    -8k     8k      .      .  2430sdp        omap2plus_defconfig
    -8k     8k      .      .  3517evm        omap2plus_defconfig
    -8k     8k      .      .  3530es3beagle  omap2plus_defconfig
    -8k     8k      .      .  3730beaglexm   omap2plus_defconfig
    -8k     8k      .      .  37xxevm        omap2plus_defconfig
    -8k     8k      .      .  4430es2panda   omap2plus_defconfig
    -8k     8k      .      .  4460pandaes    omap2plus_defconfig
    -8k     8k      .      .  cmt3517        omap2plus_defconfig

Jean Pihet (6):
ARM: OMAP2+: PM: introduce power domains functional states
ARM: OMAP2+: PM debug: trace the functional power domains states
ARM: OMAP2xxx: PM: convert to use the functional power states API
ARM: OMAP3xxx: PM: convert to use the functional power states API
ARM: OMAP44xx: PM: convert to use the functional power states API
ARM: OMAP2+: PM: use power domain functional state in stats counters

Paul Walmsley (6):
ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities
ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs
ARM: OMAP2+: powerdomain: add ability to test for supported power states
ARM: OMAP2+: powerdomain/PM: only program supported power states
ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init
ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain

 arch/arm/mach-omap2/common.h              |    7 
 arch/arm/mach-omap2/cpuidle34xx.c         |   95 +-
 arch/arm/mach-omap2/cpuidle44xx.c         |   32 -
 arch/arm/mach-omap2/omap-hotplug.c        |    2 
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   69 +-
 arch/arm/mach-omap2/pm-debug.c            |   46 -
 arch/arm/mach-omap2/pm.h                  |    2 
 arch/arm/mach-omap2/pm24xx.c              |   33 -
 arch/arm/mach-omap2/pm34xx.c              |  188 +++-
 arch/arm/mach-omap2/pm44xx.c              |   47 +
 arch/arm/mach-omap2/powerdomain.c         | 1235 +++++++++++++++++------------
 arch/arm/mach-omap2/powerdomain.h         |   69 +-
 12 files changed, 1040 insertions(+), 785 deletions(-)
#1 lore raw

PATCH 1/12 ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities

Add several functions to report on whether powerdomains can change their power state or logic retention power state, and whether those abilities can be controlled by the kernel. This code is used in subsequent patches that add the functional power state code.

---
 arch/arm/mach-omap2/powerdomain.c |   56 +++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
arch/arm/mach-omap2/powerdomain.c +56 -0
index 2a5f15b..94b89a25 100644
@@ -203,6 +203,62 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
 	return 0;
 }
 
+/**
+ * _pwrdm_pwrst_is_controllable - can software change the powerdomain pwrst?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the kernel can program the power state that the powerdomain
+ * @pwrdm should enter next, return 1; otherwise, return 0.
+ */
+static bool _pwrdm_pwrst_is_controllable(struct powerdomain *pwrdm)
+{
+	return (!pwrdm->pwrsts || pwrdm->pwrsts == PWRSTS_ON) ? 0 : 1;
+}
+
+/**
+ * _pwrdm_pwrst_can_change - can the power state of @pwrdm change?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the power state of the powerdomain represented by @pwrdm can
+ * change (i.e., is not always on), and the kernel has some way to
+ * detect this, return 1; otherwise, return 0.  XXX The current
+ * implementation of this is based on an assumption and has not been
+ * verified against all OMAPs.
+ */
+static bool _pwrdm_pwrst_can_change(struct powerdomain *pwrdm)
+{
+	return _pwrdm_pwrst_is_controllable(pwrdm);
+}
+
+/**
+ * _pwrdm_logic_retst_is_controllable - can software change the logic retst?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the kernel can program the power state that the powerdomain
+ * @pwrdm logic should enter when the @pwrdm enters the RETENTION
+ * power state, return 1; otherwise, return 0.
+ */
+static bool _pwrdm_logic_retst_is_controllable(struct powerdomain *pwrdm)
+{
+	return (!pwrdm->pwrsts_logic_ret ||
+		pwrdm->pwrsts_logic_ret == PWRSTS_RET) ? 0 : 1;
+}
+
+/**
+ * _pwrdm_logic_retst_can_change - can the logic retst change on @pwrdm?
+ * @pwrdm: struct powerdomain * to test
+ *
+ * If the logic powerstate for the powerdomain represented by @pwrdm
+ * can ever be something other than the powerdomain's powerstate, and
+ * the kernel has some way to detect this, return 1; otherwise, return
+ * 0.  XXX The current implementation of this is based on an
+ * assumption and has not been verified against all OMAPs.
+ */
+static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm)
+{
+	return _pwrdm_logic_retst_is_controllable(pwrdm);
+}
+
 /* Public functions */
 
 /**
#2 lore raw

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

In reply to Paul Walmsley

From: Jean Pihet <[email protected]>

Introduce the functional states for power domains, which include the power states and the logic states.
This patch provides the API functions to set and read the power domains functional state and internal functions to convert between the functional (i.e. logical) and the internal (or registers) values.

In the new API only the functions pwrdm_set_next_fpwrst() and pwrdm_set_fpwrst() shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters.

Note about the power domains allowed states:
Power domains have varied capabilities, as defined by the value of the pwrsts and pwrsts_logic_ret fields of the powerdomain struct. When reading or setting a low power state such as OFF/RET, a specific requested state may not be supported on the given power domain. In the states conversion functions a power or logic 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. An iteration function is used, as suggested by Rajendra Nayak <[email protected]> This function is temporary and will be removed later in the series.

This functionality brings consistency in the functional power states core code and acts as a guard against hardware implementations discrepancies, e.g. some power domains only support the RET logic state although reading the logic state registers (previous, current and next) always returns OFF. The DSS power domain on OMAP3 is an example.

Cc Tero Kristo <[email protected]>
Cc Rajendra Nayak <[email protected]>
Cc Nishanth Menon <[email protected]>

[paul at pwsan.com: add offset for functional powerstates so it's not
possible to confuse them with the old API; use one fn to convert func pwrsts to low-level hardware bits; skip hardware reads when hardware logic retst and logic pwrst bits are missing; fix kerneldoc and commit message; remove unnecessary PWRDM_LOGIC_MEM_PWRST_* macros; combine spinlock patch into this patch; expand the number of operations which take the spinlock]

---
 arch/arm/mach-omap2/powerdomain.c |  525 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   33 ++
 2 files changed, 553 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/powerdomain.c +521 -4
index 94b89a25..18f33de 100644
@@ -1,7 +1,7 @@
 /*
  * OMAP powerdomain control
  *
- * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2011-2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -44,12 +44,19 @@ enum {
 	PWRDM_STATE_PREV,
 };
 
-
 /* pwrdm_list contains all registered struct powerdomains */
 static LIST_HEAD(pwrdm_list);
 
 static struct pwrdm_ops *arch_pwrdm;
 
+/*
+ * _fpwrst_names: human-readable functional powerstate names - should match
+ *    the enum pwrdm_func_state order and names
+ */
+static const char * const _fpwrst_names[] = {
+	"OFF", "OSWR", "CSWR", "INACTIVE", "ON"
+};
+
 /* Private functions */
 
 static struct powerdomain *_pwrdm_lookup(const char *name)
@@ -145,7 +152,6 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm)
 
 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 {
-
 	int prev, next, state, trace_state = 0;
 
 	if (pwrdm == NULL)
@@ -259,6 +265,309 @@ static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm)
 	return _pwrdm_logic_retst_is_controllable(pwrdm);
 }
 
+/**
+ * _match_pwrst: determine the closest supported power state
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point
+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Search down then up for a valid state from a list of allowed
+ * states.  Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * Returns the matching allowed state.  XXX Deprecated.  The software
+ * should not try to program unsupported powerstates.
+ */
+static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max)
+{
+	int found = 1, new_pwrst = pwrst;
+
+	/*
+	 * If the power domain does not allow any state programmation
+	 * return the max state which is always allowed
+	 */
+	if (!pwrsts)
+		return max;
+
+	/*
+	 * Search lower: if the requested state is not supported
+	 * try the lower states, stopping at the minimum allowed
+	 * state
+	 */
+	while (!(pwrsts & (1 << new_pwrst))) {
+		if (new_pwrst <= min) {
+			found = 0;
+			break;
+		}
+		new_pwrst--;
+	}
+
+	/*
+	 * Search higher: if no lower state found fallback to the higher
+	 * states, stopping@the maximum allowed state
+	 */
+	if (!found) {
+		new_pwrst = pwrst;
+		while (!(pwrsts & (1 << new_pwrst))) {
+			if (new_pwrst >= max) {
+				new_pwrst = max;
+				break;
+			}
+			new_pwrst++;
+		}
+	}
+
+	return new_pwrst;
+}
+
+/**
+ * _pwrdm_fpwrst_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @fpwrst: functional power state
+ * @pwrdm_pwrst: ptr to u8 to return the power state in
+ * @logic_retst: ptr to u8 to return the logic retention state in
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
+				  u8 *pwrdm_pwrst, u8 *logic_retst)
+{
+	if (!pwrdm || !pwrdm_pwrst || !logic_retst)
+		return -EINVAL;
+
+	switch (fpwrst) {
+	case PWRDM_FUNC_PWRST_ON:
+		*pwrdm_pwrst = PWRDM_POWER_ON;
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_INACTIVE:
+		*pwrdm_pwrst = PWRDM_POWER_INACTIVE;
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_CSWR:
+		*pwrdm_pwrst = PWRDM_POWER_RET;
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_OSWR:
+		*pwrdm_pwrst = PWRDM_POWER_RET;
+		*logic_retst = PWRDM_POWER_OFF;
+		break;
+	case PWRDM_FUNC_PWRST_OFF:
+		*pwrdm_pwrst = PWRDM_POWER_OFF;
+		/*
+		 * logic_retst is set to PWRDM_POWER_RET in this case
+		 * since the actual value does not matter, and because
+		 * some powerdomains don't support a logic_retst of
+		 * OFF.  XXX Maybe there's some way to indicate a
+		 * 'don't care' value here?
+		 */
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* XXX deprecated */
+	*pwrdm_pwrst = _match_pwrst(pwrdm->pwrsts, *pwrdm_pwrst,
+				    PWRDM_POWER_OFF, PWRDM_POWER_ON);
+
+	*logic_retst = _match_pwrst(pwrdm->pwrsts_logic_ret, *logic_retst,
+				    PWRDM_POWER_OFF, PWRDM_POWER_RET);
+
+	pr_debug("powerdomain %s: convert fpwrst %0x to pwrst %0x\n",
+		 pwrdm->name, fpwrst, *pwrdm_pwrst);
+
+	return 0;
+}
+
+/**
+ * _pwrdm_pwrst_to_fpwrst - Convert internal (i.e. registers) to
+ * functional (i.e. logical) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @pwrst: internal powerdomain power state
+ * @logic: internal powerdomain logic power state
+ * @fpwrst: pointer to a u8 to store the corresponding functional power state to
+ *
+ * Returns the functional power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.  @pwrdm, @logic, and @pwrst
+ * are passed in, along with a pointer to the location to store the fpwrst to
+ * in @fpwrst.
+ */
+static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,
+				  u8 *fpwrst)
+{
+	if (!pwrdm || !fpwrst)
+		return -EINVAL;
+
+	switch (pwrst) {
+	case PWRDM_POWER_ON:
+		*fpwrst = PWRDM_FUNC_PWRST_ON;
+		break;
+	case PWRDM_POWER_INACTIVE:
+		*fpwrst = PWRDM_FUNC_PWRST_INACTIVE;
+		break;
+	case PWRDM_POWER_RET:
+		if (logic == PWRDM_POWER_OFF)
+			*fpwrst = PWRDM_FUNC_PWRST_OSWR;
+		else if (logic == PWRDM_POWER_RET)
+			*fpwrst = PWRDM_FUNC_PWRST_CSWR;
+		else
+			return -EINVAL;
+		break;
+	case PWRDM_POWER_OFF:
+		*fpwrst = PWRDM_FUNC_PWRST_OFF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	pr_debug("powerdomain: convert pwrst (%0x,%0x) to fpwrst %0x\n",
+		 pwrst, logic, *fpwrst);
+
+	return 0;
+}
+
+/**
+ * _set_logic_retst_and_pwrdm_pwrst - program logic retst and pwrdm next pwrst
+ * @pwrdm: struct powerdomain * to program
+ * @logic: logic retention state to attempt to program
+ * @pwrst: powerdomain next-power-state to program
+ *
+ * Program the next-power-state and logic retention power state of the
+ * powerdomain represented by @pwrdm to @pwrst and @logic,
+ * respectively.  If the powerdomain next-power-state is not
+ * software-controllable, returns 0; otherwise, passes along the
+ * return value from pwrdm_set_logic_retst() if there is an error
+ * returned by that function, otherwise, passes along the return value
+ * from pwrdm_set_next_pwrst()
+ */
+static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
+					    u8 logic, u8 pwrst)
+{
+	int ret;
+
+	if (!_pwrdm_pwrst_is_controllable(pwrdm))
+		return 0;
+
+	if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET) {
+		ret = pwrdm_set_logic_retst(pwrdm, logic);
+		if (ret) {
+			pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
+			       __func__, logic, pwrdm->name);
+			return ret;
+		}
+	}
+
+	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state %0x of powerdomain: %s\n",
+		       __func__, pwrst, pwrdm->name);
+
+	return ret;
+}
+
+/**
+ * _pwrdm_read_next_fpwrst - get next powerdomain func power state (lockless)
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Caller must hold @pwrdm->_lock.  Returns -EINVAL if the powerdomain
+ * pointer is null or returns the next power state upon success.
+ */
+static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
+{
+	int next_pwrst, next_logic, ret;
+	u8 fpwrst;
+
+	if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst)
+		return -EINVAL;
+
+	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
+	if (next_pwrst < 0)
+		return next_pwrst;
+
+	next_logic = next_pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_logic_pwrst) {
+		next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+		if (next_logic < 0)
+			return next_logic;
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+
+	return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_read_fpwrst - get current func powerdomain power state (lockless)
+ * @pwrdm: struct powerdomain * to get current functional 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.
+ */
+static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)
+{
+	int pwrst, logic_pwrst, ret;
+	u8 fpwrst;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
+	if (pwrst < 0)
+		return pwrst;
+
+	logic_pwrst = pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_logic_pwrst) {
+		logic_pwrst = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+		if (logic_pwrst < 0)
+			return logic_pwrst;
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+
+	return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_read_prev_fpwrst - get previous powerdomain func pwr state (lockless)
+ * @pwrdm: struct powerdomain * to get previous functional power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous functional power state upon success.
+ */
+static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
+{
+	int ret = -EINVAL;
+	int pwrst, logic_pwrst;
+	u8 fpwrst;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	pwrst = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
+	if (pwrst < 0)
+		return pwrst;
+
+	logic_pwrst = pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_prev_logic_pwrst) {
+		logic_pwrst = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
+		if (logic_pwrst < 0)
+			return logic_pwrst;
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+
+	return (ret) ? ret : fpwrst;
+}
+
 /* Public functions */
 
 /**
@@ -620,7 +929,7 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 	if (!pwrdm)
 		return -EINVAL;
 
-	if (pwrdm->pwrsts == PWRSTS_ON)
+	if (!_pwrdm_pwrst_can_change(pwrdm))
 		return PWRDM_POWER_ON;
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
@@ -1213,3 +1522,211 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
 
 	return 0;
 }
+
+/* Public functions for functional power state handling */
+
+/**
+ * pwrdm_convert_fpwrst_to_name - return the name of a functional power state
+ * @fpwrst: functional power state to return the name of
+ *
+ * Return a pointer to a string with the human-readable name of the
+ * functional power state (e.g., "ON", "CSWR", etc.)  Intended for use
+ * in debugging.  Returns NULL if @fpwrst is outside the range of the
+ * known functional power states.
+ */
+const char *pwrdm_convert_fpwrst_to_name(u8 fpwrst)
+{
+	if (fpwrst < PWRDM_FPWRST_OFFSET || fpwrst >= PWRDM_MAX_FUNC_PWRSTS)
+		return NULL;
+
+	return _fpwrst_names[fpwrst - PWRDM_FPWRST_OFFSET];
+}
+
+/**
+ * pwrdm_set_next_fpwrst - set next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the powerdomain @pwrdm's next power state to @fpwrst.  The
+ * powerdomain may not enter this state immediately if the
+ * preconditions for this state have not been satisfied.  Returns
+ * -EINVAL if the powerdomain pointer is null or if the power state is
+ * invalid for the powerdomin, or returns 0 upon success.
+ */
+int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
+{
+	u8 pwrst, logic;
+	int ret;
+
+	if (!pwrdm || IS_ERR(pwrdm))
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_is_controllable(pwrdm))
+		return 0;
+
+	ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+	if (ret)
+		return ret;
+
+	pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst,
+		 pwrdm->name);
+
+	pwrdm_lock(pwrdm);
+	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
+/**
+ * pwrdm_read_next_fpwrst - 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_fpwrst(struct powerdomain *pwrdm)
+{
+	int next_pwrst, next_logic, ret;
+	u8 fpwrst;
+
+	if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst)
+		return -EINVAL;
+
+	pwrdm_lock(pwrdm);
+
+	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
+	if (next_pwrst < 0) {
+		ret = next_pwrst;
+		goto prnf_out;
+	}
+
+	next_logic = next_pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_logic_pwrst) {
+		next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+		if (next_logic < 0) {
+			ret = next_logic;
+			goto prnf_out;
+		}
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+
+prnf_out:
+	pwrdm_unlock(pwrdm);
+
+	return (ret) ? ret : fpwrst;
+}
+
+/**
+ * pwrdm_set_fpwrst - program next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: 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 pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
+{
+	u8 next_fpwrst, pwrst, logic, sleep_switch;
+	int ret = 0;
+	bool hwsup;
+
+	if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm ||
+	    !arch_pwrdm->pwrdm_read_pwrst)
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_is_controllable(pwrdm))
+		return 0;
+
+	ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+	if (ret)
+		return -EINVAL;
+
+	pr_debug("%s: pwrdm %s: set fpwrst %0x\n", __func__, pwrdm->name,
+		 fpwrst);
+
+	pwrdm_lock(pwrdm);
+
+	/*
+	 * XXX quite heavyweight for what this is intended to do; the
+	 * next fpwrst should simply be cached
+	 */
+	next_fpwrst = _pwrdm_read_next_fpwrst(pwrdm);
+	if (next_fpwrst == fpwrst)
+		goto psf_out;
+
+	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, pwrst,
+							    &hwsup);
+
+	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state of powerdomain: %s\n",
+		       __func__, pwrdm->name);
+
+	_pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
+
+psf_out:
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
+/**
+ * pwrdm_read_fpwrst - get current functional powerdomain power state
+ * @pwrdm: struct powerdomain * to get current functional 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_fpwrst(struct powerdomain *pwrdm)
+{
+	int ret;
+
+	if (!pwrdm || !arch_pwrdm)
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	if (!arch_pwrdm->pwrdm_read_pwrst)
+		return -EINVAL;
+
+	pwrdm_lock(pwrdm);
+	ret = _pwrdm_read_fpwrst(pwrdm);
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
+/**
+ * pwrdm_read_prev_fpwrst - get previous powerdomain functional power state
+ * @pwrdm: struct powerdomain * to get previous functional power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous functional power state upon success.
+ */
+int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
+{
+	int ret = -EINVAL;
+
+	if (!pwrdm || !arch_pwrdm)
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	if (!arch_pwrdm->pwrdm_read_prev_pwrst)
+		return -EINVAL;
+
+	pwrdm_lock(pwrdm);
+	ret = _pwrdm_read_prev_fpwrst(pwrdm);
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
arch/arm/mach-omap2/powerdomain.h +32 -1
index 842ba46..be835ff 100644
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3/4 powerdomain control
  *
- * Copyright (C) 2007-2008, 2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010-2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Paul Walmsley
@@ -23,6 +23,29 @@
 
 #include "voltage.h"
 
+/*
+ * PWRDM_FPWRST_OFFSET: offset of the first functional power state
+ * from 0.  This offset can be subtracted from the functional power
+ * state macros to produce offsets suitable for array indices, for
+ * example.  The intention behind the addition of this offset is to
+ * prevent functional power states from accidentally being confused
+ * with the low-level, hardware power states.
+ */
+#define PWRDM_FPWRST_OFFSET		0x80
+
+/*
+ * Powerdomain functional power states, used by the external API functions
+ * These must match the order and names in _fpwrst_names[]
+ */
+enum pwrdm_func_state {
+	PWRDM_FUNC_PWRST_OFF		= PWRDM_FPWRST_OFFSET,
+	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 */
+};
+
 /* Powerdomain basic power states */
 #define PWRDM_POWER_OFF		0x0
 #define PWRDM_POWER_RET		0x1
@@ -238,6 +261,14 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
 
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);
 
+extern const char *pwrdm_convert_fpwrst_to_name(u8 fpwrst);
+extern int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst);
+extern int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm);
+extern int pwrdm_set_fpwrst(struct powerdomain *pwrdm,
+			    enum pwrdm_func_state fpwrst);
+extern int pwrdm_read_fpwrst(struct powerdomain *pwrdm);
+extern int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm);
+
 extern void omap242x_powerdomains_init(void);
 extern void omap243x_powerdomains_init(void);
 extern void omap3xxx_powerdomains_init(void);
#3 lore raw

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

Hi Paul,

Quoted 55 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

Introduce the functional states for power domains, which include the power states and the logic states.
This patch provides the API functions to set and read the power domains functional state and internal functions to convert between the functional (i.e. logical) and the internal (or registers) values.

In the new API only the functions pwrdm_set_next_fpwrst() and pwrdm_set_fpwrst() shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters.

Note about the power domains allowed states:
Power domains have varied capabilities, as defined by the value of the pwrsts and pwrsts_logic_ret fields of the powerdomain struct. When reading or setting a low power state such as OFF/RET, a specific requested state may not be supported on the given power domain. In the states conversion functions a power or logic 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. An iteration function is used, as suggested by Rajendra Nayak <[email protected]> This function is temporary and will be removed later in the series.

This functionality brings consistency in the functional power states core code and acts as a guard against hardware implementations discrepancies, e.g. some power domains only support the RET logic state although reading the logic state registers (previous, current and next) always returns OFF. The DSS power domain on OMAP3 is an example.

Cc Tero Kristo <[email protected]>
Cc Rajendra Nayak <[email protected]>
Cc Nishanth Menon <[email protected]>

[paul at pwsan.com: add offset for functional powerstates so it's not
possible to confuse them with the old API; use one fn to convert func pwrsts to low-level hardware bits; skip hardware reads when hardware logic retst and logic pwrst bits are missing; fix kerneldoc and commit message; remove unnecessary PWRDM_LOGIC_MEM_PWRST_* macros; combine spinlock patch into this patch; expand the number of operations which take the spinlock]

---
 arch/arm/mach-omap2/powerdomain.c |  525
+++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   33 ++
 2 files changed, 553 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/powerdomain.c +0 -0
index 94b89a25..18f33de 100644

arch/arm/mach-omap2/powerdomain.c line 1

Quoted 1 line
arch/arm/mach-omap2/powerdomain.c +0 -0
@@ -1,7 +1,7 @@
 

...

+/**

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 279

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
+ * _match_pwrst: determine the closest supported power state
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point
+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Search down then up for a valid state from a list of allowed
+ * states.  Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * Returns the matching allowed state.  XXX Deprecated.  The software
+ * should not try to program unsupported powerstates.

Why is this new code already deprecated? Does this require a rewrite?

+ */

Quoted 83 lines
arch/arm/mach-omap2/powerdomain.c +82 -0
+static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max)
+{
+       int found = 1, new_pwrst = pwrst;
+
+       /*
+        * If the power domain does not allow any state programmation
+        * return the max state which is always allowed
+        */
+       if (!pwrsts)
+               return max;
+
+       /*
+        * Search lower: if the requested state is not supported
+        * try the lower states, stopping at the minimum allowed
+        * state
+        */
+       while (!(pwrsts & (1 << new_pwrst))) {
+               if (new_pwrst <= min) {
+                       found = 0;
+                       break;
+               }
+               new_pwrst--;
+       }
+
+       /*
+        * Search higher: if no lower state found fallback to the higher
+        * states, stopping at the maximum allowed state
+        */
+       if (!found) {
+               new_pwrst = pwrst;
+               while (!(pwrsts & (1 << new_pwrst))) {
+                       if (new_pwrst >= max) {
+                               new_pwrst = max;
+                               break;
+                       }
+                       new_pwrst++;
+               }
+       }
+
+       return new_pwrst;
+}
+
+/**
+ * _pwrdm_fpwrst_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @fpwrst: functional power state
+ * @pwrdm_pwrst: ptr to u8 to return the power state in
+ * @logic_retst: ptr to u8 to return the logic retention state in
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
+                                 u8 *pwrdm_pwrst, u8 *logic_retst)
+{
+       if (!pwrdm || !pwrdm_pwrst || !logic_retst)
+               return -EINVAL;
+
+       switch (fpwrst) {
+       case PWRDM_FUNC_PWRST_ON:
+               *pwrdm_pwrst = PWRDM_POWER_ON;
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       case PWRDM_FUNC_PWRST_INACTIVE:
+               *pwrdm_pwrst = PWRDM_POWER_INACTIVE;
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       case PWRDM_FUNC_PWRST_CSWR:
+               *pwrdm_pwrst = PWRDM_POWER_RET;
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       case PWRDM_FUNC_PWRST_OSWR:
+               *pwrdm_pwrst = PWRDM_POWER_RET;
+               *logic_retst = PWRDM_POWER_OFF;
+               break;
+       case PWRDM_FUNC_PWRST_OFF:
+               *pwrdm_pwrst = PWRDM_POWER_OFF;
+               /*
+                * logic_retst is set to PWRDM_POWER_RET in this case
+                * since the actual value does not matter, and because
+                * some powerdomains don't support a logic_retst of

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 372

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+                * OFF.  XXX Maybe there's some way to indicate a
+                * 'don't care' value here?
+                */
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* XXX deprecated */

Same here

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 383

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
+       *pwrdm_pwrst = _match_pwrst(pwrdm->pwrsts, *pwrdm_pwrst,
+                                   PWRDM_POWER_OFF, PWRDM_POWER_ON);
+
+       *logic_retst = _match_pwrst(pwrdm->pwrsts_logic_ret, *logic_retst,
+                                   PWRDM_POWER_OFF, PWRDM_POWER_RET);
+
+       pr_debug("powerdomain %s: convert fpwrst %0x to pwrst %0x\n",
+                pwrdm->name, fpwrst, *pwrdm_pwrst);
+
+       return 0;
+}

Thanks & regards,
Jean
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121212/e558e7e1/attachment-0001.html>

#4 lore raw

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

Hi

(redacted some context)

Quoted 16 lines · Jean Pihet

On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <[email protected]> wrote:

+/**

Quoted 12 lines

+ * _match_pwrst: determine the closest supported power state
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point
+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Search down then up for a valid state from a list of allowed
+ * states. Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * Returns the matching allowed state. XXX Deprecated. The software
+ * should not try to program unsupported powerstates.

Quoted 1 line

Why is this new code already deprecated? Does this require a rewrite?

The reason why is documented in the above comment. The kernel should not attempt to program power states that the hardware doesn't support. Our existing code will program unrequested power states, and that isn't predictable behavior. If the kernel attempts to program a powerdomain to the CSWR power state, and the powerdomain doesn't support that state, it shouldn't silently program a different power state and return success. It should return an error, since the calling code shouldn't have tried to program that power state in the first place.

One of the subsequent patches removes this behavior and this code. It's only being kept to ensure an orderly, functional kernel from one patch series to the next.

- Paul

#5 lore raw

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

In reply to Paul Walmsley
Quoted 147 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

Introduce the functional states for power domains, which include the power states and the logic states.
This patch provides the API functions to set and read the power domains functional state and internal functions to convert between the functional (i.e. logical) and the internal (or registers) values.

In the new API only the functions pwrdm_set_next_fpwrst() and pwrdm_set_fpwrst() shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters.

Note about the power domains allowed states:
Power domains have varied capabilities, as defined by the value of the pwrsts and pwrsts_logic_ret fields of the powerdomain struct. When reading or setting a low power state such as OFF/RET, a specific requested state may not be supported on the given power domain. In the states conversion functions a power or logic 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. An iteration function is used, as suggested by Rajendra Nayak <[email protected]> This function is temporary and will be removed later in the series.

This functionality brings consistency in the functional power states core code and acts as a guard against hardware implementations discrepancies, e.g. some power domains only support the RET logic state although reading the logic state registers (previous, current and next) always returns OFF. The DSS power domain on OMAP3 is an example.

Cc Tero Kristo <[email protected]>
Cc Rajendra Nayak <[email protected]>
Cc Nishanth Menon <[email protected]>

[paul at pwsan.com: add offset for functional powerstates so it's not
possible to confuse them with the old API; use one fn to convert func pwrsts to low-level hardware bits; skip hardware reads when hardware logic retst and logic pwrst bits are missing; fix kerneldoc and commit message; remove unnecessary PWRDM_LOGIC_MEM_PWRST_* macros; combine spinlock patch into this patch; expand the number of operations which take the spinlock]

---
 arch/arm/mach-omap2/powerdomain.c |  525 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   33 ++
 2 files changed, 553 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/powerdomain.c +62 -3
index 94b89a25..18f33de 100644
@@ -1,7 +1,7 @@
 /*
  * OMAP powerdomain control
  *
- * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2011-2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Written by Paul Walmsley
@@ -44,12 +44,19 @@ enum {
 	PWRDM_STATE_PREV,
 };
 
-
 /* pwrdm_list contains all registered struct powerdomains */
 static LIST_HEAD(pwrdm_list);
 
 static struct pwrdm_ops *arch_pwrdm;
 
+/*
+ * _fpwrst_names: human-readable functional powerstate names - should match
+ *    the enum pwrdm_func_state order and names
+ */
+static const char * const _fpwrst_names[] = {
+	"OFF", "OSWR", "CSWR", "INACTIVE", "ON"
+};
+
 /* Private functions */
 
 static struct powerdomain *_pwrdm_lookup(const char *name)
@@ -145,7 +152,6 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm)
 
 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 {
-
 	int prev, next, state, trace_state = 0;
 
 	if (pwrdm == NULL)
@@ -259,6 +265,309 @@ static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm)
 	return _pwrdm_logic_retst_is_controllable(pwrdm);
 }
 
+/**
+ * _match_pwrst: determine the closest supported power state
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point
+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Search down then up for a valid state from a list of allowed
+ * states.  Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * Returns the matching allowed state.  XXX Deprecated.  The software
+ * should not try to program unsupported powerstates.
+ */
+static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max)
+{
+	int found = 1, new_pwrst = pwrst;
+
+	/*
+	 * If the power domain does not allow any state programmation
+	 * return the max state which is always allowed
+	 */
+	if (!pwrsts)
+		return max;
+
+	/*
+	 * Search lower: if the requested state is not supported
+	 * try the lower states, stopping at the minimum allowed
+	 * state
+	 */
+	while (!(pwrsts & (1 << new_pwrst))) {
+		if (new_pwrst <= min) {
+			found = 0;
+			break;
+		}
+		new_pwrst--;
+	}
+
+	/*
+	 * Search higher: if no lower state found fallback to the higher
+	 * states, stopping at the maximum allowed state
+	 */
+	if (!found) {
+		new_pwrst = pwrst;
+		while (!(pwrsts & (1 << new_pwrst))) {
+			if (new_pwrst >= max) {
+				new_pwrst = max;
+				break;
+			}
+			new_pwrst++;
+		}
+	}
+
+	return new_pwrst;

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 330

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+}
+
+/**
+ * _pwrdm_fpwrst_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @fpwrst: functional power state
+ * @pwrdm_pwrst: ptr to u8 to return the power state in
+ * @logic_retst: ptr to u8 to return the logic retention state in
+ *

I believe this is internal state, right? it would be good to specify that as well here.

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 331

Quoted 1 line
arch/arm/mach-omap2/powerdomain.c +1 -0
+ * Returns the internal power state value for the power domain,

This seems to be wrong, as this funtion always returns err or 0.

Quoted 54 lines

or
+ * -EINVAL in case of invalid parameters passed in.
+ */

arch/arm/mach-omap2/powerdomain.c +51 -0
+static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
+				  u8 *pwrdm_pwrst, u8 *logic_retst)
+{
+	if (!pwrdm || !pwrdm_pwrst || !logic_retst)
+		return -EINVAL;
+
+	switch (fpwrst) {
+	case PWRDM_FUNC_PWRST_ON:
+		*pwrdm_pwrst = PWRDM_POWER_ON;
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_INACTIVE:
+		*pwrdm_pwrst = PWRDM_POWER_INACTIVE;
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_CSWR:
+		*pwrdm_pwrst = PWRDM_POWER_RET;
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	case PWRDM_FUNC_PWRST_OSWR:
+		*pwrdm_pwrst = PWRDM_POWER_RET;
+		*logic_retst = PWRDM_POWER_OFF;
+		break;
+	case PWRDM_FUNC_PWRST_OFF:
+		*pwrdm_pwrst = PWRDM_POWER_OFF;
+		/*
+		 * logic_retst is set to PWRDM_POWER_RET in this case
+		 * since the actual value does not matter, and because
+		 * some powerdomains don't support a logic_retst of
+		 * OFF.  XXX Maybe there's some way to indicate a
+		 * 'don't care' value here?
+		 */
+		*logic_retst = PWRDM_POWER_RET;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* XXX deprecated */
+	*pwrdm_pwrst = _match_pwrst(pwrdm->pwrsts, *pwrdm_pwrst,
+				    PWRDM_POWER_OFF, PWRDM_POWER_ON);
+
+	*logic_retst = _match_pwrst(pwrdm->pwrsts_logic_ret, *logic_retst,
+				    PWRDM_POWER_OFF, PWRDM_POWER_RET);
+
+	pr_debug("powerdomain %s: convert fpwrst %0x to pwrst %0x\n",
+		 pwrdm->name, fpwrst, *pwrdm_pwrst);
+
+	return 0;
+}
+

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm)

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

Ditto here.

Quoted 220 lines

@pwrdm, @logic, and @pwrst
+ * are passed in, along with a pointer to the location to store the fpwrst to
+ * in @fpwrst.
+ */

arch/arm/mach-omap2/powerdomain.c +201 -1
+static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,
+				  u8 *fpwrst)
+{
+	if (!pwrdm || !fpwrst)
+		return -EINVAL;
+
+	switch (pwrst) {
+	case PWRDM_POWER_ON:
+		*fpwrst = PWRDM_FUNC_PWRST_ON;
+		break;
+	case PWRDM_POWER_INACTIVE:
+		*fpwrst = PWRDM_FUNC_PWRST_INACTIVE;
+		break;
+	case PWRDM_POWER_RET:
+		if (logic == PWRDM_POWER_OFF)
+			*fpwrst = PWRDM_FUNC_PWRST_OSWR;
+		else if (logic == PWRDM_POWER_RET)
+			*fpwrst = PWRDM_FUNC_PWRST_CSWR;
+		else
+			return -EINVAL;
+		break;
+	case PWRDM_POWER_OFF:
+		*fpwrst = PWRDM_FUNC_PWRST_OFF;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	pr_debug("powerdomain: convert pwrst (%0x,%0x) to fpwrst %0x\n",
+		 pwrst, logic, *fpwrst);
+
+	return 0;
+}
+
+/**
+ * _set_logic_retst_and_pwrdm_pwrst - program logic retst and pwrdm next pwrst
+ * @pwrdm: struct powerdomain * to program
+ * @logic: logic retention state to attempt to program
+ * @pwrst: powerdomain next-power-state to program
+ *
+ * Program the next-power-state and logic retention power state of the
+ * powerdomain represented by @pwrdm to @pwrst and @logic,
+ * respectively.  If the powerdomain next-power-state is not
+ * software-controllable, returns 0; otherwise, passes along the
+ * return value from pwrdm_set_logic_retst() if there is an error
+ * returned by that function, otherwise, passes along the return value
+ * from pwrdm_set_next_pwrst()
+ */
+static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
+					    u8 logic, u8 pwrst)
+{
+	int ret;
+
+	if (!_pwrdm_pwrst_is_controllable(pwrdm))
+		return 0;
+
+	if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET) {
+		ret = pwrdm_set_logic_retst(pwrdm, logic);
+		if (ret) {
+			pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
+			       __func__, logic, pwrdm->name);
+			return ret;
+		}
+	}
+
+	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state %0x of powerdomain: %s\n",
+		       __func__, pwrst, pwrdm->name);
+
+	return ret;
+}
+
+/**
+ * _pwrdm_read_next_fpwrst - get next powerdomain func power state (lockless)
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain @pwrdm's next functional power state.
+ * Caller must hold @pwrdm->_lock.  Returns -EINVAL if the powerdomain
+ * pointer is null or returns the next power state upon success.
+ */
+static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
+{
+	int next_pwrst, next_logic, ret;
+	u8 fpwrst;
+
+	if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst)
+		return -EINVAL;
+
+	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
+	if (next_pwrst < 0)
+		return next_pwrst;
+
+	next_logic = next_pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_logic_pwrst) {
+		next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+		if (next_logic < 0)
+			return next_logic;
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+
+	return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_read_fpwrst - get current func powerdomain power state (lockless)
+ * @pwrdm: struct powerdomain * to get current functional 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.
+ */
+static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)
+{
+	int pwrst, logic_pwrst, ret;
+	u8 fpwrst;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
+	if (pwrst < 0)
+		return pwrst;
+
+	logic_pwrst = pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_logic_pwrst) {
+		logic_pwrst = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+		if (logic_pwrst < 0)
+			return logic_pwrst;
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+
+	return (ret) ? ret : fpwrst;
+}
+
+/**
+ * _pwrdm_read_prev_fpwrst - get previous powerdomain func pwr state (lockless)
+ * @pwrdm: struct powerdomain * to get previous functional power state
+ *
+ * Return the powerdomain @pwrdm's previous functional power state.
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * previous functional power state upon success.
+ */
+static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
+{
+	int ret = -EINVAL;
+	int pwrst, logic_pwrst;
+	u8 fpwrst;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	pwrst = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
+	if (pwrst < 0)
+		return pwrst;
+
+	logic_pwrst = pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_prev_logic_pwrst) {
+		logic_pwrst = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
+		if (logic_pwrst < 0)
+			return logic_pwrst;
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, pwrst, logic_pwrst, &fpwrst);
+
+	return (ret) ? ret : fpwrst;
+}
+
 /* Public functions */
 
 /**
@@ -620,7 +929,7 @@ int pwrdm_read_pwrst(struct powerdomain *pwrdm)
 	if (!pwrdm)
 		return -EINVAL;
 
-	if (pwrdm->pwrsts == PWRSTS_ON)
+	if (!_pwrdm_pwrst_can_change(pwrdm))
 		return PWRDM_POWER_ON;
 
 	if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
@@ -1213,3 +1522,211 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
 
 	return 0;
 }
+
+/* Public functions for functional power state handling */
+
+/**
+ * pwrdm_convert_fpwrst_to_name - return the name of a functional power state
+ * @fpwrst: functional power state to return the name of
+ *
+ * Return a pointer to a string with the human-readable name of the
+ * functional power state (e.g., "ON", "CSWR", etc.)  Intended for use
+ * in debugging.  Returns NULL if @fpwrst is outside the range of the
+ * known functional power states.
+ */
+const char *pwrdm_convert_fpwrst_to_name(u8 fpwrst)
+{
+	if (fpwrst < PWRDM_FPWRST_OFFSET || fpwrst >= PWRDM_MAX_FUNC_PWRSTS)
+		return NULL;
+
+	return _fpwrst_names[fpwrst - PWRDM_FPWRST_OFFSET];
+}
+
+/**
+ * pwrdm_set_next_fpwrst - set next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the powerdomain @pwrdm's next power state to @fpwrst.  The
+ * powerdomain may not enter this state immediately if the

arch/arm/mach-omap2/powerdomain.c bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm) · line 1561

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+ * preconditions for this state have not been satisfied.  Returns
+ * -EINVAL if the powerdomain pointer is null or if the power state is
+ * invalid for the powerdomin, or returns 0 upon success.
+ */
+int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
+{
+	u8 pwrst, logic;
+	int ret;
+
+	if (!pwrdm || IS_ERR(pwrdm))

You can use IS_ERR_OR_NULL here.

Quoted 145 lines
arch/arm/mach-omap2/powerdomain.c +145 -0
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_is_controllable(pwrdm))
+		return 0;
+
+	ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+	if (ret)
+		return ret;
+
+	pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst,
+		 pwrdm->name);
+
+	pwrdm_lock(pwrdm);
+	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
+/**
+ * pwrdm_read_next_fpwrst - 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_fpwrst(struct powerdomain *pwrdm)
+{
+	int next_pwrst, next_logic, ret;
+	u8 fpwrst;
+
+	if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst)
+		return -EINVAL;
+
+	pwrdm_lock(pwrdm);
+
+	next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
+	if (next_pwrst < 0) {
+		ret = next_pwrst;
+		goto prnf_out;
+	}
+
+	next_logic = next_pwrst;
+	if (_pwrdm_logic_retst_can_change(pwrdm) &&
+	    arch_pwrdm->pwrdm_read_logic_pwrst) {
+		next_logic = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
+		if (next_logic < 0) {
+			ret = next_logic;
+			goto prnf_out;
+		}
+	}
+
+	ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
+
+prnf_out:
+	pwrdm_unlock(pwrdm);
+
+	return (ret) ? ret : fpwrst;
+}
+
+/**
+ * pwrdm_set_fpwrst - program next powerdomain functional power state
+ * @pwrdm: struct powerdomain * to set
+ * @fpwrst: 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 pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
+{
+	u8 next_fpwrst, pwrst, logic, sleep_switch;
+	int ret = 0;
+	bool hwsup;
+
+	if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm ||
+	    !arch_pwrdm->pwrdm_read_pwrst)
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_is_controllable(pwrdm))
+		return 0;
+
+	ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+	if (ret)
+		return -EINVAL;
+
+	pr_debug("%s: pwrdm %s: set fpwrst %0x\n", __func__, pwrdm->name,
+		 fpwrst);
+
+	pwrdm_lock(pwrdm);
+
+	/*
+	 * XXX quite heavyweight for what this is intended to do; the
+	 * next fpwrst should simply be cached
+	 */
+	next_fpwrst = _pwrdm_read_next_fpwrst(pwrdm);
+	if (next_fpwrst == fpwrst)
+		goto psf_out;
+
+	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, pwrst,
+							    &hwsup);
+
+	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
+	if (ret)
+		pr_err("%s: unable to set power state of powerdomain: %s\n",
+		       __func__, pwrdm->name);
+
+	_pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
+
+psf_out:
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
+/**
+ * pwrdm_read_fpwrst - get current functional powerdomain power state
+ * @pwrdm: struct powerdomain * to get current functional 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_fpwrst(struct powerdomain *pwrdm)
+{
+	int ret;
+
+	if (!pwrdm || !arch_pwrdm)
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	if (!arch_pwrdm->pwrdm_read_pwrst)
+		return -EINVAL;
+
+	pwrdm_lock(pwrdm);
+	ret = _pwrdm_read_fpwrst(pwrdm);
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
+/**
+ * pwrdm_read_prev_fpwrst - get previous powerdomain functional power state

arch/arm/mach-omap2/powerdomain.c bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm) · line 1716

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

No need to initialize it here.

Thanks,
Vaibhav

Quoted 82 lines
arch/arm/mach-omap2/powerdomain.c +16 -0
+	if (!pwrdm || !arch_pwrdm)
+		return -EINVAL;
+
+	if (!_pwrdm_pwrst_can_change(pwrdm))
+		return PWRDM_FUNC_PWRST_ON;
+
+	if (!arch_pwrdm->pwrdm_read_prev_pwrst)
+		return -EINVAL;
+
+	pwrdm_lock(pwrdm);
+	ret = _pwrdm_read_prev_fpwrst(pwrdm);
+	pwrdm_unlock(pwrdm);
+
+	return ret;
+}
+
arch/arm/mach-omap2/powerdomain.h +32 -1
index 842ba46..be835ff 100644
@@ -1,7 +1,7 @@
 /*
  * OMAP2/3/4 powerdomain control
  *
- * Copyright (C) 2007-2008, 2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010-2012 Texas Instruments, Inc.
  * Copyright (C) 2007-2011 Nokia Corporation
  *
  * Paul Walmsley
@@ -23,6 +23,29 @@
 
 #include "voltage.h"
 
+/*
+ * PWRDM_FPWRST_OFFSET: offset of the first functional power state
+ * from 0.  This offset can be subtracted from the functional power
+ * state macros to produce offsets suitable for array indices, for
+ * example.  The intention behind the addition of this offset is to
+ * prevent functional power states from accidentally being confused
+ * with the low-level, hardware power states.
+ */
+#define PWRDM_FPWRST_OFFSET		0x80
+
+/*
+ * Powerdomain functional power states, used by the external API functions
+ * These must match the order and names in _fpwrst_names[]
+ */
+enum pwrdm_func_state {
+	PWRDM_FUNC_PWRST_OFF		= PWRDM_FPWRST_OFFSET,
+	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 */
+};
+
 /* Powerdomain basic power states */
 #define PWRDM_POWER_OFF		0x0
 #define PWRDM_POWER_RET		0x1
@@ -238,6 +261,14 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
 
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);
 
+extern const char *pwrdm_convert_fpwrst_to_name(u8 fpwrst);
+extern int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst);
+extern int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm);
+extern int pwrdm_set_fpwrst(struct powerdomain *pwrdm,
+			    enum pwrdm_func_state fpwrst);
+extern int pwrdm_read_fpwrst(struct powerdomain *pwrdm);
+extern int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm);
+
 extern void omap242x_powerdomains_init(void);
 extern void omap243x_powerdomains_init(void);
 extern void omap3xxx_powerdomains_init(void);

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

#6 lore raw

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

In reply to Paul Walmsley

Hi Paul,

-resending in plain text only, sorry about that-

Quoted 54 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

Introduce the functional states for power domains, which include the power states and the logic states.
This patch provides the API functions to set and read the power domains functional state and internal functions to convert between the functional (i.e. logical) and the internal (or registers) values.

In the new API only the functions pwrdm_set_next_fpwrst() and pwrdm_set_fpwrst() shall be used to change a power domain target state, along with the associated PWRDM_FUNC_* macros as the state parameters.

Note about the power domains allowed states:
Power domains have varied capabilities, as defined by the value of the pwrsts and pwrsts_logic_ret fields of the powerdomain struct. When reading or setting a low power state such as OFF/RET, a specific requested state may not be supported on the given power domain. In the states conversion functions a power or logic 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. An iteration function is used, as suggested by Rajendra Nayak <[email protected]> This function is temporary and will be removed later in the series.

This functionality brings consistency in the functional power states core code and acts as a guard against hardware implementations discrepancies, e.g. some power domains only support the RET logic state although reading the logic state registers (previous, current and next) always returns OFF. The DSS power domain on OMAP3 is an example.

Cc Tero Kristo <[email protected]>
Cc Rajendra Nayak <[email protected]>
Cc Nishanth Menon <[email protected]>

[paul at pwsan.com: add offset for functional powerstates so it's not
possible to confuse them with the old API; use one fn to convert func pwrsts to low-level hardware bits; skip hardware reads when hardware logic retst and logic pwrst bits are missing; fix kerneldoc and commit message; remove unnecessary PWRDM_LOGIC_MEM_PWRST_* macros; combine spinlock patch into this patch; expand the number of operations which take the spinlock]

---
 arch/arm/mach-omap2/powerdomain.c |  525 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |   33 ++
 2 files changed, 553 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/powerdomain.c +0 -0
index 94b89a25..18f33de 100644
@@ -1,7 +1,7 @@

...

Quoted 4 lines

+/**
+ * _match_pwrst: determine the closest supported power state
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point

Quoted 8 lines

+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Search down then up for a valid state from a list of allowed
+ * states. Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * Returns the matching allowed state. XXX Deprecated. The software
+ * should not try to program unsupported powerstates.

Why is this new code already deprecated? Does this require a rewrite?

Quoted 83 lines

+ */

arch/arm/mach-omap2/powerdomain.c +82 -0
+static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max)
+{
+       int found = 1, new_pwrst = pwrst;
+
+       /*
+        * If the power domain does not allow any state programmation
+        * return the max state which is always allowed
+        */
+       if (!pwrsts)
+               return max;
+
+       /*
+        * Search lower: if the requested state is not supported
+        * try the lower states, stopping at the minimum allowed
+        * state
+        */
+       while (!(pwrsts & (1 << new_pwrst))) {
+               if (new_pwrst <= min) {
+                       found = 0;
+                       break;
+               }
+               new_pwrst--;
+       }
+
+       /*
+        * Search higher: if no lower state found fallback to the higher
+        * states, stopping at the maximum allowed state
+        */
+       if (!found) {
+               new_pwrst = pwrst;
+               while (!(pwrsts & (1 << new_pwrst))) {
+                       if (new_pwrst >= max) {
+                               new_pwrst = max;
+                               break;
+                       }
+                       new_pwrst++;
+               }
+       }
+
+       return new_pwrst;
+}
+
+/**
+ * _pwrdm_fpwrst_to_pwrst - Convert functional (i.e. logical) to
+ * internal (i.e. registers) values for the power domains states.
+ * @pwrdm: struct powerdomain * to convert the values for
+ * @fpwrst: functional power state
+ * @pwrdm_pwrst: ptr to u8 to return the power state in
+ * @logic_retst: ptr to u8 to return the logic retention state in
+ *
+ * Returns the internal power state value for the power domain, or
+ * -EINVAL in case of invalid parameters passed in.
+ */
+static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
+                                 u8 *pwrdm_pwrst, u8 *logic_retst)
+{
+       if (!pwrdm || !pwrdm_pwrst || !logic_retst)
+               return -EINVAL;
+
+       switch (fpwrst) {
+       case PWRDM_FUNC_PWRST_ON:
+               *pwrdm_pwrst = PWRDM_POWER_ON;
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       case PWRDM_FUNC_PWRST_INACTIVE:
+               *pwrdm_pwrst = PWRDM_POWER_INACTIVE;
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       case PWRDM_FUNC_PWRST_CSWR:
+               *pwrdm_pwrst = PWRDM_POWER_RET;
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       case PWRDM_FUNC_PWRST_OSWR:
+               *pwrdm_pwrst = PWRDM_POWER_RET;
+               *logic_retst = PWRDM_POWER_OFF;
+               break;
+       case PWRDM_FUNC_PWRST_OFF:
+               *pwrdm_pwrst = PWRDM_POWER_OFF;
+               /*
+                * logic_retst is set to PWRDM_POWER_RET in this case
+                * since the actual value does not matter, and because
+                * some powerdomains don't support a logic_retst of

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 372

Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +10 -0
+                * OFF.  XXX Maybe there's some way to indicate a
+                * 'don't care' value here?
+                */
+               *logic_retst = PWRDM_POWER_RET;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* XXX deprecated */

Same here

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 383

Quoted 12 lines
arch/arm/mach-omap2/powerdomain.c +11 -0
+       *pwrdm_pwrst = _match_pwrst(pwrdm->pwrsts, *pwrdm_pwrst,
+                                   PWRDM_POWER_OFF, PWRDM_POWER_ON);
+
+       *logic_retst = _match_pwrst(pwrdm->pwrsts_logic_ret, *logic_retst,
+                                   PWRDM_POWER_OFF, PWRDM_POWER_RET);
+
+       pr_debug("powerdomain %s: convert fpwrst %0x to pwrst %0x\n",
+                pwrdm->name, fpwrst, *pwrdm_pwrst);
+
+       return 0;
+}

Thanks & regards,
Jean

#7 lore raw

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

Hi Paul / Jean,

On Wed, 2012-12-12 at 11:33 +0100, Jean Pihet wrote:

<clip>

Quoted 14 lines
Quoted 4 lines

+/**
+ * _match_pwrst: determine the closest supported power state
+ * @pwrsts: list of allowed states, defined as a bitmask
+ * @pwrst: initial state to be used as a starting point

Quoted 8 lines

+ * @min: minimum (i.e. lowest consumption) allowed state
+ * @max: maximum (i.e. highest consumption) allowed state
+ *
+ * Search down then up for a valid state from a list of allowed
+ * states. Used by states conversion functions (_pwrdm_fpwrst_to_*)
+ * to look for allowed power and logic states for a powerdomain.
+ * Returns the matching allowed state. XXX Deprecated. The software
+ * should not try to program unsupported powerstates.

Quoted 1 line

Why is this new code already deprecated? Does this require a rewrite?

Looks like it is removed by another patch in the same set and could probably just be removed from this one also.

Quoted 6 lines

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 372

Quoted 3 lines
arch/arm/mach-omap2/powerdomain.c +3 -0
+       }
+
+       /* XXX deprecated */

Same here

Same thing, maybe drop the code out completely.

-Tero

#8 lore raw

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

In reply to Paul Walmsley

Hi Paul,

A minor comment below.

On Sun, Dec 09, 2012 at 23:23:01, Paul Walmsley wrote:
[...]

arch/arm/mach-omap2/powerdomain.c static bool _pwrdm_logic_retst_can_change(struct powerdomain *pwrdm) · line 428

Quoted 4 lines
arch/arm/mach-omap2/powerdomain.c +4 -0
+
+	pr_debug("powerdomain: convert pwrst (%0x,%0x) to fpwrst %0x\n",
+		 pwrst, logic, *fpwrst);
+

This function alone does not print the powerdomain name. Can you add that in the final version?

Regards,
Vaibhav

#9 lore raw

PATCH 3/12 ARM: OMAP2+: PM debug: trace the functional power domains states

In reply to Paul Walmsley

From: Jean Pihet <[email protected]>

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

[paul at pwsan.com: split the fix that was originally part of this patch into a
separate patch]

---
 arch/arm/mach-omap2/powerdomain.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)
arch/arm/mach-omap2/powerdomain.c +8 -6
index 18f33de..2c732b6 100644
@@ -881,13 +881,8 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 	pr_debug("powerdomain: %s: setting next powerstate 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;
 }
@@ -1571,6 +1566,9 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
 	pr_debug("%s: set fpwrst %0x to pwrdm %s\n", __func__, fpwrst,
 		 pwrdm->name);
 
+	/* Trace the pwrdm desired target state */
+	trace_power_domain_target(pwrdm->name, fpwrst, smp_processor_id());
+
 	pwrdm_lock(pwrdm);
 	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
 	pwrdm_unlock(pwrdm);
@@ -1658,6 +1656,10 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 	if (next_fpwrst == fpwrst)
 		goto psf_out;
 
+	/* Trace the pwrdm desired target state */
+	trace_power_domain_target(pwrdm->name, next_fpwrst,
+				  smp_processor_id());
+
 	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, pwrst,
 							    &hwsup);
 
#10 lore raw

PATCH 4/12 ARM: OMAP2xxx: PM: convert to use the functional power states API

In reply to Paul Walmsley

From: Jean Pihet <[email protected]>

Use the functional power states as the API to control power domains:

- use the PWRDM_FUNC_PWRST_* macros for the power states and logic settings,

- the function pwrdm_set_next_fpwrst(), which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst() to program the power domains next states,

- the function pwrdm_set_fpwrst(), which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state().

[paul at pwsan.com: split the original patch into OMAP2/3/4 variants; fix
commit message; update the power state programming to make sense; warn if sets fail]

---
 arch/arm/mach-omap2/pm24xx.c |   24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)
arch/arm/mach-omap2/pm24xx.c +10 -14
index 4c06d8a..29abb63 100644
@@ -89,8 +89,8 @@ static int omap2_enter_full_retention(void)
 	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
 	omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
 
-	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
-	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+	WARN_ON(pwrdm_set_next_fpwrst(core_pwrdm, PWRDM_FUNC_PWRST_CSWR));
+	WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_CSWR));
 
 	/* Workaround to kill USB */
 	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
@@ -132,8 +132,8 @@ no_sleep:
 	/* Mask future PRCM-to-MPU interrupts */
 	omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
 
-	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
-	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON);
+	WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON));
+	WARN_ON(pwrdm_set_next_fpwrst(core_pwrdm, PWRDM_FUNC_PWRST_ON));
 
 	return 0;
 }
@@ -184,16 +184,16 @@ static void omap2_enter_mpu_retention(void)
 		omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
 
 		/* Try to enter MPU retention */
-		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
-
+		WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm,
+					      PWRDM_FUNC_PWRST_CSWR));
 	} else {
 		/* Block MPU retention */
-		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
+		WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON));
 	}
 
 	omap2_sram_idle();
 
-	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
+	WARN_ON(pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON));
 }
 
 static int omap2_can_sleep(void)
@@ -248,17 +248,13 @@ static void __init prcm_setup_regs(void)
 	for (i = 0; i < num_mem_banks; i++)
 		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
 
-	pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET);
-
-	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
-
 	/* Force-power down DSP, GFX powerdomains */
 
 	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
-	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	WARN_ON(pwrdm_set_next_fpwrst(pwrdm, PWRDM_FUNC_PWRST_OFF));
 
 	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
-	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+	WARN_ON(pwrdm_set_next_fpwrst(pwrdm, PWRDM_FUNC_PWRST_OFF));
 
 	/* Enable hardware-supervised idle for all clkdms */
 	clkdm_for_each(omap_pm_clkdms_setup, NULL);
#11 lore raw

PATCH 5/12 ARM: OMAP3xxx: PM: convert to use the functional power states API

In reply to Paul Walmsley

From: Jean Pihet <[email protected]>

Use the functional power states as the API to control power domains:

- use the PWRDM_FUNC_PWRST_* macros for the power states and logic settings,

- the function pwrdm_set_next_fpwrst(), which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst() to program the power domains next states,

- the function pwrdm_set_fpwrst(), which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state().

[paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
clean up omap3_save_secure_ram_context(); fix commit message; warn if sets fail; various other changes]

---
 arch/arm/mach-omap2/cpuidle34xx.c |   95 ++++++++++++-----------
 arch/arm/mach-omap2/pm.h          |    2 
 arch/arm/mach-omap2/pm34xx.c      |  156 +++++++++++++++++++------------------
 3 files changed, 130 insertions(+), 123 deletions(-)
arch/arm/mach-omap2/cpuidle34xx.c +49 -46
index e6215b5..a8e6263 100644
@@ -36,9 +36,9 @@
 
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
-	u8 mpu_state;
-	u8 core_state;
-	u8 per_min_state;
+	u8 mpu_fpwrst;
+	u8 core_fpwrst;
+	u8 per_min_fpwrst;
 	u8 flags;
 };
 
@@ -61,41 +61,41 @@ static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
  */
 static struct omap3_idle_statedata omap3_idle_data[] = {
 	{
-		.mpu_state = PWRDM_POWER_ON,
-		.core_state = PWRDM_POWER_ON,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_ON,
+		.core_fpwrst = PWRDM_FUNC_PWRST_ON,
 		/* In C1 do not allow PER state lower than CORE state */
-		.per_min_state = PWRDM_POWER_ON,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_ON,
 		.flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE,
 	},
 	{
-		.mpu_state = PWRDM_POWER_ON,
-		.core_state = PWRDM_POWER_ON,
-		.per_min_state = PWRDM_POWER_RET,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_ON,
+		.core_fpwrst = PWRDM_FUNC_PWRST_ON,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_CSWR,
 	},
 	{
-		.mpu_state = PWRDM_POWER_RET,
-		.core_state = PWRDM_POWER_ON,
-		.per_min_state = PWRDM_POWER_RET,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_CSWR,
+		.core_fpwrst = PWRDM_FUNC_PWRST_ON,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_CSWR,
 	},
 	{
-		.mpu_state = PWRDM_POWER_OFF,
-		.core_state = PWRDM_POWER_ON,
-		.per_min_state = PWRDM_POWER_RET,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_OFF,
+		.core_fpwrst = PWRDM_FUNC_PWRST_ON,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_CSWR,
 	},
 	{
-		.mpu_state = PWRDM_POWER_RET,
-		.core_state = PWRDM_POWER_RET,
-		.per_min_state = PWRDM_POWER_OFF,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_CSWR,
+		.core_fpwrst = PWRDM_FUNC_PWRST_CSWR,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_OFF,
 	},
 	{
-		.mpu_state = PWRDM_POWER_OFF,
-		.core_state = PWRDM_POWER_RET,
-		.per_min_state = PWRDM_POWER_OFF,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_OFF,
+		.core_fpwrst = PWRDM_FUNC_PWRST_CSWR,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_OFF,
 	},
 	{
-		.mpu_state = PWRDM_POWER_OFF,
-		.core_state = PWRDM_POWER_OFF,
-		.per_min_state = PWRDM_POWER_OFF,
+		.mpu_fpwrst = PWRDM_FUNC_PWRST_OFF,
+		.core_fpwrst = PWRDM_FUNC_PWRST_OFF,
+		.per_min_fpwrst = PWRDM_FUNC_PWRST_OFF,
 	},
 };
 
@@ -116,15 +116,15 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
 	if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) {
 		clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]);
 	} else {
-		pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
-		pwrdm_set_next_pwrst(core_pd, cx->core_state);
+		pwrdm_set_next_fpwrst(mpu_pd, cx->mpu_fpwrst);
+		pwrdm_set_next_fpwrst(core_pd, cx->core_fpwrst);
 	}
 
 	/*
 	 * Call idle CPU PM enter notifier chain so that
 	 * VFP context is saved.
 	 */
-	if (cx->mpu_state == PWRDM_POWER_OFF)
+	if (cx->mpu_fpwrst == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_enter();
 
 	/* Execute ARM wfi */
@@ -134,8 +134,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
 	 * Call idle CPU PM enter notifier chain to restore
 	 * VFP context.
 	 */
-	if (cx->mpu_state == PWRDM_POWER_OFF &&
-	    pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
+	if (cx->mpu_fpwrst == PWRDM_FUNC_PWRST_OFF &&
+	    pwrdm_read_prev_fpwrst(mpu_pd) == PWRDM_FUNC_PWRST_OFF)
 		cpu_pm_exit();
 
 	/* Re-allow idle for C1 */
@@ -181,25 +181,25 @@ 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;
+	u8 mpu_deepest_fpwrst = PWRDM_FUNC_PWRST_CSWR;
+	u8 core_deepest_fpwrst = PWRDM_FUNC_PWRST_CSWR;
 	int idx;
 	int next_index = 0; /* C1 is the default value */
 
 	if (enable_off_mode) {
-		mpu_deepest_state = PWRDM_POWER_OFF;
+		mpu_deepest_fpwrst = 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_fpwrst = PWRDM_FUNC_PWRST_OFF;
 	}
 
 	/* Check if current state is valid */
-	if ((cx->mpu_state >= mpu_deepest_state) &&
-	    (cx->core_state >= core_deepest_state))
+	if ((cx->mpu_fpwrst >= mpu_deepest_fpwrst) &&
+	    (cx->core_fpwrst >= core_deepest_fpwrst))
 		return index;
 
 	/*
@@ -208,8 +208,8 @@ static int next_valid_state(struct cpuidle_device *dev,
 	 */
 	for (idx = index - 1; idx >= 0; idx--) {
 		cx = &omap3_idle_data[idx];
-		if ((cx->mpu_state >= mpu_deepest_state) &&
-		    (cx->core_state >= core_deepest_state)) {
+		if ((cx->mpu_fpwrst >= mpu_deepest_fpwrst) &&
+		    (cx->core_fpwrst >= core_deepest_fpwrst)) {
 			next_index = idx;
 			break;
 		}
@@ -232,14 +232,16 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 			       int index)
 {
 	int new_state_idx, ret;
-	u8 per_next_state, per_saved_state;
+	int per_next_fpwrst, per_saved_fpwrst;
 	struct omap3_idle_statedata *cx;
 
 	/*
 	 * Use only C1 if CAM is active.
 	 * CAM does not have wakeup capability in OMAP3.
+	 * XXX This workaround belongs in the hwmod code & data
+	 * as a hwmod flag
 	 */
-	if (pwrdm_read_pwrst(cam_pd) == PWRDM_POWER_ON)
+	if (pwrdm_read_fpwrst(cam_pd) == PWRDM_FUNC_PWRST_ON)
 		new_state_idx = drv->safe_state_index;
 	else
 		new_state_idx = next_valid_state(dev, drv, index);
@@ -255,18 +257,19 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
 	/* Program PER state */
 	cx = &omap3_idle_data[new_state_idx];
 
-	per_next_state = pwrdm_read_next_pwrst(per_pd);
-	per_saved_state = per_next_state;
-	if (per_next_state < cx->per_min_state) {
-		per_next_state = cx->per_min_state;
-		pwrdm_set_next_pwrst(per_pd, per_next_state);
+	per_next_fpwrst = pwrdm_read_next_fpwrst(per_pd);
+	WARN_ON(per_next_fpwrst < 0);
+	per_saved_fpwrst = per_next_fpwrst;
+	if (per_next_fpwrst < cx->per_min_fpwrst) {
+		per_next_fpwrst = cx->per_min_fpwrst;
+		WARN_ON(pwrdm_set_next_fpwrst(per_pd, per_next_fpwrst));
 	}
 
 	ret = omap3_enter_idle(dev, drv, new_state_idx);
 
 	/* Restore original PER state if it was modified */
-	if (per_next_state != per_saved_state)
-		pwrdm_set_next_pwrst(per_pd, per_saved_state);
+	if (per_next_fpwrst != per_saved_fpwrst)
+		WARN_ON(pwrdm_set_next_fpwrst(per_pd, per_saved_fpwrst));
 
 	return ret;
 }
arch/arm/mach-omap2/pm.h +1 -1
index 707e9cb..19ef376 100644
@@ -51,7 +51,7 @@ static inline int omap4_opp_init(void)
 #endif
 
 extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
-extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
+extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, u8 fpwrst);
 
 #ifdef CONFIG_PM_DEBUG
 extern u32 enable_off_mode;
arch/arm/mach-omap2/pm34xx.c +80 -76

287 lines not on this page · raw message

#12 lore raw

PATCH 5/12 ARM: OMAP3xxx: PM: convert to use the functional power states API

Paul,

Quoted 11 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

Use the functional power states as the API to control power domains:

- use the PWRDM_FUNC_PWRST_* macros for the power states and logic settings,

- the function pwrdm_set_next_fpwrst(), which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst() to program the power domains next states,

Quoted 9 lines

- the function pwrdm_set_fpwrst(), which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state().

[paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
clean up omap3_save_secure_ram_context(); fix commit message; warn if sets fail; various other changes]

There are a lot of 'XXX' comments, can this be fixed by a proper comment?

Regards,
Jean

Quoted 10 lines
---
 arch/arm/mach-omap2/cpuidle34xx.c |   95 ++++++++++++-----------
 arch/arm/mach-omap2/pm.h          |    2
 arch/arm/mach-omap2/pm34xx.c      |  156
+++++++++++++++++++------------------
 3 files changed, 130 insertions(+), 123 deletions(-)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121212/77892ace/attachment-0001.html>

#13 lore raw

PATCH 5/12 ARM: OMAP3xxx: PM: convert to use the functional power states API

In reply to Paul Walmsley

Paul,

-resending in plain text only, sorry about that-

Quoted 12 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

Use the functional power states as the API to control power domains:

- use the PWRDM_FUNC_PWRST_* macros for the power states and logic settings,

- the function pwrdm_set_next_fpwrst(), which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst() to program the power domains next states,

Quoted 8 lines

- the function pwrdm_set_fpwrst(), which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state().

[paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
clean up omap3_save_secure_ram_context(); fix commit message; warn if sets fail; various other changes]

There are a lot of 'XXX' comments, can this be fixed by a proper comment?

Regards,
Jean

#14 lore raw

PATCH 5/12 ARM: OMAP3xxx: PM: convert to use the functional power states API

In reply to Paul Walmsley

Hi Paul,

On Sun, 2012-12-09 at 10:53 -0700, Paul Walmsley wrote:

<clip>

Quoted 31 lines
arch/arm/mach-omap2/pm34xx.c +9 -17
@@ -112,24 +112,26 @@ static void omap3_core_restore_context(void)
 static void omap3_save_secure_ram_context(void)
 {
 	u32 ret;
-	int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+	int mpu_next_fpwrst;
 
-	if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
-		/*
-		 * MPU next state must be set to POWER_ON temporarily,
-		 * otherwise the WFI executed inside the ROM code
-		 * will hang the system.
-		 */
-		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
-		ret = _omap_save_secure_sram((u32 *)
-				__pa(omap3_secure_ram_storage));
-		pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
-		/* Following is for error tracking, it should not happen */
-		if (ret) {
-			pr_err("save_secure_sram() returns %08x\n", ret);
-			while (1)
-				;
-		}
+	if (omap_type() == OMAP2_DEVICE_TYPE_GP)
+		return;
+
+	/*
+	 * MPU next state must be set to POWER_ON temporarily,
+	 * otherwise the WFI executed inside the ROM code will hang
+	 * the system.
+	 */

arch/arm/mach-omap2/pm34xx.c static void omap3_core_restore_context(void) · line 134

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +10 -0
+	mpu_next_fpwrst = pwrdm_read_next_fpwrst(mpu_pwrdm);
+	pwrdm_set_next_fpwrst(mpu_pwrdm, PWRDM_FUNC_PWRST_ON);
+	ret = _omap_save_secure_sram((u32 *)__pa(omap3_secure_ram_storage));
+	pwrdm_set_next_fpwrst(mpu_pwrdm, mpu_next_fpwrst);
+	/* Following is for error tracking, it should not happen */
+	/* XXX This needs to be converted to a BUG() or removed */
+	if (ret) {
+		pr_err("save_secure_sram() returns %08x\n", ret);
+		while (1)
+			;

Just a minor comment here, this can be converted to BUG_ON right now, as it is only used from init code.

Another thing to consider with this code is, that there might be someone who actually wants to use secure services from the kernel, and in this case you need to do the save every time you are entering off-mode if secure services have been used. If this save fails, the core powerdomain should be re-programmed to RET, or prevent idle completely. Maybe this needs to be moved into secure driver or something, and use cpu_pm notifiers.... they don't support failures currently though.

-Tero

#15 lore raw

PATCH 6/12 ARM: OMAP44xx: PM: convert to use the functional power states API

In reply to Paul Walmsley

From: Jean Pihet <[email protected]>

Use the functional power states as the API to control power domains:
- use the PWRDM_FUNC_PWRST_* and PWRDM_LOGIC_MEM_PWRST_* macros for the power states and logic settings,
- the function pwrdm_set_next_fpwrst, which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst to program the power domains next states,
- the function pwrdm_set_fpwrst, which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state.

[paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
warn if sets fail; various other changes]

---
 arch/arm/mach-omap2/common.h              |    7 +--
 arch/arm/mach-omap2/cpuidle44xx.c         |   32 +++++--------
 arch/arm/mach-omap2/omap-hotplug.c        |    2 -
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   69 +++++++++++++++++------------
 arch/arm/mach-omap2/pm44xx.c              |   42 +++++++++---------
 5 files changed, 79 insertions(+), 73 deletions(-)
arch/arm/mach-omap2/common.h +3 -4
index c57eeea..5ad846a 100644
@@ -235,14 +235,13 @@ extern void omap5_secondary_startup(void);
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PM)
 extern int omap4_mpuss_init(void);
-extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state);
+extern int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst);
 extern int omap4_finish_suspend(unsigned long cpu_state);
 extern void omap4_cpu_resume(void);
-extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state);
+extern int omap4_mpuss_hotplug_cpu(unsigned int cpu, u8 fpwrst);
 extern u32 omap4_mpuss_read_prev_context_state(void);
 #else
-static inline int omap4_enter_lowpower(unsigned int cpu,
-					unsigned int power_state)
+static inline int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst)
 {
 	cpu_do_idle();
 	return 0;
arch/arm/mach-omap2/cpuidle44xx.c +13 -19
index d639aef..2cb5332 100644
@@ -25,26 +25,22 @@
 
 /* Machine specific information */
 struct omap4_idle_statedata {
-	u32 cpu_state;
-	u32 mpu_logic_state;
-	u32 mpu_state;
+	u8 cpu_pwrst;
+	u8 mpu_pwrst;
 };
 
 static struct omap4_idle_statedata omap4_idle_data[] = {
 	{
-		.cpu_state = PWRDM_POWER_ON,
-		.mpu_state = PWRDM_POWER_ON,
-		.mpu_logic_state = PWRDM_POWER_RET,
+		.cpu_pwrst = PWRDM_FUNC_PWRST_ON,
+		.mpu_pwrst = PWRDM_FUNC_PWRST_ON,
 	},
 	{
-		.cpu_state = PWRDM_POWER_OFF,
-		.mpu_state = PWRDM_POWER_RET,
-		.mpu_logic_state = PWRDM_POWER_RET,
+		.cpu_pwrst = PWRDM_FUNC_PWRST_OFF,
+		.mpu_pwrst = PWRDM_FUNC_PWRST_CSWR,
 	},
 	{
-		.cpu_state = PWRDM_POWER_OFF,
-		.mpu_state = PWRDM_POWER_RET,
-		.mpu_logic_state = PWRDM_POWER_OFF,
+		.cpu_pwrst = PWRDM_FUNC_PWRST_OFF,
+		.mpu_pwrst = PWRDM_FUNC_PWRST_OSWR,
 	},
 };
 
@@ -93,7 +89,7 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
 	 * out of coherency and in OFF mode.
 	 */
 	if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) {
-		while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) {
+		while (pwrdm_read_fpwrst(cpu_pd[1]) != PWRDM_FUNC_PWRST_OFF) {
 			cpu_relax();
 
 			/*
@@ -118,19 +114,17 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
 	cpu_pm_enter();
 
 	if (dev->cpu == 0) {
-		pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
-		omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
+		WARN_ON(pwrdm_set_fpwrst(mpu_pd, cx->mpu_pwrst));
 
 		/*
 		 * 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))
-				cpu_cluster_pm_enter();
+		if (cx->mpu_pwrst == PWRDM_FUNC_PWRST_OSWR)
+			cpu_cluster_pm_enter();
 	}
 
-	omap4_enter_lowpower(dev->cpu, cx->cpu_state);
+	omap4_mpuss_enter_lowpower(dev->cpu, cx->cpu_pwrst);
 	cpu_done[dev->cpu] = true;
 
 	/* Wakeup CPU1 only if it is not offlined */
arch/arm/mach-omap2/omap-hotplug.c +1 -1
index e712d17..d38b12d 100644
@@ -53,7 +53,7 @@ void __ref omap4_cpu_die(unsigned int cpu)
 		/*
 		 * Enter into low power state
 		 */
-		omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF);
+		omap4_mpuss_hotplug_cpu(cpu, PWRDM_FUNC_PWRST_OFF);
 
 		if (omap_secure_apis_support())
 			boot_cpu = omap_read_auxcoreboot0();
arch/arm/mach-omap2/omap-mpuss-lowpower.c +41 -28

178 lines not on this page · raw message

arch/arm/mach-omap2/pm44xx.c +21 -21

79 lines not on this page · raw message

#16 lore raw

PATCH 6/12 ARM: OMAP44xx: PM: convert to use the functional power states API

Paul,

Quoted 53 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

Use the functional power states as the API to control power domains:
- use the PWRDM_FUNC_PWRST_* and PWRDM_LOGIC_MEM_PWRST_* macros for the power states and logic settings,
- the function pwrdm_set_next_fpwrst, which controls the power domains next power and logic settings, shall be used instead of pwrdm_set_next_pwrst to program the power domains next states,
- the function pwrdm_set_fpwrst, which programs the power domains power and logic settings, shall be used instead of omap_set_pwrdm_state.

[paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
warn if sets fail; various other changes]

---
 arch/arm/mach-omap2/common.h              |    7 +--
 arch/arm/mach-omap2/cpuidle44xx.c         |   32 +++++--------
 arch/arm/mach-omap2/omap-hotplug.c        |    2 -
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   69 +++++++++++++++++------------
 arch/arm/mach-omap2/pm44xx.c              |   42 +++++++++---------
 5 files changed, 79 insertions(+), 73 deletions(-)
arch/arm/mach-omap2/common.h +3 -4
index c57eeea..5ad846a 100644
@@ -235,14 +235,13 @@ extern void omap5_secondary_startup(void);
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PM)
 extern int omap4_mpuss_init(void);
-extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state);
+extern int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst);
 extern int omap4_finish_suspend(unsigned long cpu_state);
 extern void omap4_cpu_resume(void);
-extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state);
+extern int omap4_mpuss_hotplug_cpu(unsigned int cpu, u8 fpwrst);
 extern u32 omap4_mpuss_read_prev_context_state(void);
 #else
-static inline int omap4_enter_lowpower(unsigned int cpu,
-                                       unsigned int power_state)
+static inline int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst)
 {
        cpu_do_idle();
        return 0;
arch/arm/mach-omap2/cpuidle44xx.c +0 -0
index d639aef..2cb5332 100644

arch/arm/mach-omap2/cpuidle44xx.c line 29

Quoted 8 lines
arch/arm/mach-omap2/cpuidle44xx.c +2 -3
@@ -25,26 +25,22 @@
 
 /* Machine specific information */
 struct omap4_idle_statedata {
-       u32 cpu_state;
-       u32 mpu_logic_state;
-       u32 mpu_state;
+       u8 cpu_pwrst;
+       u8 mpu_pwrst;

This should be cpu_fpwrst and mpu_fwprst for consistency.

Quoted 317 lines
arch/arm/mach-omap2/cpuidle44xx.c +11 -16
 };
 
 static struct omap4_idle_statedata omap4_idle_data[] = {
        {
-               .cpu_state = PWRDM_POWER_ON,
-               .mpu_state = PWRDM_POWER_ON,
-               .mpu_logic_state = PWRDM_POWER_RET,
+               .cpu_pwrst = PWRDM_FUNC_PWRST_ON,
+               .mpu_pwrst = PWRDM_FUNC_PWRST_ON,
        },
        {
-               .cpu_state = PWRDM_POWER_OFF,
-               .mpu_state = PWRDM_POWER_RET,
-               .mpu_logic_state = PWRDM_POWER_RET,
+               .cpu_pwrst = PWRDM_FUNC_PWRST_OFF,
+               .mpu_pwrst = PWRDM_FUNC_PWRST_CSWR,
        },
        {
-               .cpu_state = PWRDM_POWER_OFF,
-               .mpu_state = PWRDM_POWER_RET,
-               .mpu_logic_state = PWRDM_POWER_OFF,
+               .cpu_pwrst = PWRDM_FUNC_PWRST_OFF,
+               .mpu_pwrst = PWRDM_FUNC_PWRST_OSWR,
        },
 };
 
@@ -93,7 +89,7 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
         * out of coherency and in OFF mode.
         */
        if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) {
-               while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) {
+               while (pwrdm_read_fpwrst(cpu_pd[1]) != PWRDM_FUNC_PWRST_OFF) {
                        cpu_relax();
 
                        /*
@@ -118,19 +114,17 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
        cpu_pm_enter();
 
        if (dev->cpu == 0) {
-               pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
-               omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
+               WARN_ON(pwrdm_set_fpwrst(mpu_pd, cx->mpu_pwrst));
 
                /*
                 * 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))
-                               cpu_cluster_pm_enter();
+               if (cx->mpu_pwrst == PWRDM_FUNC_PWRST_OSWR)
+                       cpu_cluster_pm_enter();
        }
 
-       omap4_enter_lowpower(dev->cpu, cx->cpu_state);
+       omap4_mpuss_enter_lowpower(dev->cpu, cx->cpu_pwrst);
        cpu_done[dev->cpu] = true;
 
        /* Wakeup CPU1 only if it is not offlined */
arch/arm/mach-omap2/omap-hotplug.c +1 -1
index e712d17..d38b12d 100644
@@ -53,7 +53,7 @@ void __ref omap4_cpu_die(unsigned int cpu)
                /*
                 * Enter into low power state
                 */
-               omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF);
+               omap4_mpuss_hotplug_cpu(cpu, PWRDM_FUNC_PWRST_OFF);
 
                if (omap_secure_apis_support())
                        boot_cpu = omap_read_auxcoreboot0();
arch/arm/mach-omap2/omap-mpuss-lowpower.c +41 -28
index 80d4742..4dcebda 100644
@@ -82,31 +82,40 @@ static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr)
 {
        struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
 
+       /*
+        * XXX should not be writing directly into another IP block's
+        * address space!
+        */
        __raw_writel(addr, pm_info->wkup_sar_addr);
 }
 
 /*
  * Store the SCU power status value to scratchpad memory
  */
-static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
+static void scu_pwrst_prepare(unsigned int cpu_id, u8 fpwrst)
 {
        struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
        u32 scu_pwr_st;
 
-       switch (cpu_state) {
-       case PWRDM_POWER_RET:
+       switch (fpwrst) {
+       case PWRDM_FUNC_PWRST_CSWR:
+       case PWRDM_FUNC_PWRST_OSWR: /* XXX is this accurate? */
                scu_pwr_st = SCU_PM_DORMANT;
                break;
-       case PWRDM_POWER_OFF:
+       case PWRDM_FUNC_PWRST_OFF:
                scu_pwr_st = SCU_PM_POWEROFF;
                break;
-       case PWRDM_POWER_ON:
-       case PWRDM_POWER_INACTIVE:
+       case PWRDM_FUNC_PWRST_ON:
+       case PWRDM_FUNC_PWRST_INACTIVE:
        default:
                scu_pwr_st = SCU_PM_NORMAL;
                break;
        }
 
+       /*
+        * XXX should not be writing directly into another IP block's
+        * address space!
+        */
        __raw_writel(scu_pwr_st, pm_info->scu_sar_addr);
 }
 
@@ -159,6 +168,10 @@ static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state)
 {
        struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
 
+       /*
+        * XXX should not be writing directly into another IP block's
+        * address space!
+        */
        __raw_writel(save_state, pm_info->l2x0_sar_addr);
 }
 
@@ -183,11 +196,11 @@ static void save_l2x0_context(void)
 #endif
 
 /**
- * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
+ * omap4_mpuss_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
  * The purpose of this function is to manage low power programming
  * of OMAP4 MPUSS subsystem
  * @cpu : CPU ID
- * @power_state: Low power state.
+ * @fpwrst: functional powerstate for the MPUSS to enter
  *
  * MPUSS states for the context save:
  * save_state =
@@ -196,7 +209,7 @@ static void save_l2x0_context(void)
  *     2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
  *     3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
  */
-int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
+int omap4_mpuss_enter_lowpower(unsigned int cpu, u8 fpwrst)
 {
        struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
        unsigned int save_state = 0;
@@ -205,15 +218,16 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
        if (omap_rev() == OMAP4430_REV_ES1_0)
                return -ENXIO;
 
-       switch (power_state) {
-       case PWRDM_POWER_ON:
-       case PWRDM_POWER_INACTIVE:
+       switch (fpwrst) {
+       case PWRDM_FUNC_PWRST_ON:
+       case PWRDM_FUNC_PWRST_INACTIVE:
                save_state = 0;
                break;
-       case PWRDM_POWER_OFF:
+       case PWRDM_FUNC_PWRST_OFF:
                save_state = 1;
                break;
-       case PWRDM_POWER_RET:
+       case PWRDM_FUNC_PWRST_CSWR:
+       case PWRDM_FUNC_PWRST_OSWR:
        default:
                /*
                 * CPUx CSWR is invalid hardware state. Also CPUx OSWR
@@ -229,17 +243,16 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 
        /*
         * Check MPUSS next state and save interrupt controller if needed.
-        * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
+        * In MPUSS OSWR or device OFF, interrupt controller context is lost.
         */
        mpuss_clear_prev_logic_pwrst();
-       if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
-               (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
+       if (pwrdm_read_next_fpwrst(mpuss_pd) == PWRDM_FUNC_PWRST_OSWR)
                save_state = 2;
 
        cpu_clear_prev_logic_pwrst(cpu);
-       pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
+       WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, fpwrst));
        set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
-       scu_pwrst_prepare(cpu, power_state);
+       scu_pwrst_prepare(cpu, fpwrst);
        l2x0_pwrst_prepare(cpu, save_state);
 
        /*
@@ -255,7 +268,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
         * domain transition
         */
        wakeup_cpu = smp_processor_id();
-       pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
+       WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
 
        pwrdm_post_transition(NULL);
 
@@ -265,9 +278,9 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
 /**
  * omap4_hotplug_cpu: OMAP4 CPU hotplug entry
  * @cpu : CPU ID
- * @power_state: CPU low power state.
+ * @fpwrst: functional power state to program the CPU powerdomain to enter
  */
-int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
+int __cpuinit omap4_mpuss_hotplug_cpu(unsigned int cpu, u8 fpwrst)
 {
        struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
        unsigned int cpu_state = 0;
@@ -275,13 +288,13 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
        if (omap_rev() == OMAP4430_REV_ES1_0)
                return -ENXIO;
 
-       if (power_state == PWRDM_POWER_OFF)
+       if (fpwrst == PWRDM_FUNC_PWRST_OFF || fpwrst == PWRDM_FUNC_PWRST_OSWR)
                cpu_state = 1;
 
        pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
-       pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
+       WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, fpwrst));
        set_cpu_wakeup_addr(cpu, virt_to_phys(omap_secondary_startup));
-       scu_pwrst_prepare(cpu, power_state);
+       scu_pwrst_prepare(cpu, fpwrst);
 
        /*
         * CPU never retuns back if targeted power state is OFF mode.
@@ -290,7 +303,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
         */
        omap4_finish_suspend(cpu_state);
 
-       pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
+       WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
        return 0;
 }
 
@@ -325,7 +338,7 @@ int __init omap4_mpuss_init(void)
        cpu_clear_prev_logic_pwrst(0);
 
        /* Initialise CPU0 power domain state to ON */
-       pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
+       WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
 
        pm_info = &per_cpu(omap4_pm_info, 0x1);
        pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
@@ -342,7 +355,7 @@ int __init omap4_mpuss_init(void)
        cpu_clear_prev_logic_pwrst(1);
 
        /* Initialise CPU1 power domain state to ON */
-       pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
+       WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
 
        mpuss_pd = pwrdm_lookup("mpu_pwrdm");
        if (!mpuss_pd) {
arch/arm/mach-omap2/pm44xx.c +10 -13
index 7da75ae..595f84e 100644
@@ -26,10 +26,9 @@
 
 struct power_state {
        struct powerdomain *pwrdm;
-       u32 next_state;
+       u8 next_fpwrst;
 #ifdef CONFIG_SUSPEND
-       u32 saved_state;
-       u32 saved_logic_state;
+       u8 saved_fpwrst;
 #endif
        struct list_head node;
 };
@@ -40,20 +39,19 @@ static LIST_HEAD(pwrst_list);
 static int omap4_pm_suspend(void)
 {
        struct power_state *pwrst;
-       int state, ret = 0;
+       int prev_fpwrst;
+       int ret = 0;
        u32 cpu_id = smp_processor_id();
 
+       /* XXX Seems like these two loops could be combined into one loop? */
+
        /* Save current powerdomain state */
-       list_for_each_entry(pwrst, &pwrst_list, node) {
-               pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
-               pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm);
-       }
+       list_for_each_entry(pwrst, &pwrst_list, node)
+               pwrst->saved_fpwrst = pwrdm_read_next_fpwrst(pwrst->pwrdm);
 
        /* Set targeted power domain states by suspend */
-       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);
-       }
+       list_for_each_entry(pwrst, &pwrst_list, node)
+               WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
 
        /*
         * For MPUSS to hit power domain retention(CSWR or OSWR),
@@ -64,18 +62,20 @@ 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);

arch/arm/mach-omap2/pm44xx.c static int omap4_pm_suspend(void) · line 70

Quoted 10 lines
arch/arm/mach-omap2/pm44xx.c +3 -4
+       omap4_mpuss_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);
-               if (state > pwrst->next_state) {
-                       pr_info("Powerdomain (%s) didn't enter target state %d\n",
-                               pwrst->pwrdm->name, pwrst->next_state);
+               prev_fpwrst = pwrdm_read_prev_fpwrst(pwrst->pwrdm);
+               /* XXX test below should be != */

Is a change needed here?

Quoted 29 lines
arch/arm/mach-omap2/pm44xx.c +8 -5
+               if (prev_fpwrst > pwrst->next_fpwrst) {
+                       pr_info("Powerdomain (%s) didn't enter target state %s - entered state %s instead\n",
+                               pwrst->pwrdm->name,
+                               pwrdm_convert_fpwrst_to_name(pwrst->next_fpwrst),
+                               pwrdm_convert_fpwrst_to_name(prev_fpwrst));
                        ret = -1;
                }
-               omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
-               pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
+               WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->saved_fpwrst));
        }
        if (ret)
                pr_crit("Could not enter target state in pm_suspend\n");
@@ -113,10 +113,10 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
                return -ENOMEM;
 
        pwrst->pwrdm = pwrdm;
-       pwrst->next_state = PWRDM_POWER_RET;
+       pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
        list_add(&pwrst->node, &pwrst_list);
 
-       return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+       return WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
 }
 
 /**
 
 
--
Quoted 3 lines

To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

Regards,
Jean

#17 lore raw

PATCH 6/12 ARM: OMAP44xx: PM: convert to use the functional power states API

In reply to Paul Walmsley

Hi Paul,

On Sun, 2012-12-09 at 10:53 -0700, Paul Walmsley wrote:

<clip>

Review static LIST_HEAD(pwrst_list); · line 47

Quoted 11 lines
(quoted diff) +4 -1
@@ -40,20 +39,19 @@ static LIST_HEAD(pwrst_list);
 static int omap4_pm_suspend(void)
 {
 	struct power_state *pwrst;
-	int state, ret = 0;
+	int prev_fpwrst;
+	int ret = 0;
 	u32 cpu_id = smp_processor_id();
 
+	/* XXX Seems like these two loops could be combined into one loop? */
+

They can be combined yes.

<clip>

Review static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) · line 119

Quoted 10 lines
(quoted diff) +2 -2
@@ -113,10 +113,10 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 		return -ENOMEM;
 
 	pwrst->pwrdm = pwrdm;
-	pwrst->next_state = PWRDM_POWER_RET;
+	pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
 	list_add(&pwrst->node, &pwrst_list);
 
-	return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+	return WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));

This causes a regression on omap4, as several power domains can't idle after this anymore (they get programmed to ON state due to CSWR not being supported on them.) Following patch fixes this problem (applies on top of the whole set):

=============

From: Tero Kristo <[email protected]>
Date: Wed, 2 Jan 2013 18:05:42 +0200
Subject: [PATCH] ARM: OMAP4: PM: fix the power state setup

After the functional power state code changes, OMAP4 PM init code programs
powerdomains now to ON state if the domain does not support CSWR. This breaks
suspend and should be avoided.

Fixed by adding a loop to the pwrdms_setup code, that for each domain selects
the next fpwrst based on following order: CSWR, OSWR, OFF, ON. This allows
all the domains to enter supported low power states, instead of always selecting ON.

---
 arch/arm/mach-omap2/pm44xx.c |   22 +++++++++++++++++-----
 1 files changed, 17 insertions(+), 5 deletions(-)
arch/arm/mach-omap2/pm44xx.c +7 -0
index 8775ee5..67f05fe 100644
@@ -88,6 +88,13 @@ static int omap4_pm_suspend(void)
 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 {
 	struct power_state *pwrst;
+	const u8 fpwrst_states[] = {
+		PWRDM_FUNC_PWRST_CSWR,
+		PWRDM_FUNC_PWRST_OSWR,
+		PWRDM_FUNC_PWRST_OFF,
+		PWRDM_FUNC_PWRST_ON,
+	};
+	int i;
 
 	if (!pwrdm->pwrsts)
 		return 0;
@@ -106,12 +113,17 @@ static int __init pwrdms_setup(struct powerdomain

*pwrdm, void *unused)

pwrst->pwrdm = pwrdm;
/*
- * XXX This should be replaced by explicit lists of
- * powerdomains with specific powerstates to set
+ * We attempt to program the fpwrst of a domain in the following
+ * order: CSWR, OSWR, OFF, ON. This is needed as some domains
+ * don't support retention, and instead should go to off in low
+ * power modes. If everything else fails, the code falls back
+ * to ON state.
*/
- pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
- if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
- pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON;
+ for (i = 0; i < ARRAY_SIZE(fpwrst_states); i++) {
+ pwrst->next_fpwrst = fpwrst_states[i];
+ if (pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
+ break;
+ }
list_add(&pwrst->node, &pwrst_list);

return WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));

Signature · 1 line
1.7.4.1
#18 lore raw

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

In reply to Paul Walmsley

From: Jean Pihet <[email protected]>

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.

[paul at pwsan.com: use PWRDM_FPWRSTS_COUNT due to functional power state offset;
use powerdomain.c fn to convert func pwrsts to names; rename 'state' to 'fpwrst' to indicate use of func pwrsts; convert remaining users of the non-func pwrst API; add some kerneldoc]

---
 arch/arm/mach-omap2/pm-debug.c    |   42 ++++-----
 arch/arm/mach-omap2/powerdomain.c |  167 ++++++++++++++++++-------------------
 arch/arm/mach-omap2/powerdomain.h |   17 ++--
 3 files changed, 108 insertions(+), 118 deletions(-)
arch/arm/mach-omap2/pm-debug.c +20 -22
index 806a06b..72cf9e0 100644
@@ -53,13 +53,6 @@ enum {
 	DEBUG_FILE_TIMERS,
 };
 
-static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
-	"OFF",
-	"RET",
-	"INA",
-	"ON"
-};
-
 void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
 {
 	s64 t;
@@ -70,7 +63,7 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
 	/* Update timer for previous state */
 	t = sched_clock();
 
-	pwrdm->state_timer[prev] += t - pwrdm->timer;
+	pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer;
 
 	pwrdm->timer = t;
 }
@@ -79,6 +72,7 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
 {
 	struct seq_file *s = (struct seq_file *)user;
 
+	/* XXX This needs to be implemented in a better way */
 	if (strcmp(clkdm->name, "emu_clkdm") == 0 ||
 		strcmp(clkdm->name, "wkup_clkdm") == 0 ||
 		strncmp(clkdm->name, "dpll", 4) == 0)
@@ -94,23 +88,26 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
 {
 	struct seq_file *s = (struct seq_file *)user;
 	int i;
+	int curr_fpwrst;
 
 	if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
 		strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
 		strncmp(pwrdm->name, "dpll", 4) == 0)
 		return 0;
 
-	if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
-		printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
-			pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
+	curr_fpwrst = pwrdm_read_fpwrst(pwrdm);
+	if (pwrdm->fpwrst != curr_fpwrst)
+		pr_err("pwrdm state mismatch(%s) %s != %s\n",
+		       pwrdm->name,
+		       pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst),
+		       pwrdm_convert_fpwrst_to_name(curr_fpwrst));
 
 	seq_printf(s, "%s (%s)", pwrdm->name,
-			pwrdm_state_names[pwrdm->state]);
-	for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
-		seq_printf(s, ",%s:%d", pwrdm_state_names[i],
-			pwrdm->state_counter[i]);
+		   pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst));
+	for (i = PWRDM_FPWRST_OFFSET; i < PWRDM_MAX_FUNC_PWRSTS; i++)
+		seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i),
+			   pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]);
 
-	seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter);
 	for (i = 0; i < pwrdm->banks; i++)
 		seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1,
 				pwrdm->ret_mem_off_counter[i]);
@@ -133,11 +130,12 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
 	pwrdm_state_switch(pwrdm);
 
 	seq_printf(s, "%s (%s)", pwrdm->name,
-		pwrdm_state_names[pwrdm->state]);
+		   pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst));
 
-	for (i = 0; i < 4; i++)
-		seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
-			pwrdm->state_timer[i]);
+	for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+		seq_printf(s, ",%s:%lld",
+			   pwrdm_convert_fpwrst_to_name(i + PWRDM_FPWRST_OFFSET),
+			   pwrdm->fpwrst_timer[i]);
 
 	seq_printf(s, "\n");
 	return 0;
@@ -209,8 +207,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
 
 	t = sched_clock();
 
-	for (i = 0; i < 4; i++)
-		pwrdm->state_timer[i] = 0;
+	for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+		pwrdm->fpwrst_timer[i] = 0;
 
 	pwrdm->timer = t;
 
arch/arm/mach-omap2/powerdomain.c +79 -88

197 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.h +9 -8
index be835ff..849bc55 100644
@@ -46,6 +46,8 @@ enum pwrdm_func_state {
 	PWRDM_MAX_FUNC_PWRSTS		/* Last value, used as the max value */
 };
 
+#define PWRDM_FPWRSTS_COUNT	(PWRDM_MAX_FUNC_PWRSTS - PWRDM_FPWRST_OFFSET)
+
 /* Powerdomain basic power states */
 #define PWRDM_POWER_OFF		0x0
 #define PWRDM_POWER_RET		0x1
@@ -123,10 +125,10 @@ struct powerdomain;
  * @mem_pwrst_mask: (AM33XX only) mask for mem state bitfield in @pwrstst_offs
  * @mem_retst_mask: (AM33XX only) mask for mem retention state bitfield
  *	in @pwrstctrl_offs
- * @state:
- * @state_counter:
- * @timer:
- * @state_timer:
+ * @fpwrst: current func power state (set during pwrdm_(pre|post)_transition())
+ * @fpwrst_counter: estimated number of times the pwrdm entered the power states
+ * @timer: sched_clock() timestamp of last pwrdm_state_switch()
+ * @fpwrst_timer: estimated nanoseconds of residency in the various power states
  * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
  * @_lock_flags: stored flags when @_lock is taken
  *
@@ -146,12 +148,11 @@ struct powerdomain {
 	const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
 	const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
 	const u8 prcm_partition;
+	u8 fpwrst;
 	struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
 	struct list_head node;
 	struct list_head voltdm_node;
-	int state;
-	unsigned state_counter[PWRDM_MAX_PWRSTS];
-	unsigned ret_logic_off_counter;
+	unsigned fpwrst_counter[PWRDM_FPWRSTS_COUNT];
 	unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
 	spinlock_t _lock;
 	unsigned long _lock_flags;
@@ -165,7 +166,7 @@ struct powerdomain {
 
 #ifdef CONFIG_PM_DEBUG
 	s64 timer;
-	s64 state_timer[PWRDM_MAX_PWRSTS];
+	s64 fpwrst_timer[PWRDM_FPWRSTS_COUNT];
 #endif
 };
 
#19 lore raw

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

Paul,

Quoted 7 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

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.

Quoted 8 lines

This patch provides the information for each functional state.

[paul at pwsan.com: use PWRDM_FPWRSTS_COUNT due to functional power state offset;
use powerdomain.c fn to convert func pwrsts to names; rename 'state' to 'fpwrst' to indicate use of func pwrsts; convert remaining users of the non-func pwrst API; add some kerneldoc]

The patch does more than the description is telling. The function _update_logic_membank_counters is removed by this patch, is this intentional?

Quoted 211 lines
---
 arch/arm/mach-omap2/pm-debug.c    |   42 ++++-----
 arch/arm/mach-omap2/powerdomain.c |  167 ++++++++++++++++++-------------------
 arch/arm/mach-omap2/powerdomain.h |   17 ++--
 3 files changed, 108 insertions(+), 118 deletions(-)
arch/arm/mach-omap2/pm-debug.c +20 -22
index 806a06b..72cf9e0 100644
@@ -53,13 +53,6 @@ enum {
        DEBUG_FILE_TIMERS,
 };
 
-static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
-       "OFF",
-       "RET",
-       "INA",
-       "ON"
-};
-
 void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
 {
        s64 t;
@@ -70,7 +63,7 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
        /* Update timer for previous state */
        t = sched_clock();
 
-       pwrdm->state_timer[prev] += t - pwrdm->timer;
+       pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer;
 
        pwrdm->timer = t;
 }
@@ -79,6 +72,7 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
 {
        struct seq_file *s = (struct seq_file *)user;
 
+       /* XXX This needs to be implemented in a better way */
        if (strcmp(clkdm->name, "emu_clkdm") == 0 ||
                strcmp(clkdm->name, "wkup_clkdm") == 0 ||
                strncmp(clkdm->name, "dpll", 4) == 0)
@@ -94,23 +88,26 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
 {
        struct seq_file *s = (struct seq_file *)user;
        int i;
+       int curr_fpwrst;
 
        if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
                strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
                strncmp(pwrdm->name, "dpll", 4) == 0)
                return 0;
 
-       if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
-               printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
-                       pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
+       curr_fpwrst = pwrdm_read_fpwrst(pwrdm);
+       if (pwrdm->fpwrst != curr_fpwrst)
+               pr_err("pwrdm state mismatch(%s) %s != %s\n",
+                      pwrdm->name,
+                      pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst),
+                      pwrdm_convert_fpwrst_to_name(curr_fpwrst));
 
        seq_printf(s, "%s (%s)", pwrdm->name,
-                       pwrdm_state_names[pwrdm->state]);
-       for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
-               seq_printf(s, ",%s:%d", pwrdm_state_names[i],
-                       pwrdm->state_counter[i]);
+                  pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst));
+       for (i = PWRDM_FPWRST_OFFSET; i < PWRDM_MAX_FUNC_PWRSTS; i++)
+               seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i),
+                          pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]);
 
-       seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter);
        for (i = 0; i < pwrdm->banks; i++)
                seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1,
                                pwrdm->ret_mem_off_counter[i]);
@@ -133,11 +130,12 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
        pwrdm_state_switch(pwrdm);
 
        seq_printf(s, "%s (%s)", pwrdm->name,
-               pwrdm_state_names[pwrdm->state]);
+                  pwrdm_convert_fpwrst_to_name(pwrdm->fpwrst));
 
-       for (i = 0; i < 4; i++)
-               seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
-                       pwrdm->state_timer[i]);
+       for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+               seq_printf(s, ",%s:%lld",
+                          pwrdm_convert_fpwrst_to_name(i + PWRDM_FPWRST_OFFSET),
+                          pwrdm->fpwrst_timer[i]);
 
        seq_printf(s, "\n");
        return 0;
@@ -209,8 +207,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
 
        t = sched_clock();
 
-       for (i = 0; i < 4; i++)
-               pwrdm->state_timer[i] = 0;
+       for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+               pwrdm->fpwrst_timer[i] = 0;
 
        pwrdm->timer = t;
 
arch/arm/mach-omap2/powerdomain.c +4 -85
index 2c732b6..3e2e263 100644
@@ -115,97 +115,16 @@ 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++)
-               pwrdm->state_counter[i] = 0;
+       for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
+               pwrdm->fpwrst_counter[i] = 0;
 
-       pwrdm->ret_logic_off_counter = 0;
        for (i = 0; i < pwrdm->banks; i++)
                pwrdm->ret_mem_off_counter[i] = 0;
 
        arch_pwrdm->pwrdm_wait_transition(pwrdm);
-       pwrdm->state = pwrdm_read_pwrst(pwrdm);
-       pwrdm->state_counter[pwrdm->state] = 1;
+       pwrdm->fpwrst = pwrdm_read_fpwrst(pwrdm);
+       pwrdm->fpwrst_counter[pwrdm->fpwrst - PWRDM_FPWRST_OFFSET] = 1;
 
-       pr_debug("powerdomain: registered %s\n", pwrdm->name);
-
-       return 0;
-}
-
-static void _update_logic_membank_counters(struct powerdomain *pwrdm)
-{
-       int i;
-       u8 prev_logic_pwrst, prev_mem_pwrst;
-
-       prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
-       if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
-           (prev_logic_pwrst == PWRDM_POWER_OFF))
-               pwrdm->ret_logic_off_counter++;
-
-       for (i = 0; i < pwrdm->banks; i++) {
-               prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
-
-               if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
-                   (prev_mem_pwrst == PWRDM_POWER_OFF))
-                       pwrdm->ret_mem_off_counter[i]++;
-       }
-}
-
-static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
-{
-       int prev, next, state, trace_state = 0;
-
-       if (pwrdm == NULL)
-               return -EINVAL;
-
-       state = pwrdm_read_pwrst(pwrdm);
-
-       switch (flag) {
-       case PWRDM_STATE_NOW:
-               prev = pwrdm->state;
-               break;
-       case PWRDM_STATE_PREV:
-               prev = pwrdm_read_prev_pwrst(pwrdm);
-               if (pwrdm->state != prev)
-                       pwrdm->state_counter[prev]++;
-               if (prev == PWRDM_POWER_RET)
-                       _update_logic_membank_counters(pwrdm);
-               /*
-                * If the power domain did not hit the desired state,
-                * generate a trace event with both the desired and hit states
-                */
-               next = pwrdm_read_next_pwrst(pwrdm);
-               if (next != prev) {
-                       trace_state = (PWRDM_TRACE_STATES_FLAG |
-                                      ((next & OMAP_POWERSTATE_MASK) << 8) |
-                                      ((prev & OMAP_POWERSTATE_MASK) << 0));
-                       trace_power_domain_target(pwrdm->name, trace_state,
-                                                 smp_processor_id());
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (state != prev)
-               pwrdm->state_counter[state]++;
-
-       pm_dbg_update_time(pwrdm, prev);
-
-       pwrdm->state = state;
-
-       return 0;
-}
-
-static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
-{
-       pwrdm_clear_all_prev_pwrst(pwrdm);
-       _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
-       return 0;
-}
-
-static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
-{
-       _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
        return 0;
 }
 

arch/arm/mach-omap2/powerdomain.c static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) · line 490

Quoted 4 lines
arch/arm/mach-omap2/powerdomain.c +1 -0
@@ -568,6 +487,76 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
        return (ret) ? ret : fpwrst;
 }
 
+/* XXX Caller must hold pwrdm->_lock */

XXX should be replaced with a proper comment.

Quoted 149 lines
arch/arm/mach-omap2/powerdomain.c +74 -3
+static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
+{
+       int prev, next, fpwrst, trace_state = 0;
+       int i;
+       u8 prev_mem_pwrst;
+
+       if (pwrdm == NULL)
+               return -EINVAL;
+
+       fpwrst = _pwrdm_read_fpwrst(pwrdm);
+
+       switch (flag) {
+       case PWRDM_STATE_NOW:
+               prev = pwrdm->fpwrst;
+               break;
+       case PWRDM_STATE_PREV:
+               prev = _pwrdm_read_prev_fpwrst(pwrdm);
+               if (pwrdm->fpwrst != prev)
+                       pwrdm->fpwrst_counter[prev - PWRDM_FPWRST_OFFSET]++;
+               if (prev == PWRDM_FUNC_PWRST_CSWR ||
+                   prev == PWRDM_FUNC_PWRST_OSWR) {
+                       for (i = 0; i < pwrdm->banks; i++) {
+                               prev_mem_pwrst =
+                                       pwrdm_read_prev_mem_pwrst(pwrdm, i);
+                               if ((pwrdm->pwrsts_mem_ret[i] ==
+                                    PWRSTS_OFF_RET) &&
+                                   (prev_mem_pwrst == PWRDM_POWER_OFF))
+                                       pwrdm->ret_mem_off_counter[i]++;
+                       }
+               }
+               /*
+                * If the power domain did not hit the desired state,
+                * generate a trace event with both the desired and hit states
+                */
+               next = _pwrdm_read_next_fpwrst(pwrdm);
+               if (next != prev) {
+                       trace_state = (PWRDM_TRACE_STATES_FLAG | next << 8 |
+                                      prev);
+                       trace_power_domain_target(pwrdm->name, trace_state,
+                                                 smp_processor_id());
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (fpwrst != prev)
+               pwrdm->fpwrst_counter[fpwrst - PWRDM_FPWRST_OFFSET]++;
+
+       pm_dbg_update_time(pwrdm, prev);
+
+       pwrdm->fpwrst = fpwrst;
+
+       return 0;
+}
+
+static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
+{
+       pwrdm_clear_all_prev_pwrst(pwrdm);
+       _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
+       return 0;
+}
+
+static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
+{
+       _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
+       return 0;
+}
+
 /* Public functions */
 
 /**
@@ -638,7 +627,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);
+               pwrdm_set_next_fpwrst(temp_p, PWRDM_FUNC_PWRST_ON);
 
        return 0;
 }
@@ -1459,8 +1448,10 @@ int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
                return -ENODEV;
        }
 
-       count = pwrdm->state_counter[PWRDM_POWER_OFF];
-       count += pwrdm->ret_logic_off_counter;
+       count = pwrdm->fpwrst_counter[PWRDM_FUNC_PWRST_OFF -
+                                     PWRDM_FPWRST_OFFSET];
+       count += pwrdm->fpwrst_counter[PWRDM_FUNC_PWRST_OSWR -
+                                      PWRDM_FPWRST_OFFSET];
 
        for (i = 0; i < pwrdm->banks; i++)
                count += pwrdm->ret_mem_off_counter[i];
arch/arm/mach-omap2/powerdomain.h +9 -9
index be835ff..849bc55 100644
@@ -46,6 +46,8 @@ enum pwrdm_func_state {
        PWRDM_MAX_FUNC_PWRSTS           /* Last value, used as the max value */
 };
 
+#define PWRDM_FPWRSTS_COUNT    (PWRDM_MAX_FUNC_PWRSTS - PWRDM_FPWRST_OFFSET)
+
 /* Powerdomain basic power states */
 #define PWRDM_POWER_OFF                0x0
 #define PWRDM_POWER_RET                0x1
@@ -123,10 +125,10 @@ struct powerdomain;
  * @mem_pwrst_mask: (AM33XX only) mask for mem state bitfield in @pwrstst_offs
  * @mem_retst_mask: (AM33XX only) mask for mem retention state bitfield
  *     in @pwrstctrl_offs
- * @state:
- * @state_counter:
- * @timer:
- * @state_timer:
+ * @fpwrst: current func power state (set during pwrdm_(pre|post)_transition())
+ * @fpwrst_counter: estimated number of times the pwrdm entered the power states
+ * @timer: sched_clock() timestamp of last pwrdm_state_switch()
+ * @fpwrst_timer: estimated nanoseconds of residency in the various power states
  * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
  * @_lock_flags: stored flags when @_lock is taken
  *
@@ -146,12 +148,11 @@ struct powerdomain {
        const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
        const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
        const u8 prcm_partition;
+       u8 fpwrst;
        struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
        struct list_head node;
        struct list_head voltdm_node;
-       int state;
-       unsigned state_counter[PWRDM_MAX_PWRSTS];
-       unsigned ret_logic_off_counter;
+       unsigned fpwrst_counter[PWRDM_FPWRSTS_COUNT];
        unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
        spinlock_t _lock;
        unsigned long _lock_flags;
@@ -165,7 +166,7 @@ struct powerdomain {
 
 #ifdef CONFIG_PM_DEBUG
        s64 timer;
-       s64 state_timer[PWRDM_MAX_PWRSTS];
+       s64 fpwrst_timer[PWRDM_FPWRSTS_COUNT];
 #endif
 };
 
 
 
--
Quoted 3 lines

To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

Regards,
Jean

#20 lore raw

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

In reply to Paul Walmsley

Hi Paul,

Quoted 49 lines · Paul Walmsley

From: Jean Pihet <[email protected]>

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.

[paul at pwsan.com: use PWRDM_FPWRSTS_COUNT due to functional power state offset;
use powerdomain.c fn to convert func pwrsts to names; rename 'state' to 'fpwrst' to indicate use of func pwrsts; convert remaining users of the non-func pwrst API; add some kerneldoc]

---
 arch/arm/mach-omap2/pm-debug.c    |   42 ++++-----
 arch/arm/mach-omap2/powerdomain.c |  167 ++++++++++++++++++-------------------
 arch/arm/mach-omap2/powerdomain.h |   17 ++--
 3 files changed, 108 insertions(+), 118 deletions(-)
arch/arm/mach-omap2/pm-debug.c +1 -8
index 806a06b..72cf9e0 100644
@@ -53,13 +53,6 @@ enum {
 	DEBUG_FILE_TIMERS,
 };
 
-static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = {
-	"OFF",
-	"RET",
-	"INA",
-	"ON"
-};
-
 void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
 {
 	s64 t;
@@ -70,7 +63,7 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
 	/* Update timer for previous state */
 	t = sched_clock();
 
-	pwrdm->state_timer[prev] += t - pwrdm->timer;
+	pwrdm->fpwrst_timer[prev - PWRDM_FPWRST_OFFSET] += t - pwrdm->timer;
 
 	pwrdm->timer = t;
 }

arch/arm/mach-omap2/pm-debug.c static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) · line 75

Quoted 4 lines
arch/arm/mach-omap2/pm-debug.c +1 -0
@@ -79,6 +72,7 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
 {
 	struct seq_file *s = (struct seq_file *)user;
 
+	/* XXX This needs to be implemented in a better way */

IMO, this part should be dropped, or re-implemented completely. It is uninformative and I don't think anybody uses it. With the usecounting fixes in place, it is better than before but still doesn't provide too much useful information. Would be good to show the clocks that actually are enabled along with the clockdomain use counts, but in either case, it doesn't belong in the same debugfs file as the pwrdm counters.

-Tero

#21 lore raw

PATCH 8/12 ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs

In reply to Paul Walmsley

The powerdomain code that exported the ability to read or change the previous, current, or next powerdomain or logic power states can now be removed. All this is controlled via the powerdomain functional power state interface now.

---
 arch/arm/mach-omap2/powerdomain.c |  270 +++----------------------------------
 arch/arm/mach-omap2/powerdomain.h |    9 -
 2 files changed, 21 insertions(+), 258 deletions(-)
arch/arm/mach-omap2/powerdomain.c +21 -249
index 3e2e263..86fe84c 100644
@@ -253,9 +253,6 @@ static int _match_pwrst(u32 pwrsts, int pwrst, int min, int max)
 static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
 				  u8 *pwrdm_pwrst, u8 *logic_retst)
 {
-	if (!pwrdm || !pwrdm_pwrst || !logic_retst)
-		return -EINVAL;
-
 	switch (fpwrst) {
 	case PWRDM_FUNC_PWRST_ON:
 		*pwrdm_pwrst = PWRDM_POWER_ON;
@@ -317,9 +314,6 @@ static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
 static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,
 				  u8 *fpwrst)
 {
-	if (!pwrdm || !fpwrst)
-		return -EINVAL;
-
 	switch (pwrst) {
 	case PWRDM_POWER_ON:
 		*fpwrst = PWRDM_FUNC_PWRST_ON;
@@ -370,16 +364,27 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
 	if (!_pwrdm_pwrst_is_controllable(pwrdm))
 		return 0;
 
+	if (!arch_pwrdm || !arch_pwrdm->pwrdm_set_next_pwrst)
+		return -EINVAL;
+
+	if (!(pwrdm->pwrsts & (1 << pwrst)))
+		return -EINVAL;
+
 	if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET) {
-		ret = pwrdm_set_logic_retst(pwrdm, logic);
-		if (ret) {
-			pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
-			       __func__, logic, pwrdm->name);
-			return ret;
+		if (!(pwrdm->pwrsts_logic_ret & (1 << logic)))
+			return -EINVAL;
+
+		if (arch_pwrdm->pwrdm_set_logic_retst) {
+			ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, logic);
+			if (ret) {
+				pr_err("%s: unable to set logic state %0x of powerdomain: %s\n",
+				       __func__, logic, pwrdm->name);
+				return ret;
+			}
 		}
 	}
 
-	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
+	ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
 	if (ret)
 		pr_err("%s: unable to set power state %0x of powerdomain: %s\n",
 		       __func__, pwrst, pwrdm->name);
@@ -847,133 +852,6 @@ int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
 }
 
 /**
- * pwrdm_set_next_pwrst - set next powerdomain power state
- * @pwrdm: struct powerdomain * to set
- * @pwrst: one of the PWRDM_POWER_* macros
- *
- * Set the powerdomain @pwrdm's next power state to @pwrst.  The powerdomain
- * may not enter this state immediately if the preconditions for this state
- * have not been satisfied.  Returns -EINVAL if the powerdomain pointer is
- * null or if the power state is invalid for the powerdomin, or returns 0
- * upon success.
- */
-int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (!(pwrdm->pwrsts & (1 << pwrst)))
-		return -EINVAL;
-
-	pr_debug("powerdomain: %s: setting next powerstate to %0x\n",
-		 pwrdm->name, pwrst);
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst)
-		ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
-
-	return ret;
-}
-
-/**
- * pwrdm_read_next_pwrst - get next powerdomain power state
- * @pwrdm: struct powerdomain * to get power state
- *
- * Return the powerdomain @pwrdm's next power state.  Returns -EINVAL
- * if the powerdomain pointer is null or returns the next power state
- * upon success.
- */
-int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst)
-		ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
-
-	return ret;
-}
-
-/**
- * pwrdm_read_pwrst - get current powerdomain power state
- * @pwrdm: struct powerdomain * to get power state
- *
- * Return the powerdomain @pwrdm's current power state.	Returns -EINVAL
- * if the powerdomain pointer is null or returns the current power state
- * upon success. Note that if the power domain only supports the ON state
- * then just return ON as the current state.
- */
-int pwrdm_read_pwrst(struct powerdomain *pwrdm)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (!_pwrdm_pwrst_can_change(pwrdm))
-		return PWRDM_POWER_ON;
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
-		ret = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
-
-	return ret;
-}
-
-/**
- * pwrdm_read_prev_pwrst - get previous powerdomain power state
- * @pwrdm: struct powerdomain * to get previous power state
- *
- * Return the powerdomain @pwrdm's previous power state.  Returns -EINVAL
- * if the powerdomain pointer is null or returns the previous power state
- * upon success.
- */
-int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst)
-		ret = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
-
-	return ret;
-}
-
-/**
- * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
- * @pwrdm: struct powerdomain * to set
- * @pwrst: one of the PWRDM_POWER_* macros
- *
- * Set the next power state @pwrst that the logic portion of the
- * powerdomain @pwrdm will enter when the powerdomain enters retention.
- * This will be either RETENTION or OFF, if supported.  Returns
- * -EINVAL if the powerdomain pointer is null or the target power
- * state is not not supported, or returns 0 upon success.
- */
-int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
-		return -EINVAL;
-
-	pr_debug("powerdomain: %s: setting next logic powerstate to %0x\n",
-		 pwrdm->name, pwrst);
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
-		ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, pwrst);
-
-	return ret;
-}
-
-/**
  * pwrdm_set_mem_onst - set memory power state while powerdomain ON
  * @pwrdm: struct powerdomain * to set
  * @bank: memory bank number to set (0-3)
@@ -1049,70 +927,6 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
 }
 
 /**
- * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
- * @pwrdm: struct powerdomain * to get current logic retention power state
- *
- * Return the power state that the logic portion of powerdomain @pwrdm
- * will enter when the powerdomain enters retention.  Returns -EINVAL
- * if the powerdomain pointer is null or returns the logic retention
- * power state upon success.
- */
-int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst)
-		ret = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
-
-	return ret;
-}
-
-/**
- * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
- * @pwrdm: struct powerdomain * to get previous logic power state
- *
- * Return the powerdomain @pwrdm's previous logic power state.  Returns
- * -EINVAL if the powerdomain pointer is null or returns the previous
- * logic power state upon success.
- */
-int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst)
-		ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
-
-	return ret;
-}
-
-/**
- * pwrdm_read_logic_retst - get next powerdomain logic power state
- * @pwrdm: struct powerdomain * to get next logic power state
- *
- * Return the powerdomain pwrdm's logic power state.  Returns -EINVAL
- * if the powerdomain pointer is null or returns the next logic
- * power state upon success.
- */
-int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
-{
-	int ret = -EINVAL;
-
-	if (!pwrdm)
-		return -EINVAL;
-
-	if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst)
-		ret = arch_pwrdm->pwrdm_read_logic_retst(pwrdm);
-
-	return ret;
-}
-
-/**
  * pwrdm_read_mem_pwrst - get current memory bank power state
  * @pwrdm: struct powerdomain * to get current memory bank power state
  * @bank: memory bank number (0-3)
@@ -1342,7 +1156,7 @@ int pwrdm_post_transition(struct powerdomain *pwrdm)
 	return 0;
 }
 
-/* Types of sleep_switch used in omap_set_pwrdm_state */
+/* Types of sleep_switch used in pwrdm_set_fpwrst() */
 #define ALREADYACTIVE_SWITCH	0
 #define FORCEWAKEUP_SWITCH	1
 #define LOWPOWERSTATE_SWITCH	2
@@ -1352,7 +1166,7 @@ static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
 {
 	u8 curr_pwrst, sleep_switch;
 
-	curr_pwrst = pwrdm_read_pwrst(pwrdm);
+	curr_pwrst = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
 	if (curr_pwrst < PWRDM_POWER_ON) {
 		if (curr_pwrst > pwrst &&
 		    pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
@@ -1389,48 +1203,6 @@ static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
 	}
 }
 
-/*
- * This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported.
- */
-int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
-{
-	u8 next_pwrst, sleep_switch;
-	int ret = 0;
-	bool hwsup = false;
-
-	if (!pwrdm || IS_ERR(pwrdm))
-		return -EINVAL;
-
-	while (!(pwrdm->pwrsts & (1 << pwrst))) {
-		if (pwrst == PWRDM_POWER_OFF)
-			return ret;
-		pwrst--;
-	}
-
-	pwrdm_lock(pwrdm);
-
-	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
-	if (next_pwrst == pwrst) {
-		pwrdm_unlock(pwrdm);
-		return ret;
-	}
-
-	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, pwrst,
-							    &hwsup);
-
-	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
-	if (ret)
-		pr_err("%s: unable to set power state of powerdomain: %s\n",
-		       __func__, pwrdm->name);
-
-	_pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
-
-	pwrdm_unlock(pwrdm);
-
-	return ret;
-}
-
 /**
  * pwrdm_get_context_loss_count - get powerdomain's context loss count
  * @pwrdm: struct powerdomain * to wait for
@@ -1621,7 +1393,7 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 {
 	u8 next_fpwrst, pwrst, logic, sleep_switch;
 	int ret = 0;
-	bool hwsup;
+	bool hwsup = false;
 
 	if (!pwrdm || IS_ERR(pwrdm) || !arch_pwrdm ||
 	    !arch_pwrdm->pwrdm_read_pwrst)
@@ -1651,7 +1423,7 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
 	trace_power_domain_target(pwrdm->name, next_fpwrst,
 				  smp_processor_id());
 
-	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, pwrst,
+	sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, fpwrst,
 							    &hwsup);
 
 	ret = _set_logic_retst_and_pwrdm_pwrst(pwrdm, logic, pwrst);
arch/arm/mach-omap2/powerdomain.h +0 -9
index 849bc55..aa1c9ae 100644
@@ -232,19 +232,10 @@ 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);
-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 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);
-
-int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
-int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
-int pwrdm_read_logic_retst(struct powerdomain *pwrdm);
 int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
 int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
 int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank);
#22 lore raw

PATCH 9/12 ARM: OMAP2+: powerdomain: add ability to test for supported power states

In reply to Paul Walmsley

Add pwrdm_supports_fpwrst(), intended for use by the PM code to avoid attempting to program a powerdomain to a power state that it doesn't support.

---
 arch/arm/mach-omap2/powerdomain.c |   33 +++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/powerdomain.h |    1 +
 2 files changed, 34 insertions(+)
arch/arm/mach-omap2/powerdomain.c +33 -0
index 86fe84c..6ba79df 100644
@@ -1495,3 +1495,36 @@ int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
 	return ret;
 }
 
+/**
+ * pwrdm_supports_fpwrst - does the powerdomain @pwrdm support the @fpwrst power
+ * state?
+ * @pwrdm: struct powerdomain * pointing to a powerdomain to test
+ * @fpwrst: functional power state
+ *
+ * Returns true if the powerdomain pointed to by @pwrdm can enter the
+ * functional power state @fpwrst, or false if not.
+ */
+bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
+{
+	u8 pwrst, logic;
+	int ret;
+
+	if (!pwrdm || IS_ERR(pwrdm))
+		return false;
+
+	ret = _pwrdm_fpwrst_to_pwrst(pwrdm, fpwrst, &pwrst, &logic);
+	if (ret)
+		return false;
+
+	pr_debug("%s: pwrdm %s: set fpwrst %0x\n", __func__, pwrdm->name,
+		 fpwrst);
+
+	if (pwrdm->pwrsts_logic_ret && pwrst == PWRDM_POWER_RET &&
+	    !(pwrdm->pwrsts_logic_ret & (1 << logic)))
+		return false;
+
+	if (!(pwrdm->pwrsts & (1 << pwrst)))
+		return false;
+
+	return true;
+}
arch/arm/mach-omap2/powerdomain.h +1 -0
index aa1c9ae..52be8cd 100644
@@ -260,6 +260,7 @@ extern int pwrdm_set_fpwrst(struct powerdomain *pwrdm,
 			    enum pwrdm_func_state fpwrst);
 extern int pwrdm_read_fpwrst(struct powerdomain *pwrdm);
 extern int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm);
+extern bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst);
 
 extern void omap242x_powerdomains_init(void);
 extern void omap243x_powerdomains_init(void);
#23 lore raw

PATCH 10/12 ARM: OMAP2+: powerdomain/PM: only program supported power states

In reply to Paul Walmsley

Previously the PM code attempted to program power states that the underlying powerdomain didn't support. Change this to only program power states that are supported by the hardware.

In the future, the PM code should be changed further to program explicit lists of powerdomain power states that are valid for each chip (and supported by the underlying software). Also the powerdomain code should return errors when PM code tries to program an unsupported power state, rather than simply ignoring the requrest.

---
 arch/arm/mach-omap2/pm34xx.c      |   34 +++++++++++++++++
 arch/arm/mach-omap2/pm44xx.c      |    9 ++++-
 arch/arm/mach-omap2/powerdomain.c |   74 ++++++-------------------------------
 3 files changed, 52 insertions(+), 65 deletions(-)
arch/arm/mach-omap2/pm34xx.c +33 -1
index 8aac26e..c4d4154 100644
@@ -395,7 +395,14 @@ restore:
 	/* Restore next_pwrsts */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		prev_fpwrst = pwrdm_read_prev_fpwrst(pwrst->pwrdm);
-		if (prev_fpwrst > pwrst->next_fpwrst) {
+		/*
+		 * The SGX powerdomain will report its previous state as
+		 * INACTIVE when it's been programmed to ON.  This seems to
+		 * be the only OMAP3 powerdomain that does this.
+		 */
+		if (prev_fpwrst == PWRDM_FUNC_PWRST_INACTIVE)
+			prev_fpwrst = PWRDM_FUNC_PWRST_ON;
+		if (prev_fpwrst != pwrst->next_fpwrst) {
 			pr_info("Powerdomain %s didn't enter target state %s - entered state %s instead\n",
 				pwrst->pwrdm->name,
 				pwrdm_convert_fpwrst_to_name(pwrst->next_fpwrst),
@@ -575,6 +582,10 @@ void omap3_pm_off_mode_enable(int enable)
 
 	fpwrst = (enable) ? PWRDM_FUNC_PWRST_OFF : PWRDM_FUNC_PWRST_CSWR;
 
+	/*
+	 * XXX This should be replaced by explicit lists of
+	 * powerdomains with specific powerstates to set
+	 */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) &&
 		    pwrst->pwrdm == core_pwrdm &&
@@ -584,6 +595,12 @@ void omap3_pm_off_mode_enable(int enable)
 				__func__);
 		} else {
 			pwrst->next_fpwrst = fpwrst;
+			if (!pwrdm_supports_fpwrst(pwrst->pwrdm,
+						   pwrst->next_fpwrst))
+				pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
+			if (!pwrdm_supports_fpwrst(pwrst->pwrdm,
+						   pwrst->next_fpwrst))
+				pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON;
 		}
 		WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
 	}
@@ -603,9 +620,17 @@ int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, u8 fpwrst)
 {
 	struct power_state *pwrst;
 
+	/*
+	 * XXX This should be replaced by per-powerdomain suspend
+	 * power state files
+	 */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		if (pwrst->pwrdm == pwrdm) {
 			pwrst->next_fpwrst = fpwrst;
+			if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
+				pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
+			if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
+				pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON;
 			return 0;
 		}
 	}
@@ -623,7 +648,14 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
+
+	/*
+	 * XXX This should be replaced by explicit lists of
+	 * powerdomains with specific powerstates to set
+	 */
 	pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
+	if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
+		pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON;
 	list_add(&pwrst->node, &pwrst_list);
 
 	if (pwrdm_has_hdwr_sar(pwrdm))
arch/arm/mach-omap2/pm44xx.c +7 -2
index 595f84e..5db9a91 100644
@@ -67,8 +67,7 @@ static int omap4_pm_suspend(void)
 	/* Restore next powerdomain state */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		prev_fpwrst = pwrdm_read_prev_fpwrst(pwrst->pwrdm);
-		/* XXX test below should be != */
-		if (prev_fpwrst > pwrst->next_fpwrst) {
+		if (prev_fpwrst != pwrst->next_fpwrst) {
 			pr_info("Powerdomain (%s) didn't enter target state %s - entered state %s instead\n",
 				pwrst->pwrdm->name,
 				pwrdm_convert_fpwrst_to_name(pwrst->next_fpwrst),
@@ -113,7 +112,13 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 		return -ENOMEM;
 
 	pwrst->pwrdm = pwrdm;
+	/*
+	 * XXX This should be replaced by explicit lists of
+	 * powerdomains with specific powerstates to set
+	 */
 	pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
+	if (!pwrdm_supports_fpwrst(pwrdm, pwrst->next_fpwrst))
+		pwrst->next_fpwrst = PWRDM_FUNC_PWRST_ON;
 	list_add(&pwrst->node, &pwrst_list);
 
 	return WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
arch/arm/mach-omap2/powerdomain.c +12 -62

113 lines not on this page · raw message

#24 lore raw

PATCH 11/12 ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init

In reply to Paul Walmsley

During powerdomain init, we were previously programming a reasonable default for the powerdomain and logic next-power-state fields, but not touching the memory bank next-power-state fields. To ensure that the previous OS or bootloader didn't leave the system in a bad state, program the memory bank next-power-state bitfields to reasonable defaults.

---
 arch/arm/mach-omap2/powerdomain.c |   21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/powerdomain.c +14 -7
index fdeabbf..a70e3f6 100644
@@ -563,21 +563,28 @@ int pwrdm_register_pwrdms(struct powerdomain **ps)
  *
  * Do whatever is necessary to initialize registered powerdomains and
  * powerdomain code.  Currently, this programs the next power state
- * for each powerdomain to ON.  This prevents powerdomains from
- * unexpectedly losing context or entering high wakeup latency modes
- * with non-power-management-enabled kernels.  Must be called after
- * pwrdm_register_pwrdms().  Returns -EACCES if called before
- * pwrdm_register_pwrdms(), or 0 upon success.
+ * for each powerdomain to ON, and programs the memory bank power
+ * states to follow the powerdomain power states.  This prevents
+ * powerdomains from unexpectedly losing context or entering high
+ * wakeup latency modes with non-power-management-enabled kernels.
+ * Must be called after pwrdm_register_pwrdms().  Returns -EACCES if
+ * called before pwrdm_register_pwrdms(), or 0 upon success.
  */
 int pwrdm_complete_init(void)
 {
 	struct powerdomain *temp_p;
+	int i;
 
 	if (list_empty(&pwrdm_list))
 		return -EACCES;
 
-	list_for_each_entry(temp_p, &pwrdm_list, node)
-		pwrdm_set_next_fpwrst(temp_p, PWRDM_FUNC_PWRST_ON);
+	list_for_each_entry(temp_p, &pwrdm_list, node) {
+		for (i = 0; i < temp_p->banks; i++) {
+			pwrdm_set_mem_onst(temp_p, i, PWRDM_POWER_ON);
+			pwrdm_set_mem_retst(temp_p, i, PWRDM_POWER_RET);
+		}
+		WARN_ON(pwrdm_set_next_fpwrst(temp_p, PWRDM_FUNC_PWRST_ON));
+	}
 
 	return 0;
 }
#25 lore raw

PATCH 12/12 ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain

In reply to Paul Walmsley

Assume that the memory bank power states follow the powerdomain power states. The motivations are to reduce the amount of powerdomain code, decrease the execution time of the powerdomain state switch code, and simplify the power state debug.

This assumption is true for the currently-implemented functional power states. If it ceases to be true, the memory bank power states should be controlled via the functional power states, rather than controlled via low-level functions.

For the moment, the underlying implementation code in mach-omap2/prm*.c has been preserved, although some of that code may be removable too.

Cc Tero Kristo <[email protected]>
Cc Rajendra Nayak <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/pm-debug.c    |    4 -
 arch/arm/mach-omap2/pm24xx.c      |    9 -
 arch/arm/mach-omap2/powerdomain.c |  277 +++++++++++--------------------------
 arch/arm/mach-omap2/powerdomain.h |    9 -
 4 files changed, 79 insertions(+), 220 deletions(-)
arch/arm/mach-omap2/pm-debug.c +0 -4
index 72cf9e0..03da2e3 100644
@@ -108,10 +108,6 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
 		seq_printf(s, ",%s:%d", pwrdm_convert_fpwrst_to_name(i),
 			   pwrdm->fpwrst_counter[i - PWRDM_FPWRST_OFFSET]);
 
-	for (i = 0; i < pwrdm->banks; i++)
-		seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1,
-				pwrdm->ret_mem_off_counter[i]);
-
 	seq_printf(s, "\n");
 
 	return 0;
arch/arm/mach-omap2/pm24xx.c +0 -9
index 29abb63..99c16c2 100644
@@ -230,7 +230,6 @@ out:
 
 static void __init prcm_setup_regs(void)
 {
-	int i, num_mem_banks;
 	struct powerdomain *pwrdm;
 
 	/*
@@ -240,14 +239,6 @@ static void __init prcm_setup_regs(void)
 	omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
 			  OMAP2_PRCM_SYSCONFIG_OFFSET);
 
-	/*
-	 * Set CORE powerdomain memory banks to retain their contents
-	 * during RETENTION
-	 */
-	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);
-
 	/* Force-power down DSP, GFX powerdomains */
 
 	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
arch/arm/mach-omap2/powerdomain.c +79 -198

329 lines not on this page · raw message

arch/arm/mach-omap2/powerdomain.h +0 -9
index 52be8cd..7921f52 100644
@@ -153,7 +153,6 @@ struct powerdomain {
 	struct list_head node;
 	struct list_head voltdm_node;
 	unsigned fpwrst_counter[PWRDM_FPWRSTS_COUNT];
-	unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
 	spinlock_t _lock;
 	unsigned long _lock_flags;
 	const u8 pwrstctrl_offs;
@@ -230,16 +229,8 @@ int pwrdm_for_each_clkdm(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_clear_all_prev_pwrst(struct powerdomain *pwrdm);
 
-int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
-int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
-int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
-int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
-int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank);
-
 int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
 int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
 bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
#26 lore raw

cover ARM: OMAP2+: powerdomain/PM: convert to functional power states

In reply to Paul Walmsley

Hi Paul,

As mentioned with the previous set, I have tested this one also on omap3beagle + omap4panda boards. omap4 has one regression caused by this set, as commented on the patch itself. Also posted a couple of other minor comments. Other than that, you can consider this set as acked by me.

-Tero

Quoted 83 lines · Paul Walmsley

Hi

This series converts the OMAP2+ powerdomain and PM code to use "functional power states" - high-level power states such as "OSWR", which reflect changes in multiple underlying registers, rather than expecting high-level PM code to program the registers directly. This is intended to reduce the complexity of the high-level PM code and to make it easier to implement register caching of the various powerdomain registers, some of which are quite slow to access.

- Paul

---

vmlinux object size
(delta in bytes from TEST_pm_cleanup_fixes_b_3.9 (2f8d7b1f0048df431ca226d81c5c27c4dd21953b)):

   text     data      bss    total  kernel
   +456      -56        0     +400  am33xx_only
   +448      -96        0     +352  n800_multi_omap2xxx
   +448      -96        0     +352  n800_only_a
      0        0        0        0  omap1_defconfig
      0        0        0        0  omap1_defconfig_1510innovator_only
      0        0        0        0  omap1_defconfig_5912osk_only
  +1180     -744        0     +436  omap2plus_defconfig
   +584      -72        0     +512  omap2plus_defconfig_2430sdp_only
  +1244     -808        0     +436  omap2plus_defconfig_cpupm
   +976    -1224        0     -248  omap2plus_defconfig_no_pm
   +844     -408        0     +436  omap2plus_defconfig_omap2_4_only
  +1088     -624        0     +464  omap2plus_defconfig_omap3_4_only
  +1292    -1232     -352     -292  rmk_omap3430_ldp_allnoconfig
   +916     -720        0     +196  rmk_omap3430_ldp_oldconfig
  +1292    -1232     -352     -292  rmk_omap4430_sdp_allnoconfig
   +840     -392        0     +448  rmk_omap4430_sdp_oldconfig

Boot-time memory difference
(delta in bytes from TEST_pm_cleanup_fixes_b_3.9 (2f8d7b1f0048df431ca226d81c5c27c4dd21953b))

  avail  rsrvd   high  freed  board          kconfig
    -8k     8k      .      .  2430sdp        omap2plus_defconfig
    -8k     8k      .      .  3517evm        omap2plus_defconfig
    -8k     8k      .      .  3530es3beagle  omap2plus_defconfig
    -8k     8k      .      .  3730beaglexm   omap2plus_defconfig
    -8k     8k      .      .  37xxevm        omap2plus_defconfig
    -8k     8k      .      .  4430es2panda   omap2plus_defconfig
    -8k     8k      .      .  4460pandaes    omap2plus_defconfig
    -8k     8k      .      .  cmt3517        omap2plus_defconfig

Jean Pihet (6):
ARM: OMAP2+: PM: introduce power domains functional states
ARM: OMAP2+: PM debug: trace the functional power domains states
ARM: OMAP2xxx: PM: convert to use the functional power states API
ARM: OMAP3xxx: PM: convert to use the functional power states API
ARM: OMAP44xx: PM: convert to use the functional power states API
ARM: OMAP2+: PM: use power domain functional state in stats counters

Paul Walmsley (6):
ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities
ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs
ARM: OMAP2+: powerdomain: add ability to test for supported power states
ARM: OMAP2+: powerdomain/PM: only program supported power states
ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init
ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain

 arch/arm/mach-omap2/common.h              |    7 
 arch/arm/mach-omap2/cpuidle34xx.c         |   95 +-
 arch/arm/mach-omap2/cpuidle44xx.c         |   32 -
 arch/arm/mach-omap2/omap-hotplug.c        |    2 
 arch/arm/mach-omap2/omap-mpuss-lowpower.c |   69 +-
 arch/arm/mach-omap2/pm-debug.c            |   46 -
 arch/arm/mach-omap2/pm.h                  |    2 
 arch/arm/mach-omap2/pm24xx.c              |   33 -
 arch/arm/mach-omap2/pm34xx.c              |  188 +++-
 arch/arm/mach-omap2/pm44xx.c              |   47 +
 arch/arm/mach-omap2/powerdomain.c         | 1235 +++++++++++++++++------------
 arch/arm/mach-omap2/powerdomain.h         |   69 +-
 12 files changed, 1040 insertions(+), 785 deletions(-)

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