diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index ef3982f8a78..a1652114d05 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) @@ -168,9 +169,9 @@ static uint32_t get_bus_clock(uint32_t clock, uint32_t prescaler) __unused static uint32_t get_pllout_frequency(uint32_t pllsrc_freq, - int pllm_div, - int plln_mul, - int pllout_div) + int pllm_div, + int plln_mul, + int pllout_div) { __ASSERT_NO_MSG(pllm_div && pllout_div); @@ -321,6 +322,28 @@ static uint32_t get_vco_output_range(uint32_t vco_input_range) #endif /* ! CONFIG_CPU_CORTEX_M4 */ +/** @brief Verifies clock is part of actve clock configuration */ +static int enabled_clock(uint32_t src_clk) +{ + + if ((src_clk == STM32_SRC_SYSCLK) || + ((src_clk == STM32_SRC_HSE) && IS_ENABLED(STM32_HSE_ENABLED)) || + ((src_clk == STM32_SRC_HSI_KER) && IS_ENABLED(STM32_HSI_ENABLED)) || + ((src_clk == STM32_SRC_CSI_KER) && IS_ENABLED(STM32_CSI_ENABLED)) || + ((src_clk == STM32_SRC_LSE) && IS_ENABLED(STM32_LSE_ENABLED)) || + ((src_clk == STM32_SRC_LSI) && IS_ENABLED(STM32_LSI_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_P) && IS_ENABLED(STM32_PLL_P_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_Q) && IS_ENABLED(STM32_PLL_Q_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_R) && IS_ENABLED(STM32_PLL_R_ENABLED)) || + ((src_clk == STM32_SRC_PLL3_P) && IS_ENABLED(STM32_PLL3_P_ENABLED)) || + ((src_clk == STM32_SRC_PLL3_Q) && IS_ENABLED(STM32_PLL3_Q_ENABLED)) || + ((src_clk == STM32_SRC_PLL3_R) && IS_ENABLED(STM32_PLL3_R_ENABLED))) { + return 0; + } + + return -ENOTSUP; +} + static inline int stm32_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) { @@ -373,6 +396,40 @@ static inline int stm32_clock_control_off(const struct device *dev, 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; + int err; + + ARG_UNUSED(dev); + ARG_UNUSED(data); + + err = enabled_clock(pclken->bus); + if (err < 0) { + /* Attemp to configure a src clock not available or not valid */ + return err; + } + + 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 0; +} + static int stm32_clock_control_get_subsys_rate(const struct device *clock, clock_control_subsys_t sub_system, uint32_t *rate) @@ -416,6 +473,64 @@ 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_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; } @@ -427,6 +542,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/include/zephyr/dt-bindings/clock/stm32h7_clock.h b/include/zephyr/dt-bindings/clock/stm32h7_clock.h index 608bc218281..65b647826b6 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7_clock.h @@ -6,16 +6,163 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ -/* clock bus references */ -#define STM32_CLOCK_BUS_AHB3 0x134 -#define STM32_CLOCK_BUS_AHB1 0x138 -#define STM32_CLOCK_BUS_AHB2 0x13c -#define STM32_CLOCK_BUS_AHB4 0x140 -#define STM32_CLOCK_BUS_APB3 0x144 -#define STM32_CLOCK_BUS_APB1 0x148 -#define STM32_CLOCK_BUS_APB1_2 0x14c -#define STM32_CLOCK_BUS_APB2 0x150 -#define STM32_CLOCK_BUS_APB4 0x154 +/** 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_PER 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) #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB3 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB4