1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * INT3400 thermal driver 4 * 5 * Copyright (C) 2014, Intel Corporation 6 * Authors: Zhang Rui <rui.zhang@intel.com> 7 */ 8 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/acpi.h> 12 #include <linux/thermal.h> 13 #include "acpi_thermal_rel.h" 14 15 #define INT3400_THERMAL_TABLE_CHANGED 0x83 16 #define INT3400_ODVP_CHANGED 0x88 17 #define INT3400_KEEP_ALIVE 0xA0 18 19 enum int3400_thermal_uuid { 20 INT3400_THERMAL_ACTIVE = 0, 21 INT3400_THERMAL_PASSIVE_1, 22 INT3400_THERMAL_CRITICAL, 23 INT3400_THERMAL_ADAPTIVE_PERFORMANCE, 24 INT3400_THERMAL_EMERGENCY_CALL_MODE, 25 INT3400_THERMAL_PASSIVE_2, 26 INT3400_THERMAL_POWER_BOSS, 27 INT3400_THERMAL_VIRTUAL_SENSOR, 28 INT3400_THERMAL_COOLING_MODE, 29 INT3400_THERMAL_HARDWARE_DUTY_CYCLING, 30 INT3400_THERMAL_MAXIMUM_UUID, 31 }; 32 33 static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { 34 "3A95C389-E4B8-4629-A526-C52C88626BAE", 35 "42A441D6-AE6A-462b-A84B-4A8CE79027D3", 36 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", 37 "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D", 38 "5349962F-71E6-431D-9AE8-0A635B710AEE", 39 "9E04115A-AE87-4D1C-9500-0F3E340BFE75", 40 "F5A35014-C209-46A4-993A-EB56DE7530A1", 41 "6ED722A7-9240-48A5-B479-31EEF723D7CF", 42 "16CAF1B7-DD38-40ED-B1C1-1B8A1913D531", 43 "BE84BABF-C4D4-403D-B495-3128FD44dAC1", 44 }; 45 46 struct odvp_attr; 47 48 struct int3400_thermal_priv { 49 struct acpi_device *adev; 50 struct platform_device *pdev; 51 struct thermal_zone_device *thermal; 52 int art_count; 53 struct art *arts; 54 int trt_count; 55 struct trt *trts; 56 u32 uuid_bitmap; 57 int rel_misc_dev_res; 58 int current_uuid_index; 59 char *data_vault; 60 int odvp_count; 61 int *odvp; 62 u32 os_uuid_mask; 63 struct odvp_attr *odvp_attrs; 64 }; 65 66 static int evaluate_odvp(struct int3400_thermal_priv *priv); 67 68 struct odvp_attr { 69 int odvp; 70 struct int3400_thermal_priv *priv; 71 struct device_attribute attr; 72 }; 73 74 static ssize_t data_vault_read(struct file *file, struct kobject *kobj, 75 struct bin_attribute *attr, char *buf, loff_t off, size_t count) 76 { 77 memcpy(buf, attr->private + off, count); 78 return count; 79 } 80 81 static BIN_ATTR_RO(data_vault, 0); 82 83 static struct bin_attribute *data_attributes[] = { 84 &bin_attr_data_vault, 85 NULL, 86 }; 87 88 static ssize_t imok_store(struct device *dev, struct device_attribute *attr, 89 const char *buf, size_t count) 90 { 91 struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 92 acpi_status status; 93 int input, ret; 94 95 ret = kstrtouint(buf, 10, &input); 96 if (ret) 97 return ret; 98 status = acpi_execute_simple_method(priv->adev->handle, "IMOK", input); 99 if (ACPI_FAILURE(status)) 100 return -EIO; 101 102 return count; 103 } 104 105 static DEVICE_ATTR_WO(imok); 106 107 static struct attribute *imok_attr[] = { 108 &dev_attr_imok.attr, 109 NULL 110 }; 111 112 static const struct attribute_group imok_attribute_group = { 113 .attrs = imok_attr, 114 }; 115 116 static const struct attribute_group data_attribute_group = { 117 .bin_attrs = data_attributes, 118 }; 119 120 static ssize_t available_uuids_show(struct device *dev, 121 struct device_attribute *attr, 122 char *buf) 123 { 124 struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 125 int i; 126 int length = 0; 127 128 if (!priv->uuid_bitmap) 129 return sprintf(buf, "UNKNOWN\n"); 130 131 for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; i++) { 132 if (priv->uuid_bitmap & (1 << i)) 133 length += scnprintf(&buf[length], 134 PAGE_SIZE - length, 135 "%s\n", 136 int3400_thermal_uuids[i]); 137 } 138 139 return length; 140 } 141 142 static ssize_t current_uuid_show(struct device *dev, 143 struct device_attribute *devattr, char *buf) 144 { 145 struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 146 int i, length = 0; 147 148 if (priv->current_uuid_index > 0) 149 return sprintf(buf, "%s\n", 150 int3400_thermal_uuids[priv->current_uuid_index]); 151 152 for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) { 153 if (priv->os_uuid_mask & BIT(i)) 154 length += scnprintf(&buf[length], 155 PAGE_SIZE - length, 156 "%s\n", 157 int3400_thermal_uuids[i]); 158 } 159 160 if (length) 161 return length; 162 163 return sprintf(buf, "INVALID\n"); 164 } 165 166 static int int3400_thermal_run_osc(acpi_handle handle, char *uuid_str, int *enable) 167 { 168 u32 ret, buf[2]; 169 acpi_status status; 170 int result = 0; 171 struct acpi_osc_context context = { 172 .uuid_str = uuid_str, 173 .rev = 1, 174 .cap.length = 8, 175 .cap.pointer = buf, 176 }; 177 178 buf[OSC_QUERY_DWORD] = 0; 179 buf[OSC_SUPPORT_DWORD] = *enable; 180 181 status = acpi_run_osc(handle, &context); 182 if (ACPI_SUCCESS(status)) { 183 ret = *((u32 *)(context.ret.pointer + 4)); 184 if (ret != *enable) 185 result = -EPERM; 186 187 kfree(context.ret.pointer); 188 } else 189 result = -EPERM; 190 191 return result; 192 } 193 194 static int set_os_uuid_mask(struct int3400_thermal_priv *priv, u32 mask) 195 { 196 int cap = 0; 197 198 /* 199 * Capability bits: 200 * Bit 0: set to 1 to indicate DPTF is active 201 * Bi1 1: set to 1 to active cooling is supported by user space daemon 202 * Bit 2: set to 1 to passive cooling is supported by user space daemon 203 * Bit 3: set to 1 to critical trip is handled by user space daemon 204 */ 205 if (mask) 206 cap = (priv->os_uuid_mask << 1) | 0x01; 207 208 return int3400_thermal_run_osc(priv->adev->handle, 209 "b23ba85d-c8b7-3542-88de-8de2ffcfd698", 210 &cap); 211 } 212 213 static ssize_t current_uuid_store(struct device *dev, 214 struct device_attribute *attr, 215 const char *buf, size_t count) 216 { 217 struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 218 int ret, i; 219 220 for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; ++i) { 221 if (!strncmp(buf, int3400_thermal_uuids[i], 222 sizeof(int3400_thermal_uuids[i]) - 1)) { 223 /* 224 * If we have a list of supported UUIDs, make sure 225 * this one is supported. 226 */ 227 if (priv->uuid_bitmap & BIT(i)) { 228 priv->current_uuid_index = i; 229 return count; 230 } 231 232 /* 233 * There is support of only 3 policies via the new 234 * _OSC to inform OS capability: 235 * INT3400_THERMAL_ACTIVE 236 * INT3400_THERMAL_PASSIVE_1 237 * INT3400_THERMAL_CRITICAL 238 */ 239 240 if (i > INT3400_THERMAL_CRITICAL) 241 return -EINVAL; 242 243 priv->os_uuid_mask |= BIT(i); 244 245 break; 246 } 247 } 248 249 if (priv->os_uuid_mask) { 250 ret = set_os_uuid_mask(priv, priv->os_uuid_mask); 251 if (ret) 252 return ret; 253 } 254 255 return count; 256 } 257 258 static DEVICE_ATTR_RW(current_uuid); 259 static DEVICE_ATTR_RO(available_uuids); 260 static struct attribute *uuid_attrs[] = { 261 &dev_attr_available_uuids.attr, 262 &dev_attr_current_uuid.attr, 263 NULL 264 }; 265 266 static const struct attribute_group uuid_attribute_group = { 267 .attrs = uuid_attrs, 268 .name = "uuids" 269 }; 270 271 static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv) 272 { 273 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL}; 274 union acpi_object *obja, *objb; 275 int i, j; 276 int result = 0; 277 acpi_status status; 278 279 status = acpi_evaluate_object(priv->adev->handle, "IDSP", NULL, &buf); 280 if (ACPI_FAILURE(status)) 281 return -ENODEV; 282 283 obja = (union acpi_object *)buf.pointer; 284 if (obja->type != ACPI_TYPE_PACKAGE) { 285 result = -EINVAL; 286 goto end; 287 } 288 289 for (i = 0; i < obja->package.count; i++) { 290 objb = &obja->package.elements[i]; 291 if (objb->type != ACPI_TYPE_BUFFER) { 292 result = -EINVAL; 293 goto end; 294 } 295 296 /* UUID must be 16 bytes */ 297 if (objb->buffer.length != 16) { 298 result = -EINVAL; 299 goto end; 300 } 301 302 for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) { 303 guid_t guid; 304 305 guid_parse(int3400_thermal_uuids[j], &guid); 306 if (guid_equal((guid_t *)objb->buffer.pointer, &guid)) { 307 priv->uuid_bitmap |= (1 << j); 308 break; 309 } 310 } 311 } 312 313 end: 314 kfree(buf.pointer); 315 return result; 316 } 317 318 static ssize_t odvp_show(struct device *dev, struct device_attribute *attr, 319 char *buf) 320 { 321 struct odvp_attr *odvp_attr; 322 323 odvp_attr = container_of(attr, struct odvp_attr, attr); 324 325 return sprintf(buf, "%d\n", odvp_attr->priv->odvp[odvp_attr->odvp]); 326 } 327 328 static void cleanup_odvp(struct int3400_thermal_priv *priv) 329 { 330 int i; 331 332 if (priv->odvp_attrs) { 333 for (i = 0; i < priv->odvp_count; i++) { 334 sysfs_remove_file(&priv->pdev->dev.kobj, 335 &priv->odvp_attrs[i].attr.attr); 336 kfree(priv->odvp_attrs[i].attr.attr.name); 337 } 338 kfree(priv->odvp_attrs); 339 } 340 kfree(priv->odvp); 341 priv->odvp_count = 0; 342 } 343 344 static int evaluate_odvp(struct int3400_thermal_priv *priv) 345 { 346 struct acpi_buffer odvp = { ACPI_ALLOCATE_BUFFER, NULL }; 347 union acpi_object *obj = NULL; 348 acpi_status status; 349 int i, ret; 350 351 status = acpi_evaluate_object(priv->adev->handle, "ODVP", NULL, &odvp); 352 if (ACPI_FAILURE(status)) { 353 ret = -EINVAL; 354 goto out_err; 355 } 356 357 obj = odvp.pointer; 358 if (obj->type != ACPI_TYPE_PACKAGE) { 359 ret = -EINVAL; 360 goto out_err; 361 } 362 363 if (priv->odvp == NULL) { 364 priv->odvp_count = obj->package.count; 365 priv->odvp = kmalloc_array(priv->odvp_count, sizeof(int), 366 GFP_KERNEL); 367 if (!priv->odvp) { 368 ret = -ENOMEM; 369 goto out_err; 370 } 371 } 372 373 if (priv->odvp_attrs == NULL) { 374 priv->odvp_attrs = kcalloc(priv->odvp_count, 375 sizeof(struct odvp_attr), 376 GFP_KERNEL); 377 if (!priv->odvp_attrs) { 378 ret = -ENOMEM; 379 goto out_err; 380 } 381 for (i = 0; i < priv->odvp_count; i++) { 382 struct odvp_attr *odvp = &priv->odvp_attrs[i]; 383 384 sysfs_attr_init(&odvp->attr.attr); 385 odvp->priv = priv; 386 odvp->odvp = i; 387 odvp->attr.attr.name = kasprintf(GFP_KERNEL, 388 "odvp%d", i); 389 390 if (!odvp->attr.attr.name) { 391 ret = -ENOMEM; 392 goto out_err; 393 } 394 odvp->attr.attr.mode = 0444; 395 odvp->attr.show = odvp_show; 396 odvp->attr.store = NULL; 397 ret = sysfs_create_file(&priv->pdev->dev.kobj, 398 &odvp->attr.attr); 399 if (ret) 400 goto out_err; 401 } 402 } 403 404 for (i = 0; i < obj->package.count; i++) { 405 if (obj->package.elements[i].type == ACPI_TYPE_INTEGER) 406 priv->odvp[i] = obj->package.elements[i].integer.value; 407 } 408 409 kfree(obj); 410 return 0; 411 412 out_err: 413 cleanup_odvp(priv); 414 kfree(obj); 415 return ret; 416 } 417 418 static void int3400_notify(acpi_handle handle, 419 u32 event, 420 void *data) 421 { 422 struct int3400_thermal_priv *priv = data; 423 char *thermal_prop[5]; 424 int therm_event; 425 426 if (!priv) 427 return; 428 429 switch (event) { 430 case INT3400_THERMAL_TABLE_CHANGED: 431 therm_event = THERMAL_TABLE_CHANGED; 432 break; 433 case INT3400_KEEP_ALIVE: 434 therm_event = THERMAL_EVENT_KEEP_ALIVE; 435 break; 436 case INT3400_ODVP_CHANGED: 437 evaluate_odvp(priv); 438 therm_event = THERMAL_DEVICE_POWER_CAPABILITY_CHANGED; 439 break; 440 default: 441 /* Ignore unknown notification codes sent to INT3400 device */ 442 return; 443 } 444 445 thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", priv->thermal->type); 446 thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", priv->thermal->temperature); 447 thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP="); 448 thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", therm_event); 449 thermal_prop[4] = NULL; 450 kobject_uevent_env(&priv->thermal->device.kobj, KOBJ_CHANGE, thermal_prop); 451 kfree(thermal_prop[0]); 452 kfree(thermal_prop[1]); 453 kfree(thermal_prop[2]); 454 kfree(thermal_prop[3]); 455 } 456 457 static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, 458 int *temp) 459 { 460 *temp = 20 * 1000; /* faked temp sensor with 20C */ 461 return 0; 462 } 463 464 static int int3400_thermal_change_mode(struct thermal_zone_device *thermal, 465 enum thermal_device_mode mode) 466 { 467 struct int3400_thermal_priv *priv = thermal->devdata; 468 int result = 0; 469 470 if (!priv) 471 return -EINVAL; 472 473 if (mode != thermal->mode) { 474 int enabled; 475 476 enabled = mode == THERMAL_DEVICE_ENABLED; 477 478 if (priv->os_uuid_mask) { 479 if (!enabled) { 480 priv->os_uuid_mask = 0; 481 result = set_os_uuid_mask(priv, priv->os_uuid_mask); 482 } 483 goto eval_odvp; 484 } 485 486 if (priv->current_uuid_index < 0 || 487 priv->current_uuid_index >= INT3400_THERMAL_MAXIMUM_UUID) 488 return -EINVAL; 489 490 result = int3400_thermal_run_osc(priv->adev->handle, 491 int3400_thermal_uuids[priv->current_uuid_index], 492 &enabled); 493 } 494 495 eval_odvp: 496 evaluate_odvp(priv); 497 498 return result; 499 } 500 501 static struct thermal_zone_device_ops int3400_thermal_ops = { 502 .get_temp = int3400_thermal_get_temp, 503 .change_mode = int3400_thermal_change_mode, 504 }; 505 506 static struct thermal_zone_params int3400_thermal_params = { 507 .governor_name = "user_space", 508 .no_hwmon = true, 509 }; 510 511 static void int3400_setup_gddv(struct int3400_thermal_priv *priv) 512 { 513 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 514 union acpi_object *obj; 515 acpi_status status; 516 517 status = acpi_evaluate_object(priv->adev->handle, "GDDV", NULL, 518 &buffer); 519 if (ACPI_FAILURE(status) || !buffer.length) 520 return; 521 522 obj = buffer.pointer; 523 if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 1 524 || obj->package.elements[0].type != ACPI_TYPE_BUFFER) 525 goto out_free; 526 527 priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer, 528 obj->package.elements[0].buffer.length, 529 GFP_KERNEL); 530 if (ZERO_OR_NULL_PTR(priv->data_vault)) 531 goto out_free; 532 533 bin_attr_data_vault.private = priv->data_vault; 534 bin_attr_data_vault.size = obj->package.elements[0].buffer.length; 535 out_free: 536 kfree(buffer.pointer); 537 } 538 539 static int int3400_thermal_probe(struct platform_device *pdev) 540 { 541 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 542 struct int3400_thermal_priv *priv; 543 int result; 544 545 if (!adev) 546 return -ENODEV; 547 548 priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL); 549 if (!priv) 550 return -ENOMEM; 551 552 priv->pdev = pdev; 553 priv->adev = adev; 554 555 result = int3400_thermal_get_uuids(priv); 556 557 /* Missing IDSP isn't fatal */ 558 if (result && result != -ENODEV) 559 goto free_priv; 560 561 priv->current_uuid_index = -1; 562 563 result = acpi_parse_art(priv->adev->handle, &priv->art_count, 564 &priv->arts, true); 565 if (result) 566 dev_dbg(&pdev->dev, "_ART table parsing error\n"); 567 568 result = acpi_parse_trt(priv->adev->handle, &priv->trt_count, 569 &priv->trts, true); 570 if (result) 571 dev_dbg(&pdev->dev, "_TRT table parsing error\n"); 572 573 platform_set_drvdata(pdev, priv); 574 575 int3400_setup_gddv(priv); 576 577 evaluate_odvp(priv); 578 579 priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, 580 priv, &int3400_thermal_ops, 581 &int3400_thermal_params, 0, 0); 582 if (IS_ERR(priv->thermal)) { 583 result = PTR_ERR(priv->thermal); 584 goto free_art_trt; 585 } 586 587 priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add( 588 priv->adev->handle); 589 590 result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group); 591 if (result) 592 goto free_rel_misc; 593 594 if (acpi_has_method(priv->adev->handle, "IMOK")) { 595 result = sysfs_create_group(&pdev->dev.kobj, &imok_attribute_group); 596 if (result) 597 goto free_imok; 598 } 599 600 if (!ZERO_OR_NULL_PTR(priv->data_vault)) { 601 result = sysfs_create_group(&pdev->dev.kobj, 602 &data_attribute_group); 603 if (result) 604 goto free_uuid; 605 } 606 607 result = acpi_install_notify_handler( 608 priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify, 609 (void *)priv); 610 if (result) 611 goto free_sysfs; 612 613 return 0; 614 615 free_sysfs: 616 cleanup_odvp(priv); 617 if (!ZERO_OR_NULL_PTR(priv->data_vault)) { 618 sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); 619 kfree(priv->data_vault); 620 } 621 free_uuid: 622 sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 623 free_imok: 624 sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); 625 free_rel_misc: 626 if (!priv->rel_misc_dev_res) 627 acpi_thermal_rel_misc_device_remove(priv->adev->handle); 628 thermal_zone_device_unregister(priv->thermal); 629 free_art_trt: 630 kfree(priv->trts); 631 kfree(priv->arts); 632 free_priv: 633 kfree(priv); 634 return result; 635 } 636 637 static int int3400_thermal_remove(struct platform_device *pdev) 638 { 639 struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); 640 641 acpi_remove_notify_handler( 642 priv->adev->handle, ACPI_DEVICE_NOTIFY, 643 int3400_notify); 644 645 cleanup_odvp(priv); 646 647 if (!priv->rel_misc_dev_res) 648 acpi_thermal_rel_misc_device_remove(priv->adev->handle); 649 650 if (!ZERO_OR_NULL_PTR(priv->data_vault)) 651 sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); 652 sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 653 sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); 654 thermal_zone_device_unregister(priv->thermal); 655 kfree(priv->data_vault); 656 kfree(priv->trts); 657 kfree(priv->arts); 658 kfree(priv); 659 return 0; 660 } 661 662 static const struct acpi_device_id int3400_thermal_match[] = { 663 {"INT3400", 0}, 664 {"INTC1040", 0}, 665 {"INTC1041", 0}, 666 {"INTC1042", 0}, 667 {"INTC10A0", 0}, 668 {} 669 }; 670 671 MODULE_DEVICE_TABLE(acpi, int3400_thermal_match); 672 673 static struct platform_driver int3400_thermal_driver = { 674 .probe = int3400_thermal_probe, 675 .remove = int3400_thermal_remove, 676 .driver = { 677 .name = "int3400 thermal", 678 .acpi_match_table = ACPI_PTR(int3400_thermal_match), 679 }, 680 }; 681 682 module_platform_driver(int3400_thermal_driver); 683 684 MODULE_DESCRIPTION("INT3400 Thermal driver"); 685 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); 686 MODULE_LICENSE("GPL"); 687