- Add drivers for MFD STM32 TIMERS and STM32 PWM and enable them on stm32mp135f-dk

- Restrict _debug_uart_init() usage in STM32 serial driver
 - Add support for environment in eMMC on STM32MP13xx DHCOR SoM
 - Introduce DH STM32MP15xx DHSOM board specific defconfigs
 - Fix CONFIG_BOOTCOUNT_ALTBOOTCMD update on DH STM32MP1 DHSOM
 - Update maintainer for board stm32f746-disco
 - Fix Linux cmdline for stm32f769-disco
 - Cleanup in stm32f***-u-boot.dtsi and in board_late_init() by removing
   legacy led and button management.
 -----BEGIN PGP SIGNATURE-----
 
 iQJQBAABCgA6FiEEXyrViUccKBz9c35Jysd4L3sz/6YFAmfRsL4cHHBhdHJpY2Uu
 Y2hvdGFyZEBmb3NzLnN0LmNvbQAKCRDKx3gvezP/psU2D/9LPdhwyvmi595AgjNf
 0t4rqKKTPhjb43UZeuAnFOg4PJcH7eXd2tQq5htK+ir8jeLU7cZWRGjA6eXtRQni
 IKYtWlz4OY/xuQhJbQqMBGb1EVJE432LlfVp3rKpCpBMoANU+h//opd/m4CKsMYN
 SiIikf3Xasgy7APSGTQcNGZyzVcVPeL8e68hEAOuFfCBMmd4JRb7RMwro9mG+/SU
 9PzOLvCEfNTq9k87vT8SH4UQHv/NF8OaH6v77SJFt+RHdQr/G9MNbdP5IVwuWkgU
 CfcWRFzmofFACueZ/6vA+hFYarF5tsv043GJyJkTh/0CUbFx8vS0+x1WoL7YcviA
 5Ro+tEEfpB1F1qLyOJV698l1vm3Zj452oZ6e2PBPMGqfKy1vkBjh9OjhfqpjILHX
 uAkxxd/dx6FzK8jo4Qki7JT4W2MmD3jTeHsVunLOC1tS1f44MHwnjpZZH2ttXT/4
 VLPkIYf9kKJA/squ0Lx+ZCjFtiM/XenWHhQxsO9QxKUqSHgBZuwBj8VRNRrMs/N+
 3mN4PLNuYtagJjCvvsxiMg0aB7LH22kXA657nQfHM01WlR9I/B2K0aIil/I/kVV9
 b9LtUven4sXUEexszEY/xFxF2utU+Xh57wKh+3qm2XVw8pfSKItvBXBK/lo/ULWV
 62xL179ziFFGrE/2o/m87VT30w==
 =xL/c
 -----END PGP SIGNATURE-----

Merge tag 'u-boot-stm32-20250312' of https://source.denx.de/u-boot/custodians/u-boot-stm into next

CI: https://source.denx.de/u-boot/custodians/u-boot-stm/-/pipelines/25112

- Add drivers for MFD STM32 TIMERS and STM32 PWM and enable them on stm32mp135f-dk
- Restrict _debug_uart_init() usage in STM32 serial driver
- Add support for environment in eMMC on STM32MP13xx DHCOR SoM
- Introduce DH STM32MP15xx DHSOM board specific defconfigs
- Fix CONFIG_BOOTCOUNT_ALTBOOTCMD update on DH STM32MP1 DHSOM
- Update maintainer for board stm32f746-disco
- Fix Linux cmdline for stm32f769-disco
- Cleanup in stm32f***-u-boot.dtsi and in board_late_init() by removing
  legacy led and button management.
This commit is contained in:
Tom Rini 2025-03-12 21:36:52 -06:00
commit eeefcacb85
35 changed files with 475 additions and 97 deletions

View File

