Skip to content

Commit 29dba32

Browse files
committed
dvfs: move functionality to secdom core.
All voltage scaling can be done using secdom core. This is optimization to simplify DVFS service and save memory space. Signed-off-by: Łukasz Stępnicki <[email protected]>
1 parent e48bca4 commit 29dba32

File tree

6 files changed

+361
-1
lines changed

6 files changed

+361
-1
lines changed

modules/hal_nordic/nrfs/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ if(CONFIG_NRFS)
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)
21+
zephyr_include_directories_ifdef(CONFIG_NRFS_DVFS_NEW_LOCAL_DOMAIN ${CMAKE_CURRENT_SOURCE_DIR}/dvfs_new)
2122

2223
zephyr_library_sources(${HELPERS_DIR}/dvfs_oppoint.c)
2324

@@ -36,6 +37,7 @@ if(CONFIG_NRFS)
3637
zephyr_library_sources_ifdef(CONFIG_NRFS_VBUS_DETECTOR_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_usb.c)
3738
zephyr_library_sources(${SRC_DIR}/internal/nrfs_dispatcher.c)
3839
add_subdirectory_ifdef(CONFIG_NRFS_DVFS_LOCAL_DOMAIN dvfs)
40+
add_subdirectory_ifdef(CONFIG_NRFS_DVFS_NEW_LOCAL_DOMAIN dvfs_new)
3941

4042
if(CONFIG_NRFS_DIAG_SERVICE_ENABLED)
4143
message(WARNING "This service is for Nordic Semiconductor INTERNAL purposes ONLY. Use it with caution due to risk of hardware damage!")

modules/hal_nordic/nrfs/Kconfig

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ config NRFS_DVFS_LOCAL_DOMAIN
7474
depends on NRFS_DVFS_SERVICE_ENABLED
7575
default y if NRFS_DVFS_SERVICE_ENABLED
7676

77+
config NRFS_DVFS_NEW_LOCAL_DOMAIN
78+
bool "Local domain that supports DVFS without sysctrl"
79+
depends on NRFS_LOCAL_DOMAIN
80+
default y if SOC_NRF54H20_CPUAPP
81+
7782
menu "Enabled Services"
7883

7984
module = NRFS
@@ -110,7 +115,7 @@ config NRFS_PMIC_SERVICE_ENABLED
110115
config NRFS_DVFS_SERVICE_ENABLED
111116
bool "DVFS service"
112117
depends on NRFS_HAS_DVFS_SERVICE
113-
default y if SOC_NRF54H20_CPUAPP || SOC_NRF9280_CPUAPP
118+
default y if SOC_NRF9280_CPUAPP
114119

115120
config NRFS_DIAG_SERVICE_ENABLED
116121
bool "System Diagnostics service (only for development purposes)"
@@ -148,5 +153,9 @@ if NRFS_DVFS_LOCAL_DOMAIN
148153
rsource "dvfs/Kconfig"
149154
endif # NRFS_DVFS_LOCAL_DOMAIN
150155

