clk: clk_stm32f: Fix stm32_clk_get_rate() for timer
authorPatrice Chotard <patrice.chotard@st.com>
Wed, 7 Feb 2018 09:44:46 +0000 (10:44 +0100)
committerTom Rini <trini@konsulko.com>
Wed, 14 Mar 2018 01:45:37 +0000 (21:45 -0400)
For timer clock, an additionnal prescaler is used which was
not taken into account previously.

Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
drivers/clk/clk_stm32f.c
include/stm32_rcc.h

index 926b249ff3b7e7097d14a61e9150f185f0d8b0be..bde31607cfe90a7fabc513046019e1f5ab7f4c5d 100644 (file)
@@ -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;
index 063177bc9877cdf4d87affba15df09dc26c79eb6..484bc305f9c0c3fcd1db5e57255b914da9b7e608 100644 (file)
@@ -45,6 +45,11 @@ enum soc_family {
        STM32F7,
 };
 
+enum apb {
+       APB1,
+       APB2,
+};
+
 struct stm32_rcc_clk {
        char *drv_name;
        enum soc_family soc;