diff --git a/boards/arm/nucleo_h723zg/arduino_r3_connector.dtsi b/boards/arm/nucleo_h723zg/arduino_r3_connector.dtsi index 172fadfabee8c..6d5288633d2e7 100644 --- a/boards/arm/nucleo_h723zg/arduino_r3_connector.dtsi +++ b/boards/arm/nucleo_h723zg/arduino_r3_connector.dtsi @@ -35,5 +35,5 @@ }; arduino_i2c: &i2c1 {}; - +arduino_spi: &spi1 {}; arduino_serial: &uart8 {}; diff --git a/boards/arm/nucleo_h723zg/doc/index.rst b/boards/arm/nucleo_h723zg/doc/index.rst index 3df5540abffc0..4bf531006b8e0 100644 --- a/boards/arm/nucleo_h723zg/doc/index.rst +++ b/boards/arm/nucleo_h723zg/doc/index.rst @@ -107,6 +107,8 @@ features: +-------------+------------+-------------------------------------+ | I2C | on-chip | i2c | +-------------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-------------+------------+-------------------------------------+ | PWM | on-chip | pwm | +-------------+------------+-------------------------------------+ | ETHERNET | on-chip | ethernet | @@ -135,6 +137,7 @@ and a ST morpho connector. Board is configured as follows: - LD2 : PB7 - LD3 : PB14 - I2C : PB8, PB9 +- SPI1 NSS/SCK/MISO/MOSI : PD14PA5/PA6/PB5 (Arduino SPI) System Clock ------------ diff --git a/boards/arm/nucleo_h723zg/nucleo_h723zg.dts b/boards/arm/nucleo_h723zg/nucleo_h723zg.dts index 610d0a93bb64a..b97ee2737120b 100644 --- a/boards/arm/nucleo_h723zg/nucleo_h723zg.dts +++ b/boards/arm/nucleo_h723zg/nucleo_h723zg.dts @@ -115,6 +115,13 @@ status = "okay"; }; +&spi1 { + status = "okay"; + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pb5>; + pinctrl-names = "default"; + cs-gpios = <&gpiod 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + &i2c1 { pinctrl-0 = <&i2c1_scl_pb8 &i2c1_sda_pb9>; pinctrl-names = "default"; diff --git a/boards/arm/nucleo_h723zg/nucleo_h723zg.yaml b/boards/arm/nucleo_h723zg/nucleo_h723zg.yaml index 0539a8926fb68..98a6a0efcf592 100644 --- a/boards/arm/nucleo_h723zg/nucleo_h723zg.yaml +++ b/boards/arm/nucleo_h723zg/nucleo_h723zg.yaml @@ -11,10 +11,12 @@ flash: 1024 supported: - arduino_gpio - arduino_i2c + - arduino_spi - uart - gpio - counter - i2c - pwm + - spi - netif:eth - backup_sram diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 058c5a0cc94d2..56f0eaf69579a 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_control_rv32m1_pcc.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) + zephyr_library_sources_ifdef(CONFIG_CLOCK_STM32_MUX clock_stm32_mux.c) if(CONFIG_SOC_SERIES_STM32MP1X) zephyr_library_sources(clock_stm32_ll_mp1.c) elseif(CONFIG_SOC_SERIES_STM32H7X) diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index 83b70832bcba3..ba4d441656462 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -8,7 +8,7 @@ menuconfig CLOCK_CONTROL_STM32_CUBE bool "STM32 Reset & Clock Control" depends on SOC_FAMILY_STM32 select USE_STM32_LL_UTILS - select USE_STM32_LL_RCC if SOC_SERIES_STM32MP1X + select USE_STM32_LL_RCC if (SOC_SERIES_STM32MP1X || SOC_SERIES_STM32H7X) help Enable driver for Reset & Clock Control subsystem found in STM32 family of MCUs @@ -17,6 +17,7 @@ if CLOCK_CONTROL_STM32_CUBE DT_STM32_HSE_CLOCK := $(dt_nodelabel_path,clk_hse) DT_STM32_HSE_CLOCK_FREQ := $(dt_node_int_prop_int,$(DT_STM32_HSE_CLOCK),clock-frequency) +DT_COMPAT_ST_MUX_CLOCK := st,stm32-clock-mux config CLOCK_STM32_HSE_CLOCK int "HSE clock value" @@ -33,6 +34,15 @@ config CLOCK_STM32_HSE_CLOCK Note: Device tree configuration is overridden when current symbol is set: CONFIG_CLOCK_STM32_HSE_CLOCK=32000000 +config CLOCK_STM32_MUX + bool "STM32 clock mux driver" + default $(dt_compat_enabled,$(DT_COMPAT_ST_MUX_CLOCK)) + help + Enable driver for STM32 clock mux which don't match an + existing clock hardware block but allows to select a clock + for a specific domain. For instance per_ck clock on STM32H7 or + CLK48 clock + # Micro-controller Clock output configuration options choice diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index 93cbc401b8404..d678016a4025d 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -17,6 +17,7 @@ #include #include "stm32_hsem.h" + /* Macros to fill up prescaler values */ #define z_hsi_divider(v) LL_RCC_HSI_DIV ## v #define hsi_divider(v) z_hsi_divider(v) @@ -158,8 +159,6 @@ static uint32_t get_bus_clock(uint32_t clock, uint32_t prescaler) return clock / prescaler; } -#if !defined(CONFIG_CPU_CORTEX_M4) - static inline uint32_t get_pllout_frequency(uint32_t pllsrc_freq, int pllm_div, int plln_mul, @@ -214,6 +213,8 @@ static uint32_t get_hclk_frequency(void) return get_bus_clock(sysclk, STM32_HPRE); } +#if !defined(CONFIG_CPU_CORTEX_M4) + static int32_t prepare_regulator_voltage_scale(void) { /* Apply system power supply configuration */ @@ -310,101 +311,164 @@ static uint32_t get_vco_output_range(uint32_t vco_input_range) #endif /* ! CONFIG_CPU_CORTEX_M4 */ -static inline int stm32_clock_control_on(const struct device *dev, - clock_control_subsys_t sub_system) +/** @Brief Verifies clock is part of actve clock configuration */ +static inline int enabled_clock(uint32_t src_clk) { - struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); - int rc = 0; + int r = 0; - ARG_UNUSED(dev); - - /* Both cores can access banks by following LL API */ - /* Using "_Cn_" LL API would restrict access to one or the other */ - z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); - switch (pclken->bus) { - case STM32_CLOCK_BUS_AHB1: - LL_AHB1_GRP1_EnableClock(pclken->enr); + switch (src_clk) { + case STM32_SRC_SYSCLK: break; - case STM32_CLOCK_BUS_AHB2: - LL_AHB2_GRP1_EnableClock(pclken->enr); + case STM32_SRC_CKPER: + if (!IS_ENABLED(STM32_CKPER_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_AHB3: - LL_AHB3_GRP1_EnableClock(pclken->enr); + case STM32_SRC_HSE: + if (!IS_ENABLED(STM32_HSE_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_AHB4: - LL_AHB4_GRP1_EnableClock(pclken->enr); + case STM32_SRC_HSI_KER: + if (!IS_ENABLED(STM32_HSI_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_APB1: - LL_APB1_GRP1_EnableClock(pclken->enr); + case STM32_SRC_CSI_KER: + if (!IS_ENABLED(STM32_CSI_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_APB1_2: - LL_APB1_GRP2_EnableClock(pclken->enr); + case STM32_SRC_LSE: + if (!IS_ENABLED(STM32_LSE_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_APB2: - LL_APB2_GRP1_EnableClock(pclken->enr); + case STM32_SRC_LSI: + if (!IS_ENABLED(STM32_LSI_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_APB3: - LL_APB3_GRP1_EnableClock(pclken->enr); + case STM32_SRC_PLL1_P: + if (!IS_ENABLED(STM32_PLL_P_ENABLED)) { + r = -ENOTSUP; + } break; - case STM32_CLOCK_BUS_APB4: - LL_APB4_GRP1_EnableClock(pclken->enr); + case STM32_SRC_PLL1_Q: + if (!IS_ENABLED(STM32_PLL_Q_ENABLED)) { + r = -ENOTSUP; + } break; - default: - rc = -ENOTSUP; + case STM32_SRC_PLL1_R: + if (!IS_ENABLED(STM32_PLL_R_ENABLED)) { + r = -ENOTSUP; + } + break; + case STM32_SRC_PLL3_P: + if (!IS_ENABLED(STM32_PLL3_P_ENABLED)) { + r = -ENOTSUP; + } + break; + case STM32_SRC_PLL3_Q: + if (!IS_ENABLED(STM32_PLL3_Q_ENABLED)) { + r = -ENOTSUP; + } + break; + case STM32_SRC_PLL3_R: + if (!IS_ENABLED(STM32_PLL3_R_ENABLED)) { + r = -ENOTSUP; + } break; + default: + return -ENOTSUP; + } + + return r; +} + +static inline int stm32_clock_control_on(const struct device *dev, + clock_control_subsys_t sub_system) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); + volatile uint32_t *reg; + uint32_t reg_val; + + ARG_UNUSED(dev); + + if (IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX) == 0) { + /* Attemp to toggle a wrong periph clock bit */ + return -ENOTSUP; } + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); + + reg = (uint32_t *)(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus); + reg_val = *reg; + reg_val &= ~pclken->enr; + reg_val |= pclken->enr; + *reg = reg_val; + z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); - return rc; + return 0; } static inline int stm32_clock_control_off(const struct device *dev, clock_control_subsys_t sub_system) { struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); - int rc = 0; + volatile uint32_t *reg; + uint32_t reg_val; ARG_UNUSED(dev); - /* Both cores can access banks by following LL API */ - /* Using "_Cn_" LL API would restrict access to one or the other */ + if (IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX) == 0) { + /* Attemp to toggle a wrong periph clock bit */ + return -ENOTSUP; + } + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); - switch (pclken->bus) { - case STM32_CLOCK_BUS_AHB1: - LL_AHB1_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_AHB2: - LL_AHB2_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_AHB3: - LL_AHB3_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_AHB4: - LL_AHB4_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_APB1: - LL_APB1_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_APB1_2: - LL_APB1_GRP2_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_APB2: - LL_APB2_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_APB3: - LL_APB3_GRP1_DisableClock(pclken->enr); - break; - case STM32_CLOCK_BUS_APB4: - LL_APB4_GRP1_DisableClock(pclken->enr); - break; - default: - rc = -ENOTSUP; - break; + + reg = (uint32_t *)(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus); + reg_val = *reg; + reg_val &= ~pclken->enr; + *reg = reg_val; + + z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); + + return 0; +} + +static inline int stm32_clock_control_configure(const struct device *dev, + clock_control_subsys_t sub_system, + void *data) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); + volatile uint32_t *reg; + uint32_t reg_val, dt_val; + + ARG_UNUSED(dev); + ARG_UNUSED(data); + + if (enabled_clock(pclken->bus) < 0) { + /* Attemp to configure a src clock not available or not valid */ + return -ENOTSUP; } + + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); + + dt_val = STM32H7_CLOCK_VAL_GET(pclken->enr) << + STM32H7_CLOCK_SHIFT_GET(pclken->enr); + reg = (uint32_t *)(DT_REG_ADDR(DT_NODELABEL(rcc)) + + STM32H7_CLOCK_REG_GET(pclken->enr)); + reg_val = *reg; + reg_val &= ~dt_val; + reg_val |= dt_val; + *reg = reg_val; + z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); - return rc; + return 0; } static int stm32_clock_control_get_subsys_rate(const struct device *clock, @@ -450,6 +514,69 @@ static int stm32_clock_control_get_subsys_rate(const struct device *clock, case STM32_CLOCK_BUS_APB4: *rate = apb4_clock; break; + case STM32_SRC_SYSCLK: + *rate = get_hclk_frequency(); + break; +#if defined(STM32_CKPER_ENABLED) + case STM32_SRC_CKPER: + *rate = LL_RCC_GetCLKPClockFreq(LL_RCC_CLKP_CLKSOURCE); + break; +#endif /* STM32_CKPER_ENABLED */ +#if defined(STM32_HSE_ENABLED) + case STM32_SRC_HSE: + *rate = STM32_HSE_FREQ; + break; +#endif /* STM32_HSE_ENABLED */ +#if defined(STM32_LSE_ENABLED) + case STM32_SRC_LSE: + *rate = STM32_LSE_FREQ; + break; +#endif /* STM32_LSE_ENABLED */ +#if defined(STM32_LSI_ENABLED) + case STM32_SRC_LSI: + *rate = STM32_LSI_FREQ; + break; +#endif /* STM32_LSI_ENABLED */ +#if defined(STM32_PLL_ENABLED) + case STM32_SRC_PLL1_P: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_P_DIVISOR); + break; + case STM32_SRC_PLL1_Q: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_Q_DIVISOR); + break; + case STM32_SRC_PLL1_R: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_R_DIVISOR); + break; +#endif /* STM32_PLL_ENABLED */ +#if defined(STM32_PLL3_ENABLED) + case STM32_SRC_PLL3_P: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL3_M_DIVISOR, + STM32_PLL3_N_MULTIPLIER, + STM32_PLL3_P_DIVISOR); + break; + case STM32_SRC_PLL3_Q: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL3_M_DIVISOR, + STM32_PLL3_N_MULTIPLIER, + STM32_PLL3_Q_DIVISOR); + break; + case STM32_SRC_PLL3_R: + *rate = get_pllout_frequency(get_pllsrc_frequency(), + STM32_PLL3_M_DIVISOR, + STM32_PLL3_N_MULTIPLIER, + STM32_PLL3_R_DIVISOR); + break; +#endif /* STM32_PLL3_ENABLED */ default: return -ENOTSUP; } @@ -461,6 +588,7 @@ static struct clock_control_driver_api stm32_clock_control_api = { .on = stm32_clock_control_on, .off = stm32_clock_control_off, .get_rate = stm32_clock_control_get_subsys_rate, + .configure = stm32_clock_control_configure, }; __unused diff --git a/drivers/clock_control/clock_stm32_mux.c b/drivers/clock_control/clock_stm32_mux.c new file mode 100644 index 0000000000000..c4030475597f3 --- /dev/null +++ b/drivers/clock_control/clock_stm32_mux.c @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2022, Linaro Ltd + * + */ + +#include +#include +#include + +#include +#include + +#define DT_DRV_COMPAT st_stm32_clock_mux + +LOG_MODULE_REGISTER(clock_mux, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + + +struct stm32_clk_mux_config { + const struct stm32_pclken pclken; +}; + +static int stm32_clk_mux_init(const struct device *dev) +{ + const struct stm32_clk_mux_config *cfg = dev->config; + + if (clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &cfg->pclken) != 0) { + LOG_ERR("Could not enable clock mux"); + return -EIO; + } + + return 0; +} + +#define STM32_MUX_CLK_INIT(id) \ + \ +static const struct stm32_clk_mux_config stm32_clk_mux_cfg_##id = { \ + .pclken = STM32_INST_CLOCK_INFO(id, 0) \ +}; \ + \ +DEVICE_DT_INST_DEFINE(id, &stm32_clk_mux_init, NULL, \ + NULL, &stm32_clk_mux_cfg_##id, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(STM32_MUX_CLK_INIT) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 7e7387f099e9e..9015472524c61 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -489,10 +489,18 @@ static int spi_stm32_configure(const struct device *dev, #endif } - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &cfg->pclken, &clock) < 0) { - LOG_ERR("Failed call clock_control_get_rate"); - return -EIO; + if (IS_ENABLED(STM32_SPI_OPT_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) { + if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &cfg->pclken[1], &clock) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclk[1])"); + return -EIO; + } + } else { + if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &cfg->pclken[0], &clock) < 0) { + LOG_ERR("Failed call clock_control_get_rate(pclk[0])"); + return -EIO; + } } for (br = 1 ; br <= ARRAY_SIZE(scaler) ; ++br) { @@ -861,11 +869,20 @@ static int spi_stm32_init(const struct device *dev) int err; if (clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &cfg->pclken) != 0) { + (clock_control_subsys_t) &cfg->pclken[0]) != 0) { LOG_ERR("Could not enable SPI clock"); return -EIO; } + if (IS_ENABLED(STM32_SPI_OPT_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) { + if (clock_control_configure(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &cfg->pclken[1], + NULL) != 0) { + LOG_ERR("Could not select SPI soutce clock"); + return -EIO; + } + } + if (!spi_stm32_is_subghzspi(dev)) { /* Configure dt provided device signals when available */ err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); @@ -971,17 +988,20 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \ #define STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) #endif + + #define STM32_SPI_INIT(id) \ STM32_SPI_IRQ_HANDLER_DECL(id); \ \ PINCTRL_DT_INST_DEFINE(id); \ \ +static const struct stm32_pclken pclken_##id[] = \ + STM32_DT_INST_CLOCKS(id);\ + \ static const struct spi_stm32_config spi_stm32_cfg_##id = { \ .spi = (SPI_TypeDef *) DT_INST_REG_ADDR(id), \ - .pclken = { \ - .enr = DT_INST_CLOCKS_CELL(id, bits), \ - .bus = DT_INST_CLOCKS_CELL(id, bus) \ - }, \ + .pclken = pclken_##id, \ + .pclk_len = DT_INST_NUM_CLOCKS(id), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ STM32_SPI_IRQ_HANDLER_FUNC(id) \ STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) \ diff --git a/drivers/spi/spi_ll_stm32.h b/drivers/spi/spi_ll_stm32.h index 7d8206ee33359..969c0b9624c12 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -11,8 +11,15 @@ typedef void (*irq_config_func_t)(const struct device *port); +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with an optional clock */ +#if STM32_DT_INST_DEV_OPT_CLOCK_SUPPORT +#define STM32_SPI_OPT_CLOCK_SUPPORT 1 +#else +#define STM32_SPI_OPT_CLOCK_SUPPORT 0 +#endif + struct spi_stm32_config { - struct stm32_pclken pclken; SPI_TypeDef *spi; const struct pinctrl_dev_config *pcfg; #ifdef CONFIG_SPI_STM32_INTERRUPT @@ -21,6 +28,8 @@ struct spi_stm32_config { #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz) bool use_subghzspi_nss; #endif + size_t pclk_len; + const struct stm32_pclken *pclken; }; #ifdef CONFIG_SPI_STM32_DMA diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index eaa243b639c60..7ea27fa740ab3 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include #include @@ -90,6 +90,12 @@ reg = <2>; status = "disabled"; }; + + perck: perck { + #clock-cells = <0>; + compatible = "st,stm32-clock-mux"; + status = "disabled"; + }; }; soc { diff --git a/dts/bindings/clock/st,stm32-clock-mux.yaml b/dts/bindings/clock/st,stm32-clock-mux.yaml new file mode 100644 index 0000000000000..14981e0682437 --- /dev/null +++ b/dts/bindings/clock/st,stm32-clock-mux.yaml @@ -0,0 +1,43 @@ +# Copyright (c) 2022, Linaro ltd +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32 Clock multiplexer + Describes a clock multiplexer, such as per_ck on STM32H7 or + CLK48 on STM32L5. + The only property of this node is to select a clock input. + For instance: + &perck { + clocks = <&rcc STM32_SRC_HSI_KER CKPER_SEL(0)>; + status = "okay"; + }; + +compatible: "st,stm32-clock-mux" + +properties: + status: + type: string + required: false + description: indicates the operational status of a device + enum: + - "ok" # Deprecated form + - "okay" + - "disabled" + - "reserved" + - "fail" + - "fail-sss" + + compatible: + type: string-array + required: true + description: compatible strings + + clocks: + type: phandle-array + required: false + description: Clock gate information + + clock-names: + type: string-array + required: false + description: name of each clock diff --git a/include/drivers/clock_control.h b/include/drivers/clock_control.h index b64b3d1708982..99190b6448277 100644 --- a/include/drivers/clock_control.h +++ b/include/drivers/clock_control.h @@ -92,6 +92,10 @@ typedef int (*clock_control_set)(const struct device *dev, clock_control_subsys_t sys, clock_control_subsys_rate_t rate); +typedef int (*clock_control_configure_fn)(const struct device *dev, + clock_control_subsys_t sys, + void *data); + struct clock_control_driver_api { clock_control on; clock_control off; @@ -99,6 +103,7 @@ struct clock_control_driver_api { clock_control_get get_rate; clock_control_get_status_fn get_status; clock_control_set set_rate; + clock_control_configure_fn configure; }; /** @@ -270,6 +275,45 @@ static inline int clock_control_set_rate(const struct device *dev, return api->set_rate(dev, sys, rate); } +/** + * @brief Configure a source clock + * + * This function is non-blocking and can be called from any context. + * On success, the selected clock is configured as per caller's request. + * + * It is caller's responsibility to ensure that subsequent calls to the API + * provide the right information to allows clock_control driver to perform + * the right action (such as using the right clock source on clock_control_get_rate + * call). + * + * @p data is implementation specific and could be used to convey + * supplementary information required for expected clock configuration. + * + * @param dev Device structure whose driver controls the clock + * @param sys Opaque data representing the clock + * @param data Opaque data providing additional input for clock configuration + * + * @retval 0 On success + * @retval -ENOSYS If the device driver does not implement this call + * @retval -errno Other negative errno on failure. + */ +static inline int clock_control_configure(const struct device *dev, + clock_control_subsys_t sys, + void *data) +{ + if (!device_is_ready(dev)) { + return -ENODEV; + } + + const struct clock_control_driver_api *api = + (const struct clock_control_driver_api *)dev->api; + + if (api->configure == NULL) { + return -ENOSYS; + } + + return api->configure(dev, sys, data); +} #ifdef __cplusplus } diff --git a/include/drivers/clock_control/stm32_clock_control.h b/include/drivers/clock_control/stm32_clock_control.h index b1ee442c635eb..db6b06df389a8 100644 --- a/include/drivers/clock_control/stm32_clock_control.h +++ b/include/drivers/clock_control/stm32_clock_control.h @@ -10,7 +10,12 @@ #define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_STM32_CLOCK_CONTROL_H_ #include + +#if !defined(CONFIG_SOC_SERIES_STM32H7X) #include +#else +#include +#endif /** Common clock control device node for all STM32 chips */ #define STM32_CLOCK_CONTROL_NODE DT_NODELABEL(rcc) @@ -73,11 +78,11 @@ #define STM32_PLL_M_DIVISOR DT_PROP(DT_NODELABEL(pll), div_m) #define STM32_PLL_N_MULTIPLIER DT_PROP(DT_NODELABEL(pll), mul_n) #define STM32_PLL_P_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll), div_p) -#define STM32_PLL_P_DIVISOR DT_PROP(DT_NODELABEL(pll), div_p) +#define STM32_PLL_P_DIVISOR DT_PROP_OR(DT_NODELABEL(pll), div_p, 1) #define STM32_PLL_Q_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll), div_q) -#define STM32_PLL_Q_DIVISOR DT_PROP(DT_NODELABEL(pll), div_q) +#define STM32_PLL_Q_DIVISOR DT_PROP_OR(DT_NODELABEL(pll), div_q, 1) #define STM32_PLL_R_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll), div_r) -#define STM32_PLL_R_DIVISOR DT_PROP(DT_NODELABEL(pll), div_r) +#define STM32_PLL_R_DIVISOR DT_PROP_OR(DT_NODELABEL(pll), div_r, 1) #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll3), st_stm32h7_pll_clock, okay) @@ -85,11 +90,11 @@ #define STM32_PLL3_M_DIVISOR DT_PROP(DT_NODELABEL(pll3), div_m) #define STM32_PLL3_N_MULTIPLIER DT_PROP(DT_NODELABEL(pll3), mul_n) #define STM32_PLL3_P_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll3), div_p) -#define STM32_PLL3_P_DIVISOR DT_PROP(DT_NODELABEL(pll3), div_p) +#define STM32_PLL3_P_DIVISOR DT_PROP_OR(DT_NODELABEL(pll3), div_p, 1) #define STM32_PLL3_Q_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll3), div_q) -#define STM32_PLL3_Q_DIVISOR DT_PROP(DT_NODELABEL(pll3), div_q) +#define STM32_PLL3_Q_DIVISOR DT_PROP_OR(DT_NODELABEL(pll3), div_q, 1) #define STM32_PLL3_R_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll3), div_r) -#define STM32_PLL3_R_DIVISOR DT_PROP(DT_NODELABEL(pll3), div_r) +#define STM32_PLL3_R_DIVISOR DT_PROP_OR(DT_NODELABEL(pll3), div_r, 1) #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f1_pll_clock, okay) @@ -193,6 +198,10 @@ #define STM32_HSE_FREQ 0 #endif +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(perck), st_stm32_clock_mux, okay) +#define STM32_CKPER_ENABLED 1 +#endif + /** Driver structure definition */ struct stm32_pclken { @@ -200,4 +209,36 @@ struct stm32_pclken { uint32_t enr; }; +/** Device tree clocks helpers */ + +#define STM32_CLOCK_INFO(clk_index, id) \ + { \ + .enr = DT_CLOCKS_CELL_BY_IDX(DT_NODELABEL(id), clk_index, bits),\ + .bus = DT_CLOCKS_CELL_BY_IDX(DT_NODELABEL(id), clk_index, bus) \ + } +#define STM32_DT_CLOCKS(id) \ + { \ + LISTIFY(DT_NUM_CLOCKS(DT_NODELABEL(id)), \ + STM32_CLOCK_INFO, (,), id) \ + } + +#define STM32_INST_CLOCK_INFO(clk_index, inst) \ + { \ + .enr = DT_INST_CLOCKS_CELL_BY_IDX(inst, clk_index, bits), \ + .bus = DT_INST_CLOCKS_CELL_BY_IDX(inst, clk_index, bus) \ + } +#define STM32_DT_INST_CLOCKS(inst) \ + { \ + LISTIFY(DT_INST_NUM_CLOCKS(inst), \ + STM32_INST_CLOCK_INFO, (,), inst) \ + } + +#define STM32_OPT_CLOCK_INST_SUPPORT(inst) DT_INST_CLOCKS_HAS_IDX(inst, 1) || +#define STM32_DT_INST_DEV_OPT_CLOCK_SUPPORT \ + (DT_INST_FOREACH_STATUS_OKAY(STM32_OPT_CLOCK_INST_SUPPORT) 0) + +#define STM32_OPT_CLOCK_SUPPORT(id) DT_CLOCKS_HAS_IDX(DT_NODELABEL(id), 1) || +#define STM32_DT_DEV_OPT_CLOCK_SUPPORT \ + (DT_FOREACH_STATUS_OKAY(STM32_OPT_CLOCK_SUPPORT) 0) + #endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_STM32_CLOCK_CONTROL_H_ */ diff --git a/include/dt-bindings/clock/stm32h7_clock.h b/include/dt-bindings/clock/stm32h7_clock.h new file mode 100644 index 0000000000000..fb653af013e7b --- /dev/null +++ b/include/dt-bindings/clock/stm32h7_clock.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2017 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ + +/** Peripheral clock sources */ + +/* RM0468, Table 56 Kernel clock dictribution summary */ + +/** PLL outputs */ +#define STM32_SRC_PLL1_P 0x001 +#define STM32_SRC_PLL1_Q 0x002 +#define STM32_SRC_PLL1_R 0x003 +/** PLL2 not yet supported */ +/* #define STM32_SRC_PLL2_P 0x004 */ +/* #define STM32_SRC_PLL2_Q 0x005 */ +/* #define STM32_SRC_PLL2_R 0x006 */ +#define STM32_SRC_PLL3_P 0x007 +#define STM32_SRC_PLL3_Q 0x008 +#define STM32_SRC_PLL3_R 0x009 +/** Oscillators */ +#define STM32_SRC_HSE 0x00A +#define STM32_SRC_LSE 0x00B +#define STM32_SRC_LSI 0x00C +/** Oscillators not yet supported */ +/* #define STM32_SRC_HSI48 0x00D */ +#define STM32_SRC_HSI_KER 0x00E /* HSI + HSIKERON */ +#define STM32_SRC_CSI_KER 0x00F /* CSI + CSIKERON */ +/** Core clock */ +#define STM32_SRC_SYSCLK 0x010 +/** Others: Not yet supported */ +/* #define STM32_SRC_I2SCKIN 0x011 */ +/* #define STM32_SRC_SPDIFRX 0x012 */ +/** Clock muxes */ +#define STM32_SRC_CKPER 0x013 + +#define STM32_SRC_CLOCK_MIN STM32_SRC_PLL1_P +#define STM32_SRC_CLOCK_MAX STM32_SRC_CKPER + +/** Bus clocks */ +#define STM32_CLOCK_BUS_AHB3 0x0D4 +#define STM32_CLOCK_BUS_AHB1 0x0D8 +#define STM32_CLOCK_BUS_AHB2 0x0DC +#define STM32_CLOCK_BUS_AHB4 0x0E0 +#define STM32_CLOCK_BUS_APB3 0x0E4 +#define STM32_CLOCK_BUS_APB1 0x0E8 +#define STM32_CLOCK_BUS_APB1_2 0x0EC +#define STM32_CLOCK_BUS_APB2 0x0F0 +#define STM32_CLOCK_BUS_APB4 0x0F4 +/** Alias D1/2/3 domains clocks */ /* TBD: To remove ? */ +#define STM32_SRC_PCLK1 STM32_CLOCK_BUS_APB1 +#define STM32_SRC_PCLK2 STM32_CLOCK_BUS_APB2 +#define STM32_SRC_HCLK3 STM32_CLOCK_BUS_AHB3 +#define STM32_SRC_PCLK3 STM32_CLOCK_BUS_APB3 +#define STM32_SRC_PCLK4 STM32_CLOCK_BUS_APB4 + +#define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB3 +#define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB4 + +/** + * @brief STM32H7 clock configuration bit field. + * + * - reg (0/1) [ 0 : 7 ] + * - shift (0..31) [ 8 : 12 ] + * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] + * - val (0..3) [ 16 : 18 ] + * + * @param reg RCC_DxCCIP register offset + * @param shift Position within RCC_DxCCIP. + * @param mask Mask for the RCC_DxCCIP field. + * @param val Clock value (0, 1, 2 or 3). + */ + +#define STM32H7_CLOCK_REG_MASK 0xFFU +#define STM32H7_CLOCK_REG_SHIFT 0U +#define STM32H7_CLOCK_SHIFT_MASK 0x1FU +#define STM32H7_CLOCK_SHIFT_SHIFT 8U +#define STM32H7_CLOCK_MASK_MASK 0x7U +#define STM32H7_CLOCK_MASK_SHIFT 13U +#define STM32H7_CLOCK_VAL_MASK 0x7U +#define STM32H7_CLOCK_VAL_SHIFT 16U + +#define STM32H7_CLOCK(val, mask, shift, reg) \ + ((((reg) & STM32H7_CLOCK_REG_MASK) << STM32H7_CLOCK_REG_SHIFT) | \ + (((shift) & STM32H7_CLOCK_SHIFT_MASK) << STM32H7_CLOCK_SHIFT_SHIFT) | \ + (((mask) & STM32H7_CLOCK_MASK_MASK) << STM32H7_CLOCK_MASK_SHIFT) | \ + (((val) & STM32H7_CLOCK_VAL_MASK) << STM32H7_CLOCK_VAL_SHIFT)) + + +/* Accessors for clock value */ + +/** + * @brief Obtain register field from clock configuration. + * + * @param clock clock bit field value. + */ +#define STM32H7_CLOCK_REG_GET(clock) \ + (((clock) >> STM32H7_CLOCK_REG_SHIFT) & STM32H7_CLOCK_REG_MASK) + +/** + * @brief Obtain position field from clock configuration. + * + * @param clock Clock bit field value. + */ +#define STM32H7_CLOCK_SHIFT_GET(clock) \ + (((clock) >> STM32H7_CLOCK_SHIFT_SHIFT) & STM32H7_CLOCK_SHIFT_MASK) + +/** + * @brief Obtain mask field from clock configuration. + * + * @param clock Clock bit field value. + */ +#define STM32H7_CLOCK_MASK_GET(clock) \ + (((clock) >> STM32H7_CLOCK_MASK_SHIFT) & STM32H7_CLOCK_MASK_MASK) + +/** + * @brief Obtain value field from clock configuration. + * + * @param clock Clock bit field value. + */ +#define STM32H7_CLOCK_VAL_GET(clock) \ + (((clock) >> STM32H7_CLOCK_VAL_SHIFT) & STM32H7_CLOCK_VAL_MASK) + +/** @brief RCC_DxCCIP register offset (RM0399.pdf) */ +#define D1CCIPR_REG 0x4C +#define D2CCIP1R_REG 0x50 +#define D2CCIP2R_REG 0x54 +#define D3CCIPR_REG 0x58 + +/** @brief Device clk sources selection helpers (RM0399.pdf) */ +/** D1CCIPR devices */ +#define FMC_SEL(val) STM32H7_CLOCK(val, 3, 0, D1CCIPR_REG) +#define QSPI_SEL(val) STM32H7_CLOCK(val, 3, 4, D1CCIPR_REG) +#define DSI_SEL(val) STM32H7_CLOCK(val, 1, 8, D1CCIPR_REG) +#define SDMMC_SEL(val) STM32H7_CLOCK(val, 1, 16, D1CCIPR_REG) +#define CKPER_SEL(val) STM32H7_CLOCK(val, 3, 28, D1CCIPR_REG) +/** D2CCIP1R devices */ +#define SAI1_SEL(val) STM32H7_CLOCK(val, 7, 0, D2CCIP1R_REG) +#define SAI23_SEL(val) STM32H7_CLOCK(val, 7, 6, D2CCIP1R_REG) +#define SPI123_SEL(val) STM32H7_CLOCK(val, 7, 12, D2CCIP1R_REG) +#define SPI45_SEL(val) STM32H7_CLOCK(val, 7, 16, D2CCIP1R_REG) +#define SPDIF_SEL(val) STM32H7_CLOCK(val, 3, 20, D2CCIP1R_REG) +#define DFSDM1_SEL(val) STM32H7_CLOCK(val, 1, 24, D2CCIP1R_REG) +#define FDCAN_SEL(val) STM32H7_CLOCK(val, 3, 28, D2CCIP1R_REG) +#define SWP_SEL(val) STM32H7_CLOCK(val, 1, 31, D2CCIP1R_REG) +/** D2CCIP2R devices */ +#define USART2345678_SEL(val) STM32H7_CLOCK(val, 7, 0, D2CCIP2R_REG) +#define USART16_SEL(val) STM32H7_CLOCK(val, 7, 3, D2CCIP2R_REG) +#define RNG_SEL(val) STM32H7_CLOCK(val, 3, 8, D2CCIP2R_REG) +#define I2C123_SEL(val) STM32H7_CLOCK(val, 3, 12, D2CCIP2R_REG) +#define USB_SEL(val) STM32H7_CLOCK(val, 3, 20, D2CCIP2R_REG) +#define CEC_SEL(val) STM32H7_CLOCK(val, 3, 22, D2CCIP2R_REG) +#define LPTIM1_SEL(val) STM32H7_CLOCK(val, 7, 28, D2CCIP2R_REG) +/** D3CCIPR devices */ +#define LPUART1_SEL(val) STM32H7_CLOCK(val, 7, 0, D3CCIPR_REG) +#define I2C4_SEL(val) STM32H7_CLOCK(val, 3, 8, D3CCIPR_REG) +#define LPTIM2_SEL(val) STM32H7_CLOCK(val, 7, 10, D3CCIPR_REG) +#define LPTIM345_SEL(val) STM32H7_CLOCK(val, 7, 13, D3CCIPR_REG) +#define ADC_SEL(val) STM32H7_CLOCK(val, 3, 16, D3CCIPR_REG) +#define SAI4A_SEL(val) STM32H7_CLOCK(val, 7, 21, D3CCIPR_REG) +#define SAI4B_SEL(val) STM32H7_CLOCK(val, 7, 24, D3CCIPR_REG) +#define SPI6_SEL(val) STM32H7_CLOCK(val, 7, 28, D3CCIPR_REG) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ */ diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/CMakeLists.txt b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/CMakeLists.txt similarity index 82% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/CMakeLists.txt rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/CMakeLists.txt index c6ced117d5672..d0636fde3bbdc 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/CMakeLists.txt +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(stm32_clock_configuration_h7) +project(stm32_clock_configuration_h7_core) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/clear_clocks.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/clear_clocks.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/clear_clocks.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/clear_clocks.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/csi_4.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/csi_4.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/csi_4.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/csi_4.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/hse_8.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hse_8.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/hse_8.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hse_8.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/hsi_64.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hsi_64.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/hsi_64.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/hsi_64.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_csi_96.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_csi_96.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_csi_96.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_csi_96.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_hse_550.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_hse_550.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_hse_550.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_hse_550.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_hse_96.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_hse_96.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_hse_96.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_hse_96.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_hsi_96.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_hsi_96.overlay similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/boards/pll_hsi_96.overlay rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/boards/pll_hsi_96.overlay diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/prj.conf b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/prj.conf similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/prj.conf rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/prj.conf diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/src/test_stm32_clock_configuration.c b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/src/test_stm32_clock_configuration.c similarity index 100% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/src/test_stm32_clock_configuration.c rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/src/test_stm32_clock_configuration.c diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/testcase.yaml b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml similarity index 61% rename from tests/drivers/clock_control/stm32_clock_configuration/stm32h7/testcase.yaml rename to tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml index 885530b7cd5ca..caa87da49ae20 100644 --- a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7/testcase.yaml +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_core/testcase.yaml @@ -2,18 +2,18 @@ common: timeout: 5 platform_allow: nucleo_h723zg tests: - drivers.stm32_clock_configuration.h7.sysclksrc_pll_hse_96: + drivers.stm32_clock_configuration.h7_core.sysclksrc_pll_hse_96: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_hse_96.overlay" - drivers.stm32_clock_configuration.h7.sysclksrc_pll_hsi_96: + drivers.stm32_clock_configuration.h7_core.sysclksrc_pll_hsi_96: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_hsi_96.overlay" - drivers.stm32_clock_configuration.h7.sysclksrc_hsi_64: + drivers.stm32_clock_configuration.h7_core.sysclksrc_hsi_64: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hsi_64.overlay" - drivers.stm32_clock_configuration.h7.sysclksrc_csi_4: + drivers.stm32_clock_configuration.h7_core.sysclksrc_csi_4: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/csi_4.overlay" - drivers.stm32_clock_configuration.h7.sysclksrc_hse_8: + drivers.stm32_clock_configuration.h7_core.sysclksrc_hse_8: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hse_8.overlay" - drivers.stm32_clock_configuration.h7.sysclksrc_pll_csi_96: + drivers.stm32_clock_configuration.h7_core.sysclksrc_pll_csi_96: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_csi_96.overlay" - drivers.stm32_clock_configuration.h7.sysclksrc_pll_hse_550: + drivers.stm32_clock_configuration.h7_core.sysclksrc_pll_hse_550: extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_hse_550.overlay" platform_allow: nucleo_h723zg stm32h735g_disco diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/CMakeLists.txt b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/CMakeLists.txt new file mode 100644 index 0000000000000..fdef1a9b79454 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(stm32_clock_configuration_h7_devices) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/core_init.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/core_init.overlay new file mode 100644 index 0000000000000..5b1e3c19f3aa7 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/core_init.overlay @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay clears clocks back to a state equivalent to what could + * be found in stm32h7.dtsi + */ + + +/* Clocks clean up config + * Aim is to avoid conflict with specific default board configuration + */ + +&clk_hse { + status = "disabled"; + /delete-property/ hse-bypass; + /delete-property/ clock-frequency; +}; + +&clk_hsi { + status = "disabled"; + /delete-property/ hsi-div; +}; + +&clk_csi { + status = "disabled"; +}; + +&clk_lse { + status = "disabled"; +}; + +&clk_lsi { + status = "disabled"; +}; + +&pll { + /delete-property/ div-m; + /delete-property/ mul-n; + /delete-property/ div-p; + /delete-property/ div-q; + /delete-property/ div-r; + /delete-property/ clocks; + status = "disabled"; +}; + +&pll3 { + /delete-property/ div-m; + /delete-property/ mul-n; + /delete-property/ div-p; + /delete-property/ div-q; + /delete-property/ div-r; + /delete-property/ clocks; + status = "disabled"; +}; + +&rcc { + /delete-property/ clocks; + /delete-property/ clock-frequency; + /delete-property/ d1cpre; + /delete-property/ hpre; + /delete-property/ d1ppre; + /delete-property/ d2ppre1; + /delete-property/ d2ppre2; + /delete-property/ d3ppre; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pb5>; + pinctrl-names = "default"; + status = "disabled"; +}; + +/* Core set up + * Aim of this part is to provide a base working clock config + */ + +&clk_hse { + hse-bypass; + clock-frequency = ; /* STLink 8MHz clock */ + status = "okay"; +}; + +&pll { + div-m = <1>; + mul-n = <24>; + div-p = <2>; + div-q = <1>; + div-r = <1>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + d1cpre = <1>; + hpre = <1>; + d1ppre = <1>; + d2ppre1 = <1>; + d2ppre2 = <1>; + d3ppre = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_per_ck_d1ppre_1.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_per_ck_d1ppre_1.overlay new file mode 100644 index 0000000000000..7b74b243d70bd --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_per_ck_d1ppre_1.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after core_init.overlay file. + */ + +&clk_hsi { + status = "okay"; + hsi-div = <1>; +}; + +&perck { + clocks = <&rcc STM32_SRC_HSI_KER CKPER_SEL(0)>; + status = "okay"; +}; + +&spi1 { + /delete-property/ clocks; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_CKPER SPI123_SEL(4)>; + clock-names = "reg", "kernel"; + status = "okay"; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_per_ck_hsi.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_per_ck_hsi.overlay new file mode 100644 index 0000000000000..eaf1a621395dc --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_per_ck_hsi.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after core_init.overlay file. + */ + +&clk_hsi { + status = "okay"; + hsi-div = <8>; /* HSI RC: 64MHz, hsi_clk = 8MHz */ +}; + +&perck { + clocks = <&rcc STM32_SRC_HSI_KER CKPER_SEL(0)>; + status = "okay"; +}; + +&spi1 { + /delete-property/ clocks; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_CKPER SPI123_SEL(4)>; + clock-names = "reg", "kernel"; + status = "okay"; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pll3p_1_d1ppre_4.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pll3p_1_d1ppre_4.overlay new file mode 100644 index 0000000000000..0fce8a24c2022 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pll3p_1_d1ppre_4.overlay @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after core_init.overlay file. + */ + +&pll3 { + clocks = <&clk_hse>; + div-m = <1>; + mul-n = <24>; + div-p = <1>; + status = "okay"; +}; + +&rcc { + /delete-property/ d1ppre; + d1ppre = <4>; +}; + +&spi1 { + /delete-property/ clocks; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_PLL3_P SPI123_SEL(2)>; + clock-names = "reg", "kernel"; + status = "okay"; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pllq_1_d1ppre_1.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pllq_1_d1ppre_1.overlay new file mode 100644 index 0000000000000..9adca96611f6b --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pllq_1_d1ppre_1.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after core_init.overlay file. + */ + +&pll { + /delete-property/ div-q; + div-q = <1>; +}; + +&rcc { + /delete-property/ d1ppre; + d1ppre = <1>; +}; + +&spi1 { + /delete-property/ clocks; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + clock-names = "reg", "kernel"; + status = "okay"; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pllq_2_d1ppre_4.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pllq_2_d1ppre_4.overlay new file mode 100644 index 0000000000000..5cfb5e6da47f5 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/boards/spi1_pllq_2_d1ppre_4.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after core_init.overlay file. + */ + +/* With this particular div-q and d1ppre values + * APB2 and PLL_Q clock frequencies are equal. + * This setting is default stm32h7 SPI devices configuration. + * This test config ensures it still works. + */ + +&pll { + /delete-property/ div-q; + div-q = <2>; +}; + +&rcc { + /delete-property/ d1ppre; + d1ppre = <4>; +}; + +&spi1 { + /delete-property/ clocks; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>; + clock-names = "reg"; + status = "okay"; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/prj.conf b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/prj.conf new file mode 100644 index 0000000000000..9467c2926896d --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/src/test_stm32_clock_configuration.c b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/src/test_stm32_clock_configuration.c new file mode 100644 index 0000000000000..a682d427475f2 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/src/test_stm32_clock_configuration.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2022 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(test); + +#define DT_DRV_COMPAT st_stm32_spi + +#if STM32_DT_INST_DEV_OPT_CLOCK_SUPPORT +#define STM32_SPI_OPT_CLOCK_SUPPORT 1 +#else +#define STM32_SPI_OPT_CLOCK_SUPPORT 0 +#endif + +#define DT_NO_CLOCK 0xFFFFU + +/* Not device related, but keep it to ensure core clock config is correct */ +static void test_sysclk_freq(void) +{ + uint32_t soc_sys_clk_freq; + + soc_sys_clk_freq = HAL_RCC_GetSysClockFreq(); + + zassert_equal(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, soc_sys_clk_freq, + "Expected sysclockfreq: %d. Actual sysclockfreq: %d", + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, soc_sys_clk_freq); +} + +static void test_spi_clk_config(void) +{ + static const struct stm32_pclken pclken[] = STM32_DT_CLOCKS(spi1); + struct stm32_pclken spi1_reg_clk_cfg = pclken[0]; + + uint32_t spi1_actual_clk_src, spi1_dt_ker_clk_src; + uint32_t spi1_dt_clk_freq, spi1_actual_clk_freq; + int r; + + /* Test clock_on(reg_clk) */ + r = clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &spi1_reg_clk_cfg); + zassert_true((r == 0), "Could not enable SPI reg_clk"); + + zassert_true(__HAL_RCC_SPI1_IS_CLK_ENABLED(), "SPI1 reg_clk should be on"); + TC_PRINT("SPI1 reg_clk on\n"); + + if (IS_ENABLED(STM32_SPI_OPT_CLOCK_SUPPORT) && DT_NUM_CLOCKS(DT_NODELABEL(spi1)) > 1) { + struct stm32_pclken spi1_ker_clk_cfg = pclken[1]; + + /* Select ker_clk as device source clock */ + r = clock_control_configure(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &spi1_ker_clk_cfg, + NULL); + zassert_true((r == 0), "Could not enable SPI ker_clk"); + TC_PRINT("SPI1 ker_clk on\n"); + + /* Test ker_clk is configured as device's source clock */ + spi1_dt_ker_clk_src = COND_CODE_1(DT_CLOCKS_HAS_NAME(DT_NODELABEL(spi1), kernel), + (DT_CLOCKS_CELL_BY_NAME(DT_NODELABEL(spi1), + kernel, bus)), + (DT_NO_CLOCK)); + spi1_actual_clk_src = __HAL_RCC_GET_SPI1_SOURCE(); + + if (spi1_dt_ker_clk_src == STM32_SRC_PLL1_Q) { + zassert_equal(spi1_actual_clk_src, RCC_SPI123CLKSOURCE_PLL, + "Expected SPI src: PLLQ (%d). Actual SPI src: %d", + spi1_actual_clk_src, RCC_SPI123CLKSOURCE_PLL); + } else if (spi1_dt_ker_clk_src == STM32_SRC_PLL3_P) { + zassert_equal(spi1_actual_clk_src, RCC_SPI123CLKSOURCE_PLL3, + "Expected SPI src: PLLQ (%d). Actual SPI src: %d", + spi1_actual_clk_src, RCC_SPI123CLKSOURCE_PLL3); + } else if (spi1_dt_ker_clk_src == STM32_SRC_CKPER) { + zassert_equal(spi1_actual_clk_src, RCC_SPI123CLKSOURCE_CLKP, + "Expected SPI src: PLLQ (%d). Actual SPI src: %d", + spi1_actual_clk_src, RCC_SPI123CLKSOURCE_CLKP); + } else { + zassert_true(1, "Unexpected ker_clk src(%d)", spi1_dt_ker_clk_src); + } + + /* Test get_rate(ker_clk) */ + r = clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &spi1_ker_clk_cfg, + &spi1_dt_clk_freq); + zassert_true((r == 0), "Could not get SPI clk freq"); + + spi1_actual_clk_freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI1); + zassert_equal(spi1_dt_clk_freq, spi1_actual_clk_freq, + "Expected SPI clk: (%d). Actual SPI clk: %d", + spi1_dt_clk_freq, spi1_actual_clk_freq); + } else { + /* No alt clock available, get rate from reg_clk */ + + /* Test get_rate(reg_clk) */ + r = clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &spi1_reg_clk_cfg, + &spi1_dt_clk_freq); + zassert_true((r == 0), "Could not get SPI clk freq"); + + spi1_actual_clk_freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI1); + zassert_equal(spi1_dt_clk_freq, spi1_actual_clk_freq, + "Expected SPI clk: (%d). Actual SPI clk: %d", + spi1_dt_clk_freq, spi1_actual_clk_freq); + } + + TC_PRINT("SPI1 clock freq: %d(MHz)\n", spi1_actual_clk_freq / (1000*1000)); + + /* Test clock_off(reg_clk) */ + r = clock_control_off(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), + (clock_control_subsys_t) &spi1_reg_clk_cfg); + zassert_true((r == 0), "Could not disable SPI reg_clk"); + + zassert_true(!__HAL_RCC_SPI1_IS_CLK_ENABLED(), "SPI1 reg_clk should be off"); + TC_PRINT("SPI1 reg_clk off\n"); + + /* Test clock_off(ker_clk) */ + /* Not supported today */ +} + +void test_main(void) +{ + ztest_test_suite(test_stm32h7_devices_clocks, + ztest_unit_test(test_sysclk_freq), + ztest_unit_test(test_spi_clk_config) + ); + ztest_run_test_suite(test_stm32h7_devices_clocks); +} diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/testcase.yaml b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/testcase.yaml new file mode 100644 index 0000000000000..0742d727e52fb --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32h7_devices/testcase.yaml @@ -0,0 +1,14 @@ +common: + timeout: 5 + platform_allow: nucleo_h723zg +tests: + drivers.stm32_clock_configuration.h7_dev.spi1_pllq_1_d1ppre_1: + extra_args: DTC_OVERLAY_FILE="boards/core_init.overlay;boards/spi1_pllq_1_d1ppre_1.overlay" + drivers.stm32_clock_configuration.h7_dev.spi1_pllq_2_d1ppre_4: + extra_args: DTC_OVERLAY_FILE="boards/core_init.overlay;boards/spi1_pllq_2_d1ppre_4.overlay" + drivers.stm32_clock_configuration.h7_dev.spi1_pll3p_1_d1ppre_4: + extra_args: DTC_OVERLAY_FILE="boards/core_init.overlay;boards/spi1_pll3p_1_d1ppre_4.overlay" + drivers.stm32_clock_configuration.h7_dev.spi1_per_ck_d1ppre_1: + extra_args: DTC_OVERLAY_FILE="boards/core_init.overlay;boards/spi1_per_ck_d1ppre_1.overlay" + drivers.stm32_clock_configuration.h7_dev.spi1_per_ck_hsi: + extra_args: DTC_OVERLAY_FILE="boards/core_init.overlay;boards/spi1_per_ck_hsi.overlay" diff --git a/tests/drivers/spi/spi_loopback/boards/nucleo_h723zg.overlay b/tests/drivers/spi/spi_loopback/boards/nucleo_h723zg.overlay new file mode 100644 index 0000000000000..acfb504ab4ac0 --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/nucleo_h723zg.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2021 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Set div-q to get test clk freq into acceptable SPI freq range */ +&pll { + /delete-property/ div-q; + div-q = <8>; +}; + +/* Define PLL1_Q as SPI1 kernel clock source */ +&spi1 { + /delete-property/ clocks; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + clock-names = "reg", "kernel"; +};