Commit | Line | Data |
---|---|---|
02361418 ADK |
1 | /* |
2 | * linux/drivers/thermal/cpu_cooling.c | |
3 | * | |
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) | |
5 | * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> | |
6 | * | |
73904cbc VK |
7 | * Copyright (C) 2014 Viresh Kumar <viresh.kumar@linaro.org> |
8 | * | |
02361418 ADK |
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; version 2 of the License. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | |
21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
22 | * | |
23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
24 | */ | |
02361418 ADK |
25 | #include <linux/module.h> |
26 | #include <linux/thermal.h> | |
02361418 ADK |
27 | #include <linux/cpufreq.h> |
28 | #include <linux/err.h> | |
c36cf071 | 29 | #include <linux/pm_opp.h> |
02361418 ADK |
30 | #include <linux/slab.h> |
31 | #include <linux/cpu.h> | |
32 | #include <linux/cpu_cooling.h> | |
1cac41cb | 33 | #include <linux/exynos-ss.h> |
02361418 | 34 | |
6828a471 JM |
35 | #include <trace/events/thermal.h> |
36 | ||
1cac41cb MB |
37 | #include <soc/samsung/tmu.h> |
38 | #include <soc/samsung/cal-if.h> | |
39 | #include <soc/samsung/ect_parser.h> | |
40 | ||
41 | #if defined(CONFIG_SOC_EXYNOS8895) && defined(CONFIG_SOC_EMULATOR8895) | |
42 | #include <dt-bindings/clock/emulator8895.h> | |
43 | #elif defined(CONFIG_SOC_EXYNOS8895) && !defined(CONFIG_SOC_EMULATOR8895) | |
44 | #include <dt-bindings/clock/exynos8895.h> | |
45 | #endif | |
46 | ||
07d888d8 VK |
47 | /* |
48 | * Cooling state <-> CPUFreq frequency | |
49 | * | |
50 | * Cooling states are translated to frequencies throughout this driver and this | |
51 | * is the relation between them. | |
52 | * | |
53 | * Highest cooling state corresponds to lowest possible frequency. | |
54 | * | |
55 | * i.e. | |
56 | * level 0 --> 1st Max Freq | |
57 | * level 1 --> 2nd Max Freq | |
58 | * ... | |
59 | */ | |
60 | ||
c36cf071 JM |
61 | /** |
62 | * struct power_table - frequency to power conversion | |
63 | * @frequency: frequency in KHz | |
64 | * @power: power in mW | |
65 | * | |
66 | * This structure is built when the cooling device registers and helps | |
67 | * in translating frequency to power and viceversa. | |
68 | */ | |
69 | struct power_table { | |
70 | u32 frequency; | |
71 | u32 power; | |
72 | }; | |
73 | ||
02361418 | 74 | static DEFINE_IDR(cpufreq_idr); |
160b7d80 | 75 | static DEFINE_MUTEX(cooling_cpufreq_lock); |
02361418 | 76 | |
02373d7c RK |
77 | static unsigned int cpufreq_dev_count; |
78 | ||
79 | static DEFINE_MUTEX(cooling_list_lock); | |
2dcd851f | 80 | static LIST_HEAD(cpufreq_dev_list); |
02361418 | 81 | |
1cac41cb MB |
82 | static BLOCKING_NOTIFIER_HEAD(cpu_notifier); |
83 | ||
84 | static enum tmu_noti_state_t cpu_tstate = TMU_NORMAL; | |
85 | ||
02361418 ADK |
86 | /** |
87 | * get_idr - function to get a unique id. | |
88 | * @idr: struct idr * handle used to create a id. | |
89 | * @id: int * value generated by this function. | |
79491e53 EV |
90 | * |
91 | * This function will populate @id with an unique | |
92 | * id, using the idr API. | |
93 | * | |
94 | * Return: 0 on success, an error code on failure. | |
02361418 ADK |
95 | */ |
96 | static int get_idr(struct idr *idr, int *id) | |
97 | { | |
6deb69fa | 98 | int ret; |
02361418 ADK |
99 | |
100 | mutex_lock(&cooling_cpufreq_lock); | |
6deb69fa | 101 | ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL); |
02361418 | 102 | mutex_unlock(&cooling_cpufreq_lock); |
6deb69fa TH |
103 | if (unlikely(ret < 0)) |
104 | return ret; | |
105 | *id = ret; | |
79491e53 | 106 | |
02361418 ADK |
107 | return 0; |
108 | } | |
109 | ||
110 | /** | |
111 | * release_idr - function to free the unique id. | |
112 | * @idr: struct idr * handle used for creating the id. | |
113 | * @id: int value representing the unique id. | |
114 | */ | |
115 | static void release_idr(struct idr *idr, int id) | |
116 | { | |
117 | mutex_lock(&cooling_cpufreq_lock); | |
118 | idr_remove(idr, id); | |
119 | mutex_unlock(&cooling_cpufreq_lock); | |
120 | } | |
121 | ||
122 | /* Below code defines functions to be used for cpufreq as cooling device */ | |
123 | ||
124 | /** | |
4843c4a1 | 125 | * get_level: Find the level for a particular frequency |
b9f8b416 | 126 | * @cpufreq_dev: cpufreq_dev for which the property is required |
4843c4a1 | 127 | * @freq: Frequency |
82b9ee40 | 128 | * |
4843c4a1 | 129 | * Return: level on success, THERMAL_CSTATE_INVALID on error. |
02361418 | 130 | */ |
4843c4a1 VK |
131 | static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, |
132 | unsigned int freq) | |
02361418 | 133 | { |
4843c4a1 | 134 | unsigned long level; |
a116776f | 135 | |
4843c4a1 VK |
136 | for (level = 0; level <= cpufreq_dev->max_level; level++) { |
137 | if (freq == cpufreq_dev->freq_table[level]) | |
138 | return level; | |
02361418 | 139 | |
4843c4a1 VK |
140 | if (freq > cpufreq_dev->freq_table[level]) |
141 | break; | |
fc35b35c | 142 | } |
02361418 | 143 | |
4843c4a1 | 144 | return THERMAL_CSTATE_INVALID; |
fc35b35c ZR |
145 | } |
146 | ||
44952d33 | 147 | /** |
728c03c9 | 148 | * cpufreq_cooling_get_level - for a given cpu, return the cooling level. |
44952d33 EV |
149 | * @cpu: cpu for which the level is required |
150 | * @freq: the frequency of interest | |
151 | * | |
152 | * This function will match the cooling level corresponding to the | |
153 | * requested @freq and return it. | |
154 | * | |
155 | * Return: The matched cooling level on success or THERMAL_CSTATE_INVALID | |
156 | * otherwise. | |
157 | */ | |
57df8106 ZR |
158 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) |
159 | { | |
b9f8b416 | 160 | struct cpufreq_cooling_device *cpufreq_dev; |
02361418 | 161 | |
02373d7c | 162 | mutex_lock(&cooling_list_lock); |
b9f8b416 VK |
163 | list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { |
164 | if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { | |
2c1ac372 VK |
165 | unsigned long level = get_level(cpufreq_dev, freq); |
166 | ||
02373d7c | 167 | mutex_unlock(&cooling_list_lock); |
2c1ac372 | 168 | return level; |
b9f8b416 | 169 | } |
02361418 | 170 | } |
02373d7c | 171 | mutex_unlock(&cooling_list_lock); |
02361418 | 172 | |
b9f8b416 VK |
173 | pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); |
174 | return THERMAL_CSTATE_INVALID; | |
02361418 | 175 | } |
243dbd9c | 176 | EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); |
02361418 ADK |
177 | |
178 | /** | |
179 | * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. | |
180 | * @nb: struct notifier_block * with callback info. | |
181 | * @event: value showing cpufreq event for which this function invoked. | |
182 | * @data: callback-specific data | |
bab30554 | 183 | * |
9746b6e7 | 184 | * Callback to hijack the notification on cpufreq policy transition. |
bab30554 EV |
185 | * Every time there is a change in policy, we will intercept and |
186 | * update the cpufreq policy with thermal constraints. | |
187 | * | |
188 | * Return: 0 (success) | |
02361418 ADK |
189 | */ |
190 | static int cpufreq_thermal_notifier(struct notifier_block *nb, | |
5fda7f68 | 191 | unsigned long event, void *data) |
02361418 ADK |
192 | { |
193 | struct cpufreq_policy *policy = data; | |
abcbcc25 | 194 | unsigned long clipped_freq; |
2dcd851f | 195 | struct cpufreq_cooling_device *cpufreq_dev; |
02361418 | 196 | |
a24af233 VK |
197 | if (event != CPUFREQ_ADJUST) |
198 | return NOTIFY_DONE; | |
02361418 | 199 | |
a24af233 VK |
200 | mutex_lock(&cooling_list_lock); |
201 | list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { | |
202 | if (!cpumask_test_cpu(policy->cpu, &cpufreq_dev->allowed_cpus)) | |
203 | continue; | |
c36cf071 | 204 | |
1afb9c53 VK |
205 | /* |
206 | * policy->max is the maximum allowed frequency defined by user | |
207 | * and clipped_freq is the maximum that thermal constraints | |
208 | * allow. | |
209 | * | |
210 | * If clipped_freq is lower than policy->max, then we need to | |
211 | * readjust policy->max. | |
212 | * | |
213 | * But, if clipped_freq is greater than policy->max, we don't | |
214 | * need to do anything. | |
215 | */ | |
abcbcc25 | 216 | clipped_freq = cpufreq_dev->clipped_freq; |
c36cf071 | 217 | |
1cac41cb | 218 | if (policy->max > clipped_freq) { |
abcbcc25 | 219 | cpufreq_verify_within_limits(policy, 0, clipped_freq); |
1cac41cb MB |
220 | exynos_ss_thermal(NULL, 0, cpufreq_dev->cool_dev->type, clipped_freq); |
221 | } | |
c36cf071 | 222 | break; |
c36cf071 | 223 | } |
a24af233 | 224 | mutex_unlock(&cooling_list_lock); |
c36cf071 JM |
225 | |
226 | return NOTIFY_OK; | |
227 | } | |
228 | ||
229 | /** | |
230 | * build_dyn_power_table() - create a dynamic power to frequency table | |
231 | * @cpufreq_device: the cpufreq cooling device in which to store the table | |
232 | * @capacitance: dynamic power coefficient for these cpus | |
233 | * | |
234 | * Build a dynamic power to frequency table for this cpu and store it | |
235 | * in @cpufreq_device. This table will be used in cpu_power_to_freq() and | |
236 | * cpu_freq_to_power() to convert between power and frequency | |
237 | * efficiently. Power is stored in mW, frequency in KHz. The | |
238 | * resulting table is in ascending order. | |
239 | * | |
459ac375 JM |
240 | * Return: 0 on success, -EINVAL if there are no OPPs for any CPUs, |
241 | * -ENOMEM if we run out of memory or -EAGAIN if an OPP was | |
242 | * added/enabled while the function was executing. | |
c36cf071 JM |
243 | */ |
244 | static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, | |
245 | u32 capacitance) | |
246 | { | |
247 | struct power_table *power_table; | |
248 | struct dev_pm_opp *opp; | |
249 | struct device *dev = NULL; | |
eba4f88d | 250 | int num_opps = 0, cpu, i, ret = 0; |
c36cf071 JM |
251 | unsigned long freq; |
252 | ||
c36cf071 JM |
253 | for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { |
254 | dev = get_cpu_device(cpu); | |
255 | if (!dev) { | |
256 | dev_warn(&cpufreq_device->cool_dev->device, | |
257 | "No cpu device for cpu %d\n", cpu); | |
2dcd851f | 258 | continue; |
c36cf071 | 259 | } |
2dcd851f | 260 | |
c36cf071 | 261 | num_opps = dev_pm_opp_get_opp_count(dev); |
459ac375 | 262 | if (num_opps > 0) |
c36cf071 | 263 | break; |
459ac375 JM |
264 | else if (num_opps < 0) |
265 | return num_opps; | |
c36cf071 | 266 | } |
02361418 | 267 | |
459ac375 JM |
268 | if (num_opps == 0) |
269 | return -EINVAL; | |
02361418 | 270 | |
c36cf071 | 271 | power_table = kcalloc(num_opps, sizeof(*power_table), GFP_KERNEL); |
459ac375 JM |
272 | if (!power_table) |
273 | return -ENOMEM; | |
274 | ||
275 | rcu_read_lock(); | |
c36cf071 JM |
276 | |
277 | for (freq = 0, i = 0; | |
278 | opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp); | |
279 | freq++, i++) { | |
280 | u32 freq_mhz, voltage_mv; | |
281 | u64 power; | |
282 | ||
459ac375 JM |
283 | if (i >= num_opps) { |
284 | rcu_read_unlock(); | |
eba4f88d JM |
285 | ret = -EAGAIN; |
286 | goto free_power_table; | |
459ac375 JM |
287 | } |
288 | ||
c36cf071 JM |
289 | freq_mhz = freq / 1000000; |
290 | voltage_mv = dev_pm_opp_get_voltage(opp) / 1000; | |
291 | ||
292 | /* | |
293 | * Do the multiplication with MHz and millivolt so as | |
294 | * to not overflow. | |
295 | */ | |
296 | power = (u64)capacitance * freq_mhz * voltage_mv * voltage_mv; | |
297 | do_div(power, 1000000000); | |
298 | ||
299 | /* frequency is stored in power_table in KHz */ | |
300 | power_table[i].frequency = freq / 1000; | |
301 | ||
302 | /* power is stored in mW */ | |
303 | power_table[i].power = power; | |
304 | } | |
305 | ||
459ac375 JM |
306 | rcu_read_unlock(); |
307 | ||
eba4f88d JM |
308 | if (i != num_opps) { |
309 | ret = PTR_ERR(opp); | |
310 | goto free_power_table; | |
311 | } | |
c36cf071 JM |
312 | |
313 | cpufreq_device->cpu_dev = dev; | |
314 | cpufreq_device->dyn_power_table = power_table; | |
315 | cpufreq_device->dyn_power_table_entries = i; | |
316 | ||
459ac375 | 317 | return 0; |
eba4f88d JM |
318 | |
319 | free_power_table: | |
320 | kfree(power_table); | |
321 | ||
322 | return ret; | |
c36cf071 JM |
323 | } |
324 | ||
1cac41cb MB |
325 | static int build_static_power_table(struct cpufreq_cooling_device *cpufreq_device) |
326 | { | |
327 | int i, j; | |
328 | int ratio = cal_asv_get_ids_info(ACPM_DVFS_CPUCL0); | |
329 | int asv_group = cal_asv_get_grp(ACPM_DVFS_CPUCL0); | |
330 | void *gen_block; | |
331 | struct ect_gen_param_table *volt_temp_param, *asv_param; | |
332 | int ratio_table[16] = { 0, 18, 22, 27, 33, 40, 49, 60, 73, 89, 108, 131, 159, 194, 232, 250}; | |
333 | ||
334 | if (asv_group < 0 || asv_group > 15) | |
335 | asv_group = 0; | |
336 | ||
337 | if (!ratio) | |
338 | ratio = ratio_table[asv_group]; | |
339 | ||
340 | gen_block = ect_get_block("GEN"); | |
341 | if (gen_block == NULL) { | |
342 | pr_err("%s: Failed to get gen block from ECT\n", __func__); | |
343 | return -EINVAL; | |
344 | } | |
345 | ||
346 | volt_temp_param = ect_gen_param_get_table(gen_block, "DTM_MNGS_VOLT_TEMP"); | |
347 | asv_param = ect_gen_param_get_table(gen_block, "DTM_MNGS_ASV"); | |
348 | ||
349 | if (volt_temp_param && asv_param) { | |
350 | cpufreq_device->var_volt_size = volt_temp_param->num_of_row - 1; | |
351 | cpufreq_device->var_temp_size = volt_temp_param->num_of_col - 1; | |
352 | ||
353 | cpufreq_device->var_coeff = kzalloc(sizeof(int) * | |
354 | volt_temp_param->num_of_row * | |
355 | volt_temp_param->num_of_col, | |
356 | GFP_KERNEL); | |
357 | if (!cpufreq_device->var_coeff) | |
358 | goto err_mem; | |
359 | ||
360 | cpufreq_device->asv_coeff = kzalloc(sizeof(int) * | |
361 | asv_param->num_of_row * | |
362 | asv_param->num_of_col, | |
363 | GFP_KERNEL); | |
364 | if (!cpufreq_device->asv_coeff) | |
365 | goto free_var_coeff; | |
366 | ||
367 | cpufreq_device->var_table = kzalloc(sizeof(int) * | |
368 | volt_temp_param->num_of_row * | |
369 | volt_temp_param->num_of_col, | |
370 | GFP_KERNEL); | |
371 | if (!cpufreq_device->var_table) | |
372 | goto free_asv_coeff; | |
373 | ||
374 | memcpy(cpufreq_device->var_coeff, volt_temp_param->parameter, | |
375 | sizeof(int) * volt_temp_param->num_of_row * volt_temp_param->num_of_col); | |
376 | memcpy(cpufreq_device->asv_coeff, asv_param->parameter, | |
377 | sizeof(int) * asv_param->num_of_row * asv_param->num_of_col); | |
378 | memcpy(cpufreq_device->var_table, volt_temp_param->parameter, | |
379 | sizeof(int) * volt_temp_param->num_of_row * volt_temp_param->num_of_col); | |
380 | } else { | |
381 | pr_err("%s: Failed to get param table from ECT\n", __func__); | |
382 | return -EINVAL; | |
383 | } | |
384 | ||
385 | for (i = 1; i <= cpufreq_device->var_volt_size; i++) { | |
386 | long asv_coeff = (long)cpufreq_device->asv_coeff[3 * i + 0] * asv_group * asv_group | |
387 | + (long)cpufreq_device->asv_coeff[3 * i + 1] * asv_group | |
388 | + (long)cpufreq_device->asv_coeff[3 * i + 2]; | |
389 | asv_coeff = asv_coeff / 100; | |
390 | ||
391 | for (j = 1; j <= cpufreq_device->var_temp_size; j++) { | |
392 | long var_coeff = (long)cpufreq_device->var_coeff[i * (cpufreq_device->var_temp_size + 1) + j]; | |
393 | var_coeff = ratio * var_coeff * asv_coeff; | |
394 | var_coeff = var_coeff / 100000; | |
395 | cpufreq_device->var_table[i * (cpufreq_device->var_temp_size + 1) + j] = (int)var_coeff; | |
396 | } | |
397 | } | |
398 | ||
399 | return 0; | |
400 | ||
401 | free_asv_coeff: | |
402 | kfree(cpufreq_device->asv_coeff); | |
403 | free_var_coeff: | |
404 | kfree(cpufreq_device->var_coeff); | |
405 | err_mem: | |
406 | return -ENOMEM; | |
407 | } | |
408 | ||
409 | static int lookup_static_power(struct cpufreq_cooling_device *cpufreq_device, | |
410 | unsigned long voltage, int temperature, u32 *power) | |
411 | { | |
412 | int volt_index = 0, temp_index = 0; | |
413 | int index = 0; | |
414 | int num_cpus; | |
415 | int max_cpus; | |
416 | struct cpumask *cpumask = &cpufreq_device->allowed_cpus; | |
417 | cpumask_t tempmask; | |
418 | ||
419 | cpumask_and(&tempmask, cpumask, cpu_online_mask); | |
420 | max_cpus = cpumask_weight(cpumask); | |
421 | num_cpus = cpumask_weight(&tempmask); | |
422 | voltage = voltage / 1000; | |
423 | temperature = temperature / 1000; | |
424 | ||
425 | for (volt_index = 0; volt_index <= cpufreq_device->var_volt_size; volt_index++) { | |
426 | if (voltage < cpufreq_device->var_table[volt_index * (cpufreq_device->var_temp_size + 1)]) { | |
427 | volt_index = volt_index - 1; | |
428 | break; | |
429 | } | |
430 | } | |
431 | ||
432 | if (volt_index == 0) | |
433 | volt_index = 1; | |
434 | ||
435 | if (volt_index > cpufreq_device->var_volt_size) | |
436 | volt_index = cpufreq_device->var_volt_size; | |
437 | ||
438 | for (temp_index = 0; temp_index <= cpufreq_device->var_temp_size; temp_index++) { | |
439 | if (temperature < cpufreq_device->var_table[temp_index]) { | |
440 | temp_index = temp_index - 1; | |
441 | break; | |
442 | } | |
443 | } | |
444 | ||
445 | if (temp_index == 0) | |
446 | temp_index = 1; | |
447 | ||
448 | if (temp_index > cpufreq_device->var_temp_size) | |
449 | temp_index = cpufreq_device->var_temp_size; | |
450 | ||
451 | index = (int)(volt_index * (cpufreq_device->var_temp_size + 1) + temp_index); | |
452 | *power = (unsigned int)cpufreq_device->var_table[index] * num_cpus / max_cpus; | |
453 | ||
454 | return 0; | |
455 | } | |
456 | ||
c36cf071 JM |
457 | static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_device, |
458 | u32 freq) | |
459 | { | |
460 | int i; | |
461 | struct power_table *pt = cpufreq_device->dyn_power_table; | |
462 | ||
463 | for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++) | |
464 | if (freq < pt[i].frequency) | |
465 | break; | |
466 | ||
467 | return pt[i - 1].power; | |
468 | } | |
469 | ||
470 | static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device, | |
471 | u32 power) | |
472 | { | |
473 | int i; | |
474 | struct power_table *pt = cpufreq_device->dyn_power_table; | |
475 | ||
476 | for (i = 1; i < cpufreq_device->dyn_power_table_entries; i++) | |
477 | if (power < pt[i].power) | |
478 | break; | |
479 | ||
480 | return pt[i - 1].frequency; | |
481 | } | |
482 | ||
483 | /** | |
484 | * get_load() - get load for a cpu since last updated | |
485 | * @cpufreq_device: &struct cpufreq_cooling_device for this cpu | |
486 | * @cpu: cpu number | |
e6f54e7f | 487 | * @cpu_idx: index of the cpu in cpufreq_device->allowed_cpus |
c36cf071 JM |
488 | * |
489 | * Return: The average load of cpu @cpu in percentage since this | |
490 | * function was last called. | |
491 | */ | |
e6f54e7f JM |
492 | static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu, |
493 | int cpu_idx) | |
c36cf071 JM |
494 | { |
495 | u32 load; | |
496 | u64 now, now_idle, delta_time, delta_idle; | |
497 | ||
498 | now_idle = get_cpu_idle_time(cpu, &now, 0); | |
e6f54e7f JM |
499 | delta_idle = now_idle - cpufreq_device->time_in_idle[cpu_idx]; |
500 | delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu_idx]; | |
c36cf071 JM |
501 | |
502 | if (delta_time <= delta_idle) | |
503 | load = 0; | |
504 | else | |
505 | load = div64_u64(100 * (delta_time - delta_idle), delta_time); | |
506 | ||
e6f54e7f JM |
507 | cpufreq_device->time_in_idle[cpu_idx] = now_idle; |
508 | cpufreq_device->time_in_idle_timestamp[cpu_idx] = now; | |
c36cf071 JM |
509 | |
510 | return load; | |
511 | } | |
512 | ||
513 | /** | |
514 | * get_static_power() - calculate the static power consumed by the cpus | |
515 | * @cpufreq_device: struct &cpufreq_cooling_device for this cpu cdev | |
516 | * @tz: thermal zone device in which we're operating | |
517 | * @freq: frequency in KHz | |
518 | * @power: pointer in which to store the calculated static power | |
519 | * | |
520 | * Calculate the static power consumed by the cpus described by | |
521 | * @cpu_actor running at frequency @freq. This function relies on a | |
522 | * platform specific function that should have been provided when the | |
523 | * actor was registered. If it wasn't, the static power is assumed to | |
524 | * be negligible. The calculated static power is stored in @power. | |
525 | * | |
526 | * Return: 0 on success, -E* on failure. | |
527 | */ | |
528 | static int get_static_power(struct cpufreq_cooling_device *cpufreq_device, | |
529 | struct thermal_zone_device *tz, unsigned long freq, | |
530 | u32 *power) | |
531 | { | |
532 | struct dev_pm_opp *opp; | |
533 | unsigned long voltage; | |
c36cf071 JM |
534 | unsigned long freq_hz = freq * 1000; |
535 | ||
1cac41cb | 536 | if (!cpufreq_device->cpu_dev) { |
c36cf071 JM |
537 | *power = 0; |
538 | return 0; | |
539 | } | |
540 | ||
541 | rcu_read_lock(); | |
542 | ||
543 | opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz, | |
544 | true); | |
545 | voltage = dev_pm_opp_get_voltage(opp); | |
546 | ||
547 | rcu_read_unlock(); | |
548 | ||
549 | if (voltage == 0) { | |
550 | dev_warn_ratelimited(cpufreq_device->cpu_dev, | |
551 | "Failed to get voltage for frequency %lu: %ld\n", | |
552 | freq_hz, IS_ERR(opp) ? PTR_ERR(opp) : 0); | |
553 | return -EINVAL; | |
554 | } | |
555 | ||
1cac41cb | 556 | return lookup_static_power(cpufreq_device, voltage, tz->temperature, power); |
c36cf071 JM |
557 | } |
558 | ||
559 | /** | |
560 | * get_dynamic_power() - calculate the dynamic power | |
561 | * @cpufreq_device: &cpufreq_cooling_device for this cdev | |
562 | * @freq: current frequency | |
563 | * | |
564 | * Return: the dynamic power consumed by the cpus described by | |
565 | * @cpufreq_device. | |
566 | */ | |
567 | static u32 get_dynamic_power(struct cpufreq_cooling_device *cpufreq_device, | |
568 | unsigned long freq) | |
569 | { | |
570 | u32 raw_cpu_power; | |
571 | ||
572 | raw_cpu_power = cpu_freq_to_power(cpufreq_device, freq); | |
573 | return (raw_cpu_power * cpufreq_device->last_load) / 100; | |
02361418 ADK |
574 | } |
575 | ||
1b9e3526 | 576 | /* cpufreq cooling device callback functions are defined below */ |
02361418 ADK |
577 | |
578 | /** | |
579 | * cpufreq_get_max_state - callback function to get the max cooling state. | |
580 | * @cdev: thermal cooling device pointer. | |
581 | * @state: fill this variable with the max cooling state. | |
62c00421 EV |
582 | * |
583 | * Callback for the thermal cooling device to return the cpufreq | |
584 | * max cooling state. | |
585 | * | |
586 | * Return: 0 on success, an error code otherwise. | |
02361418 ADK |
587 | */ |
588 | static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, | |
589 | unsigned long *state) | |
590 | { | |
160b7d80 | 591 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
9c51b05a | 592 | |
dcc6c7fd VK |
593 | *state = cpufreq_device->max_level; |
594 | return 0; | |
02361418 ADK |
595 | } |
596 | ||
597 | /** | |
598 | * cpufreq_get_cur_state - callback function to get the current cooling state. | |
599 | * @cdev: thermal cooling device pointer. | |
600 | * @state: fill this variable with the current cooling state. | |
3672552d EV |
601 | * |
602 | * Callback for the thermal cooling device to return the cpufreq | |
603 | * current cooling state. | |
604 | * | |
605 | * Return: 0 on success, an error code otherwise. | |
02361418 ADK |
606 | */ |
607 | static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, | |
608 | unsigned long *state) | |
609 | { | |
160b7d80 | 610 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
02361418 | 611 | |
160b7d80 | 612 | *state = cpufreq_device->cpufreq_state; |
79491e53 | 613 | |
160b7d80 | 614 | return 0; |
02361418 ADK |
615 | } |
616 | ||
617 | /** | |
618 | * cpufreq_set_cur_state - callback function to set the current cooling state. | |
619 | * @cdev: thermal cooling device pointer. | |
620 | * @state: set this variable to the current cooling state. | |
56e05fdb EV |
621 | * |
622 | * Callback for the thermal cooling device to change the cpufreq | |
623 | * current cooling state. | |
624 | * | |
625 | * Return: 0 on success, an error code otherwise. | |
02361418 | 626 | */ |
1cac41cb MB |
627 | #if defined(CONFIG_SEC_DEBUG_HW_PARAM) |
628 | static u64 last_time[THERMAL_ZONE_MAX], curr_time[THERMAL_ZONE_MAX]; | |
629 | extern struct thermal_data_devices thermal_data_info[THERMAL_ZONE_MAX]; | |
630 | #endif | |
631 | ||
02361418 ADK |
632 | static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, |
633 | unsigned long state) | |
634 | { | |
160b7d80 | 635 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
5194fe46 VK |
636 | unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); |
637 | unsigned int clip_freq; | |
1cac41cb MB |
638 | #if defined(CONFIG_SEC_DEBUG_HW_PARAM) |
639 | int tid = cdev->id; | |
640 | #endif | |
4843c4a1 VK |
641 | |
642 | /* Request state should be less than max_level */ | |
643 | if (WARN_ON(state > cpufreq_device->max_level)) | |
644 | return -EINVAL; | |
5194fe46 VK |
645 | |
646 | /* Check if the old cooling action is same as new cooling action */ | |
647 | if (cpufreq_device->cpufreq_state == state) | |
648 | return 0; | |
02361418 | 649 | |
4843c4a1 | 650 | clip_freq = cpufreq_device->freq_table[state]; |
5194fe46 | 651 | cpufreq_device->cpufreq_state = state; |
59f0d218 | 652 | cpufreq_device->clipped_freq = clip_freq; |
5194fe46 | 653 | |
1cac41cb MB |
654 | #if defined(CONFIG_SEC_DEBUG_HW_PARAM) |
655 | curr_time[tid] = ktime_to_ns(ktime_get()) / 1000000; | |
656 | if (last_time[tid]) { | |
657 | thermal_data_info[tid].freq_level[state] += | |
658 | curr_time[tid] - last_time[tid]; | |
659 | } | |
660 | last_time[tid] = curr_time[tid]; | |
661 | thermal_data_info[tid].max_level = cpufreq_device->max_level; | |
662 | #endif | |
663 | ||
5194fe46 VK |
664 | cpufreq_update_policy(cpu); |
665 | ||
666 | return 0; | |
02361418 ADK |
667 | } |
668 | ||
c36cf071 JM |
669 | /** |
670 | * cpufreq_get_requested_power() - get the current power | |
671 | * @cdev: &thermal_cooling_device pointer | |
672 | * @tz: a valid thermal zone device pointer | |
673 | * @power: pointer in which to store the resulting power | |
674 | * | |
675 | * Calculate the current power consumption of the cpus in milliwatts | |
676 | * and store it in @power. This function should actually calculate | |
677 | * the requested power, but it's hard to get the frequency that | |
678 | * cpufreq would have assigned if there were no thermal limits. | |
679 | * Instead, we calculate the current power on the assumption that the | |
680 | * immediate future will look like the immediate past. | |
681 | * | |
682 | * We use the current frequency and the average load since this | |
683 | * function was last called. In reality, there could have been | |
684 | * multiple opps since this function was last called and that affects | |
685 | * the load calculation. While it's not perfectly accurate, this | |
686 | * simplification is good enough and works. REVISIT this, as more | |
687 | * complex code may be needed if experiments show that it's not | |
688 | * accurate enough. | |
689 | * | |
690 | * Return: 0 on success, -E* if getting the static power failed. | |
691 | */ | |
692 | static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, | |
693 | struct thermal_zone_device *tz, | |
694 | u32 *power) | |
695 | { | |
696 | unsigned long freq; | |
6828a471 | 697 | int i = 0, cpu, ret; |
c36cf071 JM |
698 | u32 static_power, dynamic_power, total_load = 0; |
699 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; | |
6828a471 | 700 | u32 *load_cpu = NULL; |
c36cf071 | 701 | |
dd658e02 KS |
702 | cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask); |
703 | ||
704 | /* | |
705 | * All the CPUs are offline, thus the requested power by | |
706 | * the cdev is 0 | |
707 | */ | |
708 | if (cpu >= nr_cpu_ids) { | |
709 | *power = 0; | |
710 | return 0; | |
711 | } | |
712 | ||
713 | freq = cpufreq_quick_get(cpu); | |
c36cf071 | 714 | |
1cac41cb MB |
715 | if (freq == 0) { |
716 | *power = 0; | |
717 | return 0; | |
718 | } | |
719 | ||
6828a471 JM |
720 | if (trace_thermal_power_cpu_get_power_enabled()) { |
721 | u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus); | |
722 | ||
a71544cd | 723 | load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL); |
6828a471 JM |
724 | } |
725 | ||
c36cf071 JM |
726 | for_each_cpu(cpu, &cpufreq_device->allowed_cpus) { |
727 | u32 load; | |
728 | ||
729 | if (cpu_online(cpu)) | |
e6f54e7f | 730 | load = get_load(cpufreq_device, cpu, i); |
c36cf071 JM |
731 | else |
732 | load = 0; | |
733 | ||
734 | total_load += load; | |
6828a471 JM |
735 | if (trace_thermal_power_cpu_limit_enabled() && load_cpu) |
736 | load_cpu[i] = load; | |
737 | ||
738 | i++; | |
c36cf071 JM |
739 | } |
740 | ||
741 | cpufreq_device->last_load = total_load; | |
742 | ||
743 | dynamic_power = get_dynamic_power(cpufreq_device, freq); | |
744 | ret = get_static_power(cpufreq_device, tz, freq, &static_power); | |
6828a471 | 745 | if (ret) { |
a71544cd | 746 | kfree(load_cpu); |
c36cf071 | 747 | return ret; |
6828a471 JM |
748 | } |
749 | ||
750 | if (load_cpu) { | |
751 | trace_thermal_power_cpu_get_power( | |
752 | &cpufreq_device->allowed_cpus, | |
753 | freq, load_cpu, i, dynamic_power, static_power); | |
754 | ||
a71544cd | 755 | kfree(load_cpu); |
6828a471 | 756 | } |
c36cf071 JM |
757 | |
758 | *power = static_power + dynamic_power; | |
759 | return 0; | |
760 | } | |
761 | ||
762 | /** | |
763 | * cpufreq_state2power() - convert a cpu cdev state to power consumed | |
764 | * @cdev: &thermal_cooling_device pointer | |
765 | * @tz: a valid thermal zone device pointer | |
766 | * @state: cooling device state to be converted | |
767 | * @power: pointer in which to store the resulting power | |
768 | * | |
769 | * Convert cooling device state @state into power consumption in | |
770 | * milliwatts assuming 100% load. Store the calculated power in | |
771 | * @power. | |
772 | * | |
773 | * Return: 0 on success, -EINVAL if the cooling device state could not | |
774 | * be converted into a frequency or other -E* if there was an error | |
775 | * when calculating the static power. | |
776 | */ | |
777 | static int cpufreq_state2power(struct thermal_cooling_device *cdev, | |
778 | struct thermal_zone_device *tz, | |
779 | unsigned long state, u32 *power) | |
780 | { | |
781 | unsigned int freq, num_cpus; | |
782 | cpumask_t cpumask; | |
783 | u32 static_power, dynamic_power; | |
784 | int ret; | |
785 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; | |
786 | ||
787 | cpumask_and(&cpumask, &cpufreq_device->allowed_cpus, cpu_online_mask); | |
788 | num_cpus = cpumask_weight(&cpumask); | |
789 | ||
790 | /* None of our cpus are online, so no power */ | |
791 | if (num_cpus == 0) { | |
792 | *power = 0; | |
793 | return 0; | |
794 | } | |
795 | ||
796 | freq = cpufreq_device->freq_table[state]; | |
797 | if (!freq) | |
798 | return -EINVAL; | |
799 | ||
800 | dynamic_power = cpu_freq_to_power(cpufreq_device, freq) * num_cpus; | |
801 | ret = get_static_power(cpufreq_device, tz, freq, &static_power); | |
802 | if (ret) | |
803 | return ret; | |
804 | ||
805 | *power = static_power + dynamic_power; | |
806 | return 0; | |
807 | } | |
808 | ||
809 | /** | |
810 | * cpufreq_power2state() - convert power to a cooling device state | |
811 | * @cdev: &thermal_cooling_device pointer | |
812 | * @tz: a valid thermal zone device pointer | |
813 | * @power: power in milliwatts to be converted | |
814 | * @state: pointer in which to store the resulting state | |
815 | * | |
816 | * Calculate a cooling device state for the cpus described by @cdev | |
817 | * that would allow them to consume at most @power mW and store it in | |
818 | * @state. Note that this calculation depends on external factors | |
819 | * such as the cpu load or the current static power. Calling this | |
820 | * function with the same power as input can yield different cooling | |
821 | * device states depending on those external factors. | |
822 | * | |
823 | * Return: 0 on success, -ENODEV if no cpus are online or -EINVAL if | |
824 | * the calculated frequency could not be converted to a valid state. | |
825 | * The latter should not happen unless the frequencies available to | |
826 | * cpufreq have changed since the initialization of the cpu cooling | |
827 | * device. | |
828 | */ | |
829 | static int cpufreq_power2state(struct thermal_cooling_device *cdev, | |
830 | struct thermal_zone_device *tz, u32 power, | |
831 | unsigned long *state) | |
832 | { | |
833 | unsigned int cpu, cur_freq, target_freq; | |
834 | int ret; | |
835 | s32 dyn_power; | |
1cac41cb | 836 | u32 normalised_power, static_power; |
c36cf071 | 837 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
1cac41cb MB |
838 | cpumask_t tempmask; |
839 | int num_cpus; | |
840 | ||
841 | cpumask_and(&tempmask, &cpufreq_device->allowed_cpus, &cpufreq_device->target_cpus); | |
842 | num_cpus = cpumask_weight(&tempmask); | |
c36cf071 JM |
843 | |
844 | cpu = cpumask_any_and(&cpufreq_device->allowed_cpus, cpu_online_mask); | |
845 | ||
846 | /* None of our cpus are online */ | |
847 | if (cpu >= nr_cpu_ids) | |
848 | return -ENODEV; | |
849 | ||
850 | cur_freq = cpufreq_quick_get(cpu); | |
851 | ret = get_static_power(cpufreq_device, tz, cur_freq, &static_power); | |
852 | if (ret) | |
853 | return ret; | |
854 | ||
855 | dyn_power = power - static_power; | |
856 | dyn_power = dyn_power > 0 ? dyn_power : 0; | |
1cac41cb | 857 | normalised_power = dyn_power / num_cpus; |
c36cf071 JM |
858 | target_freq = cpu_power_to_freq(cpufreq_device, normalised_power); |
859 | ||
860 | *state = cpufreq_cooling_get_level(cpu, target_freq); | |
861 | if (*state == THERMAL_CSTATE_INVALID) { | |
862 | dev_warn_ratelimited(&cdev->device, | |
863 | "Failed to convert %dKHz for cpu %d into a cdev state\n", | |
864 | target_freq, cpu); | |
865 | return -EINVAL; | |
866 | } | |
867 | ||
6828a471 JM |
868 | trace_thermal_power_cpu_limit(&cpufreq_device->allowed_cpus, |
869 | target_freq, *state, power); | |
c36cf071 JM |
870 | return 0; |
871 | } | |
872 | ||
1cac41cb MB |
873 | static int cpufreq_set_cur_temp(struct thermal_cooling_device *cdev, |
874 | bool suspended, int temp) | |
875 | { | |
876 | enum tmu_noti_state_t tstate; | |
877 | unsigned int on; | |
878 | ||
879 | if (suspended || temp < EXYNOS_COLD_TEMP) { | |
880 | tstate = TMU_COLD; | |
881 | on = 1; | |
882 | } else { | |
883 | tstate = TMU_NORMAL; | |
884 | on = 0; | |
885 | } | |
886 | ||
887 | if (cpu_tstate == tstate) | |
888 | return 0; | |
889 | ||
890 | cpu_tstate = tstate; | |
891 | ||
892 | blocking_notifier_call_chain(&cpu_notifier, TMU_COLD, &on); | |
893 | ||
894 | return 0; | |
895 | } | |
896 | ||
02361418 | 897 | /* Bind cpufreq callbacks to thermal cooling device ops */ |
c36cf071 | 898 | static struct thermal_cooling_device_ops cpufreq_cooling_ops = { |
02361418 ADK |
899 | .get_max_state = cpufreq_get_max_state, |
900 | .get_cur_state = cpufreq_get_cur_state, | |
901 | .set_cur_state = cpufreq_set_cur_state, | |
902 | }; | |
903 | ||
904 | /* Notifier for cpufreq policy change */ | |
905 | static struct notifier_block thermal_cpufreq_notifier_block = { | |
906 | .notifier_call = cpufreq_thermal_notifier, | |
907 | }; | |
908 | ||
1cac41cb MB |
909 | int exynos_tmu_add_notifier(struct notifier_block *n) |
910 | { | |
911 | return blocking_notifier_chain_register(&cpu_notifier, n); | |
912 | } | |
913 | ||
f6859014 VK |
914 | static unsigned int find_next_max(struct cpufreq_frequency_table *table, |
915 | unsigned int prev_max) | |
916 | { | |
917 | struct cpufreq_frequency_table *pos; | |
918 | unsigned int max = 0; | |
919 | ||
920 | cpufreq_for_each_valid_entry(pos, table) { | |
921 | if (pos->frequency > max && pos->frequency < prev_max) | |
922 | max = pos->frequency; | |
923 | } | |
924 | ||
925 | return max; | |
926 | } | |
927 | ||
02361418 | 928 | /** |
39d99cff EV |
929 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device |
930 | * @np: a valid struct device_node to the cooling device device tree node | |
02361418 | 931 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. |
405fb825 | 932 | * Normally this should be same as cpufreq policy->related_cpus. |
c36cf071 JM |
933 | * @capacitance: dynamic power coefficient for these cpus |
934 | * @plat_static_func: function to calculate the static power consumed by these | |
935 | * cpus (optional) | |
12cb08ba EV |
936 | * |
937 | * This interface function registers the cpufreq cooling device with the name | |
938 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq | |
39d99cff EV |
939 | * cooling devices. It also gives the opportunity to link the cooling device |
940 | * with a device tree node, in order to bind it via the thermal DT code. | |
12cb08ba EV |
941 | * |
942 | * Return: a valid struct thermal_cooling_device pointer on success, | |
943 | * on failure, it returns a corresponding ERR_PTR(). | |
02361418 | 944 | */ |
39d99cff EV |
945 | static struct thermal_cooling_device * |
946 | __cpufreq_cooling_register(struct device_node *np, | |
c36cf071 JM |
947 | const struct cpumask *clip_cpus, u32 capacitance, |
948 | get_static_t plat_static_func) | |
02361418 ADK |
949 | { |
950 | struct thermal_cooling_device *cool_dev; | |
5d3bdb89 | 951 | struct cpufreq_cooling_device *cpufreq_dev; |
02361418 | 952 | char dev_name[THERMAL_NAME_LENGTH]; |
dcc6c7fd | 953 | struct cpufreq_frequency_table *pos, *table; |
c36cf071 | 954 | unsigned int freq, i, num_cpus; |
405fb825 | 955 | int ret; |
02361418 | 956 | |
dcc6c7fd VK |
957 | table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); |
958 | if (!table) { | |
0f1be51c EV |
959 | pr_debug("%s: CPUFreq table not found\n", __func__); |
960 | return ERR_PTR(-EPROBE_DEFER); | |
02361418 | 961 | } |
0f1be51c | 962 | |
98d522f0 | 963 | cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); |
02361418 ADK |
964 | if (!cpufreq_dev) |
965 | return ERR_PTR(-ENOMEM); | |
966 | ||
c36cf071 JM |
967 | num_cpus = cpumask_weight(clip_cpus); |
968 | cpufreq_dev->time_in_idle = kcalloc(num_cpus, | |
969 | sizeof(*cpufreq_dev->time_in_idle), | |
970 | GFP_KERNEL); | |
971 | if (!cpufreq_dev->time_in_idle) { | |
972 | cool_dev = ERR_PTR(-ENOMEM); | |
973 | goto free_cdev; | |
974 | } | |
975 | ||
976 | cpufreq_dev->time_in_idle_timestamp = | |
977 | kcalloc(num_cpus, sizeof(*cpufreq_dev->time_in_idle_timestamp), | |
978 | GFP_KERNEL); | |
979 | if (!cpufreq_dev->time_in_idle_timestamp) { | |
980 | cool_dev = ERR_PTR(-ENOMEM); | |
981 | goto free_time_in_idle; | |
982 | } | |
983 | ||
dcc6c7fd VK |
984 | /* Find max levels */ |
985 | cpufreq_for_each_valid_entry(pos, table) | |
986 | cpufreq_dev->max_level++; | |
987 | ||
f6859014 VK |
988 | cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * |
989 | cpufreq_dev->max_level, GFP_KERNEL); | |
990 | if (!cpufreq_dev->freq_table) { | |
f6859014 | 991 | cool_dev = ERR_PTR(-ENOMEM); |
c36cf071 | 992 | goto free_time_in_idle_timestamp; |
f6859014 VK |
993 | } |
994 | ||
dcc6c7fd VK |
995 | /* max_level is an index, not a counter */ |
996 | cpufreq_dev->max_level--; | |
997 | ||
02361418 | 998 | cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); |
1cac41cb | 999 | cpumask_copy(&cpufreq_dev->target_cpus, clip_cpus); |
02361418 | 1000 | |
c36cf071 JM |
1001 | if (capacitance) { |
1002 | cpufreq_cooling_ops.get_requested_power = | |
1003 | cpufreq_get_requested_power; | |
1004 | cpufreq_cooling_ops.state2power = cpufreq_state2power; | |
1005 | cpufreq_cooling_ops.power2state = cpufreq_power2state; | |
c36cf071 JM |
1006 | |
1007 | ret = build_dyn_power_table(cpufreq_dev, capacitance); | |
1008 | if (ret) { | |
1009 | cool_dev = ERR_PTR(ret); | |
1010 | goto free_table; | |
1011 | } | |
1cac41cb MB |
1012 | |
1013 | ret = build_static_power_table(cpufreq_dev); | |
1014 | if (ret) { | |
1015 | cool_dev = ERR_PTR(ret); | |
1016 | goto free_table; | |
1017 | } | |
c36cf071 JM |
1018 | } |
1019 | ||
02361418 ADK |
1020 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); |
1021 | if (ret) { | |
730abe06 | 1022 | cool_dev = ERR_PTR(ret); |
eba4f88d | 1023 | goto free_power_table; |
02361418 ADK |
1024 | } |
1025 | ||
f6859014 VK |
1026 | /* Fill freq-table in descending order of frequencies */ |
1027 | for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { | |
1028 | freq = find_next_max(table, freq); | |
1029 | cpufreq_dev->freq_table[i] = freq; | |
1030 | ||
1031 | /* Warn for duplicate entries */ | |
1032 | if (!freq) | |
1033 | pr_warn("%s: table has duplicate entries\n", __func__); | |
1034 | else | |
1035 | pr_debug("%s: freq:%u KHz\n", __func__, freq); | |
02361418 | 1036 | } |
f6859014 | 1037 | |
1cac41cb MB |
1038 | if (cpufreq_dev->id == 0) |
1039 | cpufreq_cooling_ops.set_cur_temp = cpufreq_set_cur_temp; | |
1040 | ||
a519bfe6 LL |
1041 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", |
1042 | cpufreq_dev->id); | |
1043 | ||
1044 | cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, | |
1045 | &cpufreq_cooling_ops); | |
1046 | if (IS_ERR(cool_dev)) | |
1047 | goto remove_idr; | |
1048 | ||
59f0d218 | 1049 | cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0]; |
02361418 | 1050 | cpufreq_dev->cool_dev = cool_dev; |
92e615ec | 1051 | |
02361418 | 1052 | mutex_lock(&cooling_cpufreq_lock); |
02361418 | 1053 | |
02373d7c RK |
1054 | mutex_lock(&cooling_list_lock); |
1055 | list_add(&cpufreq_dev->node, &cpufreq_dev_list); | |
1056 | mutex_unlock(&cooling_list_lock); | |
1057 | ||
02361418 | 1058 | /* Register the notifier for first cpufreq cooling device */ |
02373d7c | 1059 | if (!cpufreq_dev_count++) |
02361418 | 1060 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, |
5fda7f68 | 1061 | CPUFREQ_POLICY_NOTIFIER); |
02361418 | 1062 | mutex_unlock(&cooling_cpufreq_lock); |
79491e53 | 1063 | |
730abe06 VK |
1064 | return cool_dev; |
1065 | ||
1066 | remove_idr: | |
1067 | release_idr(&cpufreq_idr, cpufreq_dev->id); | |
eba4f88d JM |
1068 | free_power_table: |
1069 | kfree(cpufreq_dev->dyn_power_table); | |
f6859014 VK |
1070 | free_table: |
1071 | kfree(cpufreq_dev->freq_table); | |
c36cf071 JM |
1072 | free_time_in_idle_timestamp: |
1073 | kfree(cpufreq_dev->time_in_idle_timestamp); | |
1074 | free_time_in_idle: | |
1075 | kfree(cpufreq_dev->time_in_idle); | |
730abe06 VK |
1076 | free_cdev: |
1077 | kfree(cpufreq_dev); | |
1078 | ||
02361418 ADK |
1079 | return cool_dev; |
1080 | } | |
39d99cff EV |
1081 | |
1082 | /** | |
1083 | * cpufreq_cooling_register - function to create cpufreq cooling device. | |
1084 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. | |
1085 | * | |
1086 | * This interface function registers the cpufreq cooling device with the name | |
1087 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq | |
1088 | * cooling devices. | |
1089 | * | |
1090 | * Return: a valid struct thermal_cooling_device pointer on success, | |
1091 | * on failure, it returns a corresponding ERR_PTR(). | |
1092 | */ | |
1093 | struct thermal_cooling_device * | |
1094 | cpufreq_cooling_register(const struct cpumask *clip_cpus) | |
1095 | { | |
c36cf071 | 1096 | return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL); |
39d99cff | 1097 | } |
243dbd9c | 1098 | EXPORT_SYMBOL_GPL(cpufreq_cooling_register); |
02361418 | 1099 | |
39d99cff EV |
1100 | /** |
1101 | * of_cpufreq_cooling_register - function to create cpufreq cooling device. | |
1102 | * @np: a valid struct device_node to the cooling device device tree node | |
1103 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. | |
1104 | * | |
1105 | * This interface function registers the cpufreq cooling device with the name | |
1106 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq | |
1107 | * cooling devices. Using this API, the cpufreq cooling device will be | |
1108 | * linked to the device tree node provided. | |
1109 | * | |
1110 | * Return: a valid struct thermal_cooling_device pointer on success, | |
1111 | * on failure, it returns a corresponding ERR_PTR(). | |
1112 | */ | |
1113 | struct thermal_cooling_device * | |
1114 | of_cpufreq_cooling_register(struct device_node *np, | |
1115 | const struct cpumask *clip_cpus) | |
1116 | { | |
1117 | if (!np) | |
1118 | return ERR_PTR(-EINVAL); | |
1119 | ||
c36cf071 | 1120 | return __cpufreq_cooling_register(np, clip_cpus, 0, NULL); |
39d99cff EV |
1121 | } |
1122 | EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); | |
1123 | ||
c36cf071 JM |
1124 | /** |
1125 | * cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions | |
1126 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen | |
1127 | * @capacitance: dynamic power coefficient for these cpus | |
1128 | * @plat_static_func: function to calculate the static power consumed by these | |
1129 | * cpus (optional) | |
1130 | * | |
1131 | * This interface function registers the cpufreq cooling device with | |
1132 | * the name "thermal-cpufreq-%x". This api can support multiple | |
1133 | * instances of cpufreq cooling devices. Using this function, the | |
1134 | * cooling device will implement the power extensions by using a | |
1135 | * simple cpu power model. The cpus must have registered their OPPs | |
1136 | * using the OPP library. | |
1137 | * | |
1138 | * An optional @plat_static_func may be provided to calculate the | |
1139 | * static power consumed by these cpus. If the platform's static | |
1140 | * power consumption is unknown or negligible, make it NULL. | |
1141 | * | |
1142 | * Return: a valid struct thermal_cooling_device pointer on success, | |
1143 | * on failure, it returns a corresponding ERR_PTR(). | |
1144 | */ | |
1145 | struct thermal_cooling_device * | |
1146 | cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, | |
1147 | get_static_t plat_static_func) | |
1148 | { | |
1149 | return __cpufreq_cooling_register(NULL, clip_cpus, capacitance, | |
1150 | plat_static_func); | |
1151 | } | |
1152 | EXPORT_SYMBOL(cpufreq_power_cooling_register); | |
1153 | ||
1154 | /** | |
1155 | * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions | |
1156 | * @np: a valid struct device_node to the cooling device device tree node | |
1157 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen | |
1158 | * @capacitance: dynamic power coefficient for these cpus | |
1159 | * @plat_static_func: function to calculate the static power consumed by these | |
1160 | * cpus (optional) | |
1161 | * | |
1162 | * This interface function registers the cpufreq cooling device with | |
1163 | * the name "thermal-cpufreq-%x". This api can support multiple | |
1164 | * instances of cpufreq cooling devices. Using this API, the cpufreq | |
1165 | * cooling device will be linked to the device tree node provided. | |
1166 | * Using this function, the cooling device will implement the power | |
1167 | * extensions by using a simple cpu power model. The cpus must have | |
1168 | * registered their OPPs using the OPP library. | |
1169 | * | |
1170 | * An optional @plat_static_func may be provided to calculate the | |
1171 | * static power consumed by these cpus. If the platform's static | |
1172 | * power consumption is unknown or negligible, make it NULL. | |
1173 | * | |
1174 | * Return: a valid struct thermal_cooling_device pointer on success, | |
1175 | * on failure, it returns a corresponding ERR_PTR(). | |
1176 | */ | |
1177 | struct thermal_cooling_device * | |
1178 | of_cpufreq_power_cooling_register(struct device_node *np, | |
1179 | const struct cpumask *clip_cpus, | |
1180 | u32 capacitance, | |
1181 | get_static_t plat_static_func) | |
1182 | { | |
1183 | if (!np) | |
1184 | return ERR_PTR(-EINVAL); | |
1185 | ||
1186 | return __cpufreq_cooling_register(np, clip_cpus, capacitance, | |
1187 | plat_static_func); | |
1188 | } | |
1189 | EXPORT_SYMBOL(of_cpufreq_power_cooling_register); | |
1190 | ||
02361418 ADK |
1191 | /** |
1192 | * cpufreq_cooling_unregister - function to remove cpufreq cooling device. | |
1193 | * @cdev: thermal cooling device pointer. | |
135266b4 EV |
1194 | * |
1195 | * This interface function unregisters the "thermal-cpufreq-%x" cooling device. | |
02361418 ADK |
1196 | */ |
1197 | void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | |
1198 | { | |
50e66c7e | 1199 | struct cpufreq_cooling_device *cpufreq_dev; |
02361418 | 1200 | |
50e66c7e EV |
1201 | if (!cdev) |
1202 | return; | |
1203 | ||
1204 | cpufreq_dev = cdev->devdata; | |
02361418 ADK |
1205 | |
1206 | /* Unregister the notifier for the last cpufreq cooling device */ | |
02373d7c RK |
1207 | mutex_lock(&cooling_cpufreq_lock); |
1208 | if (!--cpufreq_dev_count) | |
02361418 | 1209 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, |
5fda7f68 | 1210 | CPUFREQ_POLICY_NOTIFIER); |
02373d7c RK |
1211 | |
1212 | mutex_lock(&cooling_list_lock); | |
1213 | list_del(&cpufreq_dev->node); | |
1214 | mutex_unlock(&cooling_list_lock); | |
1215 | ||
02361418 | 1216 | mutex_unlock(&cooling_cpufreq_lock); |
160b7d80 | 1217 | |
02361418 ADK |
1218 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); |
1219 | release_idr(&cpufreq_idr, cpufreq_dev->id); | |
eba4f88d | 1220 | kfree(cpufreq_dev->dyn_power_table); |
c36cf071 JM |
1221 | kfree(cpufreq_dev->time_in_idle_timestamp); |
1222 | kfree(cpufreq_dev->time_in_idle); | |
f6859014 | 1223 | kfree(cpufreq_dev->freq_table); |
02361418 ADK |
1224 | kfree(cpufreq_dev); |
1225 | } | |
243dbd9c | 1226 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); |