From 53d431983fd60be5293879c231d2a7c2cd210f31 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Thu, 28 Nov 2024 10:51:52 +0100 Subject: [PATCH 1/6] Revert "[nrf fromlist] dts: arm: nordic: Add power states for nRF54H20" This reverts commit 1eef25baf4e477a03d8c070cdbe11465d86a80e6. Signed-off-by: Adam Kondraciuk --- dts/common/nordic/nrf54h20.dtsi | 9 +++------ soc/nordic/nrf54h/power.c | 10 +++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index a9523f15465..479bd4e3298 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -31,7 +31,7 @@ device_type = "cpu"; clocks = <&cpuapp_hsfll>; clock-frequency = ; - cpu-power-states = <&idle_cache_disabled &s2ram>; + cpu-power-states = <&idle &s2ram>; }; cpurad: cpu@3 { @@ -40,7 +40,6 @@ device_type = "cpu"; clocks = <&cpurad_hsfll>; clock-frequency = ; - cpu-power-states = <&idle_cache_disabled>; }; cpuppr: cpu@d { @@ -129,14 +128,12 @@ }; power-states { - // substate-id = <0>; is reserved for "idle", cache powered on - // substate-id = <1>; is reserved for "idle-cache-retained" - idle_cache_disabled: idle_cache_disabled { + idle: idle { compatible = "zephyr,power-state"; power-state-name = "suspend-to-idle"; - substate-id = <2>; min-residency-us = <100000>; }; + s2ram: s2ram { compatible = "zephyr,power-state"; power-state-name = "suspend-to-ram"; diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index c6cf44953fa..11c16b32e71 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -68,7 +68,7 @@ void nrf_poweroff(void) nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, 0); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, false); -#if !defined(NRF_RADIOCORE) +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) /* 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); @@ -98,7 +98,7 @@ static void s2idle_enter(uint8_t substate_id) case 1: /* Substate for idle with cache retained - not implemented yet. */ break; case 2: /* Substate for idle with cache disabled. */ -#if !defined(NRF_RADIOCORE) +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) soc_lrcconf_poweron_request(node, NRF_LRCCONF_POWER_MAIN); #endif common_suspend(); @@ -127,7 +127,7 @@ static void s2idle_exit(uint8_t substate_id) break; case 2: /* Substate for idle with cache disabled. */ common_resume(); -#if !defined(NRF_RADIOCORE) +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) soc_lrcconf_poweron_release(node, NRF_LRCCONF_POWER_MAIN); #endif default: /* Unknown substate. */ @@ -140,7 +140,7 @@ static void s2idle_exit(uint8_t substate_id) static void s2ram_exit(void) { common_resume(); -#if !defined(NRF_RADIOCORE) +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) /* Re-enable domain retention. */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); #endif @@ -156,7 +156,7 @@ static int sys_suspend_to_ram(void) NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true); -#if !defined(NRF_RADIOCORE) +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) /* Disable retention */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); #endif From 7ef7b81e067e12eba951f0f3ea98b36d95a4da97 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Thu, 28 Nov 2024 10:52:01 +0100 Subject: [PATCH 2/6] Revert "[nrf fromlist] soc: nordic: nrf54h: disable IRQ before PM config" This reverts commit dab9c11bdcc80f1e0670ef686e6066ee3304ac47. Signed-off-by: Adam Kondraciuk --- soc/nordic/nrf54h/pm_s2ram.c | 3 +++ soc/nordic/nrf54h/power.c | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/soc/nordic/nrf54h/pm_s2ram.c b/soc/nordic/nrf54h/pm_s2ram.c index 20c28e42df5..88529c4bb75 100644 --- a/soc/nordic/nrf54h/pm_s2ram.c +++ b/soc/nordic/nrf54h/pm_s2ram.c @@ -111,15 +111,18 @@ int soc_s2ram_suspend(pm_s2ram_system_off_fn_t system_off) { int ret; + __disable_irq(); nvic_suspend(&backup_data.nvic_context); mpu_suspend(&backup_data.mpu_context); ret = arch_pm_s2ram_suspend(system_off); if (ret < 0) { + __enable_irq(); return ret; } mpu_resume(&backup_data.mpu_context); nvic_resume(&backup_data.nvic_context); + __enable_irq(); return ret; } diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index 11c16b32e71..1a59320d80b 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -188,19 +188,15 @@ static void s2ram_enter(void) void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state == PM_STATE_SUSPEND_TO_IDLE) { - __disable_irq(); s2idle_enter(substate_id); /* Resume here. */ s2idle_exit(substate_id); - __enable_irq(); } #if defined(CONFIG_PM_S2RAM) else if (state == PM_STATE_SUSPEND_TO_RAM) { - __disable_irq(); s2ram_enter(); /* On resuming or error we return exactly *HERE* */ s2ram_exit(); - __enable_irq(); } #endif else { From 940e4a5e961a215cc1105507c887e92e9c184f74 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Thu, 28 Nov 2024 10:52:43 +0100 Subject: [PATCH 3/6] Revert "[nrf fromlist] soc: nordic: Add LRCCONF management" This reverts commit 1cc6e1580906a0699d69f56dd83cc2591717918c. Signed-off-by: Adam Kondraciuk --- .../clock_control/clock_control_nrf2_common.c | 35 ++++ .../clock_control/clock_control_nrf2_common.h | 10 ++ .../clock_control/clock_control_nrf2_fll16m.c | 8 +- .../clock_control/clock_control_nrf2_hfxo.c | 8 +- soc/nordic/common/CMakeLists.txt | 3 - soc/nordic/common/soc_lrcconf.c | 61 ------- soc/nordic/common/soc_lrcconf.h | 34 ---- soc/nordic/nrf54h/power.c | 163 ++++++------------ soc/nordic/nrf54h/soc.c | 16 +- soc/nordic/nrf54h/soc.h | 11 -- 10 files changed, 109 insertions(+), 240 deletions(-) delete mode 100644 soc/nordic/common/soc_lrcconf.c delete mode 100644 soc/nordic/common/soc_lrcconf.h diff --git a/drivers/clock_control/clock_control_nrf2_common.c b/drivers/clock_control/clock_control_nrf2_common.c index f3b21a5dd1f..7f8f2cbcd42 100644 --- a/drivers/clock_control/clock_control_nrf2_common.c +++ b/drivers/clock_control/clock_control_nrf2_common.c @@ -4,6 +4,7 @@ */ #include "clock_control_nrf2_common.h" +#include #include LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -24,6 +25,9 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); */ STRUCT_CLOCK_CONFIG(generic, ONOFF_CNT_MAX); +static sys_slist_t poweron_main_list; +static struct k_spinlock poweron_main_lock; + static void update_config(struct clock_config_generic *cfg) { atomic_val_t prev_flags = atomic_or(&cfg->flags, FLAG_UPDATE_NEEDED); @@ -159,3 +163,34 @@ int api_nosys_on_off(const struct device *dev, clock_control_subsys_t sys) return -ENOSYS; } + +void clock_request_lrcconf_poweron_main(struct clock_lrcconf_sink *sink) +{ + K_SPINLOCK(&poweron_main_lock) { + if (sys_slist_len(&poweron_main_list) == 0) { + LOG_DBG("%s forced on", "main domain"); + NRF_LRCCONF010->POWERON &= ~LRCCONF_POWERON_MAIN_Msk; + NRF_LRCCONF010->POWERON |= LRCCONF_POWERON_MAIN_AlwaysOn; + } + + sys_slist_find_and_remove(&poweron_main_list, &sink->node); + sys_slist_append(&poweron_main_list, &sink->node); + } +} + +void clock_release_lrcconf_poweron_main(struct clock_lrcconf_sink *sink) +{ + K_SPINLOCK(&poweron_main_lock) { + if (!sys_slist_find_and_remove(&poweron_main_list, &sink->node)) { + K_SPINLOCK_BREAK; + } + + if (sys_slist_len(&poweron_main_list) > 0) { + K_SPINLOCK_BREAK; + } + + LOG_DBG("%s automatic", "main domain"); + NRF_LRCCONF010->POWERON &= ~LRCCONF_POWERON_MAIN_Msk; + NRF_LRCCONF010->POWERON |= LRCCONF_POWERON_MAIN_Automatic; + } +} diff --git a/drivers/clock_control/clock_control_nrf2_common.h b/drivers/clock_control/clock_control_nrf2_common.h index 858698c38ea..67d303c132d 100644 --- a/drivers/clock_control/clock_control_nrf2_common.h +++ b/drivers/clock_control/clock_control_nrf2_common.h @@ -75,4 +75,14 @@ void clock_config_update_end(void *clk_cfg, int status); int api_nosys_on_off(const struct device *dev, clock_control_subsys_t sys); +struct clock_lrcconf_sink { + sys_snode_t node; +}; + +/** + * @brief Request or release lrcconf main power domain + */ +void clock_request_lrcconf_poweron_main(struct clock_lrcconf_sink *sink); +void clock_release_lrcconf_poweron_main(struct clock_lrcconf_sink *sink); + #endif /* ZEPHYR_DRIVERS_CLOCK_CONTROL_NRF2_COMMON_H_ */ diff --git a/drivers/clock_control/clock_control_nrf2_fll16m.c b/drivers/clock_control/clock_control_nrf2_fll16m.c index 613e433e527..7462d822f44 100644 --- a/drivers/clock_control/clock_control_nrf2_fll16m.c +++ b/drivers/clock_control/clock_control_nrf2_fll16m.c @@ -8,7 +8,7 @@ #include "clock_control_nrf2_common.h" #include #include -#include +#include #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -64,7 +64,7 @@ static const struct clock_options { struct fll16m_dev_data { STRUCT_CLOCK_CONFIG(fll16m, ARRAY_SIZE(clock_options)) clk_cfg; struct onoff_client hfxo_cli; - sys_snode_t fll16m_node; + struct clock_lrcconf_sink lrcconf_sink; }; struct fll16m_dev_config { @@ -76,13 +76,13 @@ static void activate_fll16m_mode(struct fll16m_dev_data *dev_data, uint8_t mode) /* TODO: change to nrf_lrcconf_* function when such is available. */ if (mode != FLL16M_MODE_DEFAULT) { - soc_lrcconf_poweron_request(&dev_data->fll16m_node, NRF_LRCCONF_POWER_MAIN); + clock_request_lrcconf_poweron_main(&dev_data->lrcconf_sink); } NRF_LRCCONF010->CLKCTRL[0].SRC = mode; if (mode == FLL16M_MODE_DEFAULT) { - soc_lrcconf_poweron_release(&dev_data->fll16m_node, NRF_LRCCONF_POWER_MAIN); + clock_release_lrcconf_poweron_main(&dev_data->lrcconf_sink); } nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_CLKSTART_0); diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index 977c0aaa0d6..ca49d9015cc 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -11,7 +11,7 @@ #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); -#include +#include BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "multiple instances not supported"); @@ -20,7 +20,7 @@ struct dev_data_hfxo { struct onoff_manager mgr; onoff_notify_fn notify; struct k_timer timer; - sys_snode_t hfxo_node; + struct clock_lrcconf_sink lrcconf_sink; }; struct dev_config_hfxo { @@ -58,7 +58,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) dev_data->notify = notify; nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED); - soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); + clock_request_lrcconf_poweron_main(&dev_data->lrcconf_sink); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO); /* Due to a hardware issue, the HFXOSTARTED event is currently @@ -74,7 +74,7 @@ static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) CONTAINER_OF(mgr, struct dev_data_hfxo, mgr); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO); - soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); + clock_release_lrcconf_poweron_main(&dev_data->lrcconf_sink); notify(mgr, 0); } diff --git a/soc/nordic/common/CMakeLists.txt b/soc/nordic/common/CMakeLists.txt index 4808319557c..1a4e17c20d1 100644 --- a/soc/nordic/common/CMakeLists.txt +++ b/soc/nordic/common/CMakeLists.txt @@ -12,9 +12,6 @@ if(CONFIG_ARM) endif() zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) -if(CONFIG_ARM) - zephyr_library_sources_ifdef(CONFIG_NRF_PLATFORM_HALTIUM soc_lrcconf.c) -endif() if((CONFIG_SOC_SERIES_NRF54HX OR CONFIG_SOC_SERIES_NRF92X) AND CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS) zephyr_library_sources(nrf54hx_nrf92x_mpu_regions.c) diff --git a/soc/nordic/common/soc_lrcconf.c b/soc/nordic/common/soc_lrcconf.c deleted file mode 100644 index f7a40c1d099..00000000000 --- a/soc/nordic/common/soc_lrcconf.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -static struct k_spinlock lock; -static sys_slist_t poweron_main_list; -static sys_slist_t poweron_active_list; - -void soc_lrcconf_poweron_request(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain) -{ - __ASSERT(is_power_of_two(domain), "Only one bit can be set for the domain parameter"); - - sys_slist_t *poweron_list; - - if (domain == NRF_LRCCONF_POWER_MAIN) { - poweron_list = &poweron_main_list; - } else if (domain == NRF_LRCCONF_POWER_DOMAIN_0) { - poweron_list = &poweron_active_list; - } else { - return; - } - K_SPINLOCK(&lock) { - if (sys_slist_len(poweron_list) == 0) { - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, domain, true); - } - - sys_slist_find_and_remove(poweron_list, node); - sys_slist_append(poweron_list, node); - } -} - -void soc_lrcconf_poweron_release(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain) -{ - __ASSERT(is_power_of_two(domain), "Only one bit can be set for the domain parameter"); - - sys_slist_t *poweron_list; - - if (domain == NRF_LRCCONF_POWER_MAIN) { - poweron_list = &poweron_main_list; - } else if (domain == NRF_LRCCONF_POWER_DOMAIN_0) { - poweron_list = &poweron_active_list; - } else { - return; - } - - K_SPINLOCK(&lock) { - if (!sys_slist_find_and_remove(poweron_list, node)) { - K_SPINLOCK_BREAK; - } - - if (sys_slist_len(poweron_list) > 0) { - K_SPINLOCK_BREAK; - } - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, domain, false); - } -} diff --git a/soc/nordic/common/soc_lrcconf.h b/soc/nordic/common/soc_lrcconf.h deleted file mode 100644 index 5ce47112529..00000000000 --- a/soc/nordic/common/soc_lrcconf.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file nRF SoC specific helpers for lrcconf management - */ - -#ifndef ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ -#define ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ - -#include - -/** - * @brief Request lrcconf power domain - * - * @param node Pointer to the @ref sys_snode_t structure which is the ID of the - * requesting module. - * @param domain The mask that represents the power domain ID. - */ -void soc_lrcconf_poweron_request(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain); - -/** - * @brief Release lrcconf power domain - * - * @param node Pointer to the @ref sys_snode_t structure which is the ID of the - * requesting module. - * @param domain The mask that represents the power domain ID. - */ -void soc_lrcconf_poweron_release(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain); - -#endif /* ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ */ diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index 1a59320d80b..ad7ae18d9bb 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -9,26 +9,20 @@ #include #include #include +#include #include #include #include -#include -#include "soc.h" #include "pm_s2ram.h" -static void common_suspend(void) +static void suspend_common(void) { - sys_snode_t *node; - node = soc_pd_sys_snode_get(); - - if (IS_ENABLED(CONFIG_DCACHE)) { - /* 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, - RAMBLOCK_CONTROL_BIT_DCACHE, false); - } + /* 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, + RAMBLOCK_CONTROL_BIT_DCACHE, false); if (IS_ENABLED(CONFIG_ICACHE)) { /* Disable and power down ICACHE */ @@ -37,30 +31,9 @@ static void common_suspend(void) RAMBLOCK_CONTROL_BIT_ICACHE, false); } - soc_lrcconf_poweron_release(node, NRF_LRCCONF_POWER_DOMAIN_0); -} - -static void common_resume(void) -{ - sys_snode_t *node; - - node = soc_pd_sys_snode_get(); - - if (IS_ENABLED(CONFIG_ICACHE)) { - /* Power up and re-enable 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)) { - /* Power up and re-enable DCACHE */ - nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, - RAMBLOCK_CONTROL_BIT_DCACHE, true); - sys_cache_data_enable(); - } - - soc_lrcconf_poweron_request(node, NRF_LRCCONF_POWER_DOMAIN_0); + /* Disable retention */ + 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); } void nrf_poweroff(void) @@ -68,12 +41,13 @@ 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) - /* 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); -#endif - common_suspend(); + + /* TODO: Move it around k_cpu_idle() implementation. */ + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); + + suspend_common(); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY); @@ -85,65 +59,30 @@ void nrf_poweroff(void) CODE_UNREACHABLE; } -static void s2idle_enter(uint8_t substate_id) +#if IS_ENABLED(CONFIG_PM_S2RAM) +/* Resume domain after local suspend to RAM. */ +static void sys_resume(void) { - sys_snode_t *node; - - node = soc_pd_sys_snode_get(); - - switch (substate_id) { - case 0: - /* Substate for idle with cache powered on - not implemented yet. */ - break; - case 1: /* Substate for idle with cache retained - not implemented yet. */ - break; - case 2: /* Substate for idle with cache disabled. */ -#if !defined(CONFIG_SOC_NRF54H20_CPURAD) - soc_lrcconf_poweron_request(node, NRF_LRCCONF_POWER_MAIN); -#endif - common_suspend(); - break; - default: /* Unknown substate. */ - return; + if (IS_ENABLED(CONFIG_ICACHE)) { + /* Power up and re-enable ICACHE */ + nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, + RAMBLOCK_CONTROL_BIT_ICACHE, true); + sys_cache_instr_enable(); } - __set_BASEPRI(0); - __ISB(); - __DSB(); - __WFI(); -} - -static void s2idle_exit(uint8_t substate_id) -{ - sys_snode_t *node; - - node = soc_pd_sys_snode_get(); - - switch (substate_id) { - case 0: - /* Substate for idle with cache powered on - not implemented yet. */ - break; - case 1: /* Substate for idle with cache retained - not implemented yet. */ - break; - case 2: /* Substate for idle with cache disabled. */ - common_resume(); -#if !defined(CONFIG_SOC_NRF54H20_CPURAD) - soc_lrcconf_poweron_release(node, NRF_LRCCONF_POWER_MAIN); -#endif - default: /* Unknown substate. */ - return; + if (IS_ENABLED(CONFIG_DCACHE)) { + /* Power up and re-enable DCACHE */ + nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, + RAMBLOCK_CONTROL_BIT_DCACHE, true); + sys_cache_data_enable(); } -} -#if defined(CONFIG_PM_S2RAM) -/* Resume domain after local suspend to RAM. */ -static void s2ram_exit(void) -{ - common_resume(); -#if !defined(CONFIG_SOC_NRF54H20_CPURAD) /* Re-enable domain retention. */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); -#endif + + /* TODO: Move it around k_cpu_idle() implementation. */ + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, + !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); } /* Function called during local domain suspend to RAM. */ @@ -155,12 +94,10 @@ static int sys_suspend_to_ram(void) nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); -#if !defined(CONFIG_SOC_NRF54H20_CPURAD) - /* Disable retention */ - nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); -#endif - common_suspend(); + suspend_common(); __set_BASEPRI(0); __ISB(); @@ -173,7 +110,7 @@ static int sys_suspend_to_ram(void) return -EBUSY; } -static void s2ram_enter(void) +static void do_suspend_to_ram(void) { /* * Save the CPU context (including the return address),set the SRAM @@ -182,26 +119,24 @@ static void s2ram_enter(void) if (soc_s2ram_suspend(sys_suspend_to_ram)) { return; } + + /* + * On resuming or error we return exactly *HERE* + */ + + sys_resume(); } -#endif /* defined(CONFIG_PM_S2RAM) */ +#endif /* IS_ENABLED(CONFIG_PM_S2RAM) */ void pm_state_set(enum pm_state state, uint8_t substate_id) { - if (state == PM_STATE_SUSPEND_TO_IDLE) { - s2idle_enter(substate_id); - /* Resume here. */ - s2idle_exit(substate_id); - } -#if defined(CONFIG_PM_S2RAM) - else if (state == PM_STATE_SUSPEND_TO_RAM) { - s2ram_enter(); - /* On resuming or error we return exactly *HERE* */ - s2ram_exit(); - } -#endif - else { + if (state != PM_STATE_SUSPEND_TO_RAM) { k_cpu_idle(); + return; } +#if IS_ENABLED(CONFIG_PM_S2RAM) + do_suspend_to_ram(); +#endif } void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index 85570bd9ff3..4ffb17bef51 100644 --- a/soc/nordic/nrf54h/soc.c +++ b/soc/nordic/nrf54h/soc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); @@ -30,8 +29,6 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); #define HSFLL_NODE DT_NODELABEL(cpurad_hsfll) #endif -static sys_snode_t soc_node; - #define FICR_ADDR_GET(node_id, name) \ DT_REG_ADDR(DT_PHANDLE_BY_NAME(node_id, nordic_ficrs, name)) + \ DT_PHA_BY_NAME(node_id, nordic_ficrs, name, offset) @@ -41,10 +38,6 @@ static sys_snode_t soc_node; ADDRESS_SECURITY_Msk | \ ADDRESS_DOMAIN_Msk | \ ADDRESS_BUS_Msk))) -sys_snode_t *soc_pd_sys_snode_get(void) -{ - return &soc_node; -} static void power_domain_init(void) { @@ -59,9 +52,13 @@ static void power_domain_init(void) * WFI the power domain will be correctly retained. */ - soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, + !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, + !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_BIT_ICACHE, false); nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_BIT_DCACHE, false); nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_BIT_ICACHE, false); @@ -125,6 +122,7 @@ bool z_arm_on_enter_cpu_idle(void) #ifdef CONFIG_LOG_FRONTEND_STMESP log_frontend_stmesp_pre_sleep(); #endif + return true; } #endif diff --git a/soc/nordic/nrf54h/soc.h b/soc/nordic/nrf54h/soc.h index 92c411ec9c9..566c07a8c2c 100644 --- a/soc/nordic/nrf54h/soc.h +++ b/soc/nordic/nrf54h/soc.h @@ -8,7 +8,6 @@ #define SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ #include -#include #if defined(CONFIG_SOC_NRF54H20_CPUAPP) #define RAMBLOCK_CONTROL_BIT_ICACHE MEMCONF_POWER_CONTROL_MEM1_Pos @@ -37,14 +36,4 @@ #define RAMBLOCK_RET2_BIT_DCACHE MEMCONF_POWER_RET2_MEM7_Pos #endif -/** - * @brief Get the ID of the node used by the power domain management. - * - * This function returns the node ID to be shared with other dependent modules. - * - * @return The pointer to the node assigned to the SOC module - * used for the power domain management purposes. - */ -sys_snode_t *soc_pd_sys_snode_get(void); - #endif /* SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ */ From 8f8b18d68db457fb27ebc6e065d028798fc66ded Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Wed, 18 Sep 2024 17:58:24 +0200 Subject: [PATCH 4/6] [nrf fromtree] soc: nordic: Add LRCCONF management Due to the possibility of simultaneous accesess to LRCCONF registers, additional management is required. Signed-off-by: Adam Kondraciuk (cherry picked from commit 9b252855fd075d39a41ba61dccea8f7a81ecb77e) --- .../clock_control/clock_control_nrf2_common.c | 35 ---- .../clock_control/clock_control_nrf2_common.h | 10 -- .../clock_control/clock_control_nrf2_fll16m.c | 8 +- .../clock_control/clock_control_nrf2_hfxo.c | 8 +- soc/nordic/common/CMakeLists.txt | 3 + soc/nordic/common/soc_lrcconf.c | 62 +++++++ soc/nordic/common/soc_lrcconf.h | 34 ++++ soc/nordic/nrf54h/power.c | 151 ++++++++++++------ soc/nordic/nrf54h/soc.c | 12 +- 9 files changed, 213 insertions(+), 110 deletions(-) create mode 100644 soc/nordic/common/soc_lrcconf.c create mode 100644 soc/nordic/common/soc_lrcconf.h diff --git a/drivers/clock_control/clock_control_nrf2_common.c b/drivers/clock_control/clock_control_nrf2_common.c index 7f8f2cbcd42..f3b21a5dd1f 100644 --- a/drivers/clock_control/clock_control_nrf2_common.c +++ b/drivers/clock_control/clock_control_nrf2_common.c @@ -4,7 +4,6 @@ */ #include "clock_control_nrf2_common.h" -#include #include LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -25,9 +24,6 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); */ STRUCT_CLOCK_CONFIG(generic, ONOFF_CNT_MAX); -static sys_slist_t poweron_main_list; -static struct k_spinlock poweron_main_lock; - static void update_config(struct clock_config_generic *cfg) { atomic_val_t prev_flags = atomic_or(&cfg->flags, FLAG_UPDATE_NEEDED); @@ -163,34 +159,3 @@ int api_nosys_on_off(const struct device *dev, clock_control_subsys_t sys) return -ENOSYS; } - -void clock_request_lrcconf_poweron_main(struct clock_lrcconf_sink *sink) -{ - K_SPINLOCK(&poweron_main_lock) { - if (sys_slist_len(&poweron_main_list) == 0) { - LOG_DBG("%s forced on", "main domain"); - NRF_LRCCONF010->POWERON &= ~LRCCONF_POWERON_MAIN_Msk; - NRF_LRCCONF010->POWERON |= LRCCONF_POWERON_MAIN_AlwaysOn; - } - - sys_slist_find_and_remove(&poweron_main_list, &sink->node); - sys_slist_append(&poweron_main_list, &sink->node); - } -} - -void clock_release_lrcconf_poweron_main(struct clock_lrcconf_sink *sink) -{ - K_SPINLOCK(&poweron_main_lock) { - if (!sys_slist_find_and_remove(&poweron_main_list, &sink->node)) { - K_SPINLOCK_BREAK; - } - - if (sys_slist_len(&poweron_main_list) > 0) { - K_SPINLOCK_BREAK; - } - - LOG_DBG("%s automatic", "main domain"); - NRF_LRCCONF010->POWERON &= ~LRCCONF_POWERON_MAIN_Msk; - NRF_LRCCONF010->POWERON |= LRCCONF_POWERON_MAIN_Automatic; - } -} diff --git a/drivers/clock_control/clock_control_nrf2_common.h b/drivers/clock_control/clock_control_nrf2_common.h index 67d303c132d..858698c38ea 100644 --- a/drivers/clock_control/clock_control_nrf2_common.h +++ b/drivers/clock_control/clock_control_nrf2_common.h @@ -75,14 +75,4 @@ void clock_config_update_end(void *clk_cfg, int status); int api_nosys_on_off(const struct device *dev, clock_control_subsys_t sys); -struct clock_lrcconf_sink { - sys_snode_t node; -}; - -/** - * @brief Request or release lrcconf main power domain - */ -void clock_request_lrcconf_poweron_main(struct clock_lrcconf_sink *sink); -void clock_release_lrcconf_poweron_main(struct clock_lrcconf_sink *sink); - #endif /* ZEPHYR_DRIVERS_CLOCK_CONTROL_NRF2_COMMON_H_ */ diff --git a/drivers/clock_control/clock_control_nrf2_fll16m.c b/drivers/clock_control/clock_control_nrf2_fll16m.c index 7462d822f44..613e433e527 100644 --- a/drivers/clock_control/clock_control_nrf2_fll16m.c +++ b/drivers/clock_control/clock_control_nrf2_fll16m.c @@ -8,7 +8,7 @@ #include "clock_control_nrf2_common.h" #include #include -#include +#include #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -64,7 +64,7 @@ static const struct clock_options { struct fll16m_dev_data { STRUCT_CLOCK_CONFIG(fll16m, ARRAY_SIZE(clock_options)) clk_cfg; struct onoff_client hfxo_cli; - struct clock_lrcconf_sink lrcconf_sink; + sys_snode_t fll16m_node; }; struct fll16m_dev_config { @@ -76,13 +76,13 @@ static void activate_fll16m_mode(struct fll16m_dev_data *dev_data, uint8_t mode) /* TODO: change to nrf_lrcconf_* function when such is available. */ if (mode != FLL16M_MODE_DEFAULT) { - clock_request_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_request(&dev_data->fll16m_node, NRF_LRCCONF_POWER_MAIN); } NRF_LRCCONF010->CLKCTRL[0].SRC = mode; if (mode == FLL16M_MODE_DEFAULT) { - clock_release_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_release(&dev_data->fll16m_node, NRF_LRCCONF_POWER_MAIN); } nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_CLKSTART_0); diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index ca49d9015cc..977c0aaa0d6 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -11,7 +11,7 @@ #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); -#include +#include BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "multiple instances not supported"); @@ -20,7 +20,7 @@ struct dev_data_hfxo { struct onoff_manager mgr; onoff_notify_fn notify; struct k_timer timer; - struct clock_lrcconf_sink lrcconf_sink; + sys_snode_t hfxo_node; }; struct dev_config_hfxo { @@ -58,7 +58,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) dev_data->notify = notify; nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED); - clock_request_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO); /* Due to a hardware issue, the HFXOSTARTED event is currently @@ -74,7 +74,7 @@ static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) CONTAINER_OF(mgr, struct dev_data_hfxo, mgr); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO); - clock_release_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); notify(mgr, 0); } diff --git a/soc/nordic/common/CMakeLists.txt b/soc/nordic/common/CMakeLists.txt index 1a4e17c20d1..4808319557c 100644 --- a/soc/nordic/common/CMakeLists.txt +++ b/soc/nordic/common/CMakeLists.txt @@ -12,6 +12,9 @@ if(CONFIG_ARM) endif() zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) +if(CONFIG_ARM) + zephyr_library_sources_ifdef(CONFIG_NRF_PLATFORM_HALTIUM soc_lrcconf.c) +endif() if((CONFIG_SOC_SERIES_NRF54HX OR CONFIG_SOC_SERIES_NRF92X) AND CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS) zephyr_library_sources(nrf54hx_nrf92x_mpu_regions.c) diff --git a/soc/nordic/common/soc_lrcconf.c b/soc/nordic/common/soc_lrcconf.c new file mode 100644 index 00000000000..da6dbf10b3f --- /dev/null +++ b/soc/nordic/common/soc_lrcconf.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static struct k_spinlock lock; +static sys_slist_t poweron_main_list; +static sys_slist_t poweron_active_list; + +void soc_lrcconf_poweron_request(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain) +{ + __ASSERT(is_power_of_two(domain), "Only one bit can be set for the domain parameter"); + + sys_slist_t *poweron_list; + + if (domain == NRF_LRCCONF_POWER_MAIN) { + poweron_list = &poweron_main_list; + } else if (domain == NRF_LRCCONF_POWER_DOMAIN_0) { + poweron_list = &poweron_active_list; + } else { + return; + } + + K_SPINLOCK(&lock) { + if (sys_slist_len(poweron_list) == 0) { + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, domain, true); + } + + sys_slist_find_and_remove(poweron_list, node); + sys_slist_append(poweron_list, node); + } +} + +void soc_lrcconf_poweron_release(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain) +{ + __ASSERT(is_power_of_two(domain), "Only one bit can be set for the domain parameter"); + + sys_slist_t *poweron_list; + + if (domain == NRF_LRCCONF_POWER_MAIN) { + poweron_list = &poweron_main_list; + } else if (domain == NRF_LRCCONF_POWER_DOMAIN_0) { + poweron_list = &poweron_active_list; + } else { + return; + } + + K_SPINLOCK(&lock) { + if (!sys_slist_find_and_remove(poweron_list, node)) { + K_SPINLOCK_BREAK; + } + + if (sys_slist_len(poweron_list) > 0) { + K_SPINLOCK_BREAK; + } + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, domain, false); + } +} diff --git a/soc/nordic/common/soc_lrcconf.h b/soc/nordic/common/soc_lrcconf.h new file mode 100644 index 00000000000..5ce47112529 --- /dev/null +++ b/soc/nordic/common/soc_lrcconf.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file nRF SoC specific helpers for lrcconf management + */ + +#ifndef ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ +#define ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ + +#include + +/** + * @brief Request lrcconf power domain + * + * @param node Pointer to the @ref sys_snode_t structure which is the ID of the + * requesting module. + * @param domain The mask that represents the power domain ID. + */ +void soc_lrcconf_poweron_request(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain); + +/** + * @brief Release lrcconf power domain + * + * @param node Pointer to the @ref sys_snode_t structure which is the ID of the + * requesting module. + * @param domain The mask that represents the power domain ID. + */ +void soc_lrcconf_poweron_release(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain); + +#endif /* ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ */ diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index ad7ae18d9bb..07a49609151 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -9,20 +9,24 @@ #include #include #include -#include #include #include #include +#include +#include "soc.h" #include "pm_s2ram.h" -static void suspend_common(void) -{ +extern sys_snode_t soc_node; - /* 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, - RAMBLOCK_CONTROL_BIT_DCACHE, false); +static void common_suspend(void) +{ + if (IS_ENABLED(CONFIG_DCACHE)) { + /* 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, + RAMBLOCK_CONTROL_BIT_DCACHE, false); + } if (IS_ENABLED(CONFIG_ICACHE)) { /* Disable and power down ICACHE */ @@ -31,9 +35,26 @@ static void suspend_common(void) RAMBLOCK_CONTROL_BIT_ICACHE, false); } - /* Disable retention */ - 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); + soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); +} + +static void common_resume(void) +{ + if (IS_ENABLED(CONFIG_ICACHE)) { + /* Power up and re-enable 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)) { + /* Power up and re-enable DCACHE */ + nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, + RAMBLOCK_CONTROL_BIT_DCACHE, true); + sys_cache_data_enable(); + } + + soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); } void nrf_poweroff(void) @@ -41,13 +62,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) + /* Disable retention */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); - - /* TODO: Move it around k_cpu_idle() implementation. */ - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); - - suspend_common(); + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); +#endif + common_suspend(); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY); @@ -59,30 +79,57 @@ void nrf_poweroff(void) CODE_UNREACHABLE; } -#if IS_ENABLED(CONFIG_PM_S2RAM) -/* Resume domain after local suspend to RAM. */ -static void sys_resume(void) +static void s2idle_enter(uint8_t substate_id) { - if (IS_ENABLED(CONFIG_ICACHE)) { - /* Power up and re-enable ICACHE */ - nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, - RAMBLOCK_CONTROL_BIT_ICACHE, true); - sys_cache_instr_enable(); + switch (substate_id) { + case 0: + /* Substate for idle with cache powered on - not implemented yet. */ + break; + case 1: /* Substate for idle with cache retained - not implemented yet. */ + break; + case 2: /* Substate for idle with cache disabled. */ +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) + soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_MAIN); +#endif + common_suspend(); + break; + default: /* Unknown substate. */ + return; } - if (IS_ENABLED(CONFIG_DCACHE)) { - /* Power up and re-enable DCACHE */ - nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, - RAMBLOCK_CONTROL_BIT_DCACHE, true); - sys_cache_data_enable(); + __set_BASEPRI(0); + __ISB(); + __DSB(); + __WFI(); +} + +static void s2idle_exit(uint8_t substate_id) +{ + switch (substate_id) { + case 0: + /* Substate for idle with cache powered on - not implemented yet. */ + break; + case 1: /* Substate for idle with cache retained - not implemented yet. */ + break; + case 2: /* Substate for idle with cache disabled. */ + common_resume(); +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) + soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_MAIN); +#endif + default: /* Unknown substate. */ + return; } +} +#if defined(CONFIG_PM_S2RAM) +/* Resume domain after local suspend to RAM. */ +static void s2ram_exit(void) +{ + common_resume(); +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) /* Re-enable domain retention. */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); - - /* TODO: Move it around k_cpu_idle() implementation. */ - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, - !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); +#endif } /* Function called during local domain suspend to RAM. */ @@ -94,10 +141,12 @@ static int sys_suspend_to_ram(void) nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true); - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); - suspend_common(); +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) + /* Disable retention */ + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); +#endif + common_suspend(); __set_BASEPRI(0); __ISB(); @@ -110,7 +159,7 @@ static int sys_suspend_to_ram(void) return -EBUSY; } -static void do_suspend_to_ram(void) +static void s2ram_enter(void) { /* * Save the CPU context (including the return address),set the SRAM @@ -119,24 +168,26 @@ static void do_suspend_to_ram(void) if (soc_s2ram_suspend(sys_suspend_to_ram)) { return; } - - /* - * On resuming or error we return exactly *HERE* - */ - - sys_resume(); } -#endif /* IS_ENABLED(CONFIG_PM_S2RAM) */ +#endif /* defined(CONFIG_PM_S2RAM) */ void pm_state_set(enum pm_state state, uint8_t substate_id) { - if (state != PM_STATE_SUSPEND_TO_RAM) { - k_cpu_idle(); - return; + if (state == PM_STATE_SUSPEND_TO_IDLE) { + s2idle_enter(substate_id); + /* Resume here. */ + s2idle_exit(substate_id); + } +#if defined(CONFIG_PM_S2RAM) + else if (state == PM_STATE_SUSPEND_TO_RAM) { + s2ram_enter(); + /* On resuming or error we return exactly *HERE* */ + s2ram_exit(); } -#if IS_ENABLED(CONFIG_PM_S2RAM) - do_suspend_to_ram(); #endif + else { + k_cpu_idle(); + } } void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index 4ffb17bef51..43c84e1b9a7 100644 --- a/soc/nordic/nrf54h/soc.c +++ b/soc/nordic/nrf54h/soc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); @@ -29,6 +30,8 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); #define HSFLL_NODE DT_NODELABEL(cpurad_hsfll) #endif +sys_snode_t soc_node; + #define FICR_ADDR_GET(node_id, name) \ DT_REG_ADDR(DT_PHANDLE_BY_NAME(node_id, nordic_ficrs, name)) + \ DT_PHA_BY_NAME(node_id, nordic_ficrs, name, offset) @@ -52,13 +55,9 @@ static void power_domain_init(void) * WFI the power domain will be correctly retained. */ - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, - !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); - nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, - !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); + soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); - nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); - nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_BIT_ICACHE, false); nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_BIT_DCACHE, false); nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_BIT_ICACHE, false); @@ -122,7 +121,6 @@ bool z_arm_on_enter_cpu_idle(void) #ifdef CONFIG_LOG_FRONTEND_STMESP log_frontend_stmesp_pre_sleep(); #endif - return true; } #endif From 8997a18823b88b7dabd90043a323bdd6bb7ad3f8 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Wed, 2 Oct 2024 10:39:56 +0200 Subject: [PATCH 5/6] [nrf fromtree] dts: arm: nordic: Add power states for nRF54H20 Add `idle` and `s2ram` power states for nRF54H20 cpuapp and cpurad. Also the substate `idle_cache_disable` added. Signed-off-by: Adam Kondraciuk (cherry picked from commit e786c1f8492b07beb510b2a42fb1469871b5db1f) --- dts/common/nordic/nrf54h20.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index 479bd4e3298..a9523f15465 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -31,7 +31,7 @@ device_type = "cpu"; clocks = <&cpuapp_hsfll>; clock-frequency = ; - cpu-power-states = <&idle &s2ram>; + cpu-power-states = <&idle_cache_disabled &s2ram>; }; cpurad: cpu@3 { @@ -40,6 +40,7 @@ device_type = "cpu"; clocks = <&cpurad_hsfll>; clock-frequency = ; + cpu-power-states = <&idle_cache_disabled>; }; cpuppr: cpu@d { @@ -128,12 +129,14 @@ }; power-states { - idle: idle { + // substate-id = <0>; is reserved for "idle", cache powered on + // substate-id = <1>; is reserved for "idle-cache-retained" + idle_cache_disabled: idle_cache_disabled { compatible = "zephyr,power-state"; power-state-name = "suspend-to-idle"; + substate-id = <2>; min-residency-us = <100000>; }; - s2ram: s2ram { compatible = "zephyr,power-state"; power-state-name = "suspend-to-ram"; From 2a2a67b7b9ee1b10c322b4c478745ee82bbc9485 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Tue, 12 Nov 2024 11:24:40 +0100 Subject: [PATCH 6/6] [nrf fromtree] soc: nordic: nrf54h: disable IRQ before PM config IRQs must be disabled before starting any procedures to prepare for low-power states. Signed-off-by: Adam Kondraciuk (cherry picked from commit be1f40547fae11ae2ca879d900640c1666e706f5) --- soc/nordic/nrf54h/pm_s2ram.c | 3 --- soc/nordic/nrf54h/power.c | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/soc/nordic/nrf54h/pm_s2ram.c b/soc/nordic/nrf54h/pm_s2ram.c index 88529c4bb75..20c28e42df5 100644 --- a/soc/nordic/nrf54h/pm_s2ram.c +++ b/soc/nordic/nrf54h/pm_s2ram.c @@ -111,18 +111,15 @@ int soc_s2ram_suspend(pm_s2ram_system_off_fn_t system_off) { int ret; - __disable_irq(); nvic_suspend(&backup_data.nvic_context); mpu_suspend(&backup_data.mpu_context); ret = arch_pm_s2ram_suspend(system_off); if (ret < 0) { - __enable_irq(); return ret; } mpu_resume(&backup_data.mpu_context); nvic_resume(&backup_data.nvic_context); - __enable_irq(); return ret; } diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index 07a49609151..a3b39a4c5fe 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -174,15 +174,19 @@ static void s2ram_enter(void) void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state == PM_STATE_SUSPEND_TO_IDLE) { + __disable_irq(); s2idle_enter(substate_id); /* Resume here. */ s2idle_exit(substate_id); + __enable_irq(); } #if defined(CONFIG_PM_S2RAM) else if (state == PM_STATE_SUSPEND_TO_RAM) { + __disable_irq(); s2ram_enter(); /* On resuming or error we return exactly *HERE* */ s2ram_exit(); + __enable_irq(); } #endif else {