diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch b/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch new file mode 100644 index 0000000000..9ea5c407dd --- /dev/null +++ b/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch @@ -0,0 +1,370 @@ +From a9ebdf9fa18fd317a4e97f46e8c5263898094864 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu <yangbo.lu@nxp.com> +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 <Yuantian.Tang@nxp.com> +Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +--- + drivers/cpufreq/Kconfig | 2 +- + drivers/cpufreq/qoriq-cpufreq.c | 176 +++++++++++++++------------------------- + drivers/firmware/psci.c | 12 ++- + 3 files changed, 77 insertions(+), 113 deletions(-) + +diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig +index d8b164a7..bc9264c7 100644 +--- 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 +diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c +index 53d8c3fb..e2ea433a 100644 +--- a/drivers/cpufreq/qoriq-cpufreq.c ++++ b/drivers/cpufreq/qoriq-cpufreq.c +@@ -11,6 +11,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include <linux/clk.h> ++#include <linux/clk-provider.h> + #include <linux/cpufreq.h> + #include <linux/cpu_cooling.h> + #include <linux/errno.h> +@@ -22,10 +23,6 @@ + #include <linux/slab.h> + #include <linux/smp.h> + +-#if !defined(CONFIG_ARM) +-#include <asm/smp.h> /* 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_node(int cpu) + 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 cpufreq_frequency_table *freq_table, + + 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 cpufreq_policy *policy) + 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 cpufreq_policy *policy) + 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 cpufreq_policy *policy) + policy->cpuinfo.transition_latency = u64temp + 1; + + of_node_put(np); +- of_node_put(pnode); + + return 0; + +@@ -290,10 +240,7 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) + 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_cpufreq_driver = { + .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(void) + + 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"); +diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c +index 8263429e..323c9fc0 100644 +--- a/drivers/firmware/psci.c ++++ b/drivers/firmware/psci.c +@@ -418,8 +418,12 @@ CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops); + + 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_suspend(void) + 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_functions(void) + arm_pm_restart = psci_sys_reset; + + pm_power_off = psci_sys_poweroff; ++ psci_init_system_suspend(); ++ suspend_set_ops(&psci_suspend_ops); + } + + /* +-- +2.14.1 + |