@ -22,16 +22,6 @@
mmc0 = &sdio1; mmc0 = &sdio1;
spi0 = &qspi; spi0 = &qspi;
}; };
button1 {
compatible = "st,button1";
button-gpio = <&gpioc 13 0>;
};
led1 {
compatible = "st,led1";
led-gpio = <&gpiof 10 0>;
};
}; };
&fmc { &fmc {

View File

@ -22,16 +22,6 @@
mmc0 = &sdio1; mmc0 = &sdio1;
spi0 = &qspi; spi0 = &qspi;
}; };
button1 {
compatible = "st,button1";
button-gpio = <&gpioi 11 0>;
};
led1 {
compatible = "st,led1";
led-gpio = <&gpioi 1 0>;
};
}; };
&ltdc { &ltdc {

View File

@ -23,16 +23,6 @@
spi0 = &qspi; spi0 = &qspi;
}; };
button1 {
compatible = "st,button1";
button-gpio = <&gpioa 0 0>;
};
led1 {
compatible = "st,led1";
led-gpio = <&gpioj 5 0>;
};
panel: panel { panel: panel {
compatible = "orisetech,otm8009a"; compatible = "orisetech,otm8009a";
reset-gpios = <&gpioj 15 1>; reset-gpios = <&gpioj 15 1>;

View File

@ -215,6 +215,21 @@
}; };
}; };
pwm1_ch3n_pins_a: pwm1-ch3n-0 {
pins {
pinmux = <STM32_PINMUX('E', 12, AF1)>; /* TIM1_CH3N */
bias-pull-down;
drive-push-pull;
slew-rate = <0>;
};
};
pwm1_ch3n_sleep_pins_a: pwm1-ch3n-sleep-0 {
pins {
pinmux = <STM32_PINMUX('E', 12, ANALOG)>; /* TIM1_CH3N */
};
};
pwm3_pins_a: pwm3-0 { pwm3_pins_a: pwm3-0 {
pins { pins {
pinmux = <STM32_PINMUX('B', 1, AF2)>; /* TIM3_CH4 */ pinmux = <STM32_PINMUX('B', 1, AF2)>; /* TIM3_CH4 */

View File

@ -23,3 +23,25 @@
&usbphyc { &usbphyc {
bootph-all; bootph-all;
}; };
&st33htph {
reset-gpios = <&gpioe 12 GPIO_ACTIVE_LOW>;
};
/* LDO2 is expansion connector 3V3 supply on STM32MP13xx DHCOR DHSBC rev.200 */
&vdd_ldo2 {
bootph-all;
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
/* LDO5 is carrier board 3V3 supply on STM32MP13xx DHCOR DHSBC rev.200 */
&vdd_sd {
bootph-all;
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};

View File

@ -9,6 +9,7 @@
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include <dt-bindings/leds/common.h> #include <dt-bindings/leds/common.h>
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/regulator/st,stm32mp13-regulator.h> #include <dt-bindings/regulator/st,stm32mp13-regulator.h>
#include "stm32mp135.dtsi" #include "stm32mp135.dtsi"
#include "stm32mp13xf.dtsi" #include "stm32mp13xf.dtsi"
@ -207,6 +208,19 @@
status = "disabled"; status = "disabled";
}; };
&timers1 {
/* spare dmas for other usage */
/delete-property/dmas;
/delete-property/dma-names;
status = "okay";
pwm1: pwm {
pinctrl-0 = <&pwm1_ch3n_pins_a>;
pinctrl-1 = <&pwm1_ch3n_sleep_pins_a>;
pinctrl-names = "default", "sleep";
status = "okay";
};
};
&timers3 { &timers3 {
/delete-property/dmas; /delete-property/dmas;
/delete-property/dma-names; /delete-property/dma-names;

View File

@ -13,6 +13,8 @@
config { config {
dh,ddr3-coding-gpios = <&gpiod 5 0>, <&gpiod 9 0>; dh,ddr3-coding-gpios = <&gpiod 5 0>, <&gpiod 9 0>;
dh,som-coding-gpios = <&gpioa 13 0>, <&gpioi 1 0>; dh,som-coding-gpios = <&gpioa 13 0>, <&gpioi 1 0>;
u-boot,mmc-env-offset = <0x3fc000>;
u-boot,mmc-env-offset-redundant = <0x3fc000>;
}; };
}; };

View File

@ -153,6 +153,12 @@ config CMD_STM32KEY
This command is used to evaluate the secure boot on stm32mp SOC, This command is used to evaluate the secure boot on stm32mp SOC,
it is deactivated by default in real products. it is deactivated by default in real products.
config MFD_STM32_TIMERS
bool "STM32 multifonction timer support"
help
Select this to enable support for the multifunction timer found on
STM32 devices.
source "arch/arm/mach-stm32mp/Kconfig.13x" source "arch/arm/mach-stm32mp/Kconfig.13x"
source "arch/arm/mach-stm32mp/Kconfig.15x" source "arch/arm/mach-stm32mp/Kconfig.15x"
source "arch/arm/mach-stm32mp/Kconfig.25x" source "arch/arm/mach-stm32mp/Kconfig.25x"

View File

@ -12,6 +12,7 @@ obj-$(CONFIG_STM32MP15X) += stm32mp1/
obj-$(CONFIG_STM32MP13X) += stm32mp1/ obj-$(CONFIG_STM32MP13X) += stm32mp1/
obj-$(CONFIG_STM32MP25X) += stm32mp2/ obj-$(CONFIG_STM32MP25X) += stm32mp2/
obj-$(CONFIG_MFD_STM32_TIMERS) += timers.o
obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o
ifndef CONFIG_XPL_BUILD ifndef CONFIG_XPL_BUILD
obj-y += cmd_stm32prog/ obj-y += cmd_stm32prog/

View File

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2025, STMicroelectronics - All Rights Reserved
* Author: Cheick Traore <cheick.traore@foss.st.com>
*
* Originally based on the Linux kernel v6.1 include/linux/mfd/stm32-timers.h.
*/
#ifndef __STM32_TIMERS_H
#define __STM32_TIMERS_H
#include <clk.h>
#define TIM_CR1 0x00 /* Control Register 1 */
#define TIM_CR2 0x04 /* Control Register 2 */
#define TIM_SMCR 0x08 /* Slave mode control reg */
#define TIM_DIER 0x0C /* DMA/interrupt register */
#define TIM_SR 0x10 /* Status register */
#define TIM_EGR 0x14 /* Event Generation Reg */
#define TIM_CCMR1 0x18 /* Capt/Comp 1 Mode Reg */
#define TIM_CCMR2 0x1C /* Capt/Comp 2 Mode Reg */
#define TIM_CCER 0x20 /* Capt/Comp Enable Reg */
#define TIM_CNT 0x24 /* Counter */
#define TIM_PSC 0x28 /* Prescaler */
#define TIM_ARR 0x2c /* Auto-Reload Register */
#define TIM_CCRx(x) (0x34 + 4 * ((x) - 1)) /* Capt/Comp Register x (x ∈ {1, .. 4}) */
#define TIM_BDTR 0x44 /* Break and Dead-Time Reg */
#define TIM_DCR 0x48 /* DMA control register */
#define TIM_DMAR 0x4C /* DMA register for transfer */
#define TIM_TISEL 0x68 /* Input Selection */
#define TIM_CR1_CEN BIT(0) /* Counter Enable */
#define TIM_CR1_ARPE BIT(7)
#define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12))
#define TIM_CCER_CC1E BIT(0)
#define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */
#define TIM_CCER_CC1NE BIT(2) /* Capt/Comp 1N out Ena */
#define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */
#define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */
#define TIM_CCMR_M1 (BIT(6) | BIT(5)) /* Channel PWM Mode 1 */
#define TIM_BDTR_MOE BIT(15) /* Main Output Enable */
#define TIM_EGR_UG BIT(0) /* Update Generation */
#define MAX_TIM_PSC 0xFFFF
struct stm32_timers_plat {
void __iomem *base;
};
struct stm32_timers_priv {
u32 max_arr;
ulong rate;
};
#endif

View File

@ -138,8 +138,6 @@ int mach_cpu_init(void)
if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) &&
(boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART) (boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART)
gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE; gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;
else if (IS_ENABLED(CONFIG_DEBUG_UART) && IS_ENABLED(CONFIG_XPL_BUILD))
debug_uart_init();
return 0; return 0;
} }

