clk: clk_stm32f: Fix stm32_clk_get_rate() for timer
For timer clock, an additionnal prescaler is used which was not taken into account previously. Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
This commit is contained in:
parent
5120a083e7
commit
61803a95a1
@ -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(®s->dckcfgr2);
|
||||
else
|
||||
val = readl(®s->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(®s->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(®s->cfgr) & RCC_CFGR_APB1_PSC_MASK)
|
||||
>> RCC_CFGR_PPRE1_SHIFT)];
|
||||
else /* APB2 */
|
||||
return apb_psc_table[(
|
||||
(readl(®s->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(®s->cfgr) & RCC_CFGR_SWS_MASK) ==
|
||||
RCC_CFGR_SWS_PLL) {
|
||||
pllm = (readl(®s->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(®s->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(®s->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;
|
||||
}
|
||||
|
||||
shift = apb_psc_table[(
|
||||
(readl(®s->cfgr) & RCC_CFGR_APB2_PSC_MASK)
|
||||
>> RCC_CFGR_PPRE2_SHIFT)];
|
||||
return sysclk >>= shift;
|
||||
/* 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));
|
||||
|
||||
default:
|
||||
pr_err("clock index %ld out of range\n", clk->id);
|
||||
return -EINVAL;
|
||||
|
@ -45,6 +45,11 @@ enum soc_family {
|
||||
STM32F7,
|
||||
};
|
||||
|
||||
enum apb {
|
||||
APB1,
|
||||
APB2,
|
||||
};
|
||||
|
||||
struct stm32_rcc_clk {
|
||||
char *drv_name;
|
||||
enum soc_family soc;
|
||||
|
Loading…
Reference in New Issue
Block a user