tegra_soctherm.c revision 308335
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: stable/11/sys/arm/nvidia/tegra_soctherm.c 308335 2016-11-05 10:56:32Z mmel $");
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 <gnu/dts/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/* Global registers */
90#define	TSENSOR_PDIV				0x1c0
91#define	 TSENSOR_PDIV_T124				0x8888
92#define	TSENSOR_HOTSPOT_OFF			0x1c4
93#define	 TSENSOR_HOTSPOT_OFF_T124			0x00060600
94#define	TSENSOR_TEMP1				0x1c8
95#define	TSENSOR_TEMP2				0x1cc
96
97/* Readbacks */
98#define	READBACK_VALUE_MASK				0xff00
99#define	READBACK_VALUE_SHIFT				8
100#define	READBACK_ADD_HALF				(1 << 7)
101#define	READBACK_NEGATE					(1 << 0)
102
103
104/* Fuses */
105#define	 FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT		0
106#define	 FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS		13
107#define	 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT		13
108#define	 FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS		13
109
110#define	FUSE_TSENSOR8_CALIB			0x180
111#define	 FUSE_TSENSOR8_CALIB_CP_TS_BASE(x)		(((x) >>  0) & 0x3ff)
112#define	 FUSE_TSENSOR8_CALIB_FT_TS_BASE(x)		(((x) >> 10) & 0x7ff)
113
114#define	FUSE_SPARE_REALIGNMENT_REG		0x1fc
115#define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT 	0
116#define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS 	6
117#define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 	21
118#define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS 	5
119#define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP(x) 	(((x) >>  0) & 0x3f)
120#define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT(x) 	(((x) >> 21) & 0x1f)
121
122
123#define	NOMINAL_CALIB_FT_T124	105
124#define	NOMINAL_CALIB_CP_T124	25
125
126#define	WR4(_sc, _r, _v)	bus_write_4((_sc)->mem_res, (_r), (_v))
127#define	RD4(_sc, _r)		bus_read_4((_sc)->mem_res, (_r))
128
129static struct sysctl_ctx_list soctherm_sysctl_ctx;
130
131struct soctherm_shared_cal {
132	uint32_t		base_cp;
133	uint32_t		base_ft;
134	int32_t			actual_temp_cp;
135	int32_t			actual_temp_ft;
136};
137struct tsensor_cfg {
138	uint32_t		tall;
139	uint32_t		tsample;
140	uint32_t		tiddq_en;
141	uint32_t		ten_count;
142	uint32_t		pdiv;
143	uint32_t		tsample_ate;
144	uint32_t		pdiv_ate;
145};
146
147struct tsensor {
148	char 			*name;
149	int			id;
150	struct tsensor_cfg 	*cfg;
151	bus_addr_t		sensor_base;
152	bus_addr_t		calib_fuse;
153	int 			fuse_corr_alpha;
154	int			fuse_corr_beta;
155
156	int16_t			therm_a;
157	int16_t			therm_b;
158};
159
160struct soctherm_softc {
161	device_t		dev;
162	struct resource		*mem_res;
163	struct resource		*irq_res;
164	void			*irq_ih;
165
166	clk_t			tsensor_clk;
167	clk_t			soctherm_clk;
168	hwreset_t			reset;
169
170	int			ntsensors;
171	struct tsensor		*tsensors;
172};
173
174static struct ofw_compat_data compat_data[] = {
175	{"nvidia,tegra124-soctherm",	1},
176	{NULL,				0},
177};
178
179static struct tsensor_cfg t124_tsensor_config = {
180	.tall = 16300,
181	.tsample = 120,
182	.tiddq_en = 1,
183	.ten_count = 1,
184	.pdiv = 8,
185	.tsample_ate = 480,
186	.pdiv_ate = 8
187};
188
189
190static struct tsensor t124_tsensors[] = {
191	{
192		.name = "cpu0",
193		.id = TEGRA124_SOCTHERM_SENSOR_CPU,
194		.cfg = &t124_tsensor_config,
195		.sensor_base = 0x0c0,
196		.calib_fuse = 0x098,
197		.fuse_corr_alpha = 1135400,
198		.fuse_corr_beta = -6266900,
199	},
200	{
201		.name = "cpu1",
202		.id = -1,
203		.cfg = &t124_tsensor_config,
204		.sensor_base = 0x0e0,
205		.calib_fuse = 0x084,
206		.fuse_corr_alpha = 1122220,
207		.fuse_corr_beta = -5700700,
208	},
209	{
210		.name = "cpu2",
211		.id = -1,
212		.cfg = &t124_tsensor_config,
213		.sensor_base = 0x100,
214		.calib_fuse = 0x088,
215		.fuse_corr_alpha = 1127000,
216		.fuse_corr_beta = -6768200,
217	},
218	{
219		.name = "cpu3",
220		.id = -1,
221		.cfg = &t124_tsensor_config,
222		.sensor_base = 0x120,
223		.calib_fuse = 0x12c,
224		.fuse_corr_alpha = 1110900,
225		.fuse_corr_beta = -6232000,
226	},
227	{
228		.name = "mem0",
229		.id = TEGRA124_SOCTHERM_SENSOR_MEM,
230		.cfg = &t124_tsensor_config,
231		.sensor_base = 0x140,
232		.calib_fuse = 0x158,
233		.fuse_corr_alpha = 1122300,
234		.fuse_corr_beta = -5936400,
235	},
236	{
237		.name = "mem1",
238		.id = -1,
239		.cfg = &t124_tsensor_config,
240		.sensor_base = 0x160,
241		.calib_fuse = 0x15c,
242		.fuse_corr_alpha = 1145700,
243		.fuse_corr_beta = -7124600,
244	},
245	{
246		.name = "gpu",
247		.id = TEGRA124_SOCTHERM_SENSOR_GPU,
248		.cfg = &t124_tsensor_config,
249		.sensor_base = 0x180,
250		.calib_fuse = 0x154,
251		.fuse_corr_alpha = 1120100,
252		.fuse_corr_beta = -6000500,
253	},
254	{
255		.name = "pllX",
256		.id = TEGRA124_SOCTHERM_SENSOR_PLLX,
257		.cfg = &t124_tsensor_config,
258		.sensor_base = 0x1a0,
259		.calib_fuse = 0x160,
260		.fuse_corr_alpha = 1106500,
261		.fuse_corr_beta = -6729300,
262	},
263};
264
265/* Extract signed integer bitfield from register */
266static int
267extract_signed(uint32_t reg, int shift, int bits)
268{
269	int32_t val;
270	uint32_t mask;
271
272	mask = (1 << bits) - 1;
273	val = ((reg >> shift) & mask) << (32 - bits);
274	val >>= 32 - bits;
275	return ((int32_t)val);
276}
277
278static inline int64_t div64_s64_precise(int64_t a, int64_t b)
279{
280	int64_t r, al;
281
282	al = a << 16;
283	r = (al * 2 + 1) / (2 * b);
284	return r >> 16;
285}
286
287static void
288get_shared_cal(struct soctherm_softc *sc, struct soctherm_shared_cal *cal)
289{
290	uint32_t val;
291	int calib_cp, calib_ft;
292
293	val = tegra_fuse_read_4(FUSE_TSENSOR8_CALIB);
294	cal->base_cp = FUSE_TSENSOR8_CALIB_CP_TS_BASE(val);
295	cal->base_ft = FUSE_TSENSOR8_CALIB_FT_TS_BASE(val);
296
297	val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
298	calib_ft = extract_signed(val,
299	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT,
300	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS);
301	calib_cp = extract_signed(val,
302	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
303	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
304
305	cal->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + calib_cp;
306	cal->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + calib_ft;
307#ifdef DEBUG
308	printf("%s: base_cp: %u, base_ft: %d,"
309	    " actual_temp_cp: %d, actual_temp_ft: %d\n",
310	    __func__, cal->base_cp, cal->base_ft,
311	    cal->actual_temp_cp, cal->actual_temp_ft);
312#endif
313}
314
315
316static void
317tsensor_calibration(struct tsensor *sensor, struct soctherm_shared_cal *shared)
318{
319	uint32_t val;
320	int mult, div, calib_cp, calib_ft;
321	int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
322	int temp_a, temp_b;
323	int64_t tmp;
324
325	val =  tegra_fuse_read_4(sensor->calib_fuse);
326	calib_cp = extract_signed(val,
327	    FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
328	    FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
329	actual_tsensor_cp = shared->base_cp * 64 + calib_cp;
330
331	calib_ft = extract_signed(val,
332	    FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
333	    FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
334	actual_tsensor_ft = shared->base_ft * 32 + calib_ft;
335
336	delta_sens = actual_tsensor_ft - actual_tsensor_cp;
337	delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
338	mult = sensor->cfg->pdiv * sensor->cfg->tsample_ate;
339	div = sensor->cfg->tsample * sensor->cfg->pdiv_ate;
340
341
342	temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
343				   (int64_t) delta_sens * div);
344
345	tmp = (int64_t)actual_tsensor_ft * shared->actual_temp_cp -
346	      (int64_t)actual_tsensor_cp * shared->actual_temp_ft;
347	temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
348
349	temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
350				   1000000);
351	temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
352				   sensor->fuse_corr_beta, 1000000);
353	sensor->therm_a = (int16_t)temp_a;
354	sensor->therm_b = (int16_t)temp_b;
355#ifdef DEBUG
356	printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
357	    " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
358	    __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
359	    calib_cp, calib_cp, calib_ft, calib_ft);
360	printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
361	    (uint16_t)sensor->therm_a, temp_a,
362	    (uint16_t)sensor->therm_b, sensor->therm_b);
363#endif
364}
365
366static void
367soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor,
368    struct soctherm_shared_cal *shared_cal)
369{
370	uint32_t val;
371
372	tsensor_calibration(sensor, shared_cal);
373
374	val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
375	val |= TSENSOR_CONFIG0_STOP;
376	val |= TSENSOR_CONFIG0_STATUS_CLR;
377	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
378
379	val = TSENSOR_CONFIG0_TALL(sensor->cfg->tall);
380	val |= TSENSOR_CONFIG0_STOP;
381	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
382
383	val = TSENSOR_CONFIG1_TSAMPLE(sensor->cfg->tsample - 1);
384	val |= TSENSOR_CONFIG1_TIDDQ_EN(sensor->cfg->tiddq_en);
385	val |= TSENSOR_CONFIG1_TEN_COUNT(sensor->cfg->ten_count);
386	val |= TSENSOR_CONFIG1_TEMP_ENABLE;
387	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
388
389	val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
390	     TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
391	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
392
393	val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
394	val &= ~TSENSOR_CONFIG0_STOP;
395	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
396#ifdef DEBUG
397	printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
398	    " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
399	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
400	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
401	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
402	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
403	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
404	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
405	    );
406#endif
407}
408
409static int
410soctherm_convert_raw(uint32_t val)
411{
412	int32_t t;
413
414	t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
415	if (val & READBACK_ADD_HALF)
416		t += 500;
417	if (val & READBACK_NEGATE)
418		t *= -1;
419
420	return t;
421}
422
423static int
424soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
425{
426	int timeout;
427	uint32_t val;
428
429
430	/* wait for valid sample */
431	for (timeout = 1000; timeout > 0; timeout--) {
432		val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
433		if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
434			break;
435		DELAY(100);
436	}
437	if (timeout <= 0)
438		device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
439	*temp = soctherm_convert_raw(val);
440#ifdef DEBUG
441	printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
442	printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
443	    " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
444	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
445	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
446	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
447	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
448	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
449	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
450	    );
451#endif
452	return 0;
453}
454
455static int
456soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
457{
458	struct soctherm_softc *sc;
459	int i;
460
461	sc = device_get_softc(dev);
462	/* The direct sensor map starts at 0x100 */
463	if (id >= 0x100) {
464		id -= 0x100;
465		if (id >= sc->ntsensors)
466			return (ERANGE);
467		return(soctherm_read_temp(sc, sc->tsensors + id, val));
468	}
469	/* Linux (DT) compatible thermal zones */
470	for (i = 0; i < sc->ntsensors; i++) {
471		if (sc->tsensors->id == id)
472			return(soctherm_read_temp(sc, sc->tsensors + id, val));
473	}
474	return (ERANGE);
475}
476
477static int
478soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
479{
480	struct soctherm_softc *sc;
481	int val;
482	int rv;
483	int id;
484
485	/* Write request */
486	if (req->newptr != NULL)
487		return (EINVAL);
488
489	sc = arg1;
490	id = arg2;
491
492	if (id >= sc->ntsensors)
493		return (ERANGE);
494	rv =  soctherm_read_temp(sc, sc->tsensors + id, &val);
495	if (rv != 0)
496		return (rv);
497
498	val = val / 100;
499	val +=  2731;
500	rv = sysctl_handle_int(oidp, &val, 0, req);
501	return (rv);
502}
503
504static int
505soctherm_init_sysctl(struct soctherm_softc *sc)
506{
507	int i;
508	struct sysctl_oid *oid, *tmp;
509
510	sysctl_ctx_init(&soctherm_sysctl_ctx);
511	/* create node for hw.temp */
512	oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
513	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
514	    CTLFLAG_RD, NULL, "");
515	if (oid == NULL)
516		return (ENXIO);
517
518	/* Add sensors */
519	for (i = sc->ntsensors  - 1; i >= 0; i--) {
520		tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
521		    SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
522		    CTLTYPE_INT | CTLFLAG_RD, sc, i,
523		    soctherm_sysctl_temperature, "IK", "SoC Temperature");
524		if (tmp == NULL)
525			return (ENXIO);
526	}
527
528	return (0);
529}
530
531static int
532soctherm_probe(device_t dev)
533{
534
535	if (!ofw_bus_status_okay(dev))
536		return (ENXIO);
537
538	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
539		return (ENXIO);
540
541	device_set_desc(dev, "Tegra temperature sensors");
542	return (BUS_PROBE_DEFAULT);
543}
544
545static int
546soctherm_attach(device_t dev)
547{
548	struct soctherm_softc *sc;
549	phandle_t node;
550	int i, rid, rv;
551	struct soctherm_shared_cal shared_calib;
552
553	sc = device_get_softc(dev);
554	sc->dev = dev;
555	node = ofw_bus_get_node(sc->dev);
556
557	rid = 0;
558	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
559	    RF_ACTIVE);
560	if (sc->mem_res == NULL) {
561		device_printf(dev, "Cannot allocate memory resources\n");
562		goto fail;
563	}
564
565	rid = 0;
566	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
567	if (sc->irq_res == NULL) {
568		device_printf(dev, "Cannot allocate IRQ resources\n");
569		goto fail;
570	}
571
572/*
573	if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
574	    soctherm_intr, NULL, sc, &sc->irq_ih))) {
575		device_printf(dev,
576		    "WARNING: unable to register interrupt handler\n");
577		goto fail;
578	}
579*/
580
581	/* OWF resources */
582	rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
583	if (rv != 0) {
584		device_printf(dev, "Cannot get fuse reset\n");
585		goto fail;
586	}
587	rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
588	if (rv != 0) {
589		device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
590		goto fail;
591	}
592	rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
593	if (rv != 0) {
594		device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
595		goto fail;
596	}
597
598	rv = hwreset_assert(sc->reset);
599	if (rv != 0) {
600		device_printf(dev, "Cannot assert reset\n");
601		goto fail;
602	}
603	rv = clk_enable(sc->tsensor_clk);
604	if (rv != 0) {
605		device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
606		goto fail;
607	}
608	rv = clk_enable(sc->soctherm_clk);
609	if (rv != 0) {
610		device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
611		goto fail;
612	}
613	rv = hwreset_deassert(sc->reset);
614	if (rv != 0) {
615		device_printf(dev, "Cannot clear reset\n");
616		goto fail;
617	}
618
619	/* Tegra 124 */
620	sc->tsensors = t124_tsensors;
621	sc->ntsensors = nitems(t124_tsensors);
622	get_shared_cal(sc, &shared_calib);
623
624	WR4(sc, TSENSOR_PDIV, TSENSOR_PDIV_T124);
625	WR4(sc, TSENSOR_HOTSPOT_OFF, TSENSOR_HOTSPOT_OFF_T124);
626
627	for (i = 0; i < sc->ntsensors; i++)
628		soctherm_init_tsensor(sc, sc->tsensors + i, &shared_calib);
629
630	rv = soctherm_init_sysctl(sc);
631	if (rv != 0) {
632		device_printf(sc->dev, "Cannot initialize sysctls\n");
633		goto fail;
634	}
635
636	OF_device_register_xref(OF_xref_from_node(node), dev);
637	return (bus_generic_attach(dev));
638
639fail:
640	if (sc->irq_ih != NULL)
641		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
642	sysctl_ctx_free(&soctherm_sysctl_ctx);
643	if (sc->tsensor_clk != NULL)
644		clk_release(sc->tsensor_clk);
645	if (sc->soctherm_clk != NULL)
646		clk_release(sc->soctherm_clk);
647	if (sc->reset != NULL)
648		hwreset_release(sc->reset);
649	if (sc->irq_res != NULL)
650		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
651	if (sc->mem_res != NULL)
652		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
653
654	return (ENXIO);
655}
656
657static int
658soctherm_detach(device_t dev)
659{
660	struct soctherm_softc *sc;
661	sc = device_get_softc(dev);
662
663	if (sc->irq_ih != NULL)
664		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
665	sysctl_ctx_free(&soctherm_sysctl_ctx);
666	if (sc->tsensor_clk != NULL)
667		clk_release(sc->tsensor_clk);
668	if (sc->soctherm_clk != NULL)
669		clk_release(sc->soctherm_clk);
670	if (sc->reset != NULL)
671		hwreset_release(sc->reset);
672	if (sc->irq_res != NULL)
673		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
674	if (sc->mem_res != NULL)
675		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
676
677	return (ENXIO);
678}
679
680static device_method_t tegra_soctherm_methods[] = {
681	/* Device interface */
682	DEVMETHOD(device_probe,			soctherm_probe),
683	DEVMETHOD(device_attach,		soctherm_attach),
684	DEVMETHOD(device_detach,		soctherm_detach),
685
686	/* SOCTHERM interface */
687	DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
688
689	DEVMETHOD_END
690};
691
692static devclass_t tegra_soctherm_devclass;
693static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
694    sizeof(struct soctherm_softc));
695EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
696    tegra_soctherm_devclass, NULL, NULL, 79);
697