-
Notifications
You must be signed in to change notification settings - Fork 677
[nrf fromlist] drivers: clock control: ironside dvfs hsfll #3006
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lstnl
wants to merge
1
commit into
nrfconnect:main
Choose a base branch
from
lstnl:nrf-clock-ctrl-ironside-hsfll
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
244 changes: 244 additions & 0 deletions
244
drivers/clock_control/clock_control_nrf_iron_hsfll_local.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
/* | ||
* Copyright (c) 2025 Nordic Semiconductor ASA | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#define DT_DRV_COMPAT nordic_nrf_iron_hsfll_local | ||
|
||
#include "clock_control_nrf2_common.h" | ||
#include <zephyr/devicetree.h> | ||
#include <zephyr/drivers/clock_control/nrf_clock_control.h> | ||
|
||
#include <zephyr/logging/log.h> | ||
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); | ||
|
||
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "multiple instances not supported"); | ||
|
||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
#include <zephyr/drivers/firmware/nrf_ironside/dvfs.h> | ||
|
||
#define HSFLL_FREQ_LOW MHZ(64) | ||
#define HSFLL_FREQ_MEDLOW MHZ(128) | ||
#define HSFLL_FREQ_HIGH MHZ(320) | ||
|
||
#define IRONSIDE_DVFS_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL_DVFS_TIMEOUT_MS) | ||
|
||
/* Clock options sorted from lowest to highest frequency */ | ||
static const struct clock_options { | ||
uint32_t frequency; | ||
enum ironside_dvfs_oppoint setting; | ||
} clock_options[] = { | ||
{ | ||
.frequency = HSFLL_FREQ_LOW, | ||
.setting = IRONSIDE_DVFS_OPP_LOW, | ||
}, | ||
{ | ||
.frequency = HSFLL_FREQ_MEDLOW, | ||
.setting = IRONSIDE_DVFS_OPP_MEDLOW, | ||
}, | ||
{ | ||
.frequency = HSFLL_FREQ_HIGH, | ||
.setting = IRONSIDE_DVFS_OPP_HIGH, | ||
}, | ||
}; | ||
|
||
struct hsfll_dev_data { | ||
STRUCT_CLOCK_CONFIG(hsfll, ARRAY_SIZE(clock_options)) clk_cfg; | ||
struct k_timer timer; | ||
}; | ||
|
||
static void hsfll_update_timeout_handler(struct k_timer *timer) | ||
{ | ||
struct hsfll_dev_data *dev_data = CONTAINER_OF(timer, struct hsfll_dev_data, timer); | ||
|
||
clock_config_update_end(&dev_data->clk_cfg, -ETIMEDOUT); | ||
} | ||
|
||
static void hsfll_work_handler(struct k_work *work) | ||
{ | ||
struct hsfll_dev_data *dev_data = CONTAINER_OF(work, struct hsfll_dev_data, clk_cfg.work); | ||
enum ironside_dvfs_oppoint required_setting; | ||
uint8_t to_activate_idx; | ||
int rc; | ||
|
||
to_activate_idx = clock_config_update_begin(work); | ||
required_setting = clock_options[to_activate_idx].setting; | ||
|
||
k_timer_start(&dev_data->timer, IRONSIDE_DVFS_TIMEOUT, K_NO_WAIT); | ||
|
||
/* Request the DVFS service to change the OPP point. */ | ||
rc = ironside_dvfs_change_oppoint(required_setting); | ||
k_timer_stop(&dev_data->timer); | ||
clock_config_update_end(&dev_data->clk_cfg, rc); | ||
} | ||
|
||
static int hsfll_resolve_spec_to_idx(const struct nrf_clock_spec *req_spec) | ||
{ | ||
uint32_t req_frequency; | ||
|
||
if (req_spec->accuracy || req_spec->precision) { | ||
LOG_ERR("invalid specification of accuracy or precision"); | ||
return -EINVAL; | ||
} | ||
|
||
req_frequency = req_spec->frequency == NRF_CLOCK_CONTROL_FREQUENCY_MAX | ||
? HSFLL_FREQ_HIGH | ||
: req_spec->frequency; | ||
|
||
for (int i = 0; i < ARRAY_SIZE(clock_options); ++i) { | ||
if (req_frequency > clock_options[i].frequency) { | ||
continue; | ||
} | ||
|
||
return i; | ||
} | ||
|
||
LOG_ERR("invalid frequency"); | ||
return -EINVAL; | ||
} | ||
|
||
static void hsfll_get_spec_by_idx(uint8_t idx, struct nrf_clock_spec *spec) | ||
{ | ||
spec->frequency = clock_options[idx].frequency; | ||
spec->accuracy = 0; | ||
spec->precision = 0; | ||
} | ||
|
||
static struct onoff_manager *hsfll_get_mgr_by_idx(const struct device *dev, uint8_t idx) | ||
{ | ||
struct hsfll_dev_data *dev_data = dev->data; | ||
|
||
return &dev_data->clk_cfg.onoff[idx].mgr; | ||
} | ||
|
||
static struct onoff_manager *hsfll_find_mgr_by_spec(const struct device *dev, | ||
const struct nrf_clock_spec *spec) | ||
{ | ||
int idx; | ||
|
||
if (!spec) { | ||
return hsfll_get_mgr_by_idx(dev, 0); | ||
} | ||
|
||
idx = hsfll_resolve_spec_to_idx(spec); | ||
return idx < 0 ? NULL : hsfll_get_mgr_by_idx(dev, idx); | ||
} | ||
#endif /* CONFIG_NRF_IRONSIDE_DVFS_SERVICE */ | ||
|
||
static int api_request_hsfll(const struct device *dev, const struct nrf_clock_spec *spec, | ||
struct onoff_client *cli) | ||
{ | ||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
struct onoff_manager *mgr = hsfll_find_mgr_by_spec(dev, spec); | ||
|
||
if (mgr) { | ||
return clock_config_request(mgr, cli); | ||
} | ||
|
||
return -EINVAL; | ||
#else | ||
return -ENOTSUP; | ||
#endif | ||
} | ||
|
||
static int api_release_hsfll(const struct device *dev, const struct nrf_clock_spec *spec) | ||
{ | ||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
struct onoff_manager *mgr = hsfll_find_mgr_by_spec(dev, spec); | ||
|
||
if (mgr) { | ||
return onoff_release(mgr); | ||
} | ||
|
||
return -EINVAL; | ||
#else | ||
return -ENOTSUP; | ||
#endif | ||
} | ||
|
||
static int api_cancel_or_release_hsfll(const struct device *dev, const struct nrf_clock_spec *spec, | ||
struct onoff_client *cli) | ||
{ | ||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
struct onoff_manager *mgr = hsfll_find_mgr_by_spec(dev, spec); | ||
|
||
if (mgr) { | ||
return onoff_cancel_or_release(mgr, cli); | ||
} | ||
|
||
return -EINVAL; | ||
#else | ||
return -ENOTSUP; | ||
#endif | ||
} | ||
|
||
static int api_resolve_hsfll(const struct device *dev, const struct nrf_clock_spec *req_spec, | ||
struct nrf_clock_spec *res_spec) | ||
{ | ||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
int idx; | ||
|
||
idx = hsfll_resolve_spec_to_idx(req_spec); | ||
if (idx < 0) { | ||
return -EINVAL; | ||
} | ||
|
||
hsfll_get_spec_by_idx(idx, res_spec); | ||
return 0; | ||
#else | ||
return -ENOTSUP; | ||
#endif | ||
} | ||
|
||
static int hsfll_init(const struct device *dev) | ||
{ | ||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
struct hsfll_dev_data *dev_data = dev->data; | ||
int rc; | ||
|
||
rc = clock_config_init(&dev_data->clk_cfg, ARRAY_SIZE(dev_data->clk_cfg.onoff), | ||
hsfll_work_handler); | ||
if (rc < 0) { | ||
return rc; | ||
} | ||
|
||
k_timer_init(&dev_data->timer, hsfll_update_timeout_handler, NULL); | ||
|
||
#endif | ||
|
||
return 0; | ||
} | ||
|
||
static DEVICE_API(nrf_clock_control, hsfll_drv_api) = { | ||
.std_api = { | ||
.on = api_nosys_on_off, | ||
.off = api_nosys_on_off, | ||
}, | ||
.request = api_request_hsfll, | ||
Check notice on line 217 in drivers/clock_control/clock_control_nrf_iron_hsfll_local.c
|
||
.release = api_release_hsfll, | ||
.cancel_or_release = api_cancel_or_release_hsfll, | ||
.resolve = api_resolve_hsfll, | ||
}; | ||
|
||
#ifdef CONFIG_NRF_IRONSIDE_DVFS_SERVICE | ||
static struct hsfll_dev_data hsfll_data; | ||
#endif | ||
|
||
#ifdef CONFIG_CLOCK_CONTROL_NRF_IRON_HSFLL_LOCAL_REQ_LOW_FREQ | ||
static int dvfs_low_init(void) | ||
{ | ||
static const k_timeout_t timeout = IRONSIDE_DVFS_TIMEOUT; | ||
static const struct device *hsfll_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_NODELABEL(cpu))); | ||
static const struct nrf_clock_spec clk_spec = {.frequency = HSFLL_FREQ_LOW}; | ||
|
||
return nrf_clock_control_request_sync(hsfll_dev, &clk_spec, timeout); | ||
} | ||
|
||
SYS_INIT(dvfs_low_init, APPLICATION, 0); | ||
#endif | ||
|
||
DEVICE_DT_INST_DEFINE(0, hsfll_init, NULL, | ||
COND_CODE_1(CONFIG_NRF_IRONSIDE_DVFS_SERVICE, | ||
(&hsfll_data), | ||
(NULL)), NULL, PRE_KERNEL_1, | ||
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &hsfll_drv_api); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Copyright (c) 2025 Nordic Semiconductor ASA | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
description: | | ||
Nordic nRF local HSFLL with IronSide DVFS support | ||
|
||
The local HSFLL mixed-mode IP generates several clock frequencies in the range | ||
from 64 MHz to 400 MHz (in steps of 16 MHz). | ||
|
||
Usage example: | ||
|
||
hsfll: clock@deadbeef { | ||
compatible = "nordic,nrf-hsfll-local"; | ||
reg = <0xdeadbeef 0x1000>; | ||
clocks = <&fll16m>; | ||
clock-frequency = <DT_FREQ_M(320)>; | ||
nordic,ficrs = <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP>, | ||
<&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0>, | ||
<&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0>; | ||
nordic,ficr-names = "vsup", "coarse", "fine"; | ||
}; | ||
|
||
Required FICR entries are for VSUP, COARSE and FINE trim values. | ||
|
||
compatible: "nordic,nrf-iron-hsfll-local" | ||
|
||
include: [base.yaml, fixed-clock.yaml, nordic-nrf-ficr-client.yaml] | ||
|
||
properties: | ||
reg: | ||
required: true | ||
|
||
clocks: | ||
required: true | ||
|
||
clock-frequency: | ||
enum: | ||
- 64000000 | ||
- 80000000 | ||
- 96000000 | ||
- 112000000 | ||
- 128000000 | ||
- 144000000 | ||
- 160000000 | ||
- 176000000 | ||
- 192000000 | ||
- 208000000 | ||
- 224000000 | ||
- 240000000 | ||
- 256000000 | ||
- 272000000 | ||
- 288000000 | ||
- 304000000 | ||
- 320000000 | ||
- 336000000 | ||
- 352000000 | ||
- 368000000 | ||
- 384000000 | ||
- 400000000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider improving the error message in hsfll_resolve_spec_to_idx to indicate the acceptable frequency range or valid values, which may help integrators diagnose configuration issues.
Copilot uses AI. Check for mistakes.