Skip to content
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

[WIP] Pull in global hsfll clock device driver #2300

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/clock_control/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA_CGC clock_cont
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL clock_control_nrf2_global_hsfll.c)

if(CONFIG_CLOCK_CONTROL_NRF2)
zephyr_library_sources(clock_control_nrf2_common.c)
Expand Down
13 changes: 13 additions & 0 deletions drivers/clock_control/Kconfig.nrf
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,17 @@ config CLOCK_CONTROL_NRF2_NRFS_CLOCK_TIMEOUT_MS
int "Timeout waiting for nrfs clock service callback in milliseconds"
default 1000

config CLOCK_CONTROL_NRF2_GLOBAL_HSFLL
bool "Clock control for global HSFLL"
depends on NRFS_GDFS_SERVICE_ENABLED
default y

if CLOCK_CONTROL_NRF2_GLOBAL_HSFLL

config CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_TIMEOUT_MS
int "Frequency request timeout in milliseconds"
default 10000

endif # CLOCK_CONTROL_NRF2_GLOBAL_HSFLL

endif # CLOCK_CONTROL_NRF2
259 changes: 259 additions & 0 deletions drivers/clock_control/clock_control_nrf2_global_hsfll.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nordic_nrf_hsfll_global

#include "clock_control_nrf2_common.h"
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <nrfs_gdfs.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);

#define GLOBAL_HSFLL_CLOCK_FREQUENCIES \
DT_INST_PROP(0, supported_clock_frequencies)

#define GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(idx) \
DT_INST_PROP_BY_IDX(0, supported_clock_frequencies, idx)

#define GLOBAL_HSFLL_CLOCK_FREQUENCIES_SIZE \
DT_INST_PROP_LEN(0, supported_clock_frequencies)

#define GLOBAL_HSFLL_FREQ_REQ_TIMEOUT \
K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_TIMEOUT_MS)

Check notice on line 27 in drivers/clock_control/clock_control_nrf2_global_hsfll.c

View workflow job for this annotation

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

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_global_hsfll.c:27 -#define GLOBAL_HSFLL_CLOCK_FREQUENCIES \ - DT_INST_PROP(0, supported_clock_frequencies) - -#define GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(idx) \ +#define GLOBAL_HSFLL_CLOCK_FREQUENCIES DT_INST_PROP(0, supported_clock_frequencies) + +#define GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(idx) \ DT_INST_PROP_BY_IDX(0, supported_clock_frequencies, idx) -#define GLOBAL_HSFLL_CLOCK_FREQUENCIES_SIZE \ - DT_INST_PROP_LEN(0, supported_clock_frequencies) - -#define GLOBAL_HSFLL_FREQ_REQ_TIMEOUT \ - K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_TIMEOUT_MS) +#define GLOBAL_HSFLL_CLOCK_FREQUENCIES_SIZE DT_INST_PROP_LEN(0, supported_clock_frequencies) + +#define GLOBAL_HSFLL_FREQ_REQ_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_TIMEOUT_MS)
BUILD_ASSERT(GLOBAL_HSFLL_CLOCK_FREQUENCIES_SIZE == 4);
BUILD_ASSERT(GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(0) == 64000000);
BUILD_ASSERT(GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(1) == 128000000);
BUILD_ASSERT(GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(2) == 256000000);
BUILD_ASSERT(GLOBAL_HSFLL_CLOCK_FREQUENCIES_IDX(3) == 320000000);
BUILD_ASSERT(GDFS_FREQ_COUNT == 4);
BUILD_ASSERT(GDFS_FREQ_HIGH == 0);
BUILD_ASSERT(GDFS_FREQ_MEDHIGH == 1);
BUILD_ASSERT(GDFS_FREQ_MEDLOW == 2);
BUILD_ASSERT(GDFS_FREQ_LOW == 3);

struct global_hsfll_dev_config {
uint32_t clock_frequencies[GLOBAL_HSFLL_CLOCK_FREQUENCIES_SIZE];
};

struct global_hsfll_dev_data {
STRUCT_CLOCK_CONFIG(global_hsfll, GLOBAL_HSFLL_CLOCK_FREQUENCIES_SIZE) clk_cfg;
const struct device *dev;
struct k_work evt_work;
nrfs_gdfs_evt_type_t evt;
struct k_work_delayable timeout_dwork;
};

static uint32_t global_hsfll_get_max_clock_frequency(const struct device *dev)
{
const struct global_hsfll_dev_config *dev_config = dev->config;

return dev_config->clock_frequencies[ARRAY_SIZE(dev_config->clock_frequencies) - 1];
}

