Skip to content

Commit 3dd1d79

Browse files
committed
drivers: nrf_ironside dvfs service
Added handling of new IRONside DVFS service. NRFS DVFS is now not enabled by default. Signed-off-by: Łukasz Stępnicki <lukasz.stepnicki@nordicsemi.no>
1 parent 5e9a10c commit 3dd1d79

File tree

6 files changed

+272
-3
lines changed

6 files changed

+272
-3
lines changed

drivers/firmware/nrf_ironside/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CALL call.c)
77

88
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CPUCONF_SERVICE cpuconf.c)
99
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_UPDATE_SERVICE update.c)
10+
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_DVFS_SERVICE ironside_dvfs.c)

drivers/firmware/nrf_ironside/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,11 @@ config NRF_IRONSIDE_UPDATE_SERVICE
4343
help
4444
Service used to update the IRONside SE firmware.
4545

46+
config NRF_IRONSIDE_DVFS_SERVICE
47+
bool "IRONside DVFS service"
48+
depends on SOC_NRF54H20_CPUAPP
49+
select NRF_IRONSIDE_CALL
50+
help
51+
Service used to handle DVFS operating point requests.
52+
4653
endmenu
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
#include <hal/nrf_hsfll.h>
6+
#include <zephyr/kernel.h>
7+
8+
#include <zephyr/drivers/firmware/nrf_ironside/ironside_dvfs.h>
9+
#include <zephyr/drivers/firmware/nrf_ironside/call.h>
10+
11+
static volatile enum ironside_dvfs_oppoint current_dvfs_oppoint = IRONSIDE_DVFS_OPP_HIGH;
12+
static volatile enum ironside_dvfs_oppoint requested_dvfs_oppoint = IRONSIDE_DVFS_OPP_HIGH;
13+
K_MUTEX_DEFINE(ironside_dvfs_mutex);
14+
15+
struct dvfs_hsfll_data {
16+
uint32_t new_f_mult;
17+
uint32_t new_f_trim_entry;
18+
uint32_t max_hsfll_freq;
19+
};
20+
21+
static const struct dvfs_hsfll_data dvfs_hsfll_data[IRONSIDE_DVFS_OPP_COUNT] = {
22+
/* ABB oppoint 0.8V */
23+
{
24+
.new_f_mult = 20,
25+
.new_f_trim_entry = 0,
26+
.max_hsfll_freq = 320000000,
27+
},
28+
/* ABB oppoint 0.6V */
29+
{
30+
.new_f_mult = 8,
31+
.new_f_trim_entry = 2,
32+
.max_hsfll_freq = 128000000,
33+
},
34+
/* ABB oppoint 0.5V */
35+
{
36+
.new_f_mult = 4,
37+
.new_f_trim_entry = 3,
38+
.max_hsfll_freq = 64000000,
39+
},
40+
};
41+
42+
/**
43+
* @brief Check if the requested oppoint is allowed.
44+
*
45+
* @param freq_setting The requested oppoint to check.
46+
* @return true if the oppoint is allowed, false otherwise.
47+
*/
48+
static bool ironside_dvfs_opp_allowed(enum ironside_dvfs_oppoint freq_setting)
49+
{
50+
if (freq_setting == IRONSIDE_DVFS_OPP_HIGH || freq_setting == IRONSIDE_DVFS_OPP_MEDLOW ||
51+
freq_setting == IRONSIDE_DVFS_OPP_LOW) {
52+
return true;
53+
}
54+
55+
return false;
56+
}
57+
58+
/**
59+
* @brief Check if the requested oppoint change operation is downscaling.
60+
*
61+
* @param target_freq_setting The target oppoint to check.
62+
* @return true if the current oppoint is higher than the target, false otherwise.
63+
*/
64+
static bool ironside_dvfs_is_downscaling(enum ironside_dvfs_oppoint target_freq_setting)
65+
{
66+
return current_dvfs_oppoint < target_freq_setting;
67+
}
68+
69+
/**
70+
* @brief Configure hsfll depending on selected oppoint
71+
*
72+
* @param enum oppoint target operation point
73+
* @return 0 value indicates no error.
74+
* @return -EINVAL invalid oppoint or domain.
75+
*/
76+
static int32_t ironside_dvfs_configure_hsfll(enum ironside_dvfs_oppoint oppoint)
77+
{
78+
if (oppoint >= IRONSIDE_DVFS_OPP_COUNT) {
79+
return -EINVAL;
80+
}
81+
82+
nrf_hsfll_trim_t hsfll_trim = {};
83+
uint8_t freq_trim_idx = dvfs_hsfll_data[oppoint].new_f_trim_entry;
84+
85+
#if defined(NRF_APPLICATION)
86+
hsfll_trim.vsup = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.VSUP;
87+
hsfll_trim.coarse = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.COARSE[freq_trim_idx];
88+
hsfll_trim.fine = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.FINE[freq_trim_idx];
89+
#if NRF_HSFLL_HAS_TCOEF_TRIM
90+
hsfll_trim.tcoef = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.TCOEF;
91+
#endif
92+
#else
93+
/* Currently only application core is supported */
94+
return -EINVAL;
95+
#endif
96+
97+
nrf_hsfll_clkctrl_mult_set(NRF_HSFLL, dvfs_hsfll_data[oppoint].new_f_mult);
98+
nrf_hsfll_trim_set(NRF_HSFLL, &hsfll_trim);
99+
nrf_barrier_w();
100+
101+
nrf_hsfll_task_trigger(NRF_HSFLL, NRF_HSFLL_TASK_FREQ_CHANGE);
102+
/* Trigger hsfll task one more time, SEE PAC-4078 */
103+
nrf_hsfll_task_trigger(NRF_HSFLL, NRF_HSFLL_TASK_FREQ_CHANGE);
104+
105+
return 0;
106+
}
107+
108+
/* Function handling steps for DVFS oppoint change. */
109+
static int ironside_dvfs_prepare_to_scale(enum ironside_dvfs_oppoint freq_setting)
110+
{
111+
int err = 0;
112+
113+
if (ironside_dvfs_is_downscaling(freq_setting)) {
114+
err = ironside_dvfs_configure_hsfll(freq_setting);
115+
}
116+
117+
return err;
118+
}
119+
120+
/* Update MDK variable which is used by nrfx_coredep_delay_us (k_busy_wait). */
121+
static void ironside_dvfs_update_core_clock(enum ironside_dvfs_oppoint oppoint_freq)
122+
{
123+
extern uint32_t SystemCoreClock;
124+
125+
SystemCoreClock = dvfs_hsfll_data[oppoint_freq].max_hsfll_freq;
126+
}
127+
128+
/* Perform scaling finnish procedure. */
129+
static int ironside_dvfs_change_oppoint_complete(enum ironside_dvfs_oppoint dvfs_oppoint)
130+
{
131+
int err = 0;
132+
133+
if (!ironside_dvfs_is_downscaling(dvfs_oppoint)) {
134+
err = ironside_dvfs_configure_hsfll(dvfs_oppoint);
135+
}
136+
137+
current_dvfs_oppoint = dvfs_oppoint;
138+
ironside_dvfs_update_core_clock(dvfs_oppoint);
139+
140+
return err;
141+
}
142+
143+
/**
144+
* @brief Request DVFS oppoint change from IRONside secure domain.
145+
* This function will send a request over IPC to the IRONside secure domain
146+
* This function is synchronous and will return when the request is completed.
147+
*
148+
* @param oppoint @ref enum ironside_dvfs_oppoint
149+
* @return int
150+
*/
151+
static int ironside_dvfs_req_oppoint(enum ironside_dvfs_oppoint oppoint)
152+
{
153+
int err;
154+
155+
struct ironside_call_buf *const buf = ironside_call_alloc();
156+
157+
buf->id = IRONSIDE_CALL_ID_DVFS_SERVICE_V0;
158+
buf->args[IRONSIDE_DVFS_SERVICE_OPPOINT_IDX] = oppoint;
159+
160+
ironside_call_dispatch(buf);
161+
162+
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
163+
err = buf->args[IRONSIDE_DVFS_SERVICE_RETCODE_IDX];
164+
} else {
165+
err = buf->status;
166+
}
167+
168+
ironside_call_release(buf);
169+
170+
return err;
171+
}
172+
173+
int ironside_dvfs_change_oppoint(enum ironside_dvfs_oppoint dvfs_oppoint)
174+
{
175+
int status = 0;
176+
177+
if (!ironside_dvfs_opp_allowed(dvfs_oppoint)) {
178+
return -EINVAL;
179+
}
180+
181+
if (dvfs_oppoint == current_dvfs_oppoint) {
182+
return 0;
183+
}
184+
185+
if (!k_mutex_lock(&ironside_dvfs_mutex, K_MSEC(1000))) {
186+
requested_dvfs_oppoint = dvfs_oppoint;
187+
188+
ironside_dvfs_prepare_to_scale(requested_dvfs_oppoint);
189+
190+
status = ironside_dvfs_req_oppoint(requested_dvfs_oppoint);
191+
192+
if (status != 0) {
193+
k_mutex_unlock(&ironside_dvfs_mutex);
194+
return status;
195+
}
196+
status = ironside_dvfs_change_oppoint_complete(requested_dvfs_oppoint);
197+
k_mutex_unlock(&ironside_dvfs_mutex);
198+
} else {
199+
return -EBUSY;
200+
}
201+
202+
return status;
203+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_IRONSIDE_DVFS_H_
7+
#define ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_IRONSIDE_DVFS_H_
8+
9+
#include <stdint.h>
10+
#include <stddef.h>
11+
#include <errno.h>
12+
13+
enum ironside_dvfs_oppoint {
14+
IRONSIDE_DVFS_OPP_HIGH = 0,
15+
IRONSIDE_DVFS_OPP_MEDLOW = 1,
16+
IRONSIDE_DVFS_OPP_LOW = 2,
17+
IRONSIDE_DVFS_OPP_COUNT
18+
};
19+
20+
/**
21+
* @name IRONside DVFS service error codes.
22+
* @{
23+
*/
24+
25+
/** The requested DVFS oppoint is not allowed. */
26+
#define IRONSIDE_DVFS_ERROR_WRONG_OPPOINT (EINVAL)
27+
/** Waiting for mutex lock timed out, or hardware is busy. */
28+
#define IRONSIDE_DVFS_ERROR_BUSY (EBUSY)
29+
/** There is configuration error in the DVFS service. */
30+
#define IRONSIDE_DVFS_ERROR_OPPOINT_DATA (ECANCELED)
31+
32+
/**
33+
* @}
34+
*/
35+
36+
/* IRONside call identifiers with implicit versions.
37+
*
38+
* With the initial "version 0", the service ABI is allowed to break until the
39+
* first production release of IRONside SE.
40+
*/
41+
#define IRONSIDE_CALL_ID_DVFS_SERVICE_V0 3
42+
43+
/* Index of the DVFS oppoint within the service buffer. */
44+
#define IRONSIDE_DVFS_SERVICE_OPPOINT_IDX (0)
45+
/* Index of the return code within the service buffer. */
46+
#define IRONSIDE_DVFS_SERVICE_RETCODE_IDX (0)
47+
48+
/**
49+
* @brief Change the current DVFS oppoint.
50+
*
51+
* This function will request a change of the current DVFS oppoint to the
52+
* specified value. It will block until the change is applied.
53+
*
54+
* @param dvfs_oppoint The new DVFS oppoint to set.
55+
* @return int 0 on success, negative error code on failure.
56+
*/
57+
int ironside_dvfs_change_oppoint(enum ironside_dvfs_oppoint dvfs_oppoint);
58+
59+
#endif /* ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_IRONSIDE_DVFS_H_ */

modules/hal_nordic/nrfs/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ if(CONFIG_NRFS)
1414

1515
zephyr_include_directories(${INC_DIR})
1616
zephyr_include_directories(${INC_DIR}/services)
17-
zephyr_include_directories(${HELPERS_DIR})
17+
zephyr_include_directories_ifdef(CONFIG_NRFS_HAS_DVFS_SERVICE ${HELPERS_DIR})
1818
zephyr_include_directories(.)
1919
zephyr_include_directories(${CMAKE_CURRENT_SOURCE_DIR}/backends)
2020
zephyr_include_directories_ifdef(CONFIG_NRFS_DVFS_LOCAL_DOMAIN ${CMAKE_CURRENT_SOURCE_DIR}/dvfs)
2121

22-
zephyr_library_sources(${HELPERS_DIR}/dvfs_oppoint.c)
22+
zephyr_library_sources_ifdef(CONFIG_NRFS_HAS_DVFS_SERVICE ${HELPERS_DIR}/dvfs_oppoint.c)
2323

2424
if(CONFIG_NRFS_LOCAL_DOMAIN)
2525
zephyr_library_sources_ifdef(CONFIG_NRFS_AUDIOPLL_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_audiopll.c)

soc/nordic/nrf54h/Kconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ config SOC_NRF54H20_CPUAPP_COMMON
2828
select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE
2929
select NRFS_HAS_AUDIOPLL_SERVICE
3030
select NRFS_HAS_CLOCK_SERVICE
31-
select NRFS_HAS_DVFS_SERVICE
3231
select NRFS_HAS_GDFS_SERVICE
3332
select NRFS_HAS_GDPWR_SERVICE
3433
select NRFS_HAS_MRAM_SERVICE

0 commit comments

Comments
 (0)