* [PATCH 01/12] ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
@ 2012-12-09 17:52 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states Paul Walmsley
` (11 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:52 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/powerdomain.c | 56 +++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 2a5f15b..94b89a25 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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 */
/**
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
2012-12-09 17:52 ` [PATCH 01/12] ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-12 10:00 ` Jean Pihet
` (3 more replies)
2012-12-09 17:53 ` [PATCH 03/12] ARM: OMAP2+: PM debug: trace the functional power domains states Paul Walmsley
` (10 subsequent siblings)
12 siblings, 4 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <jean.pihet@newoldbits.com>
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 <rnayak@ti.com>
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.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Cc: Tero Kristo <t-kristo@ti.com>
Cc: Rajendra Nayak <rnayak@ti.com>
Cc: Nishanth Menon <nm@ti.com>
[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]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/powerdomain.c | 525 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 33 ++
2 files changed, 553 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 94b89a25..18f33de 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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;
+}
+
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 842ba46..be835ff 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-09 17:53 ` [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states Paul Walmsley
@ 2012-12-12 10:00 ` Jean Pihet
2013-01-29 21:20 ` Paul Walmsley
2012-12-12 10:21 ` Vaibhav Hiremath
` (2 subsequent siblings)
3 siblings, 1 reply; 27+ messages in thread
From: Jean Pihet @ 2012-12-12 10:00 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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 <rnayak@ti.com>
> 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.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> Cc: Tero Kristo <t-kristo@ti.com>
> Cc: Rajendra Nayak <rnayak@ti.com>
> Cc: Nishanth Menon <nm@ti.com>
> [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]
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> ---
> arch/arm/mach-omap2/powerdomain.c | 525
> +++++++++++++++++++++++++++++++++++++
> arch/arm/mach-omap2/powerdomain.h | 33 ++
> 2 files changed, 553 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/powerdomain.c
> b/arch/arm/mach-omap2/powerdomain.c
> index 94b89a25..18f33de 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -1,7 +1,7 @@
>
...
+/**
> + * _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?
+ */
> +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
> + * 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
> + *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>
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-12 10:00 ` Jean Pihet
@ 2013-01-29 21:20 ` Paul Walmsley
0 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2013-01-29 21:20 UTC (permalink / raw)
To: linux-arm-kernel
Hi
(redacted some context)
On Wed, 12 Dec 2012, Jean Pihet wrote:
> On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
>
> +/**
> > + * _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?
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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-09 17:53 ` [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states Paul Walmsley
2012-12-12 10:00 ` Jean Pihet
@ 2012-12-12 10:21 ` Vaibhav Hiremath
2012-12-12 10:33 ` Jean Pihet
2012-12-26 6:06 ` Bedia, Vaibhav
3 siblings, 0 replies; 27+ messages in thread
From: Vaibhav Hiremath @ 2012-12-12 10:21 UTC (permalink / raw)
To: linux-arm-kernel
On 12/9/2012 11:23 PM, Paul Walmsley wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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 <rnayak@ti.com>
> 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.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> Cc: Tero Kristo <t-kristo@ti.com>
> Cc: Rajendra Nayak <rnayak@ti.com>
> Cc: Nishanth Menon <nm@ti.com>
> [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]
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> ---
> arch/arm/mach-omap2/powerdomain.c | 525 +++++++++++++++++++++++++++++++++++++
> arch/arm/mach-omap2/powerdomain.h | 33 ++
> 2 files changed, 553 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> index 94b89a25..18f33de 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -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;
> +}
> +
> +/**
> + * _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.
> + * Returns the internal power state value for the power domain,
This seems to be wrong, as this funtion always returns err or 0.
> 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.
Ditto here.
> @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))
You can use IS_ERR_OR_NULL here.
> + 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;
> +
No need to initialize it here.
Thanks,
Vaibhav
> + 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;
> +}
> +
> diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
> index 842ba46..be835ff 100644
> --- a/arch/arm/mach-omap2/powerdomain.h
> +++ b/arch/arm/mach-omap2/powerdomain.h
> @@ -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
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-09 17:53 ` [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states Paul Walmsley
2012-12-12 10:00 ` Jean Pihet
2012-12-12 10:21 ` Vaibhav Hiremath
@ 2012-12-12 10:33 ` Jean Pihet
2013-01-04 13:22 ` Tero Kristo
2012-12-26 6:06 ` Bedia, Vaibhav
3 siblings, 1 reply; 27+ messages in thread
From: Jean Pihet @ 2012-12-12 10:33 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
-resending in plain text only, sorry about that-
On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
>
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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 <rnayak@ti.com>
> 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.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> Cc: Tero Kristo <t-kristo@ti.com>
> Cc: Rajendra Nayak <rnayak@ti.com>
> Cc: Nishanth Menon <nm@ti.com>
> [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]
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> ---
> arch/arm/mach-omap2/powerdomain.c | 525 +++++++++++++++++++++++++++++++++++++
> arch/arm/mach-omap2/powerdomain.h | 33 ++
> 2 files changed, 553 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> index 94b89a25..18f33de 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -1,7 +1,7 @@
...
> +/**
> + * _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?
> + */
> +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
> + * 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
>
> + *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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-12 10:33 ` Jean Pihet
@ 2013-01-04 13:22 ` Tero Kristo
0 siblings, 0 replies; 27+ messages in thread
From: Tero Kristo @ 2013-01-04 13:22 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul / Jean,
On Wed, 2012-12-12 at 11:33 +0100, Jean Pihet wrote:
<clip>
> > +/**
> > + * _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?
Looks like it is removed by another patch in the same set and could
probably just be removed from this one also.
> > + }
> > +
> > + /* XXX deprecated */
>
>
> Same here
Same thing, maybe drop the code out completely.
-Tero
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states
2012-12-09 17:53 ` [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states Paul Walmsley
` (2 preceding siblings ...)
2012-12-12 10:33 ` Jean Pihet
@ 2012-12-26 6:06 ` Bedia, Vaibhav
3 siblings, 0 replies; 27+ messages in thread
From: Bedia, Vaibhav @ 2012-12-26 6:06 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
A minor comment below.
On Sun, Dec 09, 2012 at 23:23:01, Paul Walmsley wrote:
[...]
> +
> + 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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 03/12] ARM: OMAP2+: PM debug: trace the functional power domains states
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
2012-12-09 17:52 ` [PATCH 01/12] ARM: OMAP2+: powerdomain: add functions that report on powerdomain capabilities Paul Walmsley
2012-12-09 17:53 ` [PATCH 02/12] ARM: OMAP2+: PM: introduce power domains functional states Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 04/12] ARM: OMAP2xxx: PM: convert to use the functional power states API Paul Walmsley
` (9 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <jean.pihet@newoldbits.com>
Trace the power domain transitions using the functional power states,
which include the power and logic states.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
[paul at pwsan.com: split the fix that was originally part of this patch into a
separate patch]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/powerdomain.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 18f33de..2c732b6 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 04/12] ARM: OMAP2xxx: PM: convert to use the functional power states API
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (2 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 03/12] ARM: OMAP2+: PM debug: trace the functional power domains states Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 05/12] ARM: OMAP3xxx: " Paul Walmsley
` (8 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <jean.pihet@newoldbits.com>
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().
Signed-off-by: Jean Pihet <j-pihet@ti.com>
[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]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/pm24xx.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 4c06d8a..29abb63 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 05/12] ARM: OMAP3xxx: PM: convert to use the functional power states API
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (3 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 04/12] ARM: OMAP2xxx: PM: convert to use the functional power states API Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-12 10:18 ` Jean Pihet
` (2 more replies)
2012-12-09 17:53 ` [PATCH 06/12] ARM: OMAP44xx: " Paul Walmsley
` (7 subsequent siblings)
12 siblings, 3 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <jean.pihet@newoldbits.com>
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().
Signed-off-by: Jean Pihet <j-pihet@ti.com>
[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]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
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(-)
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index e6215b5..a8e6263 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -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;
}
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 707e9cb..19ef376 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -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;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index aa701d7..8aac26e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -57,9 +57,9 @@ u16 pm34xx_errata;
struct power_state {
struct powerdomain *pwrdm;
- u32 next_state;
+ u8 next_fpwrst;
#ifdef CONFIG_SUSPEND
- u32 saved_state;
+ u8 saved_fpwrst;
#endif
struct list_head node;
};
@@ -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.
+ */
+ 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)
+ ;
}
}
@@ -242,21 +244,20 @@ void omap_sram_idle(void)
/* save_state = 2 => Only L2 lost */
/* save_state = 3 => L1, L2 and logic lost */
int save_state = 0;
- int mpu_next_state = PWRDM_POWER_ON;
- int per_next_state = PWRDM_POWER_ON;
- int core_next_state = PWRDM_POWER_ON;
- int per_going_off;
- int core_prev_state;
+ int mpu_next_fpwrst, per_next_fpwrst, core_next_fpwrst;
+ int per_going_off, core_prev_fpwrst;
u32 sdrc_pwr = 0;
- mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
- switch (mpu_next_state) {
- case PWRDM_POWER_ON:
- case PWRDM_POWER_RET:
+ mpu_next_fpwrst = pwrdm_read_next_fpwrst(mpu_pwrdm);
+ switch (mpu_next_fpwrst) {
+ case PWRDM_FUNC_PWRST_ON:
+ case PWRDM_FUNC_PWRST_CSWR:
+ case PWRDM_FUNC_PWRST_INACTIVE:
/* No need to save context */
save_state = 0;
break;
- case PWRDM_POWER_OFF:
+ case PWRDM_FUNC_PWRST_OSWR: /* XXX accurate? */
+ case PWRDM_FUNC_PWRST_OFF:
save_state = 3;
break;
default:
@@ -266,33 +267,34 @@ void omap_sram_idle(void)
}
/* NEON control */
- if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
- pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
+ if (pwrdm_read_fpwrst(neon_pwrdm) == PWRDM_FUNC_PWRST_ON)
+ WARN_ON(pwrdm_set_next_fpwrst(neon_pwrdm, mpu_next_fpwrst));
- /* Enable IO-PAD and IO-CHAIN wakeups */
- per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
- core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
+ per_next_fpwrst = pwrdm_read_next_fpwrst(per_pwrdm);
+ core_next_fpwrst = pwrdm_read_next_fpwrst(core_pwrdm);
pwrdm_pre_transition(NULL);
/* PER */
- if (per_next_state < PWRDM_POWER_ON) {
- per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
+ if (per_next_fpwrst != PWRDM_FUNC_PWRST_ON &&
+ per_next_fpwrst != PWRDM_FUNC_PWRST_INACTIVE) {
+ per_going_off =
+ (per_next_fpwrst == PWRDM_FUNC_PWRST_OFF) ? 1 : 0;
omap2_gpio_prepare_for_idle(per_going_off);
}
/* CORE */
- if (core_next_state < PWRDM_POWER_ON) {
- if (core_next_state == PWRDM_POWER_OFF) {
- omap3_core_save_context();
- omap3_cm_save_context();
- }
+ /* XXX Does the context save need to happen for OSWR? */
+ if (core_next_fpwrst == PWRDM_FUNC_PWRST_OFF ||
+ core_next_fpwrst == PWRDM_FUNC_PWRST_OSWR) {
+ omap3_core_save_context();
+ omap3_cm_save_context();
}
omap3_intc_prepare_idle();
/*
- * On EMU/HS devices ROM code restores a SRDC value
+ * On EMU/HS devices ROM code restores a SDRC value
* from scratchpad which has automatic self refresh on timeout
* of AUTO_CNT = 1 enabled. This takes care of erratum ID i443.
* Hence store/restore the SDRC_POWER register here.
@@ -300,7 +302,7 @@ void omap_sram_idle(void)
if (cpu_is_omap3430() && omap_rev() >= OMAP3430_REV_ES3_0 &&
(omap_type() == OMAP2_DEVICE_TYPE_EMU ||
omap_type() == OMAP2_DEVICE_TYPE_SEC) &&
- core_next_state == PWRDM_POWER_OFF)
+ core_next_fpwrst == PWRDM_FUNC_PWRST_OFF)
sdrc_pwr = sdrc_read_reg(SDRC_POWER);
/*
@@ -319,29 +321,32 @@ void omap_sram_idle(void)
if (cpu_is_omap3430() && omap_rev() >= OMAP3430_REV_ES3_0 &&
(omap_type() == OMAP2_DEVICE_TYPE_EMU ||
omap_type() == OMAP2_DEVICE_TYPE_SEC) &&
- core_next_state == PWRDM_POWER_OFF)
+ core_next_fpwrst == PWRDM_FUNC_PWRST_OFF)
sdrc_write_reg(sdrc_pwr, SDRC_POWER);
/* CORE */
- if (core_next_state < PWRDM_POWER_ON) {
- core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
- if (core_prev_state == PWRDM_POWER_OFF) {
+ if (core_next_fpwrst != PWRDM_FUNC_PWRST_ON &&
+ core_next_fpwrst != PWRDM_FUNC_PWRST_INACTIVE) {
+ core_prev_fpwrst = pwrdm_read_prev_fpwrst(core_pwrdm);
+ if (core_prev_fpwrst == PWRDM_FUNC_PWRST_OFF ||
+ core_prev_fpwrst == PWRDM_FUNC_PWRST_OSWR) {
omap3_core_restore_context();
omap3_cm_restore_context();
omap3_sram_restore_context();
omap2_sms_restore_context();
}
- if (core_next_state == PWRDM_POWER_OFF)
+ if (core_next_fpwrst == PWRDM_FUNC_PWRST_OFF)
omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
- OMAP3430_GR_MOD,
- OMAP3_PRM_VOLTCTRL_OFFSET);
+ OMAP3430_GR_MOD,
+ OMAP3_PRM_VOLTCTRL_OFFSET);
}
omap3_intc_resume_idle();
pwrdm_post_transition(NULL);
/* PER */
- if (per_next_state < PWRDM_POWER_ON)
+ if (per_next_fpwrst != PWRDM_FUNC_PWRST_ON &&
+ per_next_fpwrst != PWRDM_FUNC_PWRST_INACTIVE)
omap2_gpio_resume_after_idle();
}
@@ -368,14 +373,15 @@ out:
static int omap3_pm_suspend(void)
{
struct power_state *pwrst;
- int state, ret = 0;
+ int prev_fpwrst;
+ int ret = 0;
/* Read current next_pwrsts */
list_for_each_entry(pwrst, &pwrst_list, node)
- pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+ pwrst->saved_fpwrst = pwrdm_read_next_fpwrst(pwrst->pwrdm);
/* Set ones wanted by suspend */
list_for_each_entry(pwrst, &pwrst_list, node) {
- if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+ if (pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst))
goto restore;
if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
goto restore;
@@ -388,13 +394,15 @@ static int omap3_pm_suspend(void)
restore:
/* Restore next_pwrsts */
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);
+ 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);
+ WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->saved_fpwrst));
}
if (ret)
pr_err("Could not enter target state in pm_suspend\n");
@@ -563,24 +571,21 @@ static void __init prcm_setup_regs(void)
void omap3_pm_off_mode_enable(int enable)
{
struct power_state *pwrst;
- u32 state;
+ u8 fpwrst;
- if (enable)
- state = PWRDM_POWER_OFF;
- else
- state = PWRDM_POWER_RET;
+ fpwrst = (enable) ? PWRDM_FUNC_PWRST_OFF : PWRDM_FUNC_PWRST_CSWR;
list_for_each_entry(pwrst, &pwrst_list, node) {
if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) &&
- pwrst->pwrdm == core_pwrdm &&
- state == PWRDM_POWER_OFF) {
- pwrst->next_state = PWRDM_POWER_RET;
+ pwrst->pwrdm == core_pwrdm &&
+ fpwrst == PWRDM_FUNC_PWRST_OFF) {
+ pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
pr_warn("%s: Core OFF disabled due to errata i583\n",
__func__);
} else {
- pwrst->next_state = state;
+ pwrst->next_fpwrst = fpwrst;
}
- omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+ WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
}
}
@@ -588,20 +593,19 @@ int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
{
struct power_state *pwrst;
- list_for_each_entry(pwrst, &pwrst_list, node) {
+ list_for_each_entry(pwrst, &pwrst_list, node)
if (pwrst->pwrdm == pwrdm)
- return pwrst->next_state;
- }
+ return pwrst->next_fpwrst;
return -EINVAL;
}
-int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state)
+int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, u8 fpwrst)
{
struct power_state *pwrst;
list_for_each_entry(pwrst, &pwrst_list, node) {
if (pwrst->pwrdm == pwrdm) {
- pwrst->next_state = state;
+ pwrst->next_fpwrst = fpwrst;
return 0;
}
}
@@ -619,13 +623,13 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
if (!pwrst)
return -ENOMEM;
pwrst->pwrdm = pwrdm;
- pwrst->next_state = PWRDM_POWER_RET;
+ pwrst->next_fpwrst = PWRDM_FUNC_PWRST_CSWR;
list_add(&pwrst->node, &pwrst_list);
if (pwrdm_has_hdwr_sar(pwrdm))
pwrdm_enable_hdwr_sar(pwrdm);
- return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+ return WARN_ON(pwrdm_set_fpwrst(pwrst->pwrdm, pwrst->next_fpwrst));
}
/*
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 05/12] ARM: OMAP3xxx: PM: convert to use the functional power states API
2012-12-09 17:53 ` [PATCH 05/12] ARM: OMAP3xxx: " Paul Walmsley
@ 2012-12-12 10:18 ` Jean Pihet
2012-12-12 10:29 ` Jean Pihet
2013-01-04 13:45 ` Tero Kristo
2 siblings, 0 replies; 27+ messages in thread
From: Jean Pihet @ 2012-12-12 10:18 UTC (permalink / raw)
To: linux-arm-kernel
Paul,
On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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().
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> [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
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> ---
> 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>
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 05/12] ARM: OMAP3xxx: PM: convert to use the functional power states API
2012-12-09 17:53 ` [PATCH 05/12] ARM: OMAP3xxx: " Paul Walmsley
2012-12-12 10:18 ` Jean Pihet
@ 2012-12-12 10:29 ` Jean Pihet
2013-01-04 13:45 ` Tero Kristo
2 siblings, 0 replies; 27+ messages in thread
From: Jean Pihet @ 2012-12-12 10:29 UTC (permalink / raw)
To: linux-arm-kernel
Paul,
-resending in plain text only, sorry about that-
On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
>
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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().
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> [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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 05/12] ARM: OMAP3xxx: PM: convert to use the functional power states API
2012-12-09 17:53 ` [PATCH 05/12] ARM: OMAP3xxx: " Paul Walmsley
2012-12-12 10:18 ` Jean Pihet
2012-12-12 10:29 ` Jean Pihet
@ 2013-01-04 13:45 ` Tero Kristo
2 siblings, 0 replies; 27+ messages in thread
From: Tero Kristo @ 2013-01-04 13:45 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
On Sun, 2012-12-09 at 10:53 -0700, Paul Walmsley wrote:
<clip>
> @@ -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.
> + */
> + 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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 06/12] ARM: OMAP44xx: PM: convert to use the functional power states API
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (4 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 05/12] ARM: OMAP3xxx: " Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-12 10:41 ` Jean Pihet
2013-01-04 14:01 ` Tero Kristo
2012-12-09 17:53 ` [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters Paul Walmsley
` (6 subsequent siblings)
12 siblings, 2 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <jean.pihet@newoldbits.com>
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.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
[paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
warn if sets fail; various other changes]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
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(-)
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index c57eeea..5ad846a 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -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;
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index d639aef..2cb5332 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -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 */
diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c
index e712d17..d38b12d 100644
--- a/arch/arm/mach-omap2/omap-hotplug.c
+++ b/arch/arm/mach-omap2/omap-hotplug.c
@@ -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();
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 80d4742..4dcebda 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -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) {
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 7da75ae..595f84e 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -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);
+ 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 != */
+ 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));
}
/**
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 06/12] ARM: OMAP44xx: PM: convert to use the functional power states API
2012-12-09 17:53 ` [PATCH 06/12] ARM: OMAP44xx: " Paul Walmsley
@ 2012-12-12 10:41 ` Jean Pihet
2013-01-04 14:01 ` Tero Kristo
1 sibling, 0 replies; 27+ messages in thread
From: Jean Pihet @ 2012-12-12 10:41 UTC (permalink / raw)
To: linux-arm-kernel
Paul,
On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> [paul at pwsan.com: split the original patch into OMAP2/3/4 variants;
> warn if sets fail; various other changes]
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> ---
> 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(-)
>
> diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
> index c57eeea..5ad846a 100644
> --- a/arch/arm/mach-omap2/common.h
> +++ b/arch/arm/mach-omap2/common.h
> @@ -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;
> diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
> index d639aef..2cb5332 100644
> --- a/arch/arm/mach-omap2/cpuidle44xx.c
> +++ b/arch/arm/mach-omap2/cpuidle44xx.c
> @@ -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.
> };
>
> 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 */
> diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c
> index e712d17..d38b12d 100644
> --- a/arch/arm/mach-omap2/omap-hotplug.c
> +++ b/arch/arm/mach-omap2/omap-hotplug.c
> @@ -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();
> diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> index 80d4742..4dcebda 100644
> --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
> @@ -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) {
> diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
> index 7da75ae..595f84e 100644
> --- a/arch/arm/mach-omap2/pm44xx.c
> +++ b/arch/arm/mach-omap2/pm44xx.c
> @@ -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);
> + 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?
> + 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));
> }
>
> /**
>
>
> --
> 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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 06/12] ARM: OMAP44xx: PM: convert to use the functional power states API
2012-12-09 17:53 ` [PATCH 06/12] ARM: OMAP44xx: " Paul Walmsley
2012-12-12 10:41 ` Jean Pihet
@ 2013-01-04 14:01 ` Tero Kristo
1 sibling, 0 replies; 27+ messages in thread
From: Tero Kristo @ 2013-01-04 14:01 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
On Sun, 2012-12-09 at 10:53 -0700, Paul Walmsley wrote:
<clip>
> @@ -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>
> @@ -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 <t-kristo@ti.com>
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.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
---
arch/arm/mach-omap2/pm44xx.c | 22 +++++++++++++++++-----
1 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 8775ee5..67f05fe 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -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));
--
1.7.4.1
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (5 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 06/12] ARM: OMAP44xx: " Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-12 10:46 ` Jean Pihet
2013-01-04 14:07 ` Tero Kristo
2012-12-09 17:53 ` [PATCH 08/12] ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs Paul Walmsley
` (5 subsequent siblings)
12 siblings, 2 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean Pihet <jean.pihet@newoldbits.com>
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.
Signed-off-by: Jean Pihet <j-pihet@ti.com>
[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]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
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(-)
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 806a06b..72cf9e0 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -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;
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 2c732b6..3e2e263 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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;
}
@@ -568,6 +487,76 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
return (ret) ? ret : fpwrst;
}
+/* XXX Caller must hold pwrdm->_lock */
+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];
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index be835ff..849bc55 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -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
};
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters
2012-12-09 17:53 ` [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters Paul Walmsley
@ 2012-12-12 10:46 ` Jean Pihet
2013-01-04 14:07 ` Tero Kristo
1 sibling, 0 replies; 27+ messages in thread
From: Jean Pihet @ 2012-12-12 10:46 UTC (permalink / raw)
To: linux-arm-kernel
Paul,
On Sun, Dec 9, 2012 at 6:53 PM, Paul Walmsley <paul@pwsan.com> wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> [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]
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
The patch does more than the description is telling. The function
_update_logic_membank_counters is removed by this patch, is this
intentional?
> ---
> 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(-)
>
> diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
> index 806a06b..72cf9e0 100644
> --- a/arch/arm/mach-omap2/pm-debug.c
> +++ b/arch/arm/mach-omap2/pm-debug.c
> @@ -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;
>
> diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
> index 2c732b6..3e2e263 100644
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -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;
> }
>
> @@ -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.
> +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];
> diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
> index be835ff..849bc55 100644
> --- a/arch/arm/mach-omap2/powerdomain.h
> +++ b/arch/arm/mach-omap2/powerdomain.h
> @@ -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
> };
>
>
>
> --
> 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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters
2012-12-09 17:53 ` [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters Paul Walmsley
2012-12-12 10:46 ` Jean Pihet
@ 2013-01-04 14:07 ` Tero Kristo
1 sibling, 0 replies; 27+ messages in thread
From: Tero Kristo @ 2013-01-04 14:07 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paul,
On Sun, 2012-12-09 at 10:53 -0700, Paul Walmsley wrote:
> From: Jean Pihet <jean.pihet@newoldbits.com>
>
> 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.
>
> Signed-off-by: Jean Pihet <j-pihet@ti.com>
> [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]
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> ---
> 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(-)
>
> diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
> index 806a06b..72cf9e0 100644
> --- a/arch/arm/mach-omap2/pm-debug.c
> +++ b/arch/arm/mach-omap2/pm-debug.c
> @@ -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 */
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
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 08/12] ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (6 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 07/12] ARM: OMAP2+: PM: use power domain functional state in stats counters Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 09/12] ARM: OMAP2+: powerdomain: add ability to test for supported power states Paul Walmsley
` (4 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/powerdomain.c | 270 +++----------------------------------
arch/arm/mach-omap2/powerdomain.h | 9 -
2 files changed, 21 insertions(+), 258 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 3e2e263..86fe84c 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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);
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 849bc55..aa1c9ae 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 09/12] ARM: OMAP2+: powerdomain: add ability to test for supported power states
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (7 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 08/12] ARM: OMAP2+: powerdomain: drop many low-level powerdomain funcs Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 10/12] ARM: OMAP2+: powerdomain/PM: only program " Paul Walmsley
` (3 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/powerdomain.c | 33 +++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 1 +
2 files changed, 34 insertions(+)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 86fe84c..6ba79df 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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;
+}
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index aa1c9ae..52be8cd 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 10/12] ARM: OMAP2+: powerdomain/PM: only program supported power states
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (8 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 09/12] ARM: OMAP2+: powerdomain: add ability to test for supported power states Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 11/12] ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init Paul Walmsley
` (2 subsequent siblings)
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
---
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(-)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 8aac26e..c4d4154 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -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))
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 595f84e..5db9a91 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -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));
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 6ba79df..fdeabbf 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -185,61 +185,9 @@ static bool _pwrdm_logic_retst_can_change(struct powerdomain *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
@@ -285,13 +233,6 @@ static int _pwrdm_fpwrst_to_pwrst(struct powerdomain *pwrdm, u8 fpwrst,
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);
@@ -361,6 +302,10 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,
{
int ret;
+ /*
+ * XXX Should return an error, but this means that our PM code
+ * will need to be much more careful about what it programs
+ */
if (!_pwrdm_pwrst_is_controllable(pwrdm))
return 0;
@@ -1319,6 +1264,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
if (!pwrdm || IS_ERR(pwrdm))
return -EINVAL;
+ /*
+ * XXX Should return an error, but this means that our PM code
+ * will need to be much more careful about what it programs
+ */
if (!_pwrdm_pwrst_is_controllable(pwrdm))
return 0;
@@ -1399,6 +1348,10 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)
!arch_pwrdm->pwrdm_read_pwrst)
return -EINVAL;
+ /*
+ * XXX Should return an error, but this means that our PM code
+ * will need to be much more careful about what it programs
+ */
if (!_pwrdm_pwrst_is_controllable(pwrdm))
return 0;
@@ -1516,9 +1469,6 @@ bool pwrdm_supports_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)
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;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 11/12] ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (9 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 10/12] ARM: OMAP2+: powerdomain/PM: only program " Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2012-12-09 17:53 ` [PATCH 12/12] ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain Paul Walmsley
2013-01-04 14:12 ` [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Tero Kristo
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/powerdomain.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index fdeabbf..a70e3f6 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -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;
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 12/12] ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (10 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 11/12] ARM: OMAP2+: powerdomain: program memory bank next-power-state upon init Paul Walmsley
@ 2012-12-09 17:53 ` Paul Walmsley
2013-01-04 14:12 ` [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Tero Kristo
12 siblings, 0 replies; 27+ messages in thread
From: Paul Walmsley @ 2012-12-09 17:53 UTC (permalink / raw)
To: linux-arm-kernel
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.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Tero Kristo <t-kristo@ti.com>
Cc: Rajendra Nayak <rnayak@ti.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
---
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(-)
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 72cf9e0..03da2e3 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -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;
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 29abb63..99c16c2 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -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);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index a70e3f6..7a32fcc 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -118,9 +118,6 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
for (i = 0; i < PWRDM_FPWRSTS_COUNT; i++)
pwrdm->fpwrst_counter[i] = 0;
- for (i = 0; i < pwrdm->banks; i++)
- pwrdm->ret_mem_off_counter[i] = 0;
-
arch_pwrdm->pwrdm_wait_transition(pwrdm);
pwrdm->fpwrst = pwrdm_read_fpwrst(pwrdm);
pwrdm->fpwrst_counter[pwrdm->fpwrst - PWRDM_FPWRST_OFFSET] = 1;
@@ -364,7 +361,6 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)
if (next_logic < 0)
return next_logic;
}
-
ret = _pwrdm_pwrst_to_fpwrst(pwrdm, next_pwrst, next_logic, &fpwrst);
return (ret) ? ret : fpwrst;
@@ -437,12 +433,86 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)
return (ret) ? ret : fpwrst;
}
+/**
+ * _pwrdm_set_mem_onst - set memory power state while powerdomain ON
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state @pwrst that memory bank @bank of the
+ * powerdomain @pwrdm will enter when the powerdomain enters the ON
+ * state. @bank will be a number from 0 to 3, and represents different
+ * types of memory, depending on the powerdomain. Returns -EINVAL if
+ * the powerdomain pointer is null or the target power state is not
+ * not supported for this memory bank, -EEXIST if the target memory
+ * bank does not exist or is not controllable, or returns 0 upon
+ * success.
+ */
+static int _pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+ int ret = -EINVAL;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
+ pwrdm->name, bank, pwrst);
+
+ if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
+ ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
+
+ return ret;
+}
+
+/**
+ * _pwrdm_set_mem_retst - set memory power state while powerdomain in RET
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state @pwrst that memory bank @bank of the
+ * powerdomain @pwrdm will enter when the powerdomain enters the
+ * RETENTION state. Bank will be a number from 0 to 3, and represents
+ * different types of memory, depending on the powerdomain. @pwrst
+ * 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 for this memory bank, -EEXIST if the target memory
+ * bank does not exist or is not controllable, or returns 0 upon
+ * success.
+ */
+static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+ int ret = -EINVAL;
+
+ if (!pwrdm)
+ return -EINVAL;
+
+ if (pwrdm->banks < (bank + 1))
+ return -EEXIST;
+
+ if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
+ return -EINVAL;
+
+ pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
+ pwrdm->name, bank, pwrst);
+
+ if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
+ ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
+
+ return ret;
+}
+
+
/* XXX Caller must hold pwrdm->_lock */
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;
@@ -457,17 +527,6 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
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
@@ -580,8 +639,8 @@ int pwrdm_complete_init(void)
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);
+ _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));
}
@@ -789,181 +848,6 @@ struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm)
}
/**
- * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
- * @pwrdm: struct powerdomain *
- *
- * Return the number of controllable memory banks in powerdomain @pwrdm,
- * starting with 1. Returns -EINVAL if the powerdomain pointer is null.
- */
-int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
-{
- if (!pwrdm)
- return -EINVAL;
-
- return pwrdm->banks;
-}
-
-/**
- * pwrdm_set_mem_onst - set memory power state while powerdomain ON
- * @pwrdm: struct powerdomain * to set
- * @bank: memory bank number to set (0-3)
- * @pwrst: one of the PWRDM_POWER_* macros
- *
- * Set the next power state @pwrst that memory bank @bank of the
- * powerdomain @pwrdm will enter when the powerdomain enters the ON
- * state. @bank will be a number from 0 to 3, and represents different
- * types of memory, depending on the powerdomain. Returns -EINVAL if
- * the powerdomain pointer is null or the target power state is not
- * not supported for this memory bank, -EEXIST if the target memory
- * bank does not exist or is not controllable, or returns 0 upon
- * success.
- */
-int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
-
- if (pwrdm->banks < (bank + 1))
- return -EEXIST;
-
- if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
- return -EINVAL;
-
- pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
- pwrdm->name, bank, pwrst);
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
- ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
-
- return ret;
-}
-
-/**
- * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
- * @pwrdm: struct powerdomain * to set
- * @bank: memory bank number to set (0-3)
- * @pwrst: one of the PWRDM_POWER_* macros
- *
- * Set the next power state @pwrst that memory bank @bank of the
- * powerdomain @pwrdm will enter when the powerdomain enters the
- * RETENTION state. Bank will be a number from 0 to 3, and represents
- * different types of memory, depending on the powerdomain. @pwrst
- * 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 for this memory bank, -EEXIST if the target memory
- * bank does not exist or is not controllable, or returns 0 upon
- * success.
- */
-int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return -EINVAL;
-
- if (pwrdm->banks < (bank + 1))
- return -EEXIST;
-
- if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
- return -EINVAL;
-
- pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
- pwrdm->name, bank, pwrst);
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
- ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
-
- 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)
- *
- * Return the powerdomain @pwrdm's current memory power state for bank
- * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
- * the target memory bank does not exist or is not controllable, or
- * returns the current memory power state upon success.
- */
-int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return ret;
-
- if (pwrdm->banks < (bank + 1))
- return ret;
-
- if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
- bank = 1;
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
- ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
-
- return ret;
-}
-
-/**
- * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
- * @pwrdm: struct powerdomain * to get previous memory bank power state
- * @bank: memory bank number (0-3)
- *
- * Return the powerdomain @pwrdm's previous memory power state for
- * bank @bank. Returns -EINVAL if the powerdomain pointer is null,
- * -EEXIST if the target memory bank does not exist or is not
- * controllable, or returns the previous memory power state upon
- * success.
- */
-int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return ret;
-
- if (pwrdm->banks < (bank + 1))
- return ret;
-
- if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
- bank = 1;
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
- ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
-
- return ret;
-}
-
-/**
- * pwrdm_read_mem_retst - get next memory bank power state
- * @pwrdm: struct powerdomain * to get mext memory bank power state
- * @bank: memory bank number (0-3)
- *
- * Return the powerdomain pwrdm's next memory power state for bank
- * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
- * the target memory bank does not exist or is not controllable, or
- * returns the next memory power state upon success.
- */
-int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
-{
- int ret = -EINVAL;
-
- if (!pwrdm)
- return ret;
-
- if (pwrdm->banks < (bank + 1))
- return ret;
-
- if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
- ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
-
- return ret;
-}
-
-/**
* pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
* @pwrdm: struct powerdomain * to clear
*
@@ -1165,7 +1049,7 @@ static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
*/
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
{
- int i, count;
+ int count;
if (!pwrdm) {
WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
@@ -1177,9 +1061,6 @@ int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
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];
-
/*
* Context loss count has to be a non-negative value. Clear the sign
* bit to get a value range from 0 to INT_MAX.
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 52be8cd..7921f52 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states
2012-12-09 17:52 [PATCH 00/12] ARM: OMAP2+: powerdomain/PM: convert to functional power states Paul Walmsley
` (11 preceding siblings ...)
2012-12-09 17:53 ` [PATCH 12/12] ARM: OMAP2+: powerdomain: assume memory bank power states follow powerdomain Paul Walmsley
@ 2013-01-04 14:12 ` Tero Kristo
12 siblings, 0 replies; 27+ messages in thread
From: Tero Kristo @ 2013-01-04 14:12 UTC (permalink / raw)
To: linux-arm-kernel
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
On Sun, 2012-12-09 at 10:52 -0700, Paul Walmsley wrote:
> 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
^ permalink raw reply [flat|nested] 27+ messages in thread