static struct onoff_manager *global_hsfll_find_mgr(const struct device *dev,
const struct nrf_clock_spec *spec)
{
struct global_hsfll_dev_data *dev_data = dev->data;
const struct global_hsfll_dev_config *dev_config = dev->config;
uint32_t frequency;

if (!spec) {
return &dev_data->clk_cfg.onoff[0].mgr;
}

if (spec->accuracy || spec->precision) {
LOG_ERR("invalid specification of accuracy or precision");
return NULL;
}

frequency = spec->frequency == NRF_CLOCK_CONTROL_FREQUENCY_MAX
? global_hsfll_get_max_clock_frequency(dev)
: spec->frequency;

Check notice on line 77 in drivers/clock_control/clock_control_nrf2_global_hsfll.c

View workflow job for this annotation

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

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_global_hsfll.c:77 - ? global_hsfll_get_max_clock_frequency(dev) - : spec->frequency; + ? global_hsfll_get_max_clock_frequency(dev) + : spec->frequency;
for (uint8_t i = 0; i < ARRAY_SIZE(dev_config->clock_frequencies); i++) {
if (dev_config->clock_frequencies[i] < frequency) {
continue;
}

return &dev_data->clk_cfg.onoff[i].mgr;
}

LOG_ERR("invalid frequency");
return NULL;
}

static int api_request_global_hsfll(const struct device *dev,
const struct nrf_clock_spec *spec,
struct onoff_client *cli)

Check notice on line 92 in drivers/clock_control/clock_control_nrf2_global_hsfll.c

