Skip to content

Commit f3c8bba

Browse files
committed
samples: soft off with entering from idle/s2ram
This is new method of entering system off state. Local domains do not shut down immediatelly but rather go to deep sleep (idle or s2ram) and waits for other domains to go to system off. This enable option to go back to normal operation if there is something blocking system off. For example application is not yet ready to soft off and wakes up radio. This also enables GRTC to be used with system methods like k_sleep to wake up from system off at scheduled time. Signed-off-by: Łukasz Stępnicki <[email protected]>
1 parent 9c00288 commit f3c8bba

File tree

7 files changed

+169
-13
lines changed

7 files changed

+169
-13
lines changed

samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
#
66

77
CONFIG_SOC_NRF54H20_CPURAD_ENABLE=y
8+
CONFIG_PM_S2RAM=y
9+
CONFIG_PM_S2RAM_CUSTOM_MARKING=y

samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,21 @@
22
zephyr,pm-device-runtime-auto;
33
disable-rx;
44
};
5+
6+
/ {
7+
cpus {
8+
power-states {
9+
soft_off: soft_off {
10+
compatible = "zephyr,power-state";
11+
power-state-name = "soft-off";
12+
min-residency-us = <0>;
13+
exit-latency-us = <0>;
14+
status = "disabled";
15+
};
16+
};
17+
};
18+
};
19+
20+
&cpuapp {
21+
cpu-power-states = <&idle_cache_disabled &s2ram &soft_off>;
22+
};
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
&uart135 {
2-
status = "disabled";
2+
status = "okay";
33
zephyr,pm-device-runtime-auto;
44
disable-rx;
55
};
6+
7+
/ {
8+
cpus {
9+
power-states {
10+
soft_off: soft_off {
11+
compatible = "zephyr,power-state";
12+
power-state-name = "soft-off";
13+
min-residency-us = <0>;
14+
exit-latency-us = <0>;
15+
status = "disabled";
16+
};
17+
};
18+
};
19+
};
20+
21+
&cpurad {
22+
cpu-power-states = <&idle_cache_disabled &soft_off>;
23+
};

samples/boards/nordic/system_off/remote/prj.conf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ CONFIG_PM_DEVICE=y
33
CONFIG_PM_DEVICE_RUNTIME=y
44
CONFIG_POWEROFF=y
55
CONFIG_UART_ASYNC_API=y
6-
CONFIG_SERIAL=n
7-
CONFIG_CONSOLE=n
8-
CONFIG_UART_CONSOLE=n
6+
CONFIG_SERIAL=y
7+
CONFIG_CONSOLE=y
8+
CONFIG_UART_CONSOLE=y

samples/boards/nordic/system_off/remote/src/main.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,31 @@
77
#include <zephyr/device.h>
88
#include <zephyr/pm/device.h>
99
#include <zephyr/pm/device_runtime.h>
10+
#include <zephyr/pm/pm.h>
1011
#include <zephyr/sys/poweroff.h>
11-
#include <hal/nrf_memconf.h>
1212
#include <zephyr/drivers/timer/nrf_grtc_timer.h>
1313

1414
int main(void)
1515
{
1616

1717
if (IS_ENABLED(CONFIG_CONSOLE)) {
18-
printf("%s system off demo. Ready for system off.\n", CONFIG_BOARD);
18+
printf("%s system off demo. Ready for system off.\n", CONFIG_BOARD_QUALIFIERS);
1919
}
2020

21-
sys_poweroff();
21+
if (IS_ENABLED(CONFIG_PM_DEVICE) && IS_ENABLED(CONFIG_SERIAL)) {
22+
static const struct device *cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
23+
int err;
24+
enum pm_device_state state;
25+
26+
if (cons) {
27+
do {
28+
err = pm_device_state_get(cons, &state);
29+
} while ((err == 0) && (state == PM_DEVICE_STATE_ACTIVE));
30+
}
31+
}
32+
33+
pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
34+
k_sleep(K_FOREVER);
2235

2336
return 0;
2437
}

samples/boards/nordic/system_off/src/main.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <zephyr/drivers/hwinfo.h>
1515
#include <zephyr/drivers/comparator.h>
1616
#include <zephyr/kernel.h>
17+
#include <zephyr/pm/pm.h>
1718
#include <zephyr/pm/device.h>
1819
#include <zephyr/sys/poweroff.h>
1920
#include <zephyr/sys/util.h>
@@ -83,7 +84,7 @@ int main(void)
8384
do_poweroff = false;
8485
}
8586

86-
printf("\n%s system off demo\n", CONFIG_BOARD);
87+
printf("\n%s system off demo\n", CONFIG_BOARD_QUALIFIERS);
8788
hwinfo_get_reset_cause(&reset_cause);
8889
rc = print_reset_cause(reset_cause);
8990

@@ -209,13 +210,19 @@ int main(void)
209210
nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, false);
210211
nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, false);
211212
#endif
212-
sys_poweroff();
213+
214+
while (1) {
215+
pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
216+
k_sleep(K_SECONDS(5));
217+
printk("Woke up from system off with current context, retrying...\n");
218+
}
213219
} else {
214220
k_sleep(K_FOREVER);
215221
}
216222

217223
hwinfo_clear_reset_cause();
218-
sys_poweroff();
224+
pm_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
225+
k_sleep(K_FOREVER);
219226

220227
return 0;
221228
}

