|
@@ -35,6 +35,7 @@ DECLARE_GLOBAL_DATA_PTR;
|
|
|
#define RCC_CFGR_SW_CSI 1
|
|
|
#define RCC_CFGR_SW_HSE 2
|
|
|
#define RCC_CFGR_SW_PLL1 3
|
|
|
+#define RCC_CFGR_TIMPRE BIT(15)
|
|
|
|
|
|
#define RCC_PLLCKSELR_PLLSRC_HSI 0
|
|
|
#define RCC_PLLCKSELR_PLLSRC_CSI 1
|
|
@@ -339,6 +340,11 @@ struct pll_psc sys_pll_psc = {
|
|
|
.divr = 2,
|
|
|
};
|
|
|
|
|
|
+enum apb {
|
|
|
+ APB1,
|
|
|
+ APB2,
|
|
|
+};
|
|
|
+
|
|
|
int configure_clocks(struct udevice *dev)
|
|
|
{
|
|
|
struct stm32_clk *priv = dev_get_priv(dev);
|
|
@@ -562,6 +568,67 @@ static u32 stm32_get_PLL1_rate(struct stm32_rcc_regs *regs,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+static u32 stm32_get_apb_psc(struct stm32_rcc_regs *regs, enum apb apb)
|
|
|
+{
|
|
|
+ u16 prescaler_table[8] = {2, 4, 8, 16, 64, 128, 256, 512};
|
|
|
+ u32 d2cfgr = readl(®s->d2cfgr);
|
|
|
+
|
|
|
+ if (apb == APB1) {
|
|
|
+ if (d2cfgr & RCC_D2CFGR_D2PPRE1_DIVIDED)
|
|
|
+ /* get D2 domain APB1 prescaler */
|
|
|
+ return prescaler_table[
|
|
|
+ ((d2cfgr & RCC_D2CFGR_D2PPRE1_DIVIDER)
|
|
|
+ >> RCC_D2CFGR_D2PPRE1_SHIFT)];
|
|
|
+ } else { /* APB2 */
|
|
|
+ if (d2cfgr & RCC_D2CFGR_D2PPRE2_DIVIDED)
|
|
|
+ /* get D2 domain APB2 prescaler */
|
|
|
+ return prescaler_table[
|
|
|
+ ((d2cfgr & RCC_D2CFGR_D2PPRE2_DIVIDER)
|
|
|
+ >> RCC_D2CFGR_D2PPRE2_SHIFT)];
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+};
|
|
|
+
|
|
|
+static u32 stm32_get_timer_rate(struct stm32_clk *priv, u32 sysclk,
|
|
|
+ enum apb apb)
|
|
|
+{
|
|
|
+ struct stm32_rcc_regs *regs = priv->rcc_base;
|
|
|
+u32 psc = stm32_get_apb_psc(regs, apb);
|
|
|
+
|
|
|
+ if (readl(®s->cfgr) & RCC_CFGR_TIMPRE)
|
|
|
+ /*
|
|
|
+ * if APB prescaler is configured to a
|
|
|
+ * division factor of 1, 2 or 4
|
|
|
+ */
|
|
|
+ switch (psc) {
|
|
|
+ case 1:
|
|
|
+ case 2:
|
|
|
+ case 4:
|
|
|
+ return sysclk;
|
|
|
+ case 8:
|
|
|
+ return sysclk / 2;
|
|
|
+ case 16:
|
|
|
+ return sysclk / 4;
|
|
|
+ default:
|
|
|
+ pr_err("unexpected prescaler value (%d)\n", psc);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ switch (psc) {
|
|
|
+ case 1:
|
|
|
+ return sysclk;
|
|
|
+ case 2:
|
|
|
+ case 4:
|
|
|
+ case 8:
|
|
|
+ case 16:
|
|
|
+ return sysclk / psc;
|
|
|
+ default:
|
|
|
+ pr_err("unexpected prescaler value (%d)\n", psc);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
static ulong stm32_clk_get_rate(struct clk *clk)
|
|
|
{
|
|
|
struct stm32_clk *priv = dev_get_priv(clk->dev);
|
|
@@ -660,31 +727,42 @@ static ulong stm32_clk_get_rate(struct clk *clk)
|
|
|
|
|
|
case RCC_APB1LENR:
|
|
|
case RCC_APB1HENR:
|
|
|
- if (d1cfgr & RCC_D2CFGR_D2PPRE1_DIVIDED) {
|
|
|
- /* get D2 domain APB1 prescaler */
|
|
|
- idx = (d1cfgr & RCC_D2CFGR_D2PPRE1_DIVIDER) >>
|
|
|
- RCC_D2CFGR_D2PPRE1_SHIFT;
|
|
|
- sysclk = sysclk / prescaler_table[idx];
|
|
|
+ /* special case for GPT timers */
|
|
|
+ switch (clk->id) {
|
|
|
+ case TIM14_CK:
|
|
|
+ case TIM13_CK:
|
|
|
+ case TIM12_CK:
|
|
|
+ case TIM7_CK:
|
|
|
+ case TIM6_CK:
|
|
|
+ case TIM5_CK:
|
|
|
+ case TIM4_CK:
|
|
|
+ case TIM3_CK:
|
|
|
+ case TIM2_CK:
|
|
|
+ return stm32_get_timer_rate(priv, sysclk, APB1);
|
|
|
}
|
|
|
|
|
|
debug("%s system clock: freq after APB1 prescaler = %ld\n",
|
|
|
__func__, sysclk);
|
|
|
|
|
|
- return sysclk;
|
|
|
+ return (sysclk / stm32_get_apb_psc(regs, APB1));
|
|
|
break;
|
|
|
|
|
|
case RCC_APB2ENR:
|
|
|
- if (d1cfgr & RCC_D2CFGR_D2PPRE2_DIVIDED) {
|
|
|
- /* get D2 domain APB1 prescaler */
|
|
|
- idx = (d1cfgr & RCC_D2CFGR_D2PPRE2_DIVIDER) >>
|
|
|
- RCC_D2CFGR_D2PPRE2_SHIFT;
|
|
|
- sysclk = sysclk / prescaler_table[idx];
|
|
|
+ /* special case for timers */
|
|
|
+ switch (clk->id) {
|
|
|
+ case TIM17_CK:
|
|
|
+ case TIM16_CK:
|
|
|
+ case TIM15_CK:
|
|
|
+ case TIM8_CK:
|
|
|
+ case TIM1_CK:
|
|
|
+ return stm32_get_timer_rate(priv, sysclk, APB2);
|
|
|
}
|
|
|
|
|
|
debug("%s system clock: freq after APB2 prescaler = %ld\n",
|
|
|
__func__, sysclk);
|
|
|
|
|
|
- return sysclk;
|
|
|
+ return (sysclk / stm32_get_apb_psc(regs, APB2));
|
|
|
+
|
|
|
break;
|
|
|
|
|
|
default:
|