ARM: OMAP2+: powerdomain updates after the functional power state conversion
Subsystems (6)
Paul Walmsley
maintainercover ARM: OMAP2+: powerdomain updates after the functional power state conversion
OMAP powerdomain code updates, implemented on top of the functional power state conversion series. This series fixes the powerdomain handling for OMAP2xxx, adds caching for the powerdomain next-power-state and previous-power-state register bitfields, and some cleanup that's intended to make it easier to move the powerdomain code out to drivers/.
- Paul
---
vmlinux object size
(delta in bytes from TEST_func_powerstates_devel_3.9 (6d8345f4177c976eca1a1368cdd68e95f80c3f27)):
text data bss total kernel
-68 +48 0 -20 am33xx_only
-136 +48 0 -88 n800_multi_omap2xxx
-128 +48 0 -80 n800_only_a
0 0 0 0 omap1_defconfig
0 0 0 0 omap1_defconfig_1510innovator_only
0 0 0 0 omap1_defconfig_5912osk_only
-32 +368 0 +336 omap2plus_defconfig
+20 +16 0 +36 omap2plus_defconfig_2430sdp_only
-32 +432 0 +400 omap2plus_defconfig_cpupm
+572 +192 0 +764 omap2plus_defconfig_no_pm
-20 +208 0 +188 omap2plus_defconfig_omap2_4_only
-84 +304 0 +220 omap2plus_defconfig_omap3_4_only
+708 +200 -104 +804 rmk_omap3430_ldp_allnoconfig
+352 +128 0 +480 rmk_omap3430_ldp_oldconfig
+708 +200 -104 +804 rmk_omap4430_sdp_allnoconfig
-164 +8 0 -156 rmk_omap4430_sdp_oldconfigPaul Walmsley (12):
ARM: OMAP2+: powerdomain: consolidate arch_pwrdm check code
ARM: OMAP2+: PM/powerdomain: move the power state time tracking into the powerdomain code
ARM: OMAP2+: powerdomain: split pwrdm_state_switch()
ARM: OMAP2+: PM: clean up some debugfs functions
ARM: OMAP2+: powerdomain: remove some redundant checks; add some notes
ARM: OMAP2+: CM: use the cached copy of the clockdomain's hwsup state
ARM: OMAP2+: powerdomain: cache the powerdomain next power state
ARM: OMAP2+: powerdomain: cache the powerdomain's previous power state
ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
ARM: OMAP2+: powerdomain: skip previous-power-state read if next_pwrst is ON
ARM: OMAP2xxx: powerdomain: add previous power state tracking
ARM: OMAP2xxx: PM: add pwrdm_(pre|post)_transition() calls to the 2xxx PM code
arch/arm/mach-omap2/clockdomain.c | 18 + arch/arm/mach-omap2/clockdomain.h | 2 arch/arm/mach-omap2/cm2xxx.c | 19 - arch/arm/mach-omap2/cm3xxx.c | 14 - arch/arm/mach-omap2/pm-debug.c | 101 -------- arch/arm/mach-omap2/pm.h | 6 arch/arm/mach-omap2/pm24xx.c | 8 + arch/arm/mach-omap2/powerdomain.c | 352 +++++++++++++++++++-------- arch/arm/mach-omap2/powerdomain.h | 40 +++ arch/arm/mach-omap2/powerdomains2xxx_data.c | 2 arch/arm/mach-omap2/powerdomains33xx_data.c | 3 arch/arm/mach-omap2/powerdomains3xxx_data.c | 9 - arch/arm/mach-omap2/powerdomains44xx_data.c | 5 arch/arm/mach-omap2/prm2xxx.c | 12 + 14 files changed, 347 insertions(+), 244 deletions(-)
Paul Walmsley
maintainerPATCH 1/12 ARM: OMAP2+: powerdomain: consolidate arch_pwrdm check code
Check for the presence of some of the arch_pwrdm function pointers during powerdomain setup, rather than in the individual functions. The primary motivation is to make the code slightly easier to read, but it also should avoid a few instructions in some hot paths.
--- arch/arm/mach-omap2/powerdomain.c | 43 +++++++++++++++---------------------- 1 file changed, 18 insertions(+), 25 deletions(-)
arch/arm/mach-omap2/powerdomain.c +18 -25
@@ -385,9 +385,6 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,if (!_pwrdm_pwrst_is_controllable (pwrdm))return 0 ; -if (!arch_pwrdm || !arch_pwrdm->pwrdm_set_next_pwrst) -return -EINVAL ; -if (!(pwrdm->pwrsts & (1 << pwrst)))return -EINVAL ;
@@ -395,13 +392,11 @@ static int _set_logic_retst_and_pwrdm_pwrst(struct powerdomain *pwrdm,if (!(pwrdm->pwrsts_logic_ret & (1 << logic)))return -EINVAL ; -if (arch_pwrdm->pwrdm_set_logic_retst) { - ret = arch_pwrdm->pwrdm_set_logic_retst (pwrdm, logic); -if (ret) { -pr_err ("%s: unable to set logic state %0x of powerdomain: %s\n" , - __func__, logic, pwrdm->name); -return ret; - } + ret = arch_pwrdm->pwrdm_set_logic_retst (pwrdm, logic); +if (ret) { +pr_err ("%s: unable to set logic state %0x of powerdomain: %s\n" , + __func__, logic, pwrdm->name); +return ret; } }
@@ -426,9 +421,6 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)int next_pwrst, next_logic, ret;u8 fpwrst; -if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst) -return -EINVAL ; - next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst (pwrdm);if (next_pwrst <0 )return next_pwrst;
@@ -653,9 +645,12 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)* * Register the list of function pointers used to implement the * powerdomain functions on different OMAP SoCs. Should be called -* before any other pwrdm_register*() function. Returns -EINVAL if -* @po is null, -EEXIST if platform functions have already been -* registered, or 0 upon success. +* before any other pwrdm_register*() function. Several function +* pointers in @po are required to be non-null for the powerdomain +* code to function: pwrdm_wait_transition, pwrdm_read_next_pwrst, +* pwrdm_read_pwrst, pwrdm_set_next_pwrst, pwrdm_set_logic_retst, and +* pwrdm_read_prev_pwrst. Returns -EINVAL if @po is null, -EEXIST if +* platform functions have already been registered, or 0 upon success. */ int pwrdm_register_platform_funcs (struct pwrdm_ops *po) {
@@ -665,6 +660,11 @@ int pwrdm_register_platform_funcs(struct pwrdm_ops *po)if (arch_pwrdm)return -EEXIST ; +if (!po->pwrdm_wait_transition || !po->pwrdm_read_next_pwrst || + !po->pwrdm_read_pwrst || !po->pwrdm_set_next_pwrst || + !po->pwrdm_set_logic_retst || !po->pwrdm_read_prev_pwrst) +return -ENOENT ; + arch_pwrdm = po;return 0 ;
@@ -1221,7 +1221,7 @@ int pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)int next_pwrst, next_logic, ret;u8 fpwrst; -if (!arch_pwrdm || !arch_pwrdm->pwrdm_read_next_pwrst) +if (!arch_pwrdm)return -EINVAL ;pwrdm_lock (pwrdm);
@@ -1264,8 +1264,7 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)int ret =0 ;bool hwsup = false; -if (!pwrdm ||IS_ERR (pwrdm) || !arch_pwrdm || - !arch_pwrdm->pwrdm_read_pwrst) +if (!pwrdm ||IS_ERR (pwrdm) || !arch_pwrdm)return -EINVAL ;/*
@@ -1334,9 +1333,6 @@ int pwrdm_read_fpwrst(struct powerdomain *pwrdm)if (!_pwrdm_pwrst_can_change (pwrdm))return PWRDM_FUNC_PWRST_ON ; -if (!arch_pwrdm->pwrdm_read_pwrst) -return -EINVAL ; -pwrdm_lock (pwrdm); ret =_pwrdm_read_fpwrst (pwrdm);pwrdm_unlock (pwrdm);
@@ -1362,9 +1358,6 @@ int pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)if (!_pwrdm_pwrst_can_change (pwrdm))return PWRDM_FUNC_PWRST_ON ; -if (!arch_pwrdm->pwrdm_read_prev_pwrst) -return -EINVAL ; -pwrdm_lock (pwrdm); ret =_pwrdm_read_prev_fpwrst (pwrdm);pwrdm_unlock (pwrdm);
Paul Walmsley
maintainerPATCH 2/12 ARM: OMAP2+: PM/powerdomain: move the power state time tracking into the powerdomain code
In reply to Paul WalmsleyMove the power state time tracking code into the powerdomain code. This code accesses internal powerdomain state, so this change will allow us to reduce what is exported from the powerdomain code.
--- arch/arm/mach-omap2/pm-debug.c | 24 ------------------------ arch/arm/mach-omap2/pm.h | 6 ------ arch/arm/mach-omap2/powerdomain.c | 22 +++++++++++++++++++++- 3 files changed, 21 insertions(+), 31 deletions(-)
arch/arm/mach-omap2/pm-debug.c +0 -24
@@ -53,21 +53,6 @@ enum { DEBUG_FILE_TIMERS, }; -void pm_dbg_update_time (struct powerdomain *pwrdm,int prev) -{ -s64 t; - -if (!pm_dbg_init_done) -return ; - -/* Update timer for previous state */ - t =sched_clock (); - - pwrdm->fpwrst_timer[prev -PWRDM_FPWRST_OFFSET ] += t - pwrdm->timer; - - pwrdm->timer = t; -} -static int clkdm_dbg_show_counter (struct clockdomain *clkdm,void *user) {struct seq_file *s = (struct seq_file *)user;
@@ -197,17 +182,8 @@ DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,static int __init pwrdms_setup (struct powerdomain *pwrdm,void *dir) { -int i; -s64 t;struct dentry *d; - t =sched_clock (); - -for (i =0 ; i <PWRDM_FPWRSTS_COUNT ; i++) - pwrdm->fpwrst_timer[i] =0 ; - - pwrdm->timer = t; -if (strncmp (pwrdm->name,"dpll" ,4 ) ==0 )return 0 ;
arch/arm/mach-omap2/pm.h +0 -6
@@ -59,12 +59,6 @@ extern u32 enable_off_mode;#define enable_off_mode 0#endif -#if defined(CONFIG_PM_DEBUG ) && defined(CONFIG_DEBUG_FS ) -extern void pm_dbg_update_time (struct powerdomain *pwrdm,int prev); -#else -#define pm_dbg_update_time (pwrdm, prev) do {} while (0); -#endif /* CONFIG_PM_DEBUG */ -/* 24xx */ extern void omap24xx_idle_loop_suspend (void );extern unsigned int omap24xx_idle_loop_suspend_sz;
arch/arm/mach-omap2/powerdomain.c +21 -1
@@ -20,6 +20,8 @@#include <linux/errno.h> #include <linux/string.h> #include <linux/spinlock.h> +#include <linux/sched.h> +#include <trace/events/power.h> #include "cm2xxx_3xxx.h"
@@ -126,6 +128,9 @@ static int _pwrdm_register(struct powerdomain *pwrdm) arch_pwrdm->pwrdm_wait_transition (pwrdm); pwrdm->fpwrst =pwrdm_read_fpwrst (pwrdm); pwrdm->fpwrst_counter[pwrdm->fpwrst -PWRDM_FPWRST_OFFSET ] =1 ; +#ifdef CONFIG_PM_DEBUG + pwrdm->timer =sched_clock (); +#endif return 0 ; }
@@ -579,6 +584,21 @@ static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)return ret; } +/* XXX prev is wrong type */ +/* XXX is sched_clock() correct to use here? */ +/* Update timer for previous state */ +static void _pwrdm_update_pwrst_time (struct powerdomain *pwrdm,int prev) +{ +#ifdef CONFIG_PM_DEBUG +s64 t; + + t =sched_clock (); + + pwrdm->fpwrst_timer[prev -PWRDM_FPWRST_OFFSET ] += t - pwrdm->timer; + + pwrdm->timer = t; +#endif +}/* XXX Caller must hold pwrdm->_lock */ static int _pwrdm_state_switch (struct powerdomain *pwrdm,int flag)
@@ -617,7 +637,7 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)if (fpwrst != prev) pwrdm->fpwrst_counter[fpwrst -PWRDM_FPWRST_OFFSET ]++; -pm_dbg_update_time (pwrdm, prev); +_pwrdm_update_pwrst_time (pwrdm, prev); pwrdm->fpwrst = fpwrst;
Paul Walmsley
maintainerPATCH 3/12 ARM: OMAP2+: powerdomain: split pwrdm_state_switch()
In reply to Paul WalmsleyMove the pwrdm_state_switch() code that deals with previous power states into the post-transition callback. This improves the clarity of pwrdm_state_switch() considerably. Add some sorely-needed kerneldoc for these functions.
It should be possible to drop pwrdm_state_switch() completely during 3.9.
--- arch/arm/mach-omap2/powerdomain.c | 118 ++++++++++++++++++++++++------------- arch/arm/mach-omap2/powerdomain.h | 1 2 files changed, 76 insertions(+), 43 deletions(-)
arch/arm/mach-omap2/powerdomain.c +75 -43
@@ -40,11 +40,6 @@#define PWRDM_TRACE_STATES_FLAG (1<<31) -enum { -PWRDM_STATE_NOW =0 , -PWRDM_STATE_PREV , -}; -/* Types of sleep_switch used in pwrdm_set_fpwrst() */ #define ALREADYACTIVE_SWITCH 0#define FORCEWAKEUP_SWITCH 1
@@ -600,60 +595,97 @@ static void _pwrdm_update_pwrst_time(struct powerdomain *pwrdm, int prev)#endif } -/* XXX Caller must hold pwrdm->_lock */ -static int _pwrdm_state_switch (struct powerdomain *pwrdm,int flag) +/** +* _pwrdm_state_switch - record powerdomain usage data; track power state +* (before powerdomain state transition) +* @pwrdm: struct powerdomain * to observe +* +* If the powerdomain @pwrdm's current power state is not what we last +* observed it to be, then increment the counter for that power state. +* This is used to track context loss events, and for debugging. Also +* if CONFIG_PM_DEBUG=y, track the amount of time the powerdomain has +* spent in the current power state. Caller must hold pwrdm->_lock. +* Intended to be called immediately before the powerdomain's power +* state is likely to change. XXX Note that the counts and durations +* observed by this function may be inaccurate. Powerdomains can +* transition power states automatically, without the kernel being +* involved -- for example, a device can DMA data from memory while +* the MPU is asleep. This function does not attempt to account for +* that. XXX It may be possible to skip this function completely if +* PM debugging is not needed and off-mode and OSWR is disabled (e.g., +* no context loss events). No return value. +*/ +static void _pwrdm_state_switch (struct powerdomain *pwrdm) { -int prev, next, fpwrst, trace_state =0 ; - -if (pwrdm ==NULL ) -return -EINVAL ; +int fpwrst; fpwrst =_pwrdm_read_fpwrst (pwrdm); - -switch (flag) { -case PWRDM_STATE_NOW : - prev = pwrdm->fpwrst; -break ; -case PWRDM_STATE_PREV : - prev =_pwrdm_read_prev_fpwrst (pwrdm); -if (pwrdm->fpwrst != prev) - pwrdm->fpwrst_counter[prev -PWRDM_FPWRST_OFFSET ]++; -/* -* If the power domain did not hit the desired state, -* generate a trace event with both the desired and hit states -*/ - next =_pwrdm_read_next_fpwrst (pwrdm); -if (next != prev) { - trace_state = (PWRDM_TRACE_STATES_FLAG | next <<8 | - prev); -trace_power_domain_target (pwrdm->name, trace_state, -smp_processor_id ()); - } -break ; -default : -return -EINVAL ; - } - -if (fpwrst != prev) +if (fpwrst != pwrdm->fpwrst) pwrdm->fpwrst_counter[fpwrst -PWRDM_FPWRST_OFFSET ]++; -_pwrdm_update_pwrst_time (pwrdm, prev); +_pwrdm_update_pwrst_time (pwrdm, pwrdm->fpwrst); pwrdm->fpwrst = fpwrst; - -return 0 ; }static int _pwrdm_pre_transition_cb (struct powerdomain *pwrdm,void *unused) {pwrdm_clear_all_prev_pwrst (pwrdm); -_pwrdm_state_switch (pwrdm,PWRDM_STATE_NOW ); +_pwrdm_state_switch (pwrdm);return 0 ; } +/** +* _pwrdm_post_transition_cb - record powerdomain usage data; track power state +* (after powerdomain power state transition) +* @pwrdm: struct powerdomain * to observe +* +* If the powerdomain @pwrdm's previous power state doesn't match our +* recollection of the powerdomain's current power state, then +* increment the counter for the previous power state. And if the +* powerdomain's previous power state doesn't match the current power +* state, increment the counter for the current power state. This +* function is used to track context loss events, and for debugging. +* Also if CONFIG_PM_DEBUG=y, track the approximate amount of time the +* powerdomain has spent in the previous power state. Caller must +* hold pwrdm->_lock. XXX Note that the counts and durations observed +* by this function may be inaccurate. Powerdomains can transition +* power states automatically, without the kernel being involved -- +* for example, a device can DMA data from memory while the MPU is +* asleep. This function does not attempt to account for that. XXX +* It may be possible to skip this function completely if PM debugging +* is not needed and off-mode and OSWR is disabled (e.g., no context +* loss events). No return value. +*/ static int _pwrdm_post_transition_cb (struct powerdomain *pwrdm,void *unused) { -_pwrdm_state_switch (pwrdm,PWRDM_STATE_PREV ); +int prev, next, fpwrst; +int trace_state =0 ; + + prev =_pwrdm_read_prev_fpwrst (pwrdm); +if (pwrdm->fpwrst != prev) + pwrdm->fpwrst_counter[prev -PWRDM_FPWRST_OFFSET ]++; + +_pwrdm_update_pwrst_time (pwrdm, prev); + +/* +* If the power domain did not hit the desired state, +* generate a trace event with both the desired and hit states +*/ + next =_pwrdm_read_next_fpwrst (pwrdm); +if (next != prev) { + trace_state = (PWRDM_TRACE_STATES_FLAG | next <<8 | + prev); +trace_power_domain_target (pwrdm->name, trace_state, +smp_processor_id ()); + } + + fpwrst =_pwrdm_read_fpwrst (pwrdm); +if (fpwrst != prev) + pwrdm->fpwrst_counter[fpwrst -PWRDM_FPWRST_OFFSET ]++; + + pwrdm->fpwrst = fpwrst; +return 0 ; }
@@ -1055,7 +1087,7 @@ int pwrdm_state_switch_nolock(struct powerdomain *pwrdm) ret = arch_pwrdm->pwrdm_wait_transition (pwrdm);if (!ret) - ret =_pwrdm_state_switch (pwrdm,PWRDM_STATE_NOW ); +_pwrdm_state_switch (pwrdm);return ret; }
arch/arm/mach-omap2/powerdomain.h +1 -0
@@ -237,6 +237,7 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);int pwrdm_state_switch_nolock (struct powerdomain *pwrdm);int pwrdm_state_switch (struct powerdomain *pwrdm); +int pwrdm_state_switch_nolock (struct powerdomain *pwrdm);int pwrdm_pre_transition (struct powerdomain *pwrdm);int pwrdm_post_transition (struct powerdomain *pwrdm);int pwrdm_get_context_loss_count (struct powerdomain *pwrdm);
Paul Walmsley
maintainerPATCH 4/12 ARM: OMAP2+: PM: clean up some debugfs functions
In reply to Paul WalmsleyMove some debugfs functions into the powerdomain and clockdomain code; the ultimate goal is to stop exporting some of the powerdomain/clockdomain functions. Get rid of the nasty hacks that avoid executing some of the debug functions based on string comparisons on powerdomain and clockdomain names. Lock the powerdomain for the duration of these functions so that the debug information doesn't change during execution. Also, while here, fix a whitespace issue in mach-omap2/pm-debug.c.
--- arch/arm/mach-omap2/clockdomain.c | 18 +++++++- arch/arm/mach-omap2/clockdomain.h | 2 + arch/arm/mach-omap2/pm-debug.c | 77 ++-------------------------------- arch/arm/mach-omap2/powerdomain.c | 85 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/powerdomain.h | 4 ++ 5 files changed, 111 insertions(+), 75 deletions(-)
arch/arm/mach-omap2/clockdomain.c +16 -2
@@ -22,9 +22,8 @@#include <linux/clk.h> #include <linux/limits.h> #include <linux/err.h> - +#include <linux/seq_file.h> #include <linux/io.h> -#include <linux/bitops.h> #include "soc.h"
@@ -1281,3 +1280,18 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)return _clkdm_clk_hwmod_disable (clkdm); } +/* Clockdomain debugfs functions */ + +int clkdm_dbg_show_counter (struct clockdomain *clkdm,void *seq_file) +{ +struct seq_file *s = (struct seq_file *)seq_file; + +if (!clkdm->flags) +return 0 ; + +seq_printf (s,"%s->%s (%d)\n" , clkdm->name, clkdm->pwrdm.ptr->name, + clkdm->usecount); + +return 0 ; +} +
arch/arm/mach-omap2/clockdomain.h +2 -0
@@ -229,4 +229,6 @@ extern struct clkdm_dep gfx_24xx_wkdeps[];extern struct clkdm_dep dsp_24xx_wkdeps[];extern struct clockdomain wkup_common_clkdm; +extern int clkdm_dbg_show_counter (struct clockdomain *clkdm,void *seq_file); +#endif
arch/arm/mach-omap2/pm-debug.c +4 -73
89 lines not on this page · raw message
arch/arm/mach-omap2/powerdomain.c +85 -0
100 lines not on this page · raw message
arch/arm/mach-omap2/powerdomain.h +4 -0
@@ -276,4 +276,8 @@ extern struct powerdomain gfx_omap2_pwrdm;extern void pwrdm_lock (struct powerdomain *pwrdm);extern void pwrdm_unlock (struct powerdomain *pwrdm); +/* Debugfs functions */ +extern int pwrdm_dbg_show_counter (struct powerdomain *pwrdm,void *seq_file); +extern int pwrdm_dbg_show_timer (struct powerdomain *pwrdm,void *seq_file); +#endif
Paul Walmsley
maintainerPATCH 5/12 ARM: OMAP2+: powerdomain: remove some redundant checks; add some notes
In reply to Paul WalmsleyRemove some redundant tests in static functions, and add some comments to some code that should have future attention.
--- arch/arm/mach-omap2/powerdomain.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/powerdomain.c +11 -7
@@ -95,7 +95,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)int i;struct voltagedomain *voltdm; -if (!pwrdm || !pwrdm->name) +if (!pwrdm->name)return -EINVAL ; if (cpu_is_omap44xx() &&
@@ -528,9 +528,6 @@ static int _pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) {int ret = -EINVAL ; -if (!pwrdm) -return -EINVAL ; -if (pwrdm->banks < (bank +1 ))return -EEXIST ;
@@ -566,9 +563,6 @@ static int _pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst) {int ret = -EINVAL ; -if (!pwrdm) -return -EINVAL ; -if (pwrdm->banks < (bank +1 ))return -EEXIST ;
@@ -635,6 +629,11 @@ static void _pwrdm_state_switch(struct powerdomain *pwrdm)static int _pwrdm_pre_transition_cb (struct powerdomain *pwrdm,void *unused) { +/* +* XXX It should be possible to avoid the clear_all_prev_pwrst +* call for powerdomains if we are programming them to stay on, +* for example. +*/ pwrdm_clear_all_prev_pwrst (pwrdm);_pwrdm_state_switch (pwrdm);return 0 ;
@@ -1000,6 +999,11 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)return ret;/* +* XXX Is there some way for us to skip powerdomains that +* don't have a prev pwrst register? +*/ + +/* * XXX should get the powerdomain's current state here; * warn & fail if it is not ON. */
Paul Walmsley
maintainerPATCH 6/12 ARM: OMAP2+: CM: use the cached copy of the clockdomain's hwsup state
In reply to Paul WalmsleyAvoid some unnecessary CM IP block reads by using the cached copy of the clockdomain's hardware-supervised idle state. This should simplify the code slightly and save a few hundred nanoseconds in these paths.
--- arch/arm/mach-omap2/cm2xxx.c | 19 ++----------------- arch/arm/mach-omap2/cm3xxx.c | 14 ++------------ 2 files changed, 4 insertions(+), 29 deletions(-)
arch/arm/mach-omap2/cm2xxx.c +2 -17
@@ -285,14 +285,7 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm)static int omap2xxx_clkdm_clk_enable (struct clockdomain *clkdm) { -bool hwsup = false; - -if (!clkdm->clktrctrl_mask) -return 0 ; - - hwsup =omap2xxx_cm_is_clkdm_in_hwsup (clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); -if (!hwsup && clkdm->flags &CLKDM_CAN_FORCE_WAKEUP ) +if (!clkdm_in_hwsup (clkdm) && clkdm->flags &CLKDM_CAN_FORCE_WAKEUP )omap2xxx_clkdm_wakeup (clkdm);return 0 ;
@@ -300,15 +293,7 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm)static int omap2xxx_clkdm_clk_disable (struct clockdomain *clkdm) { -bool hwsup = false; - -if (!clkdm->clktrctrl_mask) -return 0 ; - - hwsup =omap2xxx_cm_is_clkdm_in_hwsup (clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - -if (!hwsup && clkdm->flags &CLKDM_CAN_FORCE_SLEEP ) +if (!clkdm_in_hwsup (clkdm) && clkdm->flags &CLKDM_CAN_FORCE_SLEEP )omap2xxx_clkdm_sleep (clkdm);return 0 ;
arch/arm/mach-omap2/cm3xxx.c +2 -12
@@ -227,8 +227,6 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm)static int omap3xxx_clkdm_clk_enable (struct clockdomain *clkdm) { -bool hwsup = false; -if (!clkdm->clktrctrl_mask)return 0 ;
@@ -243,10 +241,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)return 0 ; } - hwsup =omap3xxx_cm_is_clkdm_in_hwsup (clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - -if (hwsup) { +if (clkdm_in_hwsup (clkdm)) {/* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup (clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask);
@@ -263,8 +258,6 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)static int omap3xxx_clkdm_clk_disable (struct clockdomain *clkdm) { -bool hwsup = false; -if (!clkdm->clktrctrl_mask)return 0 ;
@@ -280,10 +273,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)return 0 ; } - hwsup =omap3xxx_cm_is_clkdm_in_hwsup (clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - -if (hwsup) { +if (clkdm_in_hwsup (clkdm)) {/* Disable HW transitions when we are changing deps */ omap3xxx_cm_clkdm_disable_hwsup (clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask);
Paul Walmsley
maintainerPATCH 7/12 ARM: OMAP2+: powerdomain: cache the powerdomain next power state
In reply to Paul WalmsleyCache the powerdomain next power state registers. The objective here is to avoid unneeded reads and writes to the next power state registers, which are slow compared to RAM & CPU cache.
--- arch/arm/mach-omap2/powerdomain.c | 64 +++++++++++++++++-------------------- arch/arm/mach-omap2/powerdomain.h | 17 ++++++++++ 2 files changed, 46 insertions(+), 35 deletions(-)
arch/arm/mach-omap2/powerdomain.c +29 -35
@@ -376,7 +376,7 @@ static int _pwrdm_pwrst_to_fpwrst(struct powerdomain *pwrdm, u8 pwrst, u8 logic,* software-controllable, returns 0; otherwise, passes along the * return value from pwrdm_set_logic_retst() if there is an error * returned by that function, otherwise, passes along the return value -* from pwrdm_set_next_pwrst() +* from pwrdm_set_next_fpwrst() */ static int _set_logic_retst_and_pwrdm_pwrst (struct powerdomain *pwrdm,u8 logic,u8 pwrst)
@@ -426,6 +426,9 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)int next_pwrst, next_logic, ret;u8 fpwrst; +if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID) +return pwrdm->next_fpwrst; + next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst (pwrdm);if (next_pwrst <0 )return next_pwrst;
@@ -438,6 +441,10 @@ static int _pwrdm_read_next_fpwrst(struct powerdomain *pwrdm)return next_logic; } ret =_pwrdm_pwrst_to_fpwrst (pwrdm, next_pwrst, next_logic, &fpwrst); +if (!ret) { + pwrdm->next_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID; + }return (ret) ? ret : fpwrst; }
@@ -663,7 +670,7 @@ static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)*/ static int _pwrdm_post_transition_cb (struct powerdomain *pwrdm,void *unused) { -int prev, next, fpwrst; +int prev, fpwrst;int trace_state =0 ; prev =_pwrdm_read_prev_fpwrst (pwrdm);
@@ -676,10 +683,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)* If the power domain did not hit the desired state, * generate a trace event with both the desired and hit states */ - next =_pwrdm_read_next_fpwrst (pwrdm); -if (next != prev) { - trace_state = (PWRDM_TRACE_STATES_FLAG | next <<8 | - prev); +if (pwrdm->next_fpwrst != prev) { + trace_state = (PWRDM_TRACE_STATES_FLAG | + pwrdm->next_fpwrst <<8 | prev);trace_power_domain_target (pwrdm->name, trace_state,smp_processor_id ()); }
@@ -1256,6 +1262,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)if (ret)return ret; +if (pwrdm->_flags & _PWRDM_NEXT_FPWRST_IS_VALID && + pwrdm->next_fpwrst == fpwrst) +return 0 ; +pr_debug ("%s: set fpwrst %0x to pwrdm %s\n" , __func__, fpwrst, pwrdm->name);
@@ -1264,6 +1274,10 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)pwrdm_lock (pwrdm); ret =_set_logic_retst_and_pwrdm_pwrst (pwrdm, logic, pwrst); +if (!ret) { + pwrdm->next_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID; + }pwrdm_unlock (pwrdm);return ret;
@@ -1279,36 +1293,16 @@ int pwrdm_set_next_fpwrst(struct powerdomain *pwrdm, u8 fpwrst)*/ int pwrdm_read_next_fpwrst (struct powerdomain *pwrdm) { -int next_pwrst, next_logic, ret; -u8 fpwrst; +int ret; -if (!arch_pwrdm) +if (!pwrdm)return -EINVAL ;pwrdm_lock (pwrdm); - - next_pwrst = arch_pwrdm->pwrdm_read_next_pwrst (pwrdm); -if (next_pwrst <0 ) { - ret = next_pwrst; - goto prnf_out; - } - - next_logic = next_pwrst; -if (_pwrdm_logic_retst_can_change (pwrdm) && - arch_pwrdm->pwrdm_read_logic_pwrst) { - next_logic = arch_pwrdm->pwrdm_read_logic_pwrst (pwrdm); -if (next_logic <0 ) { - ret = next_logic; - goto prnf_out; - } - } - - ret =_pwrdm_pwrst_to_fpwrst (pwrdm, next_pwrst, next_logic, &fpwrst); - -prnf_out: + ret =_pwrdm_read_next_fpwrst (pwrdm);pwrdm_unlock (pwrdm); -return (ret) ? ret : fpwrst; +return ret; }/**
@@ -1344,10 +1338,6 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst)pwrdm_lock (pwrdm); -/* -* XXX quite heavyweight for what this is intended to do; the -* next fpwrst should simply be cached -*/ next_fpwrst =_pwrdm_read_next_fpwrst (pwrdm);if (next_fpwrst == fpwrst) goto psf_out;
@@ -1364,9 +1354,13 @@ int pwrdm_set_fpwrst(struct powerdomain *pwrdm, enum pwrdm_func_state fpwrst) } ret =_set_logic_retst_and_pwrdm_pwrst (pwrdm, logic, pwrst); -if (ret) +if (ret) {pr_err ("%s: unable to set power state of powerdomain: %s\n" , __func__, pwrdm->name); + }else { + pwrdm->next_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_NEXT_FPWRST_IS_VALID; + }_pwrdm_restore_clkdm_state (pwrdm, sleep_switch, hwsup);
arch/arm/mach-omap2/powerdomain.h +17 -0
@@ -84,6 +84,16 @@ enum pwrdm_func_state {#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2)/* +* Powerdomain internal flags (struct powerdomain._flags) +* +* _PWRDM_NEXT_FPWRST_IS_VALID: the locally-cached copy of the +* powerdomain's next-functional-power-state -- struct +* powerdomain.next_fpwrst -- is valid. If this bit is not set, +* the code needs to load the current value from the hardware. +*/ +#define _PWRDM_NEXT_FPWRST_IS_VALID BIT(0) + +/* * Number of memory banks that are power-controllable. On OMAP4430, the * maximum is 5. */
@@ -127,12 +137,17 @@ struct powerdomain;* in @pwrstctrl_offs * @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans) * @fpwrst_counter: estimated number of times the pwrdm entered the power states +* @next_fpwrst: cache of the powerdomain's next-power-state * @timer: sched_clock() timestamp of last pwrdm_state_switch() * @fpwrst_timer: estimated nanoseconds of residency in the various power states * @_lock: spinlock used to serialize powerdomain and some clockdomain ops * @_lock_flags: stored flags when @_lock is taken +* @_flags: flags (for internal use only) * * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. +* +* Possible values for @_flags are documented above in the +* "Powerdomain internal flags (struct powerdomain._flags)" comments. */ struct powerdomain {const char *name;
@@ -149,6 +164,8 @@ struct powerdomain {const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS ];const u8 prcm_partition;u8 fpwrst; +u8 next_fpwrst; +u8 _flags;struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS ];struct list_head node;struct list_head voltdm_node;
Paul Walmsley
maintainerPATCH 8/12 ARM: OMAP2+: powerdomain: cache the powerdomain's previous power state
In reply to Paul WalmsleyCache the powerdomain previous power state registers. The objective here is to avoid unneeded reads from the previous power state registers. Reads from these registers can be extremely slow, even by I/O device standards. I no longer recall the exact measurements, but my recollection was that they cost several microseconds.
The cache is invalidated as part of the powerdomain pre-transition code, which runs shortly before WFI/WFE.
--- arch/arm/mach-omap2/powerdomain.c | 9 +++++++++ arch/arm/mach-omap2/powerdomain.h | 14 ++++++++++++++ 2 files changed, 23 insertions(+)
arch/arm/mach-omap2/powerdomain.c +9 -0
@@ -499,6 +499,9 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm)if (!_pwrdm_pwrst_can_change (pwrdm))return PWRDM_FUNC_PWRST_ON ; +if (pwrdm->_flags & _PWRDM_PREV_FPWRST_IS_VALID) +return pwrdm->prev_fpwrst; + pwrst = arch_pwrdm->pwrdm_read_prev_pwrst (pwrdm);if (pwrst <0 )return pwrst;
@@ -512,6 +515,10 @@ static int _pwrdm_read_prev_fpwrst(struct powerdomain *pwrdm) } ret =_pwrdm_pwrst_to_fpwrst (pwrdm, pwrst, logic_pwrst, &fpwrst); +if (!ret) { + pwrdm->prev_fpwrst = fpwrst; + pwrdm->_flags |= _PWRDM_PREV_FPWRST_IS_VALID; + }return (ret) ? ret : fpwrst; }
@@ -1017,6 +1024,8 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)pr_debug ("powerdomain: %s: clearing previous power state reg\n" , pwrdm->name); + pwrdm->_flags &= ~_PWRDM_PREV_FPWRST_IS_VALID; +if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst) ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst (pwrdm);
arch/arm/mach-omap2/powerdomain.h +14 -0
@@ -90,8 +90,17 @@ enum pwrdm_func_state {* powerdomain's next-functional-power-state -- struct * powerdomain.next_fpwrst -- is valid. If this bit is not set, * the code needs to load the current value from the hardware. +* +* _PWRDM_PREV_FPWRST_IS_VALID: the locally-cached copy of the +* powerdomain's previous-functional-power-state -- struct +* powerdomain.prev_fpwrst -- is valid. If this bit is not set, +* the code needs to load the current value from the hardware. The +* previous-functional-power-state cache for the CORE and MPU needs +* to be invalidated right before WFI, unless they were not programmed +* to change power states. */ #define _PWRDM_NEXT_FPWRST_IS_VALID BIT(0) +#define _PWRDM_PREV_FPWRST_IS_VALID BIT(1)/* * Number of memory banks that are power-controllable. On OMAP4430, the
@@ -138,6 +147,7 @@ struct powerdomain;* @fpwrst: current func power state (set in pwrdm_state_switch() or post_trans) * @fpwrst_counter: estimated number of times the pwrdm entered the power states * @next_fpwrst: cache of the powerdomain's next-power-state +* @prev_fpwrst: cache of the powerdomain's previous-power-state bitfield * @timer: sched_clock() timestamp of last pwrdm_state_switch() * @fpwrst_timer: estimated nanoseconds of residency in the various power states * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
@@ -146,6 +156,9 @@ struct powerdomain;* * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. * +* @prev_fpwrst is updated during pwrdm_pre_transition(), but presumably +* should also be updated upon clock/IP block idle transitions. +* * Possible values for @_flags are documented above in the * "Powerdomain internal flags (struct powerdomain._flags)" comments. */
@@ -165,6 +178,7 @@ struct powerdomain {const u8 prcm_partition;u8 fpwrst;u8 next_fpwrst; +u8 prev_fpwrst;u8 _flags;struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS ];struct list_head node;
Paul Walmsley
maintainerPATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
In reply to Paul WalmsleyThere's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag, PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.
--- arch/arm/mach-omap2/powerdomain.c | 9 ++++++--- arch/arm/mach-omap2/powerdomain.h | 4 ++++ arch/arm/mach-omap2/powerdomains2xxx_data.c | 2 ++ arch/arm/mach-omap2/powerdomains33xx_data.c | 3 ++- arch/arm/mach-omap2/powerdomains3xxx_data.c | 9 ++++++--- arch/arm/mach-omap2/powerdomains44xx_data.c | 5 ++++- 6 files changed, 24 insertions(+), 8 deletions(-)
arch/arm/mach-omap2/powerdomain.c +6 -3
@@ -462,7 +462,8 @@ static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)int pwrst, logic_pwrst, ret;u8 fpwrst; -if (!_pwrdm_pwrst_can_change (pwrdm)) +if (!_pwrdm_pwrst_can_change (pwrdm) || + pwrdm->flags &PWRDM_ACTIVE_WITH_KERNEL )return PWRDM_FUNC_PWRST_ON ; pwrst = arch_pwrdm->pwrdm_read_pwrst (pwrdm);
@@ -1104,12 +1105,14 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)int pwrdm_state_switch_nolock (struct powerdomain *pwrdm) { -int ret; +int ret =0 ;if (!pwrdm || !arch_pwrdm)return -EINVAL ; - ret = arch_pwrdm->pwrdm_wait_transition (pwrdm); +if (!(pwrdm->flags &PWRDM_ACTIVE_WITH_KERNEL )) + ret = arch_pwrdm->pwrdm_wait_transition (pwrdm); +if (!ret)_pwrdm_state_switch (pwrdm);
arch/arm/mach-omap2/powerdomain.h +4 -0
@@ -78,10 +78,14 @@ enum pwrdm_func_state {* * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state * to a lower sleep state without waking up the powerdomain +* +* PWRDM_ACTIVE_WITH_KERNEL - this powerdomain's current power state is +* guaranteed to be ON whenever the kernel is running */ #define PWRDM_HAS_HDWR_SAR BIT(0)#define PWRDM_HAS_MPU_QUIRK BIT(1)#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2) +#define PWRDM_ACTIVE_WITH_KERNEL BIT(3)/* * Powerdomain internal flags (struct powerdomain._flags)
arch/arm/mach-omap2/powerdomains2xxx_data.c +2 -0
@@ -54,6 +54,7 @@ static struct powerdomain mpu_24xx_pwrdm = { [0] = PWRSTS_ON, }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };static struct powerdomain core_24xx_pwrdm = {
@@ -73,6 +74,7 @@ static struct powerdomain core_24xx_pwrdm = { [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };
arch/arm/mach-omap2/powerdomains33xx_data.c +2 -1
@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = { .pwrstst_offs = AM33XX_PM_MPU_PWRSTST_OFFSET, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL), .banks = 3, .logicretstate_mask = AM33XX_LOGICRETSTATE_MASK, .mem_on_mask = {
arch/arm/mach-omap2/powerdomains3xxx_data.c +6 -3
@@ -58,7 +58,7 @@ static struct powerdomain mpu_3xxx_pwrdm = { .prcm_offs = MPU_MOD, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_MPU_QUIRK, + .flags = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL), .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET,
@@ -74,7 +74,7 @@ static struct powerdomain mpu_am35x_pwrdm = { .prcm_offs = MPU_MOD, .pwrsts = PWRSTS_ON, .pwrsts_logic_ret = PWRSTS_ON, - .flags = PWRDM_HAS_MPU_QUIRK, + .flags = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL), .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_ON,
@@ -110,6 +110,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { [1 ] =PWRSTS_OFF_RET_ON ,/* MEM2ONSTATE */ }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, }; static struct powerdomain core_3xxx_es3_1_pwrdm = {
@@ -121,7 +122,8 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {* Setting the SAR flag for errata ID i478 which applies * to 3430 <= ES3.1 */ - .flags = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */ + .flags = (PWRDM_HAS_HDWR_SAR | /* for USBTLL only */ + PWRDM_ACTIVE_WITH_KERNEL), .banks = 2, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */
@@ -149,6 +151,7 @@ static struct powerdomain core_am35x_pwrdm = { [1 ] =PWRSTS_ON ,/* MEM2ONSTATE */ }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, }; static struct powerdomain dss_pwrdm = {
arch/arm/mach-omap2/powerdomains44xx_data.c +4 -1
@@ -53,7 +53,8 @@ static struct powerdomain core_44xx_pwrdm = { [3] = PWRSTS_ON, /* ducati_l2ram */ [4] = PWRSTS_ON, /* ducati_unicache */ }, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL), };/* gfx_44xx_pwrdm: 3D accelerator power domain */
@@ -164,6 +165,7 @@ static struct powerdomain cpu0_44xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* cpu0_l1 */ }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };/* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
@@ -218,6 +220,7 @@ static struct powerdomain mpu_44xx_pwrdm = { [1] = PWRSTS_ON, /* mpu_l2 */ [2] = PWRSTS_ON, /* mpu_ram */ }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };/* ivahd_44xx_pwrdm: IVA-HD power domain */
PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
Quoted 92 lines · Paul Walmsley
There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag,
PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.Signed-off-by Paul Walmsley <[email protected]>Cc Beno?t Cousson <[email protected]>--- arch/arm/mach-omap2/powerdomain.c | 9 ++++++--- arch/arm/mach-omap2/powerdomain.h | 4 ++++ arch/arm/mach-omap2/powerdomains2xxx_data.c | 2 ++ arch/arm/mach-omap2/powerdomains33xx_data.c | 3 ++- arch/arm/mach-omap2/powerdomains3xxx_data.c | 9 ++++++--- arch/arm/mach-omap2/powerdomains44xx_data.c | 5 ++++- 6 files changed, 24 insertions(+), 8 deletions(-)arch/arm/mach-omap2/powerdomain.c +6
-3@@ -462,7 +462,8 @@ static int _pwrdm_read_fpwrst(struct powerdomain *pwrdm)int pwrst, logic_pwrst, ret;u8 fpwrst; -if (!_pwrdm_pwrst_can_change (pwrdm)) +if (!_pwrdm_pwrst_can_change (pwrdm) || + pwrdm->flags &PWRDM_ACTIVE_WITH_KERNEL )return PWRDM_FUNC_PWRST_ON ; pwrst = arch_pwrdm->pwrdm_read_pwrst (pwrdm);@@ -1104,12 +1105,14 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)int pwrdm_state_switch_nolock (struct powerdomain *pwrdm) { -int ret; +int ret =0 ;if (!pwrdm || !arch_pwrdm)return -EINVAL ; - ret = arch_pwrdm->pwrdm_wait_transition (pwrdm); +if (!(pwrdm->flags &PWRDM_ACTIVE_WITH_KERNEL )) + ret = arch_pwrdm->pwrdm_wait_transition (pwrdm); +if (!ret)_pwrdm_state_switch (pwrdm);arch/arm/mach-omap2/powerdomain.h +4
-0@@ -78,10 +78,14 @@ enum pwrdm_func_state {* * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state * to a lower sleep state without waking up the powerdomain +* +* PWRDM_ACTIVE_WITH_KERNEL - this powerdomain's current power state is +* guaranteed to be ON whenever the kernel is running */ #define PWRDM_HAS_HDWR_SAR BIT(0)#define PWRDM_HAS_MPU_QUIRK BIT(1)#define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2) +#define PWRDM_ACTIVE_WITH_KERNEL BIT(3)/* * Powerdomain internal flags (struct powerdomain._flags) arch/arm/mach-omap2/powerdomains2xxx_data.c +2
-0@@ -54,6 +54,7 @@ static struct powerdomain mpu_24xx_pwrdm = { [0] = PWRSTS_ON, }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };static struct powerdomain core_24xx_pwrdm = {@@ -73,6 +74,7 @@ static struct powerdomain core_24xx_pwrdm = { [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };arch/arm/mach-omap2/powerdomains33xx_data.c +0
-0
arch/arm/mach-omap2/powerdomains33xx_data.c static struct powerdomain mpu_33xx_pwrdm = { · line 127
Quoted 6 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +2
-1@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = { .pwrstst_offs = AM33XX_PM_MPU_PWRSTST_OFFSET, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL),
This needs to be applicable for "wkup_pwrdm" as well.
Thanks,
Vaibhav
Quoted 89 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +0
-0.banks = 3, .logicretstate_mask = AM33XX_LOGICRETSTATE_MASK, .mem_on_mask = {arch/arm/mach-omap2/powerdomains3xxx_data.c +6
-3@@ -58,7 +58,7 @@ static struct powerdomain mpu_3xxx_pwrdm = { .prcm_offs = MPU_MOD, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_MPU_QUIRK, + .flags = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL), .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET,@@ -74,7 +74,7 @@ static struct powerdomain mpu_am35x_pwrdm = { .prcm_offs = MPU_MOD, .pwrsts = PWRSTS_ON, .pwrsts_logic_ret = PWRSTS_ON, - .flags = PWRDM_HAS_MPU_QUIRK, + .flags = (PWRDM_HAS_MPU_QUIRK | PWRDM_ACTIVE_WITH_KERNEL), .banks = 1, .pwrsts_mem_ret = { [0] = PWRSTS_ON,@@ -110,6 +110,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { [1 ] =PWRSTS_OFF_RET_ON ,/* MEM2ONSTATE */ }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, }; static struct powerdomain core_3xxx_es3_1_pwrdm = {@@ -121,7 +122,8 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {* Setting the SAR flag for errata ID i478 which applies * to 3430 <= ES3.1 */ - .flags = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */ + .flags = (PWRDM_HAS_HDWR_SAR | /* for USBTLL only */ + PWRDM_ACTIVE_WITH_KERNEL), .banks = 2, .pwrsts_mem_ret = { [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */@@ -149,6 +151,7 @@ static struct powerdomain core_am35x_pwrdm = { [1 ] =PWRSTS_ON ,/* MEM2ONSTATE */ }, .voltdm = { .name = "core" }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, }; static struct powerdomain dss_pwrdm = {arch/arm/mach-omap2/powerdomains44xx_data.c +4
-1@@ -53,7 +53,8 @@ static struct powerdomain core_44xx_pwrdm = { [3] = PWRSTS_ON, /* ducati_l2ram */ [4] = PWRSTS_ON, /* ducati_unicache */ }, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL), };/* gfx_44xx_pwrdm: 3D accelerator power domain */ @@ -164,6 +165,7 @@ static struct powerdomain cpu0_44xx_pwrdm = { .pwrsts_mem_on = { [0] = PWRSTS_ON, /* cpu0_l1 */ }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };/* cpu1_44xx_pwrdm: MPU1 processor and Neon coprocessor power domain */ @@ -218,6 +220,7 @@ static struct powerdomain mpu_44xx_pwrdm = { [1] = PWRSTS_ON, /* mpu_l2 */ [2] = PWRSTS_ON, /* mpu_ram */ }, + .flags = PWRDM_ACTIVE_WITH_KERNEL, };/* ivahd_44xx_pwrdm: IVA-HD power domain */ _______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
In reply to Paul WalmsleyHi Paul,
Quoted 16 lines · Paul Walmsley
There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag,
PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.Signed-off-by Paul Walmsley <[email protected]>Cc Beno?t Cousson <[email protected]>--- arch/arm/mach-omap2/powerdomain.c | 9 ++++++--- arch/arm/mach-omap2/powerdomain.h | 4 ++++ arch/arm/mach-omap2/powerdomains2xxx_data.c | 2 ++ arch/arm/mach-omap2/powerdomains33xx_data.c | 3 ++- arch/arm/mach-omap2/powerdomains3xxx_data.c | 9 ++++++--- arch/arm/mach-omap2/powerdomains44xx_data.c | 5 ++++- 6 files changed, 24 insertions(+), 8 deletions(-)
[snip]
arch/arm/mach-omap2/powerdomains44xx_data.c static struct powerdomain core_44xx_pwrdm = { · line 58
Quoted 12 lines
arch/arm/mach-omap2/powerdomains44xx_data.c +2
-1@@ -53,7 +53,8 @@ static struct powerdomain core_44xx_pwrdm = { [3] = PWRSTS_ON, /* ducati_l2ram */ [4] = PWRSTS_ON, /* ducati_unicache */ }, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL), };
My understanding is that for OMAP4 devices, the core power domain may not be active the same time as the MPU power domain. The Cortex-A9 has the ability to access some peripherals (such as timer, McBSP) via a private bus that does not require the core domain to be active. This is a difference from OMAP3 devices, where the core would always be on with the MPU power domain.
Hopefully, Benoit will chime in if I have gotten this wrong ;-)
Cheers
Jon
Paul Walmsley
maintainerPATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
Quoted 6 lines · Jon Hunter
My understanding is that for OMAP4 devices, the core power domain may not be active the same time as the MPU power domain. The Cortex-A9 has the ability to access some peripherals (such as timer, McBSP) via a private bus that does not require the core domain to be active. This is a difference from OMAP3 devices, where the core would always be on with the MPU power domain.
You are absolutely right and I will drop that part from this patch.
- Paul
PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
Quoted 11 lines · Paul Walmsley
Quoted 6 lines · Jon Hunter
My understanding is that for OMAP4 devices, the core power domain may not be active the same time as the MPU power domain. The Cortex-A9 has the ability to access some peripherals (such as timer, McBSP) via a private bus that does not require the core domain to be active. This is a difference from OMAP3 devices, where the core would always be on with the MPU power domain.
You are absolutely right and I will drop that part from this patch.
Just to be clear, MPU has direct path to ABE domain peripherals on OMAP4. As Jon pointed out MCBSP and few timers are put under this domain can be directly accessed by MPU without L3. ABE also can be accessed via L3 by MPU. ABE has a dual map with MPU.
Regards
Santosh
PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
In reply to Paul WalmsleyHi Paul,
Quoted 5 lines · Paul Walmsley
There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag,
PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.
[...]
arch/arm/mach-omap2/powerdomains33xx_data.c static struct powerdomain mpu_33xx_pwrdm = { · line 127
Quoted 11 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +2
-1@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = { .pwrstst_offs = AM33XX_PM_MPU_PWRSTST_OFFSET, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL),
In case of AM33xx, this flag should be set for PER and WKUP pwrdms also. EMIF, L3, L4 etc come under PER so this domain can't transition on an active system. PRCM and Control module come under WKUP, so the WKUP should the kernel should attempt to transition WKUP domain also.
Regards,
Vaibhav
PATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
Quoted 9 lines · Vaibhav
Hi Paul,
Quoted 5 lines · Paul Walmsley
There's no need to determine the current power state for powerdomains that must be on while the kernel is running. We mark these powerdomains with a new flag,
PWRDM_ACTIVE_WITH_KERNEL. Any powerdomain marked with that flag is reported as being in the ON power state while the kernel is running.[...]
Quoted 15 lines
arch/arm/mach-omap2/powerdomains33xx_data.c static struct powerdomain mpu_33xx_pwrdm = { · line 127
Quoted 11 lines
arch/arm/mach-omap2/powerdomains33xx_data.c +2
-1@@ -123,7 +123,8 @@ static struct powerdomain mpu_33xx_pwrdm = { .pwrstst_offs = AM33XX_PM_MPU_PWRSTST_OFFSET, .pwrsts = PWRSTS_OFF_RET_ON, .pwrsts_logic_ret = PWRSTS_OFF_RET, - .flags = PWRDM_HAS_LOWPOWERSTATECHANGE, + .flags = (PWRDM_HAS_LOWPOWERSTATECHANGE | + PWRDM_ACTIVE_WITH_KERNEL),In case of AM33xx, this flag should be set for PER and WKUP pwrdms also. EMIF, L3, L4 etc come under PER so this domain can't transition on an active system. PRCM and Control module come under WKUP, so
... the kernel should not attempt to change the WKUP power domain state.
Regards,
Vaibhav
Paul Walmsley
maintainerPATCH 9/12 ARM: OMAP2+: powerdomain: skip register reads for powerdomains known to be on
In reply to Bedia, VaibhavQuoted 4 lines · Vaibhav
In case of AM33xx, this flag should be set for PER and WKUP pwrdms also. EMIF, L3, L4 etc come under PER so this domain can't transition on an active system. PRCM and Control module come under WKUP, so the WKUP should the kernel should attempt to transition WKUP domain also.
Thanks - the patch has been updated to reflect this.
- Paul
Paul Walmsley
maintainerPATCH 10/12 ARM: OMAP2+: powerdomain: skip previous-power-state read if next_pwrst is ON
In reply to Paul WalmsleyIf the powerdomain's next-power-state is set to ON, then we can skip the powerdomain previous-power-state read during pwrdm_post_transition(). This is both an optimization (for all OMAPs) and a fix (for OMAP2xxx). It turns out the OMAP2xxx previous power state mechanism is slightly different than the OMAP3+ mechanism. The bitfield can't be cleared, and it's only updated after a powerdomain power state transition. So reading this value before any powerdomain power state transition occurred will always return OFF (the reset value). After this patch, if the power domain was programmed to stay ON before pwrdm_pre_transition() is called, the previous power state code will return ON during pwrdm_post_transition().
--- arch/arm/mach-omap2/powerdomain.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/powerdomain.c +3 -1
@@ -681,7 +681,9 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)int prev, fpwrst;int trace_state =0 ; - prev =_pwrdm_read_prev_fpwrst (pwrdm); + prev = (pwrdm->next_fpwrst ==PWRDM_FUNC_PWRST_ON ) ? +PWRDM_FUNC_PWRST_ON :_pwrdm_read_prev_fpwrst (pwrdm); +if (pwrdm->fpwrst != prev) pwrdm->fpwrst_counter[prev -PWRDM_FPWRST_OFFSET ]++;
Paul Walmsley
maintainerPATCH 11/12 ARM: OMAP2xxx: powerdomain: add previous power state tracking
In reply to Paul WalmsleyThe OMAP2xxx PRM does support a form of powerdomain previous-power-state tracking; so add it. This allows the power state tracking and debugging code to do something useful on this platform.
--- arch/arm/mach-omap2/prm2xxx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/arm/mach-omap2/prm2xxx.c +12 -0
@@ -180,10 +180,22 @@ static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)return omap2xxx_pwrst_to_common_pwrst (omap2xxx_pwrst); } +static int omap2xxx_pwrdm_read_prev_pwrst (struct powerdomain *pwrdm) +{ +u8 omap2xxx_pwrst; + + omap2xxx_pwrst =omap2_prm_read_mod_bits_shift (pwrdm->prcm_offs, +OMAP2_PM_PWSTST , +OMAP24XX_LASTSTATEENTERED_MASK ); + +return omap2xxx_pwrst_to_common_pwrst (omap2xxx_pwrst); +} +struct pwrdm_ops omap2_pwrdm_operations = { .pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst, .pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst, + .pwrdm_read_prev_pwrst = omap2xxx_pwrdm_read_prev_pwrst, .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst,
Paul Walmsley
maintainerPATCH 12/12 ARM: OMAP2xxx: PM: add pwrdm_(pre|post)_transition() calls to the 2xxx PM code
In reply to Paul WalmsleyThe OMAP2xxx PM code was missing calls to pwrdm_pre_transition() and pwrdm_post_transition(). This prevented the power state debugging from working correctly, and also violated some assumptions that are used in future power state caching patches.
--- arch/arm/mach-omap2/pm24xx.c | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/arm/mach-omap2/pm24xx.c +8 -0
@@ -98,6 +98,8 @@ static int omap2_enter_full_retention(void)omap2_gpio_prepare_for_idle (0 ); +pwrdm_pre_transition (NULL ); +/* One last check for pending IRQs to avoid extra latency due * to sleeping unnecessarily. */ if (omap_irq_pending ())
@@ -109,6 +111,8 @@ static int omap2_enter_full_retention(void) OMAP_SDRC_REGADDR(SDRC_POWER)); no_sleep: +pwrdm_post_transition (NULL ); +omap2_gpio_resume_after_idle ();clk_enable (osc_ck);
@@ -191,8 +195,12 @@ static void omap2_enter_mpu_retention(void)WARN_ON (pwrdm_set_next_fpwrst (mpu_pwrdm,PWRDM_FUNC_PWRST_ON )); } +pwrdm_pre_transition (mpu_pwrdm); +omap2_sram_idle (); +pwrdm_post_transition (mpu_pwrdm); +WARN_ON (pwrdm_set_next_fpwrst (mpu_pwrdm,PWRDM_FUNC_PWRST_ON )); }
cover ARM: OMAP2+: powerdomain updates after the functional power state conversion
In reply to Paul WalmsleyHi Paul,
Tested this whole set on omap3beagle and omap4panda. The only regression I noticed was that cpu0 debug counters do not increment on omap4 after this set. The patch at the end fixes this problem. Other than that, you can add acked-by tag from me if you want, I went the code through quickly and don't have any comments to it.
-Tero
From: Tero Kristo <[email protected]>
Date: Thu, 3 Jan 2013 20:07:27 +0200
Subject: [PATCH] ARM: OMAP4: PM: fix cpu0 statistics update during idle
Cpu0 PM counters do not update, as the cpu0 fpwrst is set to ON before calling pwrdm_post_transition. The optimized code checks whether the fpwrst is ON, and skips any further checks if this is the case. Fixed by re-ordering the code within omap4_mpuss_enter_lowpower function.
--- arch/arm/mach-omap2/omap-mpuss-lowpower.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
(quoted diff) +0 -0
b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 9acd52a..1bdd59e 100644
arch/arm/mach-omap2/omap-mpuss-lowpower.c +0 -0
@@ -269,10 +269,16 @@ int omap4_mpuss_enter_lowpower(unsigned int cpu,
u8 fpwrst)
* domain transition
*/
wakeup_cpu = smp_processor_id();
- WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
+ /*
+ * Due to optimizations to the code, pwrdm_post_transition
+ * must be called prior to resetting cpu0 pwrst to ON,
+ * otherwise cpu0 powerstate statistics don't update properly
+ */
pwrdm_post_transition(NULL);
+ WARN_ON(pwrdm_set_next_fpwrst(pm_info->pwrdm, PWRDM_FUNC_PWRST_ON));
+
return 0;
}
Signature · 1 line
1.7.4.1