aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch
diff options
context:
space:
mode:
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.patch370
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
+