Skip to content

Commit

Permalink
[nrf noup] soc: nordic: Add LRCCONF management
Browse files Browse the repository at this point in the history
Due to the possibility of simultaneous accesess to LRCCONF registers,
additional management is required.

Signed-off-by: Adam Kondraciuk <[email protected]>
  • Loading branch information
adamkondraciuk committed Sep 25, 2024
1 parent ace7017 commit ab8772c
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 60 deletions.
34 changes: 0 additions & 34 deletions drivers/clock_control/clock_control_nrf2_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}
6 changes: 0 additions & 6 deletions drivers/clock_control/clock_control_nrf2_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
6 changes: 3 additions & 3 deletions drivers/clock_control/clock_control_nrf2_fll16m.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "clock_control_nrf2_common.h"
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <hal/nrf_lrcconf.h>
#include <soc/nordic/common/soc_lrcconf.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions drivers/clock_control/clock_control_nrf2_hfxo.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

#include <hal/nrf_lrcconf.h>
#include <soc/nordic/common/soc_lrcconf.h>

BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
"multiple instances not supported");
Expand Down Expand Up @@ -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
Expand All @@ -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);
}

Expand Down
63 changes: 63 additions & 0 deletions soc/nordic/common/soc_lrcconf.c
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;
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) {

Check failure on line 21 in soc/nordic/common/soc_lrcconf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

soc/nordic/common/soc_lrcconf.c:21 space required before the open parenthesis '('
poweron_list = &poweron_main_list;
} else if(domain == NRF_LRCCONF_POWER_DOMAIN_0) {

Check failure on line 23 in soc/nordic/common/soc_lrcconf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

soc/nordic/common/soc_lrcconf.c:23 space required before the open parenthesis '('
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) {

Check failure on line 45 in soc/nordic/common/soc_lrcconf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

soc/nordic/common/soc_lrcconf.c:45 space required before the open parenthesis '('
poweron_list = &poweron_main_list;
} else if(domain == NRF_LRCCONF_POWER_DOMAIN_0) {

Check failure on line 47 in soc/nordic/common/soc_lrcconf.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACING

soc/nordic/common/soc_lrcconf.c:47 space required before the open parenthesis '('
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 changes: 34 additions & 0 deletions soc/nordic/common/soc_lrcconf.h
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.

Check warning on line 20 in soc/nordic/common/soc_lrcconf.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACE_BEFORE_TAB

soc/nordic/common/soc_lrcconf.h:20 please, no space before tabs
* @param domain The ID of the domain to be forced power-on.
*/
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.

Check warning on line 29 in soc/nordic/common/soc_lrcconf.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

SPACE_BEFORE_TAB

soc/nordic/common/soc_lrcconf.h:29 please, no space before tabs
* @param domain The ID of the domain for which force power-on is no longer needed.
*/
void soc_lrcconf_poweron_release(sys_snode_t *node, nrf_lrcconf_power_domain_mask_t domain);

#endif /* ZEPHYR_SOC_NORDIC_COMMON_LRCCONF_H_ */
1 change: 1 addition & 0 deletions soc/nordic/nrf54h/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
41 changes: 34 additions & 7 deletions soc/nordic/nrf54h/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)
static sys_snode_t pm_node;
#endif

static void suspend_common(void)
{

Expand All @@ -31,20 +35,24 @@ 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);

/* 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);
soc_lrcconf_poweron_release(&pm_node, NRF_LRCCONF_POWER_MAIN);
soc_lrcconf_poweron_release(&pm_node, NRF_LRCCONF_POWER_DOMAIN_0);
#endif
}

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);
#endif

suspend_common();

Expand Down Expand Up @@ -76,12 +84,14 @@ 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));
soc_lrcconf_poweron_request(&pm_node, NRF_LRCCONF_POWER_MAIN);
soc_lrcconf_poweron_request(&pm_node, NRF_LRCCONF_POWER_DOMAIN_0);
#endif
}

/* Function called during local domain suspend to RAM. */
Expand Down Expand Up @@ -138,8 +148,25 @@ 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 (state == PM_STATE_SUSPEND_TO_IDLE && !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)) {
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false);
#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);
}


void pm_state_enter_idle_prepare(void)
{
#if !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)
soc_lrcconf_poweron_request(&pm_node, NRF_LRCCONF_POWER_DOMAIN_0);
#endif
}

#if !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)
sys_snode_t *pm_sys_node_id_get(void)
{
return &pm_node;
}
#endif
18 changes: 18 additions & 0 deletions soc/nordic/nrf54h/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,29 @@
#ifndef _ZEPHYR_SOC_ARM_NORDIC_NRF_POWER_H_
#define _ZEPHYR_SOC_ARM_NORDIC_NRF_POWER_H_

#include <zephyr/sys/slist.h>

/**
* @brief Perform a power off.
*
* This function performs a power off of the core.
*/
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_ */
32 changes: 25 additions & 7 deletions soc/nordic/nrf54h/soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
#include <hal/nrf_spu.h>
#include <hal/nrf_memconf.h>
#include <soc/nrfx_coredep.h>
#include <soc_lrcconf.h>
#include <dmm.h>
#include "power.h"

LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);

Expand All @@ -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)
Expand All @@ -52,13 +60,22 @@ 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
soc_lrcconf_poweron_request(node, NRF_LRCCONF_POWER_DOMAIN_0);
soc_lrcconf_poweron_request(node, NRF_LRCCONF_POWER_MAIN);
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);
Expand Down Expand Up @@ -122,8 +139,9 @@ bool z_arm_on_enter_cpu_idle(void)
#ifdef CONFIG_LOG_FRONTEND_STMESP
log_frontend_stmesp_pre_sleep();
#endif
nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0,
!IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD));
#if IS_ENABLED(CONFIG_PM) || IS_ENABLED(CONFIG_POWEROFF)
pm_state_enter_idle_prepare();
#endif

return true;
}
Expand Down

0 comments on commit ab8772c

Please sign in to comment.