[U-Boot] [PATCH 2/6] clk: clk_stm32f: Fix stm32_clk_get_rate() for timer

patrice.chotard at st.com patrice.chotard at st.com
Wed Feb 7 09:44:46 UTC 2018


From: Patrice Chotard <patrice.chotard at st.com>

For timer clock, an additionnal prescaler is used which was
not taken into account previously.

Signed-off-by: Patrice Chotard <patrice.chotard at st.com>
---
 drivers/clk/clk_stm32f.c | 116 ++++++++++++++++++++++++++++++++++++++++-------
 include/stm32_rcc.h      |   5 ++
 2 files changed, 104 insertions(+), 17 deletions(-)

diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c
index 926b249ff3b7..bde31607cfe9 100644
--- a/drivers/clk/clk_stm32f.c
+++ b/drivers/clk/clk_stm32f.c
@@ -63,6 +63,7 @@
 #define RCC_PLLSAICFGR_PLLSAIQ_4	BIT(26)
 #define RCC_PLLSAICFGR_PLLSAIR_2	BIT(29)
 
+#define RCC_DCKCFGRX_TIMPRE		BIT(24)
 #define RCC_DCKCFGRX_CK48MSEL		BIT(27)
 #define RCC_DCKCFGRX_SDMMC1SEL		BIT(28)
 #define RCC_DCKCFGR2_SDMMC2SEL		BIT(29)
@@ -260,21 +261,88 @@ static unsigned long stm32_clk_pll48clk_rate(struct stm32_clk *priv,
 	return sysclk / pllq;
 }
 
