Skip to content

Commit 81e9846

Browse files
zyczrlubos
authored andcommitted
applications: nrf_desktop: Use clock api for DVFS
Use clock api in nrf_desktop dvfs module. Use notification handler to notify correct completion of DVFS. JIRA: NCSDK-29351 Signed-off-by: Jan Zyczkowski <[email protected]>
1 parent fa50704 commit 81e9846

File tree

3 files changed

+188
-58
lines changed

3 files changed

+188
-58
lines changed

applications/nrf_desktop/configuration/nrf54h20dk_nrf54h20_cpuapp/app.overlay

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
in-polling-period-us = <125>;
6060
in-report-size = <64>;
6161
};
62+
63+
aliases {
64+
nrfdesktop-dvfs-clock = &cpuapp_hsfll;
65+
};
6266
};
6367

6468
&cpusec_cpuapp_ipc {

applications/nrf_desktop/src/modules/Kconfig.dvfs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,28 @@
77
menuconfig DESKTOP_DVFS
88
bool "DVFS module"
99
depends on SOC_NRF54H20_CPUAPP
10+
select NRFS_DVFS_SERVICE_ENABLED
11+
select CLOCK_CONTROL
12+
select CLOCK_CONTROL_NRF2
1013
default y
1114
help
1215
This option enable DVFS module which switches frequency and voltage according
1316
to application needs.
1417

1518
if DESKTOP_DVFS
1619

20+
config DESKTOP_DVFS_FREQ_HIGH
21+
int
22+
default 320000000
23+
24+
config DESKTOP_DVFS_FREQ_MED
25+
int
26+
default 128000000
27+
28+
config DESKTOP_DVFS_FREQ_LOW
29+
int
30+
default 64000000
31+
1732
config DESKTOP_DVFS_RETRY_BUSY_TIMEOUT_MS
1833
int "Retry timeout"
1934
default 1

applications/nrf_desktop/src/modules/dvfs.c

Lines changed: 169 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,28 @@
1616
#include <zephyr/logging/log.h>
1717
LOG_MODULE_REGISTER(MODULE, CONFIG_DESKTOP_DVFS_LOG_LEVEL);
1818

19-
#include <ld_dvfs_handler.h>
19+
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
20+
#include <zephyr/devicetree.h>
21+
22+
#define CLOCK_NODE DT_ALIAS(nrfdesktop_dvfs_clock)
23+
24+
#if !DT_NODE_HAS_STATUS(CLOCK_NODE, okay)
25+
#error "Alias 'nrfdesktop-dvfs-clock' is not defined in the device tree!"
26+
#endif
27+
28+
static const struct device *dvfs_clock_dev = DEVICE_DT_GET(CLOCK_NODE);
29+
static struct onoff_client cli;
30+
31+
/* The used nrf_clock_control driver implementation does not support
32+
* clock precision and clock accuracy ppm.
33+
*/
34+
#define DESKTOP_DVFS_CLOCK_PRECISION 0
35+
#define DESKTOP_DVFS_CLOCK_ACCURACY_PPM 0
36+
37+
static struct nrf_clock_spec spec = {
38+
.accuracy = DESKTOP_DVFS_CLOCK_ACCURACY_PPM,
39+
.precision = DESKTOP_DVFS_CLOCK_PRECISION,
40+
};
2041

2142
#define DVFS_RETRY_INITIALIZATION_TIMEOUT K_MSEC(CONFIG_DESKTOP_DVFS_RETRY_INIT_TIMEOUT_MS)
2243
#define DVFS_RETRY_BUSY_TIMEOUT K_MSEC(CONFIG_DESKTOP_DVFS_RETRY_BUSY_TIMEOUT_MS)
@@ -66,16 +87,33 @@ enum dvfs_state {
6687
LIST_FOR_DVFS_STATE(DVFS_STATE)
6788
};
6889

69-
static const uint8_t dvfs_high_freq_bitmask = INITIALIZE_DVFS_FREQ_MASK(ACTIVE_FREQ_HIGH);
70-
static const uint8_t dvfs_medlow_freq_bitmask = INITIALIZE_DVFS_FREQ_MASK(ACTIVE_FREQ_MEDLOW);
90+
struct dvfs_frequency {
91+
uint32_t freq;
92+
uint8_t bitmask;
93+
};
94+
95+
static const struct dvfs_frequency dvfs_freq_array[] = {
96+
{
97+
.freq = CONFIG_DESKTOP_DVFS_FREQ_HIGH,
98+
.bitmask = INITIALIZE_DVFS_FREQ_MASK(ACTIVE_FREQ_HIGH)
99+
},
100+
{
101+
.freq = CONFIG_DESKTOP_DVFS_FREQ_MED,
102+
.bitmask = INITIALIZE_DVFS_FREQ_MASK(ACTIVE_FREQ_MEDLOW)
103+
},
104+
{
105+
.freq = CONFIG_DESKTOP_DVFS_FREQ_LOW,
106+
.bitmask = UINT8_MAX
107+
},
108+
};
71109

72110
/* Binary mask tracking which states are requested. */
73111
static uint8_t dfvs_requests_state_bitmask;
74112

75-
static enum dvfs_frequency_setting current_freq = DVFS_FREQ_HIGH;
113+
/* SoC starts with 320MHz frequency */
114+
static uint32_t current_freq = dvfs_freq_array[0].freq;
76115

77-
BUILD_ASSERT(sizeof(dvfs_high_freq_bitmask) == sizeof(dfvs_requests_state_bitmask));
78-
BUILD_ASSERT(sizeof(dvfs_medlow_freq_bitmask) == sizeof(dfvs_requests_state_bitmask));
116+
BUILD_ASSERT(sizeof(dvfs_freq_array[0].bitmask) == sizeof(dfvs_requests_state_bitmask));
79117
BUILD_ASSERT(CHAR_BIT * sizeof(dfvs_requests_state_bitmask) >= DVFS_STATE_COUNT);
80118

81119
static struct dvfs_retry {
@@ -88,20 +126,14 @@ struct dvfs_state_timeout {
88126
uint16_t timeout_ms;
89127
};
90128

129+
static struct k_work dvfs_notify_work;
130+
static uint32_t requested_freq;
131+
static bool request_in_progress;
132+
91133
static struct dvfs_state_timeout dvfs_state_timeouts[DVFS_STATE_COUNT] = {
92134
LIST_FOR_DVFS_STATE(INITIALIZE_DVFS_STATE_TIMEOUT)
93135
};
94136

95-
static const char *get_dvfs_frequency_setting_name(enum dvfs_frequency_setting setting)
96-
{
97-
switch (setting) {
98-
case DVFS_FREQ_HIGH: return "DVFS_FREQ_HIGH";
99-
case DVFS_FREQ_MEDLOW: return "DVFS_FREQ_MEDLOW";
100-
case DVFS_FREQ_LOW: return "DVFS_FREQ_LOW";
101-
default: return "Unknown";
102-
}
103-
}
104-
105137
static const char *get_dvfs_state_name(enum dvfs_state state)
106138
{
107139
switch (state) {
@@ -111,19 +143,21 @@ static const char *get_dvfs_state_name(enum dvfs_state state)
111143
}
112144
}
113145

114-
static void cancel_dvfs_retry_work(void)
146+
static void dvfs_fatal_error(void)
115147
{
148+
module_set_state(MODULE_STATE_ERROR);
149+
module_state = STATE_ERROR;
116150
(void) k_work_cancel_delayable(&dvfs_retry.retry_work);
117-
dvfs_retry.retries_cnt = 0;
151+
for (size_t i = 0; i < ARRAY_SIZE(dvfs_state_timeouts); i++) {
152+
(void) k_work_cancel_delayable(&dvfs_state_timeouts[i].timeout_work);
153+
}
118154
}
119155

120156
static void handle_dvfs_error(int32_t err)
121157
{
122158
if (dvfs_retry.retries_cnt >= DVFS_NUMBER_OF_RETRIES) {
123159
LOG_ERR("DVFS retry count exceeded.");
124-
module_set_state(MODULE_STATE_ERROR);
125-
module_state = STATE_ERROR;
126-
cancel_dvfs_retry_work();
160+
dvfs_fatal_error();
127161
return;
128162
}
129163
dvfs_retry.retries_cnt++;
@@ -137,37 +171,113 @@ static void handle_dvfs_error(int32_t err)
137171
timeout = DVFS_RETRY_INITIALIZATION_TIMEOUT;
138172
} else {
139173
LOG_ERR("DVFS freq change returned with error: %d", err);
140-
module_set_state(MODULE_STATE_ERROR);
141-
module_state = STATE_ERROR;
142-
cancel_dvfs_retry_work();
174+
dvfs_fatal_error();
143175
return;
144176
}
145177
(void) k_work_reschedule(&dvfs_retry.retry_work, timeout);
146178
}
147179

148-
static void set_dvfs_freq(enum dvfs_frequency_setting target_freq)
180+
static uint32_t check_required_frequency(void)
149181
{
150-
int32_t ret = dvfs_service_handler_change_freq_setting(target_freq);
182+
for (size_t i = 0; i < ARRAY_SIZE(dvfs_freq_array) - 1; i++) {
183+
if (dfvs_requests_state_bitmask & dvfs_freq_array[i].bitmask) {
184+
return dvfs_freq_array[i].freq;
185+
}
186+
}
187+
188+
/* If no state is active, return the lowest frequency. */
189+
return dvfs_freq_array[ARRAY_SIZE(dvfs_freq_array) - 1].freq;
190+
}
191+
192+
static void dvfs_notify_cb(struct onoff_manager *srv,
193+
struct onoff_client *cli,
194+
uint32_t state,
195+
int res)
196+
{
197+
(void) k_work_submit(&dvfs_notify_work);
198+
}
199+
200+
static void set_dvfs_freq(uint32_t target_freq)
201+
{
202+
int ret;
203+
204+
if (spec.frequency != 0) {
205+
ret = nrf_clock_control_release(dvfs_clock_dev, &spec);
206+
if (ret < 0) {
207+
LOG_ERR("Failed to release requested clock specs, error: %d", ret);
208+
dvfs_fatal_error();
209+
return;
210+
}
211+
}
212+
213+
sys_notify_init_callback(&cli.notify, dvfs_notify_cb);
151214

215+
spec.frequency = target_freq;
216+
ret = nrf_clock_control_request(dvfs_clock_dev, &spec, &cli);
152217
if (ret) {
153218
handle_dvfs_error(ret);
154219
} else {
155-
current_freq = target_freq;
156-
LOG_INF("Have requested %s frequency",
157-
get_dvfs_frequency_setting_name(target_freq));
158-
cancel_dvfs_retry_work();
220+
LOG_INF("Have requested %" PRIu32 " frequency", target_freq);
221+
requested_freq = target_freq;
222+
request_in_progress = true;
159223
}
160224
}
161225

162-
static enum dvfs_frequency_setting check_required_frequency(void)
226+
static void dvfs_frequency_update(void)
163227
{
164-
if (dfvs_requests_state_bitmask & dvfs_high_freq_bitmask) {
165-
return DVFS_FREQ_HIGH;
166-
} else if (dfvs_requests_state_bitmask & dvfs_medlow_freq_bitmask) {
167-
return DVFS_FREQ_MEDLOW;
168-
} else {
169-
return DVFS_FREQ_LOW;
228+
uint32_t required_freq = check_required_frequency();
229+
230+
if ((!k_work_delayable_is_pending(&dvfs_retry.retry_work)) &&
231+
!request_in_progress && (required_freq != current_freq)) {
232+
set_dvfs_freq(required_freq);
233+
} else if ((required_freq == current_freq) &&
234+
(k_work_delayable_is_pending(&dvfs_retry.retry_work))) {
235+
(void) k_work_cancel_delayable(&dvfs_retry.retry_work);
236+
/* retry_cnt should be only cleared on successful frequency change. */
237+
}
238+
}
239+
240+
static void dvfs_notify_work_handler(struct k_work *work)
241+
{
242+
int res;
243+
int ret = sys_notify_fetch_result(&cli.notify, &res);
244+
245+
if (ret < 0) {
246+
LOG_ERR("Work not completed, verify usage of notify API");
247+
dvfs_fatal_error();
248+
return;
249+
}
250+
251+
__ASSERT_NO_MSG(request_in_progress);
252+
request_in_progress = false;
253+
254+
if (res < 0) {
255+
handle_dvfs_error(res);
256+
return;
257+
}
258+
ret = clock_control_get_rate(dvfs_clock_dev, NULL, &current_freq);
259+
if (ret < 0) {
260+
LOG_ERR("Failed to get current frequency with error: %d", ret);
261+
dvfs_fatal_error();
262+
return;
263+
}
264+
if (requested_freq != current_freq) {
265+
/*
266+
* In current solution it is assumed that no other module
267+
* will change cpu frequency.
268+
*/
269+
LOG_ERR("Requested frequency %" PRIu32
270+
" is not the same as current frequency %" PRIu32,
271+
requested_freq, current_freq);
272+
dvfs_fatal_error();
273+
return;
170274
}
275+
276+
dvfs_retry.retries_cnt = 0;
277+
LOG_INF("DVFS completed, current frequency is: %" PRIu32, current_freq);
278+
279+
/* Check if there were any new requests. */
280+
dvfs_frequency_update();
171281
}
172282

173283
static void process_dvfs_states(enum dvfs_state state, bool turn_on)
@@ -184,15 +294,7 @@ static void process_dvfs_states(enum dvfs_state state, bool turn_on)
184294
LOG_DBG("%s NOT ACTIVE", get_dvfs_state_name(state));
185295
}
186296

187-
enum dvfs_frequency_setting required_freq = check_required_frequency();
188-
189-
if ((required_freq != current_freq) &&
190-
(!k_work_delayable_is_pending(&dvfs_retry.retry_work))) {
191-
set_dvfs_freq(required_freq);
192-
} else if ((required_freq == current_freq) &&
193-
(k_work_delayable_is_pending(&dvfs_retry.retry_work))) {
194-
cancel_dvfs_retry_work();
195-
}
297+
dvfs_frequency_update();
196298
}
197299

