On 3/6/25 11:56, Cheick Traore wrote:
> Add support for STM32MP timer multi-function driver.
> These timers can be use as counter, trigger or pwm generator.
> This driver will be used to manage the main resources of the timer to
> provide them to the functionnalities which need these ones.
> 
> Signed-off-by: Cheick Traore <cheick.tra...@foss.st.com>
> ---
> 
>  arch/arm/mach-stm32mp/Kconfig               |  6 ++
>  arch/arm/mach-stm32mp/Makefile              |  1 +
>  arch/arm/mach-stm32mp/include/mach/timers.h | 55 ++++++++++++++
>  arch/arm/mach-stm32mp/timers.c              | 82 +++++++++++++++++++++
>  4 files changed, 144 insertions(+)
>  create mode 100644 arch/arm/mach-stm32mp/include/mach/timers.h
>  create mode 100644 arch/arm/mach-stm32mp/timers.c

Hi Cheick,

Reviewed-by: Fabrice Gasnier <fabrice.gasn...@foss.st.com>

Thanks,
Best Regards,
Fabrice

> 
> 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.tra...@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/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.tra...@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,
> +};

Reply via email to