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