View workflow job for this annotation

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

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_global_hsfll.c:92 -static int api_request_global_hsfll(const struct device *dev, - const struct nrf_clock_spec *spec, +static int api_request_global_hsfll(const struct device *dev, const struct nrf_clock_spec *spec,
{
struct onoff_manager *mgr = global_hsfll_find_mgr(dev, spec);

if (mgr) {
return onoff_request(mgr, cli);
}

return -EINVAL;
}

static int api_release_global_hsfll(const struct device *dev,
const struct nrf_clock_spec *spec)
{

Check notice on line 105 in drivers/clock_control/clock_control_nrf2_global_hsfll.c

View workflow job for this annotation

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

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_global_hsfll.c:105 -static int api_release_global_hsfll(const struct device *dev, - const struct nrf_clock_spec *spec) +static int api_release_global_hsfll(const struct device *dev, const struct nrf_clock_spec *spec)
struct onoff_manager *mgr = global_hsfll_find_mgr(dev, spec);

if (mgr) {
return onoff_release(mgr);
}

return -EINVAL;
}

static int api_cancel_or_release_global_hsfll(const struct device *dev,
const struct nrf_clock_spec *spec,
struct onoff_client *cli)
{
struct onoff_manager *mgr = global_hsfll_find_mgr(dev, spec);

if (mgr) {
return onoff_cancel_or_release(mgr, cli);
}

return -EINVAL;
}

static struct nrf_clock_control_driver_api driver_api = {
.std_api = {
.on = api_nosys_on_off,
.off = api_nosys_on_off,
},
.request = api_request_global_hsfll,

Check notice on line 133 in drivers/clock_control/clock_control_nrf2_global_hsfll.c

View workflow job for this annotation

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

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_global_hsfll.c:133 - .std_api = { - .on = api_nosys_on_off, - .off = api_nosys_on_off, - }, + .std_api = + { + .on = api_nosys_on_off, + .off = api_nosys_on_off, + },
.release = api_release_global_hsfll,
.cancel_or_release = api_cancel_or_release_global_hsfll,
};

static enum gdfs_frequency_setting global_hsfll_freq_idx_to_nrfs_freq(const struct device *dev,
uint8_t freq_idx)
{
const struct global_hsfll_dev_config *dev_config = dev->config;

return ARRAY_SIZE(dev_config->clock_frequencies) - 1 - freq_idx;
}

static const char *global_hsfll_gdfs_freq_to_str(enum gdfs_frequency_setting freq)
{
switch (freq) {
case GDFS_FREQ_HIGH:
return "GDFS_FREQ_HIGH";
case GDFS_FREQ_MEDHIGH:
return "GDFS_FREQ_MEDHIGH";
case GDFS_FREQ_MEDLOW:
return "GDFS_FREQ_MEDLOW";
case GDFS_FREQ_LOW:
return "GDFS_FREQ_LOW";
default:
break;
}

return "UNKNOWN";
}

static void global_hsfll_work_handler(struct k_work *work)
{
struct global_hsfll_dev_data *dev_data =
CONTAINER_OF(work, struct global_hsfll_dev_data, clk_cfg.work);
const struct device *dev = dev_data->dev;
uint8_t freq_idx;
enum gdfs_frequency_setting target_freq;
nrfs_err_t err;

freq_idx = clock_config_update_begin(work);
target_freq = global_hsfll_freq_idx_to_nrfs_freq(dev, freq_idx);

LOG_DBG("requesting %s", global_hsfll_gdfs_freq_to_str(target_freq));
err = nrfs_gdfs_request_freq(target_freq, dev_data);
if (err != NRFS_SUCCESS) {
clock_config_update_end(&dev_data->clk_cfg, -EIO);
return;
}

k_work_schedule(&dev_data->timeout_dwork, GLOBAL_HSFLL_FREQ_REQ_TIMEOUT);
}

static void global_hsfll_evt_handler(struct k_work *work)
{
struct global_hsfll_dev_data *dev_data =
CONTAINER_OF(work, struct global_hsfll_dev_data, evt_work);
int rc;

k_work_cancel_delayable(&dev_data->timeout_dwork);
rc = dev_data->evt == NRFS_GDFS_EVT_FREQ_CONFIRMED ? 0 : -EIO;
clock_config_update_end(&dev_data->clk_cfg, rc);
}

static void global_hfsll_nrfs_gdfs_evt_handler(nrfs_gdfs_evt_t const *p_evt, void *context)
{
struct global_hsfll_dev_data *dev_data = context;

if (k_work_is_pending(&dev_data->evt_work)) {
return;
}

dev_data->evt = p_evt->type;
k_work_submit(&dev_data->evt_work);
}

static void global_hsfll_timeout_handler(struct k_work *work)
{
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
struct global_hsfll_dev_data *dev_data =
CONTAINER_OF(dwork, struct global_hsfll_dev_data, timeout_dwork);

clock_config_update_end(&dev_data->clk_cfg, -ETIMEDOUT);
}

static int global_hfsll_init(const struct device *dev)
{
struct global_hsfll_dev_data *dev_data = dev->data;
int rc;
nrfs_err_t err;

rc = clock_config_init(&dev_data->clk_cfg,
ARRAY_SIZE(dev_data->clk_cfg.onoff),
global_hsfll_work_handler);

Check notice on line 226 in drivers/clock_control/clock_control_nrf2_global_hsfll.c

View workflow job for this annotation

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

You may want to run clang-format on this change

drivers/clock_control/clock_control_nrf2_global_hsfll.c:226 - rc = clock_config_init(&dev_data->clk_cfg, - ARRAY_SIZE(dev_data->clk_cfg.onoff), + rc = clock_config_init(&dev_data->clk_cfg, ARRAY_SIZE(dev_data->clk_cfg.onoff),
if (rc < 0) {
return rc;
}

k_work_init_delayable(&dev_data->timeout_dwork, global_hsfll_timeout_handler);
k_work_init(&dev_data->evt_work, global_hsfll_evt_handler);

err = nrfs_gdfs_init(global_hfsll_nrfs_gdfs_evt_handler);
if (err != NRFS_SUCCESS) {
return -EIO;
}

return 0;
}

static struct global_hsfll_dev_data driver_data = {
.dev = DEVICE_DT_INST_GET(0),
};

static const struct global_hsfll_dev_config driver_config = {
GLOBAL_HSFLL_CLOCK_FREQUENCIES
};

DEVICE_DT_INST_DEFINE(
0,
global_hfsll_init,
NULL,
&driver_data,
&driver_config,
PRE_KERNEL_1,
CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
&driver_api
);
18 changes: 2 additions & 16 deletions drivers/clock_control/clock_control_nrf2_hsfll.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nordic_nrf_hsfll
#define DT_DRV_COMPAT nordic_nrf_hsfll_local

#include "clock_control_nrf2_common.h"
#include <zephyr/devicetree.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <hal/nrf_hsfll.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
Expand Down Expand Up @@ -48,7 +47,7 @@ static const struct clock_options {
};

struct hsfll_dev_data {
STRUCT_CLOCK_CONFIG(hsfll, ARRAY_SIZE(clock_options)) clk_cfg;
STRUCT_CLOCK_CONFIG(global_hsfll, ARRAY_SIZE(clock_options)) clk_cfg;
struct k_timer timer;
};

Expand Down Expand Up @@ -183,18 +182,6 @@ static int api_cancel_or_release_hsfll(const struct device *dev,
#endif
}

static int api_get_rate_hsfll(const struct device *dev,
clock_control_subsys_t sys,
uint32_t *rate)
{
ARG_UNUSED(dev);
ARG_UNUSED(sys);

*rate = nrf_hsfll_clkctrl_mult_get(NRF_HSFLL) * MHZ(16);

return 0;
}

static int hsfll_init(const struct device *dev)
{
#ifdef CONFIG_NRFS_DVFS_LOCAL_DOMAIN
Expand All @@ -221,7 +208,6 @@ static struct nrf_clock_control_driver_api hsfll_drv_api = {
.std_api = {
.on = api_nosys_on_off,
.off = api_nosys_on_off,
.get_rate = api_get_rate_hsfll,
},
.request = api_request_hsfll,
.release = api_release_hsfll,
Expand Down
37 changes: 37 additions & 0 deletions dts/bindings/clock/nordic,nrf-global-hsfll.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (c) 2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: |
Nordic Global HSFLL clock.

The lowest supported clock frequency is the default
clock frequency.

Example:

global_hsfll: global_hsfll {
compatible = "nordic,nrf-hsfll-global";
clocks = <&fll16>;
#clock-cells = <0>;
supported-clock-frequencies = <64000000
128000000
256000000
320000000>;
};

compatible: "nordic,nrf-hsfll-global"

include:
- "base.yaml"
- "clock-controller.yaml"

properties:
clocks:
required: true

"#clock-cells":
const: 0

supported-clock-frequencies:
type: array
description: Supported clock frequencies in ascending order
Loading
Loading