summaryrefslogtreecommitdiff
path: root/drivers/clk/starfive/clk-starfive-jh7110-sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/starfive/clk-starfive-jh7110-sys.c')
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7110-sys.c135
1 files changed, 88 insertions, 47 deletions
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
index e6031345ef05..52833d4241c5 100644
--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c
+++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
@@ -7,6 +7,7 @@
*/
#include <linux/auxiliary_bus.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -35,18 +36,18 @@
static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
/* root */
- JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2,
+ JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 0, 2,
JH7110_SYSCLK_OSC,
JH7110_SYSCLK_PLL0_OUT),
JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT),
JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE),
- JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2,
+ JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 0, 2,
JH7110_SYSCLK_PLL2_OUT,
JH7110_SYSCLK_PLL1_OUT),
JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2,
JH7110_SYSCLK_PLL0_OUT,
JH7110_SYSCLK_PLL2_OUT),
- JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2,
+ JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 0, 2,
JH7110_SYSCLK_OSC,
JH7110_SYSCLK_PLL2_OUT),
JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT),
@@ -61,7 +62,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT),
JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT),
JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT),
- JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 0, 2,
JH7110_SYSCLK_MCLK_INNER,
JH7110_SYSCLK_MCLK_EXT),
JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER),
@@ -95,7 +96,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC),
JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2),
JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4),
- JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4,
+ JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 0, 4,
JH7110_SYSCLK_OSC_DIV2,
JH7110_SYSCLK_PLL1_DIV2,
JH7110_SYSCLK_PLL1_DIV4,
@@ -185,7 +186,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30,
JH7110_SYSCLK_GMAC1_RMII_REFIN),
JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC),
- JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2,
+ JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 0, 2,
JH7110_SYSCLK_GMAC1_RGMII_RXIN,
JH7110_SYSCLK_GMAC1_RMII_RTX),
JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX),
@@ -269,11 +270,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2,
JH7110_SYSCLK_I2STX0_BCLK_MST_INV,
JH7110_SYSCLK_I2STX0_BCLK_MST),
- JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 0, 2,
JH7110_SYSCLK_I2STX0_BCLK_MST,
JH7110_SYSCLK_I2STX_BCLK_EXT),
JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK),
- JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 0, 2,
JH7110_SYSCLK_I2STX0_LRCK_MST,
JH7110_SYSCLK_I2STX_LRCK_EXT),
/* i2stx1 */
@@ -284,11 +285,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2,
JH7110_SYSCLK_I2STX1_BCLK_MST_INV,
JH7110_SYSCLK_I2STX1_BCLK_MST),
- JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 0, 2,
JH7110_SYSCLK_I2STX1_BCLK_MST,
JH7110_SYSCLK_I2STX_BCLK_EXT),
JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK),
- JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 0, 2,
JH7110_SYSCLK_I2STX1_LRCK_MST,
JH7110_SYSCLK_I2STX_LRCK_EXT),
/* i2srx */
@@ -299,11 +300,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2,
JH7110_SYSCLK_I2SRX_BCLK_MST_INV,
JH7110_SYSCLK_I2SRX_BCLK_MST),
- JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 0, 2,
JH7110_SYSCLK_I2SRX_BCLK_MST,
JH7110_SYSCLK_I2SRX_BCLK_EXT),
JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK),
- JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 0, 2,
JH7110_SYSCLK_I2SRX_LRCK_MST,
JH7110_SYSCLK_I2SRX_LRCK_EXT),
/* pdm */
@@ -313,7 +314,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0),
JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0),
JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK),
- JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2,
+ JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 0, 2,
JH7110_SYSCLK_TDM_INTERNAL,
JH7110_SYSCLK_TDM_EXT),
JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM),
@@ -322,17 +323,6 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH7110_SYSCLK_OSC),
};
-static struct clk_hw *jh7110_sysclk_get(struct of_phandle_args *clkspec, void *data)
-{
- struct jh71x0_clk_priv *priv = data;
- unsigned int idx = clkspec->args[0];
-
- if (idx < JH7110_SYSCLK_END)
- return &priv->reg[idx].hw;
-
- return ERR_PTR(-EINVAL);
-}
-
static void jh7110_reset_unregister_adev(void *_adev)
{
struct auxiliary_device *adev = _adev;
@@ -384,11 +374,38 @@ 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 current parent clock and switch its parent
+ * clock to osc before PLL0 rate will be changed. Then switch 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;
unsigned int idx;
int ret;
+ struct clk *pllclk;
priv = devm_kzalloc(&pdev->dev,
struct_size(priv, reg, JH7110_SYSCLK_END),
@@ -397,33 +414,51 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev)
return -ENOMEM;
spin_lock_init(&priv->rmw_lock);
+ priv->num_reg = JH7110_SYSCLK_END;
priv->dev = &pdev->dev;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- /*
- * These PLL clocks are not actually fixed factor clocks and can be
- * controlled by the syscon registers of JH7110. They will be dropped
- * and registered in the PLL clock driver instead.
- */
- /* 24MHz -> 1000.0MHz */
- priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out",
- "osc", 0, 125, 3);
- if (IS_ERR(priv->pll[0]))
- return PTR_ERR(priv->pll[0]);
-
- /* 24MHz -> 1066.0MHz */
- priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out",
- "osc", 0, 533, 12);
- if (IS_ERR(priv->pll[1]))
- return PTR_ERR(priv->pll[1]);
-
- /* 24MHz -> 1188.0MHz */
- priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out",
- "osc", 0, 99, 2);
- if (IS_ERR(priv->pll[2]))
- return PTR_ERR(priv->pll[2]);
+ /* Use fixed factor clocks if can not get the PLL clocks from DTS */
+ pllclk = clk_get(priv->dev, "pll0_out");
+ if (IS_ERR(pllclk)) {
+ /* 24MHz -> 1000.0MHz */
+ priv->pll[0] = devm_clk_hw_register_fixed_factor(priv->dev, "pll0_out",
+ "osc", 0, 125, 3);
+ if (IS_ERR(priv->pll[0]))
+ return PTR_ERR(priv->pll[0]);
+ } else {
+ 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;
+ }
+
+ pllclk = clk_get(priv->dev, "pll1_out");
+ if (IS_ERR(pllclk)) {
+ /* 24MHz -> 1066.0MHz */
+ priv->pll[1] = devm_clk_hw_register_fixed_factor(priv->dev, "pll1_out",
+ "osc", 0, 533, 12);
+ if (IS_ERR(priv->pll[1]))
+ return PTR_ERR(priv->pll[1]);
+ } else {
+ clk_put(pllclk);
+ priv->pll[1] = NULL;
+ }
+
+ pllclk = clk_get(priv->dev, "pll2_out");
+ if (IS_ERR(pllclk)) {
+ /* 24MHz -> 1188.0MHz */
+ priv->pll[2] = devm_clk_hw_register_fixed_factor(priv->dev, "pll2_out",
+ "osc", 0, 99, 2);
+ if (IS_ERR(priv->pll[2]))
+ return PTR_ERR(priv->pll[2]);
+ } else {
+ clk_put(pllclk);
+ priv->pll[2] = NULL;
+ }
for (idx = 0; idx < JH7110_SYSCLK_END; idx++) {
u32 max = jh7110_sysclk_data[idx].max;
@@ -462,6 +497,12 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev)
parents[i].fw_name = "tdm_ext";
else if (pidx == JH7110_SYSCLK_MCLK_EXT)
parents[i].fw_name = "mclk_ext";
+ else if (pidx == JH7110_SYSCLK_PLL0_OUT && !priv->pll[0])
+ parents[i].fw_name = "pll0_out";
+ else if (pidx == JH7110_SYSCLK_PLL1_OUT && !priv->pll[1])
+ parents[i].fw_name = "pll1_out";
+ else if (pidx == JH7110_SYSCLK_PLL2_OUT && !priv->pll[2])
+ parents[i].fw_name = "pll2_out";
else
parents[i].hw = priv->pll[pidx - JH7110_SYSCLK_PLL0_OUT];
}
@@ -475,7 +516,7 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev)
return ret;
}
- ret = devm_of_clk_add_hw_provider(&pdev->dev, jh7110_sysclk_get, priv);
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv);
if (ret)
return ret;