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