arm: tegra: soctherm: mark some variables const as necessary
[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
47  *  0: Lo precision option: 2^0  = 1.0C
48  *  NB: We must use lower precision (0) due to cp_fuse corrections
49  *  (see Sec9.2 T35_Thermal_Sensing_IAS.docx)
50  */
51 static const int soc_therm_precision; /* default 0 -> low precision */
52
53 #define TS_TSENSE_REGS_SIZE             0x20
54 #define TS_TSENSE_REG_OFFSET(reg, ts)   ((reg) + ((ts) * TS_TSENSE_REGS_SIZE))
55
56 #define TS_THERM_LVL_REGS_SIZE          0x20
57 #define TS_THERM_GRP_REGS_SIZE          0x04
58 #define TS_THERM_REG_OFFSET(rg, lv, gr) ((rg) + ((lv) * TS_THERM_LVL_REGS_SIZE)\
59                                         + ((gr) * TS_THERM_GRP_REGS_SIZE))
60
61 #define CTL_LVL0_CPU0                   0x0
62 #define CTL_LVL0_CPU0_UP_THRESH_SHIFT   17
63 #define CTL_LVL0_CPU0_UP_THRESH_MASK    0xff
64 #define CTL_LVL0_CPU0_DN_THRESH_SHIFT   9
65 #define CTL_LVL0_CPU0_DN_THRESH_MASK    0xff
66 #define CTL_LVL0_CPU0_EN_SHIFT          8
67 #define CTL_LVL0_CPU0_EN_MASK           0x1
68 #define CTL_LVL0_CPU0_CPU_THROT_SHIFT   5
69 #define CTL_LVL0_CPU0_CPU_THROT_MASK    0x3
70 #define CTL_LVL0_CPU0_CPU_THROT_LIGHT   0x1
71 #define CTL_LVL0_CPU0_CPU_THROT_HEAVY   0x2
72 #define CTL_LVL0_CPU0_MEM_THROT_SHIFT   2
73 #define CTL_LVL0_CPU0_MEM_THROT_MASK    0x1
74 #define CTL_LVL0_CPU0_STATUS_SHIFT      0
75 #define CTL_LVL0_CPU0_STATUS_MASK       0x3
76
77 #define THERMTRIP                       0x80
78 #define THERMTRIP_ANY_EN_SHIFT          28
79 #define THERMTRIP_ANY_EN_MASK           0x1
80 #define THERMTRIP_MEM_EN_SHIFT          27
81 #define THERMTRIP_MEM_EN_MASK           0x1
82 #define THERMTRIP_GPU_EN_SHIFT          26
83 #define THERMTRIP_GPU_EN_MASK           0x1
84 #define THERMTRIP_CPU_EN_SHIFT          25
85 #define THERMTRIP_CPU_EN_MASK           0x1
86 #define THERMTRIP_TSENSE_EN_SHIFT       24
87 #define THERMTRIP_TSENSE_EN_MASK        0x1
88 #define THERMTRIP_GPUMEM_THRESH_SHIFT   16
89 #define THERMTRIP_GPUMEM_THRESH_MASK    0xff
90 #define THERMTRIP_CPU_THRESH_SHIFT      8
91 #define THERMTRIP_CPU_THRESH_MASK       0xff
92 #define THERMTRIP_TSENSE_THRESH_SHIFT   0
93 #define THERMTRIP_TSENSE_THRESH_MASK    0xff
94
95 #define TS_CPU0_CONFIG0                         0xc0
96 #define TS_CPU0_CONFIG0_TALL_SHIFT              8
97 #define TS_CPU0_CONFIG0_TALL_MASK               0xfffff
98 #define TS_CPU0_CONFIG0_TCALC_OVER_SHIFT        4
99 #define TS_CPU0_CONFIG0_TCALC_OVER_MASK         0x1
100 #define TS_CPU0_CONFIG0_OVER_SHIFT              3
101 #define TS_CPU0_CONFIG0_OVER_MASK               0x1
102 #define TS_CPU0_CONFIG0_CPTR_OVER_SHIFT         2
103 #define TS_CPU0_CONFIG0_CPTR_OVER_MASK          0x1
104 #define TS_CPU0_CONFIG0_STOP_SHIFT              0
105 #define TS_CPU0_CONFIG0_STOP_MASK               0x1
106
107 #define TS_CPU0_CONFIG1                 0xc4
108 #define TS_CPU0_CONFIG1_EN_SHIFT        31
109 #define TS_CPU0_CONFIG1_EN_MASK         0x1
110 #define TS_CPU0_CONFIG1_TIDDQ_SHIFT     15
111 #define TS_CPU0_CONFIG1_TIDDQ_MASK      0x3f
112 #define TS_CPU0_CONFIG1_TEN_COUNT_SHIFT 24
113 #define TS_CPU0_CONFIG1_TEN_COUNT_MASK  0x3f
114 #define TS_CPU0_CONFIG1_TSAMPLE_SHIFT   0
115 #define TS_CPU0_CONFIG1_TSAMPLE_MASK    0x3ff
116
117 #define TS_CPU0_CONFIG2                 0xc8
118 #define TS_CPU0_CONFIG2_THERM_A_SHIFT   16
119 #define TS_CPU0_CONFIG2_THERM_A_MASK    0xffff
120 #define TS_CPU0_CONFIG2_THERM_B_SHIFT   0
121 #define TS_CPU0_CONFIG2_THERM_B_MASK    0xffff
122
123 #define TS_CPU0_STATUS0                 0xcc
124 #define TS_CPU0_STATUS0_VALID_SHIFT     31
125 #define TS_CPU0_STATUS0_VALID_MASK      0x1
126 #define TS_CPU0_STATUS0_CAPTURE_SHIFT   0
127 #define TS_CPU0_STATUS0_CAPTURE_MASK    0xffff
128
129 #define TS_CPU0_STATUS1                         0xd0
130 #define TS_CPU0_STATUS1_TEMP_VALID_SHIFT        31
131 #define TS_CPU0_STATUS1_TEMP_VALID_MASK         0x1
132 #define TS_CPU0_STATUS1_TEMP_SHIFT              0
133 #define TS_CPU0_STATUS1_TEMP_MASK               0xffff
134
135 #define TS_CPU0_STATUS2                 0xd4
136
137 #define TS_PDIV                         0x1c0
138 #define TS_PDIV_CPU_SHIFT               12
139 #define TS_PDIV_CPU_MASK                0xf
140 #define TS_PDIV_GPU_SHIFT               8
141 #define TS_PDIV_GPU_MASK                0xf
142 #define TS_PDIV_MEM_SHIFT               4
143 #define TS_PDIV_MEM_MASK                0xf
144 #define TS_PDIV_PLLX_SHIFT              0
145 #define TS_PDIV_PLLX_MASK               0xf
146
147 #define TS_TEMP1                        0x1c8
148 #define TS_TEMP1_CPU_TEMP_SHIFT         16
149 #define TS_TEMP1_CPU_TEMP_MASK          0xffff
150 #define TS_TEMP1_GPU_TEMP_SHIFT         0
151 #define TS_TEMP1_GPU_TEMP_MASK          0xffff
152
153 #define TS_TEMP2                        0x1cc
154 #define TS_TEMP2_MEM_TEMP_SHIFT         16
155 #define TS_TEMP2_MEM_TEMP_MASK          0xffff
156 #define TS_TEMP2_PLLX_TEMP_SHIFT        0
157 #define TS_TEMP2_PLLX_TEMP_MASK         0xffff
158
159 #define INTR_STATUS                     0x84
160 #define INTR_STATUS_CD2_SHIFT           13
161 #define INTR_STATUS_CD2_MASK            0x1
162 #define INTR_STATUS_CU2_SHIFT           12
163 #define INTR_STATUS_CU2_MASK            0x1
164 #define INTR_STATUS_CD1_SHIFT           11
165 #define INTR_STATUS_CD1_MASK            0x1
166 #define INTR_STATUS_CU1_SHIFT           10
167 #define INTR_STATUS_CU1_MASK            0x1
168 #define INTR_STATUS_CD0_SHIFT           9
169 #define INTR_STATUS_CD0_MASK            0x1
170 #define INTR_STATUS_CU0_SHIFT           8
171 #define INTR_STATUS_CU0_MASK            0x1
172
173 #define INTR_EN                 0x88
174 #define INTR_EN_MU0_SHIFT       24
175 #define INTR_EN_MD0_SHIFT       25
176 #define INTR_EN_CU0_SHIFT       8
177 #define INTR_EN_CD0_SHIFT       9
178
179 #define INTR_DIS                0x8c
180 #define LOCK_CTL                0x90
181
182 #define UP_STATS_L0             0x10
183 #define DN_STATS_L0             0x14
184
185 #define STATS_CTL               0x94
186 #define STATS_CTL_CLR_DN        0x8
187 #define STATS_CTL_EN_DN         0x4
188 #define STATS_CTL_CLR_UP        0x2
189 #define STATS_CTL_EN_UP         0x1
190
191 #define THROT_GLOBAL_CFG        0x400
192
193 #define CPU_PSKIP_STATUS                        0x418
194 #define CPU_PSKIP_STATUS_M_SHIFT                12
195 #define CPU_PSKIP_STATUS_M_MASK                 0xff
196 #define CPU_PSKIP_STATUS_N_SHIFT                4
197 #define CPU_PSKIP_STATUS_N_MASK                 0xff
198 #define CPU_PSKIP_STATUS_ENABLED_SHIFT          0
199 #define CPU_PSKIP_STATUS_ENABLED_MASK           0x1
200
201 #define THROT_PRIORITY_LOCK                     0x424
202 #define THROT_PRIORITY_LOCK_PRIORITY_SHIFT      0
203 #define THROT_PRIORITY_LOCK_PRIORITY_MASK       0xff
204
205 #define THROT_STATUS                            0x428
206 #define THROT_STATUS_BREACH_SHIFT               12
207 #define THROT_STATUS_BREACH_MASK                0x1
208 #define THROT_STATUS_STATE_SHIFT                4
209 #define THROT_STATUS_STATE_MASK                 0xff
210 #define THROT_STATUS_ENABLED_SHIFT              0
211 #define THROT_STATUS_ENABLED_MASK               0x1
212
213 #define THROT_PSKIP_CTRL_LITE_CPU               0x430
214 #define THROT_PSKIP_CTRL_ENABLE_SHIFT           31
215 #define THROT_PSKIP_CTRL_ENABLE_MASK            0x1
216 #define THROT_PSKIP_CTRL_DIVIDEND_SHIFT 8
217 #define THROT_PSKIP_CTRL_DIVIDEND_MASK          0xff
218 #define THROT_PSKIP_CTRL_DIVISOR_SHIFT          0
219 #define THROT_PSKIP_CTRL_DIVISOR_MASK           0xff
220
221 #define THROT_PSKIP_RAMP_LITE_CPU               0x434
222 #define THROT_PSKIP_RAMP_DURATION_SHIFT         8
223 #define THROT_PSKIP_RAMP_DURATION_MASK          0xffff
224 #define THROT_PSKIP_RAMP_STEP_SHIFT             0
225 #define THROT_PSKIP_RAMP_STEP_MASK              0xff
226
227 #define THROT_LITE_PRIORITY                     0x444
228 #define THROT_LITE_PRIORITY_PRIORITY_SHIFT      0
229 #define THROT_LITE_PRIORITY_PRIORITY_MASK       0xff
230
231 #define THROT_OFFSET                            0x30
232
233 #define FUSE_BASE_CP_SHIFT      0
234 #define FUSE_BASE_CP_MASK       0x3ff
235 #define FUSE_BASE_FT_SHIFT      16
236 #define FUSE_BASE_FT_MASK       0x7ff
237 #define FUSE_SHIFT_CP_SHIFT     10
238 #define FUSE_SHIFT_CP_MASK      0x3f
239 #define FUSE_SHIFT_CP_BITS      6
240 #define FUSE_SHIFT_FT_SHIFT     27
241 #define FUSE_SHIFT_FT_MASK      0x1f
242 #define FUSE_SHIFT_FT_BITS      5
243
244 #define FUSE_TSENSOR_CALIB_FT_SHIFT     13
245 #define FUSE_TSENSOR_CALIB_FT_MASK      0x1fff
246 #define FUSE_TSENSOR_CALIB_CP_SHIFT     0
247 #define FUSE_TSENSOR_CALIB_CP_MASK      0x1fff
248 #define FUSE_TSENSOR_CALIB_BITS         13
249
250 #define PSKIP_CTRL_OC1_CPU                      0x490
251
252 #define THROT_PSKIP_CTRL(throt, dev)            (THROT_PSKIP_CTRL_LITE_CPU + \
253                                                 (THROT_OFFSET * throt) + \
254                                                 (8 * dev))
255 #define THROT_PSKIP_RAMP(throt, dev)            (THROT_PSKIP_RAMP_LITE_CPU + \
256                                                 (THROT_OFFSET * throt) + \
257                                                 (8 * dev))
258
259 #define REG_SET(r, _name, val)  (((r) & ~(_name##_MASK << _name##_SHIFT)) | \
260                                  (((val) & _name##_MASK) << _name##_SHIFT))
261 #define REG_GET_BIT(r, _name)   ((r) & (_name##_MASK << _name##_SHIFT))
262 #define REG_GET(r, _name)       (REG_GET_BIT(r, _name) >> _name##_SHIFT)
263 #define MAKE_SIGNED32(val, nb)  ((s32)(val) << (32 - (nb)) >> (32 - (nb)))
264
265 static const void __iomem *reg_soctherm_base = IO_ADDRESS(TEGRA_SOCTHERM_BASE);
266 static const void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
267 static const void __iomem *clk_reset_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
268
269 #define clk_reset_writel(value, reg) \
270         __raw_writel(value, (u32)clk_reset_base + (reg))
271 #define clk_reset_readl(reg) __raw_readl((u32)clk_reset_base + (reg))
272
273 #define pmc_writel(value, reg) __raw_writel(value, (u32)pmc_base + (reg))
274 #define pmc_readl(reg) __raw_readl((u32)pmc_base + (reg))
275
276 #define soctherm_writel(value, reg) \
277         __raw_writel(value, (u32)reg_soctherm_base + (reg))
278 #define soctherm_readl(reg) \
279         __raw_readl((u32)reg_soctherm_base + (reg))
280
281 #define max4(a, b, c, d)        (max((max((a), (b))), (max((c), (d)))))
282
283 static struct soctherm_platform_data plat_data;
284
285 /*
286  * Remove this flag once this "driver" is structured as a platform driver and
287  * the board files calls platform_device_register instead of directly calling
288  * tegra11_soctherm_init(). See nvbug 1206311.
289  */
290 static bool soctherm_init_platform_done;
291
292 static struct clk *soctherm_clk;
293 static struct clk *tsensor_clk;
294
295 #ifdef CONFIG_THERMAL
296 static struct thermal_zone_device *thz[THERM_SIZE];
297 #endif
298 static struct workqueue_struct *workqueue;
299 static struct work_struct work;
300
301 static u32 fuse_calib_base_cp;
302 static u32 fuse_calib_base_ft;
303 static s32 actual_temp_cp;
304 static s32 actual_temp_ft;
305
306 static const char *const therm_names[] = {
307         [THERM_CPU] = "CPU",
308         [THERM_MEM] = "MEM",
309         [THERM_GPU] = "GPU",
310         [THERM_PLL] = "PLL",
311 };
312
313 static const char *const sensor_names[] = {
314         [TSENSE_CPU0] = "cpu0",
315         [TSENSE_CPU1] = "cpu1",
316         [TSENSE_CPU2] = "cpu2",
317         [TSENSE_CPU3] = "cpu3",
318         [TSENSE_MEM0] = "mem0",
319         [TSENSE_MEM1] = "mem1",
320         [TSENSE_GPU]  = "gpu0",
321         [TSENSE_PLLX] = "pllx",
322 };
323
324 static const int sensor2tsensorcalib[] = {
325         [TSENSE_CPU0] = 0,
326         [TSENSE_CPU1] = 1,
327         [TSENSE_CPU2] = 2,
328         [TSENSE_CPU3] = 3,
329         [TSENSE_MEM0] = 5,
330         [TSENSE_MEM1] = 6,
331         [TSENSE_GPU]  = 4,
332         [TSENSE_PLLX] = 7,
333 };
334
335 static const int tsensor2therm_map[] = {
336         [TSENSE_CPU0] = THERM_CPU,
337         [TSENSE_CPU1] = THERM_CPU,
338         [TSENSE_CPU2] = THERM_CPU,
339         [TSENSE_CPU3] = THERM_CPU,
340         [TSENSE_GPU]  = THERM_GPU,
341         [TSENSE_MEM0] = THERM_MEM,
342         [TSENSE_MEM1] = THERM_MEM,
343         [TSENSE_PLLX] = THERM_PLL,
344 };
345
346 static const enum soctherm_throttle_dev_id therm2dev[] = {
347         [THERM_CPU] = THROTTLE_DEV_CPU,
348         [THERM_MEM] = -1,
349         [THERM_GPU] = THROTTLE_DEV_GPU,
350         [THERM_PLL] = -1,
351 };
352
353 static const struct soctherm_sensor sensor_defaults = {
354         .tall      = 16300,
355         .tiddq     = 1,
356         .ten_count = 1,
357         .tsample   = 163,
358         .pdiv      = 10,
359 };
360
361 static const unsigned long default_soctherm_clk_rate = 136000000;
362 static const unsigned long default_tsensor_clk_rate = 500000;
363
364 static const struct soctherm_throttle_dev throttle_defaults[] = {
365         [THROTTLE_LIGHT] = {
366                 .dividend = 229,        /* 20% throttling */
367                 .divisor  = 255,
368                 .duration = 0xff,
369                 .step     = 0xf,
370         },
371         [THROTTLE_HEAVY] = {
372                 .dividend = 51,         /* 80% throttling */
373                 .divisor  = 255,
374                 .duration = 0xff,
375                 .step     = 0xf,
376         },
377 };
378
379 static inline s64 div64_s64_precise(s64 a, s32 b)
380 {
381         s64 r, al;
382
383         /* scale up for increased precision in division */
384         al = a << 16;
385
386         r = div64_s64((al * 2) + 1, 2 * b);
387         return r >> 16;
388 }
389
390 static inline long temp_translate(int readback)
391 {
392         int abs = readback >> 8;
393         int lsb = (readback & 0x80) >> 7;
394         int sign = readback & 0x01 ? -1 : 1;
395
396         if (!soc_therm_precision)
397                 return (abs * 2000 + lsb * 1000) * sign;
398         else
399                 return (abs * 1000 + lsb * 500) * sign;
400 }
401
402 #ifdef CONFIG_THERMAL
403 static inline void prog_hw_shutdown(struct thermal_trip_info *trip_state,
404                                     int therm)
405 {
406         int trip_temp;
407         u32 r;
408
409         trip_temp = trip_state->trip_temp / 1000;
410         if (!soc_therm_precision)
411                 trip_temp /= 2;
412
413         r = soctherm_readl(THERMTRIP);
414         if (therm == THERM_CPU) {
415                 r = REG_SET(r, THERMTRIP_CPU_EN, 1);
416                 r = REG_SET(r, THERMTRIP_CPU_THRESH, trip_temp);
417         } else {
418                 r = REG_SET(r, THERMTRIP_GPU_EN, 1);
419                 r = REG_SET(r, THERMTRIP_GPUMEM_THRESH, trip_temp);
420         }
421         soctherm_writel(r, THERMTRIP);
422 }
423
424 static inline void prog_hw_threshold(struct thermal_trip_info *trip_state,
425                                      int therm, int throt)
426 {
427         int trip_temp;
428         u32 r, reg_off;
429
430         trip_temp = trip_state->trip_temp / 1000;
431         if (!soc_therm_precision)
432                 trip_temp /= 2;
433
434         /* Hardcode LITE on level-1 and HEAVY on level-2 */
435         reg_off = TS_THERM_REG_OFFSET(CTL_LVL0_CPU0, throt + 1, therm);
436
437         r = soctherm_readl(reg_off);
438         r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, trip_temp);
439
440         trip_state->hysteresis = trip_state->hysteresis ?:
441                 !soc_therm_precision ? 1000 : 2000;
442         trip_temp -= (trip_state->hysteresis / 1000);
443
444         r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, trip_temp);
445         r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
446         r = REG_SET(r, CTL_LVL0_CPU0_CPU_THROT,
447                     throt == THROTTLE_HEAVY ?
448                     CTL_LVL0_CPU0_CPU_THROT_HEAVY :
449                     CTL_LVL0_CPU0_CPU_THROT_LIGHT);
450
451         soctherm_writel(r, reg_off);
452 }
453
454 static int soctherm_set_limits(enum soctherm_therm_id therm,
455                                 long lo_limit, long hi_limit)
456 {
457         u32 r = soctherm_readl(CTL_LVL0_CPU0);
458
459         if (!soc_therm_precision) {
460                 lo_limit /= 2;
461                 hi_limit /= 2;
462         }
463
464         r = REG_SET(r, CTL_LVL0_CPU0_DN_THRESH, lo_limit);
465         r = REG_SET(r, CTL_LVL0_CPU0_UP_THRESH, hi_limit);
466         soctherm_writel(r, CTL_LVL0_CPU0);
467
468         soctherm_writel(1<<INTR_EN_CU0_SHIFT, INTR_EN);
469         soctherm_writel(1<<INTR_EN_CD0_SHIFT, INTR_EN);
470         return 0;
471 }
472
473 static void soctherm_update(void)
474 {
475         long temp, trip_temp, low_temp = 0, high_temp = 128000;
476         int i, count;
477         enum thermal_trip_type trip_type;
478
479         if (!soctherm_init_platform_done)
480                 return;
481
482         for (i = 0; i < THERM_SIZE; i++) {
483                 if (!thz[i])
484                         continue;
485
486                 thermal_zone_device_update(thz[i]);
487
488                 thz[i]->ops->get_temp(thz[i], &temp);
489
490                 for (count = 0; count < thz[i]->trips; count++) {
491                         thz[i]->ops->get_trip_type(thz[i], count, &trip_type);
492                         if ((trip_type == THERMAL_TRIP_HOT) ||
493                             (trip_type == THERMAL_TRIP_CRITICAL))
494                                 continue; /* handled in HW */
495
496                         thz[i]->ops->get_trip_temp(thz[i], count, &trip_temp);
497
498                         if ((trip_temp >= temp) && (trip_temp < high_temp))
499                                 high_temp = trip_temp;
500
501                         if ((trip_temp < temp) && (trip_temp > low_temp))
502                                 low_temp = trip_temp -
503                                     plat_data.therm[i].trips[count].hysteresis;
504                 }
505         }
506
507         soctherm_set_limits(THERM_CPU, low_temp/1000, high_temp/1000);
508 }
509
510 static int soctherm_hw_action_get_max_state(struct thermal_cooling_device *cdev,
511                                             unsigned long *max_state)
512 {
513         struct thermal_trip_info *trip_state = cdev->devdata;
514
515         if (!trip_state)
516                 return 0;
517
518         *max_state = 1;
519         return 0;
520 }
521
522 static int soctherm_hw_action_get_cur_state(struct thermal_cooling_device *cdev,
523                                             unsigned long *cur_state)
524 {
525         struct thermal_trip_info *trip_state = cdev->devdata;
526         u32 pskip_m;
527
528         if (!trip_state)
529                 return 0;
530
531         *cur_state = 0;
532         if (trip_state->trip_type != THERMAL_TRIP_HOT)
533                 return 0;
534
535         pskip_m = REG_GET(soctherm_readl(CPU_PSKIP_STATUS), CPU_PSKIP_STATUS_M);
536
537         if (strnstr(trip_state->cdev_type, "heavy", THERMAL_NAME_LENGTH) &&
538             pskip_m == throttle_defaults[THROTTLE_LIGHT].dividend)
539                 return 0;
540
541         if (strnstr(trip_state->cdev_type, "light", THERMAL_NAME_LENGTH) &&
542             pskip_m == throttle_defaults[THROTTLE_HEAVY].dividend)
543                 return 0;
544
545         *cur_state =
546                 !!REG_GET(soctherm_readl(THROT_STATUS), THROT_STATUS_STATE);
547         return 0;
548 }
549
550 static int soctherm_hw_action_set_cur_state(struct thermal_cooling_device *cdev,
551                                             unsigned long cur_state)
552 {
553         return 0; /* hw sets this state */
554 }
555
556 static struct thermal_cooling_device_ops soctherm_hw_action_ops = {
557         .get_max_state = soctherm_hw_action_get_max_state,
558         .get_cur_state = soctherm_hw_action_get_cur_state,
559         .set_cur_state = soctherm_hw_action_set_cur_state,
560 };
561
562 static int soctherm_bind(struct thermal_zone_device *thz,
563                                 struct thermal_cooling_device *cdev)
564 {
565         int i, index = ((int)thz->devdata) - TSENSE_SIZE;
566         struct thermal_trip_info *trip_state;
567
568         if (index < 0)
569                 return 0;
570
571         for (i = 0; i < plat_data.therm[index].num_trips; i++) {
572                 trip_state = &plat_data.therm[index].trips[i];
573                 trip_state->hysteresis = trip_state->hysteresis ?: 2000;
574                 if (trip_state->cdev_type &&
575                     !strncmp(trip_state->cdev_type, cdev->type,
576                              THERMAL_NAME_LENGTH))
577                         thermal_zone_bind_cooling_device(thz, i, cdev,
578                                                          trip_state->upper,
579                                                          trip_state->lower);
580         }
581
582         return 0;
583 }
584
585 static int soctherm_unbind(struct thermal_zone_device *thz,
586                                 struct thermal_cooling_device *cdev)
587 {
588         int i, index = ((int)thz->devdata) - TSENSE_SIZE;
589         struct thermal_trip_info *trip_state;
590
591         if (index < 0)
592                 return 0;
593
594         for (i = 0; i < plat_data.therm[index].num_trips; i++) {
595                 trip_state = &plat_data.therm[index].trips[i];
596                 if (trip_state->cdev_type &&
597                     !strncmp(trip_state->cdev_type, cdev->type,
598                              THERMAL_NAME_LENGTH))
599                         thermal_zone_unbind_cooling_device(thz, 0, cdev);
600         }
601
602         return 0;
603 }
604
605 static int soctherm_get_temp(struct thermal_zone_device *thz,
606                                         unsigned long *temp)
607 {
608         int index = (int)thz->devdata;
609         u32 r;
610
611         if (index < TSENSE_SIZE) {
612                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_STATUS1,
613                                                         index));
614                 *temp = temp_translate(REG_GET(r, TS_CPU0_STATUS1_TEMP));
615         } else {
616                 index -= TSENSE_SIZE;
617
618                 if (index == THERM_CPU || index == THERM_GPU)
619                         r = soctherm_readl(TS_TEMP1);
620                 else
621                         r = soctherm_readl(TS_TEMP2);
622
623                 if (index == THERM_CPU || index == THERM_MEM)
624                         *temp = temp_translate(REG_GET(r, TS_TEMP1_CPU_TEMP));
625                 else
626                         *temp = temp_translate(REG_GET(r, TS_TEMP1_GPU_TEMP));
627
628                 plat_data.therm[index].etemp = *temp;
629         }
630
631         return 0;
632 }
633
634 static int soctherm_get_trip_type(struct thermal_zone_device *thz,
635                                 int trip, enum thermal_trip_type *type)
636 {
637         int index = ((int)thz->devdata) - TSENSE_SIZE;
638         struct thermal_trip_info *trip_state;
639
640         if (index < 0)
641                 return -EINVAL;
642
643         trip_state = &plat_data.therm[index].trips[trip];
644         *type = trip_state->trip_type;
645         return 0;
646 }
647
648 static int soctherm_get_trip_temp(struct thermal_zone_device *thz,
649                                 int trip, unsigned long *temp)
650 {
651         int index = ((int)thz->devdata) - TSENSE_SIZE;
652         struct thermal_trip_info *trip_state;
653
654         if (index < 0)
655                 return -EINVAL;
656
657         trip_state = &plat_data.therm[index].trips[trip];
658         *temp = trip_state->trip_temp;
659         return 0;
660 }
661
662 static int soctherm_set_trip_temp(struct thermal_zone_device *thz,
663                                 int trip, unsigned long temp)
664 {
665         int index = ((int)thz->devdata) - TSENSE_SIZE;
666         struct thermal_trip_info *trip_state;
667         long rem;
668
669         if (index < 0)
670                 return -EINVAL;
671
672         trip_state = &plat_data.therm[index].trips[trip];
673         trip_state->trip_temp = temp;
674
675         rem = trip_state->trip_temp % (!soc_therm_precision ? 2000 : 1000);
676         if (rem) {
677                 pr_warn("soctherm: zone%d/trip_point%d %ld mC rounded down\n",
678                         index, trip, trip_state->trip_temp);
679                 trip_state->trip_temp -= rem;
680         }
681
682         if (trip_state->trip_type == THERMAL_TRIP_HOT) {
683                 if (strnstr(trip_state->cdev_type,
684                                 "heavy", THERMAL_NAME_LENGTH))
685                         prog_hw_threshold(trip_state, index, THROTTLE_HEAVY);
686                 else if (strnstr(trip_state->cdev_type,
687                                 "light", THERMAL_NAME_LENGTH))
688                         prog_hw_threshold(trip_state, index, THROTTLE_LIGHT);
689         }
690
691         /* Allow SW to shutdown at 'Critical temperature reached' */
692         soctherm_update();
693
694         /* Reprogram HW thermtrip */
695         if (trip_state->trip_type == THERMAL_TRIP_CRITICAL)
696                 prog_hw_shutdown(trip_state, index);
697
698         return 0;
699 }
700
701 static int soctherm_get_trend(struct thermal_zone_device *thz,
702                                 int trip,
703                                 enum thermal_trend *trend)
704 {
705         int index = ((int)thz->devdata) - TSENSE_SIZE;
706         struct thermal_trip_info *trip_state;
707
708         if (index < 0)
709                 return -EINVAL;
710
711         trip_state = &plat_data.therm[index].trips[trip];
712
713         switch (trip_state->trip_type) {
714         case THERMAL_TRIP_ACTIVE:
715                 /* aggressive active cooling */
716                 *trend = THERMAL_TREND_RAISING;
717                 break;
718         case THERMAL_TRIP_PASSIVE:
719                 if (plat_data.therm[index].etemp > trip_state->trip_temp)
720                         *trend = THERMAL_TREND_RAISING;
721                 else
722                         *trend = THERMAL_TREND_DROPPING;
723                 break;
724         default:
725                 return -EINVAL;
726         }
727
728         return 0;
729 }
730
731 static struct thermal_zone_device_ops soctherm_ops = {
732         .bind = soctherm_bind,
733         .unbind = soctherm_unbind,
734         .get_temp = soctherm_get_temp,
735         .get_trip_type = soctherm_get_trip_type,
736         .get_trip_temp = soctherm_get_trip_temp,
737         .set_trip_temp = soctherm_set_trip_temp,
738         .get_trend = soctherm_get_trend,
739 };
740
741 static int __init soctherm_thermal_sys_init(void)
742 {
743         char name[THERMAL_NAME_LENGTH];
744         struct soctherm_therm *therm;
745         int i, j, k;
746
747         if (!soctherm_init_platform_done)
748                 return 0;
749
750
751         for (i = 0; i < TSENSE_SIZE; i++) {
752                 if (plat_data.sensor_data[i].zone_enable) {
753                         snprintf(name, THERMAL_NAME_LENGTH,
754                                  "%s-tsensor", sensor_names[i]);
755                         /* Create a thermal zone device for each sensor */
756                         thermal_zone_device_register(
757                                         name,
758                                         0,
759                                         0,
760                                         (void *)i,
761                                         &soctherm_ops,
762                                         NULL,
763                                         0,
764                                         0);
765                 }
766         }
767
768         for (i = 0; i < THERM_SIZE; i++) {
769                 therm = &plat_data.therm[i];
770                 if (!therm->zone_enable)
771                         continue;
772
773                 for (j = 0; j < therm->num_trips; j++) {
774                         switch (therm->trips[j].trip_type) {
775                         case THERMAL_TRIP_CRITICAL:
776                                 thermal_cooling_device_register(
777                                                 therm->trips[j].cdev_type,
778                                                 &therm->trips[j],
779                                                 &soctherm_hw_action_ops);
780                                 break;
781
782                         case THERMAL_TRIP_HOT:
783                                 for (k = 0; k < THROTTLE_SIZE; k++) {
784                                         if ((strnstr(therm->trips[j].cdev_type,
785                                                      "heavy",
786                                                      THERMAL_NAME_LENGTH)
787                                              && k == THROTTLE_LIGHT) ||
788                                             (strnstr(therm->trips[j].cdev_type,
789                                                      "light",
790                                                      THERMAL_NAME_LENGTH)
791                                              && k == THROTTLE_HEAVY))
792                                                 continue;
793
794                                         if (!plat_data.throttle[k].
795                                             devs[therm2dev[i]].enable)
796                                                 continue;
797
798                                         thermal_cooling_device_register(
799                                                 therm->trips[j].cdev_type,
800                                                 &therm->trips[j],
801                                                 &soctherm_hw_action_ops);
802                                 }
803                                 break;
804
805                         case THERMAL_TRIP_PASSIVE:
806                         case THERMAL_TRIP_ACTIVE:
807                                 break; /* done elsewhere */
808                         }
809                 }
810
811                 snprintf(name, THERMAL_NAME_LENGTH,
812                          "%s-therm", therm_names[i]);
813                 thz[i] = thermal_zone_device_register(
814                                         name,
815                                         therm->num_trips,
816                                         (1 << therm->num_trips) - 1,
817                                         (void *)TSENSE_SIZE + i,
818                                         &soctherm_ops,
819                                         NULL,
820                                         therm->passive_delay,
821                                         0);
822         }
823
824         soctherm_update();
825         return 0;
826 }
827 module_init(soctherm_thermal_sys_init);
828
829 #else
830 static void soctherm_update(void)
831 {
832 }
833 #endif
834
835 static void soctherm_work_func(struct work_struct *work)
836 {
837         u32 st, ex = 0;
838
839         st = soctherm_readl(INTR_STATUS);
840
841         /* deliberately clear expected interrupts handled in SW */
842         ex |= REG_GET_BIT(st, INTR_STATUS_CD0);
843         ex |= REG_GET_BIT(st, INTR_STATUS_CU0);
844         if (ex) {
845                 soctherm_writel(ex, INTR_STATUS);
846                 st &= ~ex;
847                 soctherm_update();
848         }
849
850         /* deliberately ignore expected interrupts NOT handled in SW */
851         ex |= REG_GET_BIT(st, INTR_STATUS_CD1);
852         ex |= REG_GET_BIT(st, INTR_STATUS_CU1);
853         ex |= REG_GET_BIT(st, INTR_STATUS_CD2);
854         ex |= REG_GET_BIT(st, INTR_STATUS_CU2);
855         st &= ~ex;
856
857         if (!st)
858                 return;
859
860         /* Whine about any other unexpected INTR bits still set */
861         pr_err("soctherm: Ignored unexpected INTRs 0x%08x\n", st);
862         soctherm_writel(st, INTR_STATUS);
863 }
864
865 static irqreturn_t soctherm_isr(int irq, void *arg_data)
866 {
867         u32 r;
868
869         queue_work(workqueue, &work);
870
871         r = soctherm_readl(INTR_STATUS);
872         soctherm_writel(r, INTR_DIS);
873
874         return IRQ_HANDLED;
875 }
876
877 void tegra11_soctherm_throttle_program(enum soctherm_throttle_id throttle,
878                                         struct soctherm_throttle *data)
879 {
880         u32 r;
881         int i;
882         struct soctherm_throttle_dev *dev;
883
884         for (i = 0; i < THROTTLE_DEV_SIZE; i++) {
885                 dev = &data->devs[i];
886
887                 r = soctherm_readl(THROT_PSKIP_CTRL(throttle, i));
888                 r = REG_SET(r, THROT_PSKIP_CTRL_ENABLE, dev->enable);
889                 if (!dev->enable)
890                         continue;
891
892                 r = REG_SET(r, THROT_PSKIP_CTRL_DIVIDEND,
893                         dev->dividend ?: throttle_defaults[throttle].dividend);
894                 r = REG_SET(r, THROT_PSKIP_CTRL_DIVISOR,
895                         dev->divisor ?: throttle_defaults[throttle].divisor);
896                 soctherm_writel(r, THROT_PSKIP_CTRL(throttle, i));
897
898                 r = soctherm_readl(THROT_PSKIP_RAMP(throttle, i));
899                 r = REG_SET(r, THROT_PSKIP_RAMP_DURATION,
900                         dev->duration ?: throttle_defaults[throttle].duration);
901                 r = REG_SET(r, THROT_PSKIP_RAMP_STEP,
902                         dev->step ?: throttle_defaults[throttle].step);
903                 soctherm_writel(r, THROT_PSKIP_RAMP(throttle, i));
904         }
905
906         r = soctherm_readl(THROT_PRIORITY_LOCK);
907         if (r < data->priority) {
908                 r = REG_SET(0, THROT_PRIORITY_LOCK_PRIORITY, data->priority);
909                 soctherm_writel(r, THROT_PRIORITY_LOCK);
910         }
911
912         r = REG_SET(0, THROT_LITE_PRIORITY_PRIORITY, data->priority);
913         soctherm_writel(r, THROT_LITE_PRIORITY + THROT_OFFSET * throttle);
914
915         /* initialize stats collection */
916         r = STATS_CTL_CLR_DN | STATS_CTL_EN_DN |
917                 STATS_CTL_CLR_UP | STATS_CTL_EN_UP;
918         soctherm_writel(r, STATS_CTL);
919 }
920
921 static void __init soctherm_tsense_program(enum soctherm_sense sensor,
922                                                 struct soctherm_sensor *data)
923 {
924         u32 r;
925
926         r = REG_SET(0, TS_CPU0_CONFIG0_TALL, data->tall);
927         soctherm_writel(r, TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG0, sensor));
928
929         r = REG_SET(0, TS_CPU0_CONFIG1_TIDDQ, data->tiddq);
930         r = REG_SET(r, TS_CPU0_CONFIG1_EN, 1);
931         r = REG_SET(r, TS_CPU0_CONFIG1_TEN_COUNT, data->ten_count);
932         r = REG_SET(r, TS_CPU0_CONFIG1_TSAMPLE, data->tsample);
933         soctherm_writel(r, TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG1, sensor));
934 }
935
936 static int __init soctherm_clk_init(void)
937 {
938         soctherm_clk = clk_get_sys("soc_therm", NULL);
939         tsensor_clk = clk_get_sys("tegra-tsensor", NULL);
940
941         if (IS_ERR(tsensor_clk) || IS_ERR(soctherm_clk)) {
942                 clk_put(soctherm_clk);
943                 clk_put(tsensor_clk);
944                 soctherm_clk = tsensor_clk = NULL;
945                 return -EINVAL;
946         }
947
948         /* initialize default clock rates */
949         plat_data.soctherm_clk_rate =
950                 plat_data.soctherm_clk_rate ?: default_soctherm_clk_rate;
951         plat_data.tsensor_clk_rate =
952                 plat_data.tsensor_clk_rate ?: default_tsensor_clk_rate;
953
954         if (clk_get_rate(soctherm_clk) != plat_data.soctherm_clk_rate)
955                 if (clk_set_rate(soctherm_clk, plat_data.soctherm_clk_rate))
956                         return -EINVAL;
957
958         if (clk_get_rate(tsensor_clk) != plat_data.tsensor_clk_rate)
959                 if (clk_set_rate(tsensor_clk, plat_data.tsensor_clk_rate))
960                         return -EINVAL;
961
962         return 0;
963 }
964
965 static int soctherm_clk_enable(bool enable)
966 {
967         if (soctherm_clk == NULL || tsensor_clk == NULL)
968                 return -EINVAL;
969
970         if (enable) {
971                 clk_enable(soctherm_clk);
972                 clk_enable(tsensor_clk);
973         } else {
974                 clk_disable(soctherm_clk);
975                 clk_disable(tsensor_clk);
976         }
977
978         return 0;
979 }
980
981 static void soctherm_fuse_read_vsensor(void)
982 {
983         u32 value;
984         s32 calib_cp, calib_ft;
985
986         tegra_fuse_get_vsensor_calib(&value);
987
988         /* Extract bits */
989         fuse_calib_base_cp = REG_GET(value, FUSE_BASE_CP);
990         fuse_calib_base_ft = REG_GET(value, FUSE_BASE_FT);
991
992         /* Extract bits and convert to signed 2's complement */
993         calib_cp = REG_GET(value, FUSE_SHIFT_CP);
994         calib_cp = MAKE_SIGNED32(calib_cp, FUSE_SHIFT_CP_BITS);
995
996         calib_ft = REG_GET(value, FUSE_SHIFT_FT);
997         calib_ft = MAKE_SIGNED32(calib_ft, FUSE_SHIFT_FT_BITS);
998
999         /* default: HI precision: use fuse_temp in 0.5C */
1000         actual_temp_cp = 2 * 25 + calib_cp;
1001         actual_temp_ft = 2 * 90 + calib_ft;
1002
1003         /* adjust: for LO precision: use fuse_temp in 1C */
1004         if (!soc_therm_precision) {
1005                 actual_temp_cp /= 2;
1006                 actual_temp_ft /= 2;
1007         }
1008 }
1009
1010 static int fuse_corr_alpha[] = { /* scaled *1000000 */
1011         [TSENSE_CPU0] = 1196400,
1012         [TSENSE_CPU1] = 1196400,
1013         [TSENSE_CPU2] = 1196400,
1014         [TSENSE_CPU3] = 1196400,
1015         [TSENSE_GPU]  = 1124500,
1016         [TSENSE_PLLX] = 1224200,
1017 };
1018
1019 static int fuse_corr_beta[] = { /* scaled *1000000 */
1020         [TSENSE_CPU0] = -13600000,
1021         [TSENSE_CPU1] = -13600000,
1022         [TSENSE_CPU2] = -13600000,
1023         [TSENSE_CPU3] = -13600000,
1024         [TSENSE_GPU]  =  -9793100,
1025         [TSENSE_PLLX] = -14665000,
1026 };
1027
1028 static void soctherm_fuse_read_tsensor(enum soctherm_sense sensor)
1029 {
1030         u32 r, value;
1031         s32 calib, delta_sens, delta_temp;
1032         s16 therm_a, therm_b;
1033         s32 div, mult, actual_tsensor_ft, actual_tsensor_cp;
1034
1035         tegra_fuse_get_tsensor_calib(sensor2tsensorcalib[sensor], &value);
1036
1037         /* Extract bits and convert to signed 2's complement */
1038         calib = REG_GET(value, FUSE_TSENSOR_CALIB_FT);
1039         calib = MAKE_SIGNED32(calib, FUSE_TSENSOR_CALIB_BITS);
1040         actual_tsensor_ft = (fuse_calib_base_ft * 32) + calib;
1041
1042         calib = REG_GET(value, FUSE_TSENSOR_CALIB_CP);
1043         calib = MAKE_SIGNED32(calib, FUSE_TSENSOR_CALIB_BITS);
1044         actual_tsensor_cp = (fuse_calib_base_cp * 64) + calib;
1045
1046         mult = plat_data.sensor_data[sensor].pdiv * 655;
1047         div = plat_data.sensor_data[sensor].tsample * 10;
1048
1049         delta_sens = actual_tsensor_ft - actual_tsensor_cp;
1050         delta_temp = actual_temp_ft - actual_temp_cp;
1051
1052         therm_a = div64_s64_precise((s64)delta_temp * (1LL << 13) * mult,
1053                                     (s64)delta_sens * div);
1054
1055         therm_b = div64_s64_precise((((s64)actual_tsensor_ft * actual_temp_cp) -
1056                                      ((s64)actual_tsensor_cp * actual_temp_ft)),
1057                                     (s64)delta_sens);
1058
1059         if (!soc_therm_precision) {
1060                 /* cp_fuse corrections */
1061                 fuse_corr_alpha[sensor] = fuse_corr_alpha[sensor] ?: 1000000;
1062                 therm_a = div64_s64_precise(
1063                                 (s64)therm_a * fuse_corr_alpha[sensor],
1064                                 (s64)1000000LL);
1065                 therm_b = div64_s64_precise(
1066                                 (s64)therm_b * fuse_corr_alpha[sensor] +
1067                                 fuse_corr_beta[sensor], (s64)1000000LL);
1068         }
1069
1070         r = REG_SET(0, TS_CPU0_CONFIG2_THERM_A, therm_a);
1071         r = REG_SET(r, TS_CPU0_CONFIG2_THERM_B, therm_b);
1072         soctherm_writel(r, TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG2, sensor));
1073 }
1074
1075 static int soctherm_init_platform_data(void)
1076 {
1077         struct soctherm_therm *therm;
1078         struct soctherm_sensor *s;
1079         int i, j, k;
1080         long rem;
1081         u32 r;
1082
1083         /* initialize default values for unspecified params */
1084         for (i = 0; i < TSENSE_SIZE; i++) {
1085                 therm = &plat_data.therm[tsensor2therm_map[i]];
1086                 s = &plat_data.sensor_data[i];
1087                 s->sensor_enable = s->zone_enable;
1088                 s->sensor_enable = s->sensor_enable ?: therm->zone_enable;
1089                 s->tall      = s->tall      ?: sensor_defaults.tall;
1090                 s->tiddq     = s->tiddq     ?: sensor_defaults.tiddq;
1091                 s->ten_count = s->ten_count ?: sensor_defaults.ten_count;
1092                 s->tsample   = s->tsample   ?: sensor_defaults.tsample;
1093                 s->pdiv      = s->pdiv      ?: sensor_defaults.pdiv;
1094         }
1095
1096         /* Pdiv */
1097         r = soctherm_readl(TS_PDIV);
1098         r = REG_SET(r, TS_PDIV_CPU, plat_data.sensor_data[TSENSE_CPU0].pdiv);
1099         r = REG_SET(r, TS_PDIV_GPU, plat_data.sensor_data[TSENSE_GPU].pdiv);
1100         r = REG_SET(r, TS_PDIV_MEM, plat_data.sensor_data[TSENSE_MEM0].pdiv);
1101         r = REG_SET(r, TS_PDIV_PLLX, plat_data.sensor_data[TSENSE_PLLX].pdiv);
1102         soctherm_writel(r, TS_PDIV);
1103
1104         /* Thermal Sensing programming */
1105         soctherm_fuse_read_vsensor();
1106         for (i = 0; i < TSENSE_SIZE; i++) {
1107                 if (plat_data.sensor_data[i].sensor_enable) {
1108                         soctherm_tsense_program(i, &plat_data.sensor_data[i]);
1109                         soctherm_fuse_read_tsensor(i);
1110                 }
1111         }
1112
1113         /* Sanitize therm trips */
1114         for (i = 0; i < THERM_SIZE; i++) {
1115                 therm = &plat_data.therm[i];
1116                 if (!therm->zone_enable)
1117                         continue;
1118
1119                 for (j = 0; j < therm->num_trips; j++) {
1120                         rem = therm->trips[j].trip_temp %
1121                                 (!soc_therm_precision ? 2000 : 1000);
1122                         if (rem) {
1123                                 pr_warn(
1124                         "soctherm: zone%d/trip_point%d %ld mC rounded down\n",
1125                                         i, j, therm->trips[j].trip_temp);
1126                                 therm->trips[j].trip_temp -= rem;
1127                         }
1128                 }
1129         }
1130
1131         /* Sanitize HW throttle priority */
1132         for (i = 0; i < THROTTLE_SIZE; i++)
1133                 if (!plat_data.throttle[i].priority)
1134                         plat_data.throttle[i].priority = 0xE + i;
1135         if (plat_data.throttle[THROTTLE_HEAVY].priority <
1136             plat_data.throttle[THROTTLE_LIGHT].priority)
1137                 pr_err("soctherm: ERROR: Priority of HEAVY less than LIGHT\n");
1138
1139         /* Thermal HW throttle programming */
1140         for (i = 0; i < THROTTLE_SIZE; i++) {
1141                 /* Setup PSKIP parameters */
1142                 tegra11_soctherm_throttle_program(i, &plat_data.throttle[i]);
1143
1144                 /* Setup throttle thresholds per THERM */
1145                 for (j = 0; j < THERM_SIZE; j++) {
1146                         /* Check if PSKIP params are enabled */
1147                         if ((therm2dev[j] == -1) ||
1148                             (!plat_data.throttle[i].devs[therm2dev[j]].enable))
1149                                 continue;
1150
1151                         therm = &plat_data.therm[j];
1152                         for (k = 0; k < therm->num_trips; k++)
1153                                 if ((therm->trips[k].trip_type ==
1154                                      THERMAL_TRIP_HOT) &&
1155                                     strnstr(therm->trips[k].cdev_type,
1156                                             i == THROTTLE_HEAVY ? "heavy" :
1157                                             "light", THERMAL_NAME_LENGTH))
1158                                         break;
1159                         if (k < therm->num_trips)
1160                                 prog_hw_threshold(&therm->trips[k], j, i);
1161                 }
1162         }
1163
1164         /* Enable Level 0 */
1165         r = soctherm_readl(CTL_LVL0_CPU0);
1166         r = REG_SET(r, CTL_LVL0_CPU0_EN, 1);
1167         soctherm_writel(r, CTL_LVL0_CPU0);
1168
1169         /* Thermtrip */
1170         for (i = 0; i < THERM_SIZE; i++) {
1171                 therm = &plat_data.therm[i];
1172                 if (!therm->zone_enable)
1173                         continue;
1174
1175                 for (j = 0; j < therm->num_trips; j++)
1176                         if (therm->trips[j].trip_type == THERMAL_TRIP_CRITICAL)
1177                                 prog_hw_shutdown(&therm->trips[j], i);
1178         }
1179
1180         /* Enable PMC to shutdown */
1181         r = pmc_readl(0x1b0);
1182         r |= 0x2;
1183         pmc_writel(r, 0x1b0);
1184
1185         r = clk_reset_readl(0x24);
1186         r |= (1 << 30);
1187         clk_reset_writel(r, 0x24);
1188
1189         return 0;
1190 }
1191
1192 static int soctherm_suspend(void)
1193 {
1194         soctherm_writel((u32)-1, INTR_DIS);
1195         soctherm_clk_enable(false);
1196         disable_irq(INT_THERMAL);
1197         cancel_work_sync(&work);
1198
1199         return 0;
1200 }
1201
1202 static int soctherm_resume(void)
1203 {
1204         soctherm_clk_enable(true);
1205         enable_irq(INT_THERMAL);
1206         soctherm_init_platform_data();
1207         soctherm_update();
1208
1209         return 0;
1210 }
1211
1212 static int soctherm_pm_notify(struct notifier_block *nb,
1213                                 unsigned long event, void *data)
1214 {
1215         switch (event) {
1216         case PM_SUSPEND_PREPARE:
1217                 soctherm_suspend();
1218                 break;
1219         case PM_POST_SUSPEND:
1220                 soctherm_resume();
1221                 break;
1222         }
1223
1224         return NOTIFY_OK;
1225 }
1226
1227 static struct notifier_block soctherm_nb = {
1228         .notifier_call = soctherm_pm_notify,
1229 };
1230
1231 int __init tegra11_soctherm_init(struct soctherm_platform_data *data)
1232 {
1233         int err;
1234
1235         register_pm_notifier(&soctherm_nb);
1236
1237         if (!data)
1238                 return -1;
1239         plat_data = *data;
1240
1241         if (soctherm_clk_init() < 0)
1242                 return -1;
1243
1244         if (soctherm_clk_enable(true) < 0)
1245                 return -1;
1246
1247         if (soctherm_init_platform_data() < 0)
1248                 return -1;
1249
1250         soctherm_init_platform_done = true;
1251
1252         /* enable interrupts */
1253         workqueue = create_singlethread_workqueue("soctherm");
1254         INIT_WORK(&work, soctherm_work_func);
1255
1256         err = request_irq(INT_THERMAL, soctherm_isr, 0, "soctherm", NULL);
1257         if (err < 0)
1258                 return -1;
1259
1260         return 0;
1261 }
1262
1263 #ifdef CONFIG_DEBUG_FS
1264 static int regs_show(struct seq_file *s, void *data)
1265 {
1266         u32 r;
1267         u32 state;
1268         long tcpu[TSENSE_SIZE];
1269         int i, level;
1270
1271         seq_printf(s, "-----TSENSE (precision %s)-----\n",
1272                    !soc_therm_precision ? "Lo" : "Hi");
1273         for (i = 0; i < TSENSE_SIZE; i++) {
1274                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG1, i));
1275                 state = REG_GET(r, TS_CPU0_CONFIG1_EN);
1276                 if (!state)
1277                         continue;
1278
1279                 seq_printf(s, "%s: ", sensor_names[i]);
1280
1281                 seq_printf(s, "En(%d) ", state);
1282                 state = REG_GET(r, TS_CPU0_CONFIG1_TIDDQ);
1283                 seq_printf(s, "tiddq(%d) ", state);
1284                 state = REG_GET(r, TS_CPU0_CONFIG1_TEN_COUNT);
1285                 seq_printf(s, "ten_count(%d) ", state);
1286                 state = REG_GET(r, TS_CPU0_CONFIG1_TSAMPLE);
1287                 seq_printf(s, "tsample(%d) ", state);
1288
1289                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_STATUS0, i));
1290                 state = REG_GET(r, TS_CPU0_STATUS0_VALID);
1291                 seq_printf(s, "Capture(%d/", state);
1292                 state = REG_GET(r, TS_CPU0_STATUS0_CAPTURE);
1293                 seq_printf(s, "%d) ", state);
1294
1295                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_STATUS1, i));
1296                 state = REG_GET(r, TS_CPU0_STATUS1_TEMP_VALID);
1297                 seq_printf(s, "Temp(%d/", state);
1298                 state = REG_GET(r, TS_CPU0_STATUS1_TEMP);
1299                 seq_printf(s, "%ld) ", tcpu[i] = temp_translate(state));
1300
1301                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG0, i));
1302                 state = REG_GET(r, TS_CPU0_CONFIG0_TALL);
1303                 seq_printf(s, "Tall(%d) ", state);
1304                 state = REG_GET(r, TS_CPU0_CONFIG0_TCALC_OVER);
1305                 seq_printf(s, "Over(%d/", state);
1306                 state = REG_GET(r, TS_CPU0_CONFIG0_OVER);
1307                 seq_printf(s, "%d/", state);
1308                 state = REG_GET(r, TS_CPU0_CONFIG0_CPTR_OVER);
1309                 seq_printf(s, "%d) ", state);
1310
1311                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(TS_CPU0_CONFIG2, i));
1312                 state = REG_GET(r, TS_CPU0_CONFIG2_THERM_A);
1313                 seq_printf(s, "Therm_A/B(%d/", state);
1314                 state = REG_GET(r, TS_CPU0_CONFIG2_THERM_B);
1315                 seq_printf(s, "%d)\n", (s16)state);
1316         }
1317
1318         r = soctherm_readl(TS_PDIV);
1319         seq_printf(s, "PDIV: 0x%x\n", r);
1320
1321         seq_printf(s, "\n");
1322         seq_printf(s, "-----SOC_THERM-----\n");
1323
1324         r = soctherm_readl(TS_TEMP1);
1325         state = REG_GET(r, TS_TEMP1_CPU_TEMP);
1326         seq_printf(s, "Temperature: CPU(%ld) [Max(%ld)%c] ",
1327                    temp_translate(state),
1328                    max4(tcpu[0], tcpu[1], tcpu[2], tcpu[3]),
1329                    max4(tcpu[0], tcpu[1], tcpu[2], tcpu[3]) ==
1330                    temp_translate(state) ? '=' : '!');
1331         state = REG_GET(r, TS_TEMP1_GPU_TEMP);
1332         seq_printf(s, " GPU(%ld) ", temp_translate(state));
1333         r = soctherm_readl(TS_TEMP2);
1334         state = REG_GET(r, TS_TEMP2_MEM_TEMP);
1335         seq_printf(s, " MEM(%ld) ", temp_translate(state));
1336         state = REG_GET(r, TS_TEMP2_PLLX_TEMP);
1337         seq_printf(s, " PLLX(%ld)\n\n", temp_translate(state));
1338
1339         for (i = 0; i < THERM_SIZE; i++) {
1340                 seq_printf(s, "%s:\n", therm_names[i]);
1341
1342                 for (level = 0; level < 4; level++) {
1343                         r = soctherm_readl(TS_THERM_REG_OFFSET(CTL_LVL0_CPU0,
1344                                                                 level, i));
1345                         state = REG_GET(r, CTL_LVL0_CPU0_UP_THRESH);
1346                         seq_printf(s, "   %d: Up/Dn(%d/", level,
1347                                    !soc_therm_precision ? state * 2 : state);
1348                         state = REG_GET(r, CTL_LVL0_CPU0_DN_THRESH);
1349                         seq_printf(s, "%d) ",
1350                                    !soc_therm_precision ? state * 2 : state);
1351                         state = REG_GET(r, CTL_LVL0_CPU0_EN);
1352                         seq_printf(s, "En(%d) ", state);
1353                         state = REG_GET(r, CTL_LVL0_CPU0_CPU_THROT);
1354                         seq_printf(s, "Throt");
1355                         seq_printf(s, "(%s) ", state ?
1356                                 state == CTL_LVL0_CPU0_CPU_THROT_LIGHT ? "L" :
1357                                 state == CTL_LVL0_CPU0_CPU_THROT_HEAVY ? "H" :
1358                                 "H+L" : "none");
1359                         state = REG_GET(r, CTL_LVL0_CPU0_STATUS);
1360                         seq_printf(s, "Status(%s)\n",
1361                                    state == 0 ? "LO" :
1362                                    state == 1 ? "in" :
1363                                    state == 2 ? "??" : "HI");
1364                 }
1365         }
1366
1367         r = soctherm_readl(STATS_CTL);
1368         seq_printf(s, "STATS: Up(%s) Dn(%s)\n",
1369                    r & STATS_CTL_EN_UP ? "En" : "--",
1370                    r & STATS_CTL_EN_DN ? "En" : "--");
1371         for (level = 0; level < 4; level++) {
1372                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(UP_STATS_L0, level));
1373                 seq_printf(s, "  Level_%d Up(%d) ", level, r);
1374                 r = soctherm_readl(TS_TSENSE_REG_OFFSET(DN_STATS_L0, level));
1375                 seq_printf(s, "Dn(%d)\n", r);
1376         }
1377
1378         r = soctherm_readl(INTR_STATUS);
1379         state = REG_GET(r, INTR_STATUS_CD0);
1380         seq_printf(s, "CD0: %d\n", state);
1381         state = REG_GET(r, INTR_STATUS_CU0);
1382         seq_printf(s, "CU0: %d\n", state);
1383
1384         r = soctherm_readl(THERMTRIP);
1385         state = REG_GET(r, THERMTRIP_CPU_THRESH);
1386         seq_printf(s, "THERMTRIP_CPU_THRESH: %d ",
1387                    !soc_therm_precision ? state * 2 : state);
1388         state = REG_GET(r, THERMTRIP_CPU_EN);
1389         seq_printf(s, "%d\n", state);
1390
1391
1392         seq_printf(s, "\n-----THROTTLE-----\n");
1393
1394         r = soctherm_readl(THROT_GLOBAL_CFG);
1395         seq_printf(s, "GLOBAL CONFIG: 0x%x\n", r);
1396
1397         r = soctherm_readl(THROT_STATUS);
1398         state = REG_GET(r, THROT_STATUS_BREACH);
1399         seq_printf(s, "THROT STATUS: breach(%d) ", state);
1400         state = REG_GET(r, THROT_STATUS_STATE);
1401         seq_printf(s, "state(%d) ", state);
1402         state = REG_GET(r, THROT_STATUS_ENABLED);
1403         seq_printf(s, "enabled(%d)\n", state);
1404
1405         r = soctherm_readl(CPU_PSKIP_STATUS);
1406         state = REG_GET(r, CPU_PSKIP_STATUS_M);
1407         seq_printf(s, "CPU PSKIP: M(%d) ", state);
1408         state = REG_GET(r, CPU_PSKIP_STATUS_N);
1409         seq_printf(s, "N(%d) ", state);
1410         state = REG_GET(r, CPU_PSKIP_STATUS_ENABLED);
1411         seq_printf(s, "enabled(%d)\n", state);
1412
1413         r = soctherm_readl(THROT_PSKIP_CTRL(THROTTLE_LIGHT, THROTTLE_DEV_CPU));
1414         state = REG_GET(r, THROT_PSKIP_CTRL_ENABLE);
1415         seq_printf(s, "CPU PSKIP LIGHT: enabled(%d) ", state);
1416         state = REG_GET(r, THROT_PSKIP_CTRL_DIVIDEND);
1417         seq_printf(s, "dividend(%d) ", state);
1418         state = REG_GET(r, THROT_PSKIP_CTRL_DIVISOR);
1419         seq_printf(s, "divisor(%d) ", state);
1420         r = soctherm_readl(THROT_PSKIP_RAMP(THROTTLE_LIGHT, THROTTLE_DEV_CPU));
1421         state = REG_GET(r, THROT_PSKIP_RAMP_DURATION);
1422         seq_printf(s, "duration(%d) ", state);
1423         state = REG_GET(r, THROT_PSKIP_RAMP_STEP);
1424         seq_printf(s, "step(%d)\n", state);
1425
1426         r = soctherm_readl(THROT_PSKIP_CTRL(THROTTLE_HEAVY, THROTTLE_DEV_CPU));
1427         state = REG_GET(r, THROT_PSKIP_CTRL_ENABLE);
1428         seq_printf(s, "CPU PSKIP HEAVY: enabled(%d) ", state);
1429         state = REG_GET(r, THROT_PSKIP_CTRL_DIVIDEND);
1430         seq_printf(s, "dividend(%d) ", state);
1431         state = REG_GET(r, THROT_PSKIP_CTRL_DIVISOR);
1432         seq_printf(s, "divisor(%d) ", state);
1433         r = soctherm_readl(THROT_PSKIP_RAMP(THROTTLE_HEAVY, THROTTLE_DEV_CPU));
1434         state = REG_GET(r, THROT_PSKIP_RAMP_DURATION);
1435         seq_printf(s, "duration(%d) ", state);
1436         state = REG_GET(r, THROT_PSKIP_RAMP_STEP);
1437         seq_printf(s, "step(%d)\n", state);
1438         return 0;
1439 }
1440
1441 static int regs_open(struct inode *inode, struct file *file)
1442 {
1443         return single_open(file, regs_show, inode->i_private);
1444 }
1445
1446 static const struct file_operations regs_fops = {
1447         .open           = regs_open,
1448         .read           = seq_read,
1449         .llseek         = seq_lseek,
1450         .release        = single_release,
1451 };
1452
1453 static int __init soctherm_debug_init(void)
1454 {
1455         struct dentry *tegra_soctherm_root;
1456
1457         tegra_soctherm_root = debugfs_create_dir("tegra_soctherm", 0);
1458         debugfs_create_file("regs", 0644, tegra_soctherm_root,
1459                                 NULL, &regs_fops);
1460         return 0;
1461 }
1462 late_initcall(soctherm_debug_init);
1463 #endif