-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
soc: nordic: Add LRCCONF management #79067
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Copyright (c) 2024 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <soc_lrcconf.h> | ||
#include <zephyr/kernel.h> | ||
|
||
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason why simple reference counter is not used here? I only see that the difference is that you keep list of clients (but its not used anywhere) and allow to have non-symmetric requests (second request from the same client is not counted) but it can potentially cause some issues. Reference counter would be simpler and use less resources. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At least right now there is non-symmetric requests so it couldn't be dropped |
||
{ | ||
__ASSERT(is_power_of_two(domain), | ||
"Only one bit can be set for the domain parameter"); | ||
|
||
Check notice on line 18 in soc/nordic/common/soc_lrcconf.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||
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"); | ||
|
||
Check notice on line 42 in soc/nordic/common/soc_lrcconf.c GitHub Actions / Run compliance checks on patch series (PR)You may want to run clang-format on this change
|
||
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); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <hal/nrf_lrcconf.h> | ||
|
||
/** | ||
* @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_ */ |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -9,12 +9,16 @@ | |||
#include <zephyr/pm/policy.h> | ||||
#include <zephyr/arch/common/pm_s2ram.h> | ||||
#include <hal/nrf_resetinfo.h> | ||||
#include <hal/nrf_lrcconf.h> | ||||
#include <hal/nrf_memconf.h> | ||||
#include <zephyr/cache.h> | ||||
#include <power.h> | ||||
#include <soc_lrcconf.h> | ||||
#include "pm_s2ram.h" | ||||
|
||||
#if !defined(CONFIG_SOC_NRF54H20_CPURAD) | ||||
static sys_snode_t pm_node; | ||||
#endif | ||||
|
||||
static void suspend_common(void) | ||||
{ | ||||
|
||||
|
@@ -31,21 +35,20 @@ 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) | ||||
{ | ||||
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,20 +125,32 @@ 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) | ||||
{ | ||||
if (state != PM_STATE_SUSPEND_TO_RAM) { | ||||
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); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only releases the poweron request when This is still way better than losing power, but needs to be followed up to have all paths covered eventually There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a mechanism to supply an exit hook on arm cores Line 56 in abd9008
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is this mechanism but it is quite ugly and requires special header with a macro. It was added as a workaround for PAN where code need to be executed immediately after WFI (so function cannot be used). I have #71667 which adds function hook symmetric to on_enter hook but PR stuck. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe your PR would have a clean usecase now and it could be argued for again to avoid that assembly mess? |
||||
} | ||||
#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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove also the
struct clock_lrcconf_sink
definition. There is no need to keep it as it can be replaced with justsys_snode_t
.