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