diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index ffc19a3b729..d3d1807d6cf 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -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) diff --git a/drivers/clock_control/Kconfig.nrf b/drivers/clock_control/Kconfig.nrf index f7b0de3db09..5afb978b6a8 100644 --- a/drivers/clock_control/Kconfig.nrf +++ b/drivers/clock_control/Kconfig.nrf @@ -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 diff --git a/drivers/clock_control/clock_control_nrf2_global_hsfll.c b/drivers/clock_control/clock_control_nrf2_global_hsfll.c new file mode 100644 index 00000000000..a98b2caae3e --- /dev/null +++ b/drivers/clock_control/clock_control_nrf2_global_hsfll.c @@ -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 +#include +#include + +#include +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) + +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; + + 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) +{ + 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) +{ + 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, + .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); + 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 +); diff --git a/drivers/clock_control/clock_control_nrf2_hsfll.c b/drivers/clock_control/clock_control_nrf2_hsfll.c index 026edf9abbd..c1361280dad 100644 --- a/drivers/clock_control/clock_control_nrf2_hsfll.c +++ b/drivers/clock_control/clock_control_nrf2_hsfll.c @@ -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 #include -#include #include LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL); @@ -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; }; @@ -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 @@ -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, diff --git a/dts/bindings/clock/nordic,nrf-global-hsfll.yaml b/dts/bindings/clock/nordic,nrf-global-hsfll.yaml new file mode 100644 index 00000000000..7bd5e986015 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-global-hsfll.yaml @@ -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 diff --git a/dts/bindings/clock/nordic,nrf-hsfll.yaml b/dts/bindings/clock/nordic,nrf-local-hsfll.yaml similarity index 83% rename from dts/bindings/clock/nordic,nrf-hsfll.yaml rename to dts/bindings/clock/nordic,nrf-local-hsfll.yaml index f1077dbc4f0..01d0dd7aa3a 100644 --- a/dts/bindings/clock/nordic,nrf-hsfll.yaml +++ b/dts/bindings/clock/nordic,nrf-local-hsfll.yaml @@ -2,15 +2,15 @@ # SPDX-License-Identifier: Apache-2.0 description: | - Nordic nRF HSFLL + Nordic nRF local HSFLL - The HSFLL mixed-mode IP generates several clock frequencies in the range from - 64 MHz to 400 MHz (in steps of 16 MHz). + 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"; + compatible = "nordic,nrf-hsfll-local"; reg = <0xdeadbeef 0x1000>; clocks = <&fll16m>; clock-frequency = ; @@ -22,7 +22,7 @@ description: | Required FICR entries are for VSUP, COARSE and FINE trim values. -compatible: "nordic,nrf-hsfll" +compatible: "nordic,nrf-hsfll-local" include: [base.yaml, fixed-clock.yaml, nordic-nrf-ficr-client.yaml] diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index a9523f15465..3c8d2696361 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -180,10 +180,13 @@ }; hsfll120: hsfll120 { - compatible = "fixed-clock"; + compatible = "nordic,nrf-hsfll-global"; clocks = <&fll16m>; #clock-cells = <0>; - clock-frequency = ; + supported-clock-frequencies = <64000000 + 128000000 + 256000000 + 320000000>; }; lfclk: lfclk { @@ -255,7 +258,7 @@ ranges = <0x0 0x52000000 0x1000000>; cpuapp_hsfll: clock@d000 { - compatible = "nordic,nrf-hsfll"; + compatible = "nordic,nrf-hsfll-local"; #clock-cells = <0>; reg = <0xd000 0x1000>; clocks = <&fll16m>; @@ -309,7 +312,7 @@ ranges = <0x0 0x53000000 0x1000000>; cpurad_hsfll: clock@d000 { - compatible = "nordic,nrf-hsfll"; + compatible = "nordic,nrf-hsfll-local"; #clock-cells = <0>; reg = <0xd000 0x1000>; clocks = <&fll16m>; diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index 4fd64cd10be..62b22b4fbc2 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -149,7 +149,7 @@ ranges = <0x0 0x52000000 0x1000000>; cpuapp_hsfll: clock@d000 { - compatible = "nordic,nrf-hsfll"; + compatible = "nordic,nrf-hsfll-local"; #clock-cells = <0>; reg = <0xd000 0x1000>; clocks = <&fll16m>; @@ -201,7 +201,7 @@ ranges = <0x0 0x53000000 0x1000000>; cpurad_hsfll: clock@d000 { - compatible = "nordic,nrf-hsfll"; + compatible = "nordic,nrf-hsfll-local"; #clock-cells = <0>; reg = <0xd000 0x1000>; clocks = <&fll16m>; diff --git a/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h b/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h index 7f6952f6f0b..e4a5b83a304 100644 --- a/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h +++ b/include/zephyr/dt-bindings/power/nordic-nrf-gpd.h @@ -8,10 +8,10 @@ #define ZEPHYR_INCLUDE_DT_BINDINGS_POWER_NORDIC_NRF_GLOBAL_PD /* numbers aligned to nrfs service identifiers */ -#define NRF_GPD_SLOW_MAIN 2U -#define NRF_GPD_SLOW_ACTIVE 1U -#define NRF_GPD_FAST_MAIN 3U -#define NRF_GPD_FAST_ACTIVE1 0U -#define NRF_GPD_FAST_ACTIVE0 4U +#define NRF_GPD_FAST_ACTIVE0 0U +#define NRF_GPD_FAST_ACTIVE1 1U +#define NRF_GPD_FAST_MAIN 2U +#define NRF_GPD_SLOW_ACTIVE 3U +#define NRF_GPD_SLOW_MAIN 4U #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_POWER_NORDIC_NRF_GLOBAL_PD */ diff --git a/modules/hal_nordic/nrfs/CMakeLists.txt b/modules/hal_nordic/nrfs/CMakeLists.txt index f470eea00e9..41dfb61f864 100644 --- a/modules/hal_nordic/nrfs/CMakeLists.txt +++ b/modules/hal_nordic/nrfs/CMakeLists.txt @@ -31,6 +31,7 @@ if(CONFIG_NRFS) zephyr_library_sources_ifdef(CONFIG_NRFS_RESET_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_reset.c) zephyr_library_sources_ifdef(CONFIG_NRFS_TEMP_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_temp.c) zephyr_library_sources_ifdef(CONFIG_NRFS_VBUS_DETECTOR_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_usb.c) + zephyr_library_sources_ifdef(CONFIG_NRFS_GDFS_SERVICE_ENABLED ${SRC_DIR}/services/nrfs_gdfs.c) zephyr_library_sources(${SRC_DIR}/internal/nrfs_dispatcher.c) add_subdirectory_ifdef(CONFIG_NRFS_DVFS_LOCAL_DOMAIN dvfs) diff --git a/modules/hal_nordic/nrfs/Kconfig b/modules/hal_nordic/nrfs/Kconfig index 8c5b61bb11f..2d244fffd7e 100644 --- a/modules/hal_nordic/nrfs/Kconfig +++ b/modules/hal_nordic/nrfs/Kconfig @@ -19,6 +19,9 @@ config NRFS_HAS_DIAG_SERVICE config NRFS_HAS_DVFS_SERVICE bool +config NRFS_HAS_GDFS_SERVICE + bool + config NRFS_HAS_GDPWR_SERVICE bool @@ -117,6 +120,11 @@ config NRFS_GDPWR_SERVICE_ENABLED depends on NRFS_HAS_GDPWR_SERVICE default y +config NRFS_GDFS_SERVICE_ENABLED + bool "Global domain frequeny scaling service" + depends on NRFS_HAS_GDFS_SERVICE + default y + endmenu rsource "backends/Kconfig" diff --git a/modules/hal_nordic/nrfs/nrfs_config.h b/modules/hal_nordic/nrfs/nrfs_config.h index a092adb7850..722608c90b4 100644 --- a/modules/hal_nordic/nrfs/nrfs_config.h +++ b/modules/hal_nordic/nrfs/nrfs_config.h @@ -44,6 +44,10 @@ #define NRFS_GDPWR_SERVICE_ENABLED #endif +#ifdef CONFIG_NRFS_GDFS_SERVICE_ENABLED +#define NRFS_GDFS_SERVICE_ENABLED +#endif + #ifdef CONFIG_SOC_POSIX #define NRFS_UNIT_TESTS_ENABLED #endif diff --git a/samples/boards/nordic/clock_control/configs/global_hsfll.conf b/samples/boards/nordic/clock_control/configs/global_hsfll.conf new file mode 100644 index 00000000000..53eebac30be --- /dev/null +++ b/samples/boards/nordic/clock_control/configs/global_hsfll.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CLOCK_CONTROL=y + +CONFIG_SAMPLE_CLOCK_FREQUENCY_HZ=320000000 diff --git a/samples/boards/nordic/clock_control/configs/global_hsfll.overlay b/samples/boards/nordic/clock_control/configs/global_hsfll.overlay new file mode 100644 index 00000000000..24585f5a5c6 --- /dev/null +++ b/samples/boards/nordic/clock_control/configs/global_hsfll.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/{ + aliases { + sample-clock = &hsfll120; + }; +}; diff --git a/samples/boards/nordic/clock_control/sample.yaml b/samples/boards/nordic/clock_control/sample.yaml index dd2cfe86c41..cc923ba2ab6 100644 --- a/samples/boards/nordic/clock_control/sample.yaml +++ b/samples/boards/nordic/clock_control/sample.yaml @@ -29,3 +29,8 @@ tests: extra_args: - CONF_FILE="configs/cpuapp_hsfll.conf" - DTC_OVERLAY_FILE="configs/cpuapp_hsfll.overlay" + sample.boards.nrf.clock_control.global_hsfll: + filter: dt_nodelabel_enabled("hsfll120") + extra_args: + - CONF_FILE="configs/global_hsfll.conf" + - DTC_OVERLAY_FILE="configs/global_hsfll.overlay" diff --git a/soc/nordic/nrf54h/CMakeLists.txt b/soc/nordic/nrf54h/CMakeLists.txt index 10c59b04583..a630a85fe79 100644 --- a/soc/nordic/nrf54h/CMakeLists.txt +++ b/soc/nordic/nrf54h/CMakeLists.txt @@ -9,6 +9,7 @@ if(CONFIG_ARM) endif() zephyr_library_sources_ifdef(CONFIG_PM_S2RAM pm_s2ram.c) +zephyr_library_sources_ifdef(CONFIG_SOC_NRF54H20_GLOBAL_HSFLL_RESTRICT_MIN_FREQ global_hsfll.c) zephyr_include_directories(.) diff --git a/soc/nordic/nrf54h/Kconfig b/soc/nordic/nrf54h/Kconfig index 3e46ce83077..74bd21dd02e 100644 --- a/soc/nordic/nrf54h/Kconfig +++ b/soc/nordic/nrf54h/Kconfig @@ -24,6 +24,7 @@ config SOC_NRF54H20_CPUAPP_COMMON select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select NRFS_HAS_CLOCK_SERVICE select NRFS_HAS_DVFS_SERVICE + select NRFS_HAS_GDFS_SERVICE select NRFS_HAS_GDPWR_SERVICE select NRFS_HAS_MRAM_SERVICE select NRFS_HAS_TEMP_SERVICE @@ -47,6 +48,7 @@ config SOC_NRF54H20_CPURAD_COMMON select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select NRFS_HAS_CLOCK_SERVICE + select NRFS_HAS_GDFS_SERVICE select NRFS_HAS_GDPWR_SERVICE select NRFS_HAS_MRAM_SERVICE select NRFS_HAS_TEMP_SERVICE @@ -71,3 +73,36 @@ config SOC_NRF54H20_NO_MRAM_LATENCY imply NRFS imply NRFS_MRAM_SERVICE_ENABLED default y if SOC_NRF54H20_CPUAPP + +config SOC_NRF54H20_GLOBAL_HSFLL_RESTRICT_MIN_FREQ + bool "Restrict minimum global HSFLL clock frequency" + select NRFS + select NRFS_GDFS_SERVICE_ENABLED + select CLOCK_CONTROL + default y if SOC_NRF54H20_CPUAPP + +if SOC_NRF54H20_GLOBAL_HSFLL_RESTRICT_MIN_FREQ + +choice SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_CHOICE + prompt "Minimum global HSFLL clock frequency in MHz" + default SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_320_MHZ + +config SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_64_MHZ + bool "Restrict minimum global HSFLL clock frequency to 64MHz" + +config SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_128_MHZ + bool "Restrict minimum global HSFLL clock frequency to 128MHz" + +config SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_256_MHZ + bool "Restrict minimum global HSFLL clock frequency to 256MHz" + +config SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_320_MHZ + bool "Restrict minimum global HSFLL clock frequency to 320MHz" + +endchoice + +config SOC_NRF54H20_GLOBAL_HSFLL_TIMEOUT_MS + int "Global HSFLL clock frequency timeout in milliseconds" + default 10000 + +endif # SOC_NRF54H20_RESTRICT_GLOBAL_HSFLL_FREQ diff --git a/soc/nordic/nrf54h/global_hsfll.c b/soc/nordic/nrf54h/global_hsfll.c new file mode 100644 index 00000000000..ae155a7df4c --- /dev/null +++ b/soc/nordic/nrf54h/global_hsfll.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +#if CONFIG_SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_64_MHZ +#define GLOBAL_HSFLL_MIN_FREQ_HZ 64000000 +#elif CONFIG_SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_128_MHZ +#define GLOBAL_HSFLL_MIN_FREQ_HZ 128000000 +#elif CONFIG_SOC_NRF54H20_GLOBAL_HSFLL_MIN_FREQ_256_MHZ +#define GLOBAL_HSFLL_MIN_FREQ_HZ 256000000 +#else +#define GLOBAL_HSFLL_MIN_FREQ_HZ 320000000 +#endif + +#define GLOBAL_HSFLL_REQUEST_TIMEOUT_US \ + (CONFIG_SOC_NRF54H20_GLOBAL_HSFLL_TIMEOUT_MS * USEC_PER_SEC) + +static struct onoff_client cli; +static const struct device *global_hsfll = DEVICE_DT_GET(DT_NODELABEL(hsfll120)); +static const struct nrf_clock_spec spec = { + .frequency = GLOBAL_HSFLL_MIN_FREQ_HZ, +}; + +static int nordicsemi_nrf54h_global_hsfll_init(void) +{ + int ret; + int res; + bool completed; + + sys_notify_init_spinwait(&cli.notify); + + ret = nrf_clock_control_request(global_hsfll, &spec, &cli); + if (ret) { + return ret; + } + + res = -EIO; + completed = WAIT_FOR(sys_notify_fetch_result(&cli.notify, &res) == 0, + GLOBAL_HSFLL_REQUEST_TIMEOUT_US, + k_msleep(1)); + + if (!completed) { + LOG_ERR("%s request timed out", "Restrict global HSFLL"); + return -EIO; + } + + if (res) { + LOG_ERR("%s request failed: (res=%i)", "Restrict global HSFLL", res); + return res; + } + + LOG_INF("%s to %uHz", "Restrict global HSFLL", GLOBAL_HSFLL_MIN_FREQ_HZ); + return 0; +} + +SYS_INIT(nordicsemi_nrf54h_global_hsfll_init, POST_KERNEL, 99); diff --git a/soc/nordic/nrf54h/gpd/gpd.c b/soc/nordic/nrf54h/gpd/gpd.c index a4d1889e53f..3cee31b700e 100644 --- a/soc/nordic/nrf54h/gpd/gpd.c +++ b/soc/nordic/nrf54h/gpd/gpd.c @@ -20,9 +20,11 @@ LOG_MODULE_REGISTER(gpd, CONFIG_SOC_LOG_LEVEL); /* enforce alignment between DT<->nrfs */ -BUILD_ASSERT(GDPWR_POWER_DOMAIN_ACTIVE_FAST == NRF_GPD_FAST_ACTIVE1); -BUILD_ASSERT(GDPWR_POWER_DOMAIN_ACTIVE_SLOW == NRF_GPD_SLOW_ACTIVE); -BUILD_ASSERT(GDPWR_POWER_DOMAIN_MAIN_SLOW == NRF_GPD_SLOW_MAIN); +BUILD_ASSERT(GDPWR_GD_FAST_ACTIVE_0 == NRF_GPD_FAST_ACTIVE0); +BUILD_ASSERT(GDPWR_GD_FAST_ACTIVE_1 == NRF_GPD_FAST_ACTIVE1); +BUILD_ASSERT(GDPWR_GD_FAST_MAIN == NRF_GPD_FAST_MAIN); +BUILD_ASSERT(GDPWR_GD_SLOW_ACTIVE == NRF_GPD_SLOW_ACTIVE); +BUILD_ASSERT(GDPWR_GD_SLOW_MAIN == NRF_GPD_SLOW_MAIN); struct gpd_onoff_manager { struct onoff_manager mgr; @@ -44,11 +46,21 @@ static void stop(struct onoff_manager *mgr, onoff_notify_fn notify); #define GPD_SERVICE_REQ_ERR BIT(3) static atomic_t gpd_service_status = ATOMIC_INIT(0); +static struct gpd_onoff_manager fast_active0 = { + .id = NRF_GPD_FAST_ACTIVE0, + .lock = Z_MUTEX_INITIALIZER(fast_active0.lock), + .sem = Z_SEM_INITIALIZER(fast_active0.sem, 0, 1), +}; static struct gpd_onoff_manager fast_active1 = { .id = NRF_GPD_FAST_ACTIVE1, .lock = Z_MUTEX_INITIALIZER(fast_active1.lock), .sem = Z_SEM_INITIALIZER(fast_active1.sem, 0, 1), }; +static struct gpd_onoff_manager fast_main = { + .id = NRF_GPD_FAST_MAIN, + .lock = Z_MUTEX_INITIALIZER(fast_main.lock), + .sem = Z_SEM_INITIALIZER(fast_main.sem, 0, 1), +}; static struct gpd_onoff_manager slow_active = { .id = NRF_GPD_SLOW_ACTIVE, .lock = Z_MUTEX_INITIALIZER(slow_active.lock), @@ -66,8 +78,12 @@ static const struct onoff_transitions transitions = static struct gpd_onoff_manager *get_mgr(uint8_t id) { switch (id) { + case NRF_GPD_FAST_ACTIVE0: + return &fast_active0; case NRF_GPD_FAST_ACTIVE1: return &fast_active1; + case NRF_GPD_FAST_MAIN: + return &fast_main; case NRF_GPD_SLOW_ACTIVE: return &slow_active; case NRF_GPD_SLOW_MAIN: @@ -286,11 +302,21 @@ static int nrf_gpd_pre_init(void) { int ret; + ret = onoff_manager_init(&fast_active0.mgr, &transitions); + if (ret < 0) { + return ret; + } + ret = onoff_manager_init(&fast_active1.mgr, &transitions); if (ret < 0) { return ret; } + ret = onoff_manager_init(&fast_main.mgr, &transitions); + if (ret < 0) { + return ret; + } + ret = onoff_manager_init(&slow_active.mgr, &transitions); if (ret < 0) { return ret; @@ -322,11 +348,21 @@ static int nrf_gpd_post_init(void) } /* submit GD requests now to align collected statuses */ + ret = nrf_gpd_sync(&fast_active0); + if (ret < 0) { + goto err; + } + ret = nrf_gpd_sync(&fast_active1); if (ret < 0) { goto err; } + ret = nrf_gpd_sync(&fast_main); + if (ret < 0) { + goto err; + } + ret = nrf_gpd_sync(&slow_active); if (ret < 0) { goto err; diff --git a/tests/drivers/clock_control/nrf_clock_control/src/main.c b/tests/drivers/clock_control/nrf_clock_control/src/main.c index 60cb9549f3d..f06bbb87e7d 100644 --- a/tests/drivers/clock_control/nrf_clock_control/src/main.c +++ b/tests/drivers/clock_control/nrf_clock_control/src/main.c @@ -104,6 +104,37 @@ static const struct test_clk_context cpurad_hsfll_test_clk_contexts[] = { }; #endif +const struct nrf_clock_spec test_clk_specs_global_hsfll[] = { + { + .frequency = MHZ(320), + .accuracy = 0, + .precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, + }, + { + .frequency = MHZ(256), + .accuracy = 0, + .precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, + }, + { + .frequency = MHZ(128), + .accuracy = 0, + .precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, + }, + { + .frequency = MHZ(64), + .accuracy = 0, + .precision = NRF_CLOCK_CONTROL_PRECISION_DEFAULT, + }, +}; + +static const struct test_clk_context global_hsfll_test_clk_contexts[] = { + { + .clk_dev = DEVICE_DT_GET(DT_NODELABEL(hsfll120)), + .clk_specs = test_clk_specs_global_hsfll, + .clk_specs_size = ARRAY_SIZE(test_clk_specs_global_hsfll), + }, +}; + const struct nrf_clock_spec test_clk_specs_lfclk[] = { { .frequency = 32768, @@ -151,8 +182,10 @@ static void test_request_release_clock_spec(const struct device *clk_dev, zassert_ok(ret); zassert_ok(res); ret = clock_control_get_rate(clk_dev, NULL, &rate); - zassert_ok(ret); - zassert_equal(rate, clk_spec->frequency); + if (ret != -ENOSYS) { + zassert_ok(ret); + zassert_equal(rate, clk_spec->frequency); + } k_msleep(1000); ret = nrf_clock_control_release(clk_dev, clk_spec); zassert_equal(ret, ONOFF_STATE_ON); @@ -249,6 +282,13 @@ ZTEST(nrf2_clock_control, test_lfclk_control) test_clock_control_request(lfclk_test_clk_contexts, ARRAY_SIZE(lfclk_test_clk_contexts)); } +ZTEST(nrf2_clock_control, test_global_hsfll_control) +{ + TC_PRINT("Global HSFLL test\n"); + test_clock_control_request(global_hsfll_test_clk_contexts, + ARRAY_SIZE(global_hsfll_test_clk_contexts)); +} + ZTEST(nrf2_clock_control, test_safe_request_cancellation) { int ret = 0; diff --git a/we b/we new file mode 100644 index 00000000000..e69de29bb2d diff --git a/west.yml b/west.yml index 248d015f6ae..faab8a8eb49 100644 --- a/west.yml +++ b/west.yml @@ -188,7 +188,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 54bde38c6f6ffb3780b26ae728cf79426184384e + revision: pull/265/head path: modules/hal/nordic groups: - hal