View File

@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025, STMicroelectronics - All Rights Reserved
* Author: Cheick Traore <cheick.traore@foss.st.com>
*
* Originally based on the Linux kernel v6.1 drivers/mfd/stm32-timers.c.
*/
#include <dm.h>
#include <asm/io.h>
#include <asm/arch/timers.h>
#include <dm/device_compat.h>
static void stm32_timers_get_arr_size(struct udevice *dev)
{
struct stm32_timers_plat *plat = dev_get_plat(dev);
struct stm32_timers_priv *priv = dev_get_priv(dev);
u32 arr;
/* Backup ARR to restore it after getting the maximum value */
arr = readl(plat->base + TIM_ARR);
/*
* Only the available bits will be written so when readback
* we get the maximum value of auto reload register
*/
writel(~0L, plat->base + TIM_ARR);
priv->max_arr = readl(plat->base + TIM_ARR);
writel(arr, plat->base + TIM_ARR);
}
static int stm32_timers_of_to_plat(struct udevice *dev)
{
struct stm32_timers_plat *plat = dev_get_plat(dev);
plat->base = dev_read_addr_ptr(dev);
if (!plat->base) {
dev_err(dev, "can't get address\n");
return -ENOENT;
}
return 0;
}
static int stm32_timers_probe(struct udevice *dev)
{
struct stm32_timers_priv *priv = dev_get_priv(dev);
struct clk clk;
int ret = 0;
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
ret = clk_enable(&clk);
if (ret) {
dev_err(dev, "failed to enable clock: ret=%d\n", ret);
return ret;
}
priv->rate = clk_get_rate(&clk);
stm32_timers_get_arr_size(dev);
return ret;
}
static const struct udevice_id stm32_timers_ids[] = {
{ .compatible = "st,stm32-timers" },
{}
};
U_BOOT_DRIVER(stm32_timers) = {
.name = "stm32_timers",
.id = UCLASS_NOP,
.of_match = stm32_timers_ids,
.of_to_plat = stm32_timers_of_to_plat,
.plat_auto = sizeof(struct stm32_timers_plat),
.probe = stm32_timers_probe,
.priv_auto = sizeof(struct stm32_timers_priv),
.bind = dm_scan_fdt_dev,
};

