soc: nordic: Add LRCCONF management
Due to the possibility of simultaneous accesess to LRCCONF registers, additional management is required. Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
This commit is contained in:
parent
d5262b2113
commit
9b252855fd
9 changed files with 220 additions and 117 deletions
|
@ -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)
|
||||
|
|
62
soc/nordic/common/soc_lrcconf.c
Normal file
62
soc/nordic/common/soc_lrcconf.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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)
|
||||
{
|
||||
__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);
|
||||
}
|
||||
}
|
34
soc/nordic/common/soc_lrcconf.h
Normal file
34
soc/nordic/common/soc_lrcconf.h
Normal file
|
@ -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_ */
|
|
@ -9,20 +9,24 @@
|
|||
#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 "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,37 +35,10 @@ 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);
|
||||
}
|
||||
|
||||
void nrf_poweroff(void)
|
||||
{
|
||||
nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, 0);
|
||||
nrf_resetinfo_restore_valid_set(NRF_RESETINFO, false);
|
||||
|
||||
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_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY);
|
||||
|
||||
__set_BASEPRI(0);
|
||||
__ISB();
|
||||
__DSB();
|
||||
__WFI();
|
||||
|
||||
CODE_UNREACHABLE;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_PM_S2RAM)
|
||||
/* Resume domain after local suspend to RAM. */
|
||||
static void sys_resume(void)
|
||||
static void common_resume(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_ICACHE)) {
|
||||
/* Power up and re-enable ICACHE */
|
||||
|
@ -77,12 +54,82 @@ static void sys_resume(void)
|
|||
sys_cache_data_enable();
|
||||
}
|
||||
|
||||
soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY);
|
||||
|
||||
__set_BASEPRI(0);
|
||||
__ISB();
|
||||
__DSB();
|
||||
__WFI();
|
||||
|
||||
CODE_UNREACHABLE;
|
||||
}
|
||||
|
||||
static void s2idle_enter(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. */
|
||||
#if !defined(CONFIG_SOC_NRF54H20_CPURAD)
|
||||
soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_MAIN);
|
||||
#endif
|
||||
common_suspend();
|
||||
break;
|
||||
default: /* Unknown substate. */
|
||||
return;
|
||||
}
|
||||
|
||||
__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)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <hal/nrf_spu.h>
|
||||
#include <hal/nrf_memconf.h>
|
||||
#include <soc/nrfx_coredep.h>
|
||||
#include <soc_lrcconf.h>
|
||||
#include <dmm.h>
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue