diff options
Diffstat (limited to 'drivers/clk/clk-qoriq.c')
| -rw-r--r-- | drivers/clk/clk-qoriq.c | 250 |
1 files changed, 210 insertions, 40 deletions
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 5baa9e051110..a560edeb4b55 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1,15 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * Copyright 2021 NXP * * clock driver for Freescale QorIQ SoCs. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <dt-bindings/clock/fsl,qoriq-clockgen.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> @@ -18,8 +18,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_address.h> -#include <linux/of_platform.h> #include <linux/of.h> +#include <linux/platform_device.h> #include <linux/slab.h> #define PLL_DIV1 0 @@ -34,6 +34,7 @@ #define CGA_PLL4 4 /* only on clockgen-1.0, which lacks CGB */ #define CGB_PLL1 4 #define CGB_PLL2 5 +#define MAX_PLL_DIV 32 struct clockgen_pll_div { struct clk *clk; @@ -41,7 +42,7 @@ struct clockgen_pll_div { }; struct clockgen_pll { - struct clockgen_pll_div div[8]; + struct clockgen_pll_div div[MAX_PLL_DIV]; }; #define CLKSEL_VALID 1 @@ -79,7 +80,7 @@ struct clockgen_chipinfo { const struct clockgen_muxinfo *cmux_groups[2]; const struct clockgen_muxinfo *hwaccel[NUM_HWACCEL]; void (*init_periph)(struct clockgen *cg); - int cmux_to_group[NUM_CMUX]; /* -1 terminates if fewer than NUM_CMUX */ + int cmux_to_group[NUM_CMUX + 1]; /* array should be -1 terminated */ u32 pll_mask; /* 1 << n bit set if PLL n is valid */ u32 flags; /* CG_xxx */ }; @@ -97,6 +98,7 @@ struct clockgen { }; static struct clockgen clockgen; +static bool add_cpufreq_dev __initdata; static void cg_out(struct clockgen *cg, u32 val, u32 __iomem *reg) { @@ -245,6 +247,66 @@ static const struct clockgen_muxinfo clockgen2_cmux_cgb = { }, }; +static const struct clockgen_muxinfo ls1021a_cmux = { + { + { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + } +}; + +static const struct clockgen_muxinfo ls1028a_hwa1 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1028a_hwa2 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1028a_hwa3 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1028a_hwa4 = { + { + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + }, +}; + static const struct clockgen_muxinfo ls1043a_hwa1 = { { {}, @@ -292,6 +354,32 @@ static const struct clockgen_muxinfo ls1046a_hwa2 = { }, }; +static const struct clockgen_muxinfo ls1088a_hwa1 = { + { + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1088a_hwa2 = { + { + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV4 }, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + }, +}; + static const struct clockgen_muxinfo ls1012a_cmux = { { [0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, @@ -478,7 +566,9 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 1, 1, 1, -1 }, - .pll_mask = 0x3f, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3) | + BIT(CGB_PLL1) | BIT(CGB_PLL2), .flags = CG_PLL_8BIT, }, { @@ -494,18 +584,37 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 1, 1, 1, -1 }, - .pll_mask = 0x3f, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3) | + BIT(CGB_PLL1) | BIT(CGB_PLL2), .flags = CG_PLL_8BIT, }, { .compat = "fsl,ls1021a-clockgen", .cmux_groups = { - &t1023_cmux + &ls1021a_cmux }, .cmux_to_group = { 0, -1 }, - .pll_mask = 0x03, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), + }, + { + .compat = "fsl,ls1028a-clockgen", + .cmux_groups = { + &clockgen2_cmux_cga12 + }, + .hwaccel = { + &ls1028a_hwa1, &ls1028a_hwa2, + &ls1028a_hwa3, &ls1028a_hwa4 + }, + .cmux_to_group = { + 0, 0, 0, 0, -1 + }, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), + .flags = CG_VER3 | CG_LITTLE_ENDIAN, }, { .compat = "fsl,ls1043a-clockgen", @@ -519,7 +628,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), .flags = CG_PLL_8BIT, }, { @@ -534,7 +644,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), .flags = CG_PLL_8BIT, }, { @@ -542,10 +653,14 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_groups = { &clockgen2_cmux_cga12 }, + .hwaccel = { + &ls1088a_hwa1, &ls1088a_hwa2 + }, .cmux_to_group = { 0, 0, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), .flags = CG_VER3 | CG_LITTLE_ENDIAN, }, { @@ -556,7 +671,7 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, -1 }, - .pll_mask = 0x03, + .pll_mask = BIT(PLATFORM_PLL) | BIT(CGA_PLL1), }, { .compat = "fsl,ls2080a-clockgen", @@ -566,7 +681,22 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, 1, 1, -1 }, - .pll_mask = 0x37, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | + BIT(CGB_PLL1) | BIT(CGB_PLL2), + .flags = CG_VER3 | CG_LITTLE_ENDIAN, + }, + { + .compat = "fsl,lx2160a-clockgen", + .cmux_groups = { + &clockgen2_cmux_cga12, &clockgen2_cmux_cgb + }, + .cmux_to_group = { + 0, 0, 0, 0, 1, 1, 1, 1, -1 + }, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | + BIT(CGB_PLL1) | BIT(CGB_PLL2), .flags = CG_VER3 | CG_LITTLE_ENDIAN, }, { @@ -579,7 +709,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, 1, 1, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), }, { .compat = "fsl,p3041-clockgen", @@ -591,7 +722,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, 1, 1, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), }, { .compat = "fsl,p4080-clockgen", @@ -601,21 +733,24 @@ static const struct clockgen_chipinfo chipinfo[] = { &p4080_cmux_grp1, &p4080_cmux_grp2 }, .cmux_to_group = { - 0, 0, 0, 0, 1, 1, 1, 1 + 0, 0, 0, 0, 1, 1, 1, 1, -1 }, - .pll_mask = 0x1f, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | + BIT(CGA_PLL3) | BIT(CGA_PLL4), }, { .compat = "fsl,p5020-clockgen", .guts_compat = "fsl,qoriq-device-config-1.0", .init_periph = p5020_init_periph, .cmux_groups = { - &p2041_cmux_grp1, &p2041_cmux_grp2 + &p5020_cmux_grp1, &p5020_cmux_grp2 }, .cmux_to_group = { 0, 1, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), }, { .compat = "fsl,p5040-clockgen", @@ -627,7 +762,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, 1, 1, -1 }, - .pll_mask = 0x0f, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3), }, { .compat = "fsl,t1023-clockgen", @@ -642,7 +778,7 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, -1 }, - .pll_mask = 0x03, + .pll_mask = BIT(PLATFORM_PLL) | BIT(CGA_PLL1), .flags = CG_PLL_8BIT, }, { @@ -655,7 +791,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, 0, 0, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), .flags = CG_PLL_8BIT, }, { @@ -671,7 +808,8 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, -1 }, - .pll_mask = 0x07, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2), .flags = CG_PLL_8BIT, }, { @@ -687,7 +825,9 @@ static const struct clockgen_chipinfo chipinfo[] = { .cmux_to_group = { 0, 0, 1, -1 }, - .pll_mask = 0x3f, + .pll_mask = BIT(PLATFORM_PLL) | + BIT(CGA_PLL1) | BIT(CGA_PLL2) | BIT(CGA_PLL3) | + BIT(CGB_PLL1) | BIT(CGB_PLL2), .flags = CG_PLL_8BIT, }, {}, @@ -739,6 +879,7 @@ static u8 mux_get_parent(struct clk_hw *hw) } static const struct clk_ops cmux_ops = { + .determine_rate = clk_hw_determine_rate_no_reparent, .get_parent = mux_get_parent, .set_parent = mux_set_parent, }; @@ -914,7 +1055,7 @@ static void __init create_muxes(struct clockgen *cg) } } -static void __init clockgen_init(struct device_node *np); +static void __init _clockgen_init(struct device_node *np, bool legacy); /* * Legacy nodes may get probed before the parent clockgen node. @@ -924,8 +1065,10 @@ static void __init clockgen_init(struct device_node *np); */ static void __init legacy_init_clockgen(struct device_node *np) { - if (!clockgen.node) - clockgen_init(of_get_parent(np)); + if (!clockgen.node) { + struct device_node *parent_np __free(device_node) = of_get_parent(np); + _clockgen_init(parent_np, true); + } } /* Legacy node */ @@ -1020,6 +1163,7 @@ static struct clk * __init create_sysclk(const char *name) sysclk = of_get_child_by_name(clockgen.node, "sysclk"); if (sysclk) { clk = sysclk_from_fixed(sysclk, name); + of_node_put(sysclk); if (!IS_ERR(clk)) return clk; } @@ -1128,7 +1272,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx) int ret; /* - * For platform PLL, there are 8 divider clocks. + * For platform PLL, there are MAX_PLL_DIV divider clocks. * For core PLL, there are 4 divider clocks at most. */ if (idx != PLATFORM_PLL && i >= 4) @@ -1148,8 +1292,8 @@ static void __init create_one_pll(struct clockgen *cg, int idx) 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)); + pr_err("%s: %s: register to lookup table failed %d\n", + __func__, pll->div[i].name, ret); } } @@ -1254,33 +1398,33 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data) idx = clkspec->args[1]; switch (type) { - case 0: + case QORIQ_CLK_SYSCLK: if (idx != 0) goto bad_args; clk = cg->sysclk; break; - case 1: + case QORIQ_CLK_CMUX: if (idx >= ARRAY_SIZE(cg->cmux)) goto bad_args; clk = cg->cmux[idx]; break; - case 2: + case QORIQ_CLK_HWACCEL: if (idx >= ARRAY_SIZE(cg->hwaccel)) goto bad_args; clk = cg->hwaccel[idx]; break; - case 3: + case QORIQ_CLK_FMAN: if (idx >= ARRAY_SIZE(cg->fman)) goto bad_args; clk = cg->fman[idx]; break; - case 4: + case QORIQ_CLK_PLATFORM_PLL: pll = &cg->pll[PLATFORM_PLL]; if (idx >= ARRAY_SIZE(pll->div)) goto bad_args; clk = pll->div[idx].clk; break; - case 5: + case QORIQ_CLK_CORECLK: if (idx != 0) goto bad_args; clk = cg->coreclk; @@ -1342,7 +1486,7 @@ static bool __init has_erratum_a4510(void) } #endif -static void __init clockgen_init(struct device_node *np) +static void __init _clockgen_init(struct device_node *np, bool legacy) { int i, ret; bool is_old_ls1021a = false; @@ -1389,6 +1533,7 @@ static void __init clockgen_init(struct device_node *np) pr_err("%s: Couldn't map %pOF regs\n", __func__, guts); } + of_node_put(guts); } } @@ -1410,22 +1555,47 @@ static void __init clockgen_init(struct device_node *np) __func__, np, ret); } + /* Don't create cpufreq device for legacy clockgen blocks */ + add_cpufreq_dev = !legacy; + return; err: iounmap(clockgen.regs); clockgen.regs = NULL; } +static void __init clockgen_init(struct device_node *np) +{ + _clockgen_init(np, false); +} + +static int __init clockgen_cpufreq_init(void) +{ + struct platform_device *pdev; + + if (add_cpufreq_dev) { + pdev = platform_device_register_simple("qoriq-cpufreq", -1, + NULL, 0); + if (IS_ERR(pdev)) + pr_err("Couldn't register qoriq-cpufreq err=%ld\n", + PTR_ERR(pdev)); + } + return 0; +} +device_initcall(clockgen_cpufreq_init); + 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_b4420, "fsl,b4420-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_b4860, "fsl,b4860-clockgen", 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_ls1028a, "fsl,ls1028a-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); +CLK_OF_DECLARE(qoriq_clockgen_lx2160a, "fsl,lx2160a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_p2041, "fsl,p2041-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_p3041, "fsl,p3041-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_p4080, "fsl,p4080-clockgen", clockgen_init); |
