Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/nvidia/tegra_soctherm.c
39478 views
1
/*-
2
* Copyright (c) 2016 Michal Meloun <[email protected]>
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/clk/clk.h>
47
#include <dev/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
bus_attach_children(dev);
784
return (0);
785
786
fail:
787
if (sc->irq_ih != NULL)
788
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
789
sysctl_ctx_free(&soctherm_sysctl_ctx);
790
if (sc->tsensor_clk != NULL)
791
clk_release(sc->tsensor_clk);
792
if (sc->soctherm_clk != NULL)
793
clk_release(sc->soctherm_clk);
794
if (sc->reset != NULL)
795
hwreset_release(sc->reset);
796
if (sc->irq_res != NULL)
797
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
798
if (sc->mem_res != NULL)
799
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
800
801
return (ENXIO);
802
}
803
804
static int
805
soctherm_detach(device_t dev)
806
{
807
struct soctherm_softc *sc;
808
sc = device_get_softc(dev);
809
810
if (sc->irq_ih != NULL)
811
bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
812
sysctl_ctx_free(&soctherm_sysctl_ctx);
813
if (sc->tsensor_clk != NULL)
814
clk_release(sc->tsensor_clk);
815
if (sc->soctherm_clk != NULL)
816
clk_release(sc->soctherm_clk);
817
if (sc->reset != NULL)
818
hwreset_release(sc->reset);
819
if (sc->irq_res != NULL)
820
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
821
if (sc->mem_res != NULL)
822
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
823
824
return (ENXIO);
825
}
826
827
static device_method_t tegra_soctherm_methods[] = {
828
/* Device interface */
829
DEVMETHOD(device_probe, soctherm_probe),
830
DEVMETHOD(device_attach, soctherm_attach),
831
DEVMETHOD(device_detach, soctherm_detach),
832
833
/* SOCTHERM interface */
834
DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
835
836
DEVMETHOD_END
837
};
838
839
static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
840
sizeof(struct soctherm_softc));
841
EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
842
NULL, NULL, 79);
843
844