xref: /freebsd/sys/arm/nvidia/tegra_soctherm.c (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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);
844