thermal: soctherm: use thermal_trip_info struct in soctherm driver
[linux-2.6.git] / arch / arm / mach-tegra / tegra11_soctherm.c
1 /*
2  * arch/arm/mach-tegra/tegra11_soctherm.c
3  *
4  * Copyright (C) 2011-2013 NVIDIA Corporation
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  */
20
21 #include <linux/debugfs.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/list.h>
25 #include <linux/spinlock.h>
26 #include <linux/delay.h>
27 #include <linux/err.h>
28 #include <linux/io.h>
29 #include <linux/clk.h>
30 #include <linux/cpufreq.h>
31 #include <linux/seq_file.h>
32 #include <linux/irq.h>
33 #include <linux/interrupt.h>
34 #include <linux/slab.h>
35 #include <linux/suspend.h>
36 #include <linux/uaccess.h>
37 #include <linux/thermal.h>
38 #include <linux/platform_data/thermal_sensors.h>
39
40 #include <mach/tegra_fuse.h>
41 #include <mach/iomap.h>
42
43 #include "tegra11_soctherm.h"
44
45 /* Min temp granularity specified as X in 2^X.
46  * -1: Hi precision option: 2^-1 = 0.5C (default)
47  *  0: Lo precision option: 2^0  = 1.0C (for use if therm_a/b overflows 16 bits)
48  */
49 static int soc_therm_precision = -1;
50
51 #define TS_TSENSE_REGS_SIZE             0x20
52 #define TS_TSENSE_REG_OFFSET(reg, ts)   ((reg) + ((ts) * TS_TSENSE_REGS_SIZE))
53
54 #define CTL_LVL0_CPU0                   0x0
55 #define CTL_LVL0_CPU0_UP_THRESH_SHIFT   17
56 #define CTL_LVL0_CPU0_UP_THRESH_MASK    0xff
57 #define CTL_LVL0_CPU0_DN_THRESH_SHIFT   9
58 #define CTL_LVL0_CPU0_DN_THRESH_MASK    0xff
59 #define CTL_LVL0_CPU0_EN_SHIFT          8
60 #define CTL_LVL0_CPU0_EN_MASK           0x1
61 #define CTL_LVL0_CPU0_CPU_THROT_SHIFT   5
62 #define CTL_LVL0_CPU0_CPU_THROT_MASK    0x3
63 #define CTL_LVL0_CPU0_MEM_THROT_SHIFT   2
64 #define CTL_LVL0_CPU0_MEM_THROT_MASK    0x1
65 #define CTL_LVL0_CPU0_STATUS_SHIFT      0
66 #define CTL_LVL0_CPU0_STATUS_MASK       0x3
67
68 #define THERMTRIP                       0x80
69 #define THERMTRIP_ANY_EN_SHIFT          28
70 #define THERMTRIP_ANY_EN_MASK           0x1
71 #define THERMTRIP_MEM_EN_SHIFT          27
72 #define THERMTRIP_MEM_EN_MASK           0x1
73 #define THERMTRIP_GPU_EN_SHIFT          26
74 #define THERMTRIP_GPU_EN_MASK           0x1
75 #define THERMTRIP_CPU_EN_SHIFT          25
76 #define THERMTRIP_CPU_EN_MASK           0x1
77 #define THERMTRIP_TSENSE_EN_SHIFT       24
78 #define THERMTRIP_TSENSE_EN_MASK        0x1
79 #define THERMTRIP_GPUMEM_THRESH_SHIFT   16
80 #define THERMTRIP_GPUMEM_THRESH_MASK    0xff
81 #define THERMTRIP_CPU_THRESH_SHIFT      8
82 #define THERMTRIP_CPU_THRESH_MASK       0xff
83 #define THERMTRIP_TSENSE_THRESH_SHIFT   0
84 #define THERMTRIP_TSENSE_THRESH_MASK    0xff
85
86 #define TS_CPU0_CONFIG0                         0xc0
87 #define TS_CPU0_CONFIG0_TALL_SHIFT              8
88 #define TS_CPU0_CONFIG0_TALL_MASK               0xfffff
89 #define TS_CPU0_CONFIG0_TCALC_OVER_SHIFT        4
90 #define TS_CPU0_CONFIG0_TCALC_OVER_MASK         0x1
91 #define TS_CPU0_CONFIG0_OVER_SHIFT              3
92 #define TS_CPU0_CONFIG0_OVER_MASK               0x1
93 #define TS_CPU0_CONFIG0_CPTR_OVER_SHIFT         2
94 #define TS_CPU0_CONFIG0_CPTR_OVER_MASK          0x1
95 #define TS_CPU0_CONFIG0_STOP_SHIFT              0
96 #define TS_CPU0_CONFIG0_STOP_MASK               0x1
97
98 #define TS_CPU0_CONFIG1                 0xc4
99 #define TS_CPU0_CONFIG1_EN_SHIFT        31
100 #define TS_CPU0_CONFIG1_EN_MASK         0x1
101 #define TS_CPU0_CONFIG1_TIDDQ_SHIFT     15
102 #define TS_CPU0_CONFIG1_TIDDQ_MASK      0x3f
103 #define TS_CPU0_CONFIG1_TEN_COUNT_SHIFT 24
104 #define TS_CPU0_CONFIG1_TEN_COUNT_MASK  0x3f
105 #define TS_CPU0_CONFIG1_TSAMPLE_SHIFT   0
106 #define TS_CPU0_CONFIG1_TSAMPLE_MASK    0x3ff
107
108 #define TS_CPU0_CONFIG2                 0xc8
109 #define TS_CPU0_CONFIG2_THERM_A_SHIFT   16
110 #define TS_CPU0_CONFIG2_THERM_A_MASK    0xffff
111 #define TS_CPU0_CONFIG2_THERM_B_SHIFT   0
112 #define TS_CPU0_CONFIG2_THERM_B_MASK    0xffff
113
114 #define TS_CPU0_STATUS0                 0xcc
115 #define TS_CPU0_STATUS0_VALID_SHIFT     31
116 #define TS_CPU0_STATUS0_VALID_MASK      0x1
117 #define TS_CPU0_STATUS0_CAPTURE_SHIFT   0
118 #define TS_CPU0_STATUS0_CAPTURE_MASK    0xffff
119
120 #define TS_CPU0_STATUS1                         0xd0
121 #define TS_CPU0_STATUS1_TEMP_VALID_SHIFT        31
122 #define TS_CPU0_STATUS1_TEMP_VALID_MASK         0x1
123 #define TS_CPU0_STATUS1_TEMP_SHIFT              0
124 #define TS_CPU0_STATUS1_TEMP_MASK               0xffff
125
126 #define TS_CPU0_STATUS2                 0xd4
127
128 #define TS_PDIV                         0x1c0
129 #define TS_PDIV_CPU_SHIFT               12
130 #define TS_PDIV_CPU_MASK                0xf
131 #define TS_PDIV_GPU_SHIFT               8
132 #define TS_PDIV_GPU_MASK                0xf
133 #define TS_PDIV_MEM_SHIFT               4
134 #define TS_PDIV_MEM_MASK                0xf
135 #define TS_PDIV_PLLX_SHIFT              0
136 #define TS_PDIV_PLLX_MASK               0xf
137
138 #define TS_TEMP1                        0x1c8
139 #define TS_TEMP1_CPU_TEMP_SHIFT         16
140 #define TS_TEMP1_CPU_TEMP_MASK          0xffff
141 #define TS_TEMP1_GPU_TEMP_SHIFT         0
142 #define TS_TEMP1_GPU_TEMP_MASK          0xffff
143
144 #define TS_TEMP2                        0x1cc
145 #define TS_TEMP2_MEM_TEMP_SHIFT         16
146 #define TS_TEMP2_MEM_TEMP_MASK          0xffff
147 #define TS_TEMP2_PLLX_TEMP_SHIFT        0
148 #define TS_TEMP2_PLLX_TEMP_MASK         0xffff
149
150 #define UP_STATS_L0             0x10
151 #define DN_STATS_L0             0x14
152
153 #define INTR_STATUS                     0x84
154 #define INTR_STATUS_CD0_SHIFT           9
155 #define INTR_STATUS_CD0_MASK            0x1
156 #define INTR_STATUS_CU0_SHIFT           8
157 #define INTR_STATUS_CU0_MASK            0x1
158
159 #define INTR_EN                 0x88
160 #define INTR_EN_MU0_SHIFT       24
161 #define INTR_EN_MD0_SHIFT       25
162 #define INTR_EN_CU0_SHIFT       8
163 #define INTR_EN_CD0_SHIFT       9
164
165 #define INTR_DIS                0x8c
166 #define LOCK_CTL                0x90
167 #define STATS_CTL               0x94
168
169 #define THROT_GLOBAL_CFG                0x400
170
171 #define CPU_PSKIP_STATUS                        0x418
172 #define CPU_PSKIP_STATUS_M_SHIFT                12
173 #define CPU_PSKIP_STATUS_M_MASK                 0xff
174 #define CPU_PSKIP_STATUS_N_SHIFT                4
175 #define CPU_PSKIP_STATUS_N_MASK                 0xff
176 #define CPU_PSKIP_STATUS_ENABLED_SHIFT          0
177 #define CPU_PSKIP_STATUS_ENABLED_MASK           0x1
178
179 #define THROT_PRIORITY_LOCK                     0x424
180 #define THROT_PRIORITY_LOCK_PRIORITY_SHIFT      0
181 #define THROT_PRIORITY_LOCK_PRIORITY_MASK       0xff
182
183 #define THROT_STATUS                            0x428
184 #define THROT_STATUS_BREACH_SHIFT               12
185 #define THROT_STATUS_BREACH_MASK                0x1
186 #define THROT_STATUS_STATE_SHIFT                4
187 #define THROT_STATUS_STATE_MASK                 0xff
188 #define THROT_STATUS_ENABLED_SHIFT              0
189 #define THROT_STATUS_ENABLED_MASK               0x1
190
191 #define THROT_PSKIP_CTRL_LITE_CPU                       0x430
192 #define THROT_PSKIP_CTRL_ENABLE_SHIFT           31
193 #define THROT_PSKIP_CTRL_ENABLE_MASK            0x1
194 #define THROT_PSKIP_CTRL_DIVIDEND_SHIFT 8
195 #define THROT_PSKIP_CTRL_DIVIDEND_MASK          0xff
196 #define THROT_PSKIP_CTRL_DIVISOR_SHIFT          0
197 #define THROT_PSKIP_CTRL_DIVISOR_MASK           0xff
198
199 #define THROT_PSKIP_RAMP_LITE_CPU                       0x434
200 #define THROT_PSKIP_RAMP_DURATION_SHIFT 8
201 #define THROT_PSKIP_RAMP_DURATION_MASK          0xffff
202 #define THROT_PSKIP_RAMP_STEP_SHIFT             0
203 #define THROT_PSKIP_RAMP_STEP_MASK              0xff
204
205 #define THROT_LITE_PRIORITY                     0x444
206 #define THROT_LITE_PRIORITY_PRIORITY_SHIFT      0
207 #define THROT_LITE_PRIORITY_PRIORITY_MASK       0xff
208
209 #define THROT_OFFSET                            0x30
210
211 #define FUSE_BASE_CP_SHIFT      0
212 #define FUSE_BASE_CP_MASK       0x3ff
213 #define FUSE_BASE_FT_SHIFT      16
214 #define FUSE_BASE_FT_MASK       0x7ff
215 #define FUSE_SHIFT_CP_SHIFT     10
216 #define FUSE_SHIFT_CP_MASK      0x3f
217 #define FUSE_SHIFT_CP_BITS      6
218 #define FUSE_SHIFT_FT_SHIFT     27
219 #define FUSE_SHIFT_FT_MASK      0x1f
220 #define FUSE_SHIFT_FT_BITS      5
221
222 #define FUSE_TSENSOR_CALIB_FT_SHIFT     13
223 #define FUSE_TSENSOR_CALIB_FT_MASK      0x1fff
224 #define FUSE_TSENSOR_CALIB_CP_SHIFT     0
225 #define FUSE_TSENSOR_CALIB_CP_MASK      0x1fff
226 #define FUSE_TSENSOR_CALIB_BITS         13
227
228 #define THROT_PSKIP_CTRL(throt, dev)            (THROT_PSKIP_CTRL_LITE_CPU + \
229                                                 (THROT_OFFSET * throt) + \
230                                                 (8 * dev))
231 #define THROT_PSKIP_RAMP(throt, dev)            (THROT_PSKIP_RAMP_LITE_CPU + \
232                                                 (THROT_OFFSET * throt) + \
233                                                 (8 * dev))
234
235 #define PSKIP_CTRL_OC1_CPU                      0x490
236
237 #define REG_SET(r,_name,val) \
238         ((r)&~(_name##_MASK<<_name##_SHIFT))|(((val)&_name##_MASK)<<_name##_SHIFT)
239
240 #define REG_GET(r,_name) \
241         (((r)&(_name##_MASK<<_name##_SHIFT))>>_name##_SHIFT)
242
243 #define MAKE_SIGNED32(val, nb) \
244         ((s32)(val) << (32 - (nb)) >> (32 - (nb)))
245
246 static void __iomem *reg_soctherm_base = IO_ADDRESS(TEGRA_SOCTHERM_BASE);
247 static void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
248 static void __iomem *clk_reset_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
249
250 #define clk_reset_writel(value, reg) \
251         __raw_writel(value, (u32)clk_reset_base + (reg))
252 #define clk_reset_readl(reg) __raw_readl((u32)clk_reset_base + (reg))
253
254 #define pmc_writel(value, reg) __raw_writel(value, (u32)pmc_base + (reg))
255 #define pmc_readl(reg) __raw_readl((u32)pmc_base + (reg))
256
257 #define soctherm_writel(value, reg) \
258         __raw_writel(value, (u32)reg_soctherm_base + (reg))
259 #define soctherm_readl(reg) \
260         __raw_readl((u32)reg_soctherm_base + (reg))
261
262 #define max4(a, b, c, d)        max(max(a, b), max(c, d))
263
264 static struct soctherm_platform_data plat_data;
265
266 /*
267  * Remove this flag once this "driver" is structured as a platform driver and
268  * the board files calls platform_device_register instead of directly calling
269  * tegra11_soctherm_init(). See nvbug 1206311.
270  */
271 static bool soctherm_init_platform_done = false;
272
273 static struct clk *soctherm_clk;
274 static struct clk *tsensor_clk;
275
276 #ifdef CONFIG_THERMAL
277 static struct thermal_zone_device *thz[THERM_SIZE];
278 #endif
279 static struct workqueue_struct *workqueue;
280 static struct work_struct work;
281
282 static u32 fuse_calib_base_cp;
283 static u32 fuse_calib_base_ft;
284 static s32 actual_temp_cp;
285 static s32 actual_temp_ft;
286
287 static char *therm_names[] = {
288         [THERM_CPU] = "CPU",
289         [THERM_MEM] = "MEM",
290         [THERM_GPU] = "GPU",
291         [THERM_PLL] = "PLL",
292 };
293
294 static char *sensor_names[] = {
295         [TSENSE_CPU0] = "cpu0",
296         [TSENSE_CPU1] = "cpu1",
297         [TSENSE_CPU2] = "cpu2",
298         [TSENSE_CPU3] = "cpu3",
299         [TSENSE_MEM0] = "mem0",
300         [TSENSE_MEM1] = "mem1",
301         [TSENSE_GPU]  = "gpu0",
302         [TSENSE_PLLX] = "pllx",
303 };
304
305 static int sensor2tsensorcalib[] = {
306         [TSENSE_CPU0] = 0,
307         [TSENSE_CPU1] = 1,
308         [TSENSE_CPU2] = 2,
309         [TSENSE_CPU3] = 3,
310         [TSENSE_MEM0] = 5,
311         [TSENSE_MEM1] = 6,
312         [TSENSE_GPU]  = 4,
313         [TSENSE_PLLX] = 7,
314 };
315
316 static inline s64 div64_s64_precise(s64 a, s32 b)
317 {
318         s64 r, al;
319
320         /* scale up for increased precision in division */
321         al = a << 16;
322
323         r = div64_s64((al * 2) + 1, 2 * b);
324         return r >> 16;
325 }
326
327 static inline long temp_translate(int readback)
328 {
329         int abs = readback >> 8;
330         int lsb = (readback & 0x80) >> 7;
331         int sign = readback & 0x01 ? -1 : 1;
332
333         if (soc_therm_precision == -1)
334                 return (abs * 1000 + lsb * 500) * sign;
335         else
336                 return (abs * 2000 + lsb * 1000) * sign;
337 }
338
339 #ifdef CONFIG_THERMAL
340 static int soctherm_set_limits(enum soctherm_therm_id therm,
341                                 long lo_limit, long hi_limit)
342 {
343         u32 r = soctherm_readl(CTL_LVL0_CPU0);
344         r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, lo_limit);
345         r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, hi_limit);
346         soctherm_writel(r, CTL_LVL0_CPU0);
347
348         soctherm_writel(1<<INTR_EN_CU0_SHIFT, INTR_EN);
349         soctherm_writel(1<<INTR_EN_CD0_SHIFT, INTR_EN);
350         return 0;
351 }
352
353 static void soctherm_update(void)
354 {
355         long temp, trip_temp, low_temp = 0, high_temp = 128000;
356         int i, count;
357
358         if (!soctherm_init_platform_done)
359                 return;
360
361         for (i = 0; i < THERM_SIZE; i++) {
362                 if (!thz[i])
363                         continue;
364
365                 if (!thz[i]->passive)
366                         thermal_zone_device_update(thz[i]);
367
368                 thz[i]->ops->get_temp(thz[i], &temp);
369                 for (count = 0; count < thz[i]->trips; count++) {
370                         thz[i]->ops->get_trip_temp(thz[i], count, &trip_temp);
371
372                         if ((trip_temp >= temp) && (trip_temp < high_temp))
373                                 high_temp = trip_temp;
374
375                         if ((trip_temp < temp) && (trip_temp > low_temp))
376                                 low_temp = trip_temp -
377                                     plat_data.therm[i].trips[count].hysteresis;
378                 }
379         }
380
381         soctherm_set_limits(THERM_CPU, low_temp/1000, high_temp/1000);
382 }
383
384 static int soctherm_bind(struct thermal_zone_device *thz,
385                                 struct thermal_cooling_device *cdev)
386 {
387         int i, index = ((int)thz->devdata) - TSENSE_SIZE;
388         char *cdev_type;
389
390         if (index < 0)
391                 return 0;
392
393         for (i = 0; i < plat_data.therm[index].num_trips; i++) {
394                 cdev_type = plat_data.therm[index].trips[i].cdev_type;
395                 if (cdev_type && !strcmp(cdev_type, cdev->type))
396                         thermal_zone_bind_cooling_device(thz, i, cdev,
397                                         plat_data.therm[index].trips[i].upper,
398                                         plat_data.therm[index].trips[i].lower);
399         }
400
401         return 0;
402 }
403
404 static int soctherm_unbind(struct thermal_zone_device *thz,
405                                 struct thermal_cooling_device *cdev)
406 {
407         int i, index = ((int)thz->devdata) - TSENSE_SIZE;
408         char *cdev_type;
409
410         if (index < 0)
411                 return 0;
412
413         for (i = 0; i < plat_data.therm[index].num_trips; i++) {
414                 cdev_type = plat_data.therm[index].trips[i].cdev_type;
415                 if (cdev_type && !strcmp(cdev_type, cdev->type))
416                         thermal_zone_unbind_cooling_device(thz, 0, cdev);
417         }
418
419         return 0;
420 }
421
422 static int soctherm_get_temp(struct thermal_zone_device *thz,
423                                         unsigned long *temp)
424 {
425         int index = (int)thz->devdata;
426         u32 r;
427
428         if (index < TSENSE_SIZE) {
429                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_STATUS1,
430                                                         index));
431                 *temp = temp_translate(REG_GET(r, TS_CPU0_STATUS1_TEMP));
432         } else {
433                 index -= TSENSE_SIZE;
434
435                 if (index == THERM_CPU || index == THERM_GPU)
436                         r = soctherm_readl(TS_TEMP1);
437                 else
438                         r = soctherm_readl(TS_TEMP2);
439
440                 if (index == THERM_CPU || index == THERM_MEM)
441                         *temp = temp_translate(REG_GET(r, TS_TEMP1_CPU_TEMP));
442                 else
443                         *temp = temp_translate(REG_GET(r, TS_TEMP1_GPU_TEMP));
444
445                 plat_data.therm[index].etemp = *temp;
446         }
447
448         return 0;
449 }
450
451 static int soctherm_get_trip_type(struct thermal_zone_device *thz,
452                                         int trip,
453                                         enum thermal_trip_type *type) {
454         int index = ((int)thz->devdata) - TSENSE_SIZE;
455
456         if (index < 0 || !plat_data.therm[index].trips[trip].cdev_type)
457                 return -EINVAL;
458
459         *type = plat_data.therm[index].trips[trip].trip_type;
460         return 0;
461 }
462
463 static int soctherm_get_trip_temp(struct thermal_zone_device *thz,
464                                         int trip,
465                                         unsigned long *temp) {
466         int index = ((int)thz->devdata) - TSENSE_SIZE;
467
468         if (index < 0 || !plat_data.therm[index].trips[trip].cdev_type)
469                 return -EINVAL;
470
471         *temp = plat_data.therm[index].trips[trip].trip_temp;
472         return 0;
473 }
474
475 static int soctherm_set_trip_temp(struct thermal_zone_device *thz,
476                                         int trip,
477                                         unsigned long temp)
478 {
479         int index = ((int)thz->devdata) - TSENSE_SIZE;
480
481         if (index < 0 || !plat_data.therm[index].trips[trip].cdev_type)
482                 return -EINVAL;
483
484         plat_data.therm[index].trips[trip].trip_temp = temp;
485         soctherm_update();
486         return 0;
487 }
488
489 static int soctherm_get_trend(struct thermal_zone_device *thz,
490                                 int trip,
491                                 enum thermal_trend *trend)
492 {
493         int index = ((int)thz->devdata) - TSENSE_SIZE;
494         struct thermal_trip_info *trip_state;
495
496         if (index < 0 || !plat_data.therm[index].trips[trip].cdev_type)
497                 return -EINVAL;
498
499         trip_state = &plat_data.therm[index].trips[trip];
500
501         switch (trip_state->trip_type) {
502         case THERMAL_TRIP_ACTIVE:
503                 /* aggressive active cooling */
504                 *trend = THERMAL_TREND_RAISING;
505                 break;
506         case THERMAL_TRIP_PASSIVE:
507                 if (plat_data.therm[index].etemp > trip_state->trip_temp)
508                         *trend = THERMAL_TREND_RAISING;
509                 else
510                         *trend = THERMAL_TREND_DROPPING;
511                 break;
512         default:
513                 return -EINVAL;
514         }
515
516         return 0;
517 }
518
519 static struct thermal_zone_device_ops soctherm_ops = {
520         .bind = soctherm_bind,
521         .unbind = soctherm_unbind,
522         .get_temp = soctherm_get_temp,
523         .get_trip_type = soctherm_get_trip_type,
524         .get_trip_temp = soctherm_get_trip_temp,
525         .set_trip_temp = soctherm_set_trip_temp,
526         .get_trend = soctherm_get_trend,
527 };
528
529 static int __init soctherm_thermal_sys_init(void)
530 {
531         char name[64];
532         int i;
533
534         if (!soctherm_init_platform_done)
535                 return 0;
536
537         for (i = 0; i < TSENSE_SIZE; i++) {
538                 if (plat_data.sensor_data[i].zone_enable) {
539                         sprintf(name, "%s-tsensor", sensor_names[i]);
540                         /* Create a thermal zone device for each sensor */
541                         thermal_zone_device_register(
542                                         name,
543                                         0,
544                                         0,
545                                         (void *)i,
546                                         &soctherm_ops,
547                                         NULL,
548                                         0,
549                                         0);
550                 }
551         }
552
553         for (i = 0; i < THERM_SIZE; i++) {
554                 if (plat_data.therm[i].zone_enable) {
555                         sprintf(name, "%s-therm", therm_names[i]);
556                         thz[i] = thermal_zone_device_register(
557                                         name,
558                                         plat_data.therm[i].num_trips,
559                                         (1 << plat_data.therm[i].num_trips) - 1,
560                                         (void *)TSENSE_SIZE + i,
561                                         &soctherm_ops,
562                                         NULL,
563                                         plat_data.therm[i].passive_delay,
564                                         0);
565                 }
566         }
567
568         soctherm_update();
569         return 0;
570 }
571 module_init(soctherm_thermal_sys_init);
572
573 #else
574 static void soctherm_update(void)
575 {
576 }
577 #endif
578
579 static void soctherm_work_func(struct work_struct *work)
580 {
581         u32 st;
582
583         st = soctherm_readl(INTR_STATUS);
584
585         /* deliberately clear each expected interrupt */
586         if (REG_GET(st, INTR_STATUS_CD0) || REG_GET(st, INTR_STATUS_CU0)) {
587                 soctherm_writel(REG_SET(0, INTR_STATUS_CD0, 1), INTR_STATUS);
588                 soctherm_writel(REG_SET(0, INTR_STATUS_CU0, 1), INTR_STATUS);
589                 st = REG_SET(st, INTR_STATUS_CD0, 0);
590                 st = REG_SET(st, INTR_STATUS_CU0, 0);
591                 soctherm_update();
592         }
593
594         if (!st)
595                 return;
596
597         /* Whine about any other unexpected INTR bits still set */
598         pr_err("soctherm: Ignored unexpected INTR status 0x%08x\n", st);
599 }
600
601 static irqreturn_t soctherm_isr(int irq, void *arg_data)
602 {
603         u32 r;
604
605         queue_work(workqueue, &work);
606
607         r = soctherm_readl(INTR_STATUS);
608         soctherm_writel(r, INTR_DIS);
609
610         return IRQ_HANDLED;
611 }
612
613 void tegra11_soctherm_throttle_program(enum soctherm_throttle_id throttle,
614                                         struct soctherm_throttle *data)
615 {
616         u32 r;
617         int i;
618         struct soctherm_throttle_dev *dev;
619
620         for (i = 0; i < THROTTLE_DEV_SIZE; i++) {
621                 dev = &data->devs[i];
622
623                 r = soctherm_readl(THROT_PSKIP_CTRL(throttle, i));
624                 r = REG_SET(r, THROT_PSKIP_CTRL_ENABLE, dev->enable);
625                 r = REG_SET(r, THROT_PSKIP_CTRL_DIVIDEND, dev->dividend);
626                 r = REG_SET(r, THROT_PSKIP_CTRL_DIVISOR, dev->divisor);
627                 soctherm_writel(r, THROT_PSKIP_CTRL(throttle, i));
628
629                 r = soctherm_readl(THROT_PSKIP_RAMP(throttle, i));
630                 r = REG_SET(r, THROT_PSKIP_RAMP_DURATION, dev->duration);
631                 r = REG_SET(r, THROT_PSKIP_RAMP_STEP, dev->step);
632                 soctherm_writel(r, THROT_PSKIP_RAMP(throttle, i));
633         }
634
635         r = soctherm_readl(THROT_PRIORITY_LOCK);
636         if (r < data->priority) {
637                 r = REG_SET(0, THROT_PRIORITY_LOCK_PRIORITY, data->priority);
638                 soctherm_writel(r, THROT_PRIORITY_LOCK);
639         }
640
641         r = REG_SET(0, THROT_LITE_PRIORITY_PRIORITY, data->priority);
642         soctherm_writel(r, THROT_LITE_PRIORITY + THROT_OFFSET * throttle);
643 }
644
645 static void __init soctherm_tsense_program(enum soctherm_sense sensor,
646                                                 struct soctherm_sensor *data)
647 {
648         u32 r;
649
650         r = REG_SET(0, TS_CPU0_CONFIG0_TALL, data->tall);
651         soctherm_writel(r, TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG0, sensor));
652
653         r = REG_SET(0, TS_CPU0_CONFIG1_TIDDQ, data->tiddq);
654         r = REG_SET(r, TS_CPU0_CONFIG1_EN, 1);
655         r = REG_SET(r, TS_CPU0_CONFIG1_TEN_COUNT, data->ten_count);
656         r = REG_SET(r, TS_CPU0_CONFIG1_TSAMPLE, data->tsample);
657         soctherm_writel(r, TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG1, sensor));
658 }
659
660 static int __init soctherm_clk_init(void)
661 {
662         soctherm_clk = clk_get_sys("soc_therm", NULL);
663         tsensor_clk = clk_get_sys("tegra-tsensor", NULL);
664
665         if (IS_ERR(tsensor_clk) || IS_ERR(soctherm_clk)) {
666                 clk_put(soctherm_clk);
667                 clk_put(tsensor_clk);
668                 soctherm_clk = tsensor_clk = NULL;
669                 return -EINVAL;
670         }
671
672         if (clk_get_rate(soctherm_clk) != plat_data.soctherm_clk_rate)
673                 if (clk_set_rate(soctherm_clk, plat_data.soctherm_clk_rate))
674                         return -EINVAL;
675
676         if (clk_get_rate(tsensor_clk) != plat_data.tsensor_clk_rate)
677                 if (clk_set_rate(tsensor_clk, plat_data.tsensor_clk_rate))
678                         return -EINVAL;
679
680         return 0;
681 }
682
683 static int soctherm_clk_enable(bool enable)
684 {
685         if (soctherm_clk == NULL || tsensor_clk == NULL)
686                 return -EINVAL;
687
688         if (enable) {
689                 clk_enable(soctherm_clk);
690                 clk_enable(tsensor_clk);
691         } else {
692                 clk_disable(soctherm_clk);
693                 clk_disable(tsensor_clk);
694         }
695
696         return 0;
697 }
698
699 static void soctherm_fuse_read_vsensor(void)
700 {
701         u32 value;
702         s32 calib_cp, calib_ft;
703
704         tegra_fuse_get_vsensor_calib(&value);
705
706         /* Extract bits */
707         fuse_calib_base_cp = REG_GET(value, FUSE_BASE_CP);
708         fuse_calib_base_ft = REG_GET(value, FUSE_BASE_FT);
709
710         /* Extract bits and convert to signed 2's complement */
711         calib_cp = REG_GET(value, FUSE_SHIFT_CP);
712         calib_cp = MAKE_SIGNED32(calib_cp, FUSE_SHIFT_CP_BITS);
713
714         calib_ft = REG_GET(value, FUSE_SHIFT_FT);
715         calib_ft = MAKE_SIGNED32(calib_ft, FUSE_SHIFT_FT_BITS);
716
717         /* default: HI precision: use fuse_temp in 0.5C */
718         actual_temp_cp = 2 * 25 + calib_cp;
719         actual_temp_ft = 2 * 90 + calib_ft;
720
721         /* adjust: for LO precision: use fuse_temp in 1C */
722         if (soc_therm_precision != -1) {
723                 actual_temp_cp /= 2;
724                 actual_temp_ft /= 2;
725         }
726 }
727
728 static void soctherm_fuse_read_tsensor(enum soctherm_sense sensor)
729 {
730         u32 r, value;
731         s32 calib, delta_sens, delta_temp;
732         s16 therm_a, therm_b;
733         s32 div, mult, actual_tsensor_ft, actual_tsensor_cp;
734
735         tegra_fuse_get_tsensor_calib(sensor2tsensorcalib[sensor], &value);
736
737         /* Extract bits and convert to signed 2's complement */
738         calib = REG_GET(value, FUSE_TSENSOR_CALIB_FT);
739         calib = MAKE_SIGNED32(calib, FUSE_TSENSOR_CALIB_BITS);
740         actual_tsensor_ft = (fuse_calib_base_ft * 32) + calib;
741
742         calib = REG_GET(value, FUSE_TSENSOR_CALIB_CP);
743         calib = MAKE_SIGNED32(calib, FUSE_TSENSOR_CALIB_BITS);
744         actual_tsensor_cp = (fuse_calib_base_cp * 64) + calib;
745
746         mult = plat_data.sensor_data[sensor].pdiv * 655;
747         div = plat_data.sensor_data[sensor].tsample * 10;
748
749         delta_sens = actual_tsensor_ft - actual_tsensor_cp;
750         delta_temp = actual_temp_ft - actual_temp_cp;
751
752         therm_a = div64_s64_precise((s64)delta_temp * (1LL << 13) * mult,
753                                     (s64)delta_sens * div);
754
755         therm_b = div64_s64_precise((((s64)actual_tsensor_ft * actual_temp_cp) -
756                                      ((s64)actual_tsensor_cp * actual_temp_ft)),
757                                     (s64)delta_sens);
758
759         r = REG_SET(0, TS_CPU0_CONFIG2_THERM_A, therm_a);
760         r = REG_SET(r, TS_CPU0_CONFIG2_THERM_B, therm_b);
761         soctherm_writel(r, TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG2, sensor));
762 }
763
764 static int soctherm_init_platform_data(void)
765 {
766         struct soctherm_therm *therm;
767         int i;
768         u32 r;
769         u32 reg_off;
770
771         therm = plat_data.therm;
772
773         /* Can only thermtrip with either GPU or MEM but not both */
774         BUG_ON(therm[THERM_GPU].thermtrip && therm[THERM_MEM].thermtrip);
775
776         /* Pdiv */
777         r = soctherm_readl(TS_PDIV);
778         r = REG_SET(r, TS_PDIV_CPU, plat_data.sensor_data[TSENSE_CPU0].pdiv);
779         r = REG_SET(r, TS_PDIV_GPU, plat_data.sensor_data[TSENSE_GPU].pdiv);
780         r = REG_SET(r, TS_PDIV_MEM, plat_data.sensor_data[TSENSE_MEM0].pdiv);
781         r = REG_SET(r, TS_PDIV_PLLX, plat_data.sensor_data[TSENSE_PLLX].pdiv);
782         soctherm_writel(r, TS_PDIV);
783
784         /* Thermal Sensing programming */
785         soctherm_fuse_read_vsensor();
786         for (i = 0; i < TSENSE_SIZE; i++) {
787                 if (plat_data.sensor_data[i].sensor_enable) {
788                         soctherm_tsense_program(i, &plat_data.sensor_data[i]);
789                         soctherm_fuse_read_tsensor(i);
790                 }
791         }
792
793         for (i = 0; i < THERM_SIZE; i++) {
794                 if (plat_data.therm[i].hw_backstop) {
795                         reg_off = TS_TSENSE_REG_OFFSET(CTL_LVL0_CPU0, 1)
796                                 + i * 4;
797                         r = soctherm_readl(reg_off);
798                         r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH,
799                                         plat_data.therm[i].hw_backstop);
800                         r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH,
801                                         plat_data.therm[i].hw_backstop - 2);
802                         r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
803
804                         /* Heavy throttling */
805                         r = REG_SET(r, CTL_LVL0_CPU0_CPU_THROT, 2);
806                         soctherm_writel(r, reg_off);
807                 }
808         }
809
810         /* Enable Level 0 */
811         r = soctherm_readl(CTL_LVL0_CPU0);
812         r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
813         soctherm_writel(r, CTL_LVL0_CPU0);
814
815         /* Thermtrip */
816         r = REG_SET(0, THERMTRIP_CPU_EN, !!therm[THERM_CPU].thermtrip);
817         r = REG_SET(r, THERMTRIP_GPU_EN, !!therm[THERM_GPU].thermtrip);
818         r = REG_SET(r, THERMTRIP_MEM_EN, !!therm[THERM_MEM].thermtrip);
819         r = REG_SET(r, THERMTRIP_TSENSE_EN, !!therm[THERM_PLL].thermtrip);
820         r = REG_SET(r, THERMTRIP_CPU_THRESH, therm[THERM_CPU].thermtrip);
821         r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, therm[THERM_GPU].thermtrip |
822                                                 therm[THERM_MEM].thermtrip);
823         r = REG_SET(r, THERMTRIP_TSENSE_THRESH, therm[THERM_PLL].thermtrip);
824         soctherm_writel(r, THERMTRIP);
825
826         /* Enable PMC to shutdown */
827         r = pmc_readl(0x1b0);
828         r |= 0x2;
829         pmc_writel(r, 0x1b0);
830
831         /* Throttling */
832         for (i = 0; i < THROTTLE_SIZE; i++)
833                 tegra11_soctherm_throttle_program(i, &plat_data.throttle[i]);
834
835         r = clk_reset_readl(0x24);
836         r |= (1 << 30);
837         clk_reset_writel(r, 0x24);
838
839         return 0;
840 }
841
842 static int soctherm_suspend(void)
843 {
844         soctherm_writel((u32)-1, INTR_DIS);
845         soctherm_clk_enable(false);
846         disable_irq(INT_THERMAL);
847         cancel_work_sync(&work);
848
849         return 0;
850 }
851
852 static int soctherm_resume(void)
853 {
854         soctherm_clk_enable(true);
855         enable_irq(INT_THERMAL);
856         soctherm_init_platform_data();
857         soctherm_update();
858
859         return 0;
860 }
861
862 static int soctherm_pm_notify(struct notifier_block *nb,
863                                 unsigned long event, void *data)
864 {
865         switch (event) {
866         case PM_SUSPEND_PREPARE:
867                 soctherm_suspend();
868                 break;
869         case PM_POST_SUSPEND:
870                 soctherm_resume();
871                 break;
872         }
873
874         return NOTIFY_OK;
875 }
876
877 static struct notifier_block soctherm_nb = {
878         .notifier_call = soctherm_pm_notify,
879 };
880
881 int __init tegra11_soctherm_init(struct soctherm_platform_data *data)
882 {
883         int err;
884
885         register_pm_notifier(&soctherm_nb);
886
887         if (!data)
888                 return -1;
889         plat_data = *data;
890
891         if (soctherm_clk_init() < 0)
892                 return -1;
893
894         if (soctherm_clk_enable(true) < 0)
895                 return -1;
896
897         if (soctherm_init_platform_data() < 0)
898                 return -1;
899
900         soctherm_init_platform_done = true;
901
902         /* enable interrupts */
903         workqueue = create_singlethread_workqueue("soctherm");
904         INIT_WORK(&work, soctherm_work_func);
905
906         err = request_irq(INT_THERMAL, soctherm_isr, 0, "soctherm", NULL);
907         if (err < 0)
908                 return -1;
909
910         return 0;
911 }
912
913
914 #ifdef CONFIG_DEBUG_FS
915 static int regs_show(struct seq_file *s, void *data)
916 {
917         u32 r;
918         u32 state;
919         long tcpu[TSENSE_SIZE];
920         int i, level;
921
922         seq_printf(s, "-----TSENSE (precision %s)-----\n",
923                    soc_therm_precision == -1 ? "Hi" : "Lo");
924         for (i = 0; i < TSENSE_SIZE; i++) {
925                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG1, i));
926                 state = REG_GET(r, TS_CPU0_CONFIG1_EN);
927                 if (!state)
928                         continue;
929
930                 seq_printf(s, "%s: ", sensor_names[i]);
931
932                 seq_printf(s, "En(%d) ", state);
933                 state = REG_GET(r, TS_CPU0_CONFIG1_TIDDQ);
934                 seq_printf(s, "tiddq(%d) ", state);
935                 state = REG_GET(r, TS_CPU0_CONFIG1_TEN_COUNT);
936                 seq_printf(s, "ten_count(%d) ", state);
937                 state = REG_GET(r, TS_CPU0_CONFIG1_TSAMPLE);
938                 seq_printf(s, "tsample(%d) ", state);
939
940                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_STATUS0, i));
941                 state = REG_GET(r, TS_CPU0_STATUS0_VALID);
942                 seq_printf(s, "Capture(%d/", state);
943                 state = REG_GET(r, TS_CPU0_STATUS0_CAPTURE);
944                 seq_printf(s, "%d) ", state);
945
946
947                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_STATUS1, i));
948                 state = REG_GET(r, TS_CPU0_STATUS1_TEMP_VALID);
949                 seq_printf(s, "Temp(%d/", state);
950                 state = REG_GET(r, TS_CPU0_STATUS1_TEMP);
951                 seq_printf(s, "%ld) ", tcpu[i] = temp_translate(state));
952
953
954                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG0, i));
955                 state = REG_GET(r, TS_CPU0_CONFIG0_TALL);
956                 seq_printf(s, "Tall(%d) ", state);
957                 state = REG_GET(r, TS_CPU0_CONFIG0_TCALC_OVER);
958                 seq_printf(s, "Over(%d/", state);
959                 state = REG_GET(r, TS_CPU0_CONFIG0_OVER);
960                 seq_printf(s, "%d/", state);
961                 state = REG_GET(r, TS_CPU0_CONFIG0_CPTR_OVER);
962                 seq_printf(s, "%d) ", state);
963
964                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG2, i));
965                 state = REG_GET(r, TS_CPU0_CONFIG2_THERM_A);
966                 seq_printf(s, "Therm_A/B(%d/", state);
967                 state = REG_GET(r, TS_CPU0_CONFIG2_THERM_B);
968                 seq_printf(s, "%d)\n", state);
969         }
970
971         r = soctherm_readl(TS_PDIV);
972         seq_printf(s, "PDIV: 0x%x\n", r);
973
974         seq_printf(s, "\n");
975         seq_printf(s, "-----SOC_THERM-----\n");
976
977         r = soctherm_readl(TS_TEMP1);
978         state = REG_GET(r, TS_TEMP1_CPU_TEMP);
979         seq_printf(s, "Temperature: CPU(%ld) [Max(%ld)%c] ",
980                    temp_translate(state),
981                    max4(tcpu[0], tcpu[1], tcpu[2], tcpu[3]),
982                    max4(tcpu[0], tcpu[1], tcpu[2], tcpu[3]) ==
983                    temp_translate(state) ? '=' : '!');
984         state = REG_GET(r, TS_TEMP1_GPU_TEMP);
985         seq_printf(s, " GPU(%ld) ", temp_translate(state));
986         r = soctherm_readl(TS_TEMP2);
987         state = REG_GET(r, TS_TEMP2_MEM_TEMP);
988         seq_printf(s, " MEM(%ld) ", temp_translate(state));
989         state = REG_GET(r, TS_TEMP2_PLLX_TEMP);
990         seq_printf(s, " PLLX(%ld)\n\n", temp_translate(state));
991
992         for (i = 0; i < THERM_SIZE; i++) {
993                 seq_printf(s, "%s:\n", therm_names[i]);
994
995                 for (level = 0; level < 4; level++) {
996                         r = soctherm_readl(TS_TSENSE_REG_OFFSET(CTL_LVL0_CPU0,
997                                                                 i) + level * 4);
998                         state = REG_GET(r, CTL_LVL0_CPU0_UP_THRESH);
999                         seq_printf(s, "    Up/Dn(%d/", state);
1000                         state = REG_GET(r, CTL_LVL0_CPU0_DN_THRESH);
1001                         seq_printf(s, "%d) ", state);
1002                         state = REG_GET(r, CTL_LVL0_CPU0_EN);
1003                         seq_printf(s, "En(%d) ", state);
1004                         state = REG_GET(r, CTL_LVL0_CPU0_STATUS);
1005                         seq_printf(s, "Status(%s)\n",
1006                                    state == 0 ? "LO" :
1007                                    state == 1 ? "in" :
1008                                    state == 2 ? "??" : "HI");
1009                 }
1010         }
1011
1012         r = soctherm_readl(INTR_STATUS);
1013         state = REG_GET(r, INTR_STATUS_CD0);
1014         seq_printf(s, "CD0: %d\n", state);
1015         state = REG_GET(r, INTR_STATUS_CU0);
1016         seq_printf(s, "CU0: %d\n", state);
1017
1018         r = soctherm_readl(THERMTRIP);
1019         state = REG_GET(r, THERMTRIP_CPU_THRESH);
1020         seq_printf(s, "THERMTRIP_CPU_THRESH: %d ", state);
1021         state = REG_GET(r, THERMTRIP_CPU_EN);
1022         seq_printf(s, "%d\n", state);
1023
1024
1025         seq_printf(s, "\n-----THROTTLE-----\n");
1026
1027         r = soctherm_readl(THROT_GLOBAL_CFG);
1028         seq_printf(s, "GLOBAL CONFIG: 0x%x\n", r);
1029
1030         r = soctherm_readl(THROT_STATUS);
1031         state = REG_GET(r, THROT_STATUS_BREACH);
1032         seq_printf(s, "THROT STATUS: breach(%d) ", state);
1033         state = REG_GET(r, THROT_STATUS_STATE);
1034         seq_printf(s, "state(%d) ", state);
1035         state = REG_GET(r, THROT_STATUS_ENABLED);
1036         seq_printf(s, "enabled(%d)\n", state);
1037
1038         r = soctherm_readl(CPU_PSKIP_STATUS);
1039         state = REG_GET(r, CPU_PSKIP_STATUS_M);
1040         seq_printf(s, "CPU PSKIP: M(%d) ", state);
1041         state = REG_GET(r, CPU_PSKIP_STATUS_N);
1042         seq_printf(s, "N(%d) ", state);
1043         state = REG_GET(r, CPU_PSKIP_STATUS_ENABLED);
1044         seq_printf(s, "enabled(%d)\n", state);
1045
1046         r = soctherm_readl(THROT_PSKIP_CTRL(THROTTLE_HEAVY, THROTTLE_DEV_CPU));
1047         state = REG_GET(r, THROT_PSKIP_CTRL_ENABLE);
1048         seq_printf(s, "CPU PSKIP HEAVY: enabled(%d) ", state);
1049         state = REG_GET(r, THROT_PSKIP_CTRL_DIVIDEND);
1050         seq_printf(s, "dividend(%d) ", state);
1051         state = REG_GET(r, THROT_PSKIP_CTRL_DIVISOR);
1052         seq_printf(s, "divisor(%d) ", state);
1053
1054         r = soctherm_readl(THROT_PSKIP_RAMP(THROTTLE_HEAVY, THROTTLE_DEV_CPU));
1055         state = REG_GET(r, THROT_PSKIP_RAMP_DURATION);
1056         seq_printf(s, "duration(%d) ", state);
1057         state = REG_GET(r, THROT_PSKIP_RAMP_STEP);
1058         seq_printf(s, "step(%d)\n", state);
1059
1060         return 0;
1061 }
1062
1063 static int regs_open(struct inode *inode, struct file *file)
1064 {
1065         return single_open(file, regs_show, inode->i_private);
1066 }
1067
1068 static const struct file_operations regs_fops = {
1069         .open           = regs_open,
1070         .read           = seq_read,
1071         .llseek         = seq_lseek,
1072         .release        = single_release,
1073 };
1074
1075 static int __init soctherm_debug_init(void)
1076 {
1077         struct dentry *tegra_soctherm_root;
1078
1079         tegra_soctherm_root = debugfs_create_dir("tegra_soctherm", 0);
1080         debugfs_create_file("regs", 0644, tegra_soctherm_root,
1081                                 NULL, &regs_fops);
1082         return 0;
1083 }
1084 late_initcall(soctherm_debug_init);
1085 #endif