]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/nvidia/tegra_soctherm.c
ldns: Upgrade to 1.8.3.
[FreeBSD/FreeBSD.git] / sys / arm / nvidia / tegra_soctherm.c
1 /*-
2  * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31  * Thermometer and thermal zones driver for Tegra SoCs.
32  * Calibration data and algo are taken from Linux, because this part of SoC
33  * is undocumented in TRM.
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/gpio.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/malloc.h>
43 #include <sys/rman.h>
44 #include <sys/sysctl.h>
45
46 #include <machine/bus.h>
47
48 #include <dev/extres/clk/clk.h>
49 #include <dev/extres/hwreset/hwreset.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52
53 #include <arm/nvidia/tegra_efuse.h>
54 #include <dt-bindings/thermal/tegra124-soctherm.h>
55 #include "tegra_soctherm_if.h"
56
57 /* Per sensors registers - base is 0x0c0*/
58 #define TSENSOR_CONFIG0                         0x000
59 #define  TSENSOR_CONFIG0_TALL(x)                        (((x) & 0xFFFFF) << 8)
60 #define  TSENSOR_CONFIG0_STATUS_CLR                     (1 << 5)
61 #define  TSENSOR_CONFIG0_TCALC_OVERFLOW                 (1 << 4)
62 #define  TSENSOR_CONFIG0_OVERFLOW                       (1 << 3)
63 #define  TSENSOR_CONFIG0_CPTR_OVERFLOW                  (1 << 2)
64 #define  TSENSOR_CONFIG0_RO_SEL                         (1 << 1)
65 #define  TSENSOR_CONFIG0_STOP                           (1 << 0)
66
67 #define TSENSOR_CONFIG1                         0x004
68 #define  TSENSOR_CONFIG1_TEMP_ENABLE                    (1U << 31)
69 #define  TSENSOR_CONFIG1_TEN_COUNT(x)                   (((x) & 0x3F) << 24)
70 #define  TSENSOR_CONFIG1_TIDDQ_EN(x)                    (((x) & 0x3F) << 15)
71 #define  TSENSOR_CONFIG1_TSAMPLE(x)                     (((x) & 0x3FF) << 0)
72
73 #define TSENSOR_CONFIG2                         0x008
74 #define TSENSOR_CONFIG2_THERMA(x)                       (((x) & 0xFFFF) << 16)
75 #define TSENSOR_CONFIG2_THERMB(x)                       (((x) & 0xFFFF) << 0)
76
77 #define TSENSOR_STATUS0                         0x00c
78 #define  TSENSOR_STATUS0_CAPTURE_VALID                  (1U << 31)
79 #define  TSENSOR_STATUS0_CAPTURE(x)                     (((x) >> 0) & 0xffff)
80
81 #define TSENSOR_STATUS1                         0x010
82 #define  TSENSOR_STATUS1_TEMP_VALID                     (1U << 31)
83 #define  TSENSOR_STATUS1_TEMP(x)                        (((x) >> 0) & 0xffff)
84
85 #define TSENSOR_STATUS2                         0x014
86 #define  TSENSOR_STATUS2_TEMP_MAX(x)                    (((x) >> 16) & 0xffff)
87 #define  TSENSOR_STATUS2_TEMP_MIN(x)                    (((x) >>  0) & 0xffff)
88
89
90 /* Readbacks */
91 #define READBACK_VALUE(x)                               (((x) >> 8) & 0xff)
92 #define READBACK_ADD_HALF                               (1 << 7)
93 #define READBACK_NEGATE                                 (1 << 0)
94
95 /* Global registers */
96 #define TSENSOR_PDIV                            0x1c0
97 #define TSENSOR_HOTSPOT_OFF                     0x1c4
98 #define TSENSOR_TEMP1                           0x1c8
99 #define TSENSOR_TEMP2                           0x1cc
100
101 /* Fuses */
102 #define  FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT            0
103 #define  FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS             13
104 #define  FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT            13
105 #define  FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS             13
106
107 /* Layout is different for Tegra124 and Tegra210 */
108 #define FUSE_TSENSOR_COMMON                     0x180
109 #define  TEGRA124_FUSE_COMMON_CP_TS_BASE(x)             (((x) >>  0) & 0x3ff)
110 #define  TEGRA124_FUSE_COMMON_FT_TS_BASE(x)             (((x) >> 10) & 0x7ff)
111 #define  TEGRA124_FUSE_COMMON_SHIFT_FT_SHIFT            21
112 #define  TEGRA124_FUSE_COMMON_SHIFT_FT_BITS             5
113
114 #define  TEGRA210_FUSE_COMMON_CP_TS_BASE(x)             (((x) >>  11) & 0x3ff)
115 #define  TEGRA210_FUSE_COMMON_FT_TS_BASE(x)             (((x) >> 21) & 0x7ff)
116 #define  TEGRA210_FUSE_COMMON_SHIFT_CP_SHIFT            0
117 #define  TEGRA210_FUSE_COMMON_SHIFT_CP_BITS             6
118 #define  TEGRA210_FUSE_COMMON_SHIFT_FT_SHIFT            6
119 #define  TEGRA210_FUSE_COMMON_SHIFT_FT_BITS             5
120
121
122 /* Only for Tegra124 */
123 #define FUSE_SPARE_REALIGNMENT_REG              0x1fc
124 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT      0
125 #define  FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS       6
126
127 #define TEGRA124_NOMINAL_CALIB_FT       105
128 #define TEGRA124_NOMINAL_CALIB_CP       25
129
130 #define TEGRA210_NOMINAL_CALIB_FT       105
131 #define TEGRA210_NOMINAL_CALIB_CP       25
132
133 #define WR4(_sc, _r, _v)        bus_write_4((_sc)->mem_res, (_r), (_v))
134 #define RD4(_sc, _r)            bus_read_4((_sc)->mem_res, (_r))
135
136 static struct sysctl_ctx_list soctherm_sysctl_ctx;
137
138 struct tsensor_cfg {
139         uint32_t                tall;
140         uint32_t                tsample;
141         uint32_t                tiddq_en;
142         uint32_t                ten_count;
143         uint32_t                pdiv;
144         uint32_t                tsample_ate;
145         uint32_t                pdiv_ate;
146 };
147
148 struct soctherm_shared_cal {
149         uint32_t                base_cp;
150         uint32_t                base_ft;
151         int32_t                 actual_temp_cp;
152         int32_t                 actual_temp_ft;
153 };
154
155 struct tsensor {
156         char                    *name;
157         int                     id;
158         bus_addr_t              sensor_base;
159         bus_addr_t              calib_fuse;
160         int                     fuse_corr_alpha;
161         int                     fuse_corr_beta;
162
163         int16_t                 therm_a;
164         int16_t                 therm_b;
165 };
166
167 struct soctherm_soc;
168 struct soctherm_softc {
169         device_t                dev;
170         struct resource         *mem_res;
171         struct resource         *irq_res;
172         void                    *irq_ih;
173
174         clk_t                   tsensor_clk;
175         clk_t                   soctherm_clk;
176         hwreset_t               reset;
177
178         struct soctherm_soc     *soc;
179         struct soctherm_shared_cal shared_cal;
180 };
181
182 struct soctherm_soc {
183         void                    (*shared_cal)(struct soctherm_softc *sc);
184         uint32_t                tsensor_pdiv;
185         uint32_t                tsensor_hotspot_off;
186         struct tsensor_cfg      *tsensor_cfg;
187         struct tsensor          *tsensors;
188         int                     ntsensors;
189 };
190
191 /* Tegra124 config */
192
193 static struct tsensor_cfg t124_tsensor_config = {
194         .tall = 16300,
195         .tsample = 120,
196         .tiddq_en = 1,
197         .ten_count = 1,
198         .pdiv = 8,
199         .tsample_ate = 480,
200         .pdiv_ate = 8
201 };
202
203 static struct tsensor t124_tsensors[] = {
204         {
205                 .name = "cpu0",
206                 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
207                 .sensor_base = 0x0c0,
208                 .calib_fuse = 0x098,
209                 .fuse_corr_alpha = 1135400,
210                 .fuse_corr_beta = -6266900,
211         },
212         {
213                 .name = "cpu1",
214                 .id = -1,
215                 .sensor_base = 0x0e0,
216                 .calib_fuse = 0x084,
217                 .fuse_corr_alpha = 1122220,
218                 .fuse_corr_beta = -5700700,
219         },
220         {
221                 .name = "cpu2",
222                 .id = -1,
223                 .sensor_base = 0x100,
224                 .calib_fuse = 0x088,
225                 .fuse_corr_alpha = 1127000,
226                 .fuse_corr_beta = -6768200,
227         },
228         {
229                 .name = "cpu3",
230                 .id = -1,
231                 .sensor_base = 0x120,
232                 .calib_fuse = 0x12c,
233                 .fuse_corr_alpha = 1110900,
234                 .fuse_corr_beta = -6232000,
235         },
236         {
237                 .name = "mem0",
238                 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
239                 .sensor_base = 0x140,
240                 .calib_fuse = 0x158,
241                 .fuse_corr_alpha = 1122300,
242                 .fuse_corr_beta = -5936400,
243         },
244         {
245                 .name = "mem1",
246                 .id = -1,
247                 .sensor_base = 0x160,
248                 .calib_fuse = 0x15c,
249                 .fuse_corr_alpha = 1145700,
250                 .fuse_corr_beta = -7124600,
251         },
252         {
253                 .name = "gpu",
254                 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
255                 .sensor_base = 0x180,
256                 .calib_fuse = 0x154,
257                 .fuse_corr_alpha = 1120100,
258                 .fuse_corr_beta = -6000500,
259         },
260         {
261                 .name = "pllX",
262                 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
263                 .sensor_base = 0x1a0,
264                 .calib_fuse = 0x160,
265                 .fuse_corr_alpha = 1106500,
266                 .fuse_corr_beta = -6729300,
267         },
268 };
269
270 static void tegra124_shared_cal(struct soctherm_softc *sc);
271
272 static struct soctherm_soc tegra124_soc = {
273         .shared_cal = tegra124_shared_cal,
274         .tsensor_pdiv = 0x8888,
275         .tsensor_hotspot_off = 0x00060600 ,
276         .tsensor_cfg = &t124_tsensor_config,
277         .tsensors = t124_tsensors,
278         .ntsensors = nitems(t124_tsensors),
279 };
280
281 /* Tegra210 config */
282 static struct tsensor_cfg t210_tsensor_config = {
283         .tall = 16300,
284         .tsample = 120,
285         .tiddq_en = 1,
286         .ten_count = 1,
287         .pdiv = 8,
288         .tsample_ate = 480,
289         .pdiv_ate = 8
290 };
291
292 static struct tsensor t210_tsensors[] = {
293         {
294                 .name = "cpu0",
295                 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
296                 .sensor_base = 0x0c0,
297                 .calib_fuse = 0x098,
298                 .fuse_corr_alpha = 1085000,
299                 .fuse_corr_beta = 3244200,
300         },
301         {
302                 .name = "cpu1",
303                 .id = -1,
304                 .sensor_base = 0x0e0,
305                 .calib_fuse = 0x084,
306                 .fuse_corr_alpha = 1126200,
307                 .fuse_corr_beta = -67500,
308         },
309         {
310                 .name = "cpu2",
311                 .id = -1,
312                 .sensor_base = 0x100,
313                 .calib_fuse = 0x088,
314                 .fuse_corr_alpha = 1098400,
315                 .fuse_corr_beta = 2251100,
316         },
317         {
318                 .name = "cpu3",
319                 .id = -1,
320                 .sensor_base = 0x120,
321                 .calib_fuse = 0x12c,
322                 .fuse_corr_alpha = 1108000,
323                 .fuse_corr_beta = 602700,
324         },
325         {
326                 .name = "mem0",
327                 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
328                 .sensor_base = 0x140,
329                 .calib_fuse = 0x158,
330                 .fuse_corr_alpha = 1069200,
331                 .fuse_corr_beta = 3549900,
332         },
333         {
334                 .name = "mem1",
335                 .id = -1,
336                 .sensor_base = 0x160,
337                 .calib_fuse = 0x15c,
338                 .fuse_corr_alpha = 1173700,
339                 .fuse_corr_beta = -6263600,
340         },
341         {
342                 .name = "gpu",
343                 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
344                 .sensor_base = 0x180,
345                 .calib_fuse = 0x154,
346                 .fuse_corr_alpha = 1074300,
347                 .fuse_corr_beta = 2734900,
348         },
349         {
350                 .name = "pllX",
351                 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
352                 .sensor_base = 0x1a0,
353                 .calib_fuse = 0x160,
354                 .fuse_corr_alpha = 1039700,
355                 .fuse_corr_beta = 6829100,
356         },
357 };
358
359 static void tegra210_shared_cal(struct soctherm_softc *sc);
360
361 static struct soctherm_soc tegra210_soc = {
362         .shared_cal = tegra210_shared_cal,
363         .tsensor_pdiv = 0x8888,
364         .tsensor_hotspot_off = 0x000A0500 ,
365         .tsensor_cfg = &t210_tsensor_config,
366         .tsensors = t210_tsensors,
367         .ntsensors = nitems(t210_tsensors),
368 };
369
370 static struct ofw_compat_data compat_data[] = {
371         {"nvidia,tegra124-soctherm", (uintptr_t)&tegra124_soc},
372         {"nvidia,tegra210-soctherm", (uintptr_t)&tegra210_soc},
373         {NULL,                          0},
374 };
375
376 /* Extract signed integer bitfield from register */
377 static int
378 extract_signed(uint32_t reg, int shift, int bits)
379 {
380         int32_t val;
381         uint32_t mask;
382
383         mask = (1 << bits) - 1;
384         val = ((reg >> shift) & mask) << (32 - bits);
385         val >>= 32 - bits;
386         return ((int32_t)val);
387 }
388
389 static inline
390 int64_t div64_s64_precise(int64_t a, int64_t b)
391 {
392         int64_t r, al;
393
394         al = a << 16;
395         r = (al * 2 + 1) / (2 * b);
396         return (r >> 16);
397 }
398
399 static void
400 tegra124_shared_cal(struct soctherm_softc *sc)
401 {
402         uint32_t val;
403         int calib_cp, calib_ft;
404         struct soctherm_shared_cal *cal;
405
406         cal = &sc->shared_cal;
407         val = tegra_fuse_read_4(FUSE_TSENSOR_COMMON);
408         cal->base_cp = TEGRA124_FUSE_COMMON_CP_TS_BASE(val);
409         cal->base_ft = TEGRA124_FUSE_COMMON_FT_TS_BASE(val);
410
411         calib_ft = extract_signed(val,
412             TEGRA124_FUSE_COMMON_SHIFT_FT_SHIFT,
413             TEGRA124_FUSE_COMMON_SHIFT_FT_BITS);
414
415         val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
416         calib_cp = extract_signed(val,
417             FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
418             FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
419
420         cal->actual_temp_cp = 2 * TEGRA124_NOMINAL_CALIB_CP + calib_cp;
421         cal->actual_temp_ft = 2 * TEGRA124_NOMINAL_CALIB_FT + calib_ft;
422 #ifdef DEBUG
423         printf("%s: base_cp: %u, base_ft: %d,"
424             " actual_temp_cp: %d, actual_temp_ft: %d\n",
425             __func__, cal->base_cp, cal->base_ft,
426             cal->actual_temp_cp, cal->actual_temp_ft);
427 #endif
428 }
429
430 static void
431 tegra210_shared_cal(struct soctherm_softc *sc)
432 {
433         uint32_t val;
434         int calib_cp, calib_ft;
435         struct soctherm_shared_cal *cal;
436
437         cal = &sc->shared_cal;
438
439         val = tegra_fuse_read_4(FUSE_TSENSOR_COMMON);
440         cal->base_cp = TEGRA210_FUSE_COMMON_CP_TS_BASE(val);
441         cal->base_ft = TEGRA210_FUSE_COMMON_FT_TS_BASE(val);
442
443         calib_ft = extract_signed(val,
444             TEGRA210_FUSE_COMMON_SHIFT_FT_SHIFT,
445             TEGRA210_FUSE_COMMON_SHIFT_FT_BITS);
446         calib_cp = extract_signed(val,
447             TEGRA210_FUSE_COMMON_SHIFT_CP_SHIFT,
448             TEGRA210_FUSE_COMMON_SHIFT_CP_BITS);
449
450         cal->actual_temp_cp = 2 * TEGRA210_NOMINAL_CALIB_CP + calib_cp;
451         cal->actual_temp_ft = 2 * TEGRA210_NOMINAL_CALIB_FT + calib_ft;
452 #ifdef DEBUG
453         printf("%s: base_cp: %u, base_ft: %d,"
454             " actual_temp_cp: %d, actual_temp_ft: %d\n",
455             __func__, cal->base_cp, cal->base_ft,
456             cal->actual_temp_cp, cal->actual_temp_ft);
457 #endif
458 }
459
460 static void
461 tsensor_calibration(struct soctherm_softc *sc, struct tsensor *sensor)
462 {
463         uint32_t val;
464         int mult, div, calib_cp, calib_ft;
465         int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
466         int temp_a, temp_b;
467         struct tsensor_cfg *cfg;
468         struct soctherm_shared_cal *cal;
469         int64_t tmp;
470
471         cfg = sc->soc->tsensor_cfg;
472         cal = &sc->shared_cal;
473
474         val =  tegra_fuse_read_4(sensor->calib_fuse);
475         calib_cp = extract_signed(val,
476             FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
477             FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
478         actual_tsensor_cp = cal->base_cp * 64 + calib_cp;
479
480         calib_ft = extract_signed(val,
481             FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
482             FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
483         actual_tsensor_ft = cal->base_ft * 32 + calib_ft;
484
485         delta_sens = actual_tsensor_ft - actual_tsensor_cp;
486         delta_temp = cal->actual_temp_ft - cal->actual_temp_cp;
487         mult = cfg->pdiv * cfg->tsample_ate;
488         div = cfg->tsample * cfg->pdiv_ate;
489
490         temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
491                                    (int64_t) delta_sens * div);
492
493         tmp = (int64_t)actual_tsensor_ft * cal->actual_temp_cp -
494               (int64_t)actual_tsensor_cp * cal->actual_temp_ft;
495         temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
496
497         temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
498                                    1000000);
499         temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
500                                    sensor->fuse_corr_beta, 1000000);
501         sensor->therm_a = (int16_t)temp_a;
502         sensor->therm_b = (int16_t)temp_b;
503 #ifdef DEBUG
504         printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
505             " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
506             __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
507             calib_cp, calib_cp, calib_ft, calib_ft);
508         printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
509             (uint16_t)sensor->therm_a, sensor->therm_a,
510             (uint16_t)sensor->therm_b, sensor->therm_b);
511 #endif
512 }
513
514 static void
515 soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor)
516 {
517         struct tsensor_cfg *cfg;
518         uint32_t val;
519
520         cfg = sc->soc->tsensor_cfg;
521         tsensor_calibration(sc, sensor);
522
523         val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
524         val |= TSENSOR_CONFIG0_STOP;
525         val |= TSENSOR_CONFIG0_STATUS_CLR;
526         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
527
528         val = TSENSOR_CONFIG0_TALL(cfg->tall);
529         val |= TSENSOR_CONFIG0_STOP;
530         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
531
532         val = TSENSOR_CONFIG1_TSAMPLE(cfg->tsample - 1);
533         val |= TSENSOR_CONFIG1_TIDDQ_EN(cfg->tiddq_en);
534         val |= TSENSOR_CONFIG1_TEN_COUNT(cfg->ten_count);
535         val |= TSENSOR_CONFIG1_TEMP_ENABLE;
536         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
537
538         val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
539              TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
540         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
541
542         val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
543         val &= ~TSENSOR_CONFIG0_STOP;
544         WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
545 #ifdef DEBUG
546         printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
547             " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
548             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
549             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
550             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
551             RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
552             RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
553             RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
554             );
555 #endif
556 }
557
558 static int
559 soctherm_convert_raw(uint32_t val)
560 {
561         int32_t t;
562
563         t = READBACK_VALUE(val) * 1000;
564         if (val & READBACK_ADD_HALF)
565                 t += 500;
566         if (val & READBACK_NEGATE)
567                 t *= -1;
568
569         return (t);
570 }
571
572 static int
573 soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
574 {
575         int timeout;
576         uint32_t val;
577
578         /* wait for valid sample */
579         for (timeout = 100; timeout > 0; timeout--) {
580                 val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
581                 if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
582                         break;
583                 DELAY(100);
584         }
585         if (timeout <= 0)
586                 device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
587         *temp = soctherm_convert_raw(val);
588 #ifdef DEBUG
589         printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
590         printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
591             " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
592             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
593             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
594             RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
595             RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
596             RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
597             RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
598             );
599 #endif
600         return (0);
601 }
602
603 static int
604 soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
605 {
606         struct soctherm_softc *sc;
607         int i;
608
609         sc = device_get_softc(dev);
610         /* The direct sensor map starts at 0x100 */
611         if (id >= 0x100) {
612                 id -= 0x100;
613                 if (id >= sc->soc->ntsensors)
614                         return (ERANGE);
615                 return(soctherm_read_temp(sc, sc->soc->tsensors + id, val));
616         }
617         /* Linux (DT) compatible thermal zones */
618         for (i = 0; i < sc->soc->ntsensors; i++) {
619                 if (sc->soc->tsensors->id == id) {
620                         return(soctherm_read_temp(sc, sc->soc->tsensors + id,
621                             val));
622                 }
623         }
624         return (ERANGE);
625 }
626
627 static int
628 soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
629 {
630         struct soctherm_softc *sc;
631         int val;
632         int rv;
633         int id;
634
635         /* Write request */
636         if (req->newptr != NULL)
637                 return (EINVAL);
638
639         sc = arg1;
640         id = arg2;
641
642         if (id >= sc->soc->ntsensors)
643                 return (ERANGE);
644         rv =  soctherm_read_temp(sc, sc->soc->tsensors + id, &val);
645         if (rv != 0)
646                 return (rv);
647
648         val = val / 100;
649         val +=  2731;
650         rv = sysctl_handle_int(oidp, &val, 0, req);
651         return (rv);
652 }
653
654 static int
655 soctherm_init_sysctl(struct soctherm_softc *sc)
656 {
657         int i;
658         struct sysctl_oid *oid, *tmp;
659
660         sysctl_ctx_init(&soctherm_sysctl_ctx);
661         /* create node for hw.temp */
662         oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
663             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
664             CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
665         if (oid == NULL)
666                 return (ENXIO);
667
668         /* Add sensors */
669         for (i = sc->soc->ntsensors  - 1; i >= 0; i--) {
670                 tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
671                     SYSCTL_CHILDREN(oid), OID_AUTO, sc->soc->tsensors[i].name,
672                     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, i,
673                     soctherm_sysctl_temperature, "IK", "SoC Temperature");
674                 if (tmp == NULL)
675                         return (ENXIO);
676         }
677
678         return (0);
679 }
680
681 static int
682 soctherm_probe(device_t dev)
683 {
684
685         if (!ofw_bus_status_okay(dev))
686                 return (ENXIO);
687
688         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
689                 return (ENXIO);
690
691         device_set_desc(dev, "Tegra temperature sensors");
692         return (BUS_PROBE_DEFAULT);
693 }
694
695 static int
696 soctherm_attach(device_t dev)
697 {
698         struct soctherm_softc *sc;
699         phandle_t node;
700         int i, rid, rv;
701
702         sc = device_get_softc(dev);
703         sc->dev = dev;
704         sc->soc = (struct soctherm_soc *)ofw_bus_search_compatible(dev,
705            compat_data)->ocd_data;
706         node = ofw_bus_get_node(sc->dev);
707
708         rid = 0;
709         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
710             RF_ACTIVE);
711         if (sc->mem_res == NULL) {
712                 device_printf(dev, "Cannot allocate memory resources\n");
713                 goto fail;
714         }
715
716         rid = 0;
717         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
718         if (sc->irq_res == NULL) {
719                 device_printf(dev, "Cannot allocate IRQ resources\n");
720                 goto fail;
721         }
722
723 /*
724         if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
725             soctherm_intr, NULL, sc, &sc->irq_ih))) {
726                 device_printf(dev,
727                     "WARNING: unable to register interrupt handler\n");
728                 goto fail;
729         }
730 */
731
732         /* OWF resources */
733         rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
734         if (rv != 0) {
735                 device_printf(dev, "Cannot get fuse reset\n");
736                 goto fail;
737         }
738         rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
739         if (rv != 0) {
740                 device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
741                 goto fail;
742         }
743         rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
744         if (rv != 0) {
745                 device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
746                 goto fail;
747         }
748
749         rv = hwreset_assert(sc->reset);
750         if (rv != 0) {
751                 device_printf(dev, "Cannot assert reset\n");
752                 goto fail;
753         }
754         rv = clk_enable(sc->tsensor_clk);
755         if (rv != 0) {
756                 device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
757                 goto fail;
758         }
759         rv = clk_enable(sc->soctherm_clk);
760         if (rv != 0) {
761                 device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
762                 goto fail;
763         }
764         rv = hwreset_deassert(sc->reset);
765         if (rv != 0) {
766                 device_printf(dev, "Cannot clear reset\n");
767                 goto fail;
768         }
769
770         sc->soc->shared_cal(sc);
771
772         WR4(sc, TSENSOR_PDIV, sc->soc->tsensor_pdiv);
773         WR4(sc, TSENSOR_HOTSPOT_OFF, sc->soc->tsensor_hotspot_off);
774
775         for (i = 0; i < sc->soc->ntsensors; i++)
776                 soctherm_init_tsensor(sc, sc->soc->tsensors + i);
777
778         rv = soctherm_init_sysctl(sc);
779         if (rv != 0) {
780                 device_printf(sc->dev, "Cannot initialize sysctls\n");
781                 goto fail;
782         }
783
784         OF_device_register_xref(OF_xref_from_node(node), dev);
785         return (bus_generic_attach(dev));
786
787 fail:
788         if (sc->irq_ih != NULL)
789                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
790         sysctl_ctx_free(&soctherm_sysctl_ctx);
791         if (sc->tsensor_clk != NULL)
792                 clk_release(sc->tsensor_clk);
793         if (sc->soctherm_clk != NULL)
794                 clk_release(sc->soctherm_clk);
795         if (sc->reset != NULL)
796                 hwreset_release(sc->reset);
797         if (sc->irq_res != NULL)
798                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
799         if (sc->mem_res != NULL)
800                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
801
802         return (ENXIO);
803 }
804
805 static int
806 soctherm_detach(device_t dev)
807 {
808         struct soctherm_softc *sc;
809         sc = device_get_softc(dev);
810
811         if (sc->irq_ih != NULL)
812                 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
813         sysctl_ctx_free(&soctherm_sysctl_ctx);
814         if (sc->tsensor_clk != NULL)
815                 clk_release(sc->tsensor_clk);
816         if (sc->soctherm_clk != NULL)
817                 clk_release(sc->soctherm_clk);
818         if (sc->reset != NULL)
819                 hwreset_release(sc->reset);
820         if (sc->irq_res != NULL)
821                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
822         if (sc->mem_res != NULL)
823                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
824
825         return (ENXIO);
826 }
827
828 static device_method_t tegra_soctherm_methods[] = {
829         /* Device interface */
830         DEVMETHOD(device_probe,                 soctherm_probe),
831         DEVMETHOD(device_attach,                soctherm_attach),
832         DEVMETHOD(device_detach,                soctherm_detach),
833
834         /* SOCTHERM interface */
835         DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
836
837         DEVMETHOD_END
838 };
839
840 static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
841     sizeof(struct soctherm_softc));
842 EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
843     NULL, NULL, 79);