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/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 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