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