soc/nordic/nrf54h/power.c

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@ void nrf_poweroff(void)
8383
#endif
8484
common_suspend();
8585

86-
/* Disable all owned compare channels except the one used for wakeup from system-off. */
87-
z_nrf_grtc_timer_disable_owned_cc_channels(z_nrf_grtc_timer_wakeup_channel_get());
88-
8986
/* Indicate that we are ready for system off. */
9087
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY);
9188

@@ -140,6 +137,34 @@ static void s2idle_exit(uint8_t substate_id)
140137
}
141138
}
142139

140+
#if defined(CONFIG_SOC_NRF54H20_CPURAD)
141+
142+
static void s2idle_ready_for_soft_off_enter(void)
143+
{
144+
#if !defined(CONFIG_SOC_NRF54H20_CPURAD)
145+
soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_MAIN);
146+
#endif
147+
common_suspend();
148+
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY);
149+
150+
__set_BASEPRI(0);
151+
__ISB();
152+
__DSB();
153+
__WFI();
154+
}
155+
156+
static void s2idle_ready_for_soft_off_exit(void)
157+
{
158+
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFNOTREADY);
159+
160+
nrf_power_up_cache();
161+
common_resume();
162+
#if !defined(CONFIG_SOC_NRF54H20_CPURAD)
163+
soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_MAIN);
164+
#endif
165+
}
166+
#endif
167+
143168
#if defined(CONFIG_PM_S2RAM)
144169
/* Resume domain after local suspend to RAM. */
145170
static void s2ram_exit(void)
@@ -151,6 +176,17 @@ static void s2ram_exit(void)
151176
#endif
152177
}
153178

179+
static void s2ram_ready_for_soft_off_exit(void)
180+
{
181+
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFNOTREADY);
182+
183+
common_resume();
184+
#if !defined(CONFIG_SOC_NRF54H20_CPURAD)
185+
/* Re-enable domain retention. */
186+
nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true);
187+
#endif
188+
}
189+
154190
/* Function called during local domain suspend to RAM. */
155191
static int sys_suspend_to_ram(void)
156192
{
@@ -178,6 +214,35 @@ static int sys_suspend_to_ram(void)
178214
return -EBUSY;
179215
}
180216

217+
/* Function called during local domain suspend to RAM with soft off readiness. */
218+
static int sys_suspend_to_ram_ready_for_soft_off(void)
219+
{
220+
/* Set intormation which is used on domain wakeup to determine if resume from RAM shall
221+
* be performed.
222+
*/
223+
nrf_resetinfo_resetreas_local_set(NRF_RESETINFO,
224+
NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK);
225+
nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true);
226+
227+
#if !defined(CONFIG_SOC_NRF54H20_CPURAD)
228+
/* Disable retention */
229+
nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false);
230+
#endif
231+
common_suspend();
232+
233+
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY);
234+
235+
__set_BASEPRI(0);
236+
__ISB();
237+
__DSB();
238+
__WFI();
239+
/*
240+
* We might reach this point is k_cpu_idle returns (there is a pre sleep hook that
241+
* can abort sleeping.
242+
*/
243+
return -EBUSY;
244+
}
245+
181246
static void s2ram_enter(void)
182247
{
183248
/*
@@ -188,6 +253,17 @@ static void s2ram_enter(void)
188253
return;
189254
}
190255
}
256+
257+
static void s2ram_ready_for_soft_off_enter(void)
258+
{
259+
/*
260+
* Save the CPU context (including the return address),set the SRAM
261+
* marker and power off the system.
262+
*/
263+
if (soc_s2ram_suspend(sys_suspend_to_ram_ready_for_soft_off)) {
264+
return;
265+
}
266+
}
191267
#endif /* defined(CONFIG_PM_S2RAM) */
192268

193269
void pm_state_set(enum pm_state state, uint8_t substate_id)
@@ -201,6 +277,17 @@ void pm_state_set(enum pm_state state, uint8_t substate_id)
201277
sys_trace_idle_exit();
202278
__enable_irq();
203279
}
280+
#if defined(CONFIG_SOC_NRF54H20_CPURAD) && defined(CONFIG_POWEROFF)
281+
else if (state == PM_STATE_SOFT_OFF) {
282+
__disable_irq();
283+
sys_trace_idle();
284+
s2idle_ready_for_soft_off_enter();
285+
/* On resuming or error we return exactly *HERE* */
286+
s2idle_ready_for_soft_off_exit();
287+
sys_trace_idle_exit();
288+
__enable_irq();
289+
}
290+
#endif
204291
#if defined(CONFIG_PM_S2RAM)
205292
else if (state == PM_STATE_SUSPEND_TO_RAM) {
206293
__disable_irq();
@@ -211,6 +298,17 @@ void pm_state_set(enum pm_state state, uint8_t substate_id)
211298
sys_trace_idle_exit();
212299
__enable_irq();
213300
}
301+
#if defined(CONFIG_POWEROFF)
302+
else if (state == PM_STATE_SOFT_OFF) {
303+
__disable_irq();
304+
sys_trace_idle();
305+
s2ram_ready_for_soft_off_enter();
306+
/* On resuming or error we return exactly *HERE* */
307+
s2ram_ready_for_soft_off_exit();
308+
sys_trace_idle_exit();
309+
__enable_irq();
310+
}
311+
#endif
214312
#endif
215313
else {
216314
k_cpu_idle();

0 commit comments

Comments
 (0)