-
Notifications
You must be signed in to change notification settings - Fork 644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce pm config #1666
Introduce pm config #1666
Conversation
dc6053e
to
9c947e2
Compare
* @retval true if marking is found which indicates resuming after suspend-to-RAM. | ||
* @retval false if marking is not found which indicates standard boot. | ||
*/ | ||
bool pm_s2ram_mark_check_and_clear(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function documentation should describe if this function is called before or after RAMs are initialized. I would indicate if it is safe to use local variables inside.
subsys/pm/Kconfig
Outdated
depends on PM_S2RAM | ||
help | ||
By default a magic word in RAM is used to mark entering suspend-to-RAM. Enabling | ||
this option allows custom implementation of functions which handles the marking. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of functions which handle the marking.
@@ -10,3 +10,8 @@ include: base.yaml | |||
properties: | |||
reg: | |||
required: true | |||
|
|||
arm,num-mpu-regions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we should revert zephyrproject-rtos/zephyr#60780 upstream instead of creating a noup
commit. @gmarull, please have a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what we should avoid is to disalign with upstream, all this code should be developed upstream-first.
soc/arm/nordic_nrf/common/poweroff.c
Outdated
@@ -6,6 +6,7 @@ | |||
#include <zephyr/sys/poweroff.h> | |||
#include <zephyr/toolchain.h> | |||
|
|||
#if !defined(CONFIG_SOC_SERIES_NRF54HX) | |||
#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) | |||
#include <hal/nrf_power.h> | |||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this should be #elif defined (CONFIG_SOC_SERIES_NRF53...)
instead of #if !defined(NRF54H)
above.
soc/arm/nordic_nrf/nrf54h/poweroff.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the path, because this will apply to other SoCs from the family. Not only nRF54H
soc/arm/nordic_nrf/nrf54h/poweroff.c
Outdated
|
||
void pm_s2ram_mark_set(void) | ||
{ | ||
/* empty */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a comment that this mark is set by nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true);
in z_pm_sys_suspend()
soc/arm/nordic_nrf/nrf54h/poweroff.c
Outdated
bool unretained_wake; | ||
bool restore_valid; | ||
|
||
unretained_wake = nrf_resetinfo_resetreas_local_get(NRF_RESETINFO) & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check other reset reasons. If other reset reasons than unretained are set, this function must return false. (until suspend-to-ram ready fo systemoff is implemented - wake up from this sleep state will require more complex condition).
soc/arm/nordic_nrf/nrf54h/poweroff.c
Outdated
*/ | ||
|
||
if (ret == 0) { | ||
z_pm_sys_resume(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
z_pm_sys_resume must be executed even if pm_s2ram_suspend() returns an error. E.g. if there was a pending IRQ and WFI was NOP-ed and pm_s2ram_suspend() returns -EBUSY, the caches must be reinitialized afterwards with z_pm_sys_resume();
soc/arm/nordic_nrf/nrf54h/poweroff.c
Outdated
} | ||
|
||
/* Function called during local domain suspend to RAM. */ | ||
int z_pm_sys_suspend(void) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rename this and similar functions to clearly indicate they are about suspend_to_ram
not about suspend to idle or suspend to disk.
arch/arm/core/cortex_m/pm_s2ram.c
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a generic Zepyr code. I would consider upstreaming. @gmarull , FYI
soc/arm/nordic_nrf/nrf54h/poweroff.c
Outdated
#if defined(NRF_APPLICATION) | ||
#define RAMBLOCK_CONTROL_BIT_ICACHE 1 | ||
#define RAMBLOCK_CONTROL_BIT_DCACHE 2 | ||
#define RAMBLOCK_POWER_ID 0 | ||
#define RAMBLOCK_CONTROL_OFF 0 | ||
#elif defined(NRF_RADIOCORE) | ||
#define RAMBLOCK_CONTROL_BIT_ICACHE 2 | ||
#define RAMBLOCK_CONTROL_BIT_DCACHE 3 | ||
#define RAMBLOCK_POWER_ID 0 | ||
#define RAMBLOCK_CONTROL_OFF 0 | ||
#else | ||
#error "Unsupported domain." | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we could make it possible to support other cores than app or radio instead of triggering a compile time error? I.e. making these values configurable outside this C file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One idea: how about wrapping this with #ifndef RAMBLOCK_CONTROL_BIT_ICACHE
and pass the values through a build system
soc/arm/nordic_nrf/nrf54h/soc.c
Outdated
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); | ||
#if defined(CONFIG_HW_REVISION_SOC1) | ||
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); | ||
#endif | ||
|
||
nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); | ||
nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code should be moved to z_arm_on_enter_cpu_idle_prepare()
and accompanied by DCACHE handling (for now write-back of caches should be enough).
Also, a z_arm_on_exit_cpu_idle()
function should be added that would be responsible for restoring LRCCONF configuration to the reset values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For caches write-back in z_arm_on_enter_cpu_idle_prepare()
to be bullet-proof, the function must be called after
sdk-zephyr/arch/arm/core/cortex_m/cpu_idle.S
Line 113 in 99187c8
cpsid i |
9c947e2
to
933192d
Compare
Remove CONFIG_NRF_ENABLE_ICACHE as it is not needed. There is CONFIG_ICACHE which is by default enabled for nrf54h. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit cfa6e25)
Add initialization of the data cache. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit d82b27b)
Add nrf_cache_lineaddr_get to nordic HAL. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit 29a4bb6)
nrf54h20 has a bug that requires to manually set 28th bit in the line address. 28th bit indicates secure memory space. Add handling to the cache driver. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit 73d4f58)
Driver was disabling cache before full range operations and that was causing hanging on polling for cache busy status since state was never changing (because cache was disabled). Additionally, added flushing to data cache disabling. If flushing is not performed then execution fails since data in cache is lost. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit b83a112)
Apply changes which significantly speed up cache operations. Removed k_busy_wait from function which polls for cache busyness. Removed spinlock from cache operation. Lock taking and releasing takes time and it is faster to check if LINEADDR changed after performing the operation. If LINEADDR changed then it indicates that current context was preempted by another cache operation. If such state is detected current operation is repeated. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit 9f6567b)
Use Kconfig instead of fixed value in the driver code. Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> (cherry picked from commit 4e880e6)
s2ram procedure used RAM magic word for marking suspend-to-RAM. This method may not work in some cases, e.g. when global reset does not reset RAM content. In that case resuming from s2ram is detected when global reset occurred. RAM magic word method is the default but with CONFIG_PM_S2RAM_CUSTOM_MARKING a custom implementation can be provided. Upstream PR: zephyrproject-rtos/zephyr#68860 Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no> Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
Add mpu node to cpu in haltium ARM cores. Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
Add functions for local domain suspend to RAM. Add matching resume procedure. Add pm_s2ram function for determining source of reset. Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
Add preserving NVIC and MPU state in retained RAM when CPU is powered off during S2RAM procedure. Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
Currently function `z_nrf_grtc_wakeup_prepare()` should be available only for the entity which is starting the peripheral. Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
933192d
to
af63f91
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I marked multiple remarks that require attention. However, they can be fixed in the future PRs. For now, this PR should allow moving forward in the task force.
@@ -6,6 +6,7 @@ | |||
#include <zephyr/sys/poweroff.h> | |||
#include <zephyr/toolchain.h> | |||
|
|||
#if !defined(CONFIG_SOC_SERIES_NRF54HX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This #if
shows that this file is not "common" for Nordic SoCs, so it should be moved to another directory than soc/nordic/common.
/* Flush, disable and power down DCACHE */ | ||
sys_cache_data_flush_all(); | ||
sys_cache_data_disable(); | ||
nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A little updated procedure is described in this PR: https://github.com/nrfconnect/doc-internal/pull/93
nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); | ||
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); | ||
|
||
k_cpu_idle(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k_cpu_idle()
should not be called from s2ram functions. k_cpu_idle()
should contain some boilerplate around caches to safely suspend the CPU.
nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); | ||
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); | ||
|
||
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This task must be triggered after suspend_common()
because of the timing (there is a timeout in System Controller).
After suspend_common()
this function must call WFI
. The code after WFI
is reachable in some scenarios, so CODE_UNREACHABLE;
below is invalid.
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); | ||
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The domains shall not be forced on here. I guess this is a workaround for the incomplete k_cpu_idle()
implementation for nRF54H. I would at least add a TODO comment here, because when k_cpu_idle()
will be implemented, we'll encounter surprises like unexpected forcing power domains ON.
bool unretained_wake; | ||
bool restore_valid; | ||
|
||
unretained_wake = nrf_resetinfo_resetreas_local_get(NRF_RESETINFO) & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code shall check if any other reset reasons are set in the RESETINFO. If they are, the function shall return false
.
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, | ||
!IS_ENABLED(CONFIG_HALTIUM_CPURAD)); | ||
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code shall be moved around k_cpu_idle()
implementation.
* Save the CPU context (including the return address),set the SRAM | ||
* marker and power off the system. | ||
*/ | ||
(void)pm_s2ram_suspend(z_pm_sys_suspend); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this function should be called with IRQs disabled (wrapped with __disable_irq()
- __enable_irq()
).
If IRQs are enabled, we risk a race condition: after the NVIC or MPU state is saved in RAM, ZLI is triggered, resulting in a change in NVIC or MPU. When ZLI ends, this function resumes execution storing CPU registers, configuring LRCCONF, etc. When the CPU wakes up and restores NVIC and MPU, it restores incorrect values, saved before ZLI was triggered.
If IRQs are disabled, ZLI wouldn't be handled until we exit this function, WFI
would result in NOP
, so the system state would be coherent.
Or maybe disabling and enabling IRQs should be inside the implementation of this function? Anyway, it should be clearly documented in API docs.
No description provided.