clk: qoriq: Separate root input clock for core PLLs on ls1012a
authorScott Wood <oss@buserror.net>
Mon, 20 Mar 2017 02:37:23 +0000 (10:37 +0800)
committerStephen Boyd <sboyd@codeaurora.org>
Thu, 1 Jun 2017 08:24:13 +0000 (01:24 -0700)
ls1012a has separate input root clocks for core PLLs versus the
platform PLL, with the latter described as sysclk in the hw docs.
If a second input clock, named "coreclk", is present, this clock will be
used for the core PLLs.

Signed-off-by: Scott Wood <oss@buserror.net>
Signed-off-by: Tang Yuantian <andy.tang@nxp.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
drivers/clk/clk-qoriq.c

index d0bf8b1c67de51ba27e756af870cea4ccfa67eec..f3931e38fac0fb58a9bb6262e0fe7d9da33a6269 100644 (file)
@@ -87,7 +87,7 @@ struct clockgen {
        struct device_node *node;
        void __iomem *regs;
        struct clockgen_chipinfo info; /* mutable copy */
-       struct clk *sysclk;
+       struct clk *sysclk, *coreclk;
        struct clockgen_pll pll[6];
        struct clk *cmux[NUM_CMUX];
        struct clk *hwaccel[NUM_HWACCEL];
@@ -904,7 +904,12 @@ static void __init create_muxes(struct clockgen *cg)
 
 static void __init clockgen_init(struct device_node *np);
 
-/* Legacy nodes may get probed before the parent clockgen node */
+/*
+ * Legacy nodes may get probed before the parent clockgen node.
+ * It is assumed that device trees with legacy nodes will not
+ * contain a "clocks" property -- otherwise the input clocks may
+ * not be initialized at this point.
+ */
 static void __init legacy_init_clockgen(struct device_node *np)
 {
        if (!clockgen.node)
@@ -945,18 +950,13 @@ static struct clk __init
        return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
 }
 
-static struct clk *sysclk_from_parent(const char *name)
+static struct clk __init *input_clock(const char *name, struct clk *clk)
 {
-       struct clk *clk;
-       const char *parent_name;
-
-       clk = of_clk_get(clockgen.node, 0);
-       if (IS_ERR(clk))
-               return clk;
+       const char *input_name;
 
        /* Register the input clock under the desired name. */
-       parent_name = __clk_get_name(clk);
-       clk = clk_register_fixed_factor(NULL, name, parent_name,
+       input_name = __clk_get_name(clk);
+       clk = clk_register_fixed_factor(NULL, name, input_name,
                                        0, 1, 1);
        if (IS_ERR(clk))
                pr_err("%s: Couldn't register %s: %ld\n", __func__, name,
@@ -965,6 +965,29 @@ static struct clk *sysclk_from_parent(const char *name)
        return clk;
 }
 
+static struct clk __init *input_clock_by_name(const char *name,
+                                             const char *dtname)
+{
+       struct clk *clk;
+
+       clk = of_clk_get_by_name(clockgen.node, dtname);
+       if (IS_ERR(clk))
+               return clk;
+
+       return input_clock(name, clk);
+}
+
+static struct clk __init *input_clock_by_index(const char *name, int idx)
+{
+       struct clk *clk;
+
+       clk = of_clk_get(clockgen.node, 0);
+       if (IS_ERR(clk))
+               return clk;
+
+       return input_clock(name, clk);
+}
+
 static struct clk * __init create_sysclk(const char *name)
 {
        struct device_node *sysclk;
@@ -974,7 +997,11 @@ static struct clk * __init create_sysclk(const char *name)
        if (!IS_ERR(clk))
                return clk;
 
-       clk = sysclk_from_parent(name);
+       clk = input_clock_by_name(name, "sysclk");
+       if (!IS_ERR(clk))
+               return clk;
+
+       clk = input_clock_by_index(name, 0);
        if (!IS_ERR(clk))
                return clk;
 
@@ -985,7 +1012,27 @@ static struct clk * __init create_sysclk(const char *name)
                        return clk;
        }
 
-       pr_err("%s: No input clock\n", __func__);
+       pr_err("%s: No input sysclk\n", __func__);
+       return NULL;
+}
+
+static struct clk * __init create_coreclk(const char *name)
+{
+       struct clk *clk;
+
+       clk = input_clock_by_name(name, "coreclk");
+       if (!IS_ERR(clk))
+               return clk;
+
+       /*
+        * This indicates a mix of legacy nodes with the new coreclk
+        * mechanism, which should never happen.  If this error occurs,
+        * don't use the wrong input clock just because coreclk isn't
+        * ready yet.
+        */
+       if (WARN_ON(PTR_ERR(clk) == -EPROBE_DEFER))
+               return clk;
+
        return NULL;
 }
 
@@ -1008,11 +1055,19 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
        u32 __iomem *reg;
        u32 mult;
        struct clockgen_pll *pll = &cg->pll[idx];
+       const char *input = "cg-sysclk";
        int i;
 
        if (!(cg->info.pll_mask & (1 << idx)))
                return;
 
+       if (cg->coreclk && idx != PLATFORM_PLL) {
+               if (IS_ERR(cg->coreclk))
+                       return;
+
+               input = "cg-coreclk";
+       }
+
        if (cg->info.flags & CG_VER3) {
                switch (idx) {
                case PLATFORM_PLL:
@@ -1063,7 +1118,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
                         "cg-pll%d-div%d", idx, i + 1);
 
                clk = clk_register_fixed_factor(NULL,
-                               pll->div[i].name, "cg-sysclk", 0, mult, i + 1);
+                               pll->div[i].name, input, 0, mult, i + 1);
                if (IS_ERR(clk)) {
                        pr_err("%s: %s: register failed %ld\n",
                               __func__, pll->div[i].name, PTR_ERR(clk));
@@ -1200,6 +1255,13 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data)
                        goto bad_args;
                clk = pll->div[idx].clk;
                break;
+       case 5:
+               if (idx != 0)
+                       goto bad_args;
+               clk = cg->coreclk;
+               if (IS_ERR(clk))
+                       clk = NULL;
+               break;
        default:
                goto bad_args;
        }
@@ -1311,6 +1373,7 @@ static void __init clockgen_init(struct device_node *np)
                clockgen.info.flags |= CG_CMUX_GE_PLAT;
 
        clockgen.sysclk = create_sysclk("cg-sysclk");
+       clockgen.coreclk = create_coreclk("cg-coreclk");
        create_plls(&clockgen);
        create_muxes(&clockgen);