156+
if NRFS_DVFS_NEW_LOCAL_DOMAIN
157+
rsource "dvfs_new/Kconfig"
158+
endif # NRFS_DVFS_NEW_LOCAL_DOMAIN
159+
151160
endif # NRFS
152161
endmenu
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) 2024 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
zephyr_library_sources_ifdef(CONFIG_NRFS_DVFS_NEW_LOCAL_DOMAIN ld_dvfs_handler.c)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
menu "Local domain DVFS library"
8+
9+
module = LOCAL_DOMAIN_DVFS_NEW_LIB
10+
module-str = Local domain DVFS library
11+
source "subsys/logging/Kconfig.template.log_config"
12+
13+
config NRFS_LOCAL_DOMAIN_DVFS_TEST
14+
bool "Local domain DVFS test"
15+
help
16+
Disable hw registers interaction for testing.
17+
18+
config NRFS_LOCAL_DOMAIN_DVFS_SCALE_DOWN_AFTER_INIT
19+
bool "Local domain scale down after init"
20+
help
21+
Request lowest oppoint after DVFS initialization.
22+
23+
config NRFS_LOCAL_DOMAIN_DOWNSCALE_SAFETY_TIMEOUT_US
24+
int "Voltage downscale procedure safety timeout in us"
25+
range 1 10000000
26+
default 1000000 if (NRFS_LOCAL_DOMAIN_DVFS_TEST || LOG)
27+
default 1500
28+
29+
config NRFS_LOCAL_DOMAIN_DOWNSCALE_FINISH_DELAY_TIMEOUT_US
30+
int "Additional delay to let secdom finish dowscale procedure in us"
31+
range 1 10000000
32+
default 1000
33+
help
34+
This value depends on the secdom core performance and shouldn't be touched by the user.
35+
36+
endmenu
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "ld_dvfs_handler.h"
8+
9+
#include <hal/nrf_hsfll.h>
10+
#include <dvfs_oppoint.h>
11+
//#include <nrfs_dvfs.h>
12+
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/logging/log.h>
15+
LOG_MODULE_REGISTER(LD_DVFS_NEW_LIB, CONFIG_LOCAL_DOMAIN_DVFS_NEW_LIB_LOG_LEVEL);
16+
17+
/*TODO: get rid of nrfs dependency, oppoint*/
18+
#include <sdfw/sdfw_services/dvfs_service.h>
19+
20+
static volatile enum dvfs_frequency_setting current_freq_setting;
21+
static volatile enum dvfs_frequency_setting requested_freq_setting;
22+
static dvfs_service_handler_callback dvfs_frequency_change_applied_clb;
23+
24+
/*
25+
* wait max 500ms with 10us intervals for hsfll freq change event
26+
*/
27+
#define HSFLL_FREQ_CHANGE_MAX_DELAY_MS 500UL
28+
#define HSFLL_FREQ_CHANGE_CHECK_INTERVAL_US 10
29+
#define HSFLL_FREQ_CHANGE_CHECK_MAX_ATTEMPTS \
30+
((HSFLL_FREQ_CHANGE_MAX_DELAY_MS) * (USEC_PER_MSEC) / (HSFLL_FREQ_CHANGE_CHECK_INTERVAL_US))
31+
32+
/**
33+
* @brief Configure hsfll depending on selected oppoint
34+
*
35+
* @param enum oppoint target operation point
36+
* @return 0 value indicates no error.
37+
* @return -EINVAL invalid oppoint or domain.
38+
* @return -ETIMEDOUT frequency change took more than HSFLL_FREQ_CHANGE_MAX_DELAY_MS
39+
*/
40+
static int32_t ld_dvfs_configure_hsfll(enum dvfs_frequency_setting oppoint)
41+
{
42+
nrf_hsfll_trim_t hsfll_trim = {};
43+
44+
if (oppoint >= DVFS_FREQ_COUNT) {
45+
LOG_ERR("Not valid oppoint %d", oppoint);
46+
return -EINVAL;
47+
}
48+
49+
uint8_t freq_trim = get_dvfs_oppoint_data(oppoint)->new_f_trim_entry;
50+
51+
#if defined(NRF_APPLICATION)
52+
hsfll_trim.vsup = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.VSUP;
53+
hsfll_trim.coarse = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.COARSE[freq_trim];
54+
hsfll_trim.fine = NRF_FICR->TRIM.APPLICATION.HSFLL.TRIM.FINE[freq_trim];
55+
#else
56+
hsfll_trim.vsup = NRF_FICR->TRIM.SECURE.HSFLL.TRIM.VSUP;
57+
hsfll_trim.coarse = NRF_FICR->TRIM.SECURE.HSFLL.TRIM.COARSE[freq_trim];
58+
hsfll_trim.fine = NRF_FICR->TRIM.SECURE.HSFLL.TRIM.FINE[freq_trim];
59+
#endif
60+
61+
#if defined(CONFIG_NRFS_LOCAL_DOMAIN_DVFS_TEST)
62+
LOG_DBG("%s oppoint: %d", __func__, oppoint);
63+
LOG_DBG("REGW: NRF_HSFLL->MIRROR 0x%x, V: 0x%x", (uint32_t)&NRF_HSFLL->MIRROR, 1);
64+
LOG_DBG("REGW: NRF_HSFLL->TRIM.COARSE 0x%x, V: 0x%x",
65+
(uint32_t)&NRF_HSFLL->TRIM.COARSE,
66+
hsfll_trim.coarse);
67+
LOG_DBG("REGW: NRF_HSFLL->TRIM.FINE 0x%x, V: 0x%x",
68+
(uint32_t)&NRF_HSFLL->TRIM.FINE,
69+
hsfll_trim.fine);
70+
LOG_DBG("REGW: NRF_HSFLL->MIRROR 0x%x, V: 0x%x", (uint32_t)&NRF_HSFLL->MIRROR, 0);
71+
72+
LOG_DBG("REGW: NRF_HSFLL->CLOCKCTRL.MULT 0x%x, V: 0x%x",
73+
(uint32_t)&NRF_HSFLL->CLOCKCTRL.MULT,
74+
get_dvfs_oppoint_data(oppoint)->new_f_mult);
75+
76+
LOG_DBG("REGW: NRF_HSFLL->NRF_HSFLL_TASK_FREQ_CHANGE 0x%x, V: 0x%x",
77+
(uint32_t)NRF_HSFLL + NRF_HSFLL_TASK_FREQ_CHANGE,
78+
0x1);
79+
return 0;
80+
#else
81+
82+
nrf_hsfll_trim_set(NRF_HSFLL, &hsfll_trim);
83+
nrf_barrier_w();
84+
85+
nrf_hsfll_clkctrl_mult_set(NRF_HSFLL, get_dvfs_oppoint_data(oppoint)->new_f_mult);
86+
nrf_hsfll_task_trigger(NRF_HSFLL, NRF_HSFLL_TASK_FREQ_CHANGE);
87+
/* Trigger hsfll task one more time, SEE PAC-4078 */
88+
nrf_hsfll_task_trigger(NRF_HSFLL, NRF_HSFLL_TASK_FREQ_CHANGE);
89+
90+
bool hsfll_freq_changed = false;
91+
92+
NRFX_WAIT_FOR(nrf_hsfll_event_check(NRF_HSFLL, NRF_HSFLL_EVENT_FREQ_CHANGED),
93+
HSFLL_FREQ_CHANGE_CHECK_MAX_ATTEMPTS,
94+
HSFLL_FREQ_CHANGE_CHECK_INTERVAL_US,
95+
hsfll_freq_changed);
96+
97+
if (hsfll_freq_changed) {
98+
return 0;
99+
}
100+
101+
return -ETIMEDOUT;
102+
#endif
103+
}
104+
105+
106+
static enum dvfs_frequency_setting dvfs_service_handler_get_current_oppoint(void)
107+
{
108+
LOG_DBG("Current LD freq setting: %d", current_freq_setting);
109+
return current_freq_setting;
110+
}
111+
112+
static void dvfs_service_handler_error(int err)
113+
{
114+
if (err != 0) {
115+
LOG_ERR("Failed with error: %d", err);
116+
}
117+
}
118+
119+
static bool dvfs_service_handler_freq_setting_allowed(enum dvfs_frequency_setting freq_setting)
120+
{
121+
if (freq_setting == DVFS_FREQ_HIGH || freq_setting == DVFS_FREQ_MEDLOW ||
122+
freq_setting == DVFS_FREQ_LOW) {
123+
return true;
124+
}
125+
126+
return false;
127+
}
128+
129+
/* Function to check if current operation is down-scaling */
130+
static bool dvfs_service_handler_is_downscaling(enum dvfs_frequency_setting target_freq_setting)
131+
{
132+
if (dvfs_service_handler_freq_setting_allowed(target_freq_setting)) {
133+
LOG_DBG("Checking if downscaling %s",
134+
(dvfs_service_handler_get_current_oppoint() < target_freq_setting) ? "YES" :
135+
"NO");
136+
return dvfs_service_handler_get_current_oppoint() < target_freq_setting;
137+
}
138+
139+
return false;
140+
}
141+
142+
/* Function handling steps for scaling preparation. */
143+
static void dvfs_service_handler_prepare_to_scale(enum dvfs_frequency_setting oppoint_freq)
144+
{
145+
LOG_DBG("Prepare to scale, oppoint freq %d", oppoint_freq);
146+
enum dvfs_frequency_setting new_oppoint = oppoint_freq;
147+
enum dvfs_frequency_setting current_oppoint = dvfs_service_handler_get_current_oppoint();
148+
149+
if (new_oppoint == current_oppoint) {
150+
LOG_DBG("New oppoint is same as previous, no change");
151+
} else {
152+
153+
if (dvfs_service_handler_is_downscaling(new_oppoint)) {
154+
int32_t err = ld_dvfs_configure_hsfll(new_oppoint);
155+
156+
if (err != 0) {
157+
dvfs_service_handler_error(err);
158+
}
159+
}
160+
}
161+
}
162+
163+
/* Function to set hsfll to highest frequency when switched to ABB. */
164+
static int32_t dvfs_service_handler_set_initial_hsfll_config(void)
165+
{
166+
int32_t err = ld_dvfs_configure_hsfll(DVFS_FREQ_HIGH);
167+
168+
current_freq_setting = DVFS_FREQ_HIGH;
169+
requested_freq_setting = DVFS_FREQ_HIGH;
170+
if (err != 0) {
171+
dvfs_service_handler_error(err);
172+
}
173+
174+
return err;
175+
}
176+
177+
static int ld_dvfs_handler_init(void)
178+
{
179+
LOG_DBG("LD DVFS handler init");
180+
int32_t err = dvfs_service_handler_set_initial_hsfll_config();
181+
182+
return err;
183+
}
184+
SYS_INIT(ld_dvfs_handler_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
185+
186+
/* Update MDK variable which is used by nrfx_coredep_delay_us (k_busy_wait). */
187+
static void dvfs_service_update_core_clock(enum dvfs_frequency_setting oppoint_freq)
188+
{
189+
extern uint32_t SystemCoreClock;
190+
191+
SystemCoreClock = oppoint_freq == DVFS_FREQ_HIGH ? 320000000 :
192+
oppoint_freq == DVFS_FREQ_MEDLOW ? 128000000 : 64000000;
193+
}
194+
195+
/* Perform scaling finnish procedure. */
196+
static void dvfs_service_handler_scaling_finish(enum dvfs_frequency_setting oppoint_freq)
197+
{
198+
199+
LOG_DBG("Scaling finnish oppoint freq %d", oppoint_freq);
200+
if (!dvfs_service_handler_is_downscaling(oppoint_freq)) {
201+
int32_t err = ld_dvfs_configure_hsfll(oppoint_freq);
202+
203+
if (err != 0) {
204+
dvfs_service_handler_error(err);
205+
}
206+
}
207+
208+
current_freq_setting = oppoint_freq;
209+
dvfs_service_update_core_clock(oppoint_freq);
210+
LOG_DBG("Current LD freq setting: %d", current_freq_setting);
211+
if (dvfs_frequency_change_applied_clb) {
212+
dvfs_frequency_change_applied_clb(current_freq_setting);
213+
}
214+
}
215+
216+
int32_t dvfs_service_handler_change_freq_setting(enum dvfs_frequency_setting freq_setting)
217+
{
218+
static bool change_in_progress = false;
219+
if (change_in_progress) {
220+
LOG_ERR("Change in progress, please wait.");
221+
return -EBUSY;
222+
}
223+
224+
if (!dvfs_service_handler_freq_setting_allowed(freq_setting)) {
225+
LOG_ERR("Requested frequency setting %d not supported.", freq_setting);
226+
return -ENXIO;
227+
}
228+
229+
if(freq_setting == current_freq_setting) {
230+
LOG_DBG("Requested frequency setting %d is same as current.", freq_setting);
231+
return 0;
232+
}
233+
234+
change_in_progress = true;
235+
236+
requested_freq_setting = freq_setting;
237+
238+
dvfs_service_handler_prepare_to_scale(requested_freq_setting);
239+
240+
int status = ssf_dvfs_set_oppoint(requested_freq_setting);
241+
242+
if (status != 0) {
243+
LOG_ERR("Failed to set DVFS frequency: %d", status);
244+
return status;
245+
}
246+
247+
dvfs_service_handler_scaling_finish(requested_freq_setting);
248+
249+
change_in_progress = false;
250+
251+
return 0;
252+
}
253+
254+
void dvfs_service_handler_register_freq_setting_applied_callback(dvfs_service_handler_callback clb)
255+
{
256+
if (clb) {
257+
LOG_DBG("Registered frequency applied callback");
258+
dvfs_frequency_change_applied_clb = clb;
259+
} else {
260+
LOG_ERR("Invalid callback function provided!");
261+
}
262+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef LD_DVFS_HANDLER_H
7+
#define LD_DVFS_HANDLER_H
8+
9+
#include <dvfs_oppoint.h>
10+
#include <stdint.h>
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
/**
17+
* @brief Function to request LD frequency change.
18+
*
19+
* @param frequency requested frequency setting from enum dvfs_frequency_setting.
20+
* @return EBUSY Frequency change request pending.
21+
* @return EAGAIN DVFS init in progress.
22+
* @return ENXIO Not supported frequency settings.
23+
* @return NRFS_SUCCESS Request sent successfully.
24+
* @return NRFS_ERR_INVALID_STATE Service is uninitialized.
25+
* @return NRFS_ERR_IPC Backend returned error during request sending.
26+
*/
27+
int32_t dvfs_service_handler_change_freq_setting(enum dvfs_frequency_setting freq_setting);
28+
29+
/**
30+
* @brief Type to use as callback function in dvfs service
31+
*
32+
* @param new_setting applied frequency setting
33+
*/
34+
typedef void (*dvfs_service_handler_callback)(enum dvfs_frequency_setting new_setting);
35+
36+
/**
37+
* @brief Register callback function which will be called when new dvfs frequency is applied.
38+
*
39+
* @param clb dvfs_service_handler_callback to register
40+
*/
41+
void dvfs_service_handler_register_freq_setting_applied_callback(dvfs_service_handler_callback clb);
42+
43+
#ifdef __cplusplus
44+
}
45+
#endif
46+
47+
#endif /* LD_DVFS_HANDLER_H */

0 commit comments

Comments
 (0)