You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
8.2 KiB
323 lines
8.2 KiB
From 82a391a067491f4c46b75d0dfe2bf9e5a11aca8e Mon Sep 17 00:00:00 2001
|
|
From: Yangbo Lu <yangbo.lu@nxp.com>
|
|
Date: Wed, 17 Jan 2018 15:15:44 +0800
|
|
Subject: [PATCH 14/30] clk: support layerscape
|
|
|
|
This is an integrated patch for layerscape clock support.
|
|
|
|
Signed-off-by: Yuantian Tang <andy.tang@nxp.com>
|
|
Signed-off-by: Mingkai Hu <mingkai.hu@nxp.com>
|
|
Signed-off-by: Scott Wood <oss@buserror.net>
|
|
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
|
|
---
|
|
drivers/clk/clk-qoriq.c | 179 ++++++++++++++++++++++++++++++++++++++++++++----
|
|
1 file changed, 164 insertions(+), 15 deletions(-)
|
|
|
|
--- a/drivers/clk/clk-qoriq.c
|
|
+++ b/drivers/clk/clk-qoriq.c
|
|
@@ -12,6 +12,7 @@
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/clk-provider.h>
|
|
+#include <linux/clkdev.h>
|
|
#include <linux/fsl/guts.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
@@ -40,7 +41,7 @@ struct clockgen_pll_div {
|
|
};
|
|
|
|
struct clockgen_pll {
|
|
- struct clockgen_pll_div div[4];
|
|
+ struct clockgen_pll_div div[8];
|
|
};
|
|
|
|
#define CLKSEL_VALID 1
|
|
@@ -87,7 +88,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];
|
|
@@ -266,6 +267,39 @@ static const struct clockgen_muxinfo ls1
|
|
},
|
|
};
|
|
|
|
+static const struct clockgen_muxinfo ls1046a_hwa1 = {
|
|
+ {
|
|
+ {},
|
|
+ {},
|
|
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
|
|
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
|
|
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
|
|
+ { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
|
|
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
|
|
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
|
|
+ },
|
|
+};
|
|
+
|
|
+static const struct clockgen_muxinfo ls1046a_hwa2 = {
|
|
+ {
|
|
+ {},
|
|
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
|
|
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
|
|
+ { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
|
|
+ {},
|
|
+ {},
|
|
+ { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
|
|
+ },
|
|
+};
|
|
+
|
|
+static const struct clockgen_muxinfo ls1012a_cmux = {
|
|
+ {
|
|
+ [0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
|
|
+ {},
|
|
+ [2] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
|
|
+ }
|
|
+};
|
|
+
|
|
static const struct clockgen_muxinfo t1023_hwa1 = {
|
|
{
|
|
{},
|
|
@@ -489,6 +523,42 @@ static const struct clockgen_chipinfo ch
|
|
.flags = CG_PLL_8BIT,
|
|
},
|
|
{
|
|
+ .compat = "fsl,ls1046a-clockgen",
|
|
+ .init_periph = t2080_init_periph,
|
|
+ .cmux_groups = {
|
|
+ &t1040_cmux
|
|
+ },
|
|
+ .hwaccel = {
|
|
+ &ls1046a_hwa1, &ls1046a_hwa2
|
|
+ },
|
|
+ .cmux_to_group = {
|
|
+ 0, -1
|
|
+ },
|
|
+ .pll_mask = 0x07,
|
|
+ .flags = CG_PLL_8BIT,
|
|
+ },
|
|
+ {
|
|
+ .compat = "fsl,ls1088a-clockgen",
|
|
+ .cmux_groups = {
|
|
+ &clockgen2_cmux_cga12
|
|
+ },
|
|
+ .cmux_to_group = {
|
|
+ 0, 0, -1
|
|
+ },
|
|
+ .pll_mask = 0x07,
|
|
+ .flags = CG_VER3 | CG_LITTLE_ENDIAN,
|
|
+ },
|
|
+ {
|
|
+ .compat = "fsl,ls1012a-clockgen",
|
|
+ .cmux_groups = {
|
|
+ &ls1012a_cmux
|
|
+ },
|
|
+ .cmux_to_group = {
|
|
+ 0, -1
|
|
+ },
|
|
+ .pll_mask = 0x03,
|
|
+ },
|
|
+ {
|
|
.compat = "fsl,ls2080a-clockgen",
|
|
.cmux_groups = {
|
|
&clockgen2_cmux_cga12, &clockgen2_cmux_cgb
|
|
@@ -846,7 +916,12 @@ static void __init create_muxes(struct c
|
|
|
|
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)
|
|
@@ -887,18 +962,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,
|
|
@@ -907,6 +977,29 @@ static struct clk *sysclk_from_parent(co
|
|
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;
|
|
@@ -916,7 +1009,11 @@ static struct clk * __init create_sysclk
|
|
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;
|
|
|
|
@@ -927,7 +1024,27 @@ static struct clk * __init create_sysclk
|
|
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;
|
|
}
|
|
|
|
@@ -950,11 +1067,19 @@ static void __init create_one_pll(struct
|
|
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:
|
|
@@ -1000,12 +1125,20 @@ static void __init create_one_pll(struct
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pll->div); i++) {
|
|
struct clk *clk;
|
|
+ int ret;
|
|
+
|
|
+ /*
|
|
+ * For platform PLL, there are 8 divider clocks.
|
|
+ * For core PLL, there are 4 divider clocks at most.
|
|
+ */
|
|
+ if (idx != 0 && i >= 4)
|
|
+ break;
|
|
|
|
snprintf(pll->div[i].name, sizeof(pll->div[i].name),
|
|
"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));
|
|
@@ -1013,6 +1146,11 @@ static void __init create_one_pll(struct
|
|
}
|
|
|
|
pll->div[i].clk = clk;
|
|
+ ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
|
|
+ if (ret != 0)
|
|
+ pr_err("%s: %s: register to lookup table failed %ld\n",
|
|
+ __func__, pll->div[i].name, PTR_ERR(clk));
|
|
+
|
|
}
|
|
}
|
|
|
|
@@ -1142,6 +1280,13 @@ static struct clk *clockgen_clk_get(stru
|
|
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;
|
|
}
|
|
@@ -1253,6 +1398,7 @@ static void __init clockgen_init(struct
|
|
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);
|
|
|
|
@@ -1273,8 +1419,11 @@ err:
|
|
|
|
CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init);
|
|
CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init);
|
|
+CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
|
|
CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
|
|
CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
|
|
+CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
|
|
+CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
|
|
CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
|
|
|
|
/* Legacy nodes */
|
|
|