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