From c13c9266c8d1ad129362c79a567096e2d774ebf9 Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Wed, 18 Sep 2024 17:58:24 +0200 Subject: [PATCH] soc: nordic: Add LRCCONF management Due to the possibility of simultaneous accesess to LRCCONF registers, additional management is required. 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 | 1 + soc/nordic/common/soc_lrcconf.c | 63 +++++++++++++++++++ soc/nordic/common/soc_lrcconf.h | 34 ++++++++++ soc/nordic/nrf54h/Kconfig | 1 + soc/nordic/nrf54h/power.c | 41 +++++++----- soc/nordic/nrf54h/power.h | 9 +++ soc/nordic/nrf54h/soc.c | 25 ++++++-- 11 files changed, 162 insertions(+), 73 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 7f8f2cbcd422f1..f3b21a5dd1fbe0 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 67d303c132d9bc..858698c38ea7ea 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 4fdf9220c27709..217fd2147ff802 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 lrcconf_client_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->lrcconf_client_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->lrcconf_client_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 ca49d9015ccb03..91d33506d0d78b 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 lrcconf_client_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->lrcconf_client_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->lrcconf_client_node, NRF_LRCCONF_POWER_MAIN); notify(mgr, 0); } diff --git a/soc/nordic/common/CMakeLists.txt b/soc/nordic/common/CMakeLists.txt index 38c55c614e9e55..b3d0a2fe56a621 100644 --- a/soc/nordic/common/CMakeLists.txt +++ b/soc/nordic/common/CMakeLists.txt @@ -12,6 +12,7 @@ if(CONFIG_ARM) endif() zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) +zephyr_library_sources_ifdef(CONFIG_NRF_PLATFORM_HALTIUM soc_lrcconf.c) 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 00000000000000..6f3273b41f4fcc --- /dev/null +++ b/soc/nordic/common/soc_lrcconf.c @@ -0,0 +1,63 @@ +/* + * 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 00000000000000..5ce4711252968c --- /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/Kconfig b/soc/nordic/nrf54h/Kconfig index dd647174b14114..e7b3b9f310621a 100644 --- a/soc/nordic/nrf54h/Kconfig +++ b/soc/nordic/nrf54h/Kconfig @@ -28,6 +28,7 @@ config SOC_NRF54H20_CPUAPP select NRFS_HAS_VBUS_DETECTOR_SERVICE select HAS_PM select HAS_POWEROFF + select ARM_ON_ENTER_CPU_IDLE_HOOK if PM || POWEROFF config SOC_NRF54H20_CPURAD select ARM diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index ad7ae18d9bb191..4f99e380ab0968 100644 --- a/soc/nordic/nrf54h/power.c +++ b/soc/nordic/nrf54h/power.c @@ -9,12 +9,16 @@ #include #include #include -#include #include #include #include +#include #include "pm_s2ram.h" +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) +static sys_snode_t pm_node; +#endif + static void suspend_common(void) { @@ -31,9 +35,10 @@ static void suspend_common(void) RAMBLOCK_CONTROL_BIT_ICACHE, false); } +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) /* 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); +#endif } void nrf_poweroff(void) @@ -41,11 +46,9 @@ 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) 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); +#endif suspend_common(); @@ -59,7 +62,7 @@ void nrf_poweroff(void) CODE_UNREACHABLE; } -#if IS_ENABLED(CONFIG_PM_S2RAM) +#if defined(CONFIG_PM_S2RAM) /* Resume domain after local suspend to RAM. */ static void sys_resume(void) { @@ -77,12 +80,10 @@ static void sys_resume(void) sys_cache_data_enable(); } +#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,8 +95,6 @@ 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(); @@ -126,7 +125,7 @@ static void do_suspend_to_ram(void) 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) { @@ -134,12 +133,24 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) k_cpu_idle(); return; } -#if IS_ENABLED(CONFIG_PM_S2RAM) +#if defined(CONFIG_PM_S2RAM) do_suspend_to_ram(); #endif } void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) + if (state == PM_STATE_SUSPEND_TO_IDLE) { + soc_lrcconf_poweron_release(&pm_node, NRF_LRCCONF_POWER_DOMAIN_0); + } +#endif irq_unlock(0); } + +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) +void pm_state_enter_idle_prepare(void) +{ + soc_lrcconf_poweron_request(&pm_node, NRF_LRCCONF_POWER_DOMAIN_0); +} +#endif diff --git a/soc/nordic/nrf54h/power.h b/soc/nordic/nrf54h/power.h index 021c20ec4dcf7b..ecde95171247d9 100644 --- a/soc/nordic/nrf54h/power.h +++ b/soc/nordic/nrf54h/power.h @@ -10,6 +10,8 @@ #ifndef _ZEPHYR_SOC_ARM_NORDIC_NRF_POWER_H_ #define _ZEPHYR_SOC_ARM_NORDIC_NRF_POWER_H_ +#include + /** * @brief Perform a power off. * @@ -17,4 +19,11 @@ */ void nrf_poweroff(void); +/** + * @brief Prepare to the idle state. + * + * This function applies the required PM configuration before entering the idle state. + */ +void pm_state_enter_idle_prepare(void); + #endif /* _ZEPHYR_SOC_ARM_NORDIC_NRF_POWER_H_ */ diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index 2699a3ebd54060..bf6459f9fa5f25 100644 --- a/soc/nordic/nrf54h/soc.c +++ b/soc/nordic/nrf54h/soc.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include "power.h" LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); @@ -29,6 +31,12 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); #define HSFLL_NODE DT_NODELABEL(cpurad_hsfll) #endif +#if !(defined(CONFIG_PM) || defined(CONFIG_POWEROFF)) +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) +static sys_snode_t soc_node; +#endif +#endif + #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 +60,17 @@ 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)); - +#if !defined(CONFIG_SOC_NRF54H20_CPURAD) +#if !(defined(CONFIG_PM) || defined(CONFIG_POWEROFF)) + soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0); +#endif /* !(defined(CONFIG_PM) || defined(CONFIG_POWEROFF)) */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); +#else + 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); +#endif /* !defined(CONFIG_SOC_NRF54H20_CPURAD) */ + 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,6 +134,9 @@ bool z_arm_on_enter_cpu_idle(void) #ifdef CONFIG_LOG_FRONTEND_STMESP log_frontend_stmesp_pre_sleep(); #endif +#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF) + pm_state_enter_idle_prepare(); +#endif return true; }