clk: clk_stm32f: Rework SDMMC stm32_clk_get_rate() part
Rework the way SDMMC clock get rate is done in a more generic way : _ Add stm32_clk_get_pllsai_rate() which give the PLLSAI indicated output rate. _ Add stm32_clk_get_pllsai_vco_rate() which give the VCO internal rate. Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
This commit is contained in:
parent
651a70e8d5
commit
1038e033e1
@ -57,8 +57,12 @@
|
||||
|
||||
#define RCC_PLLSAICFGR_PLLSAIN_MASK GENMASK(14, 6)
|
||||
#define RCC_PLLSAICFGR_PLLSAIP_MASK GENMASK(17, 16)
|
||||
#define RCC_PLLSAICFGR_PLLSAIQ_MASK GENMASK(27, 24)
|
||||
#define RCC_PLLSAICFGR_PLLSAIR_MASK GENMASK(30, 28)
|
||||
#define RCC_PLLSAICFGR_PLLSAIN_SHIFT 6
|
||||
#define RCC_PLLSAICFGR_PLLSAIP_SHIFT 16
|
||||
#define RCC_PLLSAICFGR_PLLSAIQ_SHIFT 24
|
||||
#define RCC_PLLSAICFGR_PLLSAIR_SHIFT 28
|
||||
#define RCC_PLLSAICFGR_PLLSAIP_4 BIT(16)
|
||||
#define RCC_PLLSAICFGR_PLLSAIQ_4 BIT(26)
|
||||
#define RCC_PLLSAICFGR_PLLSAIR_2 BIT(29)
|
||||
@ -87,6 +91,12 @@
|
||||
#define RCC_APB2ENR_SYSCFGEN BIT(14)
|
||||
#define RCC_APB2ENR_SAI1EN BIT(22)
|
||||
|
||||
enum pllsai_div {
|
||||
PLLSAIP,
|
||||
PLLSAIQ,
|
||||
PLLSAIR,
|
||||
};
|
||||
|
||||
static const struct stm32_clk_info stm32f4_clk_info = {
|
||||
/* 180 MHz */
|
||||
.sys_pll_psc = {
|
||||
@ -216,32 +226,57 @@ static int configure_clocks(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long stm32_clk_pll48clk_rate(struct stm32_clk *priv,
|
||||
u32 vco)
|
||||
static bool stm32_clk_get_ck48msel(struct stm32_clk *priv)
|
||||
{
|
||||
struct stm32_rcc_regs *regs = priv->base;
|
||||
u16 pllq, pllm, pllsain, pllsaip;
|
||||
bool pllsai;
|
||||
|
||||
pllq = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLQ_MASK)
|
||||
>> RCC_PLLCFGR_PLLQ_SHIFT;
|
||||
|
||||
if (priv->info.v2) /*stm32f7 case */
|
||||
pllsai = readl(®s->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL;
|
||||
return readl(®s->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL;
|
||||
else
|
||||
pllsai = readl(®s->dckcfgr) & RCC_DCKCFGRX_CK48MSEL;
|
||||
|
||||
if (pllsai) {
|
||||
/* PLL48CLK is selected from PLLSAI, get PLLSAI value */
|
||||
pllm = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
|
||||
pllsain = ((readl(®s->pllsaicfgr) & RCC_PLLSAICFGR_PLLSAIN_MASK)
|
||||
>> RCC_PLLSAICFGR_PLLSAIN_SHIFT);
|
||||
pllsaip = ((((readl(®s->pllsaicfgr) & RCC_PLLSAICFGR_PLLSAIP_MASK)
|
||||
>> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1);
|
||||
return ((priv->hse_rate / pllm) * pllsain) / pllsaip;
|
||||
return readl(®s->dckcfgr) & RCC_DCKCFGRX_CK48MSEL;
|
||||
}
|
||||
|
||||
static unsigned long stm32_clk_get_pllsai_vco_rate(struct stm32_clk *priv)
|
||||
{
|
||||
struct stm32_rcc_regs *regs = priv->base;
|
||||
u16 pllm, pllsain;
|
||||
|
||||
pllm = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
|
||||
pllsain = ((readl(®s->pllsaicfgr) & RCC_PLLSAICFGR_PLLSAIN_MASK)
|
||||
>> RCC_PLLSAICFGR_PLLSAIN_SHIFT);
|
||||
|
||||
return ((priv->hse_rate / pllm) * pllsain);
|
||||
}
|
||||
|
||||
static unsigned long stm32_clk_get_pllsai_rate(struct stm32_clk *priv,
|
||||
enum pllsai_div output)
|
||||
{
|
||||
struct stm32_rcc_regs *regs = priv->base;
|
||||
u16 pll_div_output;
|
||||
|
||||
switch (output) {
|
||||
case PLLSAIP:
|
||||
pll_div_output = ((((readl(®s->pllsaicfgr)
|
||||
& RCC_PLLSAICFGR_PLLSAIP_MASK)
|
||||
>> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1);
|
||||
break;
|
||||
case PLLSAIQ:
|
||||
pll_div_output = (readl(®s->pllsaicfgr)
|
||||
& RCC_PLLSAICFGR_PLLSAIQ_MASK)
|
||||
>> RCC_PLLSAICFGR_PLLSAIQ_SHIFT;
|
||||
break;
|
||||
case PLLSAIR:
|
||||
pll_div_output = (readl(®s->pllsaicfgr)
|
||||
& RCC_PLLSAICFGR_PLLSAIR_MASK)
|
||||
>> RCC_PLLSAICFGR_PLLSAIR_SHIFT;
|
||||
break;
|
||||
default:
|
||||
pr_err("incorrect PLLSAI output %d\n", output);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* PLL48CLK is selected from PLLQ */
|
||||
return vco / pllq;
|
||||
|
||||
return (stm32_clk_get_pllsai_vco_rate(priv) / pll_div_output);
|
||||
}
|
||||
|
||||
static bool stm32_get_timpre(struct stm32_clk *priv)
|
||||
@ -325,7 +360,8 @@ static ulong stm32_clk_get_rate(struct clk *clk)
|
||||
struct stm32_rcc_regs *regs = priv->base;
|
||||
u32 sysclk = 0;
|
||||
u32 vco;
|
||||
u16 pllm, plln, pllp;
|
||||
u32 sdmmcxsel_bit;
|
||||
u16 pllm, plln, pllp, pllq;
|
||||
|
||||
if ((readl(®s->cfgr) & RCC_CFGR_SWS_MASK) ==
|
||||
RCC_CFGR_SWS_PLL) {
|
||||
@ -334,6 +370,8 @@ static ulong stm32_clk_get_rate(struct clk *clk)
|
||||
>> RCC_PLLCFGR_PLLN_SHIFT);
|
||||
pllp = ((((readl(®s->pllcfgr) & RCC_PLLCFGR_PLLP_MASK)
|
||||
>> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1);
|
||||
pllq = ((readl(®s->pllcfgr) & RCC_PLLCFGR_PLLQ_MASK)
|
||||
>> RCC_PLLCFGR_PLLQ_SHIFT);
|
||||
vco = (priv->hse_rate / pllm) * plln;
|
||||
sysclk = vco / pllp;
|
||||
} else {
|
||||
@ -366,25 +404,30 @@ static ulong stm32_clk_get_rate(struct clk *clk)
|
||||
|
||||
/* APB2 CLOCK */
|
||||
case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC):
|
||||
switch (clk->id) {
|
||||
/*
|
||||
* particular case for SDMMC1 and SDMMC2 :
|
||||
* 48Mhz source clock can be from main PLL or from
|
||||
* SAI PLL
|
||||
* PLLSAIP
|
||||
*/
|
||||
switch (clk->id) {
|
||||
case STM32F7_APB2_CLOCK(SDMMC1):
|
||||
if (readl(®s->dckcfgr2) & RCC_DCKCFGRX_SDMMC1SEL)
|
||||
case STM32F7_APB2_CLOCK(SDMMC2):
|
||||
if (clk->id == STM32F7_APB2_CLOCK(SDMMC1))
|
||||
sdmmcxsel_bit = RCC_DCKCFGRX_SDMMC1SEL;
|
||||
else
|
||||
sdmmcxsel_bit = RCC_DCKCFGR2_SDMMC2SEL;
|
||||
|
||||
if (readl(®s->dckcfgr2) & sdmmcxsel_bit)
|
||||
/* System clock is selected as SDMMC1 clock */
|
||||
return sysclk;
|
||||
/*
|
||||
* 48 MHz can be generated by either PLLSAIP
|
||||
* or by PLLQ depending of CK48MSEL bit of RCC_DCKCFGR
|
||||
*/
|
||||
if (stm32_clk_get_ck48msel(priv))
|
||||
return stm32_clk_get_pllsai_rate(priv, PLLSAIP);
|
||||
else
|
||||
return stm32_clk_pll48clk_rate(priv, vco);
|
||||
break;
|
||||
case STM32F7_APB2_CLOCK(SDMMC2):
|
||||
if (readl(®s->dckcfgr2) & RCC_DCKCFGR2_SDMMC2SEL)
|
||||
/* System clock is selected as SDMMC2 clock */
|
||||
return sysclk;
|
||||
else
|
||||
return stm32_clk_pll48clk_rate(priv, vco);
|
||||
return (vco / pllq);
|
||||
break;
|
||||
|
||||
/* For timer clock, an additionnal prescaler is used*/
|
||||
|
Loading…
Reference in New Issue
Block a user