ARM: tegra: Object based balanced throttling
[linux-2.6.git] / arch / arm / mach-tegra / tegra3_thermal.c
1 /*
2  * arch/arm/mach-tegra/tegra3_thermal.c
3  *
4  * Copyright (C) 2010-2012 NVIDIA Corporation.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/cpufreq.h>
19 #include <linux/delay.h>
20 #include <linux/mutex.h>
21 #include <linux/init.h>
22 #include <linux/err.h>
23 #include <linux/clk.h>
24 #include <linux/debugfs.h>
25 #include <linux/seq_file.h>
26 #include <linux/uaccess.h>
27 #include <linux/thermal.h>
28 #include <linux/module.h>
29 #include <mach/thermal.h>
30 #include <mach/edp.h>
31 #include <linux/slab.h>
32
33 #include "clock.h"
34 #include "cpu-tegra.h"
35 #include "dvfs.h"
36
37 #define MAX_ZONES (16)
38
39 struct tegra_thermal {
40         struct tegra_thermal_device *device;
41         long temp_shutdown_tj;
42 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
43         long temp_throttle_tj;
44         int tc1;
45         int tc2;
46         long passive_delay;
47 #endif
48 #ifdef CONFIG_TEGRA_EDP_LIMITS
49         int edp_thermal_zone_val;
50         long edp_offset;
51         long hysteresis_edp;
52 #endif
53         struct mutex mutex;
54 };
55
56 static struct tegra_thermal thermal_state = {
57         .device = NULL,
58 #ifdef CONFIG_TEGRA_EDP_LIMITS
59         .edp_thermal_zone_val = -1,
60 #endif
61 };
62 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
63 static struct throttle_table tj_bthrot_table[] = {
64         {      0, 1000 },
65         { 640000, 1000 },
66         { 640000, 1000 },
67         { 640000, 1000 },
68         { 640000, 1000 },
69         { 640000, 1000 },
70         { 760000, 1000 },
71         { 760000, 1050 },
72         {1000000, 1050 },
73         {1000000, 1100 },
74 };
75
76 static struct balanced_throttle *tj_bthrot;
77
78 #define TJ_BALANCED_THROTTLE_ID         (0)
79 #endif
80
81 #ifdef CONFIG_TEGRA_EDP_LIMITS
82 static inline long edp2tj(struct tegra_thermal *thermal,
83                                 long edp_temp)
84 {
85         return edp_temp + thermal->edp_offset;
86 }
87
88 static inline long tj2edp(struct tegra_thermal *thermal,
89                                 long temp_tj)
90 {
91         return temp_tj - thermal->edp_offset;
92 }
93 #endif
94
95 static inline long dev2tj(struct tegra_thermal_device *dev,
96                                 long dev_temp)
97 {
98         return dev_temp + dev->offset;
99 }
100
101 static inline long tj2dev(struct tegra_thermal_device *dev,
102                                 long tj_temp)
103 {
104         return tj_temp - dev->offset;
105 }
106
107 static int tegra_thermal_get_tj_temp(long *tj_temp)
108 {
109         long temp_dev;
110         struct tegra_thermal *thermal = &thermal_state;
111
112         if (!thermal->device)
113                 return -1;
114
115         thermal->device->get_temp(thermal->device->data,
116                                         &temp_dev);
117         *tj_temp = dev2tj(thermal->device, temp_dev);
118
119         return 0;
120 }
121
122 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
123
124 static int tegra_thermal_zone_bind(struct thermal_zone_device *thz,
125                                 struct thermal_cooling_device *cdevice) {
126
127         struct balanced_throttle *bthrot = cdevice->devdata;
128         struct tegra_thermal_device *device = thz->devdata;
129
130         if ((bthrot->id == TJ_BALANCED_THROTTLE_ID) &&
131                 (device == thermal_state.device))
132                 return thermal_zone_bind_cooling_device(thz, 0, cdevice);
133
134         return 0;
135 }
136
137 static int tegra_thermal_zone_unbind(struct thermal_zone_device *thz,
138                                 struct thermal_cooling_device *cdevice) {
139         struct balanced_throttle *bthrot = cdevice->devdata;
140         struct tegra_thermal_device *device = thz->devdata;
141
142         if ((bthrot->id == TJ_BALANCED_THROTTLE_ID) &&
143                 (device == thermal_state.device))
144                 return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
145
146         return 0;
147 }
148
149 static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
150                                         unsigned long *temp)
151 {
152         struct tegra_thermal_device *device = thz->devdata;
153
154         device->get_temp(device->data, temp);
155
156         return 0;
157 }
158
159 static int tegra_thermal_zone_get_trip_type(
160                         struct thermal_zone_device *thermal,
161                         int trip,
162                         enum thermal_trip_type *type) {
163         if (trip != 0)
164                 return -EINVAL;
165
166         *type = THERMAL_TRIP_PASSIVE;
167
168         return 0;
169 }
170
171 static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
172                                         int trip,
173                                         unsigned long *temp) {
174         struct tegra_thermal_device *device = thz->devdata;
175
176         if (trip != 0)
177                 return -EINVAL;
178
179         *temp = tj2dev(device, thermal_state.temp_throttle_tj);
180
181         return 0;
182 }
183
184 static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
185         .bind = tegra_thermal_zone_bind,
186         .unbind = tegra_thermal_zone_unbind,
187         .get_temp = tegra_thermal_zone_get_temp,
188         .get_trip_type = tegra_thermal_zone_get_trip_type,
189         .get_trip_temp = tegra_thermal_zone_get_trip_temp,
190 };
191 #endif
192
193 /* Make sure this function remains stateless */
194 void tegra_thermal_alert(void *data)
195 {
196         struct tegra_thermal *thermal = data;
197         long temp_tj;
198         long lo_limit_throttle_tj, hi_limit_throttle_tj;
199         long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0;
200         long temp_low_dev, temp_low_tj;
201         int lo_limit_tj = 0, hi_limit_tj = 0;
202 #ifdef CONFIG_TEGRA_EDP_LIMITS
203         const struct tegra_edp_limits *z;
204         int zones_sz;
205         int i;
206 #endif
207
208         if (thermal != &thermal_state)
209                 BUG();
210
211         mutex_lock(&thermal_state.mutex);
212
213 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
214         if (thermal->device->thz) {
215                 if (!thermal->device->thz->passive)
216                         thermal_zone_device_update(thermal->device->thz);
217         }
218 #endif
219
220         /* Convert all temps to tj and then do all work/logic in terms of
221            tj in order to avoid confusion */
222         if (tegra_thermal_get_tj_temp(&temp_tj))
223                 goto done;
224         thermal->device->get_temp_low(thermal->device, &temp_low_dev);
225         temp_low_tj = dev2tj(thermal->device, temp_low_dev);
226
227         lo_limit_throttle_tj = temp_low_tj;
228         hi_limit_throttle_tj = thermal->temp_shutdown_tj;
229
230 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
231         hi_limit_throttle_tj = thermal->temp_throttle_tj;
232
233         if (temp_tj > thermal->temp_throttle_tj) {
234                 lo_limit_throttle_tj = thermal->temp_throttle_tj;
235                 hi_limit_throttle_tj = thermal->temp_shutdown_tj;
236         }
237 #endif
238
239 #ifdef CONFIG_TEGRA_EDP_LIMITS
240         tegra_get_cpu_edp_limits(&z, &zones_sz);
241
242 /* edp table based off of tdiode measurements */
243 #define EDP_TEMP_TJ(_index)     edp2tj(thermal, z[_index].temperature * 1000)
244
245         if (temp_tj < EDP_TEMP_TJ(0)) {
246                 lo_limit_edp_tj = temp_low_tj;
247                 hi_limit_edp_tj = EDP_TEMP_TJ(0);
248         } else if (temp_tj >= EDP_TEMP_TJ(zones_sz-1)) {
249                 lo_limit_edp_tj = EDP_TEMP_TJ(zones_sz-1) -
250                                         thermal->hysteresis_edp;
251                 hi_limit_edp_tj = thermal->temp_shutdown_tj;
252         } else {
253                 for (i = 0; (i + 1) < zones_sz; i++) {
254                         if ((temp_tj >= EDP_TEMP_TJ(i)) &&
255                                 (temp_tj < EDP_TEMP_TJ(i+1))) {
256                                 lo_limit_edp_tj = EDP_TEMP_TJ(i) -
257                                                         thermal->hysteresis_edp;
258                                 hi_limit_edp_tj = EDP_TEMP_TJ(i+1);
259                                 break;
260                         }
261                 }
262         }
263 #undef EDP_TEMP_TJ
264 #else
265         lo_limit_edp_tj = temp_low_tj;
266         hi_limit_edp_tj = thermal->temp_shutdown_tj;
267 #endif
268
269         /* Get smallest window size */
270         lo_limit_tj = max(lo_limit_throttle_tj, lo_limit_edp_tj);
271         hi_limit_tj = min(hi_limit_throttle_tj, hi_limit_edp_tj);
272
273         thermal->device->set_limits(thermal->device->data,
274                                         tj2dev(thermal->device, lo_limit_tj),
275                                         tj2dev(thermal->device, hi_limit_tj));
276
277 #ifdef CONFIG_TEGRA_EDP_LIMITS
278         /* inform edp governor */
279         if (thermal->edp_thermal_zone_val != temp_tj)
280                 tegra_edp_update_thermal_zone(tj2edp(thermal, temp_tj)/1000);
281
282         thermal->edp_thermal_zone_val = temp_tj;
283 #endif
284
285 done:
286         mutex_unlock(&thermal_state.mutex);
287 }
288
289
290
291 int tegra_thermal_set_device(struct tegra_thermal_device *device)
292 {
293 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
294         struct thermal_zone_device *thz;
295 #endif
296
297         /* only support one device */
298         if (thermal_state.device)
299                 return -EINVAL;
300
301         thermal_state.device = device;
302
303 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
304         thz = thermal_zone_device_register(device->name,
305                                         1, /* trips */
306                                         device,
307                                         &tegra_thermal_zone_ops,
308                                         thermal_state.tc1, /* dT/dt */
309                                         thermal_state.tc2, /* throttle */
310                                         thermal_state.passive_delay,
311                                         0); /* polling delay */
312         if (IS_ERR_OR_NULL(thz))
313                 return -ENODEV;
314
315         device->thz = thz;
316
317         tj_bthrot = balanced_throttle_register(
318                                         TJ_BALANCED_THROTTLE_ID,
319                                         tj_bthrot_table,
320                                         ARRAY_SIZE(tj_bthrot_table));
321         if (IS_ERR_OR_NULL(tj_bthrot))
322                 return -ENODEV;
323
324 #endif
325         device->set_alert(device->data,
326                                 tegra_thermal_alert,
327                                 &thermal_state);
328
329         device->set_shutdown_temp(device->data,
330                                 tj2dev(device, thermal_state.temp_shutdown_tj));
331
332
333         /* initialize limits */
334         tegra_thermal_alert(&thermal_state);
335
336         return 0;
337 }
338
339 int __init tegra_thermal_init(struct tegra_thermal_data *data)
340 {
341 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
342         thermal_state.tc1 = data->tc1;
343         thermal_state.tc2 = data->tc2;
344         thermal_state.passive_delay = data->passive_delay;
345         thermal_state.temp_throttle_tj = data->temp_throttle +
346                                                 data->temp_offset;
347 #endif
348         mutex_init(&thermal_state.mutex);
349 #ifdef CONFIG_TEGRA_EDP_LIMITS
350         thermal_state.edp_offset = data->edp_offset;
351         thermal_state.hysteresis_edp = data->hysteresis_edp;
352 #endif
353         thermal_state.temp_shutdown_tj = data->temp_shutdown +
354                                                 data->temp_offset;
355
356         return 0;
357 }
358
359 int tegra_thermal_exit(void)
360 {
361 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
362         if (thermal_state.device->thz)
363                 thermal_zone_device_unregister(thermal_state.device->thz);
364 #endif
365
366         return 0;
367 }
368
369 #ifdef CONFIG_DEBUG_FS
370
371 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
372 static int tegra_thermal_throttle_temp_tj_set(void *data, u64 val)
373 {
374         mutex_lock(&thermal_state.mutex);
375         thermal_state.temp_throttle_tj = val;
376         mutex_unlock(&thermal_state.mutex);
377
378         tegra_thermal_alert(&thermal_state);
379
380         return 0;
381 }
382
383 static int tegra_thermal_throttle_temp_tj_get(void *data, u64 *val)
384 {
385         *val = (u64)thermal_state.temp_throttle_tj;
386         return 0;
387 }
388
389 DEFINE_SIMPLE_ATTRIBUTE(throttle_temp_tj_fops,
390                         tegra_thermal_throttle_temp_tj_get,
391                         tegra_thermal_throttle_temp_tj_set,
392                         "%llu\n");
393 #endif
394
395 static int tegra_thermal_shutdown_temp_tj_set(void *data, u64 val)
396 {
397         thermal_state.temp_shutdown_tj = val;
398
399         if (thermal_state.device)
400                 thermal_state.device->set_shutdown_temp(
401                                 thermal_state.device->data,
402                                 tj2dev(thermal_state.device,
403                                         thermal_state.temp_shutdown_tj));
404
405         tegra_thermal_alert(&thermal_state);
406
407         return 0;
408 }
409
410 static int tegra_thermal_shutdown_temp_tj_get(void *data, u64 *val)
411 {
412         *val = (u64)thermal_state.temp_shutdown_tj;
413         return 0;
414 }
415
416 DEFINE_SIMPLE_ATTRIBUTE(shutdown_temp_tj_fops,
417                         tegra_thermal_shutdown_temp_tj_get,
418                         tegra_thermal_shutdown_temp_tj_set,
419                         "%llu\n");
420
421
422 static int tegra_thermal_temp_tj_get(void *data, u64 *val)
423 {
424         long temp_tj;
425
426         if (tegra_thermal_get_tj_temp(&temp_tj))
427                 temp_tj = -1;
428
429         *val = (u64)temp_tj;
430
431         return 0;
432 }
433
434 DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
435                         tegra_thermal_temp_tj_get,
436                         NULL,
437                         "%llu\n");
438
439 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
440 static int tegra_thermal_tc1_set(void *data, u64 val)
441 {
442         thermal_state.device->thz->tc1 = val;
443         return 0;
444 }
445
446 static int tegra_thermal_tc1_get(void *data, u64 *val)
447 {
448         *val = (u64)thermal_state.device->thz->tc1;
449         return 0;
450 }
451
452 DEFINE_SIMPLE_ATTRIBUTE(tc1_fops,
453                         tegra_thermal_tc1_get,
454                         tegra_thermal_tc1_set,
455                         "%llu\n");
456
457 static int tegra_thermal_tc2_set(void *data, u64 val)
458 {
459         thermal_state.device->thz->tc2 = val;
460         return 0;
461 }
462
463 static int tegra_thermal_tc2_get(void *data, u64 *val)
464 {
465         *val = (u64)thermal_state.device->thz->tc2;
466         return 0;
467 }
468
469 DEFINE_SIMPLE_ATTRIBUTE(tc2_fops,
470                         tegra_thermal_tc2_get,
471                         tegra_thermal_tc2_set,
472                         "%llu\n");
473
474 static int tegra_thermal_passive_delay_set(void *data, u64 val)
475 {
476         thermal_state.device->thz->passive_delay = val;
477         return 0;
478 }
479
480 static int tegra_thermal_passive_delay_get(void *data, u64 *val)
481 {
482         *val = (u64)thermal_state.device->thz->passive_delay;
483         return 0;
484 }
485
486 DEFINE_SIMPLE_ATTRIBUTE(passive_delay_fops,
487                         tegra_thermal_passive_delay_get,
488                         tegra_thermal_passive_delay_set,
489                         "%llu\n");
490 #endif
491
492
493 static struct dentry *thermal_debugfs_root;
494
495 static int __init tegra_thermal_debug_init(void)
496 {
497         thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
498
499         if (!debugfs_create_file("shutdown_temp_tj", 0644, thermal_debugfs_root,
500                                  NULL, &shutdown_temp_tj_fops))
501                 goto err_out;
502
503         if (!debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
504                                  NULL, &temp_tj_fops))
505                 goto err_out;
506
507 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
508         if (!debugfs_create_file("throttle_temp_tj", 0644, thermal_debugfs_root,
509                                  NULL, &throttle_temp_tj_fops))
510                 goto err_out;
511
512         if (!debugfs_create_file("tc1", 0644, thermal_debugfs_root,
513                                  NULL, &tc1_fops))
514                 goto err_out;
515
516         if (!debugfs_create_file("tc2", 0644, thermal_debugfs_root,
517                                  NULL, &tc2_fops))
518                 goto err_out;
519
520         if (!debugfs_create_file("passive_delay", 0644, thermal_debugfs_root,
521                                  NULL, &passive_delay_fops))
522                 goto err_out;
523 #endif
524
525         return 0;
526
527 err_out:
528         debugfs_remove_recursive(thermal_debugfs_root);
529         return -ENOMEM;
530 }
531
532 late_initcall(tegra_thermal_debug_init);
533 #endif