From 82a391a067491f4c46b75d0dfe2bf9e5a11aca8e Mon Sep 17 00:00:00 2001 From: Yangbo Lu 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 Signed-off-by: Mingkai Hu Signed-off-by: Scott Wood Signed-off-by: Yangbo Lu --- 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 #include +#include #include #include #include @@ -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; } @@ -1254,6 +1399,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); @@ -1274,8 +1420,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 */