From b401917cd0c3a25e2a296945e3ce9ee4e85b688b Mon Sep 17 00:00:00 2001 From: Adam Kondraciuk Date: Wed, 18 Sep 2024 17:58:24 +0200 Subject: [PATCH] [nrf fromlist] soc: nordic: Add LRCCONF management Due to the possibility of simultaneous accesess to LRCCONF registers, additional management is required. Upstream PR: https://github.com/zephyrproject-rtos/zephyr/pull/79067 Signed-off-by: Adam Kondraciuk --- .../clock_control/clock_control_nrf2_common.c | 34 ---------- .../clock_control/clock_control_nrf2_common.h | 6 -- .../clock_control/clock_control_nrf2_fll16m.c | 6 +- .../clock_control/clock_control_nrf2_hfxo.c | 6 +- soc/nordic/common/soc_lrcconf.c | 63 +++++++++++++++++++ soc/nordic/common/soc_lrcconf.h | 34 ++++++++++ soc/nordic/nrf54h/CMakeLists.txt | 1 + soc/nordic/nrf54h/Kconfig | 1 + soc/nordic/nrf54h/power.c | 40 ++++++++---- soc/nordic/nrf54h/power.h | 18 ++++++ soc/nordic/nrf54h/soc.c | 28 +++++++-- 11 files changed, 174 insertions(+), 63 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 469c39a100b..5dc3f2e0362 100644 --- a/drivers/clock_control/clock_control_nrf2_common.c +++ b/drivers/clock_control/clock_control_nrf2_common.c @@ -26,9 +26,6 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); */ NRF2_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); @@ -165,34 +162,3 @@ int api_nosys_on_off(const struct device *dev, clock_control_subsys_t sys) return -ENOSYS; } - -void nrf2_clock_request_lrcconf_poweron_main(struct nrf2_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 nrf2_clock_release_lrcconf_poweron_main(struct nrf2_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 4a153216cda..fae6b8b5c85 100644 --- a/drivers/clock_control/clock_control_nrf2_common.h +++ b/drivers/clock_control/clock_control_nrf2_common.h @@ -80,10 +80,4 @@ struct nrf2_clock_lrcconf_sink { sys_snode_t node; }; -/** - * @brief Request or release lrcconf main power domain - */ -void nrf2_clock_request_lrcconf_poweron_main(struct nrf2_clock_lrcconf_sink *sink); -void nrf2_clock_release_lrcconf_poweron_main(struct nrf2_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 2ad0c773831..910c920bb17 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); @@ -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) { - nrf2_clock_request_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_request(&dev_data->lrcconf_sink.node, NRF_LRCCONF_POWER_MAIN); } NRF_LRCCONF010->CLKCTRL[0].SRC = mode; if (mode == FLL16M_MODE_DEFAULT) { - nrf2_clock_release_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_release(&dev_data->lrcconf_sink.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 1abe0c0cd67..44266fb71b0 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"); @@ -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); - nrf2_clock_request_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_request(&dev_data->lrcconf_sink.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); - nrf2_clock_release_lrcconf_poweron_main(&dev_data->lrcconf_sink); + soc_lrcconf_poweron_release(&dev_data->lrcconf_sink.node, NRF_LRCCONF_POWER_MAIN); notify(mgr, 0); } diff --git a/soc/nordic/common/soc_lrcconf.c b/soc/nordic/common/soc_lrcconf.c new file mode 100644 index 00000000000..24238c3c64f --- /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; +sys_slist_t poweron_main_list; +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/CMakeLists.txt b/soc/nordic/nrf54h/CMakeLists.txt index 0496841ffe7..8dde9fdbdae 100644 --- a/soc/nordic/nrf54h/CMakeLists.txt +++ b/soc/nordic/nrf54h/CMakeLists.txt @@ -3,6 +3,7 @@ if(CONFIG_ARM) zephyr_library_sources(soc.c) + zephyr_library_sources(../common/soc_lrcconf.c) if(CONFIG_PM OR CONFIG_POWEROFF) zephyr_library_sources(power.c) endif() diff --git a/soc/nordic/nrf54h/Kconfig b/soc/nordic/nrf54h/Kconfig index db62be6eb51..623c1db7f79 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 config SOC_NRF54H20_CPURAD select ARM diff --git a/soc/nordic/nrf54h/power.c b/soc/nordic/nrf54h/power.c index d55cd556e31..b444f1728c5 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 !IS_ENABLED(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 !IS_ENABLED(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 !IS_ENABLED(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(); @@ -77,12 +80,10 @@ static void sys_resume(void) sys_cache_data_enable(); } +#if !IS_ENABLED(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(); @@ -141,5 +140,22 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { +#if !IS_ENABLED(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 !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD) +void pm_state_enter_idle_prepare(void) +{ + soc_lrcconf_poweron_request(&pm_node, NRF_LRCCONF_POWER_DOMAIN_0); +} + +sys_snode_t *pm_sys_node_id_get(void) +{ + return &pm_node; +} +#endif diff --git a/soc/nordic/nrf54h/power.h b/soc/nordic/nrf54h/power.h index 021c20ec4dc..59224bff440 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,20 @@ */ void nrf_poweroff(void); +/** + * @brief Pepare to the idle state. + * + * This function applies required PM configuration must be performed before the idle state. + */ +void pm_state_enter_idle_prepare(void); + +/** + * @brief Get the ID of the node used by PM module. + * + * This function returns the node ID to be shared with other dependent modules. + * + * @return The pointer to the node assigned to PM module. + */ +sys_snode_t *pm_sys_node_id_get(void); + #endif /* _ZEPHYR_SOC_ARM_NORDIC_NRF_POWER_H_ */ diff --git a/soc/nordic/nrf54h/soc.c b/soc/nordic/nrf54h/soc.c index b93658b55d4..f2a97a16453 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 !(IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_POWEROFF)) +#if !IS_ENABLED(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,20 @@ 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 !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD) + sys_snode_t *node; +#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_POWEROFF) + node = pm_sys_node_id_get(); +#else + node = &soc_node; +#endif 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 /* !IS_ENABLED(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 +137,9 @@ bool z_arm_on_enter_cpu_idle(void) #ifdef CONFIG_LOG_FRONTEND_STMESP log_frontend_stmesp_pre_sleep(); #endif +#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_POWEROFF) + pm_state_enter_idle_prepare(); +#endif return true; }