aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/clk_stm32f.c105
1 files changed, 74 insertions, 31 deletions
diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c
index e8f6b47acc1..a687e2acd40 100644
--- a/drivers/clk/clk_stm32f.c
+++ b/drivers/clk/clk_stm32f.c
@@ -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(&regs->pllcfgr) & RCC_PLLCFGR_PLLQ_MASK)
- >> RCC_PLLCFGR_PLLQ_SHIFT;
if (priv->info.v2) /*stm32f7 case */
- pllsai = readl(&regs->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL;
+ return readl(&regs->dckcfgr2) & RCC_DCKCFGRX_CK48MSEL;
else
- pllsai = readl(&regs->dckcfgr) & RCC_DCKCFGRX_CK48MSEL;
- if (pllsai) {
- /* PLL48CLK is selected from PLLSAI, get PLLSAI value */
- pllm = (readl(&regs->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
- pllsain = ((readl(&regs->pllsaicfgr) & RCC_PLLSAICFGR_PLLSAIN_MASK)
- >> RCC_PLLSAICFGR_PLLSAIN_SHIFT);
- pllsaip = ((((readl(&regs->pllsaicfgr) & RCC_PLLSAICFGR_PLLSAIP_MASK)
- >> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1);
- return ((priv->hse_rate / pllm) * pllsain) / pllsaip;
+ return readl(&regs->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(&regs->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
+ pllsain = ((readl(&regs->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(&regs->pllsaicfgr)
+ & RCC_PLLSAICFGR_PLLSAIP_MASK)
+ >> RCC_PLLSAICFGR_PLLSAIP_SHIFT) + 1) << 1);
+ break;
+ case PLLSAIQ:
+ pll_div_output = (readl(&regs->pllsaicfgr)
+ & RCC_PLLSAICFGR_PLLSAIQ_MASK)
+ >> RCC_PLLSAICFGR_PLLSAIQ_SHIFT;
+ break;
+ case PLLSAIR:
+ pll_div_output = (readl(&regs->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(&regs->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(&regs->pllcfgr) & RCC_PLLCFGR_PLLP_MASK)
>> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1);
+ pllq = ((readl(&regs->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(&regs->dckcfgr2) & RCC_DCKCFGRX_SDMMC1SEL)
- /* System clock is selected as SDMMC1 clock */
- return sysclk;
- else
- return stm32_clk_pll48clk_rate(priv, vco);
- break;
case STM32F7_APB2_CLOCK(SDMMC2):
- if (readl(&regs->dckcfgr2) & RCC_DCKCFGR2_SDMMC2SEL)
- /* System clock is selected as SDMMC2 clock */
+ if (clk->id == STM32F7_APB2_CLOCK(SDMMC1))
+ sdmmcxsel_bit = RCC_DCKCFGRX_SDMMC1SEL;
+ else
+ sdmmcxsel_bit = RCC_DCKCFGR2_SDMMC2SEL;
+
+ if (readl(&regs->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);
+ return (vco / pllq);
break;
/* For timer clock, an additionnal prescaler is used*/