thermal: rockchip: add temperature dump when panic
[firefly-linux-kernel-4.4.55.git] / drivers / thermal / tegra_soctherm.c
1 /*
2  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Author:
5  *      Mikko Perttunen <mperttunen@nvidia.com>
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <linux/bitops.h>
19 #include <linux/clk.h>
20 #include <linux/delay.h>
21 #include <linux/err.h>
22 #include <linux/interrupt.h>
23 #include <linux/io.h>
24 #include <linux/module.h>
25 #include <linux/of.h>
26 #include <linux/platform_device.h>
27 #include <linux/reset.h>
28 #include <linux/thermal.h>
29
30 #include <soc/tegra/fuse.h>
31
32 #define SENSOR_CONFIG0                          0
33 #define SENSOR_CONFIG0_STOP                     BIT(0)
34 #define SENSOR_CONFIG0_TALL_SHIFT               8
35 #define SENSOR_CONFIG0_TCALC_OVER               BIT(4)
36 #define SENSOR_CONFIG0_OVER                     BIT(3)
37 #define SENSOR_CONFIG0_CPTR_OVER                BIT(2)
38
39 #define SENSOR_CONFIG1                          4
40 #define SENSOR_CONFIG1_TSAMPLE_SHIFT            0
41 #define SENSOR_CONFIG1_TIDDQ_EN_SHIFT           15
42 #define SENSOR_CONFIG1_TEN_COUNT_SHIFT          24
43 #define SENSOR_CONFIG1_TEMP_ENABLE              BIT(31)
44
45 #define SENSOR_CONFIG2                          8
46 #define SENSOR_CONFIG2_THERMA_SHIFT             16
47 #define SENSOR_CONFIG2_THERMB_SHIFT             0
48
49 #define SENSOR_PDIV                             0x1c0
50 #define SENSOR_PDIV_T124                        0x8888
51 #define SENSOR_HOTSPOT_OFF                      0x1c4
52 #define SENSOR_HOTSPOT_OFF_T124                 0x00060600
53 #define SENSOR_TEMP1                            0x1c8
54 #define SENSOR_TEMP2                            0x1cc
55
56 #define SENSOR_TEMP_MASK                        0xffff
57 #define READBACK_VALUE_MASK                     0xff00
58 #define READBACK_VALUE_SHIFT                    8
59 #define READBACK_ADD_HALF                       BIT(7)
60 #define READBACK_NEGATE                         BIT(1)
61
62 #define FUSE_TSENSOR8_CALIB                     0x180
63 #define FUSE_SPARE_REALIGNMENT_REG_0            0x1fc
64
65 #define FUSE_TSENSOR_CALIB_CP_TS_BASE_MASK      0x1fff
66 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK      (0x1fff << 13)
67 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT     13
68
69 #define FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK     0x3ff
70 #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK     (0x7ff << 10)
71 #define FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT    10
72
73 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_MASK 0x3f
74 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK (0x1f << 21)
75 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21
76
77 #define NOMINAL_CALIB_FT_T124                   105
78 #define NOMINAL_CALIB_CP_T124                   25
79
80 struct tegra_tsensor_configuration {
81         u32 tall, tsample, tiddq_en, ten_count, pdiv, tsample_ate, pdiv_ate;
82 };
83
84 struct tegra_tsensor {
85         const struct tegra_tsensor_configuration *config;
86         u32 base, calib_fuse_offset;
87         /* Correction values used to modify values read from calibration fuses */
88         s32 fuse_corr_alpha, fuse_corr_beta;
89 };
90
91 struct tegra_thermctl_zone {
92         void __iomem *reg;
93         unsigned int shift;
94 };
95
96 static const struct tegra_tsensor_configuration t124_tsensor_config = {
97         .tall = 16300,
98         .tsample = 120,
99         .tiddq_en = 1,
100         .ten_count = 1,
101         .pdiv = 8,
102         .tsample_ate = 480,
103         .pdiv_ate = 8
104 };
105
106 static const struct tegra_tsensor t124_tsensors[] = {
107         {
108                 .config = &t124_tsensor_config,
109                 .base = 0xc0,
110                 .calib_fuse_offset = 0x098,
111                 .fuse_corr_alpha = 1135400,
112                 .fuse_corr_beta = -6266900,
113         },
114         {
115                 .config = &t124_tsensor_config,
116                 .base = 0xe0,
117                 .calib_fuse_offset = 0x084,
118                 .fuse_corr_alpha = 1122220,
119                 .fuse_corr_beta = -5700700,
120         },
121         {
122                 .config = &t124_tsensor_config,
123                 .base = 0x100,
124                 .calib_fuse_offset = 0x088,
125                 .fuse_corr_alpha = 1127000,
126                 .fuse_corr_beta = -6768200,
127         },
128         {
129                 .config = &t124_tsensor_config,
130                 .base = 0x120,
131                 .calib_fuse_offset = 0x12c,
132                 .fuse_corr_alpha = 1110900,
133                 .fuse_corr_beta = -6232000,
134         },
135         {
136                 .config = &t124_tsensor_config,
137                 .base = 0x140,
138                 .calib_fuse_offset = 0x158,
139                 .fuse_corr_alpha = 1122300,
140                 .fuse_corr_beta = -5936400,
141         },
142         {
143                 .config = &t124_tsensor_config,
144                 .base = 0x160,
145                 .calib_fuse_offset = 0x15c,
146                 .fuse_corr_alpha = 1145700,
147                 .fuse_corr_beta = -7124600,
148         },
149         {
150                 .config = &t124_tsensor_config,
151                 .base = 0x180,
152                 .calib_fuse_offset = 0x154,
153                 .fuse_corr_alpha = 1120100,
154                 .fuse_corr_beta = -6000500,
155         },
156         {
157                 .config = &t124_tsensor_config,
158                 .base = 0x1a0,
159                 .calib_fuse_offset = 0x160,
160                 .fuse_corr_alpha = 1106500,
161                 .fuse_corr_beta = -6729300,
162         },
163 };
164
165 struct tegra_soctherm {
166         struct reset_control *reset;
167         struct clk *clock_tsensor;
168         struct clk *clock_soctherm;
169         void __iomem *regs;
170
171         struct thermal_zone_device *thermctl_tzs[4];
172 };
173
174 struct tsensor_shared_calibration {
175         u32 base_cp, base_ft;
176         u32 actual_temp_cp, actual_temp_ft;
177 };
178
179 static int calculate_shared_calibration(struct tsensor_shared_calibration *r)
180 {
181         u32 val, shifted_cp, shifted_ft;
182         int err;
183
184         err = tegra_fuse_readl(FUSE_TSENSOR8_CALIB, &val);
185         if (err)
186                 return err;
187         r->base_cp = val & FUSE_TSENSOR8_CALIB_CP_TS_BASE_MASK;
188         r->base_ft = (val & FUSE_TSENSOR8_CALIB_FT_TS_BASE_MASK)
189                 >> FUSE_TSENSOR8_CALIB_FT_TS_BASE_SHIFT;
190         val = ((val & FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_MASK)
191                 >> FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT);
192         shifted_ft = sign_extend32(val, 4);
193
194         err = tegra_fuse_readl(FUSE_SPARE_REALIGNMENT_REG_0, &val);
195         if (err)
196                 return err;
197         shifted_cp = sign_extend32(val, 5);
198
199         r->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + shifted_cp;
200         r->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + shifted_ft;
201
202         return 0;
203 }
204
205 static s64 div64_s64_precise(s64 a, s64 b)
206 {
207         s64 r, al;
208
209         /* Scale up for increased precision division */
210         al = a << 16;
211
212         r = div64_s64(al * 2 + 1, 2 * b);
213         return r >> 16;
214 }
215
216 static int
217 calculate_tsensor_calibration(const struct tegra_tsensor *sensor,
218                               const struct tsensor_shared_calibration *shared,
219                               u32 *calib)
220 {
221         u32 val;
222         s32 actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp,
223             mult, div;
224         s16 therma, thermb;
225         s64 tmp;
226         int err;
227
228         err = tegra_fuse_readl(sensor->calib_fuse_offset, &val);
229         if (err)
230                 return err;
231
232         actual_tsensor_cp = (shared->base_cp * 64) + sign_extend32(val, 12);
233         val = (val & FUSE_TSENSOR_CALIB_FT_TS_BASE_MASK)
234                 >> FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT;
235         actual_tsensor_ft = (shared->base_ft * 32) + sign_extend32(val, 12);
236
237         delta_sens = actual_tsensor_ft - actual_tsensor_cp;
238         delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
239
240         mult = sensor->config->pdiv * sensor->config->tsample_ate;
241         div = sensor->config->tsample * sensor->config->pdiv_ate;
242
243         therma = div64_s64_precise((s64) delta_temp * (1LL << 13) * mult,
244                                    (s64) delta_sens * div);
245
246         tmp = (s64)actual_tsensor_ft * shared->actual_temp_cp -
247               (s64)actual_tsensor_cp * shared->actual_temp_ft;
248         thermb = div64_s64_precise(tmp, (s64)delta_sens);
249
250         therma = div64_s64_precise((s64)therma * sensor->fuse_corr_alpha,
251                                    (s64)1000000LL);
252         thermb = div64_s64_precise((s64)thermb * sensor->fuse_corr_alpha +
253                                    sensor->fuse_corr_beta, (s64)1000000LL);
254
255         *calib = ((u16)therma << SENSOR_CONFIG2_THERMA_SHIFT) |
256                  ((u16)thermb << SENSOR_CONFIG2_THERMB_SHIFT);
257
258         return 0;
259 }
260
261 static int enable_tsensor(struct tegra_soctherm *tegra,
262                           const struct tegra_tsensor *sensor,
263                           const struct tsensor_shared_calibration *shared)
264 {
265         void __iomem *base = tegra->regs + sensor->base;
266         unsigned int val;
267         u32 calib;
268         int err;
269
270         err = calculate_tsensor_calibration(sensor, shared, &calib);
271         if (err)
272                 return err;
273
274         val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;
275         writel(val, base + SENSOR_CONFIG0);
276
277         val  = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;
278         val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;
279         val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;
280         val |= SENSOR_CONFIG1_TEMP_ENABLE;
281         writel(val, base + SENSOR_CONFIG1);
282
283         writel(calib, base + SENSOR_CONFIG2);
284
285         return 0;
286 }
287
288 /*
289  * Translate from soctherm readback format to millicelsius.
290  * The soctherm readback format in bits is as follows:
291  *   TTTTTTTT H______N
292  * where T's contain the temperature in Celsius,
293  * H denotes an addition of 0.5 Celsius and N denotes negation
294  * of the final value.
295  */
296 static int translate_temp(u16 val)
297 {
298         long t;
299
300         t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
301         if (val & READBACK_ADD_HALF)
302                 t += 500;
303         if (val & READBACK_NEGATE)
304                 t *= -1;
305
306         return t;
307 }
308
309 static int tegra_thermctl_get_temp(void *data, int *out_temp)
310 {
311         struct tegra_thermctl_zone *zone = data;
312         u32 val;
313
314         val = (readl(zone->reg) >> zone->shift) & SENSOR_TEMP_MASK;
315         *out_temp = translate_temp(val);
316
317         return 0;
318 }
319
320 static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
321         .get_temp = tegra_thermctl_get_temp,
322 };
323
324 static const struct of_device_id tegra_soctherm_of_match[] = {
325         { .compatible = "nvidia,tegra124-soctherm" },
326         { },
327 };
328 MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);
329
330 struct thermctl_zone_desc {
331         unsigned int offset;
332         unsigned int shift;
333 };
334
335 static const struct thermctl_zone_desc t124_thermctl_temp_zones[] = {
336         { SENSOR_TEMP1, 16 },
337         { SENSOR_TEMP2, 16 },
338         { SENSOR_TEMP1, 0 },
339         { SENSOR_TEMP2, 0 }
340 };
341
342 static int tegra_soctherm_probe(struct platform_device *pdev)
343 {
344         struct tegra_soctherm *tegra;
345         struct thermal_zone_device *tz;
346         struct tsensor_shared_calibration shared_calib;
347         struct resource *res;
348         unsigned int i;
349         int err;
350
351         const struct tegra_tsensor *tsensors = t124_tsensors;
352
353         tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
354         if (!tegra)
355                 return -ENOMEM;
356
357         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
358         tegra->regs = devm_ioremap_resource(&pdev->dev, res);
359         if (IS_ERR(tegra->regs))
360                 return PTR_ERR(tegra->regs);
361
362         tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");
363         if (IS_ERR(tegra->reset)) {
364                 dev_err(&pdev->dev, "can't get soctherm reset\n");
365                 return PTR_ERR(tegra->reset);
366         }
367
368         tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");
369         if (IS_ERR(tegra->clock_tsensor)) {
370                 dev_err(&pdev->dev, "can't get tsensor clock\n");
371                 return PTR_ERR(tegra->clock_tsensor);
372         }
373
374         tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");
375         if (IS_ERR(tegra->clock_soctherm)) {
376                 dev_err(&pdev->dev, "can't get soctherm clock\n");
377                 return PTR_ERR(tegra->clock_soctherm);
378         }
379
380         reset_control_assert(tegra->reset);
381
382         err = clk_prepare_enable(tegra->clock_soctherm);
383         if (err)
384                 return err;
385
386         err = clk_prepare_enable(tegra->clock_tsensor);
387         if (err) {
388                 clk_disable_unprepare(tegra->clock_soctherm);
389                 return err;
390         }
391
392         reset_control_deassert(tegra->reset);
393
394         /* Initialize raw sensors */
395
396         err = calculate_shared_calibration(&shared_calib);
397         if (err)
398                 goto disable_clocks;
399
400         for (i = 0; i < ARRAY_SIZE(t124_tsensors); ++i) {
401                 err = enable_tsensor(tegra, tsensors + i, &shared_calib);
402                 if (err)
403                         goto disable_clocks;
404         }
405
406         writel(SENSOR_PDIV_T124, tegra->regs + SENSOR_PDIV);
407         writel(SENSOR_HOTSPOT_OFF_T124, tegra->regs + SENSOR_HOTSPOT_OFF);
408
409         /* Initialize thermctl sensors */
410
411         for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) {
412                 struct tegra_thermctl_zone *zone =
413                         devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
414                 if (!zone) {
415                         err = -ENOMEM;
416                         goto unregister_tzs;
417                 }
418
419                 zone->reg = tegra->regs + t124_thermctl_temp_zones[i].offset;
420                 zone->shift = t124_thermctl_temp_zones[i].shift;
421
422                 tz = thermal_zone_of_sensor_register(&pdev->dev, i, zone,
423                                                      &tegra_of_thermal_ops);
424                 if (IS_ERR(tz)) {
425                         err = PTR_ERR(tz);
426                         dev_err(&pdev->dev, "failed to register sensor: %d\n",
427                                 err);
428                         goto unregister_tzs;
429                 }
430
431                 tegra->thermctl_tzs[i] = tz;
432         }
433
434         return 0;
435
436 unregister_tzs:
437         while (i--)
438                 thermal_zone_of_sensor_unregister(&pdev->dev,
439                                                   tegra->thermctl_tzs[i]);
440
441 disable_clocks:
442         clk_disable_unprepare(tegra->clock_tsensor);
443         clk_disable_unprepare(tegra->clock_soctherm);
444
445         return err;
446 }
447
448 static int tegra_soctherm_remove(struct platform_device *pdev)
449 {
450         struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
451         unsigned int i;
452
453         for (i = 0; i < ARRAY_SIZE(tegra->thermctl_tzs); ++i) {
454                 thermal_zone_of_sensor_unregister(&pdev->dev,
455                                                   tegra->thermctl_tzs[i]);
456         }
457
458         clk_disable_unprepare(tegra->clock_tsensor);
459         clk_disable_unprepare(tegra->clock_soctherm);
460
461         return 0;
462 }
463
464 static struct platform_driver tegra_soctherm_driver = {
465         .probe = tegra_soctherm_probe,
466         .remove = tegra_soctherm_remove,
467         .driver = {
468                 .name = "tegra-soctherm",
469                 .of_match_table = tegra_soctherm_of_match,
470         },
471 };
472 module_platform_driver(tegra_soctherm_driver);
473
474 MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
475 MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");
476 MODULE_LICENSE("GPL v2");