From a81e33b4ae4a397ee5f679bf3a2152d31df3ef3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 5 Sep 2024 13:04:28 +0200 Subject: [PATCH 1/3] samples: boards: nrf: system_off: Add nrf54h20 support --- drivers/timer/nrf_grtc_timer.c | 88 ++++++++++++++++++- .../boards/nordic/system_off/Kconfig.sysbuild | 9 ++ .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 7 ++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 3 + samples/boards/nordic/system_off/prj.conf | 4 + .../nordic/system_off/remote/CMakeLists.txt | 8 ++ .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 4 + .../boards/nordic/system_off/remote/prj.conf | 8 ++ .../nordic/system_off/remote/src/main.c | 36 ++++++++ samples/boards/nordic/system_off/src/main.c | 63 +++++++++++-- .../boards/nordic/system_off/sysbuild.cmake | 22 +++++ soc/nordic/nrf54h/power.c | 7 +- soc/nordic/nrf54h/soc.c | 11 +++ 13 files changed, 263 insertions(+), 7 deletions(-) create mode 100644 samples/boards/nordic/system_off/Kconfig.sysbuild create mode 100644 samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.conf create mode 100644 samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 samples/boards/nordic/system_off/remote/CMakeLists.txt create mode 100644 samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay create mode 100644 samples/boards/nordic/system_off/remote/prj.conf create mode 100644 samples/boards/nordic/system_off/remote/src/main.c create mode 100644 samples/boards/nordic/system_off/sysbuild.cmake diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c index 75278e104bd..fc952ef5808 100644 --- a/drivers/timer/nrf_grtc_timer.c +++ b/drivers/timer/nrf_grtc_timer.c @@ -368,7 +368,8 @@ uint64_t z_nrf_grtc_timer_startup_value_get(void) return grtc_start_value; } -#if defined(CONFIG_POWEROFF) && defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) +#if defined(CONFIG_POWEROFF) +#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) { nrfx_err_t err_code; @@ -430,6 +431,91 @@ int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) k_spin_unlock(&lock, key); return 0; } +#else +int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) +{ + //nrfx_err_t err_code; + //static uint8_t systemoff_channel; + //uint64_t now = counter(); + //nrfx_grtc_sleep_config_t sleep_cfg; + /* Minimum time that ensures valid execution of system-off procedure. */ + //uint32_t minimum_latency_us; + uint32_t chan; + //int ret; + + // nrfx_grtc_sleep_configuration_get(&sleep_cfg); + // minimum_latency_us = + // (sleep_cfg.waketime + sleep_cfg.timeout) * USEC_PER_SEC / LFCLK_FREQUENCY_HZ + + // CONFIG_NRF_GRTC_SYSCOUNTER_SLEEP_MINIMUM_LATENCY; + // sleep_cfg.auto_mode = false; + // nrfx_grtc_sleep_configure(&sleep_cfg); + + // if (minimum_latency_us > wake_time_us) { + // return -EINVAL; + // } + + //k_spinlock_key_t key = k_spin_lock(&lock); + + // err_code = nrfx_grtc_channel_alloc(&systemoff_channel); + // if (err_code != NRFX_SUCCESS) { + // k_spin_unlock(&lock, key); + // return -ENOMEM; + // } + //(void)nrfx_grtc_syscounter_cc_int_disable(systemoff_channel); + // ret = compare_set(systemoff_channel, + // now + wake_time_us * sys_clock_hw_cycles_per_sec() / USEC_PER_SEC, NULL, + // NULL); + // if (ret < 0) { + // k_spin_unlock(&lock, key); + // return ret; + // } + // for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { + /* Clear all GRTC channels except the systemoff_channel. */ + chan = u32_count_trailing_zeros(grtc_chan_mask); + // if (chan != systemoff_channel) { + nrfx_grtc_syscounter_cc_disable(chan); + //} + } +#if 0 +#if defined(CONFIG_SOC_NRF54H20_CPUAPP) + for (uint32_t grtc_chan_mask = 0x70; + grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { + /* Clear all GRTC channels except the systemoff_channel. */ + chan = u32_count_trailing_zeros(grtc_chan_mask); + // if (chan != systemoff_channel) { + nrfx_grtc_syscounter_cc_disable(chan); + // } + } +#endif +#if defined(CONFIG_SOC_NRF54H20_CPURAD) + //for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + for (uint32_t grtc_chan_mask = 0xFF80; + grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { + /* Clear all GRTC channels except the systemoff_channel. */ + chan = u32_count_trailing_zeros(grtc_chan_mask); + //if (chan != systemoff_channel) { + nrfx_grtc_syscounter_cc_disable(chan); + //} + } +#endif +#endif + // /* Make sure that wake_time_us was not triggered yet. */ + // if (nrfx_grtc_syscounter_compare_event_check(systemoff_channel)) { + // k_spin_unlock(&lock, key); + // return -EINVAL; + // } + + // /* This mechanism ensures that stored CC value is latched. */ + //uint32_t wait_time = + // nrfy_grtc_timeout_get(NRF_GRTC) * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 32768 + + // MAX_CC_LATCH_WAIT_TIME_US; + k_busy_wait(1000); + // k_spin_unlock(&lock, key); + return 0; +} +#endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ #endif /* CONFIG_POWEROFF */ uint32_t sys_clock_cycle_get_32(void) diff --git a/samples/boards/nordic/system_off/Kconfig.sysbuild b/samples/boards/nordic/system_off/Kconfig.sysbuild new file mode 100644 index 00000000000..f7d3e94e3e5 --- /dev/null +++ b/samples/boards/nordic/system_off/Kconfig.sysbuild @@ -0,0 +1,9 @@ +# Copyright 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config REMOTE_CORE_BOARD +string + default "nrf54h20dk/nrf54h20/cpurad" if $(BOARD) = "nrf54h20dk" diff --git a/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..cc10b7737d1 --- /dev/null +++ b/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_SOC_NRF54H20_CPURAD_ENABLE=y diff --git a/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..2668d53b0f0 --- /dev/null +++ b/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,3 @@ +&uart135 { + zephyr,pm-device-runtime-auto; +}; diff --git a/samples/boards/nordic/system_off/prj.conf b/samples/boards/nordic/system_off/prj.conf index 04450d5a22d..2fa5e8b6a2c 100644 --- a/samples/boards/nordic/system_off/prj.conf +++ b/samples/boards/nordic/system_off/prj.conf @@ -1,5 +1,9 @@ +CONFIG_PM=y CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_UART_ASYNC_API=y CONFIG_GPIO=y +CONFIG_NRF_REGTOOL_VERBOSITY=2 CONFIG_CRC=y CONFIG_POWEROFF=y CONFIG_HWINFO=y diff --git a/samples/boards/nordic/system_off/remote/CMakeLists.txt b/samples/boards/nordic/system_off/remote/CMakeLists.txt new file mode 100644 index 00000000000..6bcf49327d1 --- /dev/null +++ b/samples/boards/nordic/system_off/remote/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(nrf_system_off_remote) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay new file mode 100644 index 00000000000..c3b96611443 --- /dev/null +++ b/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -0,0 +1,4 @@ +&uart135 { + status = "disabled"; + zephyr,pm-device-runtime-auto; +}; diff --git a/samples/boards/nordic/system_off/remote/prj.conf b/samples/boards/nordic/system_off/remote/prj.conf new file mode 100644 index 00000000000..0e338826c4d --- /dev/null +++ b/samples/boards/nordic/system_off/remote/prj.conf @@ -0,0 +1,8 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_POWEROFF=y +CONFIG_UART_ASYNC_API=y +CONFIG_SERIAL=n +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n diff --git a/samples/boards/nordic/system_off/remote/src/main.c b/samples/boards/nordic/system_off/remote/src/main.c new file mode 100644 index 00000000000..3541c950211 --- /dev/null +++ b/samples/boards/nordic/system_off/remote/src/main.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + + + if (IS_ENABLED(CONFIG_CONSOLE)) { + printf("%s system off demo. Ready for system off.\n", CONFIG_BOARD); + } + + z_nrf_grtc_wakeup_prepare(1000); + + if (0) { + /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, false);*/ + /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, false);*/ + k_sleep(K_FOREVER); + } else { + /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, false);*/ + /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, false);*/ + + sys_poweroff(); + } + + return 0; +} diff --git a/samples/boards/nordic/system_off/src/main.c b/samples/boards/nordic/system_off/src/main.c index b4c2eeb2b1b..85387cd4265 100644 --- a/samples/boards/nordic/system_off/src/main.c +++ b/samples/boards/nordic/system_off/src/main.c @@ -19,6 +19,9 @@ #include #define NON_WAKEUP_RESET_REASON (RESET_PIN | RESET_SOFTWARE | RESET_POR | RESET_DEBUG) +#include +#include +#include #if defined(CONFIG_GRTC_WAKEUP_ENABLE) #include @@ -31,12 +34,15 @@ static const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios); static const struct device *comp_dev = DEVICE_DT_GET(DT_NODELABEL(comp)); #endif +static const struct gpio_dt_spec sw1 = GPIO_DT_SPEC_GET(DT_ALIAS(sw1), gpios); +static const uint32_t port_sw1 = DT_PROP(DT_GPIO_CTLR_BY_IDX(DT_ALIAS(sw1), gpios, 0), port); + int print_reset_cause(uint32_t reset_cause) { int32_t ret; uint32_t supported; - ret = hwinfo_get_supported_reset_cause((uint32_t *) &supported); + ret = hwinfo_get_supported_reset_cause((uint32_t *)&supported); if (ret || !(reset_cause & supported)) { return -ENOTSUP; @@ -60,16 +66,33 @@ int main(void) int rc; uint32_t reset_cause; const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + uint32_t nrf_pin_sw1 = 32 * port_sw1 + sw1.pin; + bool do_poweroff = true; if (!device_is_ready(cons)) { printf("%s: device not ready.\n", cons->name); return 0; } + /* TODO: this is always set and locks entering power off after gpio wakeup */ + // if (nrf_gpio_pin_latch_get(nrf_pin_sw1)) { + // nrf_gpio_pin_latch_clear(nrf_pin_sw1); + // do_poweroff = false; + // } + printf("\n%s system off demo\n", CONFIG_BOARD); hwinfo_get_reset_cause(&reset_cause); rc = print_reset_cause(reset_cause); +#if defined(CONFIG_SOC_NRF54H20_CPUAPP) +/* Temporary set gpio default if sense is set, prevent 300uA additional current after wakeup */ + for (int i = 0; i < 12; i++) { + if (nrf_gpio_pin_sense_get(i) != GPIO_PIN_CNF_SENSE_Disabled) { + nrf_gpio_cfg_default(i); + } + } +#endif + if (rc < 0) { printf("Reset cause not supported.\n"); return 0; @@ -97,13 +120,16 @@ int main(void) printf("Retained data not supported\n"); } + + k_sleep(K_MSEC(4000)); + #if defined(CONFIG_GRTC_WAKEUP_ENABLE) int err = z_nrf_grtc_wakeup_prepare(DEEP_SLEEP_TIME_S * USEC_PER_SEC); if (err < 0) { - printk("Unable to prepare GRTC as a wake up source (err = %d).\n", err); + printf("Unable to prepare GRTC as a wake up source (err = %d).\n", err); } else { - printk("Entering system off; wait %u seconds to restart\n", DEEP_SLEEP_TIME_S); + printf("Entering system off; wait %u seconds to restart\n", DEEP_SLEEP_TIME_S); } #endif #if defined(CONFIG_GPIO_WAKEUP_ENABLE) @@ -119,14 +145,29 @@ int main(void) printf("Could not configure sw0 GPIO interrupt (%d)\n", rc); return 0; } - - printf("Entering system off; press sw0 to restart\n"); #endif #if defined(CONFIG_LPCOMP_WAKEUP_ENABLE) comparator_set_trigger(comp_dev, COMPARATOR_TRIGGER_BOTH_EDGES); comparator_trigger_is_pending(comp_dev); printf("Entering system off; change signal level at comparator input to restart\n"); #endif + rc = gpio_pin_configure_dt(&sw1, GPIO_INPUT); + if (rc < 0) { + printf("Could not configure sw1 GPIO (%d)\n", rc); + return 0; + } + + rc = gpio_pin_interrupt_configure_dt(&sw1, GPIO_INT_LEVEL_ACTIVE); + if (rc < 0) { + printf("Could not configure sw0 GPIO interrupt (%d)\n", rc); + return 0; + } + + if (do_poweroff) { + printf("Entering system off; press sw0 or sw1 to restart\n"); + } else { + printf("Button sw1 pressed, not entering system off\n"); + } rc = pm_device_action_run(cons, PM_DEVICE_ACTION_SUSPEND); if (rc < 0) { @@ -140,6 +181,18 @@ int main(void) retained_update(); } + + if (do_poweroff) { +#if CONFIG_SOC_NRF54H20_CPUAPP + /* Local RAM0 (TCM) is currently not used so retention can be disabled. */ + nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, false); + nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, false); +#endif + sys_poweroff(); + } else { + k_sleep(K_FOREVER); + } + hwinfo_clear_reset_cause(); sys_poweroff(); diff --git a/samples/boards/nordic/system_off/sysbuild.cmake b/samples/boards/nordic/system_off/sysbuild.cmake new file mode 100644 index 00000000000..f22cab97904 --- /dev/null +++ b/samples/boards/nordic/system_off/sysbuild.cmake @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_REMOTE_CORE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +set(REMOTE_APP remote) + +ExternalZephyrProject_Add( + APPLICATION ${REMOTE_APP} + SOURCE_DIR ${APP_DIR}/${REMOTE_APP} + BOARD ${SB_CONFIG_REMOTE_CORE_BOARD} +) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} ${REMOTE_APP}) diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index e1263be0d0e..8189313a8bd 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -70,7 +70,12 @@ void nrf_poweroff(void) nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, 0); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, false); -#if !defined(CONFIG_SOC_NRF54H20_CPURAD) +#if defined(CONFIG_SOC_NRF54H20_CPURAD) + nrf_lrcconf_retain_set(NRF_LRCCONF010, + NRF_LRCCONF_POWER_DOMAIN_0 | NRF_LRCCONF_POWER_DOMAIN_1, false); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, + NRF_LRCCONF_POWER_DOMAIN_0 | NRF_LRCCONF_POWER_DOMAIN_1, false); +#else /* Disable retention */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index c996bc93e1b..e026f36c63c 100644 --- a/soc/nordic/nrf54h/soc.c +++ b/soc/nordic/nrf54h/soc.c @@ -148,7 +148,18 @@ void soc_early_init_hook(void) { int err; + if (IS_ENABLED(CONFIG_ICACHE)) { + nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, + RAMBLOCK_CONTROL_BIT_ICACHE, true); + } + sys_cache_instr_enable(); + + if (IS_ENABLED(CONFIG_DCACHE)) { + nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, + RAMBLOCK_CONTROL_BIT_DCACHE, true); + } + sys_cache_data_enable(); power_domain_init(); From 87abca1d488a8e45a2fae35fa4e931243f09f195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20St=C4=99pnicki?= Date: Tue, 7 Oct 2025 13:12:43 +0200 Subject: [PATCH 2/3] drivers: grtc timer added support for system off for nrf54h20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added option to use system channel for setup wakeup from soft off. In Lilium there is insuficcient grtc channels and no spare channel that can be used as wake up source. Added function to disable all grtc channels, except the one used for wake up to be able to enter soft off stated on local domain (disable uncexpected grtc wake ups). Signed-off-by: Łukasz Stępnicki --- drivers/timer/Kconfig.nrf_grtc | 7 + drivers/timer/nrf_grtc_timer.c | 152 ++++++------------ include/zephyr/drivers/timer/nrf_grtc_timer.h | 18 +++ soc/nordic/nrf54h/power.c | 5 + 4 files changed, 79 insertions(+), 103 deletions(-) diff --git a/drivers/timer/Kconfig.nrf_grtc b/drivers/timer/Kconfig.nrf_grtc index 082c15333dc..0daee3e4374 100644 --- a/drivers/timer/Kconfig.nrf_grtc +++ b/drivers/timer/Kconfig.nrf_grtc @@ -56,4 +56,11 @@ config NRF_GRTC_TIMER_AUTO_KEEP_ALIVE This feature prevents the SYSCOUNTER from sleeping when any core is in active state. +config NRF_GRTC_TIMER_USE_SYSTEM_CHANNEL_TO_WAKEUP_FROM_SYSTEMOFF + bool + depends on POWEROFF + default y if SOC_NRF54H20 + help + Use system channel to schedule wake up time. + endif # NRF_GRTC_TIMER diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c index fc952ef5808..3b69085ece3 100644 --- a/drivers/timer/nrf_grtc_timer.c +++ b/drivers/timer/nrf_grtc_timer.c @@ -369,17 +369,40 @@ uint64_t z_nrf_grtc_timer_startup_value_get(void) } #if defined(CONFIG_POWEROFF) -#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) +static int32_t wakeup_channel = -1; + +int32_t z_nrf_grtc_timer_wakeup_channel_get(void) +{ + return wakeup_channel; +} + +void z_nrf_grtc_timer_disable_owned_cc_channels(int32_t reserved_channel) +{ + uint32_t chan; + + k_spinlock_key_t key = k_spin_lock(&lock); + + for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { + /* Clear all GRTC channels except the reserved_channel. */ + chan = u32_count_trailing_zeros(grtc_chan_mask); + if (chan != reserved_channel) { + nrfx_grtc_syscounter_cc_disable(chan); + } + } + k_spin_unlock(&lock, key); +} + int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) { - nrfx_err_t err_code; static uint8_t systemoff_channel; uint64_t now = counter(); - nrfx_grtc_sleep_config_t sleep_cfg; + int ret; /* Minimum time that ensures valid execution of system-off procedure. */ uint32_t minimum_latency_us; - uint32_t chan; - int ret; + +#if CONFIG_NRF_GRTC_START_SYSCOUNTER + nrfx_grtc_sleep_config_t sleep_cfg; nrfx_grtc_sleep_configuration_get(&sleep_cfg); minimum_latency_us = (sleep_cfg.waketime + sleep_cfg.timeout) * @@ -388,34 +411,34 @@ int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) sleep_cfg.auto_mode = false; nrfx_grtc_sleep_configure(&sleep_cfg); +#else + minimum_latency_us = CONFIG_NRF_GRTC_SYSCOUNTER_SLEEP_MINIMUM_LATENCY; +#endif if (minimum_latency_us > wake_time_us) { return -EINVAL; } k_spinlock_key_t key = k_spin_lock(&lock); - err_code = nrfx_grtc_channel_alloc(&systemoff_channel); +#if CONFIG_NRF_GRTC_TIMER_USE_SYSTEM_CHANNEL_TO_WAKEUP_FROM_SYSTEMOFF + systemoff_channel = system_clock_channel_data.channel; +#else + nrfx_err_t err_code = nrfx_grtc_channel_alloc(&systemoff_channel); if (err_code != NRFX_SUCCESS) { k_spin_unlock(&lock, key); return -ENOMEM; } - (void)nrfx_grtc_syscounter_cc_int_disable(systemoff_channel); - ret = compare_set(systemoff_channel, - now + wake_time_us * sys_clock_hw_cycles_per_sec() / USEC_PER_SEC, NULL, - NULL); +#endif + (void) nrfx_grtc_syscounter_cc_int_disable(systemoff_channel); + int64_t delay = now + wake_time_us * sys_clock_hw_cycles_per_sec() / USEC_PER_SEC; + + ret = compare_set(systemoff_channel, delay, NULL, NULL); if (ret < 0) { k_spin_unlock(&lock, key); return ret; } - for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; - grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { - /* Clear all GRTC channels except the systemoff_channel. */ - chan = u32_count_trailing_zeros(grtc_chan_mask); - if (chan != systemoff_channel) { - nrfx_grtc_syscounter_cc_disable(chan); - } - } + z_nrf_grtc_timer_disable_owned_cc_channels(systemoff_channel); /* Make sure that wake_time_us was not triggered yet. */ if (nrfx_grtc_syscounter_compare_event_check(systemoff_channel)) { @@ -424,98 +447,21 @@ int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) } /* This mechanism ensures that stored CC value is latched. */ +#if CONFIG_NRF_GRTC_START_SYSCOUNTER uint32_t wait_time = nrfy_grtc_timeout_get(NRF_GRTC) * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / LFCLK_FREQUENCY_HZ + MAX_CC_LATCH_WAIT_TIME_US; - k_busy_wait(wait_time); - k_spin_unlock(&lock, key); - return 0; -} #else -int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) -{ - //nrfx_err_t err_code; - //static uint8_t systemoff_channel; - //uint64_t now = counter(); - //nrfx_grtc_sleep_config_t sleep_cfg; - /* Minimum time that ensures valid execution of system-off procedure. */ - //uint32_t minimum_latency_us; - uint32_t chan; - //int ret; - - // nrfx_grtc_sleep_configuration_get(&sleep_cfg); - // minimum_latency_us = - // (sleep_cfg.waketime + sleep_cfg.timeout) * USEC_PER_SEC / LFCLK_FREQUENCY_HZ + - // CONFIG_NRF_GRTC_SYSCOUNTER_SLEEP_MINIMUM_LATENCY; - // sleep_cfg.auto_mode = false; - // nrfx_grtc_sleep_configure(&sleep_cfg); - - // if (minimum_latency_us > wake_time_us) { - // return -EINVAL; - // } - - //k_spinlock_key_t key = k_spin_lock(&lock); - - // err_code = nrfx_grtc_channel_alloc(&systemoff_channel); - // if (err_code != NRFX_SUCCESS) { - // k_spin_unlock(&lock, key); - // return -ENOMEM; - // } - //(void)nrfx_grtc_syscounter_cc_int_disable(systemoff_channel); - // ret = compare_set(systemoff_channel, - // now + wake_time_us * sys_clock_hw_cycles_per_sec() / USEC_PER_SEC, NULL, - // NULL); - // if (ret < 0) { - // k_spin_unlock(&lock, key); - // return ret; - // } - // for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; - for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; - grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { - /* Clear all GRTC channels except the systemoff_channel. */ - chan = u32_count_trailing_zeros(grtc_chan_mask); - // if (chan != systemoff_channel) { - nrfx_grtc_syscounter_cc_disable(chan); - //} - } -#if 0 -#if defined(CONFIG_SOC_NRF54H20_CPUAPP) - for (uint32_t grtc_chan_mask = 0x70; - grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { - /* Clear all GRTC channels except the systemoff_channel. */ - chan = u32_count_trailing_zeros(grtc_chan_mask); - // if (chan != systemoff_channel) { - nrfx_grtc_syscounter_cc_disable(chan); - // } - } -#endif -#if defined(CONFIG_SOC_NRF54H20_CPURAD) - //for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; - for (uint32_t grtc_chan_mask = 0xFF80; - grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { - /* Clear all GRTC channels except the systemoff_channel. */ - chan = u32_count_trailing_zeros(grtc_chan_mask); - //if (chan != systemoff_channel) { - nrfx_grtc_syscounter_cc_disable(chan); - //} - } + uint32_t wait_time = MAX_CC_LATCH_WAIT_TIME_US; #endif -#endif - // /* Make sure that wake_time_us was not triggered yet. */ - // if (nrfx_grtc_syscounter_compare_event_check(systemoff_channel)) { - // k_spin_unlock(&lock, key); - // return -EINVAL; - // } - - // /* This mechanism ensures that stored CC value is latched. */ - //uint32_t wait_time = - // nrfy_grtc_timeout_get(NRF_GRTC) * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 32768 + - // MAX_CC_LATCH_WAIT_TIME_US; - k_busy_wait(1000); - // k_spin_unlock(&lock, key); + /* Wait until the CC value is latched. */ + k_busy_wait(wait_time); + k_spin_unlock(&lock, key); + + wakeup_channel = systemoff_channel; + return 0; } -#endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ #endif /* CONFIG_POWEROFF */ uint32_t sys_clock_cycle_get_32(void) diff --git a/include/zephyr/drivers/timer/nrf_grtc_timer.h b/include/zephyr/drivers/timer/nrf_grtc_timer.h index 5a51df21744..64c0e61653f 100644 --- a/include/zephyr/drivers/timer/nrf_grtc_timer.h +++ b/include/zephyr/drivers/timer/nrf_grtc_timer.h @@ -175,6 +175,24 @@ int z_nrf_grtc_timer_capture_prepare(int32_t chan); */ int z_nrf_grtc_timer_capture_read(int32_t chan, uint64_t *captured_time); +/** @brief Get the channel used for wakeup from system-off. + * + * @return Channel ID or -1 if no channel is reserved for that purpose. + */ +int32_t z_nrf_grtc_timer_wakeup_channel_get(void); + +/** @brief Disable all owned compare channels except the one specified. + * + * This function is used when preparing the system to enter system-off mode. + * It disables all compare channels owned by the driver except the one + * specified by @p reserved_channel. The reserved channel is typically used + * for wake-up from system-off. + * @param reserved_channel Channel ID to remain enabled. + * + * @note Set @p reserved_channel to -1 to disable all owned channels. + */ +void z_nrf_grtc_timer_disable_owned_cc_channels(int32_t reserved_channel); + /** @brief Prepare GRTC as a source of wake up event and set the wake up time. * * @note Calling this function should be immediately followed by low-power mode enter diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index 8189313a8bd..6b16877e08a 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,10 @@ void nrf_poweroff(void) #endif common_suspend(); + /* Disable all owned compare channels except the one used for wakeup from system-off. */ + z_nrf_grtc_timer_disable_owned_cc_channels(z_nrf_grtc_timer_wakeup_channel_get()); + + /* Indicate that we are ready for system off. */ nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY); __set_BASEPRI(0); From 6a7c878a2b0ab59959feaa503dfd632465664207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20St=C4=99pnicki?= Date: Tue, 7 Oct 2025 13:36:38 +0200 Subject: [PATCH 3/3] system off sample: nrf54h20 alignement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabled LATCH reading on sw1 this need additiona REATAIN bits manipulation. Changed console to be handled automatically, otherwise there are some unknown characters when console is suspended. Removed obsolete configs. Signed-off-by: Łukasz Stępnicki --- .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 3 +- samples/boards/nordic/system_off/prj.conf | 1 - .../boards/nrf54h20dk_nrf54h20_cpurad.overlay | 1 + .../nordic/system_off/remote/src/main.c | 14 +---- samples/boards/nordic/system_off/src/main.c | 63 ++++++++++++------- 5 files changed, 46 insertions(+), 36 deletions(-) diff --git a/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 2668d53b0f0..b93c888ad56 100644 --- a/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/samples/boards/nordic/system_off/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -1,3 +1,4 @@ -&uart135 { +&uart136 { zephyr,pm-device-runtime-auto; + disable-rx; }; diff --git a/samples/boards/nordic/system_off/prj.conf b/samples/boards/nordic/system_off/prj.conf index 2fa5e8b6a2c..962ad80de21 100644 --- a/samples/boards/nordic/system_off/prj.conf +++ b/samples/boards/nordic/system_off/prj.conf @@ -3,7 +3,6 @@ CONFIG_PM_DEVICE=y CONFIG_PM_DEVICE_RUNTIME=y CONFIG_UART_ASYNC_API=y CONFIG_GPIO=y -CONFIG_NRF_REGTOOL_VERBOSITY=2 CONFIG_CRC=y CONFIG_POWEROFF=y CONFIG_HWINFO=y diff --git a/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay b/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay index c3b96611443..5f27a7328bb 100644 --- a/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay +++ b/samples/boards/nordic/system_off/remote/boards/nrf54h20dk_nrf54h20_cpurad.overlay @@ -1,4 +1,5 @@ &uart135 { status = "disabled"; zephyr,pm-device-runtime-auto; + disable-rx; }; diff --git a/samples/boards/nordic/system_off/remote/src/main.c b/samples/boards/nordic/system_off/remote/src/main.c index 3541c950211..9a2bd8725c6 100644 --- a/samples/boards/nordic/system_off/remote/src/main.c +++ b/samples/boards/nordic/system_off/remote/src/main.c @@ -14,23 +14,11 @@ int main(void) { - if (IS_ENABLED(CONFIG_CONSOLE)) { printf("%s system off demo. Ready for system off.\n", CONFIG_BOARD); } - z_nrf_grtc_wakeup_prepare(1000); - - if (0) { - /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, false);*/ - /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, false);*/ - k_sleep(K_FOREVER); - } else { - /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, false);*/ - /*nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, false);*/ - - sys_poweroff(); - } + sys_poweroff(); return 0; } diff --git a/samples/boards/nordic/system_off/src/main.c b/samples/boards/nordic/system_off/src/main.c index 85387cd4265..9cf9ab24db6 100644 --- a/samples/boards/nordic/system_off/src/main.c +++ b/samples/boards/nordic/system_off/src/main.c @@ -29,6 +29,7 @@ #endif #if defined(CONFIG_GPIO_WAKEUP_ENABLE) static const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios); +static const uint32_t port_sw0 = DT_PROP(DT_GPIO_CTLR_BY_IDX(DT_ALIAS(sw0), gpios, 0), port); #endif #if defined(CONFIG_LPCOMP_WAKEUP_ENABLE) static const struct device *comp_dev = DEVICE_DT_GET(DT_NODELABEL(comp)); @@ -65,32 +66,38 @@ int main(void) { int rc; uint32_t reset_cause; - const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); uint32_t nrf_pin_sw1 = 32 * port_sw1 + sw1.pin; bool do_poweroff = true; - if (!device_is_ready(cons)) { - printf("%s: device not ready.\n", cons->name); - return 0; + if (nrf_gpio_pin_latch_get(nrf_pin_sw1)) { + nrf_gpio_pin_latch_clear(nrf_pin_sw1); +#if defined(CONFIG_SOC_NRF54H20) + /* Set gpio default if sense is set, prevent 300uA additional current after wakeup + * This is only needed for nrf54 series as PIN config is different from PAD config. + * After wakeup from system-off, SENSE bit is not reset but INPUT is. + */ + if (nrf_gpio_pin_sense_get(nrf_pin_sw1) != GPIO_PIN_CNF_SENSE_Disabled) { + nrf_gpio_cfg_default(nrf_pin_sw1); + } +#endif + do_poweroff = false; } - /* TODO: this is always set and locks entering power off after gpio wakeup */ - // if (nrf_gpio_pin_latch_get(nrf_pin_sw1)) { - // nrf_gpio_pin_latch_clear(nrf_pin_sw1); - // do_poweroff = false; - // } - printf("\n%s system off demo\n", CONFIG_BOARD); hwinfo_get_reset_cause(&reset_cause); rc = print_reset_cause(reset_cause); -#if defined(CONFIG_SOC_NRF54H20_CPUAPP) -/* Temporary set gpio default if sense is set, prevent 300uA additional current after wakeup */ - for (int i = 0; i < 12; i++) { - if (nrf_gpio_pin_sense_get(i) != GPIO_PIN_CNF_SENSE_Disabled) { - nrf_gpio_cfg_default(i); - } +#if defined(CONFIG_SOC_NRF54H20) +#if defined(CONFIG_GPIO_WAKEUP_ENABLE) + /* Set gpio default if sense is set, prevent 300uA additional current after wakeup + * This is only needed for nrf54 series as PIN config is different from PAD config. + * After wakeup from system-off, SENSE bit is not reset but INPUT is. + */ + uint32_t nrf_pin_sw0 = 32 * port_sw0 + sw0.pin; + if(nrf_gpio_pin_sense_get(nrf_pin_sw0) != GPIO_PIN_CNF_SENSE_Disabled) { + nrf_gpio_cfg_default(nrf_pin_sw0); } +#endif #endif if (rc < 0) { @@ -120,10 +127,10 @@ int main(void) printf("Retained data not supported\n"); } - k_sleep(K_MSEC(4000)); #if defined(CONFIG_GRTC_WAKEUP_ENABLE) + int err = z_nrf_grtc_wakeup_prepare(DEEP_SLEEP_TIME_S * USEC_PER_SEC); if (err < 0) { @@ -145,6 +152,10 @@ int main(void) printf("Could not configure sw0 GPIO interrupt (%d)\n", rc); return 0; } + +#if defined(CONFIG_SOC_NRF54H20) + nrf_gpio_pin_retain_disable(nrf_pin_sw0); +#endif #endif #if defined(CONFIG_LPCOMP_WAKEUP_ENABLE) comparator_set_trigger(comp_dev, COMPARATOR_TRIGGER_BOTH_EDGES); @@ -163,16 +174,26 @@ int main(void) return 0; } +#if defined(CONFIG_SOC_NRF54H20) + nrf_gpio_pin_retain_disable(nrf_pin_sw1); +#endif + if (do_poweroff) { printf("Entering system off; press sw0 or sw1 to restart\n"); } else { printf("Button sw1 pressed, not entering system off\n"); } - rc = pm_device_action_run(cons, PM_DEVICE_ACTION_SUSPEND); - if (rc < 0) { - printf("Could not suspend console (%d)\n", rc); - return 0; + if (IS_ENABLED(CONFIG_PM_DEVICE) && IS_ENABLED(CONFIG_SERIAL)) { + static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + int err; + enum pm_device_state state; + + if (dev) { + do { + err = pm_device_state_get(dev, &state); + } while ((err == 0) && (state == PM_DEVICE_STATE_ACTIVE)); + } } if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {