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 = NULL, 173 .rev = 1, 174 .cap.length = 8, 175 }; 176 177 context.uuid_str = uuid_str; 178 179 buf[OSC_QUERY_DWORD] = 0; 180 buf[OSC_SUPPORT_DWORD] = *enable; 181 182 context.cap.pointer = buf; 183 184 status = acpi_run_osc(handle, &context); 185 if (ACPI_SUCCESS(status)) { 186 ret = *((u32 *)(context.ret.pointer + 4)); 187 if (ret != *enable) 188 result = -EPERM; 189 } else 190 result = -EPERM; 191 192 kfree(context.ret.pointer); 193 194 return result; 195 } 196 197 static int set_os_uuid_mask(struct int3400_thermal_priv *priv, u32 mask) 198 { 199 int cap = 0; 200 201 /* 202 * Capability bits: 203 * Bit 0: set to 1 to indicate DPTF is active 204 * Bi1 1: set to 1 to active cooling is supported by user space daemon 205 * Bit 2: set to 1 to passive cooling is supported by user space daemon 206 * Bit 3: set to 1 to critical trip is handled by user space daemon 207 */ 208 if (mask) 209 cap = (priv->os_uuid_mask << 1) | 0x01; 210 211 return int3400_thermal_run_osc(priv->adev->handle, 212 "b23ba85d-c8b7-3542-88de-8de2ffcfd698", 213 &cap); 214 } 215 216 static ssize_t current_uuid_store(struct device *dev, 217 struct device_attribute *attr, 218 const char *buf, size_t count) 219 { 220 struct int3400_thermal_priv *priv = dev_get_drvdata(dev); 221 int ret, i; 222 223 for (i = 0; i < INT3400_THERMAL_MAXIMUM_UUID; ++i) { 224 if (!strncmp(buf, int3400_thermal_uuids[i], 225 sizeof(int3400_thermal_uuids[i]) - 1)) { 226 /* 227 * If we have a list of supported UUIDs, make sure 228 * this one is supported. 229 */ 230 if (priv->uuid_bitmap & BIT(i)) { 231 priv->current_uuid_index = i; 232 return count; 233 } 234 235 /* 236 * There is support of only 3 policies via the new 237 * _OSC to inform OS capability: 238 * INT3400_THERMAL_ACTIVE 239 * INT3400_THERMAL_PASSIVE_1 240 * INT3400_THERMAL_CRITICAL 241 */ 242 243 if (i > INT3400_THERMAL_CRITICAL) 244 return -EINVAL; 245 246 priv->os_uuid_mask |= BIT(i); 247 248 break; 249 } 250 } 251 252 if (priv->os_uuid_mask) { 253 ret = set_os_uuid_mask(priv, priv->os_uuid_mask); 254 if (ret) 255 return ret; 256 } 257 258 return count; 259 } 260 261 static DEVICE_ATTR_RW(current_uuid); 262 static DEVICE_ATTR_RO(available_uuids); 263 static struct attribute *uuid_attrs[] = { 264 &dev_attr_available_uuids.attr, 265 &dev_attr_current_uuid.attr, 266 NULL 267 }; 268 269 static const struct attribute_group uuid_attribute_group = { 270 .attrs = uuid_attrs, 271 .name = "uuids" 272 }; 273 274 static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv) 275 { 276 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL}; 277 union acpi_object *obja, *objb; 278 int i, j; 279 int result = 0; 280 acpi_status status; 281 282 status = acpi_evaluate_object(priv->adev->handle, "IDSP", NULL, &buf); 283 if (ACPI_FAILURE(status)) 284 return -ENODEV; 285 286 obja = (union acpi_object *)buf.pointer; 287 if (obja->type != ACPI_TYPE_PACKAGE) { 288 result = -EINVAL; 289 goto end; 290 } 291 292 for (i = 0; i < obja->package.count; i++) { 293 objb = &obja->package.elements[i]; 294 if (objb->type != ACPI_TYPE_BUFFER) { 295 result = -EINVAL; 296 goto end; 297 } 298 299 /* UUID must be 16 bytes */ 300 if (objb->buffer.length != 16) { 301 result = -EINVAL; 302 goto end; 303 } 304 305 for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) { 306 guid_t guid; 307 308 guid_parse(int3400_thermal_uuids[j], &guid); 309 if (guid_equal((guid_t *)objb->buffer.pointer, &guid)) { 310 priv->uuid_bitmap |= (1 << j); 311 break; 312 } 313 } 314 } 315 316 end: 317 kfree(buf.pointer); 318 return result; 319 } 320 321 static ssize_t odvp_show(struct device *dev, struct device_attribute *attr, 322 char *buf) 323 { 324 struct odvp_attr *odvp_attr; 325 326 odvp_attr = container_of(attr, struct odvp_attr, attr); 327 328 return sprintf(buf, "%d\n", odvp_attr->priv->odvp[odvp_attr->odvp]); 329 } 330 331 static void cleanup_odvp(struct int3400_thermal_priv *priv) 332 { 333 int i; 334 335 if (priv->odvp_attrs) { 336 for (i = 0; i < priv->odvp_count; i++) { 337 sysfs_remove_file(&priv->pdev->dev.kobj, 338 &priv->odvp_attrs[i].attr.attr); 339 kfree(priv->odvp_attrs[i].attr.attr.name); 340 } 341 kfree(priv->odvp_attrs); 342 } 343 kfree(priv->odvp); 344 priv->odvp_count = 0; 345 } 346 347 static int evaluate_odvp(struct int3400_thermal_priv *priv) 348 { 349 struct acpi_buffer odvp = { ACPI_ALLOCATE_BUFFER, NULL }; 350 union acpi_object *obj = NULL; 351 acpi_status status; 352 int i, ret; 353 354 status = acpi_evaluate_object(priv->adev->handle, "ODVP", NULL, &odvp); 355 if (ACPI_FAILURE(status)) { 356 ret = -EINVAL; 357 goto out_err; 358 } 359 360 obj = odvp.pointer; 361 if (obj->type != ACPI_TYPE_PACKAGE) { 362 ret = -EINVAL; 363 goto out_err; 364 } 365 366 if (priv->odvp == NULL) { 367 priv->odvp_count = obj->package.count; 368 priv->odvp = kmalloc_array(priv->odvp_count, sizeof(int), 369 GFP_KERNEL); 370 if (!priv->odvp) { 371 ret = -ENOMEM; 372 goto out_err; 373 } 374 } 375 376 if (priv->odvp_attrs == NULL) { 377 priv->odvp_attrs = kcalloc(priv->odvp_count, 378 sizeof(struct odvp_attr), 379 GFP_KERNEL); 380 if (!priv->odvp_attrs) { 381 ret = -ENOMEM; 382 goto out_err; 383 } 384 for (i = 0; i < priv->odvp_count; i++) { 385 struct odvp_attr *odvp = &priv->odvp_attrs[i]; 386 387 sysfs_attr_init(&odvp->attr.attr); 388 odvp->priv = priv; 389 odvp->odvp = i; 390 odvp->attr.attr.name = kasprintf(GFP_KERNEL, 391 "odvp%d", i); 392 393 if (!odvp->attr.attr.name) { 394 ret = -ENOMEM; 395 goto out_err; 396 } 397 odvp->attr.attr.mode = 0444; 398 odvp->attr.show = odvp_show; 399 odvp->attr.store = NULL; 400 ret = sysfs_create_file(&priv->pdev->dev.kobj, 401 &odvp->attr.attr); 402 if (ret) 403 goto out_err; 404 } 405 } 406 407 for (i = 0; i < obj->package.count; i++) { 408 if (obj->package.elements[i].type == ACPI_TYPE_INTEGER) 409 priv->odvp[i] = obj->package.elements[i].integer.value; 410 } 411 412 kfree(obj); 413 return 0; 414 415 out_err: 416 cleanup_odvp(priv); 417 kfree(obj); 418 return ret; 419 } 420 421 static void int3400_notify(acpi_handle handle, 422 u32 event, 423 void *data) 424 { 425 struct int3400_thermal_priv *priv = data; 426 char *thermal_prop[5]; 427 int therm_event; 428 429 if (!priv) 430 return; 431 432 switch (event) { 433 case INT3400_THERMAL_TABLE_CHANGED: 434 therm_event = THERMAL_TABLE_CHANGED; 435 break; 436 case INT3400_KEEP_ALIVE: 437 therm_event = THERMAL_EVENT_KEEP_ALIVE; 438 break; 439 case INT3400_ODVP_CHANGED: 440 evaluate_odvp(priv); 441 therm_event = THERMAL_DEVICE_POWER_CAPABILITY_CHANGED; 442 break; 443 default: 444 /* Ignore unknown notification codes sent to INT3400 device */ 445 return; 446 } 447 448 thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", priv->thermal->type); 449 thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", priv->thermal->temperature); 450 thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP="); 451 thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", therm_event); 452 thermal_prop[4] = NULL; 453 kobject_uevent_env(&priv->thermal->device.kobj, KOBJ_CHANGE, thermal_prop); 454 kfree(thermal_prop[0]); 455 kfree(thermal_prop[1]); 456 kfree(thermal_prop[2]); 457 kfree(thermal_prop[3]); 458 } 459 460 static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, 461 int *temp) 462 { 463 *temp = 20 * 1000; /* faked temp sensor with 20C */ 464 return 0; 465 } 466 467 static int int3400_thermal_change_mode(struct thermal_zone_device *thermal, 468 enum thermal_device_mode mode) 469 { 470 struct int3400_thermal_priv *priv = thermal->devdata; 471 int result = 0; 472 473 if (!priv) 474 return -EINVAL; 475 476 if (mode != thermal->mode) { 477 int enabled; 478 479 enabled = mode == THERMAL_DEVICE_ENABLED; 480 481 if (priv->os_uuid_mask) { 482 if (!enabled) { 483 priv->os_uuid_mask = 0; 484 result = set_os_uuid_mask(priv, priv->os_uuid_mask); 485 } 486 goto eval_odvp; 487 } 488 489 if (priv->current_uuid_index < 0 || 490 priv->current_uuid_index >= INT3400_THERMAL_MAXIMUM_UUID) 491 return -EINVAL; 492 493 result = int3400_thermal_run_osc(priv->adev->handle, 494 int3400_thermal_uuids[priv->current_uuid_index], 495 &enabled); 496 } 497 498 eval_odvp: 499 evaluate_odvp(priv); 500 501 return result; 502 } 503 504 static struct thermal_zone_device_ops int3400_thermal_ops = { 505 .get_temp = int3400_thermal_get_temp, 506 .change_mode = int3400_thermal_change_mode, 507 }; 508 509 static struct thermal_zone_params int3400_thermal_params = { 510 .governor_name = "user_space", 511 .no_hwmon = true, 512 }; 513 514 static void int3400_setup_gddv(struct int3400_thermal_priv *priv) 515 { 516 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 517 union acpi_object *obj; 518 acpi_status status; 519 520 status = acpi_evaluate_object(priv->adev->handle, "GDDV", NULL, 521 &buffer); 522 if (ACPI_FAILURE(status) || !buffer.length) 523 return; 524 525 obj = buffer.pointer; 526 if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 1 527 || obj->package.elements[0].type != ACPI_TYPE_BUFFER) { 528 kfree(buffer.pointer); 529 return; 530 } 531 532 priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer, 533 obj->package.elements[0].buffer.length, 534 GFP_KERNEL); 535 if (!priv->data_vault) { 536 kfree(buffer.pointer); 537 return; 538 } 539 540 bin_attr_data_vault.private = priv->data_vault; 541 bin_attr_data_vault.size = obj->package.elements[0].buffer.length; 542 kfree(buffer.pointer); 543 } 544 545 static int int3400_thermal_probe(struct platform_device *pdev) 546 { 547 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 548 struct int3400_thermal_priv *priv; 549 int result; 550 551 if (!adev) 552 return -ENODEV; 553 554 priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL); 555 if (!priv) 556 return -ENOMEM; 557 558 priv->pdev = pdev; 559 priv->adev = adev; 560 561 result = int3400_thermal_get_uuids(priv); 562 563 /* Missing IDSP isn't fatal */ 564 if (result && result != -ENODEV) 565 goto free_priv; 566 567 priv->current_uuid_index = -1; 568 569 result = acpi_parse_art(priv->adev->handle, &priv->art_count, 570 &priv->arts, true); 571 if (result) 572 dev_dbg(&pdev->dev, "_ART table parsing error\n"); 573 574 result = acpi_parse_trt(priv->adev->handle, &priv->trt_count, 575 &priv->trts, true); 576 if (result) 577 dev_dbg(&pdev->dev, "_TRT table parsing error\n"); 578 579 platform_set_drvdata(pdev, priv); 580 581 int3400_setup_gddv(priv); 582 583 evaluate_odvp(priv); 584 585 priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0, 586 priv, &int3400_thermal_ops, 587 &int3400_thermal_params, 0, 0); 588 if (IS_ERR(priv->thermal)) { 589 result = PTR_ERR(priv->thermal); 590 goto free_art_trt; 591 } 592 593 priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add( 594 priv->adev->handle); 595 596 result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group); 597 if (result) 598 goto free_rel_misc; 599 600 if (acpi_has_method(priv->adev->handle, "IMOK")) { 601 result = sysfs_create_group(&pdev->dev.kobj, &imok_attribute_group); 602 if (result) 603 goto free_imok; 604 } 605 606 if (priv->data_vault) { 607 result = sysfs_create_group(&pdev->dev.kobj, 608 &data_attribute_group); 609 if (result) 610 goto free_uuid; 611 } 612 613 result = acpi_install_notify_handler( 614 priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify, 615 (void *)priv); 616 if (result) 617 goto free_sysfs; 618 619 return 0; 620 621 free_sysfs: 622 cleanup_odvp(priv); 623 if (priv->data_vault) { 624 sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); 625 kfree(priv->data_vault); 626 } 627 free_uuid: 628 sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 629 free_imok: 630 sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); 631 free_rel_misc: 632 if (!priv->rel_misc_dev_res) 633 acpi_thermal_rel_misc_device_remove(priv->adev->handle); 634 thermal_zone_device_unregister(priv->thermal); 635 free_art_trt: 636 kfree(priv->trts); 637 kfree(priv->arts); 638 free_priv: 639 kfree(priv); 640 return result; 641 } 642 643 static int int3400_thermal_remove(struct platform_device *pdev) 644 { 645 struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); 646 647 acpi_remove_notify_handler( 648 priv->adev->handle, ACPI_DEVICE_NOTIFY, 649 int3400_notify); 650 651 cleanup_odvp(priv); 652 653 if (!priv->rel_misc_dev_res) 654 acpi_thermal_rel_misc_device_remove(priv->adev->handle); 655 656 if (priv->data_vault) 657 sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); 658 sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); 659 sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); 660 thermal_zone_device_unregister(priv->thermal); 661 kfree(priv->data_vault); 662 kfree(priv->trts); 663 kfree(priv->arts); 664 kfree(priv); 665 return 0; 666 } 667 668 static const struct acpi_device_id int3400_thermal_match[] = { 669 {"INT3400", 0}, 670 {"INTC1040", 0}, 671 {"INTC1041", 0}, 672 {"INTC10A0", 0}, 673 {} 674 }; 675 676 MODULE_DEVICE_TABLE(acpi, int3400_thermal_match); 677 678 static struct platform_driver int3400_thermal_driver = { 679 .probe = int3400_thermal_probe, 680 .remove = int3400_thermal_remove, 681 .driver = { 682 .name = "int3400 thermal", 683 .acpi_match_table = ACPI_PTR(int3400_thermal_match), 684 }, 685 }; 686 687 module_platform_driver(int3400_thermal_driver); 688 689 MODULE_DESCRIPTION("INT3400 Thermal driver"); 690 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); 691 MODULE_LICENSE("GPL"); 692