arm: stm32mp2: add multifunction timer support for stm32mp25

Add support for STM32MP25 SoC.
Identification and hardware configuration registers allow to read the
timer version and capabilities (counter width, ...).
So, rework the probe to avoid touching ARR register by simply read the
counter width when available. This may avoid messing with a possibly
running timer.
Also add useful bit fields to stm32-timers header file.

Signed-off-by: Cheick Traore <cheick.traore@foss.st.com>
Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com>
This commit is contained in:
Cheick Traore
2025-06-20 17:49:58 +02:00
committed by Patrice Chotard
parent 182cb30084
commit 8e1fafb807
2 changed files with 42 additions and 1 deletions

View File

@@ -29,6 +29,10 @@
#define TIM_DMAR 0x4C /* DMA register for transfer */
#define TIM_TISEL 0x68 /* Input Selection */
#define TIM_HWCFGR2 0x3EC /* hardware configuration 2 Reg (MP25) */
#define TIM_HWCFGR1 0x3F0 /* hardware configuration 1 Reg (MP25) */
#define TIM_IPIDR 0x3F8 /* IP identification Reg (MP25) */
#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))
@@ -40,11 +44,16 @@
#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 TIM_HWCFGR2_CNT_WIDTH GENMASK(15, 8) /* Counter width */
#define TIM_HWCFGR1_NB_OF_DT GENMASK(7, 4) /* Complementary outputs & dead-time generators */
#define MAX_TIM_PSC 0xFFFF
#define STM32MP25_TIM_IPIDR 0x00120002
struct stm32_timers_plat {
void __iomem *base;
u32 ipidr;
};
struct stm32_timers_priv {

View File

@@ -10,6 +10,7 @@
#include <asm/io.h>
#include <asm/arch/timers.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>
static void stm32_timers_get_arr_size(struct udevice *dev)
{
@@ -29,6 +30,33 @@ static void stm32_timers_get_arr_size(struct udevice *dev)
writel(arr, plat->base + TIM_ARR);
}
static int stm32_timers_probe_hwcfgr(struct udevice *dev)
{
struct stm32_timers_plat *plat = dev_get_plat(dev);
struct stm32_timers_priv *priv = dev_get_priv(dev);
u32 val;
if (!plat->ipidr) {
/* fallback to legacy method for probing counter width */
stm32_timers_get_arr_size(dev);
return 0;
}
val = readl(plat->base + TIM_IPIDR);
/* Sanity check on IP identification register */
if (val != plat->ipidr) {
dev_err(dev, "Unexpected identification: %u\n", val);
return -EINVAL;
}
val = readl(plat->base + TIM_HWCFGR2);
/* Counter width in bits, max reload value is BIT(width) - 1 */
priv->max_arr = BIT(FIELD_GET(TIM_HWCFGR2_CNT_WIDTH, val)) - 1;
dev_dbg(dev, "TIM width: %ld\n", FIELD_GET(TIM_HWCFGR2_CNT_WIDTH, val));
return 0;
}
static int stm32_timers_of_to_plat(struct udevice *dev)
{
struct stm32_timers_plat *plat = dev_get_plat(dev);
@@ -38,6 +66,7 @@ static int stm32_timers_of_to_plat(struct udevice *dev)
dev_err(dev, "can't get address\n");
return -ENOENT;
}
plat->ipidr = (u32)dev_get_driver_data(dev);
return 0;
}
@@ -60,13 +89,16 @@ static int stm32_timers_probe(struct udevice *dev)
priv->rate = clk_get_rate(&clk);
stm32_timers_get_arr_size(dev);
ret = stm32_timers_probe_hwcfgr(dev);
if (ret)
clk_disable(&clk);
return ret;
}
static const struct udevice_id stm32_timers_ids[] = {
{ .compatible = "st,stm32-timers" },
{ .compatible = "st,stm32mp25-timers", .data = STM32MP25_TIM_IPIDR },
{}
};