diff --git a/doc/releases/release-notes-4.4.rst b/doc/releases/release-notes-4.4.rst index a33b0b3e9d0e0..2d3010554d4b0 100644 --- a/doc/releases/release-notes-4.4.rst +++ b/doc/releases/release-notes-4.4.rst @@ -117,6 +117,12 @@ New APIs and options * :kconfig:option:`CONFIG_NVMEM_FLASH` * :kconfig:option:`CONFIG_NVMEM_FLASH_WRITE` +* Power + + * The new ``voltage-scale`` property of :dtcompatible:`st,stm32u5-pwr` can be used to + select the voltage scale manually on STM32U5 series via Devicetree. This notably + enables usage of the USB controller at lower system clock frequencies. + * Settings * :kconfig:option:`CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION` diff --git a/drivers/clock_control/clock_stm32_ll_u5.c b/drivers/clock_control/clock_stm32_ll_u5.c index d7b69a9b90d05..54574d26b6824 100644 --- a/drivers/clock_control/clock_stm32_ll_u5.c +++ b/drivers/clock_control/clock_stm32_ll_u5.c @@ -37,6 +37,17 @@ #define PLL2_ID 2 #define PLL3_ID 3 +/* Shorthand for Power Controller node */ +#define PWR_NODE DT_NODELABEL(pwr) + +/* Dummy value to use automatic voltage scale selection */ +#define VOLTAGE_SCALE_AUTOMATIC 0xFFFFFFFFu + +#define SELECTED_VOLTAGE_SCALE \ + COND_CODE_1(DT_NODE_HAS_PROP(PWR_NODE, voltage_scale), \ + (CONCAT(LL_PWR_REGU_VOLTAGE_SCALE, DT_PROP(PWR_NODE, voltage_scale))), \ + (VOLTAGE_SCALE_AUTOMATIC)) + static uint32_t get_bus_clock(uint32_t clock, uint32_t prescaler) { return clock / prescaler; @@ -430,17 +441,35 @@ static int get_vco_input_range(uint32_t m_div, uint32_t *range, size_t pll_id) return 0; } -static void set_regu_voltage(uint32_t hclk_freq) +static void set_regu_voltage(uint32_t hclk_freq, uint32_t wanted_scale) { + uint32_t minimal_scale, scale_to_apply; + if (hclk_freq < MHZ(25)) { - LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE4); + minimal_scale = LL_PWR_REGU_VOLTAGE_SCALE4; } else if (hclk_freq < MHZ(55)) { - LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE3); + minimal_scale = LL_PWR_REGU_VOLTAGE_SCALE3; } else if (hclk_freq < MHZ(110)) { - LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); + minimal_scale = LL_PWR_REGU_VOLTAGE_SCALE2; } else { - LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + minimal_scale = LL_PWR_REGU_VOLTAGE_SCALE1; } + + if (wanted_scale == VOLTAGE_SCALE_AUTOMATIC) { + scale_to_apply = minimal_scale; + } else if (wanted_scale < minimal_scale) { + /* + * This ought to never happen thanks to the + * compile-time checks, but better safe than + * sorry. Ideally, an error message should be + * logged if this ever occurs... + */ + scale_to_apply = minimal_scale; + } else { + scale_to_apply = wanted_scale; + } + + LL_PWR_SetRegulVoltageScaling(scale_to_apply); while (LL_PWR_IsActiveFlag_VOS() == 0) { } } @@ -855,7 +884,7 @@ int stm32_clock_control_init(const struct device *dev) old_hclk_freq = __LL_RCC_CALC_HCLK_FREQ(get_startup_frequency(), LL_RCC_GetAHBPrescaler()); /* Set voltage regulator to comply with targeted system frequency */ - set_regu_voltage(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + set_regu_voltage(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, SELECTED_VOLTAGE_SCALE); /* Set flash latency */ /* If freq increases, set flash latency before any clock setting */ @@ -928,6 +957,18 @@ int stm32_clock_control_init(const struct device *dev) return 0; } +/* Asserts fSYSCLK < `freq_mhz` if `vos` is selected on PWR node */ +#define ASSERT_VALID_VOS(vos, freq_mhz) \ +BUILD_ASSERT(DT_PROP_OR(PWR_NODE, voltage_scale, 0) != (vos) \ + || CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC <= MHZ(freq_mhz), \ + "Maximal system clock frequency in voltage scale " #vos \ + " is " #freq_mhz " MHz."); + +ASSERT_VALID_VOS(4, 25); +ASSERT_VALID_VOS(3, 55); +ASSERT_VALID_VOS(2, 110); +ASSERT_VALID_VOS(1, 160); + /** * @brief RCC device, note that priority is intentionally set to 1 so * that the device init runs just after SOC init diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 00b8ab45ae059..06bde7946909c 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -927,7 +927,7 @@ }; pwr: power@46020800 { - compatible = "st,stm32-dualreg-pwr", "st,stm32-pwr"; + compatible = "st,stm32u5-pwr", "st,stm32-dualreg-pwr", "st,stm32-pwr"; reg = <0x46020800 0x400>; /* PWR register bank */ status = "disabled"; diff --git a/dts/bindings/power/st,stm32u5-pwr.yaml b/dts/bindings/power/st,stm32u5-pwr.yaml new file mode 100644 index 0000000000000..5d5408ef0143a --- /dev/null +++ b/dts/bindings/power/st,stm32u5-pwr.yaml @@ -0,0 +1,58 @@ +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +title: STM32U5 power controller + +description: | + Power controller of STM32U5 series + + Controls two voltage regulators which can output one voltage + among four different voltage scales, depending on use case. + +include: "st,stm32-dualreg-pwr.yaml" + +properties: + voltage-scale: + type: int + description: | + Voltage regulator scale selection + + If present, this property can be used to indicate the desired + voltage regulator scale to use. This choice affects several + aspects of the system: + * power consumption + * memory and flash wait states + * maximal system clock frequency + * availability of certain peripherals + * ... + + The following values can be selected: + +---------+----------------+-----------------------------------+ + | Scale # | Max. frequency | Notes | + +---------+----------------+-----------------------------------+ + | 1 | 160 MHz | Highest power consumption | + +---------+----------------+-----------------------------------+ + | 2 | 110 MHz | | + +---------+----------------+-----------------------------------+ + | 3 | 55 MHz | [1] | + +---------+----------------+-----------------------------------+ + | 4 | 25 MHz | [1][2]; lowest power consumption | + +---------+----------------+-----------------------------------+ + + [1] OTG_HS cannot be used when this voltage scale is selected. + [2] OTG_FS / USB cannot be used when this voltage scale is selected. + + When this property is not present, the lowest voltage scale compatible + with the system's clock configuration is selected automatically: for + example, voltage scale 3 would be used if the system was configured + to operate with a system clock frequency of 40 MHz. + + Note that the same behavior is observed if the property is provided but + the selected voltage scale is not compatible with the system's clock + configuration; in this case, clock configuration takes precedence and + the value of this property is ignored. + enum: + - 1 + - 2 + - 3 + - 4