198300
static bool handle_ble_peer_conn_params_event(const struct ble_peer_conn_params_event *event)
@@ -226,10 +328,9 @@ static void dvfs_retry_work_handler(struct k_work *work)
226328
{
227329
LOG_DBG("Retrying to change DVFS frequency.");
228330

229-
enum dvfs_frequency_setting required_freq = check_required_frequency();
331+
uint32_t required_freq = check_required_frequency();
230332

231333
__ASSERT_NO_MSG(required_freq != current_freq);
232-
233334
set_dvfs_freq(required_freq);
234335
}
235336

@@ -252,27 +353,37 @@ static bool app_event_handler(const struct app_event_header *aeh)
252353
const struct module_state_event *event = cast_module_state_event(aeh);
253354

254355
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
255-
__ASSERT_NO_MSG((dvfs_high_freq_bitmask & dvfs_medlow_freq_bitmask) == 0);
356+
BUILD_ASSERT(ARRAY_SIZE(dvfs_freq_array) == 3,
357+
"Add asserts if frequency array is extended");
358+
__ASSERT_NO_MSG((dvfs_freq_array[0].bitmask &
359+
dvfs_freq_array[1].bitmask) == 0);
256360

257-
k_work_init_delayable(&dvfs_retry.retry_work,
258-
dvfs_retry_work_handler);
361+
k_work_init(&dvfs_notify_work, dvfs_notify_work_handler);
362+
k_work_init_delayable(&dvfs_retry.retry_work, dvfs_retry_work_handler);
259363
for (size_t i = 0; i < ARRAY_SIZE(dvfs_state_timeouts); i++) {
260364
k_work_init_delayable(&dvfs_state_timeouts[i].timeout_work,
261365
dvfs_state_timeout_work_handler);
262366
}
367+
int ret = clock_control_get_rate(dvfs_clock_dev,
368+
NULL, &current_freq);
369+
370+
if (ret < 0) {
371+
LOG_ERR("Failed to get current frequency with error: %d",
372+
ret);
373+
dvfs_fatal_error();
374+
return false;
375+
}
263376
module_state = STATE_READY;
264377

265378
if (IS_ENABLED(CONFIG_DESKTOP_DVFS_STATE_INITIALIZING_ENABLE)) {
266-
if (module_flags_check_zero(&req_modules_bm)) {
379+
get_req_modules(&req_modules_bm);
380+
if (!module_flags_check_zero(&req_modules_bm)) {
267381
process_dvfs_states(DVFS_STATE_INITIALIZING, true);
382+
} else {
383+
dvfs_frequency_update();
268384
}
269-
get_req_modules(&req_modules_bm);
270385
} else {
271-
enum dvfs_frequency_setting required_freq =
272-
check_required_frequency();
273-
if (required_freq != current_freq) {
274-
set_dvfs_freq(required_freq);
275-
}
386+
dvfs_frequency_update();
276387
}
277388
}
278389

0 commit comments

Comments
 (0)