drivers: counter: nrfx_timer: Add request for global HFSLL

Add requesting for global HFSLL when fast instance TIMER (e.g.
TIMER120 in nrf54h20) is used.

Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruściński 2024-12-11 10:47:24 +01:00 committed by Benjamin Cabé
parent fd194c1a01
commit 573ed56be7
2 changed files with 81 additions and 11 deletions

View file

@ -9,6 +9,12 @@ config COUNTER_NRF_RTC
def_bool y
depends on DT_HAS_NORDIC_NRF_RTC_ENABLED
config COUNTER_NRFX_TIMER_USE_CLOCK_CONTROL
def_bool y
depends on $(dt_nodelabel_enabled,timer120) || \
$(dt_nodelabel_enabled,timer121)
select CLOCK_CONTROL
# Internal flag which detects if PPI wrap feature is enabled for any instance
config COUNTER_RTC_WITH_PPI_WRAP
def_bool $(dt_nodelabel_bool_prop,rtc0,ppi-wrap) || \

View file

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/counter.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <zephyr/devicetree.h>
#include <hal/nrf_timer.h>
#include <zephyr/sys/atomic.h>
@ -32,11 +34,32 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL);
#define MAYBE_CONST_CONFIG const
#endif
#ifdef CONFIG_SOC_NRF54H20_GPD
#include <nrf/gpd.h>
#define NRF_CLOCKS_INSTANCE_IS_FAST(node) \
COND_CODE_1(DT_NODE_HAS_PROP(node, power_domains), \
(IS_EQ(DT_PHA(node, power_domains, id), NRF_GPD_FAST_ACTIVE1)), \
(0))
/* Macro must resolve to literal 0 or 1 */
#define INSTANCE_IS_FAST(idx) NRF_CLOCKS_INSTANCE_IS_FAST(DT_DRV_INST(idx))
#define INSTANCE_IS_FAST_OR(idx) INSTANCE_IS_FAST(idx) ||
#if (DT_INST_FOREACH_STATUS_OKAY(INSTANCE_IS_FAST_OR) 0)
#define COUNTER_ANY_FAST 1
#endif
#endif
struct counter_nrfx_data {
counter_top_callback_t top_cb;
void *top_user_data;
uint32_t guard_period;
atomic_t cc_int_pending;
#ifdef COUNTER_ANY_FAST
atomic_t active;
#endif
};
struct counter_nrfx_ch_data {
@ -48,6 +71,10 @@ struct counter_nrfx_config {
struct counter_config_info info;
struct counter_nrfx_ch_data *ch_data;
NRF_TIMER_Type *timer;
#ifdef COUNTER_ANY_FAST
const struct device *clk_dev;
struct nrf_clock_spec clk_spec;
#endif
LOG_INSTANCE_PTR_DECLARE(log);
};
@ -61,6 +88,18 @@ static int start(const struct device *dev)
{
const struct counter_nrfx_config *config = dev->config;
#ifdef COUNTER_ANY_FAST
struct counter_nrfx_data *data = dev->data;
if (config->clk_dev && atomic_cas(&data->active, 0, 1)) {
int err;
err = nrf_clock_control_request_sync(config->clk_dev, &config->clk_spec, K_FOREVER);
if (err < 0) {
return err;
}
}
#endif
nrf_timer_task_trigger(config->timer, NRF_TIMER_TASK_START);
return 0;
@ -71,6 +110,18 @@ static int stop(const struct device *dev)
const struct counter_nrfx_config *config = dev->config;
nrf_timer_task_trigger(config->timer, NRF_TIMER_TASK_STOP);
#ifdef COUNTER_ANY_FAST
struct counter_nrfx_data *data = dev->data;
if (config->clk_dev && atomic_cas(&data->active, 1, 0)) {
int err;
err = nrf_clock_control_release(config->clk_dev, &config->clk_spec);
if (err < 0) {
return err;
}
}
#endif
return 0;
}
@ -403,6 +454,20 @@ static DEVICE_API(counter, counter_nrfx_driver_api) = {
.set_guard_period = set_guard_period,
};
/* Get initialization level of an instance. Instances that requires clock control
* which is using nrfs (IPC) are initialized later.
*/
#define TIMER_INIT_LEVEL(idx) \
COND_CODE_1(INSTANCE_IS_FAST(idx), (POST_KERNEL), (PRE_KERNEL_1))
/* Get initialization priority of an instance. Instances that requires clock control
* which is using nrfs (IPC) are initialized later.
*/
#define TIMER_INIT_PRIO(idx) \
COND_CODE_1(INSTANCE_IS_FAST(idx), \
(UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \
(CONFIG_COUNTER_INIT_PRIORITY))
/*
* Device instantiation is done with node labels due to HAL API
* requirements. In particular, TIMERx_MAX_SIZE values from HALs
@ -419,14 +484,6 @@ static DEVICE_API(counter, counter_nrfx_driver_api) = {
irq_handler, DEVICE_DT_INST_GET(idx), 0)) \
)
#if !defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
#define CHECK_MAX_FREQ(idx) \
BUILD_ASSERT(DT_INST_PROP(idx, max_frequency) == \
NRF_TIMER_BASE_FREQUENCY_GET((NRF_TIMER_Type *)DT_INST_REG_ADDR(idx)))
#else
#define CHECK_MAX_FREQ(idx)
#endif
#define COUNTER_NRFX_TIMER_DEVICE(idx) \
BUILD_ASSERT(DT_INST_PROP(idx, prescaler) <= \
TIMER_PRESCALER_PRESCALER_Msk, \
@ -456,22 +513,29 @@ static DEVICE_API(counter, counter_nrfx_driver_api) = {
static MAYBE_CONST_CONFIG struct counter_nrfx_config nrfx_counter_##idx##_config = { \
.info = { \
.max_top_value = (uint32_t)BIT64_MASK(DT_INST_PROP(idx, max_bit_width)),\
.freq = DT_INST_PROP(idx, max_frequency) / \
.freq = NRF_PERIPH_GET_FREQUENCY(DT_DRV_INST(idx)) / \
BIT(DT_INST_PROP(idx, prescaler)), \
.flags = COUNTER_CONFIG_INFO_COUNT_UP, \
.channels = CC_TO_ID(DT_INST_PROP(idx, cc_num)), \
}, \
.ch_data = counter##idx##_ch_data, \
.timer = (NRF_TIMER_Type *)DT_INST_REG_ADDR(idx), \
IF_ENABLED(INSTANCE_IS_FAST(idx), \
(.clk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_DRV_INST(idx))), \
.clk_spec = { \
.frequency = NRF_PERIPH_GET_FREQUENCY(DT_DRV_INST(idx)), \
.accuracy = 0, \
.precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, \
}, \
)) \
LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \
}; \
CHECK_MAX_FREQ(idx); \
DEVICE_DT_INST_DEFINE(idx, \
counter_##idx##_init, \
NULL, \
&counter_##idx##_data, \
&nrfx_counter_##idx##_config.info, \
PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY, \
TIMER_INIT_LEVEL(idx), TIMER_INIT_PRIO(idx), \
&counter_nrfx_driver_api);
DT_INST_FOREACH_STATUS_OKAY(COUNTER_NRFX_TIMER_DEVICE)