From a9ebdf9fa18fd317a4e97f46e8c5263898094864 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 25 Sep 2017 12:20:10 +0800 Subject: [PATCH] cpufreq: support layerscape This is a integrated patch for layerscape pm support. Signed-off-by: Tang Yuantian Signed-off-by: Yangbo Lu --- drivers/cpufreq/Kconfig | 2 +- drivers/cpufreq/qoriq-cpufreq.c | 176 +++++++++++++++------------------------- drivers/firmware/psci.c | 12 ++- 3 files changed, 77 insertions(+), 113 deletions(-) --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -332,7 +332,7 @@ endif config QORIQ_CPUFREQ tristate "CPU frequency scaling driver for Freescale QorIQ SoCs" - depends on OF && COMMON_CLK && (PPC_E500MC || ARM) + depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64) depends on !CPU_THERMAL || THERMAL select CLK_QORIQ help --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -22,10 +23,6 @@ #include #include -#if !defined(CONFIG_ARM) -#include /* for get_hard_smp_processor_id() in UP configs */ -#endif - /** * struct cpu_data * @pclk: the parent clock of cpu @@ -37,73 +34,51 @@ struct cpu_data { struct thermal_cooling_device *cdev; }; +/* + * Don't use cpufreq on this SoC -- used when the SoC would have otherwise + * matched a more generic compatible. + */ +#define SOC_BLACKLIST 1 + /** * struct soc_data - SoC specific data - * @freq_mask: mask the disallowed frequencies - * @flag: unique flags + * @flags: SOC_xxx */ struct soc_data { - u32 freq_mask[4]; - u32 flag; -}; - -#define FREQ_MASK 1 -/* see hardware specification for the allowed frqeuencies */ -static const struct soc_data sdata[] = { - { /* used by p2041 and p3041 */ - .freq_mask = {0x8, 0x8, 0x2, 0x2}, - .flag = FREQ_MASK, - }, - { /* used by p5020 */ - .freq_mask = {0x8, 0x2}, - .flag = FREQ_MASK, - }, - { /* used by p4080, p5040 */ - .freq_mask = {0}, - .flag = 0, - }, + u32 flags; }; -/* - * the minimum allowed core frequency, in Hz - * for chassis v1.0, >= platform frequency - * for chassis v2.0, >= platform frequency / 2 - */ -static u32 min_cpufreq; -static const u32 *fmask; - -#if defined(CONFIG_ARM) -static int get_cpu_physical_id(int cpu) -{ - return topology_core_id(cpu); -} -#else -static int get_cpu_physical_id(int cpu) -{ - return get_hard_smp_processor_id(cpu); -} -#endif - static u32 get_bus_freq(void) { struct device_node *soc; u32 sysfreq; + struct clk *pltclk; + int ret; + /* get platform freq by searching bus-frequency property */ soc = of_find_node_by_type(NULL, "soc"); - if (!soc) - return 0; - - if (of_property_read_u32(soc, "bus-frequency", &sysfreq)) - sysfreq = 0; + if (soc) { + ret = of_property_read_u32(soc, "bus-frequency", &sysfreq); + of_node_put(soc); + if (!ret) + return sysfreq; + } - of_node_put(soc); + /* get platform freq by its clock name */ + pltclk = clk_get(NULL, "cg-pll0-div1"); + if (IS_ERR(pltclk)) { + pr_err("%s: can't get bus frequency %ld\n", + __func__, PTR_ERR(pltclk)); + return PTR_ERR(pltclk); + } - return sysfreq; + return clk_get_rate(pltclk); } -static struct device_node *cpu_to_clk_node(int cpu) +static struct clk *cpu_to_clk(int cpu) { - struct device_node *np, *clk_np; + struct device_node *np; + struct clk *clk; if (!cpu_present(cpu)) return NULL; @@ -112,37 +87,28 @@ static struct device_node *cpu_to_clk_no if (!np) return NULL; - clk_np = of_parse_phandle(np, "clocks", 0); - if (!clk_np) - return NULL; - + clk = of_clk_get(np, 0); of_node_put(np); - - return clk_np; + return clk; } /* traverse cpu nodes to get cpu mask of sharing clock wire */ static void set_affected_cpus(struct cpufreq_policy *policy) { - struct device_node *np, *clk_np; struct cpumask *dstp = policy->cpus; + struct clk *clk; int i; - np = cpu_to_clk_node(policy->cpu); - if (!np) - return; - for_each_present_cpu(i) { - clk_np = cpu_to_clk_node(i); - if (!clk_np) + clk = cpu_to_clk(i); + if (IS_ERR(clk)) { + pr_err("%s: no clock for cpu %d\n", __func__, i); continue; + } - if (clk_np == np) + if (clk_is_match(policy->clk, clk)) cpumask_set_cpu(i, dstp); - - of_node_put(clk_np); } - of_node_put(np); } /* reduce the duplicated frequencies in frequency table */ @@ -198,10 +164,11 @@ static void freq_table_sort(struct cpufr static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) { - struct device_node *np, *pnode; + struct device_node *np; int i, count, ret; - u32 freq, mask; + u32 freq; struct clk *clk; + const struct clk_hw *hwclk; struct cpufreq_frequency_table *table; struct cpu_data *data; unsigned int cpu = policy->cpu; @@ -221,17 +188,13 @@ static int qoriq_cpufreq_cpu_init(struct goto err_nomem2; } - pnode = of_parse_phandle(np, "clocks", 0); - if (!pnode) { - pr_err("%s: could not get clock information\n", __func__); - goto err_nomem2; - } + hwclk = __clk_get_hw(policy->clk); + count = clk_hw_get_num_parents(hwclk); - count = of_property_count_strings(pnode, "clock-names"); data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL); if (!data->pclk) { pr_err("%s: no memory\n", __func__); - goto err_node; + goto err_nomem2; } table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL); @@ -240,23 +203,11 @@ static int qoriq_cpufreq_cpu_init(struct goto err_pclk; } - if (fmask) - mask = fmask[get_cpu_physical_id(cpu)]; - else - mask = 0x0; - for (i = 0; i < count; i++) { - clk = of_clk_get(pnode, i); + clk = clk_hw_get_parent_by_index(hwclk, i)->clk; data->pclk[i] = clk; freq = clk_get_rate(clk); - /* - * the clock is valid if its frequency is not masked - * and large than minimum allowed frequency. - */ - if (freq < min_cpufreq || (mask & (1 << i))) - table[i].frequency = CPUFREQ_ENTRY_INVALID; - else - table[i].frequency = freq / 1000; + table[i].frequency = freq / 1000; table[i].driver_data = i; } freq_table_redup(table, count); @@ -282,7 +233,6 @@ static int qoriq_cpufreq_cpu_init(struct policy->cpuinfo.transition_latency = u64temp + 1; of_node_put(np); - of_node_put(pnode); return 0; @@ -290,10 +240,7 @@ err_nomem1: kfree(table); err_pclk: kfree(data->pclk); -err_node: - of_node_put(pnode); err_nomem2: - policy->driver_data = NULL; kfree(data); err_np: of_node_put(np); @@ -357,12 +304,25 @@ static struct cpufreq_driver qoriq_cpufr .attr = cpufreq_generic_attr, }; +static const struct soc_data blacklist = { + .flags = SOC_BLACKLIST, +}; + static const struct of_device_id node_matches[] __initconst = { - { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], }, - { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], }, - { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], }, - { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], }, - { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], }, + /* e6500 cannot use cpufreq due to erratum A-008083 */ + { .compatible = "fsl,b4420-clockgen", &blacklist }, + { .compatible = "fsl,b4860-clockgen", &blacklist }, + { .compatible = "fsl,t2080-clockgen", &blacklist }, + { .compatible = "fsl,t4240-clockgen", &blacklist }, + + { .compatible = "fsl,ls1012a-clockgen", }, + { .compatible = "fsl,ls1021a-clockgen", }, + { .compatible = "fsl,ls1043a-clockgen", }, + { .compatible = "fsl,ls1046a-clockgen", }, + { .compatible = "fsl,ls1088a-clockgen", }, + { .compatible = "fsl,ls2080a-clockgen", }, + { .compatible = "fsl,p4080-clockgen", }, + { .compatible = "fsl,qoriq-clockgen-1.0", }, { .compatible = "fsl,qoriq-clockgen-2.0", }, {} }; @@ -380,16 +340,12 @@ static int __init qoriq_cpufreq_init(voi match = of_match_node(node_matches, np); data = match->data; - if (data) { - if (data->flag) - fmask = data->freq_mask; - min_cpufreq = get_bus_freq(); - } else { - min_cpufreq = get_bus_freq() / 2; - } of_node_put(np); + if (data && data->flags & SOC_BLACKLIST) + return -ENODEV; + ret = cpufreq_register_driver(&qoriq_cpufreq_driver); if (!ret) pr_info("Freescale QorIQ CPU frequency scaling driver\n"); --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -418,8 +418,12 @@ CPUIDLE_METHOD_OF_DECLARE(psci, "psci", static int psci_system_suspend(unsigned long unused) { - return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), - virt_to_phys(cpu_resume), 0, 0); + u32 state; + + state = ( 2 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | + (1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT); + + return psci_cpu_suspend(state, virt_to_phys(cpu_resume)); } static int psci_system_suspend_enter(suspend_state_t state) @@ -439,6 +443,8 @@ static void __init psci_init_system_susp if (!IS_ENABLED(CONFIG_SUSPEND)) return; + suspend_set_ops(&psci_suspend_ops); + ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND)); if (ret != PSCI_RET_NOT_SUPPORTED) @@ -516,6 +522,8 @@ static void __init psci_0_2_set_function arm_pm_restart = psci_sys_reset; pm_power_off = psci_sys_poweroff; + psci_init_system_suspend(); + suspend_set_ops(&psci_suspend_ops); } /*