diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi index 595307aec8c81..0c5307c4c8c25 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-common.dtsi @@ -11,13 +11,8 @@ &hfxo { status = "okay"; accuracy-ppm = <30>; - startup-time-us = <850>; - mode = "crystal"; }; &lfxo { status = "okay"; - accuracy-ppm = <20>; - startup-time-us = <600000>; - mode = "crystal"; }; diff --git a/drivers/clock_control/clock_control_nrf2_common.c b/drivers/clock_control/clock_control_nrf2_common.c index 7bf8576880ba9..e9fbe00e9101c 100644 --- a/drivers/clock_control/clock_control_nrf2_common.c +++ b/drivers/clock_control/clock_control_nrf2_common.c @@ -5,6 +5,7 @@ #include "clock_control_nrf2_common.h" #include +#include #include LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -19,6 +20,8 @@ LOG_MODULE_REGISTER(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); (idx * sizeof(array[0])) - \ offsetof(type, array[0])) +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + /* * Definition of `struct clock_config_generic`. * Used to access `clock_config_*` structures in a common way. @@ -83,6 +86,40 @@ static inline uint8_t get_index_of_highest_bit(uint32_t value) return value ? (uint8_t)(31 - __builtin_clz(value)) : 0; } +int lfosc_get_accuracy(uint16_t *accuracy) +{ + switch (nrf_bicr_lfosc_accuracy_get(BICR)) { + case NRF_BICR_LFOSC_ACCURACY_500PPM: + *accuracy = 500U; + break; + case NRF_BICR_LFOSC_ACCURACY_250PPM: + *accuracy = 250U; + break; + case NRF_BICR_LFOSC_ACCURACY_150PPM: + *accuracy = 150U; + break; + case NRF_BICR_LFOSC_ACCURACY_100PPM: + *accuracy = 100U; + break; + case NRF_BICR_LFOSC_ACCURACY_75PPM: + *accuracy = 75U; + break; + case NRF_BICR_LFOSC_ACCURACY_50PPM: + *accuracy = 50U; + break; + case NRF_BICR_LFOSC_ACCURACY_30PPM: + *accuracy = 30U; + break; + case NRF_BICR_LFOSC_ACCURACY_20PPM: + *accuracy = 20U; + break; + default: + return -EINVAL; + } + + return 0; +} + int clock_config_init(void *clk_cfg, uint8_t onoff_cnt, k_work_handler_t update_work_handler) { struct clock_config_generic *cfg = clk_cfg; diff --git a/drivers/clock_control/clock_control_nrf2_common.h b/drivers/clock_control/clock_control_nrf2_common.h index 858698c38ea7e..1f08e5b090f87 100644 --- a/drivers/clock_control/clock_control_nrf2_common.h +++ b/drivers/clock_control/clock_control_nrf2_common.h @@ -36,6 +36,16 @@ struct clock_onoff { struct clock_onoff onoff[_onoff_cnt]; \ } +/** + * @brief Obtain LFOSC accuracy in ppm. + * + * @param[out] accuracy Accuracy in ppm. + * + * @retval 0 On success + * @retval -EINVAL If accuracy is not configured. + */ +int lfosc_get_accuracy(uint16_t *accuracy); + /** * @brief Initializes a clock configuration structure. * diff --git a/drivers/clock_control/clock_control_nrf2_fll16m.c b/drivers/clock_control/clock_control_nrf2_fll16m.c index 1637284b3226c..cbec791aa77c6 100644 --- a/drivers/clock_control/clock_control_nrf2_fll16m.c +++ b/drivers/clock_control/clock_control_nrf2_fll16m.c @@ -8,7 +8,9 @@ #include "clock_control_nrf2_common.h" #include #include + #include +#include #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -23,26 +25,17 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, #define FLL16M_MODE_BYPASS 2 #define FLL16M_MODE_DEFAULT FLL16M_MODE_OPEN_LOOP -#define FLL16M_LFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, lfxo) #define FLL16M_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo) -#define FLL16M_HAS_LFXO DT_NODE_HAS_STATUS_OKAY(FLL16M_LFXO_NODE) - -#define FLL16M_LFXO_ACCURACY DT_PROP(FLL16M_LFXO_NODE, accuracy_ppm) #define FLL16M_HFXO_ACCURACY DT_PROP(FLL16M_HFXO_NODE, accuracy_ppm) #define FLL16M_OPEN_LOOP_ACCURACY DT_INST_PROP(0, open_loop_accuracy_ppm) #define FLL16M_CLOSED_LOOP_BASE_ACCURACY DT_INST_PROP(0, closed_loop_base_accuracy_ppm) #define FLL16M_MAX_ACCURACY FLL16M_HFXO_ACCURACY -/* Closed-loop mode uses LFXO as source if present, HFXO otherwise */ -#if FLL16M_HAS_LFXO -#define FLL16M_CLOSED_LOOP_ACCURACY (FLL16M_CLOSED_LOOP_BASE_ACCURACY + FLL16M_LFXO_ACCURACY) -#else -#define FLL16M_CLOSED_LOOP_ACCURACY (FLL16M_CLOSED_LOOP_BASE_ACCURACY + FLL16M_HFXO_ACCURACY) -#endif +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) /* Clock options sorted from lowest to highest accuracy */ -static const struct clock_options { +static struct clock_options { uint16_t accuracy; uint8_t mode; } clock_options[] = { @@ -51,7 +44,6 @@ static const struct clock_options { .mode = FLL16M_MODE_OPEN_LOOP, }, { - .accuracy = FLL16M_CLOSED_LOOP_ACCURACY, .mode = FLL16M_MODE_CLOSED_LOOP, }, { @@ -233,6 +225,27 @@ static int api_get_rate_fll16m(const struct device *dev, static int fll16m_init(const struct device *dev) { struct fll16m_dev_data *dev_data = dev->data; + nrf_bicr_lfosc_mode_t lfosc_mode; + + clock_options[1].accuracy = FLL16M_CLOSED_LOOP_BASE_ACCURACY; + + /* Closed-loop mode uses LFXO as source if present, HFXO otherwise */ + lfosc_mode = nrf_bicr_lfosc_mode_get(BICR); + + if (lfosc_mode != NRF_BICR_LFOSC_MODE_UNCONFIGURED && + lfosc_mode != NRF_BICR_LFOSC_MODE_DISABLED) { + int ret; + uint16_t accuracy; + + ret = lfosc_get_accuracy(&accuracy); + if (ret < 0) { + return ret; + } + + clock_options[1].accuracy += accuracy; + } else { + clock_options[1].accuracy += FLL16M_HFXO_ACCURACY; + } return clock_config_init(&dev_data->clk_cfg, ARRAY_SIZE(dev_data->clk_cfg.onoff), diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index 21723716ea6f4..31693a89272dc 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -12,6 +12,7 @@ LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); #include +#include BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "multiple instances not supported"); @@ -24,14 +25,16 @@ struct dev_data_hfxo { #if defined(CONFIG_ZERO_LATENCY_IRQS) uint16_t request_count; #endif /* CONFIG_ZERO_LATENCY_IRQS */ + k_timeout_t start_up_time; }; struct dev_config_hfxo { uint32_t fixed_frequency; uint16_t fixed_accuracy; - k_timeout_t start_up_time; }; +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + #if defined(CONFIG_ZERO_LATENCY_IRQS) static uint32_t full_irq_lock(void) { @@ -114,8 +117,6 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) { struct dev_data_hfxo *dev_data = CONTAINER_OF(mgr, struct dev_data_hfxo, mgr); - const struct device *dev = DEVICE_DT_INST_GET(0); - const struct dev_config_hfxo *dev_config = dev->config; dev_data->notify = notify; request_hfxo(dev_data); @@ -124,7 +125,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) * unreliable. Hence the timer is used to simply wait the expected * start-up time. To be removed once the hardware is fixed. */ - k_timer_start(&dev_data->timer, dev_config->start_up_time, K_NO_WAIT); + k_timer_start(&dev_data->timer, dev_data->start_up_time, K_NO_WAIT); } static void stop_hfxo(struct dev_data_hfxo *dev_data) @@ -258,6 +259,7 @@ static int init_hfxo(const struct device *dev) .start = onoff_start_hfxo, .stop = onoff_stop_hfxo }; + uint32_t start_up_time; int rc; rc = onoff_manager_init(&dev_data->mgr, &transitions); @@ -265,6 +267,13 @@ static int init_hfxo(const struct device *dev) return rc; } + start_up_time = nrf_bicr_hfxo_startup_time_us_get(BICR); + if (start_up_time == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED) { + return -EINVAL; + } + + dev_data->start_up_time = K_USEC(start_up_time); + k_timer_init(&dev_data->timer, hfxo_start_up_timer_handler, NULL); return 0; @@ -286,7 +295,6 @@ static struct dev_data_hfxo data_hfxo; static const struct dev_config_hfxo config_hfxo = { .fixed_frequency = DT_INST_PROP(0, clock_frequency), .fixed_accuracy = DT_INST_PROP(0, accuracy_ppm), - .start_up_time = K_USEC(DT_INST_PROP(0, startup_time_us)), }; DEVICE_DT_INST_DEFINE(0, init_hfxo, NULL, diff --git a/drivers/clock_control/clock_control_nrf2_lfclk.c b/drivers/clock_control/clock_control_nrf2_lfclk.c index a4261c18f475f..2cbef9b8bf094 100644 --- a/drivers/clock_control/clock_control_nrf2_lfclk.c +++ b/drivers/clock_control/clock_control_nrf2_lfclk.c @@ -8,6 +8,7 @@ #include "clock_control_nrf2_common.h" #include #include +#include #include #include @@ -16,30 +17,25 @@ 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"); -#define LFCLK_LFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, lfxo) #define LFCLK_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo) -#define LFCLK_HAS_LFXO DT_NODE_HAS_STATUS_OKAY(LFCLK_LFXO_NODE) - #define LFCLK_LFLPRC_ACCURACY DT_INST_PROP(0, lflprc_accuracy_ppm) #define LFCLK_LFRC_ACCURACY DT_INST_PROP(0, lfrc_accuracy_ppm) -#define LFCLK_LFXO_ACCURACY DT_PROP(LFCLK_LFXO_NODE, accuracy_ppm) #define LFCLK_HFXO_ACCURACY DT_PROP(LFCLK_HFXO_NODE, accuracy_ppm) -#if LFCLK_HAS_LFXO -#define LFCLK_MAX_ACCURACY LFCLK_LFXO_ACCURACY -#else -#define LFCLK_MAX_ACCURACY LFCLK_HFXO_ACCURACY -#endif +#define LFCLK_MAX_OPTS 5 +#define LFCLK_DEF_OPTS 3 #define NRFS_CLOCK_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_NRFS_CLOCK_TIMEOUT_MS) +#define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr)) + /* Clock options sorted from lowest to highest accuracy/precision */ -static const struct clock_options { +static struct clock_options { uint16_t accuracy : 15; uint16_t precision : 1; nrfs_clock_src_t src; -} clock_options[] = { +} clock_options[LFCLK_MAX_OPTS] = { { .accuracy = LFCLK_LFLPRC_ACCURACY, .precision = 0, @@ -56,43 +52,13 @@ static const struct clock_options { .precision = 1, .src = NRFS_CLOCK_SRC_LFCLK_SYNTH, }, -#if LFCLK_HAS_LFXO -#if DT_ENUM_HAS_VALUE(LFCLK_LFXO_NODE, mode, crystal) - { - .accuracy = LFCLK_LFXO_ACCURACY, - .src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE, - }, - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 1, - .src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP, - }, -#elif DT_ENUM_HAS_VALUE(LFCLK_LFXO_NODE, mode, external_sine) - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 0, - .src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE, - }, - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 1, - .src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP, - }, -#elif DT_ENUM_HAS_VALUE(LFCLK_LFXO_NODE, mode, external_square) - { - .accuracy = LFCLK_LFXO_ACCURACY, - .precision = 0, - .src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE, - }, -#else -#error "unsupported LFXO mode" -#endif -#endif }; struct lfclk_dev_data { STRUCT_CLOCK_CONFIG(lfclk, ARRAY_SIZE(clock_options)) clk_cfg; struct k_timer timer; + uint16_t max_accuracy; + uint8_t clock_options_cnt; }; struct lfclk_dev_config { @@ -156,10 +122,10 @@ static struct onoff_manager *lfclk_find_mgr(const struct device *dev, } accuracy = spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX - ? LFCLK_MAX_ACCURACY + ? dev_data->max_accuracy : spec->accuracy; - for (int i = 0; i < ARRAY_SIZE(clock_options); ++i) { + for (int i = 0; i < dev_data->clock_options_cnt; ++i) { if ((accuracy && accuracy < clock_options[i].accuracy) || spec->precision > clock_options[i].precision) { @@ -227,6 +193,7 @@ static int api_get_rate_lfclk(const struct device *dev, static int lfclk_init(const struct device *dev) { struct lfclk_dev_data *dev_data = dev->data; + nrf_bicr_lfosc_mode_t lfosc_mode; nrfs_err_t res; res = nrfs_clock_init(clock_evt_handler); @@ -234,6 +201,58 @@ static int lfclk_init(const struct device *dev) return -EIO; } + dev_data->clock_options_cnt = LFCLK_DEF_OPTS; + + lfosc_mode = nrf_bicr_lfosc_mode_get(BICR); + + if (lfosc_mode == NRF_BICR_LFOSC_MODE_UNCONFIGURED || + lfosc_mode == NRF_BICR_LFOSC_MODE_DISABLED) { + dev_data->max_accuracy = LFCLK_HFXO_ACCURACY; + } else { + int ret; + + ret = lfosc_get_accuracy(&dev_data->max_accuracy); + if (ret < 0) { + LOG_ERR("LFOSC enabled with invalid accuracy"); + return ret; + } + + switch (lfosc_mode) { + case NRF_BICR_LFOSC_MODE_CRYSTAL: + clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 2].precision = 0; + clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE; + + clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 1].precision = 1; + clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP; + + dev_data->clock_options_cnt += 2; + break; + case NRF_BICR_LFOSC_MODE_EXTSINE: + clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 2].precision = 0; + clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE; + + clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 1].precision = 1; + clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP; + + dev_data->clock_options_cnt += 2; + break; + case NRF_BICR_LFOSC_MODE_EXTSQUARE: + clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy; + clock_options[LFCLK_MAX_OPTS - 2].precision = 0; + clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE; + + dev_data->clock_options_cnt += 1; + break; + default: + LOG_ERR("Unexpected LFOSC mode"); + return -EINVAL; + } + } + k_timer_init(&dev_data->timer, lfclk_update_timeout_handler, NULL); return clock_config_init(&dev_data->clk_cfg, diff --git a/dts/bindings/clock/nordic,nrf54h-hfxo.yaml b/dts/bindings/clock/nordic,nrf54h-hfxo.yaml index 1dab8b99cf868..26280e770315a 100644 --- a/dts/bindings/clock/nordic,nrf54h-hfxo.yaml +++ b/dts/bindings/clock/nordic,nrf54h-hfxo.yaml @@ -15,16 +15,3 @@ properties: type: int description: Clock accuracy in parts per million required: true - - startup-time-us: - type: int - description: Clock startup time in micro seconds - required: true - - mode: - type: string - description: HFXO operational mode - required: true - enum: - - "crystal" - - "external-square" diff --git a/dts/bindings/clock/nordic,nrf54h-lfxo.yaml b/dts/bindings/clock/nordic,nrf54h-lfxo.yaml index 3a85f27972d82..705c2483ecd12 100644 --- a/dts/bindings/clock/nordic,nrf54h-lfxo.yaml +++ b/dts/bindings/clock/nordic,nrf54h-lfxo.yaml @@ -10,22 +10,3 @@ include: fixed-clock.yaml properties: clock-frequency: const: 32768 - - accuracy-ppm: - type: int - description: Clock accuracy in parts per million - required: true - - startup-time-us: - type: int - description: Clock startup time in micro seconds - required: true - - mode: - type: string - description: LFXO operational mode - required: true - enum: - - "crystal" - - "external-sine" - - "external-square" diff --git a/dts/bindings/misc/nordic,nrf-bicr.yaml b/dts/bindings/misc/nordic,nrf-bicr.yaml new file mode 100644 index 0000000000000..f5c127e6cf126 --- /dev/null +++ b/dts/bindings/misc/nordic,nrf-bicr.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic BICR (Board Information Configuration Registers) + +compatible: "nordic,nrf-bicr" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index 085aba43c86d8..6f3748bc9ccb6 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -220,7 +220,15 @@ cpuapp_uicr: uicr@fff8000 { compatible = "nordic,nrf-uicr-v2"; reg = <0xfff8000 DT_SIZE_K(2)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xfff8000 DT_SIZE_K(2)>; domain = <2>; + + bicr: bicr@7b0 { + compatible = "nordic,nrf-bicr"; + reg = <0x7b0 48>; + }; }; cpurad_uicr: uicr@fffa000 { diff --git a/soc/nordic/validate_base_addresses.c b/soc/nordic/validate_base_addresses.c index f47c3dc456ed9..ef1dd19457894 100644 --- a/soc/nordic/validate_base_addresses.c +++ b/soc/nordic/validate_base_addresses.c @@ -330,6 +330,7 @@ CHECK_DT_REG(uart136, NRF_UARTE136); CHECK_DT_REG(uart137, NRF_UARTE137); CHECK_DT_REG(uicr, NRF_UICR); CHECK_DT_REG(cpuapp_uicr, NRF_APPLICATION_UICR); +CHECK_DT_REG(bicr, NRF_APPLICATION_BICR); CHECK_DT_REG(cpurad_uicr, NRF_RADIOCORE_UICR); CHECK_DT_REG(usbd, NRF_USBD); CHECK_DT_REG(usbhs, NRF_USBHS);