From 5d3e2f834925d74fc0eeba00286e63a9b14080a1 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Wed, 16 Jul 2025 09:37:23 +0200 Subject: [PATCH] soc: nordic: nrf54h: Implement idle with cache retained state Add new idle state with cache retention enabled. Signed-off-by: Adam Kondraciuk --- .../nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts | 13 +++-- .../nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts | 17 +++++++ dts/vendor/nordic/nrf54h20.dtsi | 12 +++-- soc/nordic/nrf54h/CMakeLists.txt | 5 ++ .../nrf54h/Kconfig.defconfig.nrf54h20_cpuapp | 3 ++ .../nrf54h/Kconfig.defconfig.nrf54h20_cpurad | 3 ++ soc/nordic/nrf54h/power.c | 50 +++++++++++++++---- soc/nordic/nrf54h/soc.c | 42 +++++++++------- soc/nordic/nrf54h/soc.h | 7 +++ 9 files changed, 116 insertions(+), 36 deletions(-) diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts index 3ec256ee0e68d..18a6e01929d0d 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts @@ -330,14 +330,21 @@ zephyr_udc0: &usbhs { status = "okay"; }; -/* Trim this RAM block for making room on all run-time common S2RAM cpu context. */ +/* Trim this RAM block for power management related features. */ &cpuapp_ram0 { - reg = <0x22000000 (DT_SIZE_K(32) - 32)>; - ranges = <0x0 0x22000000 (0x8000 - 0x20)>; + reg = <0x22000000 (DT_SIZE_K(32) - 256)>; + ranges = <0x0 0x22000000 (0x8000 - 0x100)>; }; / { soc { + /* cache control functions - must be executed from local SRAM */ + pm_ramfunc: cpuapp_s2ram@22007f00 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x22007f00 192>; + zephyr,memory-region = "PMLocalRamfunc"; + }; + /* run-time common S2RAM cpu context RAM */ pm_s2ram: cpuapp_s2ram@22007fe0 { compatible = "zephyr,memory-region", "mmio-sram"; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts index 5473d9a7405ad..f5a3b8de66717 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpurad.dts @@ -116,3 +116,20 @@ slot1_partition: &cpurad_slot1_partition { zephyr_udc0: &usbhs { status = "disabled"; }; + +/* Trim this RAM block for power management related features. */ +&cpurad_ram0 { + reg = <0x23000000 (DT_SIZE_K(192) - 192)>; + ranges = <0x0 0x23000000 (0x30000 - 0xC0)>; +}; + +/ { + soc { + /* cache control functions - must be executed from RAM */ + pm_ramfunc: cpurad_s2ram@2302ff40 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2302ff80 192>; + zephyr,memory-region = "PMLocalRamfunc"; + }; + }; +}; diff --git a/dts/vendor/nordic/nrf54h20.dtsi b/dts/vendor/nordic/nrf54h20.dtsi index 6c202aa1dbb09..dfe0c4b7c6c86 100644 --- a/dts/vendor/nordic/nrf54h20.dtsi +++ b/dts/vendor/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_cache_retained &idle_cache_disabled &s2ram>; }; cpurad: cpu@3 { @@ -40,7 +40,7 @@ device_type = "cpu"; clocks = <&cpurad_hsfll>; clock-frequency = ; - cpu-power-states = <&idle_cache_disabled>; + cpu-power-states = <&idle_cache_retained &idle_cache_disabled>; }; cpuppr: cpu@d { @@ -130,7 +130,13 @@ power-states { // substate-id = <0>; is reserved for "idle", cache powered on - // substate-id = <1>; is reserved for "idle-cache-retained" + idle_cache_retained: idle_cache_retained { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <700>; + exit-latency-us = <5>; + }; idle_cache_disabled: idle_cache_disabled { compatible = "zephyr,power-state"; power-state-name = "suspend-to-idle"; diff --git a/soc/nordic/nrf54h/CMakeLists.txt b/soc/nordic/nrf54h/CMakeLists.txt index 94e38e62f2b17..a4db05c9e643d 100644 --- a/soc/nordic/nrf54h/CMakeLists.txt +++ b/soc/nordic/nrf54h/CMakeLists.txt @@ -5,6 +5,11 @@ if(CONFIG_ARM) zephyr_library_sources(soc.c) if(CONFIG_PM OR CONFIG_POWEROFF) zephyr_library_sources(power.c) + zephyr_code_relocate( + FILES power.c + FILTER ".*\\.cache_retain_and_sleep" + LOCATION PMLocalRamfunc_TEXT + ) endif() endif() diff --git a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp index 0cdc22760405c..f2e0343d6350d 100644 --- a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp +++ b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp @@ -14,4 +14,7 @@ config SHELL_BACKEND_SERIAL config POWER_DOMAIN default y +config CODE_DATA_RELOCATION + default y if PM || POWEROFF + endif # SOC_NRF54H20_CPUAPP diff --git a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad index b3f5216c8f9f2..31687c2a54432 100644 --- a/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad +++ b/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -14,4 +14,7 @@ config PM config POWER_DOMAIN default y +config CODE_DATA_RELOCATION + default y if PM || POWEROFF + endif # SOC_NRF54H20_CPURAD diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index e1263be0d0e51..3a23a6050605f 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -87,18 +88,43 @@ void nrf_poweroff(void) CODE_UNREACHABLE; } -static void s2idle_enter(uint8_t substate_id) +static __attribute__((__used__, noinline)) void cache_retain_and_sleep(void) { + nrf_cache_task_trigger(NRF_DCACHE, NRF_CACHE_TASK_SAVE); + nrf_cache_task_trigger(NRF_ICACHE, NRF_CACHE_TASK_SAVE); + while (nrf_cache_busy_check(NRF_DCACHE) || + nrf_cache_busy_check(NRF_ICACHE)) { + + } + + __set_BASEPRI(0); + __ISB(); + __DSB(); + __WFI(); + + nrf_cache_task_trigger(NRF_ICACHE, NRF_CACHE_TASK_RESTORE); + nrf_cache_task_trigger(NRF_DCACHE, NRF_CACHE_TASK_RESTORE); + while (nrf_cache_busy_check(NRF_DCACHE) || + nrf_cache_busy_check(NRF_ICACHE)) { + + } +} + +void s2idle_enter(uint8_t substate_id) +{ +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) + soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_MAIN); +#endif 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 1: /* Substate for idle with cache retained. */ + soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); + nrf_soc_memconf_retain_set(true); + cache_retain_and_sleep(); + return; 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. */ @@ -117,17 +143,19 @@ static void s2idle_exit(uint8_t 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. */ + case 1: /* Substate for idle with cache retained. */ + nrf_soc_memconf_retain_set(false); break; case 2: /* Substate for idle with cache disabled. */ nrf_power_up_cache(); - common_resume(); -#if !defined(CONFIG_SOC_NRF54H20_CPURAD) - soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_MAIN); -#endif + break; default: /* Unknown substate. */ return; } + common_resume(); +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) + soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_MAIN); +#endif } #if defined(CONFIG_PM_S2RAM) diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index 01cacf48f62f0..1206e6767aa28 100644 --- a/soc/nordic/nrf54h/soc.c +++ b/soc/nordic/nrf54h/soc.c @@ -60,6 +60,26 @@ sys_snode_t soc_node; ADDRESS_DOMAIN_Msk | \ ADDRESS_BUS_Msk))) +void nrf_soc_memconf_retain_set(bool enable) +{ + uint32_t ret_mask = BIT(RAMBLOCK_RET_BIT_ICACHE) | BIT(RAMBLOCK_RET_BIT_DCACHE); + + nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, ret_mask, enable); + nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, ret_mask, enable); + +#if defined(RAMBLOCK_RET2_MASK) + ret_mask = 0; +#if defined(RAMBLOCK_RET2_BIT_ICACHE) + ret_mask |= BIT(RAMBLOCK_RET2_BIT_ICACHE); +#endif +#if defined(RAMBLOCK_RET2_BIT_DCACHE) + ret_mask |= BIT(RAMBLOCK_RET2_BIT_DCACHE); +#endif + nrf_memconf_ramblock_ret2_mask_enable_set(NRF_MEMCONF, 0, ret_mask, enable); + nrf_memconf_ramblock_ret2_mask_enable_set(NRF_MEMCONF, 1, ret_mask, enable); +#endif /* defined(RAMBLOCK_RET2_MASK) */ +} + static void power_domain_init(void) { /* @@ -75,28 +95,12 @@ static void power_domain_init(void) soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); - - 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); - nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_BIT_DCACHE, false); -#if defined(RAMBLOCK_RET2_BIT_ICACHE) - nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET2_BIT_ICACHE, false); - nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET2_BIT_ICACHE, false); -#endif -#if defined(RAMBLOCK_RET2_BIT_DCACHE) - nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET2_BIT_DCACHE, false); - nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET2_BIT_DCACHE, false); -#endif + nrf_soc_memconf_retain_set(false); nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, true); nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, true); #if defined(RAMBLOCK_RET2_MASK) - /* - * TODO: Use nrf_memconf_ramblock_ret2_mask_enable_set() function - * when will be provided by HAL. - */ - NRF_MEMCONF->POWER[0].RET2 = RAMBLOCK_RET2_MASK; - NRF_MEMCONF->POWER[1].RET2 = RAMBLOCK_RET2_MASK; + nrf_memconf_ramblock_ret2_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET2_MASK, true); + nrf_memconf_ramblock_ret2_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET2_MASK, true); #endif } diff --git a/soc/nordic/nrf54h/soc.h b/soc/nordic/nrf54h/soc.h index 566c07a8c2cbf..69c22e52bd16f 100644 --- a/soc/nordic/nrf54h/soc.h +++ b/soc/nordic/nrf54h/soc.h @@ -36,4 +36,11 @@ #define RAMBLOCK_RET2_BIT_DCACHE MEMCONF_POWER_RET2_MEM7_Pos #endif +/** + * @brief Enable or disable the retention for cache RAM blocks. + * + * @param enable True if the retention is to be enabled, false otherwise. + */ +void nrf_soc_memconf_retain_set(bool enable); + #endif /* SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ */