ARM: OMAP2+: PM: implement a caching mechanism on the power domains state registers
cover ARM: OMAP2+: PM: implement a caching mechanism on the power domains state registers
From: Jean Pihet <[email protected]>
The OMAP3 PRCM registers accesses are known to be slow, with a PRCM register read taking up to 12-14us depending on the OPP.
This patch adds a caching mechanism on the power domains state registers. When the cache is cold or has been invalidated a register access is performed, otherwise the register value is retrieved from the registers cache.
The API is made of read and write functions for fields in the cache, as well as an invalidate and helper functions to invalidate parts of the cache contents (i.e. previous, current power states and all fields in the cache). The power domain code is converted to use the API to read and write the previous, current and next states for the power domains states, logical and memory states.
The PM debug code also uses the caching API instead of the internal pwrdm->state variable.
Using the caching mechanism optimizes the performance of the system in the transitions to and from the low power states.
Tested on Beagleboard using cpuidle in RET and OFF modes.
Based on the linux-omap git tree (3.4.0-rc2) [1] with the changes for the functional power states [2] and the per-device PM QoS support for OMAP [3].
[1] git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
[2] http://marc.info/?l=linux-omap&m=133475291911194&w=2
[3] http://marc.info/?l=linux-omap&m=133475685213067&w=2
Jean Pihet (5):
ARM: OMAP2+: PM: implement a caching mechanism on the power domains
state registers
ARM: OMAP2+: PM: use the power domains registers cache for the power
states
ARM: OMAP2+: PM: use the power domains registers cache for the logic
and mem states
ARM: OMAP2+: PM: use the power domains registers cache invalidate API
ARM: OMAP2+: PM debug: use the power domains registers caching API
arch/arm/mach-omap2/pm-debug.c | 16 ++- arch/arm/mach-omap2/pm34xx.c | 6 + arch/arm/mach-omap2/powerdomain.c | 272 ++++++++++++++++++++++++++++++++----- arch/arm/mach-omap2/powerdomain.h | 45 ++++++- 4 files changed, 297 insertions(+), 42 deletions(-)
Signature · 1 line
1.7.7.6
PATCH 1/5 ARM: OMAP2+: PM: implement a caching mechanism on the power domains state registers
From: Jean Pihet <[email protected]>
The OMAP3 PRCM registers accesses are known to be slow. A PRCM read can take up to 12-14us depending on the OPP.
This patch adds a caching mechanism on the power domains state registers. When the cache is cold or has been invalidated a register access is performed, otherwise the register value is retrieved from the registers cache.
The API is made of read and write functions for fields in the cache, as well as an invalidate function and helper functions to invalidate parts of the cache contents (i.e. previous, current power states and all fields in the cache).
--- arch/arm/mach-omap2/powerdomain.c | 128 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/powerdomain.h | 45 ++++++++++++- 2 files changed, 171 insertions(+), 2 deletions(-)
arch/arm/mach-omap2/powerdomain.c +128 -0
@@ -697,6 +697,134 @@ out: }/** +* pwrdm_cache_read - read from the registers cache +* @pwrdm: struct powerdomain * +* @index: index of the data to be read from the cache +* @value: data value to be returned +* +* Returns 0 if the data is read from the cache. +* Returns -ENODATA if the data is not present, -EINVAL if the data is +* to be read past the end of the cache. +*/ +static int pwrdm_cache_read (struct powerdomain *pwrdm,int index,int *value) +{ +if (index >=PWRDM_CACHE_SIZE ) +return -EINVAL ; + +if (!(pwrdm->cache_state & (1 << index))) +return -ENODATA ; + + *value = pwrdm->cache[index]; +return 0 ; +} + +/** +* pwrdm_cache_write - store data to the registers cache +* @pwrdm: struct powerdomain * +* @index: index of the data to write to the cache +* @value: data value to be stored +* +* Stores the data in the cache and maintains the internal cache state. +* +* Returns -EINVAL if the data is to be written past the end of the cache, +* 0 otherwise. +*/ +static int pwrdm_cache_write (struct powerdomain *pwrdm,int index,int value) +{ +if (index >=PWRDM_CACHE_SIZE ) +return -EINVAL ; + + pwrdm->cache[index] = value; + pwrdm->cache_state |= (1 << index); + +return 0 ; +} + +/** +* pwrdm_invalidate_regs_cache_fields - invalidate fields in the +* power domain registers cache +* @pwrdm: struct powerdomain * +* @mask: cache fields to invalidate, made by OR'ing the +* PWRDM_CACHE_* values +* +* If pwrdm is NULL, invalidate the fields for all power domains, +* otherwise invalidate them for the given pwrdm only. +* +* Invalidates some of the power domain cache fields, thus imposing +* an effective re-read from the HW register@the next access. +*/ +void pwrdm_invalidate_regs_cache_fields (struct powerdomain *pwrdm,int mask) +{ +struct powerdomain *temp_pwrdm; + +if (pwrdm) { + pwrdm->cache_state &= ~mask; + }else { +list_for_each_entry (temp_pwrdm, &pwrdm_list, node) + temp_pwrdm->cache_state &= ~mask; + } +} + +/** +* pwrdm_invalidate_regs_cache_fields_prev - invalidate the previous states +* in the power domain registers cache +* @pwrdm: struct powerdomain * +* +* If pwrdm is NULL, invalidate the previous states for all power domains, +* otherwise invalidate them for the given pwrdm only. +* +* Invalidates only the previous states of the power domain cache fields, +* thus imposing an effective re-read from the HW register at the next access. +*/ +void pwrdm_invalidate_regs_cache_fields_prev (struct powerdomain *pwrdm) +{ +int i; + +pwrdm_invalidate_regs_cache_fields (pwrdm, +PWRDM_CACHE_PREV_PWRST | +PWRDM_CACHE_PREV_LOGIC_PWRST ); +for (i =0 ; i <PWRDM_MAX_MEM_BANKS ; i++) +pwrdm_invalidate_regs_cache_fields (pwrdm, +PWRDM_CACHE_PREV_MEM_PWRST + i); +} + +/** +* pwrdm_invalidate_regs_cache_fields_current - invalidate the current +* states in the power domains' registers cache +* +* If pwrdm is NULL, invalidate the current states for all power domains, +* otherwise invalidate them for the given pwrdm only. +* +* Invalidates only the current states of the power domains cache fields, +* thus imposing an effective re-read from the HW register at the next access. +*/ +void pwrdm_invalidate_regs_cache_fields_current (struct powerdomain *pwrdm) +{ +int i; + +pwrdm_invalidate_regs_cache_fields (pwrdm,PWRDM_CACHE_PWRST | +PWRDM_CACHE_LOGIC_RETST ); +for (i =0 ; i <PWRDM_MAX_MEM_BANKS ; i++) { +pwrdm_invalidate_regs_cache_fields (pwrdm, +PWRDM_CACHE_MEM_PWRST + i); +pwrdm_invalidate_regs_cache_fields (pwrdm, +PWRDM_CACHE_MEM_ONST + i); + } +} + +/** +* pwrdm_invalidate_regs_cache_all - invalidate all fields in the registers +* cache for all power domains +* +* Invalidates all of the power domain cache fields of all power domains, +* thus imposing an effective re-read from the HW register at the next access +*/ +void pwrdm_invalidate_regs_cache_all (void ) +{ +pwrdm_invalidate_regs_cache_fields (NULL ,PWRDM_CACHE_ALL ); +} + +/** * pwrdm_set_next_pwrst - set next powerdomain power state * @pwrdm: struct powerdomain * to set * @pwrst: one of the PWRDM_POWER_* macros
arch/arm/mach-omap2/powerdomain.h +43 -2
75 lines not on this page · raw message
Signature · 1 line
1.7.7.6
PATCH 2/5 ARM: OMAP2+: PM: use the power domains registers cache for the power states
In reply to jean.pihet at newoldbits.comFrom: Jean Pihet <[email protected]>
Use the caching API for the previous, current and next power domains states.
--- arch/arm/mach-omap2/powerdomain.c | 32 ++++++++++++++++++++++++++------ 1 files changed, 26 insertions(+), 6 deletions(-)
arch/arm/mach-omap2/powerdomain.c +26 -6
@@ -854,6 +854,8 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) smp_processor_id());/* Program the pwrdm desired target state */ ret = arch_pwrdm->pwrdm_set_next_pwrst (pwrdm, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_PWRST , pwrst); }return ret;
@@ -869,13 +871,19 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)*/ int pwrdm_read_next_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_NEXT_PWRST , &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst) { ret = arch_pwrdm->pwrdm_read_next_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_PWRST , ret); + }return ret; }
@@ -906,13 +914,19 @@ int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)*/ int pwrdm_read_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PWRST , &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst) { ret = arch_pwrdm->pwrdm_read_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_PWRST , ret); + }return ret; }
@@ -943,13 +957,19 @@ int pwrdm_read_func_pwrst(struct powerdomain *pwrdm)*/ int pwrdm_read_prev_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PREV_PWRST , &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst) { ret = arch_pwrdm->pwrdm_read_prev_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_PREV_PWRST , ret); + }return ret; }
Signature · 1 line
1.7.7.6
PATCH 2/5 ARM: OMAP2+: PM: use the power domains registers cache for the power states
Hi Jean,
Quoted 53 lines · jean.pihet at newoldbits.com
From: Jean Pihet <[email protected]>
Use the caching API for the previous, current and next power domains states.
Signed-off-by Jean Pihet <[email protected]>--- arch/arm/mach-omap2/powerdomain.c | 32 ++++++++++++++++++++++++++------ 1 files changed, 26 insertions(+), 6 deletions(-)arch/arm/mach-omap2/powerdomain.c +11
-3@@ -854,6 +854,8 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) smp_processor_id());/* Program the pwrdm desired target state */ ret = arch_pwrdm->pwrdm_set_next_pwrst (pwrdm, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_PWRST , pwrst); }return ret;@@ -869,13 +871,19 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)*/ int pwrdm_read_next_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_NEXT_PWRST , &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst) { ret = arch_pwrdm->pwrdm_read_next_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_PWRST , ret); + }return ret; }@@ -906,13 +914,19 @@ int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm)*/ int pwrdm_read_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ;
arch/arm/mach-omap2/powerdomain.c int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm) · line 929
Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +7
-1-if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PWRST , &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst) { ret = arch_pwrdm->pwrdm_read_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_PWRST , ret); + }
Do we really want to use the cache for the current state? This is updated by hardware. In the above it appears that once we have read it once we will just return this value until the cache is invalidated. Makes me a little nervous.
Cheers
Jon
PATCH 2/5 ARM: OMAP2+: PM: use the power domains registers cache for the power states
On Tue, May 01, 2012 at 21:07:39, Hunter, Jon wrote:
[...]
Quoted 8 lines
Quoted 8 lines
int
pwrdm_read_pwrst(struct powerdomain *pwrdm)
{arch/arm/mach-omap2/powerdomain.c +1
-1-int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ;
Quoted 15 lines
arch/arm/mach-omap2/powerdomain.c int pwrdm_read_next_func_pwrst(struct powerdomain *pwrdm) · line 929
Quoted 9 lines
arch/arm/mach-omap2/powerdomain.c +7
-1-if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PWRST , &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst) { ret = arch_pwrdm->pwrdm_read_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_PWRST , ret); + }Do we really want to use the cache for the current state? This is updated by hardware. In the above it appears that once we have read it once we will just return this value until the cache is invalidated. Makes me a little nervous.
I echo the concern here. If a powerdomain transition occurs when h/w conditions are met, the cached values will go out of sync and this may lead to unexpected behavior wherever this API is being used.
As Jon pointed out in another patch, the registers which can be updated by h/w should be handled differently.
Just a wild thought, can PRCM_MPU_IRQ ([4]TRANSITION_EN) be used as a trigger to update the cache if the transition happened under s/w control?
Regards,
Vaibhav
PATCH 2/5 ARM: OMAP2+: PM: use the power domains registers cache for the power states
Hi Jon, Vaibhav,
Quoted 24 lines · Vaibhav
On Tue, May 01, 2012 at 21:07:39, Hunter, Jon wrote:
[...]Quoted 22 lines
Quoted 8 lines
?int
pwrdm_read_pwrst(struct powerdomain *pwrdm)
?{
- ? int ret =-EINVAL;
+ ? int pwrst, ret =-EINVAL;? ? if (!pwrdm)
? ? ? ? ? ? return-EINVAL;Quoted 9 lines
- ? if (
arch_pwrdm&&arch_pwrdm->pwrdm_read_pwrst)
+ ? if (!pwrdm_cache_read(pwrdm,PWRDM_CACHE_PWRST, &pwrst))
+ ? ? ? ? ? return pwrst;
+
+ ? if (arch_pwrdm&&arch_pwrdm->pwrdm_read_pwrst) {
? ? ? ? ? ? ret =arch_pwrdm->pwrdm_read_pwrst(pwrdm);
+ ? ? ? ? ? if (ret >= 0)
+ ? ? ? ? ? ? ? ? ?pwrdm_cache_write(pwrdm, PWRDM_CACHE_PWRST, ret);
+ ? }Do we really want to use the cache for the current state? This is updated by hardware. In the above it appears that once we have read it once we will just return this value until the cache is invalidated. Makes me a little nervous.
I agree with your concerns. The HW can update things in our back and so there is a risk of having the wrong state reported by the API. Ideally the registers accesses shall be optimized in the HW itself (hint for next gen chipsets ;-).
IMO a generic approach on caching is preferred on a hack on the low power code.
The cache implementation is based on the following principles:
1. the registers value are read from the cache if it is 'hot', the values are read from the registers if the cache has been invalidated
2. the coherency of the cache fields relies on the invalidate of the fields at the right time during the low power transitions
3. the previous states fields of the cache are invalidated when clearing the previous power states
4. the current states fields of the cache are invalidated after coming back from the low power mode, i.e. after the return from the low level WFI instruction
5. the pwrdm_state_switch function detects the states changes, updates the last internal state (pwrdm->state) and the states statistics
6. in PM debug any discrepancy between pwrdm->state and the current state from the API is reported. More checking could be added in PM debug
So there must be a compromise on which fields are invalidated and when. I first tried to invalidate the whole cache after every low power transition, which works fine but does not gain much in performance. The current invalidate scheme (points 3, 4) is optimized for performance and has been tested succesfully on OMAP3 (using cpuidle in RET and OFF).
In any case if the HW asynchronously changes the registers states it will not always be detected, with or without the cache implementation. For example if a power domain transitions more than once, only the last transition -to a different state than pwrdm->state- will be detected the next time pwrdm_state_switch runs.
Quoted 7 lines
I echo the concern here. If a powerdomain transition occurs when h/w conditions are met, the cached values will go out of sync and this may lead to unexpected behavior wherever this API is being used.
As Jon pointed out in another patch, the registers which can be updated by h/w should be handled differently.
Agree but if you do not cache the previous and current registers there is no point in having the cache in place.
Quoted 3 lines
Just a wild thought, can
PRCM_MPU_IRQ([4]TRANSITION_EN) be used as a trigger to update the cache if the transition happened under s/w control?
That is a nice suggestion. We need to explore the ways to detect transitions.
Quoted 3 lines
Regards,
Vaibhav
Thanks for your comments!
Regards,
Jean
PATCH 3/5 ARM: OMAP2+: PM: use the power domains registers cache for the logic and mem states
In reply to jean.pihet at newoldbits.comFrom: Jean Pihet <[email protected]>
Use the caching API for the previous, current and next power domains logical and memory states.
--- arch/arm/mach-omap2/powerdomain.c | 108 ++++++++++++++++++++++++++++--------- 1 files changed, 82 insertions(+), 26 deletions(-)
arch/arm/mach-omap2/powerdomain.c +82 -26
@@ -1011,11 +1011,15 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))return -EINVAL ; -pr_debug ("powerdomain: setting next logic powerstate for %s to %0x\n" , +pr_debug ("powerdomain: setting next logic RET state for %s to %0x\n" , pwrdm->name, pwrst); -if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst) +if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst) { ret = arch_pwrdm->pwrdm_set_logic_retst (pwrdm, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_LOGIC_RETST , + pwrst); + }return ret; }
@@ -1023,13 +1027,13 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)/** * pwrdm_set_mem_onst - set memory power state while powerdomain ON * @pwrdm: struct powerdomain * to set -* @bank: memory bank number to set (0-3) +* @bank: memory bank number to set (0-PWRDM_MAX_MEM_BANKS) * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* 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 +* state. @bank 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
@@ -1051,8 +1055,12 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)pr_debug ("powerdomain: setting next memory powerstate for domain %s " "bank %0x while pwrdm-ON to %0x\n" , pwrdm->name, bank, pwrst); -if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst) +if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst) { ret = arch_pwrdm->pwrdm_set_mem_onst (pwrdm, bank, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_MEM_ONST + bank, + pwrst); + }return ret; }
@@ -1060,13 +1068,13 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)/** * 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) +* @bank: memory bank number to set (0-PWRDM_MAX_MEM_BANKS) * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* 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 +* RETENTION state. Bank 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
@@ -1089,8 +1097,13 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)pr_debug ("powerdomain: setting next memory powerstate for domain %s " "bank %0x while pwrdm-RET to %0x\n" , pwrdm->name, bank, pwrst); -if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst) +if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst) { ret = arch_pwrdm->pwrdm_set_mem_retst (pwrdm, bank, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm, +PWRDM_CACHE_NEXT_MEM_RETST + bank, + pwrst); + }return ret; }
@@ -1106,13 +1119,19 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)*/ int pwrdm_read_logic_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int retst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_LOGIC_RETST , &retst)) +return retst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst) { ret = arch_pwrdm->pwrdm_read_logic_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_LOGIC_RETST , ret); + }return ret; }
@@ -1127,13 +1146,20 @@ int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)*/ int pwrdm_read_prev_logic_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int retst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PREV_LOGIC_PWRST , &retst)) +return retst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst) { ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_PREV_LOGIC_PWRST , + ret); + }return ret; }
@@ -1142,19 +1168,26 @@ int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)* 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 +* Return the powerdomain pwrdm's next 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 ; +int retst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_NEXT_LOGIC_RETST , &retst)) +return retst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst) { ret = arch_pwrdm->pwrdm_read_logic_retst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_LOGIC_RETST , + ret); + }return ret; }
@@ -1162,7 +1195,7 @@ int pwrdm_read_logic_retst(struct powerdomain *pwrdm)/** * 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) +* @bank: memory bank number (0-PWRDM_MAX_MEM_BANKS) * * Return the powerdomain @pwrdm's current memory power state for bank * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
@@ -1171,7 +1204,7 @@ int pwrdm_read_logic_retst(struct powerdomain *pwrdm)*/ int pwrdm_read_mem_pwrst (struct powerdomain *pwrdm,u8 bank) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return ret;
@@ -1182,8 +1215,15 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)if (pwrdm->flags &PWRDM_HAS_MPU_QUIRK ) bank =1 ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_MEM_PWRST + bank, &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst) { ret = arch_pwrdm->pwrdm_read_mem_pwrst (pwrdm, bank); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_MEM_PWRST + bank, + ret); + }return ret; }
@@ -1191,7 +1231,7 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)/** * 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) +* @bank: memory bank number (0-PWRDM_MAX_MEM_BANKS) * * Return the powerdomain @pwrdm's previous memory power state for * bank @bank. Returns -EINVAL if the powerdomain pointer is null,
@@ -1201,7 +1241,7 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)*/ int pwrdm_read_prev_mem_pwrst (struct powerdomain *pwrdm,u8 bank) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return ret;
@@ -1212,8 +1252,16 @@ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)if (pwrdm->flags &PWRDM_HAS_MPU_QUIRK ) bank =1 ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PREV_MEM_PWRST + bank, &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst) { ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst (pwrdm, bank); +if (ret >=0 ) +pwrdm_cache_write (pwrdm, +PWRDM_CACHE_PREV_MEM_PWRST + bank, + ret); + }return ret; }
@@ -1221,7 +1269,7 @@ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)/** * 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) +* @bank: memory bank number (0-PWRDM_MAX_MEM_BANKS) * * Return the powerdomain pwrdm's next memory power state for bank * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
@@ -1230,7 +1278,7 @@ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)*/ int pwrdm_read_mem_retst (struct powerdomain *pwrdm,u8 bank) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return ret;
@@ -1238,8 +1286,16 @@ int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)if (pwrdm->banks < (bank +1 ))return ret; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_NEXT_MEM_RETST + bank, &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst) { ret = arch_pwrdm->pwrdm_read_mem_retst (pwrdm, bank); +if (ret >=0 ) +pwrdm_cache_write (pwrdm, +PWRDM_CACHE_NEXT_MEM_RETST + bank, + ret); + }return ret; }
Signature · 1 line
1.7.7.6
PATCH 3/5 ARM: OMAP2+: PM: use the power domains registers cache for the logic and mem states
Hi Jean,
Quoted 127 lines · jean.pihet at newoldbits.com
From: Jean Pihet <[email protected]>
Use the caching API for the previous, current and next power domains logical and memory states.
Signed-off-by Jean Pihet <[email protected]>--- arch/arm/mach-omap2/powerdomain.c | 108 ++++++++++++++++++++++++++++--------- 1 files changed, 82 insertions(+), 26 deletions(-)arch/arm/mach-omap2/powerdomain.c +32
-13@@ -1011,11 +1011,15 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))return -EINVAL ; -pr_debug ("powerdomain: setting next logic powerstate for %s to %0x\n" , +pr_debug ("powerdomain: setting next logic RET state for %s to %0x\n" , pwrdm->name, pwrst); -if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst) +if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst) { ret = arch_pwrdm->pwrdm_set_logic_retst (pwrdm, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_LOGIC_RETST , + pwrst); + }return ret; }@@ -1023,13 +1027,13 @@ int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)/** * pwrdm_set_mem_onst - set memory power state while powerdomain ON * @pwrdm: struct powerdomain * to set -* @bank: memory bank number to set (0-3) +* @bank: memory bank number to set (0-PWRDM_MAX_MEM_BANKS) * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* 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 +* state. @bank 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 @@ -1051,8 +1055,12 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)pr_debug ("powerdomain: setting next memory powerstate for domain %s " "bank %0x while pwrdm-ON to %0x\n" , pwrdm->name, bank, pwrst); -if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst) +if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst) { ret = arch_pwrdm->pwrdm_set_mem_onst (pwrdm, bank, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_MEM_ONST + bank, + pwrst); + }return ret; }@@ -1060,13 +1068,13 @@ int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)/** * 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) +* @bank: memory bank number to set (0-PWRDM_MAX_MEM_BANKS) * @pwrst: one of the PWRDM_LOGIC_MEM_PWRST_* 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 +* RETENTION state. Bank 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 @@ -1089,8 +1097,13 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)pr_debug ("powerdomain: setting next memory powerstate for domain %s " "bank %0x while pwrdm-RET to %0x\n" , pwrdm->name, bank, pwrst); -if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst) +if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst) { ret = arch_pwrdm->pwrdm_set_mem_retst (pwrdm, bank, pwrst); +if (!ret) +pwrdm_cache_write (pwrdm, +PWRDM_CACHE_NEXT_MEM_RETST + bank, + pwrst); + }return ret; }@@ -1106,13 +1119,19 @@ int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)*/ int pwrdm_read_logic_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int retst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_LOGIC_RETST , &retst)) +return retst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst) { ret = arch_pwrdm->pwrdm_read_logic_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_LOGIC_RETST , ret); + }return ret; }@@ -1127,13 +1146,20 @@ int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)*/ int pwrdm_read_prev_logic_pwrst (struct powerdomain *pwrdm) { -int ret = -EINVAL ; +int retst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ;
arch/arm/mach-omap2/powerdomain.c int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) · line 1162
Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +8
-1-if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PREV_LOGIC_PWRST , &retst)) +return retst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst) { ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_PREV_LOGIC_PWRST , + ret); + }
Is it necessary to cache the previous state? I don't believe this read that often. In fact I am curious how often the cache value is read.
Quoted 90 lines
arch/arm/mach-omap2/powerdomain.c +22
-9return ret; }@@ -1142,19 +1168,26 @@ int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)* 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 +* Return the powerdomain pwrdm's next 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 ; +int retst, ret = -EINVAL ;if (!pwrdm)return -EINVAL ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_NEXT_LOGIC_RETST , &retst)) +return retst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst) { ret = arch_pwrdm->pwrdm_read_logic_retst (pwrdm); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_NEXT_LOGIC_RETST , + ret); + }return ret; }@@ -1162,7 +1195,7 @@ int pwrdm_read_logic_retst(struct powerdomain *pwrdm)/** * 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) +* @bank: memory bank number (0-PWRDM_MAX_MEM_BANKS) * * Return the powerdomain @pwrdm's current memory power state for bank * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if @@ -1171,7 +1204,7 @@ int pwrdm_read_logic_retst(struct powerdomain *pwrdm)*/ int pwrdm_read_mem_pwrst (struct powerdomain *pwrdm,u8 bank) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return ret;@@ -1182,8 +1215,15 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)if (pwrdm->flags &PWRDM_HAS_MPU_QUIRK ) bank =1 ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst) +if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_MEM_PWRST + bank, &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst) { ret = arch_pwrdm->pwrdm_read_mem_pwrst (pwrdm, bank); +if (ret >=0 ) +pwrdm_cache_write (pwrdm,PWRDM_CACHE_MEM_PWRST + bank, + ret); + }return ret; }@@ -1191,7 +1231,7 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)/** * 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) +* @bank: memory bank number (0-PWRDM_MAX_MEM_BANKS) * * Return the powerdomain @pwrdm's previous memory power state for * bank @bank. Returns -EINVAL if the powerdomain pointer is null, @@ -1201,7 +1241,7 @@ int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)*/ int pwrdm_read_prev_mem_pwrst (struct powerdomain *pwrdm,u8 bank) { -int ret = -EINVAL ; +int pwrst, ret = -EINVAL ;if (!pwrdm)return ret;@@ -1212,8 +1252,16 @@ int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)if (pwrdm->flags &PWRDM_HAS_MPU_QUIRK ) bank =1 ; -if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
arch/arm/mach-omap2/powerdomain.c int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank) · line 1264
Quoted 10 lines
arch/arm/mach-omap2/powerdomain.c +9
-0+if (!pwrdm_cache_read (pwrdm,PWRDM_CACHE_PREV_MEM_PWRST + bank, &pwrst)) +return pwrst; + +if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst) { ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst (pwrdm, bank); +if (ret >=0 ) +pwrdm_cache_write (pwrdm, +PWRDM_CACHE_PREV_MEM_PWRST + bank, + ret); + }
This field is also updated by hardware. Is this appropriate for the cache?
Cheers
Jon
PATCH 4/5 ARM: OMAP2+: PM: use the power domains registers cache invalidate API
In reply to jean.pihet at newoldbits.comFrom: Jean Pihet <[email protected]>
The power domains registers cache is partially invalidated when clearing the previous power states and after coming back from the low power mode, i.e. after the return from the low level WFI instruction.
Note: this invalidate use scheme is optimized for performance, the states returned by the state read functions might not reflect the real state if the power domains registers have not been changed using the API or have not been changed by the operating system (e.g. the ROM code in case of secure code execution).
--- arch/arm/mach-omap2/pm34xx.c | 6 ++++++ arch/arm/mach-omap2/powerdomain.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/pm34xx.c +6 -0
@@ -353,6 +353,12 @@ void omap_sram_idle(void)else omap34xx_do_sram_idle (save_state); +/* +* Invalidate the current states from the regs cache +* for all power domains +*/ +pwrdm_invalidate_regs_cache_fields_current (NULL ); +/* Restore normal SDRC POWER settings */ if (cpu_is_omap3430() && omap_rev() >= OMAP3430_REV_ES3_0 && (omap_type() == OMAP2_DEVICE_TYPE_EMU ||
arch/arm/mach-omap2/powerdomain.c +3 -1
@@ -1324,8 +1324,10 @@ int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)pr_debug ("powerdomain: clearing previous power state reg for %s\n" , pwrdm->name); -if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst) +if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst) { ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst (pwrdm); +pwrdm_invalidate_regs_cache_fields_prev (pwrdm); + }return ret; }
Signature · 1 line
1.7.7.6
PATCH 5/5 ARM: OMAP2+: PM debug: use the power domains registers caching API
In reply to jean.pihet at newoldbits.comFrom: Jean Pihet <[email protected]>
Use the caching API instead of using the internal pwrdm->state field for PM debug statistics display.
Note: some power domains states mismatch messages can be printed out with the power domains states statstics, indicating that the power domains are not controlled by any driver or that the invalidate API is not correctly used.
--- arch/arm/mach-omap2/pm-debug.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/pm-debug.c +9 -7
@@ -96,19 +96,20 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)static int pwrdm_dbg_show_counter (struct powerdomain *pwrdm,void *user) {struct seq_file *s = (struct seq_file *)user; -int i; +int i, pwrst;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_func_pwrst (pwrdm)) -printk (KERN_ERR "pwrdm state mismatch(%s) %d != %d\n" , - pwrdm->name, pwrdm->state,pwrdm_read_func_pwrst (pwrdm)); + pwrst =pwrdm_read_func_pwrst (pwrdm); +if (pwrdm->state != pwrst) +printk (KERN_ERR "pwrdm state mismatch(%s): last saved %d != current %d\n" , + pwrdm->name, pwrdm->state, pwrst);seq_printf (s,"%s (%s)" , pwrdm->name, - pwrdm_state_names[pwrdm->state]); + pwrdm_state_names[pwrst]);for (i =0 ; i <PWRDM_MAX_FUNC_PWRSTS ; i++)seq_printf (s,",%s:%d" , pwrdm_state_names[i], pwrdm->state_counter[i]);
@@ -126,7 +127,7 @@ static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)static int pwrdm_dbg_show_timer (struct powerdomain *pwrdm,void *user) {struct seq_file *s = (struct seq_file *)user; -int i; +int i, pwrst; if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
@@ -134,9 +135,10 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)return 0 ;pwrdm_state_switch (pwrdm); + pwrst =pwrdm_read_func_pwrst (pwrdm);seq_printf (s,"%s (%s)" , pwrdm->name, - pwrdm_state_names[pwrdm->state]); + pwrdm_state_names[pwrst]);for (i =0 ; i <PWRDM_MAX_FUNC_PWRSTS ; i++) seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
Signature · 1 line
1.7.7.6
cover ARM: OMAP2+: PM: implement a caching mechanism on the power domains state registers
In reply to jean.pihet at newoldbits.comHi Jean,
Quoted 18 lines · jean.pihet at newoldbits.com
From: Jean Pihet <[email protected]>
The OMAP3 PRCM registers accesses are known to be slow, with a PRCM register read taking up to 12-14us depending on the OPP.
This patch adds a caching mechanism on the power domains state registers. When the cache is cold or has been invalidated a register access is performed, otherwise the register value is retrieved from the registers cache.
The API is made of read and write functions for fields in the cache, as well as an invalidate and helper functions to invalidate parts of the cache contents (i.e. previous, current power states and all fields in the cache). The power domain code is converted to use the API to read and write the previous, current and next states for the power domains states, logical and memory states.
The PM debug code also uses the caching API instead of the internalpwrdm->statevariable.
Quoted 2 lines
Using the caching mechanism optimizes the performance of the system in the transitions to and from the low power states.
Looks interesting!
A couple high level questions for you ...
1. Do you intend to cache registers that are updated by hardware?
2. If yes to 1, should there be some "cache debug mode" we can enable to test the cache and registers are in sync for testing?
Cheers
Jon