summaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/qcom-cpufreq-hw.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-06 15:59:46 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-06 15:59:46 -0500
commitef8006846a3a97d9d8bf49e63dba948d0d2dbbf0 (patch)
tree5929135c14913ba7aebe538567d0550b80a61d73 /drivers/cpufreq/qcom-cpufreq-hw.c
parent8dcd175bc3d50b78413c56d5b17d4bddd77412ef (diff)
parent1271d6d576b7e7c80519de211f250cfd4eebca1a (diff)
Merge tag 'pm-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki: "These are PM-runtime framework changes to use ktime instead of jiffies for accounting, new PM core flag to mark devices that don't need any form of power management, cpuidle updates including driver API documentation and a new governor, cpufreq updates including a new driver for Armada 8K, thermal cleanups and more, some energy-aware scheduling (EAS) enabling changes, new chips support in the intel_idle and RAPL drivers and assorted cleanups in some other places. Specifics: - Update the PM-runtime framework to use ktime instead of jiffies for accounting (Thara Gopinath, Vincent Guittot) - Optimize the autosuspend code in the PM-runtime framework somewhat (Ladislav Michl) - Add a PM core flag to mark devices that don't need any form of power management (Sudeep Holla) - Introduce driver API documentation for cpuidle and add a new cpuidle governor for tickless systems (Rafael Wysocki) - Add Jacobsville support to the intel_idle driver (Zhang Rui) - Clean up a cpuidle core header file and the cpuidle-dt and ACPI processor-idle drivers (Yangtao Li, Joseph Lo, Yazen Ghannam) - Add new cpufreq driver for Armada 8K (Gregory Clement) - Fix and clean up cpufreq core (Rafael Wysocki, Viresh Kumar, Amit Kucheria) - Add support for light-weight tear-down and bring-up of CPUs to the cpufreq core and use it in the cpufreq-dt driver (Viresh Kumar) - Fix cpu_cooling Kconfig dependencies, add support for CPU cooling auto-registration to the cpufreq core and use it in multiple cpufreq drivers (Amit Kucheria) - Fix some minor issues and do some cleanups in the davinci, e_powersaver, ap806, s5pv210, qcom and kryo cpufreq drivers (Bartosz Golaszewski, Gustavo Silva, Julia Lawall, Paweł Chmiel, Taniya Das, Viresh Kumar) - Add a Hisilicon CPPC quirk to the cppc_cpufreq driver (Xiongfeng Wang) - Clean up the intel_pstate and acpi-cpufreq drivers (Erwan Velu, Rafael Wysocki) - Clean up multiple cpufreq drivers (Yangtao Li) - Update cpufreq-related MAINTAINERS entries (Baruch Siach, Lukas Bulwahn) - Add support for exposing the Energy Model via debugfs and make multiple cpufreq drivers register an Energy Model to support energy-aware scheduling (Quentin Perret, Dietmar Eggemann, Matthias Kaehlcke) - Add Ice Lake mobile and Jacobsville support to the Intel RAPL power-capping driver (Gayatri Kammela, Zhang Rui) - Add a power estimation helper to the operating performance points (OPP) framework and clean up a core function in it (Quentin Perret, Viresh Kumar) - Make minor improvements in the generic power domains (genpd), OPP and system suspend frameworks and in the PM core (Aditya Pakki, Douglas Anderson, Greg Kroah-Hartman, Rafael Wysocki, Yangtao Li)" * tag 'pm-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (80 commits) cpufreq: kryo: Release OPP tables on module removal cpufreq: ap806: add missing of_node_put after of_device_is_available cpufreq: acpi-cpufreq: Report if CPU doesn't support boost technologies cpufreq: Pass updated policy to driver ->setpolicy() callback cpufreq: Fix two debug messages in cpufreq_set_policy() cpufreq: Reorder and simplify cpufreq_update_policy() cpufreq: Add kerneldoc comments for two core functions PM / core: Add support to skip power management in device/driver model cpufreq: intel_pstate: Rework iowait boosting to be less aggressive cpufreq: intel_pstate: Eliminate intel_pstate_get_base_pstate() cpufreq: intel_pstate: Avoid redundant initialization of local vars powercap/intel_rapl: add Ice Lake mobile ACPI / processor: Set P_LVL{2,3} idle state descriptions cpufreq / cppc: Work around for Hisilicon CPPC cpufreq ACPI / CPPC: Add a helper to get desired performance cpufreq: davinci: move configuration to include/linux/platform_data cpufreq: speedstep: convert BUG() to BUG_ON() cpufreq: powernv: fix missing check of return value in init_powernv_pstates() cpufreq: longhaul: remove unneeded semicolon cpufreq: pcc-cpufreq: remove unneeded semicolon ..
Diffstat (limited to 'drivers/cpufreq/qcom-cpufreq-hw.c')
-rw-r--r--drivers/cpufreq/qcom-cpufreq-hw.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
index d83939a1b3d4..4b0b50403901 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -10,18 +10,21 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/of_address.h> 11#include <linux/of_address.h>
12#include <linux/of_platform.h> 12#include <linux/of_platform.h>
13#include <linux/pm_opp.h>
13#include <linux/slab.h> 14#include <linux/slab.h>
14 15
15#define LUT_MAX_ENTRIES 40U 16#define LUT_MAX_ENTRIES 40U
16#define LUT_SRC GENMASK(31, 30) 17#define LUT_SRC GENMASK(31, 30)
17#define LUT_L_VAL GENMASK(7, 0) 18#define LUT_L_VAL GENMASK(7, 0)
18#define LUT_CORE_COUNT GENMASK(18, 16) 19#define LUT_CORE_COUNT GENMASK(18, 16)
20#define LUT_VOLT GENMASK(11, 0)
19#define LUT_ROW_SIZE 32 21#define LUT_ROW_SIZE 32
20#define CLK_HW_DIV 2 22#define CLK_HW_DIV 2
21 23
22/* Register offsets */ 24/* Register offsets */
23#define REG_ENABLE 0x0 25#define REG_ENABLE 0x0
24#define REG_LUT_TABLE 0x110 26#define REG_FREQ_LUT 0x110
27#define REG_VOLT_LUT 0x114
25#define REG_PERF_STATE 0x920 28#define REG_PERF_STATE 0x920
26 29
27static unsigned long cpu_hw_rate, xo_rate; 30static unsigned long cpu_hw_rate, xo_rate;
@@ -70,11 +73,12 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
70 return policy->freq_table[index].frequency; 73 return policy->freq_table[index].frequency;
71} 74}
72 75
73static int qcom_cpufreq_hw_read_lut(struct device *dev, 76static int qcom_cpufreq_hw_read_lut(struct device *cpu_dev,
74 struct cpufreq_policy *policy, 77 struct cpufreq_policy *policy,
75 void __iomem *base) 78 void __iomem *base)
76{ 79{
77 u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq; 80 u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq;
81 u32 volt;
78 unsigned int max_cores = cpumask_weight(policy->cpus); 82 unsigned int max_cores = cpumask_weight(policy->cpus);
79 struct cpufreq_frequency_table *table; 83 struct cpufreq_frequency_table *table;
80 84
@@ -83,23 +87,28 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
83 return -ENOMEM; 87 return -ENOMEM;
84 88
85 for (i = 0; i < LUT_MAX_ENTRIES; i++) { 89 for (i = 0; i < LUT_MAX_ENTRIES; i++) {
86 data = readl_relaxed(base + REG_LUT_TABLE + i * LUT_ROW_SIZE); 90 data = readl_relaxed(base + REG_FREQ_LUT +
91 i * LUT_ROW_SIZE);
87 src = FIELD_GET(LUT_SRC, data); 92 src = FIELD_GET(LUT_SRC, data);
88 lval = FIELD_GET(LUT_L_VAL, data); 93 lval = FIELD_GET(LUT_L_VAL, data);
89 core_count = FIELD_GET(LUT_CORE_COUNT, data); 94 core_count = FIELD_GET(LUT_CORE_COUNT, data);
90 95
96 data = readl_relaxed(base + REG_VOLT_LUT +
97 i * LUT_ROW_SIZE);
98 volt = FIELD_GET(LUT_VOLT, data) * 1000;
99
91 if (src) 100 if (src)
92 freq = xo_rate * lval / 1000; 101 freq = xo_rate * lval / 1000;
93 else 102 else
94 freq = cpu_hw_rate / 1000; 103 freq = cpu_hw_rate / 1000;
95 104
96 /* Ignore boosts in the middle of the table */ 105 if (freq != prev_freq && core_count == max_cores) {
97 if (core_count != max_cores) {
98 table[i].frequency = CPUFREQ_ENTRY_INVALID;
99 } else {
100 table[i].frequency = freq; 106 table[i].frequency = freq;
101 dev_dbg(dev, "index=%d freq=%d, core_count %d\n", i, 107 dev_pm_opp_add(cpu_dev, freq * 1000, volt);
108 dev_dbg(cpu_dev, "index=%d freq=%d, core_count %d\n", i,
102 freq, core_count); 109 freq, core_count);
110 } else {
111 table[i].frequency = CPUFREQ_ENTRY_INVALID;
103 } 112 }
104 113
105 /* 114 /*
@@ -116,6 +125,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
116 if (prev_cc != max_cores) { 125 if (prev_cc != max_cores) {
117 prev->frequency = prev_freq; 126 prev->frequency = prev_freq;
118 prev->flags = CPUFREQ_BOOST_FREQ; 127 prev->flags = CPUFREQ_BOOST_FREQ;
128 dev_pm_opp_add(cpu_dev, prev_freq * 1000, volt);
119 } 129 }
120 130
121 break; 131 break;
@@ -127,6 +137,7 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
127 137
128 table[i].frequency = CPUFREQ_TABLE_END; 138 table[i].frequency = CPUFREQ_TABLE_END;
129 policy->freq_table = table; 139 policy->freq_table = table;
140 dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
130 141
131 return 0; 142 return 0;
132} 143}
@@ -159,10 +170,18 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
159 struct device *dev = &global_pdev->dev; 170 struct device *dev = &global_pdev->dev;
160 struct of_phandle_args args; 171 struct of_phandle_args args;
161 struct device_node *cpu_np; 172 struct device_node *cpu_np;
173 struct device *cpu_dev;
162 struct resource *res; 174 struct resource *res;
163 void __iomem *base; 175 void __iomem *base;
164 int ret, index; 176 int ret, index;
165 177
178 cpu_dev = get_cpu_device(policy->cpu);
179 if (!cpu_dev) {
180 pr_err("%s: failed to get cpu%d device\n", __func__,
181 policy->cpu);
182 return -ENODEV;
183 }
184
166 cpu_np = of_cpu_device_node_get(policy->cpu); 185 cpu_np = of_cpu_device_node_get(policy->cpu);
167 if (!cpu_np) 186 if (!cpu_np)
168 return -EINVAL; 187 return -EINVAL;
@@ -199,12 +218,21 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
199 218
200 policy->driver_data = base + REG_PERF_STATE; 219 policy->driver_data = base + REG_PERF_STATE;
201 220
202 ret = qcom_cpufreq_hw_read_lut(dev, policy, base); 221 ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy, base);
203 if (ret) { 222 if (ret) {
204 dev_err(dev, "Domain-%d failed to read LUT\n", index); 223 dev_err(dev, "Domain-%d failed to read LUT\n", index);
205 goto error; 224 goto error;
206 } 225 }
207 226
227 ret = dev_pm_opp_get_opp_count(cpu_dev);
228 if (ret <= 0) {
229 dev_err(cpu_dev, "Failed to add OPPs\n");
230 ret = -ENODEV;
231 goto error;
232 }
233
234 dev_pm_opp_of_register_em(policy->cpus);
235
208 policy->fast_switch_possible = true; 236 policy->fast_switch_possible = true;
209 237
210 return 0; 238 return 0;
@@ -215,8 +243,10 @@ error:
215 243
216static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy) 244static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
217{ 245{
246 struct device *cpu_dev = get_cpu_device(policy->cpu);
218 void __iomem *base = policy->driver_data - REG_PERF_STATE; 247 void __iomem *base = policy->driver_data - REG_PERF_STATE;
219 248
249 dev_pm_opp_remove_all_dynamic(cpu_dev);
220 kfree(policy->freq_table); 250 kfree(policy->freq_table);
221 devm_iounmap(&global_pdev->dev, base); 251 devm_iounmap(&global_pdev->dev, base);
222 252
@@ -231,7 +261,8 @@ static struct freq_attr *qcom_cpufreq_hw_attr[] = {
231 261
232static struct cpufreq_driver cpufreq_qcom_hw_driver = { 262static struct cpufreq_driver cpufreq_qcom_hw_driver = {
233 .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | 263 .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
234 CPUFREQ_HAVE_GOVERNOR_PER_POLICY, 264 CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
265 CPUFREQ_IS_COOLING_DEV,
235 .verify = cpufreq_generic_frequency_table_verify, 266 .verify = cpufreq_generic_frequency_table_verify,
236 .target_index = qcom_cpufreq_hw_target_index, 267 .target_index = qcom_cpufreq_hw_target_index,
237 .get = qcom_cpufreq_hw_get, 268 .get = qcom_cpufreq_hw_get,
@@ -296,7 +327,7 @@ static int __init qcom_cpufreq_hw_init(void)
296{ 327{
297 return platform_driver_register(&qcom_cpufreq_hw_driver); 328 return platform_driver_register(&qcom_cpufreq_hw_driver);
298} 329}
299subsys_initcall(qcom_cpufreq_hw_init); 330device_initcall(qcom_cpufreq_hw_init);
300 331
301static void __exit qcom_cpufreq_hw_exit(void) 332static void __exit qcom_cpufreq_hw_exit(void)
302{ 333{