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_PLLSAIQ_4 BIT(26)
|
||||||
#define RCC_PLLSAICFGR_PLLSAIR_2 BIT(29)
|
#define RCC_PLLSAICFGR_PLLSAIR_2 BIT(29)
|
||||||
|
|
||||||
|
#define RCC_DCKCFGRX_TIMPRE BIT(24)
|
||||||
#define RCC_DCKCFGRX_CK48MSEL BIT(27)
|
#define RCC_DCKCFGRX_CK48MSEL BIT(27)
|
||||||
#define RCC_DCKCFGRX_SDMMC1SEL BIT(28)
|
#define RCC_DCKCFGRX_SDMMC1SEL BIT(28)
|
||||||
#define RCC_DCKCFGR2_SDMMC2SEL BIT(29)
|
#define RCC_DCKCFGR2_SDMMC2SEL BIT(29)
|
||||||
@ -260,21 +261,88 @@ static unsigned long stm32_clk_pll48clk_rate(struct stm32_clk *priv,
|
|||||||
return sysclk / pllq;
|
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;
|
struct stm32_rcc_regs *regs = priv->base;
|
||||||
u32 sysclk = 0;
|
u32 val;
|
||||||
u32 shift = 0;
|
|
||||||
u16 pllm, plln, pllp;
|
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 */
|
/* Prescaler table lookups for clock computation */
|
||||||
u8 ahb_psc_table[16] = {
|
u8 ahb_psc_table[16] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
|
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] = {
|
u8 apb_psc_table[8] = {
|
||||||
0, 0, 0, 0, 1, 2, 3, 4
|
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) ==
|
if ((readl(®s->cfgr) & RCC_CFGR_SWS_MASK) ==
|
||||||
RCC_CFGR_SWS_PLL) {
|
RCC_CFGR_SWS_PLL) {
|
||||||
pllm = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
|
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
|
* AHB1, AHB2 and AHB3
|
||||||
*/
|
*/
|
||||||
case STM32F7_AHB1_CLOCK(GPIOA) ... STM32F7_AHB3_CLOCK(QSPI):
|
case STM32F7_AHB1_CLOCK(GPIOA) ... STM32F7_AHB3_CLOCK(QSPI):
|
||||||
shift = ahb_psc_table[(
|
return stm32_get_hclk_rate(regs, sysclk);
|
||||||
(readl(®s->cfgr) & RCC_CFGR_AHB_PSC_MASK)
|
|
||||||
>> RCC_CFGR_HPRE_SHIFT)];
|
|
||||||
return sysclk >>= shift;
|
|
||||||
/* APB1 CLOCK */
|
/* APB1 CLOCK */
|
||||||
case STM32F7_APB1_CLOCK(TIM2) ... STM32F7_APB1_CLOCK(UART8):
|
case STM32F7_APB1_CLOCK(TIM2) ... STM32F7_APB1_CLOCK(UART8):
|
||||||
shift = apb_psc_table[(
|
/* For timer clock, an additionnal prescaler is used*/
|
||||||
(readl(®s->cfgr) & RCC_CFGR_APB1_PSC_MASK)
|
switch (clk->id) {
|
||||||
>> RCC_CFGR_PPRE1_SHIFT)];
|
case STM32F7_APB1_CLOCK(TIM2):
|
||||||
return sysclk >>= shift;
|
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 */
|
/* APB2 CLOCK */
|
||||||
case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC):
|
case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC):
|
||||||
/*
|
/*
|
||||||
@ -325,12 +401,18 @@ static unsigned long stm32_clk_get_rate(struct clk *clk)
|
|||||||
else
|
else
|
||||||
return stm32_clk_pll48clk_rate(priv, sysclk);
|
return stm32_clk_pll48clk_rate(priv, sysclk);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
shift = apb_psc_table[(
|
/* For timer clock, an additionnal prescaler is used*/
|
||||||
(readl(®s->cfgr) & RCC_CFGR_APB2_PSC_MASK)
|
case STM32F7_APB2_CLOCK(TIM1):
|
||||||
>> RCC_CFGR_PPRE2_SHIFT)];
|
case STM32F7_APB2_CLOCK(TIM8):
|
||||||
return sysclk >>= shift;
|
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:
|
default:
|
||||||
pr_err("clock index %ld out of range\n", clk->id);
|
pr_err("clock index %ld out of range\n", clk->id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -45,6 +45,11 @@ enum soc_family {
|
|||||||
STM32F7,
|
STM32F7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum apb {
|
||||||
|
APB1,
|
||||||
|
APB2,
|
||||||
|
};
|
||||||
|
|
||||||
struct stm32_rcc_clk {
|
struct stm32_rcc_clk {
|
||||||
char *drv_name;
|
char *drv_name;
|
||||||
enum soc_family soc;
|
enum soc_family soc;
|
||||||
|
Loading…
Reference in New Issue
Block a user