diff options
Diffstat (limited to 'drivers/clk/starfive/clk-starfive-jh7110-sys.c')
-rw-r--r-- | drivers/clk/starfive/clk-starfive-jh7110-sys.c | 54 |
1 files changed, 52 insertions, 2 deletions
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c index 8f5e5abfa178..7469981fb405 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c @@ -385,6 +385,32 @@ int jh7110_reset_controller_register(struct jh71x0_clk_priv *priv, } EXPORT_SYMBOL_GPL(jh7110_reset_controller_register); +/* + * This clock notifier is called when the rate of PLL0 clock is to be changed. + * The cpu_root clock should save the curent parent clock and swicth its parent + * clock to osc before PLL0 rate will be changed. Then swicth its parent clock + * back after the PLL0 rate is completed. + */ +static int jh7110_pll0_clk_notifier_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct jh71x0_clk_priv *priv = container_of(nb, struct jh71x0_clk_priv, pll_clk_nb); + struct clk *cpu_root = priv->reg[JH7110_SYSCLK_CPU_ROOT].hw.clk; + int ret = 0; + + if (action == PRE_RATE_CHANGE) { + struct clk *osc = clk_get(priv->dev, "osc"); + + priv->original_clk = clk_get_parent(cpu_root); + ret = clk_set_parent(cpu_root, osc); + clk_put(osc); + } else if (action == POST_RATE_CHANGE) { + ret = clk_set_parent(cpu_root, priv->original_clk); + } + + return notifier_from_errno(ret); +} + static int __init jh7110_syscrg_probe(struct platform_device *pdev) { struct jh71x0_clk_priv *priv; @@ -413,7 +439,11 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev) if (IS_ERR(priv->pll[0])) return PTR_ERR(priv->pll[0]); } else { - clk_put(pllclk); + priv->pll_clk_nb.notifier_call = jh7110_pll0_clk_notifier_cb; + ret = clk_notifier_register(pllclk, &priv->pll_clk_nb); + if (ret) + return ret; + priv->pll[0] = NULL; } @@ -501,7 +531,27 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev) if (ret) return ret; - return jh7110_reset_controller_register(priv, "rst-sys", 0); + ret = jh7110_reset_controller_register(priv, "rst-sys", 0); + if (ret) + return ret; + + /* Set the divider cpu_core to 2 and set the PLL0 rate to 1.5G. */ + pllclk = clk_get(priv->dev, "pll0_out"); + if (!IS_ERR(pllclk)) { + struct clk *cpu_core = priv->reg[JH7110_SYSCLK_CPU_CORE].hw.clk; + + ret = clk_set_rate(cpu_core, clk_get_rate(cpu_core) / 2); + if (ret) + return ret; + + ret = clk_set_rate(pllclk, 1500000000); + if (ret) + return ret; + + clk_put(pllclk); + } + + return 0; } static const struct of_device_id jh7110_syscrg_match[] = { |