View File

@ -1,5 +1,5 @@
STM32F746 DISCOVERY BOARD STM32F746 DISCOVERY BOARD
M: Vikas Manocha <vikas.manocha@st.com> M: Patrice Chotard <patrice.chotard@foss.st.com>
S: Maintained S: Maintained
F: doc/board/st/ F: doc/board/st/
F: board/st/stm32f746-disco F: board/st/stm32f746-disco

View File

@ -76,42 +76,6 @@ u32 spl_boot_device(void)
} }
#endif #endif
int board_late_init(void)
{
struct gpio_desc gpio = {};
int node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "st,led1");
if (node < 0)
return -1;
gpio_request_by_name_nodev(offset_to_ofnode(node), "led-gpio", 0, &gpio,
GPIOD_IS_OUT);
if (dm_gpio_is_valid(&gpio)) {
dm_gpio_set_value(&gpio, 0);
mdelay(10);
dm_gpio_set_value(&gpio, 1);
}
/* read button 1*/
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "st,button1");
if (node < 0)
return -1;
gpio_request_by_name_nodev(offset_to_ofnode(node), "button-gpio", 0,
&gpio, GPIOD_IS_IN);
if (dm_gpio_is_valid(&gpio)) {
if (dm_gpio_get_value(&gpio))
puts("usr button is at HIGH LEVEL\n");
else
puts("usr button is at LOW LEVEL\n");
}
return 0;
}
int board_init(void) int board_init(void)
{ {
#ifdef CONFIG_ETH_DESIGNWARE #ifdef CONFIG_ETH_DESIGNWARE

View File

@ -21,7 +21,6 @@ CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel"
CONFIG_SYS_PBSIZE=1050 CONFIG_SYS_PBSIZE=1050
# CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_CPUINFO is not set
CONFIG_BOARD_LATE_INIT=y
CONFIG_SYS_PROMPT="U-Boot > " CONFIG_SYS_PROMPT="U-Boot > "
CONFIG_CMD_GPT=y CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y CONFIG_CMD_MMC=y

View File

@ -30,7 +30,6 @@ CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel"
CONFIG_SYS_PBSIZE=1050 CONFIG_SYS_PBSIZE=1050
# CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_CPUINFO is not set
CONFIG_BOARD_LATE_INIT=y
CONFIG_SPL_PAD_TO=0x9000 CONFIG_SPL_PAD_TO=0x9000
CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_SPL_NO_BSS_LIMIT=y
CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_BOARD_INIT=y

View File

@ -21,7 +21,6 @@ CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel"
CONFIG_SYS_PBSIZE=1050 CONFIG_SYS_PBSIZE=1050
# CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_CPUINFO is not set
CONFIG_BOARD_LATE_INIT=y
CONFIG_SYS_PROMPT="U-Boot > " CONFIG_SYS_PROMPT="U-Boot > "
CONFIG_CMD_GPT=y CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y CONFIG_CMD_MMC=y

View File

@ -30,7 +30,6 @@ CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel"
CONFIG_SYS_PBSIZE=1050 CONFIG_SYS_PBSIZE=1050
# CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_CPUINFO is not set
CONFIG_BOARD_LATE_INIT=y
CONFIG_SPL_PAD_TO=0x9000 CONFIG_SPL_PAD_TO=0x9000
CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_SPL_NO_BSS_LIMIT=y
CONFIG_SPL_BOARD_INIT=y CONFIG_SPL_BOARD_INIT=y

View File

@ -18,7 +18,7 @@ CONFIG_AUTOBOOT_KEYED=y
CONFIG_AUTOBOOT_PROMPT="Hit SPACE in %d seconds to stop autoboot.\n" CONFIG_AUTOBOOT_PROMPT="Hit SPACE in %d seconds to stop autoboot.\n"
CONFIG_AUTOBOOT_STOP_STR=" " CONFIG_AUTOBOOT_STOP_STR=" "
CONFIG_USE_BOOTARGS=y CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_BOOTARGS="console=ttySTM0,115200n8 earlyprintk consoleblank=0 ignore_loglevel"
CONFIG_SYS_PBSIZE=1050 CONFIG_SYS_PBSIZE=1050
# CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_CPUINFO is not set
CONFIG_CYCLIC_MAX_CPU_TIME_US=8000 CONFIG_CYCLIC_MAX_CPU_TIME_US=8000

View File

@ -10,6 +10,7 @@ CONFIG_SYS_LOAD_ADDR=0xc2000000
CONFIG_STM32MP13X=y CONFIG_STM32MP13X=y
CONFIG_DDR_CACHEABLE_SIZE=0x8000000 CONFIG_DDR_CACHEABLE_SIZE=0x8000000
CONFIG_CMD_STM32KEY=y CONFIG_CMD_STM32KEY=y
CONFIG_MFD_STM32_TIMERS=y
CONFIG_TARGET_ST_STM32MP13X=y CONFIG_TARGET_ST_STM32MP13X=y
CONFIG_ENV_OFFSET_REDUND=0x940000 CONFIG_ENV_OFFSET_REDUND=0x940000
CONFIG_CMD_STM32PROG=y CONFIG_CMD_STM32PROG=y
@ -31,6 +32,7 @@ CONFIG_CMD_UNZIP=y
CONFIG_CMD_CLK=y CONFIG_CMD_CLK=y
CONFIG_CMD_FUSE=y CONFIG_CMD_FUSE=y
CONFIG_CMD_GPIO=y CONFIG_CMD_GPIO=y
CONFIG_CMD_PWM=y
CONFIG_CMD_I2C=y CONFIG_CMD_I2C=y
CONFIG_CMD_LSBLK=y CONFIG_CMD_LSBLK=y
CONFIG_CMD_MMC=y CONFIG_CMD_MMC=y
@ -80,6 +82,8 @@ CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_REGULATOR_SCMI=y CONFIG_DM_REGULATOR_SCMI=y
CONFIG_DM_PWM=y
CONFIG_PWM_STM32=y
CONFIG_RESET_SCMI=y CONFIG_RESET_SCMI=y
CONFIG_DM_RNG=y CONFIG_DM_RNG=y
CONFIG_RNG_STM32=y CONFIG_RNG_STM32=y

View File

@ -28,10 +28,14 @@ CONFIG_CMD_RNG=y
CONFIG_CMD_LOG=y CONFIG_CMD_LOG=y
CONFIG_CMD_UBI=y CONFIG_CMD_UBI=y
CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_ENV_MMC_USE_DT=y
CONFIG_ENV_SPI_MAX_HZ=50000000 CONFIG_ENV_SPI_MAX_HZ=50000000
CONFIG_CLK_SCMI=y CONFIG_CLK_SCMI=y
CONFIG_SET_DFU_ALT_INFO=y CONFIG_SET_DFU_ALT_INFO=y
CONFIG_SYS_I2C_EEPROM_ADDR=0x50 CONFIG_SYS_I2C_EEPROM_ADDR=0x50
CONFIG_SYS_MMC_ENV_DEV=0
CONFIG_SYS_MMC_ENV_PART=1
CONFIG_PHY_REALTEK=y CONFIG_PHY_REALTEK=y
CONFIG_DM_REGULATOR_SCMI=y CONFIG_DM_REGULATOR_SCMI=y
CONFIG_RESET_SCMI=y CONFIG_RESET_SCMI=y
@ -44,4 +48,3 @@ CONFIG_OPTEE=y
CONFIG_USB_ONBOARD_HUB=y CONFIG_USB_ONBOARD_HUB=y
CONFIG_USB_HUB_DEBOUNCE_TIMEOUT=2000 CONFIG_USB_HUB_DEBOUNCE_TIMEOUT=2000
CONFIG_ERRNO_STR=y CONFIG_ERRNO_STR=y
CONFIG_BOOTCOUNT_ALTBOOTCMD="

View File

@ -0,0 +1,8 @@
#include <configs/stm32mp15_dhsom.config>
CONFIG_ARM=y
CONFIG_ARCH_STM32MP=y
CONFIG_SYS_MEMTEST_START=0xc0000000
CONFIG_SYS_MEMTEST_END=0xc4000000
CONFIG_SYS_I2C_EEPROM_BUS=3
CONFIG_SYS_I2C_EEPROM_ADDR=0x50

View File

@ -1,11 +1,4 @@
#include <configs/stm32mp15_dhsom.config> #include <configs/stm32mp15_dhcom_basic.config>
CONFIG_ARM=y
CONFIG_ARCH_STM32MP=y
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157c-dhcom-pdk2" CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157c-dhcom-pdk2"
CONFIG_SYS_MEMTEST_START=0xc0000000
CONFIG_SYS_MEMTEST_END=0xc4000000
CONFIG_SYS_I2C_EEPROM_BUS=3
CONFIG_OF_LIST="st/stm32mp157c-dhcom-pdk2 st/stm32mp153c-dhcom-drc02 st/stm32mp157c-dhcom-picoitx" CONFIG_OF_LIST="st/stm32mp157c-dhcom-pdk2 st/stm32mp153c-dhcom-drc02 st/stm32mp157c-dhcom-picoitx"
CONFIG_SYS_I2C_EEPROM_ADDR=0x50
CONFIG_BOOTCOUNT_ALTBOOTCMD="

View File

@ -0,0 +1,4 @@
#include <configs/stm32mp15_dhcom_basic.config>
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp153c-dhcom-drc02"
CONFIG_OF_LIST="st/stm32mp153c-dhcom-drc02"

View File

@ -0,0 +1,4 @@
#include <configs/stm32mp15_dhcom_basic.config>
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157c-dhcom-pdk2"
CONFIG_OF_LIST="st/stm32mp157c-dhcom-pdk2"

View File

@ -0,0 +1,4 @@
#include <configs/stm32mp15_dhcom_basic.config>
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157c-dhcom-picoitx"
CONFIG_OF_LIST="st/stm32mp157c-dhcom-picoitx"

View File

@ -0,0 +1,4 @@
#include <configs/stm32mp15_dhcor_basic.config>
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157a-dhcor-avenger96"
CONFIG_OF_LIST="st/stm32mp157a-dhcor-avenger96"

View File

@ -0,0 +1,8 @@
#include <configs/stm32mp15_dhsom.config>
CONFIG_ARM=y
CONFIG_ARCH_STM32MP=y
CONFIG_SYS_I2C_EEPROM_BUS=2
CONFIG_SYS_I2C_EEPROM_ADDR=0x53
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -1,11 +1,4 @@
#include <configs/stm32mp15_dhsom.config> #include <configs/stm32mp15_dhcor_basic.config>
CONFIG_ARM=y
CONFIG_ARCH_STM32MP=y
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157a-dhcor-avenger96" CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp157a-dhcor-avenger96"
CONFIG_SYS_I2C_EEPROM_BUS=2
CONFIG_OF_LIST="st/stm32mp157a-dhcor-avenger96 st/stm32mp151a-dhcor-testbench st/stm32mp153c-dhcor-drc-compact" CONFIG_OF_LIST="st/stm32mp157a-dhcor-avenger96 st/stm32mp151a-dhcor-testbench st/stm32mp153c-dhcor-drc-compact"
CONFIG_SYS_I2C_EEPROM_ADDR=0x53
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y
CONFIG_BOOTCOUNT_ALTBOOTCMD="

View File

@ -0,0 +1,4 @@
#include <configs/stm32mp15_dhcor_basic.config>
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp153c-dhcor-drc-compact"
CONFIG_OF_LIST="st/stm32mp153c-dhcor-drc-compact"

View File

@ -0,0 +1,4 @@
#include <configs/stm32mp15_dhcor_basic.config>
CONFIG_DEFAULT_DEVICE_TREE="st/stm32mp151a-dhcor-testbench"
CONFIG_OF_LIST="st/stm32mp151a-dhcor-testbench"

View File

@ -105,6 +105,14 @@ config PWM_TEGRA
32KHz clock is supported by the driver but the duty cycle is 32KHz clock is supported by the driver but the duty cycle is
configurable. configurable.
config PWM_STM32
bool "Enable support for STM32 PWM"
depends on DM_PWM && MFD_STM32_TIMERS
help
This enables PWM driver for STMicroelectronics STM32 pulse width
modulation. It uses STM32 timer devices that can have up to 4 output
channels, with complementary outputs and configurable polarity.
config PWM_SUNXI config PWM_SUNXI
bool "Enable support for the Allwinner Sunxi PWM" bool "Enable support for the Allwinner Sunxi PWM"
depends on DM_PWM depends on DM_PWM

View File

@ -22,5 +22,6 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o
obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o
obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o
obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o
obj-$(CONFIG_PWM_TI_EHRPWM) += pwm-ti-ehrpwm.o obj-$(CONFIG_PWM_TI_EHRPWM) += pwm-ti-ehrpwm.o

205
drivers/pwm/pwm-stm32.c Normal file
View File

@ -0,0 +1,205 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025, STMicroelectronics - All Rights Reserved
* Author: Cheick Traore <cheick.traore@foss.st.com>
*
* Originally based on the Linux kernel v6.10 drivers/pwm/pwm-stm32.c.
*/
#include <div64.h>
#include <dm.h>
#include <pwm.h>
#include <asm/io.h>
#include <asm/arch/timers.h>
#include <dm/device_compat.h>
#include <linux/time.h>
#define CCMR_CHANNEL_SHIFT 8
#define CCMR_CHANNEL_MASK 0xFF
struct stm32_pwm_priv {
bool have_complementary_output;
bool invert_polarity;
};
static u32 active_channels(struct stm32_timers_plat *plat)
{
return readl(plat->base + TIM_CCER) & TIM_CCER_CCXE;
}
static int stm32_pwm_set_config(struct udevice *dev, uint channel,
uint period_ns, uint duty_ns)
{
struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
struct stm32_timers_priv *priv = dev_get_priv(dev_get_parent(dev));
unsigned long long prd, div, dty;
unsigned int prescaler = 0;
u32 ccmr, mask, shift;
if (duty_ns > period_ns)
return -EINVAL;
/*
* Period and prescaler values depends on clock rate
* First we need to find the minimal value for prescaler such that
*
* period_ns * clkrate
* ------------------------------ < max_arr + 1
* NSEC_PER_SEC * (prescaler + 1)
*
* This equation is equivalent to
*
* period_ns * clkrate
* ---------------------------- < prescaler + 1
* NSEC_PER_SEC * (max_arr + 1)
*
* Using integer division and knowing that the right hand side is
* integer, this is further equivalent to
*
* (period_ns * clkrate) // (NSEC_PER_SEC * (max_arr + 1)) ≤ prescaler
*/
div = (unsigned long long)priv->rate * period_ns;
do_div(div, NSEC_PER_SEC);
prd = div;
do_div(div, priv->max_arr + 1);
prescaler = div;
if (prescaler > MAX_TIM_PSC)
return -EINVAL;
do_div(prd, prescaler + 1);
if (!prd)
return -EINVAL;
/*
* All channels share the same prescaler and counter so when two
* channels are active at the same time we can't change them
*/
if (active_channels(plat) & ~(1 << channel * 4)) {
u32 psc, arr;
psc = readl(plat->base + TIM_PSC);
arr = readl(plat->base + TIM_ARR);
if (psc != prescaler || arr != prd - 1)
return -EBUSY;
}
writel(prescaler, plat->base + TIM_PSC);
writel(prd - 1, plat->base + TIM_ARR);
setbits_le32(plat->base + TIM_CR1, TIM_CR1_ARPE);
/* Calculate the duty cycles */
dty = prd * duty_ns;
do_div(dty, period_ns);
writel(dty, plat->base + TIM_CCRx(channel + 1));
/* Configure output mode */
shift = (channel & 0x1) * CCMR_CHANNEL_SHIFT;
ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
mask = CCMR_CHANNEL_MASK << shift;
if (channel < 2)
clrsetbits_le32(plat->base + TIM_CCMR1, mask, ccmr);
else
clrsetbits_le32(plat->base + TIM_CCMR2, mask, ccmr);
setbits_le32(plat->base + TIM_BDTR, TIM_BDTR_MOE);
return 0;
}
static int stm32_pwm_set_enable(struct udevice *dev, uint channel,
bool enable)
{
struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
struct stm32_pwm_priv *priv = dev_get_priv(dev);
u32 mask;
/* Enable channel */
mask = TIM_CCER_CC1E << (channel * 4);
if (priv->have_complementary_output)
mask |= TIM_CCER_CC1NE << (channel * 4);
if (enable) {
setbits_le32(plat->base + TIM_CCER, mask);
/* Make sure that registers are updated */
setbits_le32(plat->base + TIM_EGR, TIM_EGR_UG);
/* Enable controller */
setbits_le32(plat->base + TIM_CR1, TIM_CR1_CEN);
} else {
clrbits_le32(plat->base + TIM_CCER, mask);
/* When all channels are disabled, we can disable the controller */
if (!active_channels(plat))
clrbits_le32(plat->base + TIM_CR1, TIM_CR1_CEN);
}
return 0;
}
static int stm32_pwm_set_invert(struct udevice *dev, uint channel,
bool polarity)
{
struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
struct stm32_pwm_priv *priv = dev_get_priv(dev);
u32 mask;
mask = TIM_CCER_CC1P << (channel * 4);
if (priv->have_complementary_output)
mask |= TIM_CCER_CC1NP << (channel * 4);
clrsetbits_le32(plat->base + TIM_CCER, mask, polarity ? mask : 0);
return 0;
}
static void stm32_pwm_detect_complementary(struct udevice *dev)
{
struct stm32_timers_plat *plat = dev_get_plat(dev_get_parent(dev));
struct stm32_pwm_priv *priv = dev_get_priv(dev);
u32 ccer;
/*
* If complementary bit doesn't exist writing 1 will have no
* effect so we can detect it.
*/
setbits_le32(plat->base + TIM_CCER, TIM_CCER_CC1NE);
ccer = readl(plat->base + TIM_CCER);
clrbits_le32(plat->base + TIM_CCER, TIM_CCER_CC1NE);
priv->have_complementary_output = (ccer != 0);
}
static int stm32_pwm_probe(struct udevice *dev)
{
struct stm32_timers_priv *timer = dev_get_priv(dev_get_parent(dev));
if (timer->rate > 1000000000) {
dev_err(dev, "Clock freq too high (%lu)\n", timer->rate);
return -EINVAL;
}
stm32_pwm_detect_complementary(dev);
return 0;
}
static const struct pwm_ops stm32_pwm_ops = {
.set_config = stm32_pwm_set_config,
.set_enable = stm32_pwm_set_enable,
.set_invert = stm32_pwm_set_invert,
};
static const struct udevice_id stm32_pwm_ids[] = {
{ .compatible = "st,stm32-pwm" },
{ }
};
U_BOOT_DRIVER(stm32_pwm) = {
.name = "stm32_pwm",
.id = UCLASS_PWM,
.of_match = stm32_pwm_ids,
.ops = &stm32_pwm_ops,
.probe = stm32_pwm_probe,
.priv_auto = sizeof(struct stm32_pwm_priv),
};

View File

@ -299,13 +299,19 @@ static inline struct stm32_uart_info *_debug_uart_info(void)
static inline void _debug_uart_init(void) static inline void _debug_uart_init(void)
{ {
void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE); void __maybe_unused __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE);
struct stm32_uart_info *uart_info = _debug_uart_info(); struct stm32_uart_info *uart_info __maybe_unused = _debug_uart_info();
_stm32_serial_init(base, uart_info); /*
_stm32_serial_setbrg(base, uart_info, * debug_uart_init() is only usable when SPL_BUILD is enabled
CONFIG_DEBUG_UART_CLOCK, * (STM32MP1 case only)
CONFIG_BAUDRATE); */
if (IS_ENABLED(CONFIG_DEBUG_UART) && IS_ENABLED(CONFIG_SPL_BUILD)) {
_stm32_serial_init(base, uart_info);
_stm32_serial_setbrg(base, uart_info,
CONFIG_DEBUG_UART_CLOCK,
CONFIG_BAUDRATE);
}
} }
static inline void _debug_uart_putc(int c) static inline void _debug_uart_putc(int c)