Skip to content
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

Conversation

adamkondraciuk
Copy link
Contributor

No description provided.

* @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);
Copy link
Contributor

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.

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.
Copy link
Contributor

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:
Copy link
Contributor

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

Copy link
Member

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.

@@ -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
Copy link
Contributor

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.

Copy link
Contributor

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


void pm_s2ram_mark_set(void)
{
/* empty */
Copy link
Contributor

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()

bool unretained_wake;
bool restore_valid;

unretained_wake = nrf_resetinfo_resetreas_local_get(NRF_RESETINFO) &
Copy link
Contributor

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).

*/

if (ret == 0) {
z_pm_sys_resume();
Copy link
Contributor

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();

}

/* Function called during local domain suspend to RAM. */
int z_pm_sys_suspend(void)
Copy link
Contributor

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.

Copy link
Contributor

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

Comment on lines 16 to 28
#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
Copy link
Contributor

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.

Copy link
Contributor

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

Comment on lines 42 to 48
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);
Copy link
Contributor

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.

Copy link
Contributor

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

nordic-krch and others added 12 commits May 9, 2024 15:29
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>
Copy link
Contributor

@hubertmis hubertmis left a 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)
Copy link
Contributor

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,
Copy link
Contributor

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();
Copy link
Contributor

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);
Copy link
Contributor

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.

Comment on lines +92 to +93
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);
Copy link
Contributor

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) &
Copy link
Contributor

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.

Comment on lines +49 to +51
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);
Copy link
Contributor

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);
Copy link
Contributor

@hubertmis hubertmis May 17, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment