diff options
author | Tom Rini <trini@konsulko.com> | 2025-03-12 21:36:52 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2025-03-12 21:36:52 -0600 |
commit | eeefcacb851f7f0bccabc3089a725f5ce86f5c70 (patch) | |
tree | 913e063346db8a36c2094aabb35561f9669990fb | |
parent | 19a342f9122780a67d96887eae3ab62a189126d5 (diff) | |
parent | 1a87755ecd0d36ec29acdbcbc9b381e76cfd6cfd (diff) |
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.
35 files changed, 475 insertions, 97 deletions
diff --git a/arch/arm/dts/stm32746g-eval-u-boot.dtsi b/arch/arm/dts/stm32746g-eval-u-boot.dtsi index 1c288acec99..32b5c7cea4b 100644 --- a/arch/arm/dts/stm32746g-eval-u-boot.dtsi +++ b/arch/arm/dts/stm32746g-eval-u-boot.dtsi @@ -22,16 +22,6 @@ mmc0 = &sdio1; spi0 = &qspi; }; - - button1 { - compatible = "st,button1"; - button-gpio = <&gpioc 13 0>; - }; - - led1 { - compatible = "st,led1"; - led-gpio = <&gpiof 10 0>; - }; }; &fmc { diff --git a/arch/arm/dts/stm32f746-disco-u-boot.dtsi b/arch/arm/dts/stm32f746-disco-u-boot.dtsi index 1b42d6cbbc1..38d797e49a0 100644 --- a/arch/arm/dts/stm32f746-disco-u-boot.dtsi +++ b/arch/arm/dts/stm32f746-disco-u-boot.dtsi @@ -22,16 +22,6 @@ mmc0 = &sdio1; spi0 = &qspi; }; - - button1 { - compatible = "st,button1"; - button-gpio = <&gpioi 11 0>; - }; - - led1 { - compatible = "st,led1"; - led-gpio = <&gpioi 1 0>; - }; }; <dc { diff --git a/arch/arm/dts/stm32f769-disco-u-boot.dtsi b/arch/arm/dts/stm32f769-disco-u-boot.dtsi index add55c96e21..7c99a6e61b6 100644 --- a/arch/arm/dts/stm32f769-disco-u-boot.dtsi +++ b/arch/arm/dts/stm32f769-disco-u-boot.dtsi @@ -23,16 +23,6 @@ spi0 = &qspi; }; - button1 { - compatible = "st,button1"; - button-gpio = <&gpioa 0 0>; - }; - - led1 { - compatible = "st,led1"; - led-gpio = <&gpioj 5 0>; - }; - panel: panel { compatible = "orisetech,otm8009a"; reset-gpios = <&gpioj 15 1>; diff --git a/arch/arm/dts/stm32mp13-pinctrl.dtsi b/arch/arm/dts/stm32mp13-pinctrl.dtsi index c01d39f03ea..52c2a9f24d7 100644 --- a/arch/arm/dts/stm32mp13-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp13-pinctrl.dtsi @@ -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 { pins { pinmux = <STM32_PINMUX('B', 1, AF2)>; /* TIM3_CH4 */ diff --git a/arch/arm/dts/stm32mp135f-dhcor-dhsbc-u-boot.dtsi b/arch/arm/dts/stm32mp135f-dhcor-dhsbc-u-boot.dtsi index d718aae16ca..eace94f5fa4 100644 --- a/arch/arm/dts/stm32mp135f-dhcor-dhsbc-u-boot.dtsi +++ b/arch/arm/dts/stm32mp135f-dhcor-dhsbc-u-boot.dtsi @@ -23,3 +23,25 @@ &usbphyc { 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>; +}; diff --git a/arch/arm/dts/stm32mp135f-dk.dts b/arch/arm/dts/stm32mp135f-dk.dts index eea740d097c..275823da3c6 100644 --- a/arch/arm/dts/stm32mp135f-dk.dts +++ b/arch/arm/dts/stm32mp135f-dk.dts @@ -9,6 +9,7 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/leds/common.h> +#include <dt-bindings/pwm/pwm.h> #include <dt-bindings/regulator/st,stm32mp13-regulator.h> #include "stm32mp135.dtsi" #include "stm32mp13xf.dtsi" @@ -207,6 +208,19 @@ 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 { /delete-property/dmas; /delete-property/dma-names; diff --git a/arch/arm/dts/stm32mp13xx-dhcor-u-boot.dtsi b/arch/arm/dts/stm32mp13xx-dhcor-u-boot.dtsi index 30e3b91bccc..9ff42ab8248 100644 --- a/arch/arm/dts/stm32mp13xx-dhcor-u-boot.dtsi +++ b/arch/arm/dts/stm32mp13xx-dhcor-u-boot.dtsi @@ -13,6 +13,8 @@ config { dh,ddr3-coding-gpios = <&gpiod 5 0>, <&gpiod 9 0>; dh,som-coding-gpios = <&gpioa 13 0>, <&gpioi 1 0>; + u-boot,mmc-env-offset = <0x3fc000>; + u-boot,mmc-env-offset-redundant = <0x3fc000>; }; }; diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 25663a99464..002da2e3d3b 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -153,6 +153,12 @@ config CMD_STM32KEY This command is used to evaluate the secure boot on stm32mp SOC, 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.15x" source "arch/arm/mach-stm32mp/Kconfig.25x" diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index db7ed19bd91..103e3410ad9 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_STM32MP15X) += stm32mp1/ obj-$(CONFIG_STM32MP13X) += stm32mp1/ obj-$(CONFIG_STM32MP25X) += stm32mp2/ +obj-$(CONFIG_MFD_STM32_TIMERS) += timers.o obj-$(CONFIG_STM32_ECDSA_VERIFY) += ecdsa_romapi.o ifndef CONFIG_XPL_BUILD obj-y += cmd_stm32prog/ diff --git a/arch/arm/mach-stm32mp/include/mach/timers.h b/arch/arm/mach-stm32mp/include/mach/timers.h new file mode 100644 index 00000000000..a84465bb28e --- /dev/null +++ b/arch/arm/mach-stm32mp/include/mach/timers.h @@ -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 diff --git a/arch/arm/mach-stm32mp/stm32mp1/cpu.c b/arch/arm/mach-stm32mp/stm32mp1/cpu.c index d5eaf6711b6..18175fd12cc 100644 --- a/arch/arm/mach-stm32mp/stm32mp1/cpu.c +++ b/arch/arm/mach-stm32mp/stm32mp1/cpu.c @@ -138,8 +138,6 @@ int mach_cpu_init(void) if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && (boot_mode & TAMP_BOOT_DEVICE_MASK) == BOOT_SERIAL_UART) 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; } diff --git a/arch/arm/mach-stm32mp/timers.c b/arch/arm/mach-stm32mp/timers.c new file mode 100644 index 00000000000..a3207895f40 --- /dev/null +++ b/arch/arm/mach-stm32mp/timers.c @@ -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, +}; diff --git a/board/st/stm32f746-disco/MAINTAINERS b/board/st/stm32f746-disco/MAINTAINERS index 18e4c99c4fb..f9c3af6fb8b 100644 --- a/board/st/stm32f746-disco/MAINTAINERS +++ b/board/st/stm32f746-disco/MAINTAINERS @@ -1,5 +1,5 @@ STM32F746 DISCOVERY BOARD -M: Vikas Manocha <vikas.manocha@st.com> +M: Patrice Chotard <patrice.chotard@foss.st.com> S: Maintained F: doc/board/st/ F: board/st/stm32f746-disco diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 8966a09501e..07bc8a5f0a2 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -76,42 +76,6 @@ u32 spl_boot_device(void) } #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) { #ifdef CONFIG_ETH_DESIGNWARE diff --git a/configs/stm32746g-eval_defconfig b/configs/stm32746g-eval_defconfig index 4346ecd6e42..bd3a48b20a2 100644 --- a/configs/stm32746g-eval_defconfig +++ b/configs/stm32746g-eval_defconfig @@ -21,7 +21,6 @@ CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_SYS_PBSIZE=1050 # CONFIG_DISPLAY_CPUINFO is not set -CONFIG_BOARD_LATE_INIT=y CONFIG_SYS_PROMPT="U-Boot > " CONFIG_CMD_GPT=y CONFIG_CMD_MMC=y diff --git a/configs/stm32746g-eval_spl_defconfig b/configs/stm32746g-eval_spl_defconfig index 2756ad5508f..d47d059d23b 100644 --- a/configs/stm32746g-eval_spl_defconfig +++ b/configs/stm32746g-eval_spl_defconfig @@ -30,7 +30,6 @@ CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_SYS_PBSIZE=1050 # CONFIG_DISPLAY_CPUINFO is not set -CONFIG_BOARD_LATE_INIT=y CONFIG_SPL_PAD_TO=0x9000 CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_SPL_BOARD_INIT=y diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig index 35a489c34e0..f6fbf83f68f 100644 --- a/configs/stm32f746-disco_defconfig +++ b/configs/stm32f746-disco_defconfig @@ -21,7 +21,6 @@ CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_SYS_PBSIZE=1050 # CONFIG_DISPLAY_CPUINFO is not set -CONFIG_BOARD_LATE_INIT=y CONFIG_SYS_PROMPT="U-Boot > " CONFIG_CMD_GPT=y CONFIG_CMD_MMC=y diff --git a/configs/stm32f746-disco_spl_defconfig b/configs/stm32f746-disco_spl_defconfig index 6826b1cb755..dcf077dbfee 100644 --- a/configs/stm32f746-disco_spl_defconfig +++ b/configs/stm32f746-disco_spl_defconfig @@ -30,7 +30,6 @@ CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk consoleblank=0 ignore_loglevel" CONFIG_SYS_PBSIZE=1050 # CONFIG_DISPLAY_CPUINFO is not set -CONFIG_BOARD_LATE_INIT=y CONFIG_SPL_PAD_TO=0x9000 CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_SPL_BOARD_INIT=y diff --git a/configs/stm32f769-disco_defconfig b/configs/stm32f769-disco_defconfig index 5be221afd2f..9edda0e36b2 100644 --- a/configs/stm32f769-disco_defconfig +++ b/configs/stm32f769-disco_defconfig @@ -18,7 +18,7 @@ CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_PROMPT="Hit SPACE in %d seconds to stop autoboot.\n" CONFIG_AUTOBOOT_STOP_STR=" " 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_DISPLAY_CPUINFO is not set CONFIG_CYCLIC_MAX_CPU_TIME_US=8000 diff --git a/configs/stm32mp13_defconfig b/configs/stm32mp13_defconfig index 0acd1487c9a..4c6a7f82fe5 100644 --- a/configs/stm32mp13_defconfig +++ b/configs/stm32mp13_defconfig @@ -10,6 +10,7 @@ CONFIG_SYS_LOAD_ADDR=0xc2000000 CONFIG_STM32MP13X=y CONFIG_DDR_CACHEABLE_SIZE=0x8000000 CONFIG_CMD_STM32KEY=y +CONFIG_MFD_STM32_TIMERS=y CONFIG_TARGET_ST_STM32MP13X=y CONFIG_ENV_OFFSET_REDUND=0x940000 CONFIG_CMD_STM32PROG=y @@ -31,6 +32,7 @@ CONFIG_CMD_UNZIP=y CONFIG_CMD_CLK=y CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_PWM=y CONFIG_CMD_I2C=y CONFIG_CMD_LSBLK=y CONFIG_CMD_MMC=y @@ -80,6 +82,8 @@ CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_SCMI=y +CONFIG_DM_PWM=y +CONFIG_PWM_STM32=y CONFIG_RESET_SCMI=y CONFIG_DM_RNG=y CONFIG_RNG_STM32=y diff --git a/configs/stm32mp13_dhcor_defconfig b/configs/stm32mp13_dhcor_defconfig index 4dc3954128d..2da9287ea7b 100644 --- a/configs/stm32mp13_dhcor_defconfig +++ b/configs/stm32mp13_dhcor_defconfig @@ -28,10 +28,14 @@ CONFIG_CMD_RNG=y CONFIG_CMD_LOG=y CONFIG_CMD_UBI=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_CLK_SCMI=y CONFIG_SET_DFU_ALT_INFO=y CONFIG_SYS_I2C_EEPROM_ADDR=0x50 +CONFIG_SYS_MMC_ENV_DEV=0 +CONFIG_SYS_MMC_ENV_PART=1 CONFIG_PHY_REALTEK=y CONFIG_DM_REGULATOR_SCMI=y CONFIG_RESET_SCMI=y @@ -44,4 +48,3 @@ CONFIG_OPTEE=y CONFIG_USB_ONBOARD_HUB=y CONFIG_USB_HUB_DEBOUNCE_TIMEOUT=2000 CONFIG_ERRNO_STR=y -CONFIG_BOOTCOUNT_ALTBOOTCMD=" diff --git a/configs/stm32mp15_dhcom_basic.config b/configs/stm32mp15_dhcom_basic.config new file mode 100644 index 00000000000..d78916bb5b2 --- /dev/null +++ b/configs/stm32mp15_dhcom_basic.config @@ -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 diff --git a/configs/stm32mp15_dhcom_basic_defconfig b/configs/stm32mp15_dhcom_basic_defconfig index f89c921925d..297092bd746 100644 --- a/configs/stm32mp15_dhcom_basic_defconfig +++ b/configs/stm32mp15_dhcom_basic_defconfig @@ -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_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_SYS_I2C_EEPROM_ADDR=0x50 -CONFIG_BOOTCOUNT_ALTBOOTCMD=" diff --git a/configs/stm32mp15_dhcom_drc02_basic_defconfig b/configs/stm32mp15_dhcom_drc02_basic_defconfig new file mode 100644 index 00000000000..838c3db253d --- /dev/null +++ b/configs/stm32mp15_dhcom_drc02_basic_defconfig @@ -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" diff --git a/configs/stm32mp15_dhcom_pdk2_basic_defconfig b/configs/stm32mp15_dhcom_pdk2_basic_defconfig new file mode 100644 index 00000000000..c6996233c9f --- /dev/null +++ b/configs/stm32mp15_dhcom_pdk2_basic_defconfig @@ -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" diff --git a/configs/stm32mp15_dhcom_picoitx_basic_defconfig b/configs/stm32mp15_dhcom_picoitx_basic_defconfig new file mode 100644 index 00000000000..5682edbfcbf --- /dev/null +++ b/configs/stm32mp15_dhcom_picoitx_basic_defconfig @@ -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" diff --git a/configs/stm32mp15_dhcor_avenger96_basic_defconfig b/configs/stm32mp15_dhcor_avenger96_basic_defconfig new file mode 100644 index 00000000000..5d27cd5ed7e --- /dev/null +++ b/configs/stm32mp15_dhcor_avenger96_basic_defconfig @@ -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" diff --git a/configs/stm32mp15_dhcor_basic.config b/configs/stm32mp15_dhcor_basic.config new file mode 100644 index 00000000000..e9c0cb9f95a --- /dev/null +++ b/configs/stm32mp15_dhcor_basic.config @@ -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 diff --git a/configs/stm32mp15_dhcor_basic_defconfig b/configs/stm32mp15_dhcor_basic_defconfig index bde668761b3..beb6d1d5a9a 100644 --- a/configs/stm32mp15_dhcor_basic_defconfig +++ b/configs/stm32mp15_dhcor_basic_defconfig @@ -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_SYS_I2C_EEPROM_BUS=2 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=" diff --git a/configs/stm32mp15_dhcor_drc_compact_basic_defconfig b/configs/stm32mp15_dhcor_drc_compact_basic_defconfig new file mode 100644 index 00000000000..7b1d73a33b5 --- /dev/null +++ b/configs/stm32mp15_dhcor_drc_compact_basic_defconfig @@ -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" diff --git a/configs/stm32mp15_dhcor_testbench_basic_defconfig b/configs/stm32mp15_dhcor_testbench_basic_defconfig new file mode 100644 index 00000000000..7ba327cbd82 --- /dev/null +++ b/configs/stm32mp15_dhcor_testbench_basic_defconfig @@ -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" diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 6e79868d0ef..de312656746 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -105,6 +105,14 @@ config PWM_TEGRA 32KHz clock is supported by the driver but the duty cycle is 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 bool "Enable support for the Allwinner Sunxi PWM" depends on DM_PWM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index e4d10c8dc3e..76305b93bc9 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -22,5 +22,6 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.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_TI_EHRPWM) += pwm-ti-ehrpwm.o diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c new file mode 100644 index 00000000000..5fa649b5903 --- /dev/null +++ b/drivers/pwm/pwm-stm32.c @@ -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), +}; diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 1ee58142b3f..1675a9cb9d1 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -299,13 +299,19 @@ static inline struct stm32_uart_info *_debug_uart_info(void) static inline void _debug_uart_init(void) { - void __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE); - struct stm32_uart_info *uart_info = _debug_uart_info(); + void __maybe_unused __iomem *base = (void __iomem *)CONFIG_VAL(DEBUG_UART_BASE); + struct stm32_uart_info *uart_info __maybe_unused = _debug_uart_info(); - _stm32_serial_init(base, uart_info); - _stm32_serial_setbrg(base, uart_info, - CONFIG_DEBUG_UART_CLOCK, - CONFIG_BAUDRATE); + /* + * debug_uart_init() is only usable when SPL_BUILD is enabled + * (STM32MP1 case only) + */ + 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) |