-static unsigned long stm32_clk_get_rate(struct clk *clk)
+static bool stm32_get_timpre(struct stm32_clk *priv)
 {
-	struct stm32_clk *priv = dev_get_priv(clk->dev);
 	struct stm32_rcc_regs *regs = priv->base;
-	u32 sysclk = 0;
-	u32 shift = 0;
-	u16 pllm, plln, pllp;
+	u32 val;
+
+	if (priv->info.v2) /*stm32f7 case */
+		val = readl(&regs->dckcfgr2);
+	else
+		val = readl(&regs->dckcfgr);
+	/* get timer prescaler */
+	return !!(val & RCC_DCKCFGRX_TIMPRE);
+}
+
+static u32 stm32_get_hclk_rate(struct stm32_rcc_regs *regs, u32 sysclk)
+{
+	u8 shift;
 	/* Prescaler table lookups for clock computation */
 	u8 ahb_psc_table[16] = {
 		0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
 	};
+
+	shift = ahb_psc_table[(
+		(readl(&regs->cfgr) & RCC_CFGR_AHB_PSC_MASK)
+		>> RCC_CFGR_HPRE_SHIFT)];
+
+	return sysclk >> shift;
+};
+
+static u8 stm32_get_apb_shift(struct stm32_rcc_regs *regs, enum apb apb)
+{
+	/* Prescaler table lookups for clock computation */
 	u8 apb_psc_table[8] = {
 		0, 0, 0, 0, 1, 2, 3, 4
 	};
 
+	if (apb == APB1)
+		return apb_psc_table[(
+		       (readl(&regs->cfgr) & RCC_CFGR_APB1_PSC_MASK)
+		       >> RCC_CFGR_PPRE1_SHIFT)];
+	else /* APB2 */
+		return apb_psc_table[(
+		       (readl(&regs->cfgr) & RCC_CFGR_APB2_PSC_MASK)
+		       >> RCC_CFGR_PPRE2_SHIFT)];
+};
+
+static u32 stm32_get_timer_rate(struct stm32_clk *priv, u32 sysclk,
+				enum apb apb)
+{
+	struct stm32_rcc_regs *regs = priv->base;
+	u8 shift = stm32_get_apb_shift(regs, apb);
+
+	if (stm32_get_timpre(priv))
+		/*
+		 * if APB prescaler is configured to a
+		 * division factor of 1, 2 or 4
+		 */
+		switch (shift) {
+		case 0:
+		case 1:
+		case 2:
+			return stm32_get_hclk_rate(regs, sysclk);
+		default:
+			return (sysclk >> shift) * 4;
+		}
+	else
+		/*
+		 * if APB prescaler is configured to a
+		 * division factor of 1
+		 */
+		if (shift == 0)
+			return sysclk;
+		else
+			return (sysclk >> shift) * 2;
+};
+
+static ulong stm32_clk_get_rate(struct clk *clk)
+{
+	struct stm32_clk *priv = dev_get_priv(clk->dev);
+	struct stm32_rcc_regs *regs = priv->base;
+	u32 sysclk = 0;
+	u16 pllm, plln, pllp;
+
 	if ((readl(&regs->cfgr) & RCC_CFGR_SWS_MASK) ==
 			RCC_CFGR_SWS_PLL) {
 		pllm = (readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
@@ -293,16 +361,24 @@ static unsigned long stm32_clk_get_rate(struct clk *clk)
 	 * AHB1, AHB2 and AHB3
 	 */
 	case STM32F7_AHB1_CLOCK(GPIOA) ... STM32F7_AHB3_CLOCK(QSPI):
-		shift = ahb_psc_table[(
-			(readl(&regs->cfgr) & RCC_CFGR_AHB_PSC_MASK)
-			>> RCC_CFGR_HPRE_SHIFT)];
-		return sysclk >>= shift;
+		return stm32_get_hclk_rate(regs, sysclk);
 	/* APB1 CLOCK */
 	case STM32F7_APB1_CLOCK(TIM2) ... STM32F7_APB1_CLOCK(UART8):
-		shift = apb_psc_table[(
-			(readl(&regs->cfgr) & RCC_CFGR_APB1_PSC_MASK)
-			>> RCC_CFGR_PPRE1_SHIFT)];
-		return sysclk >>= shift;
+		/* For timer clock, an additionnal prescaler is used*/
+		switch (clk->id) {
+		case STM32F7_APB1_CLOCK(TIM2):
+		case STM32F7_APB1_CLOCK(TIM3):
+		case STM32F7_APB1_CLOCK(TIM4):
+		case STM32F7_APB1_CLOCK(TIM5):
+		case STM32F7_APB1_CLOCK(TIM6):
+		case STM32F7_APB1_CLOCK(TIM7):
+		case STM32F7_APB1_CLOCK(TIM12):
+		case STM32F7_APB1_CLOCK(TIM13):
+		case STM32F7_APB1_CLOCK(TIM14):
+			return stm32_get_timer_rate(priv, sysclk, APB1);
+		}
+		return (sysclk >> stm32_get_apb_shift(regs, APB1));
+
 	/* APB2 CLOCK */
 	case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC):
 		/*
@@ -325,12 +401,18 @@ static unsigned long stm32_clk_get_rate(struct clk *clk)
 			else
 				return stm32_clk_pll48clk_rate(priv, sysclk);
 			break;
+
+		/* For timer clock, an additionnal prescaler is used*/
+		case STM32F7_APB2_CLOCK(TIM1):
+		case STM32F7_APB2_CLOCK(TIM8):
+		case STM32F7_APB2_CLOCK(TIM9):
+		case STM32F7_APB2_CLOCK(TIM10):
+		case STM32F7_APB2_CLOCK(TIM11):
+			return stm32_get_timer_rate(priv, sysclk, APB2);
+		break;
 		}
+		return (sysclk >> stm32_get_apb_shift(regs, APB2));
 
-		shift = apb_psc_table[(
-			(readl(&regs->cfgr) & RCC_CFGR_APB2_PSC_MASK)
-			>> RCC_CFGR_PPRE2_SHIFT)];
-		return sysclk >>= shift;
 	default:
 		pr_err("clock index %ld out of range\n", clk->id);
 		return -EINVAL;
diff --git a/include/stm32_rcc.h b/include/stm32_rcc.h
index 063177bc9877..484bc305f9c0 100644
--- a/include/stm32_rcc.h
+++ b/include/stm32_rcc.h
@@ -45,6 +45,11 @@ enum soc_family {
 	STM32F7,
 };
 
+enum apb {
+	APB1,
+	APB2,
+};
+
 struct stm32_rcc_clk {
 	char *drv_name;
 	enum soc_family soc;
-- 
1.9.1



More information about the U-Boot mailing list