summaryrefslogtreecommitdiff
path: root/amlogic_thermal_module.c (plain)
blob: 8ee83b6533f6f1e99b560327ad8b65355fb6b45e
1/*
2 * amlogic_thermal.c - Samsung amlogic thermal (Thermal Management Unit)
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * Donggeun Kim <dg77.kim@samsung.com>
6 * Amit Daniel Kachhap <amit.kachhap@linaro.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/err.h>
26#include <linux/kernel.h>
27#include <linux/slab.h>
28#include <linux/platform_device.h>
29#include <linux/interrupt.h>
30#include <linux/clk.h>
31#include <linux/workqueue.h>
32#include <linux/sysfs.h>
33#include <linux/kobject.h>
34#include <linux/io.h>
35#include <linux/mutex.h>
36#include <linux/thermal.h>
37#include <linux/cpufreq.h>
38#include <linux/cpu_cooling.h>
39#include <linux/of.h>
40#include <linux/amlogic/saradc.h>
41#include <linux/random.h>
42#include <linux/gpu_cooling.h>
43#include <linux/cpucore_cooling.h>
44#include <linux/gpucore_cooling.h>
45#include <linux/thermal_core.h>
46#include <linux/version.h>
47#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 10, 33)
48#include <linux/amlogic/aml_thermal_hw.h>
49#else
50#include <mach/thermal.h>
51#endif
52#include <linux/version.h>
53#include "amlogic_thermal.h"
54
55#define DBG_VIRTUAL 0
56#define MIN_TEMP (-273)
57int thermal_debug_enable = 0;
58int high_temp_protect = 0;
59atomic_t freq_update_flag;
60EXPORT_SYMBOL(thermal_debug_enable);
61EXPORT_SYMBOL(high_temp_protect);
62EXPORT_SYMBOL(freq_update_flag);
63
64#define THERMAL_DBG(format,args...) \
65 if (thermal_debug_enable) { \
66 printk("[THERMAL]"format, ##args); \
67 }
68
69static struct aml_virtual_thermal_device cpu_virtual_thermal = {};
70static struct aml_virtual_thermal_device gpu_virtual_thermal = {};
71static unsigned int report_interval[4] = {};
72
73/* CPU Zone information */
74#define PANIC_ZONE 4
75#define WARN_ZONE 3
76#define MONITOR_ZONE 2
77#define SAFE_ZONE 1
78
79#define GET_ZONE(trip) (trip + 2)
80#define GET_TRIP(zone) (zone - 2)
81
82static void amlogic_unregister_thermal(struct amlogic_thermal_platform_data *pdata);
83static int amlogic_register_thermal(struct amlogic_thermal_platform_data *pdata, struct platform_device *pdev);
84
85void thermal_lock(struct mutex *lock)
86{
87 mutex_lock(lock);
88}
89EXPORT_SYMBOL(thermal_lock);
90
91void thermal_unlock(struct mutex *lock)
92{
93 mutex_unlock(lock);
94}
95EXPORT_SYMBOL(thermal_unlock);
96
97/* Get mode callback functions for thermal zone */
98static int amlogic_get_mode(struct thermal_zone_device *thermal,
99 enum thermal_device_mode *mode)
100{
101 struct amlogic_thermal_platform_data *pdata= thermal->devdata;
102
103 if (pdata)
104 *mode = pdata->mode;
105 return 0;
106}
107
108/* Set mode callback functions for thermal zone */
109static int amlogic_set_mode(struct thermal_zone_device *thermal,
110 enum thermal_device_mode mode)
111{
112 struct amlogic_thermal_platform_data *pdata= thermal->devdata;
113 struct cpucore_cooling_device *cpucore_device =NULL;
114 struct gpucore_cooling_device *gpucore_device = NULL;
115 if(!pdata)
116 return -EINVAL;
117
118 //mutex_lock(&pdata->therm_dev->lock);
119
120 if (mode == THERMAL_DEVICE_ENABLED){
121 pdata->therm_dev->polling_delay = pdata->idle_interval;
122 if(pdata->cpucore_cool_dev){
123 cpucore_device=pdata->cpucore_cool_dev->devdata;
124 cpucore_device->stop_flag=0;
125 }
126 if(pdata->gpucore_cool_dev){
127 gpucore_device=pdata->gpucore_cool_dev->devdata;
128 gpucore_device->stop_flag=0;
129 }
130 if (pdata->keep_mode) { // start work
131 schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100));
132 }
133 }
134 else{
135 pdata->therm_dev->polling_delay = 0;
136 if (pdata->keep_mode) {
137 cancel_delayed_work_sync(&pdata->thermal_work);
138 keep_mode_set_mode(pdata);
139 }
140 if(pdata->cpucore_cool_dev)
141 pdata->cpucore_cool_dev->ops->set_cur_state(pdata->cpucore_cool_dev,(0|CPU_STOP));
142 if(pdata->gpucore_cool_dev)
143 pdata->gpucore_cool_dev->ops->set_cur_state(pdata->gpucore_cool_dev,(0|GPU_STOP));
144 }
145
146 //mutex_unlock(&pdata->therm_dev->lock);
147
148 pdata->mode = mode;
149 thermal_zone_device_update(pdata->therm_dev);
150 pr_info("thermal polling set for duration=%d msec\n",
151 pdata->therm_dev->polling_delay);
152 return 0;
153}
154
155/* Get trip type callback functions for thermal zone */
156static int amlogic_get_trip_type(struct thermal_zone_device *thermal, int trip,
157 enum thermal_trip_type *type)
158{
159 if(trip < thermal->trips-1)
160 *type = THERMAL_TRIP_ACTIVE;
161 else if(trip == thermal->trips-1)
162 *type = THERMAL_TRIP_CRITICAL;
163 else
164 return -EINVAL;
165 return 0;
166}
167
168/* Get trip temperature callback functions for thermal zone */
169static int amlogic_get_trip_temp(struct thermal_zone_device *thermal, int trip,
170 unsigned long *temp)
171{
172 struct amlogic_thermal_platform_data *pdata= thermal->devdata;
173
174 if(trip > pdata->temp_trip_count ||trip<0)
175 return -EINVAL;
176 mutex_lock(&pdata->lock);
177 *temp =pdata->tmp_trip[trip].temperature;
178 /* convert the temperature into millicelsius */
179 mutex_unlock(&pdata->lock);
180
181 return 0;
182}
183
184static int amlogic_set_trip_temp(struct thermal_zone_device *thermal, int trip,
185 unsigned long temp)
186{
187 struct amlogic_thermal_platform_data *pdata= thermal->devdata;
188
189 if(trip > pdata->temp_trip_count ||trip<0)
190 return -EINVAL;
191 mutex_lock(&pdata->lock);
192 pdata->tmp_trip[trip].temperature=temp;
193 /* convert the temperature into millicelsius */
194 mutex_unlock(&pdata->lock);
195 return 0;
196}
197
198/* Get critical temperature callback functions for thermal zone */
199static int amlogic_get_crit_temp(struct thermal_zone_device *thermal,
200 unsigned long *temp)
201{
202 int ret;
203 /* Panic zone */
204 ret =amlogic_get_trip_temp(thermal, thermal->trips-1, temp);
205
206 return ret;
207}
208
209
210/* Bind callback functions for thermal zone */
211static int amlogic_bind(struct thermal_zone_device *thermal,
212 struct thermal_cooling_device *cdev)
213{
214 int ret = 0, i;
215 struct amlogic_thermal_platform_data *pdata= thermal->devdata;
216 int id;
217 char type[THERMAL_NAME_LENGTH];
218 unsigned long max;
219
220 if (!sscanf(cdev->type, "thermal-%7s-%d", type,&id))
221 return -EINVAL;
222 if(!strcmp(type,"cpufreq")){
223 /* Bind the thermal zone to the cpufreq cooling device */
224 for (i = 0; i < pdata->temp_trip_count; i++) {
225 if(pdata->tmp_trip[0].cpu_upper_level==THERMAL_CSTATE_INVALID)
226 {
227 printk("disable cpu cooling device by dtd\n");
228 ret = -EINVAL;
229 goto out;
230 }
231 if (thermal_zone_bind_cooling_device(thermal, i, cdev,
232 pdata->tmp_trip[i].cpu_upper_level,
233 pdata->tmp_trip[i].cpu_lower_level)) {
234 pr_err("error binding cdev inst %d\n", i);
235 ret = -EINVAL;
236 goto out;
237 }
238 }
239 pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
240 if (pdata->keep_mode) {
241 cdev->ops->get_max_state(cdev, &max);
242 keep_mode_bind(pdata, max, 0);
243 }
244 }
245
246 if(!strcmp(type,"gpufreq")){
247 struct gpufreq_cooling_device *gpufreq_dev=
248 (struct gpufreq_cooling_device *)cdev->devdata;
249 /* Bind the thermal zone to the cpufreq cooling device */
250 for (i = 0; i < pdata->temp_trip_count; i++) {
251 if(!gpufreq_dev->get_gpu_freq_level){
252 ret = -EINVAL;
253 pr_info("invalidate pointer %p\n",gpufreq_dev->get_gpu_freq_level);
254 goto out;
255 }
256 pdata->tmp_trip[i].gpu_lower_level=gpufreq_dev->get_gpu_freq_level(pdata->tmp_trip[i].gpu_upper_freq);
257 pdata->tmp_trip[i].gpu_upper_level=gpufreq_dev->get_gpu_freq_level(pdata->tmp_trip[i].gpu_lower_freq);
258 printk("pdata->tmp_trip[%d].gpu_lower_level=%d\n",i,pdata->tmp_trip[i].gpu_lower_level);
259 printk("pdata->tmp_trip[%d].gpu_upper_level=%d\n",i,pdata->tmp_trip[i].gpu_upper_level);
260 if(pdata->tmp_trip[0].gpu_lower_level==THERMAL_CSTATE_INVALID)
261 {
262 printk("disable gpu cooling device by dtd\n");
263 ret = -EINVAL;
264 goto out;
265 }
266 if (thermal_zone_bind_cooling_device(thermal, i, cdev,
267 pdata->tmp_trip[i].gpu_upper_level,
268 pdata->tmp_trip[i].gpu_lower_level)) {
269 pr_err("error binding cdev inst %d\n", i);
270 ret = -EINVAL;
271 goto out;
272 }
273 }
274 pdata->gpu_cool_dev=cdev;
275 pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
276 if (pdata->keep_mode) {
277 cdev->ops->get_max_state(cdev, &max);
278 keep_mode_bind(pdata, max, 1);
279 }
280 }
281
282 if(!strcmp(type,"cpucore")){
283 /* Bind the thermal zone to the cpufreq cooling device */
284 struct cpucore_cooling_device *cpucore_dev=
285 (struct cpucore_cooling_device *)cdev->devdata;
286 for (i = 0; i < pdata->temp_trip_count; i++) {
287 if(pdata->tmp_trip[0].cpu_core_num==THERMAL_CSTATE_INVALID)
288 {
289 printk("disable cpucore cooling device by dtd\n");
290 ret = -EINVAL;
291 goto out;
292 }
293 if(pdata->tmp_trip[i].cpu_core_num !=-1)
294 pdata->tmp_trip[i].cpu_core_upper=cpucore_dev->max_cpu_core_num-pdata->tmp_trip[i].cpu_core_num;
295 else
296 pdata->tmp_trip[i].cpu_core_upper=pdata->tmp_trip[i].cpu_core_num;
297 printk("tmp_trip[%d].cpu_core_upper=%d\n",i,pdata->tmp_trip[i].cpu_core_upper);
298 if (thermal_zone_bind_cooling_device(thermal, i, cdev,
299 pdata->tmp_trip[i].cpu_core_upper,
300 pdata->tmp_trip[i].cpu_core_upper)) {
301 pr_err("error binding cdev inst %d\n", i);
302 ret = -EINVAL;
303 goto out;
304 }
305 }
306 pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
307 if (pdata->keep_mode) {
308 cdev->ops->get_max_state(cdev, &max);
309 keep_mode_bind(pdata, max, 2);
310 }
311 }
312
313 if(!strcmp(type,"gpucore")){
314 /* Bind the thermal zone to the cpufreq cooling device */
315 struct gpucore_cooling_device *gpucore_dev=
316 (struct gpucore_cooling_device *)cdev->devdata;
317 for (i = 0; i < pdata->temp_trip_count; i++) {
318 if(pdata->tmp_trip[0].cpu_core_num==THERMAL_CSTATE_INVALID)
319 {
320 printk("disable gpucore cooling device by dtd\n");
321 ret = -EINVAL;
322 goto out;
323 }
324 if(pdata->tmp_trip[i].gpu_core_num != -1)
325 pdata->tmp_trip[i].gpu_core_upper=gpucore_dev->max_gpu_core_num-pdata->tmp_trip[i].gpu_core_num;
326 else
327 pdata->tmp_trip[i].gpu_core_upper=pdata->tmp_trip[i].gpu_core_num;
328
329 printk("tmp_trip[%d].gpu_core_upper=%d\n",i,pdata->tmp_trip[i].gpu_core_upper);
330 if (thermal_zone_bind_cooling_device(thermal, i, cdev,
331 pdata->tmp_trip[i].gpu_core_upper,
332 pdata->tmp_trip[i].gpu_core_upper)) {
333 pr_err("error binding cdev inst %d\n", i);
334 ret = -EINVAL;
335 goto out;
336 }
337 }
338 pdata->gpucore_cool_dev=cdev;
339 pr_info("%s bind %s okay !\n",thermal->type,cdev->type);
340 if (pdata->keep_mode) {
341 cdev->ops->get_max_state(cdev, &max);
342 keep_mode_bind(pdata, max, 3);
343 }
344 }
345 return ret;
346out:
347 return ret;
348}
349
350/* Unbind callback functions for thermal zone */
351static int amlogic_unbind(struct thermal_zone_device *thermal,
352 struct thermal_cooling_device *cdev)
353{
354 int i;
355 if(thermal && cdev){
356 struct amlogic_thermal_platform_data *pdata= thermal->devdata;
357 for (i = 0; i < pdata->temp_trip_count; i++) {
358 pr_info("\n%s unbinding %s ",thermal->type,cdev->type);
359 if (thermal_zone_unbind_cooling_device(thermal, i, cdev)) {
360 pr_err(" error %d \n", i);
361 return -EINVAL;
362 }
363 pr_info(" okay\n");
364 return 0;
365 }
366 }else{
367 return -EINVAL;
368 }
369 return -EINVAL;
370}
371#define ABS(a) ((a) > 0 ? (a) : -(a))
372
373void *thermal_alloc(size_t len)
374{
375 return kzalloc(len, GFP_KERNEL);
376}
377EXPORT_SYMBOL(thermal_alloc);
378
379static void thermal_work(struct work_struct *work)
380{
381 struct cpufreq_policy *policy = cpufreq_cpu_get(0);
382 struct amlogic_thermal_platform_data *pdata;
383 int cpu_freq = 0;
384
385 pdata = container_of((struct delayed_work *)work, struct amlogic_thermal_platform_data, thermal_work);
386 if (policy) {
387 cpu_freq = policy->cur;
388 }
389 if (pdata->temp_valid)
390 keep_mode_work(pdata, cpu_freq);
391 if (pdata->mode == THERMAL_DEVICE_ENABLED) { // no need to do this work again if thermal disabled
392 schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100));
393 }
394}
395
396static int aml_virtaul_thermal_probe(struct platform_device *pdev, struct amlogic_thermal_platform_data *pdata)
397{
398 int ret, len, cells;
399 struct property *prop;
400 void *buf;
401
402 if (!of_property_read_bool(pdev->dev.of_node, "use_virtual_thermal")) {
403 printk("%s, virtual thermal is not enabled\n", __func__);
404 pdata->virtual_thermal_en = 0;
405 return 0;
406 } else {
407 printk("%s, virtual thermal enabled\n", __func__);
408 }
409
410 ret = of_property_read_u32(pdev->dev.of_node,
411 "freq_sample_period",
412 &pdata->freq_sample_period);
413 if (ret) {
414 printk("%s, get freq_sample_period failed, us 30 as default\n", __func__);
415 pdata->freq_sample_period = 30;
416 } else {
417 printk("%s, get freq_sample_period with value:%d\n", __func__, pdata->freq_sample_period);
418 }
419 ret = of_property_read_u32_array(pdev->dev.of_node,
420 "report_time",
421 report_interval, sizeof(report_interval) / sizeof(u32));
422 if (ret) {
423 printk("%s, get report_time failed\n", __func__);
424 goto error;
425 } else {
426 printk("[virtual_thermal] report interval:%4d, %4d, %4d, %4d\n",
427 report_interval[0], report_interval[1], report_interval[2], report_interval[3]);
428 }
429 /*
430 * read cpu_virtal
431 */
432 prop = of_find_property(pdev->dev.of_node, "cpu_virtual", &len);
433 if (!prop) {
434 printk("%s, cpu virtual not found\n", __func__);
435 goto error;
436 }
437 cells = len / sizeof(struct aml_virtual_thermal);
438 buf = kzalloc(len, GFP_KERNEL);
439 if (!buf) {
440 printk("%s, no memory\n", __func__);
441 return -ENOMEM;
442 }
443 ret = of_property_read_u32_array(pdev->dev.of_node,
444 "cpu_virtual",
445 buf, len/sizeof(u32));
446 if (ret) {
447 printk("%s, read cpu_virtual failed\n", __func__);
448 kfree(buf);
449 goto error;
450 }
451 cpu_virtual_thermal.count = cells;
452 cpu_virtual_thermal.thermal = buf;
453
454 /*
455 * read gpu_virtal
456 */
457 prop = of_find_property(pdev->dev.of_node, "gpu_virtual", &len);
458 if (!prop) {
459 printk("%s, gpu virtual not found\n", __func__);
460 goto error;
461 }
462 cells = len / sizeof(struct aml_virtual_thermal);
463 buf = kzalloc(len, GFP_KERNEL);
464 if (!buf) {
465 printk("%s, no memory\n", __func__);
466 return -ENOMEM;
467 }
468 ret = of_property_read_u32_array(pdev->dev.of_node,
469 "gpu_virtual",
470 buf, len/sizeof(u32));
471 if (ret) {
472 printk("%s, read gpu_virtual failed\n", __func__);
473 kfree(buf);
474 goto error;
475 }
476 gpu_virtual_thermal.count = cells;
477 gpu_virtual_thermal.thermal = buf;
478
479#if DBG_VIRTUAL
480 printk("cpu_virtal cells:%d, table:\n", cpu_virtual_thermal.count);
481 for (len = 0; len < cpu_virtual_thermal.count; len++) {
482 printk("%2d, %8d, %4d, %4d, %4d, %4d\n",
483 len,
484 cpu_virtual_thermal.thermal[len].freq,
485 cpu_virtual_thermal.thermal[len].temp_time[0],
486 cpu_virtual_thermal.thermal[len].temp_time[1],
487 cpu_virtual_thermal.thermal[len].temp_time[2],
488 cpu_virtual_thermal.thermal[len].temp_time[3]);
489 }
490 printk("gpu_virtal cells:%d, table:\n", gpu_virtual_thermal.count);
491 for (len = 0; len < gpu_virtual_thermal.count; len++) {
492 printk("%2d, %8d, %4d, %4d, %4d, %4d\n",
493 len,
494 gpu_virtual_thermal.thermal[len].freq,
495 gpu_virtual_thermal.thermal[len].temp_time[0],
496 gpu_virtual_thermal.thermal[len].temp_time[1],
497 gpu_virtual_thermal.thermal[len].temp_time[2],
498 gpu_virtual_thermal.thermal[len].temp_time[3]);
499 }
500#endif
501
502 pdata->virtual_thermal_en = 1;
503 return 0;
504
505error:
506 pdata->virtual_thermal_en = 0;
507 return -1;
508}
509
510static void aml_virtual_thermal_remove(struct amlogic_thermal_platform_data *pdata)
511{
512 kfree(cpu_virtual_thermal.thermal);
513 kfree(gpu_virtual_thermal.thermal);
514 pdata->virtual_thermal_en = 0;
515}
516
517static int check_freq_level(struct aml_virtual_thermal_device *dev, unsigned int freq)
518{
519 int i = 0;
520
521 if (freq >= dev->thermal[dev->count-1].freq) {
522 return dev->count - 1;
523 }
524 for (i = 0; i < dev->count - 1; i++) {
525 if (freq > dev->thermal[i].freq && freq <= dev->thermal[i + 1].freq) {
526 return i + 1;
527 }
528 }
529 return 0;
530}
531
532static int check_freq_level_cnt(unsigned int cnt)
533{
534 int i;
535
536 if (cnt >= report_interval[3]) {
537 return 3;
538 }
539 for (i = 0; i < 3; i++) {
540 if (cnt >= report_interval[i] && cnt < report_interval[i + 1]) {
541 return i;
542 }
543 }
544 return 0;
545}
546
547static unsigned long aml_cal_virtual_temp(struct amlogic_thermal_platform_data *pdata)
548{
549 static unsigned int cpu_freq_level_cnt = 0, gpu_freq_level_cnt = 0;
550 static unsigned int last_cpu_freq_level = 0, last_gpu_freq_level = 0;
551 static unsigned int cpu_temp = 40, gpu_temp = 40; // default set to 40 when at homescreen
552 unsigned int curr_cpu_avg_freq, curr_gpu_avg_freq;
553 int curr_cpu_freq_level, curr_gpu_freq_level;
554 int cnt_level, level_diff;
555 int temp_update = 0, final_temp;
556
557 /*
558 * CPU temp
559 */
560 if (atomic_read(&freq_update_flag)) {
561 curr_cpu_avg_freq = pdata->monitor.avg_cpu_freq;
562 curr_cpu_freq_level = check_freq_level(&cpu_virtual_thermal, curr_cpu_avg_freq);
563 level_diff = curr_cpu_freq_level - last_cpu_freq_level;
564 if (ABS(level_diff) <= 1) { // freq change is not large
565 cpu_freq_level_cnt++;
566 cnt_level = check_freq_level_cnt(cpu_freq_level_cnt);
567 cpu_temp = cpu_virtual_thermal.thermal[curr_cpu_freq_level].temp_time[cnt_level];
568#if DBG_VIRTUAL
569 printk("%s, cur_freq:%7d, freq_level:%d, cnt_level:%d, cnt:%d, cpu_temp:%d\n",
570 __func__, curr_cpu_avg_freq, curr_cpu_freq_level, cnt_level, cpu_freq_level_cnt, cpu_temp);
571#endif
572 } else { // level not match
573 cpu_temp = cpu_virtual_thermal.thermal[curr_cpu_freq_level].temp_time[0];
574#if DBG_VIRTUAL
575 printk("%s, cur_freq:%7d, cur_level:%d, last_level:%d, last_cnt_level:%d, cpu_temp:%d\n",
576 __func__, curr_cpu_avg_freq, curr_cpu_freq_level, last_cpu_freq_level, cpu_freq_level_cnt, cpu_temp);
577#endif
578 cpu_freq_level_cnt = 0;
579 }
580 last_cpu_freq_level = curr_cpu_freq_level;
581
582 curr_gpu_avg_freq = pdata->monitor.avg_gpu_freq;
583 curr_gpu_freq_level = check_freq_level(&gpu_virtual_thermal, curr_gpu_avg_freq);
584 level_diff = curr_gpu_freq_level - last_gpu_freq_level;
585 if (ABS(level_diff) <= 1) { // freq change is not large
586 gpu_freq_level_cnt++;
587 cnt_level = check_freq_level_cnt(gpu_freq_level_cnt);
588 gpu_temp = gpu_virtual_thermal.thermal[curr_gpu_freq_level].temp_time[cnt_level];
589#if DBG_VIRTUAL
590 printk("%s, cur_freq:%7d, freq_level:%d, cnt_level:%d, cnt:%d, gpu_temp:%d\n",
591 __func__, curr_gpu_avg_freq, curr_gpu_freq_level, cnt_level, gpu_freq_level_cnt, gpu_temp);
592#endif
593 } else { // level not match
594 gpu_temp = gpu_virtual_thermal.thermal[curr_gpu_freq_level].temp_time[0];
595 gpu_freq_level_cnt = 0;
596#if DBG_VIRTUAL
597 printk("%s, cur_freq:%7d, cur_level:%d, last_level:%d, gpu_temp:%d\n",
598 __func__, curr_gpu_avg_freq, curr_gpu_freq_level, last_gpu_freq_level, gpu_temp);
599#endif
600 }
601 last_gpu_freq_level = curr_gpu_freq_level;
602
603 atomic_set(&freq_update_flag, 0);
604 temp_update = 1;
605 }
606
607 if (cpu_temp <= 0 && gpu_temp <= 0) {
608 printk("%s, Bug here, cpu & gpu temp can't be 0, cpu_temp:%d, gpu_temp:%d\n", __func__, cpu_temp, gpu_temp);
609 final_temp = 40;
610 }
611 final_temp = (cpu_temp >= gpu_temp ? cpu_temp : gpu_temp);
612 if (temp_update) {
613#if DBG_VIRTUAL
614 printk("final temp:%d\n", final_temp);
615#endif
616 }
617 return final_temp;
618}
619
620/* Get temperature callback functions for thermal zone */
621static int amlogic_get_temp(struct thermal_zone_device *thermal,
622 unsigned long *temp)
623{
624 struct amlogic_thermal_platform_data *pdata = thermal->devdata;
625 int tmp;
626
627 if (pdata->trim_flag) {
628 tmp = get_cpu_temp();
629 if (tmp < MIN_TEMP) {
630 pdata->temp_valid = 0;
631 return -EINVAL;
632 }
633 pdata->temp_valid = 1;
634 *temp = (unsigned long)get_cpu_temp();
635 pdata->current_temp = *temp;
636 } else if (pdata->virtual_thermal_en) {
637 *temp = aml_cal_virtual_temp(pdata);
638 } else {
639 *temp = 45; // fix cpu temperature to 45 if not trimed && disable virtual thermal
640 }
641 return 0;
642}
643
644/* Get the temperature trend */
645static int amlogic_get_trend(struct thermal_zone_device *thermal,
646 int trip, enum thermal_trend *trend)
647{
648 return 1;
649}
650/* Operation callback functions for thermal zone */
651static struct thermal_zone_device_ops amlogic_dev_ops = {
652 .bind = amlogic_bind,
653 .unbind = amlogic_unbind,
654 .get_temp = amlogic_get_temp,
655 .get_trend = amlogic_get_trend,
656 .get_mode = amlogic_get_mode,
657 .set_mode = amlogic_set_mode,
658 .get_trip_type = amlogic_get_trip_type,
659 .get_trip_temp = amlogic_get_trip_temp,
660 .set_trip_temp = amlogic_set_trip_temp,
661 .get_crit_temp = amlogic_get_crit_temp,
662};
663
664/*
665 * sysfs for keep_mode
666 */
667#ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG // for DEBUG
668extern unsigned int max_cpu_num;
669static ssize_t max_cpu_num_show(struct device *dev, struct device_attribute *attr, char *buf)
670{
671 return sprintf(buf, "%d\n", max_cpu_num);
672}
673#endif
674
675static ssize_t thermal_debug_show(struct device *dev, struct device_attribute *attr, char *buf)
676{
677 return sprintf(buf, "%d\n", thermal_debug_enable);
678}
679
680static ssize_t thermal_debug_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
681{
682 int32_t data = simple_strtol(buf, NULL, 10);
683
684 if (data) {
685 thermal_debug_enable = 1;
686 } else {
687 thermal_debug_enable = 0;
688 }
689 return count;
690}
691
692static ssize_t keep_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
693{
694 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
695 struct amlogic_thermal_platform_data *pdata = tz->devdata;
696
697 return sprintf(buf, "%s\n", pdata->keep_mode ? "enabled": "disabled");
698}
699
700static ssize_t keep_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
701{
702 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
703 struct amlogic_thermal_platform_data *pdata = tz->devdata;
704 if (!strncmp(buf, "enabled", sizeof("enabled") - 1)) {
705 pdata->keep_mode = 1;
706 } else if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) {
707 pdata->keep_mode = 0;
708 }
709 return count;
710}
711
712static ssize_t keep_mode_threshold_show(struct device *dev, struct device_attribute *attr, char *buf)
713{
714 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
715 struct amlogic_thermal_platform_data *pdata = tz->devdata;
716
717 return sprintf(buf, "%d\n", pdata->keep_mode_threshold);
718}
719
720static ssize_t keep_mode_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
721{
722 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
723 struct amlogic_thermal_platform_data *pdata = tz->devdata;
724 int32_t data = simple_strtol(buf, NULL, 10);
725
726 if (data > 200) {
727 printk("input is %d, seems too large, invalid\n", data);
728 }
729 keep_mode_update_threshold(pdata, data);
730 printk("set keep_mode_threshold to %d\n", data);
731 return count;
732}
733
734static ssize_t high_temp_protect_show(struct device *dev, struct device_attribute *attr, char *buf)
735{
736 return sprintf(buf, "%d\n", high_temp_protect);
737}
738
739static ssize_t high_temp_protect_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
740{
741 struct thermal_zone_device *tz = container_of(dev, struct thermal_zone_device, device);
742 struct amlogic_thermal_platform_data *pdata = tz->devdata;
743 int32_t data = simple_strtol(buf, NULL, 10);
744
745 high_temp_protect = data ? 1 : 0;
746 if (high_temp_protect) {
747 pdata->tmp_trip[1].temperature = pdata->keep_mode_threshold + 25;
748 } else {
749 pdata->tmp_trip[1].temperature = 260;
750 }
751 printk("high temperature protect %s\n", high_temp_protect ? "enabled" : "disabled");
752 return count;
753}
754
755static struct device_attribute amlogic_thermal_attr[] = {
756#ifdef CONFIG_CPU_FREQ_GOV_HOTPLUG
757 __ATTR(max_cpu_num, 0444, max_cpu_num_show, NULL),
758#endif
759 __ATTR(thermal_debug, 0644, thermal_debug_show, thermal_debug_store),
760 __ATTR(keep_mode, 0644, keep_mode_show, keep_mode_store),
761 __ATTR(keep_mode_threshold, 0644, keep_mode_threshold_show, keep_mode_threshold_store),
762 __ATTR(high_temp_protect, 0644, high_temp_protect_show, high_temp_protect_store)
763};
764
765/* Register with the in-kernel thermal management */
766static int amlogic_register_thermal(struct amlogic_thermal_platform_data *pdata, struct platform_device *pdev)
767{
768 int ret=0, j;
769 struct cpumask mask_val;
770
771 memset(&mask_val,0,sizeof(struct cpumask));
772 cpumask_set_cpu(0, &mask_val);
773 pdata->cpu_cool_dev= cpufreq_cooling_register(&mask_val);
774 if (IS_ERR(pdata->cpu_cool_dev)) {
775 pr_err("Failed to register cpufreq cooling device\n");
776 ret = -EINVAL;
777 goto err_unregister;
778 }
779 pdata->cpucore_cool_dev = cpucore_cooling_register();
780 if (IS_ERR(pdata->cpucore_cool_dev)) {
781 pr_err("Failed to register cpufreq cooling device\n");
782 ret = -EINVAL;
783 goto err_unregister;
784 }
785
786 pdata->therm_dev = thermal_zone_device_register(pdata->name,
787 pdata->temp_trip_count,
788 ((1 << pdata->temp_trip_count) - 1),
789 pdata,
790 &amlogic_dev_ops,
791 NULL,
792 0,
793 pdata->idle_interval);
794
795 if (IS_ERR(pdata->therm_dev)) {
796 pr_err("Failed to register thermal zone device, err:%p\n", pdata->therm_dev);
797 ret = -EINVAL;
798 goto err_unregister;
799 }
800
801 if (pdata->keep_mode) { // create sysfs for keep_mode
802 for (j = 0; j < ARRAY_SIZE(amlogic_thermal_attr); j++) {
803 device_create_file(&pdata->therm_dev->device, &amlogic_thermal_attr[j]);
804 }
805 }
806 pr_info("amlogic: Kernel Thermal management registered\n");
807
808 return 0;
809
810err_unregister:
811 amlogic_unregister_thermal(pdata);
812 return ret;
813}
814
815/* Un-Register with the in-kernel thermal management */
816static void amlogic_unregister_thermal(struct amlogic_thermal_platform_data *pdata)
817{
818 if (pdata->therm_dev)
819 thermal_zone_device_unregister(pdata->therm_dev);
820 if (pdata->cpu_cool_dev)
821 cpufreq_cooling_unregister(pdata->cpu_cool_dev);
822
823 pr_info("amlogic: Kernel Thermal management unregistered\n");
824}
825
826int get_desend(void)
827{
828 int i;
829 unsigned int freq = CPUFREQ_ENTRY_INVALID;
830 int descend = -1;
831 struct cpufreq_frequency_table *table =
832 cpufreq_frequency_get_table(0);
833
834 if (!table)
835 return -EINVAL;
836
837 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
838 /* ignore invalid entries */
839 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
840 continue;
841
842 /* ignore duplicate entry */
843 if (freq == table[i].frequency)
844 continue;
845
846 /* get the frequency order */
847 if (freq != CPUFREQ_ENTRY_INVALID && descend == -1){
848 descend = !!(freq > table[i].frequency);
849 break;
850 }
851
852 freq = table[i].frequency;
853 }
854 return descend;
855}
856int fix_to_freq(int freqold,int descend)
857{
858 int i;
859 unsigned int freq = CPUFREQ_ENTRY_INVALID;
860 struct cpufreq_frequency_table *table =
861 cpufreq_frequency_get_table(0);
862
863 if (!table)
864 return -EINVAL;
865
866 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
867 /* ignore invalid entry */
868 if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
869 continue;
870
871 /* ignore duplicate entry */
872 if (freq == table[i].frequency)
873 continue;
874 freq = table[i].frequency;
875 if(descend){
876 if(freqold>=table[i+1].frequency && freqold<=table[i].frequency)
877 return table[i+1].frequency;
878 }
879 else{
880 if(freqold>=table[i].frequency && freqold<=table[i+1].frequency)
881 return table[i].frequency;
882 }
883 }
884 return -EINVAL;
885}
886
887void thermal_atomic_set(atomic_t *a, int value)
888{
889 atomic_set(a, 1);
890}
891EXPORT_SYMBOL(thermal_atomic_set);
892
893static struct amlogic_thermal_platform_data * amlogic_thermal_init_from_dts(struct platform_device *pdev, int trim_flag)
894{
895 int i = 0, ret = -1, val = 0, cells, descend, error = 0;
896 struct property *prop;
897 struct temp_level *tmp_level = NULL;
898 struct amlogic_thermal_platform_data *pdata = NULL;
899
900 if(!of_property_read_u32(pdev->dev.of_node, "trip_point", &val)){
901 //INIT FROM DTS
902 pdata=kzalloc(sizeof(*pdata),GFP_KERNEL);
903 if(!pdata){
904 goto err;
905 }
906 memset((void* )pdata,0,sizeof(*pdata));
907 ret=of_property_read_u32(pdev->dev.of_node, "#thermal-cells", &val);
908 if(ret){
909 dev_err(&pdev->dev, "dt probe #thermal-cells failed: %d\n", ret);
910 goto err;
911 }
912 printk("#thermal-cells=%d\n",val);
913 cells=val;
914
915 /*
916 * process for KEEP_MODE and virtual thermal
917 * Logic: If virtual thermal is enabled, then ignore keep_mode
918 *
919 */
920 pdata->trim_flag = trim_flag;
921 if (!pdata->trim_flag) { // chip is not trimmed, use virtual thermal
922 aml_virtaul_thermal_probe(pdev, pdata);
923 } else if (of_property_read_bool(pdev->dev.of_node, "keep_mode")) {
924 if (of_property_read_u32(pdev->dev.of_node, "keep_mode_threshold", &pdata->keep_mode_threshold)) {
925 printk("ERROR:keep_mode is set but not found 'keep_mode_threshold'\n");
926 error = 1;
927 }
928 if (of_property_read_u32_array(pdev->dev.of_node,
929 "keep_mode_max_range",
930 pdata->keep_mode_max_range,
931 sizeof(pdata->keep_mode_max_range)/sizeof(u32))) {
932 printk("ERROR:keep_mode is set but not found 'keep_mode_max_range'\n");
933 error = 1;
934 }
935 if (!error && pdata->trim_flag) { // keep mode should not used for virtual thermal right now
936 printk("keep_mode enabled\n");
937 printk("keep_mode_max_range: [%7d, %3d, %d, %d]\n",
938 pdata->keep_mode_max_range[0], pdata->keep_mode_max_range[1],
939 pdata->keep_mode_max_range[2], pdata->keep_mode_max_range[3]);
940 pdata->keep_mode = 1;
941 pdata->freq_sample_period = 5;
942 }
943 } else {
944 printk("keep_mode is disabled\n");
945 }
946 if(pdata->keep_mode || !pdata->trim_flag){
947 INIT_DELAYED_WORK(&pdata->thermal_work, thermal_work);
948 schedule_delayed_work(&pdata->thermal_work, msecs_to_jiffies(100));
949 atomic_set(&freq_update_flag, 0);
950 }
951
952 prop = of_find_property(pdev->dev.of_node, "trip_point", &val);
953 if (!prop){
954 dev_err(&pdev->dev, "read %s length error\n","trip_point");
955 goto err;
956 }
957 if (pdata->keep_mode) {
958 pdata->temp_trip_count = 2;
959 } else {
960 pdata->temp_trip_count=val/cells/sizeof(u32);
961 }
962 printk("pdata->temp_trip_count=%d\n",pdata->temp_trip_count);
963 tmp_level=kzalloc(sizeof(*tmp_level)*pdata->temp_trip_count,GFP_KERNEL);
964 pdata->tmp_trip=kzalloc(sizeof(struct temp_trip)*pdata->temp_trip_count,GFP_KERNEL);
965 if(!tmp_level){
966 goto err;
967 }
968
969 if (pdata->keep_mode) { // keep mode only need one point
970 keep_mode_temp_level_init(pdata, tmp_level);
971 } else {
972 ret=of_property_read_u32_array(pdev->dev.of_node,"trip_point",(u32 *)tmp_level,val/sizeof(u32));
973 if (ret){
974 dev_err(&pdev->dev, "read %s data error\n","trip_point");
975 goto err;
976 }
977 }
978 descend=get_desend();
979 for (i = 0; i < pdata->temp_trip_count; i++) {
980 printk("temperature=%d on trip point=%d\n",tmp_level[i].temperature,i);
981 pdata->tmp_trip[i].temperature=tmp_level[i].temperature;
982 printk("fixing high_freq=%d to ",tmp_level[i].cpu_high_freq);
983 tmp_level[i].cpu_high_freq=fix_to_freq(tmp_level[i].cpu_high_freq,descend);
984 pdata->tmp_trip[i].cpu_lower_level=cpufreq_cooling_get_level(0,tmp_level[i].cpu_high_freq);
985 printk("%d at trip point %d,level=%d\n",tmp_level[i].cpu_high_freq,i,pdata->tmp_trip[i].cpu_lower_level);
986
987 printk("fixing low_freq=%d to ",tmp_level[i].cpu_low_freq);
988 tmp_level[i].cpu_low_freq=fix_to_freq(tmp_level[i].cpu_low_freq,descend);
989 pdata->tmp_trip[i].cpu_upper_level=cpufreq_cooling_get_level(0,tmp_level[i].cpu_low_freq);
990 printk("%d at trip point %d,level=%d\n",tmp_level[i].cpu_low_freq,i,pdata->tmp_trip[i].cpu_upper_level);
991 pdata->tmp_trip[i].gpu_lower_freq=tmp_level[i].gpu_low_freq;
992 pdata->tmp_trip[i].gpu_upper_freq=tmp_level[i].gpu_high_freq;
993 printk("gpu[%d].gpu_high_freq=%d,tmp_level[%d].gpu_high_freq=%d\n",i,tmp_level[i].gpu_high_freq,i,tmp_level[i].gpu_low_freq);
994
995 pdata->tmp_trip[i].cpu_core_num=tmp_level[i].cpu_core_num;
996 printk("cpu[%d] core num==%d\n",i,pdata->tmp_trip[i].cpu_core_num);
997 pdata->tmp_trip[i].gpu_core_num=tmp_level[i].gpu_core_num;
998 printk("gpu[%d] core num==%d\n",i,pdata->tmp_trip[i].gpu_core_num);
999 }
1000
1001 ret= of_property_read_u32(pdev->dev.of_node, "idle_interval", &val);
1002 if (ret){
1003 dev_err(&pdev->dev, "read %s error\n","idle_interval");
1004 goto err;
1005 }
1006 pdata->idle_interval=val;
1007 printk("idle interval=%d\n",pdata->idle_interval);
1008 ret=of_property_read_string(pdev->dev.of_node,"dev_name",&pdata->name);
1009 if (ret){
1010 dev_err(&pdev->dev, "read %s error\n","dev_name");
1011 goto err;
1012 }
1013 printk("pdata->name:%s, pdata:%p\n",pdata->name, pdata);
1014 pdata->mode=THERMAL_DEVICE_ENABLED;
1015 if(tmp_level)
1016 kfree(tmp_level);
1017 printk("%s, %d\n", __func__, __LINE__);
1018 return pdata;
1019 }
1020err:
1021 if(tmp_level)
1022 kfree(tmp_level);
1023 if(pdata)
1024 kfree(pdata);
1025 pdata= NULL;
1026 return pdata;
1027}
1028
1029static struct amlogic_thermal_platform_data * amlogic_thermal_initialize(struct platform_device *pdev, int trim_flag)
1030{
1031 struct amlogic_thermal_platform_data *pdata=NULL;
1032 pdata=amlogic_thermal_init_from_dts(pdev, trim_flag);
1033 printk("%s, %d, pdata:%p\n", __func__, __LINE__, pdata);
1034 return pdata;
1035}
1036
1037static const struct of_device_id amlogic_thermal_match[] = {
1038 {
1039 .compatible = "amlogic, amlogic-thermal",
1040 },
1041 {},
1042};
1043
1044#ifdef CONFIG_HIBERNATION
1045static int amlogic_thermal_freeze(struct device *dev)
1046{
1047 return 0;
1048}
1049
1050static int amlogic_thermal_thaw(struct device *dev)
1051{
1052 return 0;
1053}
1054
1055static int amlogic_thermal_restore(struct device *dev)
1056{
1057 thermal_firmware_init();
1058
1059 return 0;
1060}
1061
1062static struct dev_pm_ops amlogic_theraml_pm = {
1063 .freeze = amlogic_thermal_freeze,
1064 .thaw = amlogic_thermal_thaw,
1065 .restore = amlogic_thermal_restore,
1066};
1067#endif
1068
1069static int amlogic_thermal_probe(struct platform_device *pdev)
1070{
1071 int ret, trim_flag;
1072 struct amlogic_thermal_platform_data *pdata=NULL;
1073
1074 ret=thermal_firmware_init();
1075 if(ret<0){
1076 printk("%s, this chip is not trimmed, can't use thermal\n", __func__);
1077 trim_flag = 0;
1078 return -ENODEV;
1079 }else{
1080 printk("%s, this chip is trimmed, use thermal\n", __func__);
1081 trim_flag = 1;
1082 }
1083
1084 dev_info(&pdev->dev, "amlogic thermal probe start\n");
1085 pdata = amlogic_thermal_initialize(pdev, trim_flag);
1086 if (!pdata) {
1087 dev_err(&pdev->dev, "Failed to initialize thermal\n");
1088 goto err;
1089 }
1090 mutex_init(&pdata->lock);
1091 pdev->dev.platform_data=pdata;
1092 platform_set_drvdata(pdev, pdata);
1093 ret = amlogic_register_thermal(pdata, pdev);
1094 if (ret) {
1095 dev_err(&pdev->dev, "Failed to register thermal interface\n");
1096 goto err;
1097 }
1098 dev_info(&pdev->dev, "amlogic thermal probe done\n");
1099 return 0;
1100err:
1101 platform_set_drvdata(pdev, NULL);
1102 return ret;
1103}
1104
1105static int amlogic_thermal_remove(struct platform_device *pdev)
1106{
1107 struct amlogic_thermal_platform_data *pdata = platform_get_drvdata(pdev);
1108
1109 aml_virtual_thermal_remove(pdata);
1110
1111 amlogic_unregister_thermal(pdata);
1112
1113 platform_set_drvdata(pdev, NULL);
1114
1115 return 0;
1116}
1117
1118struct platform_driver amlogic_thermal_driver = {
1119 .driver = {
1120 .name = "amlogic-thermal",
1121 .owner = THIS_MODULE,
1122 #ifdef CONFIG_HIBERNATION
1123 .pm = &amlogic_theraml_pm,
1124 #endif
1125 .of_match_table = of_match_ptr(amlogic_thermal_match),
1126 },
1127 .probe = amlogic_thermal_probe,
1128 .remove = amlogic_thermal_remove,
1129};
1130
1131void *aml_get_cdevdata(struct thermal_cooling_device *cdev)
1132{
1133 return cdev->devdata;
1134}
1135EXPORT_SYMBOL(aml_get_cdevdata);
1136
1137void aml_set_cdev_update(struct thermal_cooling_device *cdev, bool update)
1138{
1139 cdev->updated = update;
1140}
1141EXPORT_SYMBOL(aml_set_cdev_update);
1142
1143void aml_cdev_lockop(struct thermal_cooling_device *cdev, bool lock)
1144{
1145 if (lock) {
1146 thermal_lock(&cdev->lock);
1147 } else {
1148 thermal_unlock(&cdev->lock);
1149 }
1150}
1151EXPORT_SYMBOL(aml_cdev_lockop);
1152
1153void aml_cdev_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *ret)
1154{
1155 cdev->ops->get_cur_state(cdev, ret);
1156}
1157EXPORT_SYMBOL(aml_cdev_get_cur_state);
1158
1159static int __init amlogic_thermal_driver_init(void)
1160{
1161 return platform_driver_register(&(amlogic_thermal_driver));
1162}
1163late_initcall(amlogic_thermal_driver_init);
1164static void __exit amlogic_thermal_driver_exit(void)
1165{
1166 platform_driver_unregister(&(amlogic_thermal_driver) );
1167}
1168module_exit(amlogic_thermal_driver_exit);
1169
1170MODULE_DESCRIPTION("amlogic thermal Driver");
1171MODULE_AUTHOR("Amlogic SH platform team");
1172MODULE_ALIAS("platform:amlogic-thermal");
1173MODULE_LICENSE("GPL");
1174
1175