1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Asus Armoury (WMI) attributes driver. 4 * 5 * This driver uses the fw_attributes class to expose various WMI functions 6 * that are present in many gaming and some non-gaming ASUS laptops. 7 * 8 * These typically don't fit anywhere else in the sysfs such as under LED class, 9 * hwmon or others, and are set in Windows using the ASUS Armoury Crate tool. 10 * 11 * Copyright(C) 2024 Luke Jones <luke@ljones.dev> 12 */ 13 14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 16 #include <linux/acpi.h> 17 #include <linux/array_size.h> 18 #include <linux/bitfield.h> 19 #include <linux/device.h> 20 #include <linux/dmi.h> 21 #include <linux/err.h> 22 #include <linux/errno.h> 23 #include <linux/fs.h> 24 #include <linux/kernel.h> 25 #include <linux/kmod.h> 26 #include <linux/kobject.h> 27 #include <linux/kstrtox.h> 28 #include <linux/module.h> 29 #include <linux/mutex.h> 30 #include <linux/pci.h> 31 #include <linux/platform_data/x86/asus-wmi.h> 32 #include <linux/printk.h> 33 #include <linux/power_supply.h> 34 #include <linux/sysfs.h> 35 36 #include "asus-armoury.h" 37 #include "firmware_attributes_class.h" 38 39 #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" 40 41 #define ASUS_MINI_LED_MODE_MASK GENMASK(1, 0) 42 /* Standard modes for devices with only on/off */ 43 #define ASUS_MINI_LED_OFF 0x00 44 #define ASUS_MINI_LED_ON 0x01 45 /* Like "on" but the effect is more vibrant or brighter */ 46 #define ASUS_MINI_LED_STRONG_MODE 0x02 47 /* New modes for devices with 3 mini-led mode types */ 48 #define ASUS_MINI_LED_2024_WEAK 0x00 49 #define ASUS_MINI_LED_2024_STRONG 0x01 50 #define ASUS_MINI_LED_2024_OFF 0x02 51 52 /* Power tunable attribute name defines */ 53 #define ATTR_PPT_PL1_SPL "ppt_pl1_spl" 54 #define ATTR_PPT_PL2_SPPT "ppt_pl2_sppt" 55 #define ATTR_PPT_PL3_FPPT "ppt_pl3_fppt" 56 #define ATTR_PPT_APU_SPPT "ppt_apu_sppt" 57 #define ATTR_PPT_PLATFORM_SPPT "ppt_platform_sppt" 58 #define ATTR_NV_DYNAMIC_BOOST "nv_dynamic_boost" 59 #define ATTR_NV_TEMP_TARGET "nv_temp_target" 60 #define ATTR_NV_BASE_TGP "nv_base_tgp" 61 #define ATTR_NV_TGP "nv_tgp" 62 63 #define ASUS_ROG_TUNABLE_DC 0 64 #define ASUS_ROG_TUNABLE_AC 1 65 66 struct rog_tunables { 67 const struct power_limits *power_limits; 68 u32 ppt_pl1_spl; // cpu 69 u32 ppt_pl2_sppt; // cpu 70 u32 ppt_pl3_fppt; // cpu 71 u32 ppt_apu_sppt; // plat 72 u32 ppt_platform_sppt; // plat 73 74 u32 nv_dynamic_boost; 75 u32 nv_temp_target; 76 u32 nv_tgp; 77 }; 78 79 struct asus_armoury_priv { 80 struct device *fw_attr_dev; 81 struct kset *fw_attr_kset; 82 83 /* 84 * Mutex to protect eGPU activation/deactivation 85 * sequences and dGPU connection status: 86 * do not allow concurrent changes or changes 87 * before a reboot if dGPU got disabled. 88 */ 89 struct mutex egpu_mutex; 90 91 /* Index 0 for DC, 1 for AC */ 92 struct rog_tunables *rog_tunables[2]; 93 94 u32 mini_led_dev_id; 95 u32 gpu_mux_dev_id; 96 }; 97 98 static struct asus_armoury_priv asus_armoury = { 99 .egpu_mutex = __MUTEX_INITIALIZER(asus_armoury.egpu_mutex), 100 }; 101 102 struct fw_attrs_group { 103 bool pending_reboot; 104 }; 105 106 static struct fw_attrs_group fw_attrs = { 107 .pending_reboot = false, 108 }; 109 110 struct asus_attr_group { 111 const struct attribute_group *attr_group; 112 u32 wmi_devid; 113 }; 114 115 static void asus_set_reboot_and_signal_event(void) 116 { 117 fw_attrs.pending_reboot = true; 118 kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE); 119 } 120 121 static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 122 { 123 return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot); 124 } 125 126 static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); 127 128 static bool asus_bios_requires_reboot(struct kobj_attribute *attr) 129 { 130 return !strcmp(attr->attr.name, "gpu_mux_mode") || 131 !strcmp(attr->attr.name, "panel_hd_mode"); 132 } 133 134 /** 135 * armoury_has_devstate() - Check presence of the WMI function state. 136 * 137 * @dev_id: The WMI method ID to check for presence. 138 * 139 * Returns: true iif method is supported. 140 */ 141 static bool armoury_has_devstate(u32 dev_id) 142 { 143 u32 retval; 144 int status; 145 146 status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval); 147 pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval); 148 149 return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); 150 } 151 152 /** 153 * armoury_get_devstate() - Get the WMI function state. 154 * @attr: NULL or the kobj_attribute associated to called WMI function. 155 * @dev_id: The WMI method ID to call. 156 * @retval: 157 * * non-NULL pointer to where to store the value returned from WMI 158 * * with the function presence bit cleared. 159 * 160 * Intended usage is from sysfs attribute checking associated WMI function. 161 * 162 * Returns: 163 * * %-ENODEV - method ID is unsupported. 164 * * %0 - successful and retval is filled. 165 * * %other - error from WMI call. 166 */ 167 static int armoury_get_devstate(struct kobj_attribute *attr, u32 *retval, u32 dev_id) 168 { 169 int err; 170 171 err = asus_wmi_get_devstate_dsts(dev_id, retval); 172 if (err) { 173 if (attr) 174 pr_err("Failed to get %s: %d\n", attr->attr.name, err); 175 else 176 pr_err("Failed to get devstate for 0x%x: %d\n", dev_id, err); 177 178 return err; 179 } 180 181 /* 182 * asus_wmi_get_devstate_dsts will populate retval with WMI return, but 183 * the true value is expressed when ASUS_WMI_DSTS_PRESENCE_BIT is clear. 184 */ 185 *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT; 186 187 return 0; 188 } 189 190 /** 191 * armoury_set_devstate() - Set the WMI function state. 192 * @attr: The kobj_attribute associated to called WMI function. 193 * @dev_id: The WMI method ID to call. 194 * @value: The new value to be set. 195 * @retval: Where to store the value returned from WMI or NULL. 196 * 197 * Intended usage is from sysfs attribute setting associated WMI function. 198 * Before calling the presence of the function should be checked. 199 * 200 * Every WMI write MUST go through this function to enforce safety checks. 201 * 202 * Results !1 is usually considered a fail by ASUS, but some WMI methods 203 * (like eGPU or CPU cores) do use > 1 to return a status code or similar: 204 * in these cases caller is interested in the actual return value 205 * and should perform relevant checks. 206 * 207 * Returns: 208 * * %-EINVAL - attempt to set a dangerous or unsupported value. 209 * * %-EIO - WMI function returned an error. 210 * * %0 - successful and retval is filled. 211 * * %other - error from WMI call. 212 */ 213 static int armoury_set_devstate(struct kobj_attribute *attr, 214 u32 value, u32 *retval, u32 dev_id) 215 { 216 u32 result; 217 int err; 218 219 /* 220 * Prevent developers from bricking devices or issuing dangerous 221 * commands that can be difficult or impossible to recover from. 222 */ 223 switch (dev_id) { 224 case ASUS_WMI_DEVID_APU_MEM: 225 /* 226 * A hard reset might suffice to save the device, 227 * but there is no value in sending these commands. 228 */ 229 if (value == 0x100 || value == 0x101) { 230 pr_err("Refusing to set APU memory to unsafe value: 0x%x\n", value); 231 return -EINVAL; 232 } 233 break; 234 default: 235 /* No problems are known for this dev_id */ 236 break; 237 } 238 239 err = asus_wmi_set_devstate(dev_id, value, retval ? retval : &result); 240 if (err) { 241 if (attr) 242 pr_err("Failed to set %s: %d\n", attr->attr.name, err); 243 else 244 pr_err("Failed to set devstate for 0x%x: %d\n", dev_id, err); 245 246 return err; 247 } 248 249 /* 250 * If retval == NULL caller is uninterested in return value: 251 * perform the most common result check here. 252 */ 253 if ((retval == NULL) && (result == 0)) { 254 pr_err("Failed to set %s: (result): 0x%x\n", attr->attr.name, result); 255 return -EIO; 256 } 257 258 return 0; 259 } 260 261 static int armoury_attr_enum_list(char *buf, size_t enum_values) 262 { 263 size_t i; 264 int len = 0; 265 266 for (i = 0; i < enum_values; i++) { 267 if (i == 0) 268 len += sysfs_emit_at(buf, len, "%zu", i); 269 else 270 len += sysfs_emit_at(buf, len, ";%zu", i); 271 } 272 len += sysfs_emit_at(buf, len, "\n"); 273 274 return len; 275 } 276 277 ssize_t armoury_attr_uint_store(struct kobject *kobj, struct kobj_attribute *attr, 278 const char *buf, size_t count, u32 min, u32 max, 279 u32 *store_value, u32 wmi_dev) 280 { 281 u32 value; 282 int err; 283 284 err = kstrtou32(buf, 10, &value); 285 if (err) 286 return err; 287 288 if (value < min || value > max) 289 return -EINVAL; 290 291 err = armoury_set_devstate(attr, value, NULL, wmi_dev); 292 if (err) 293 return err; 294 295 if (store_value != NULL) 296 *store_value = value; 297 sysfs_notify(kobj, NULL, attr->attr.name); 298 299 if (asus_bios_requires_reboot(attr)) 300 asus_set_reboot_and_signal_event(); 301 302 return count; 303 } 304 305 ssize_t armoury_attr_uint_show(struct kobject *kobj, struct kobj_attribute *attr, 306 char *buf, u32 wmi_dev) 307 { 308 u32 result; 309 int err; 310 311 err = armoury_get_devstate(attr, &result, wmi_dev); 312 if (err) 313 return err; 314 315 return sysfs_emit(buf, "%u\n", result); 316 } 317 318 static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr, 319 char *buf) 320 { 321 return sysfs_emit(buf, "enumeration\n"); 322 } 323 324 static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr, 325 char *buf) 326 { 327 return sysfs_emit(buf, "integer\n"); 328 } 329 330 /* Mini-LED mode **************************************************************/ 331 332 /* Values map for mini-led modes on 2023 and earlier models. */ 333 static u32 mini_led_mode1_map[] = { 334 [0] = ASUS_MINI_LED_OFF, 335 [1] = ASUS_MINI_LED_ON, 336 }; 337 338 /* Values map for mini-led modes on 2024 and later models. */ 339 static u32 mini_led_mode2_map[] = { 340 [0] = ASUS_MINI_LED_2024_OFF, 341 [1] = ASUS_MINI_LED_2024_WEAK, 342 [2] = ASUS_MINI_LED_2024_STRONG, 343 }; 344 345 static ssize_t mini_led_mode_current_value_show(struct kobject *kobj, 346 struct kobj_attribute *attr, char *buf) 347 { 348 u32 *mini_led_mode_map; 349 size_t mini_led_mode_map_size; 350 u32 i, mode; 351 int err; 352 353 switch (asus_armoury.mini_led_dev_id) { 354 case ASUS_WMI_DEVID_MINI_LED_MODE: 355 mini_led_mode_map = mini_led_mode1_map; 356 mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); 357 break; 358 359 case ASUS_WMI_DEVID_MINI_LED_MODE2: 360 mini_led_mode_map = mini_led_mode2_map; 361 mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); 362 break; 363 364 default: 365 pr_err("Unrecognized mini-LED device: %u\n", asus_armoury.mini_led_dev_id); 366 return -ENODEV; 367 } 368 369 err = armoury_get_devstate(attr, &mode, asus_armoury.mini_led_dev_id); 370 if (err) 371 return err; 372 373 mode = FIELD_GET(ASUS_MINI_LED_MODE_MASK, 0); 374 375 for (i = 0; i < mini_led_mode_map_size; i++) 376 if (mode == mini_led_mode_map[i]) 377 return sysfs_emit(buf, "%u\n", i); 378 379 pr_warn("Unrecognized mini-LED mode: %u", mode); 380 return -EINVAL; 381 } 382 383 static ssize_t mini_led_mode_current_value_store(struct kobject *kobj, 384 struct kobj_attribute *attr, 385 const char *buf, size_t count) 386 { 387 u32 *mini_led_mode_map; 388 size_t mini_led_mode_map_size; 389 u32 mode; 390 int err; 391 392 err = kstrtou32(buf, 10, &mode); 393 if (err) 394 return err; 395 396 switch (asus_armoury.mini_led_dev_id) { 397 case ASUS_WMI_DEVID_MINI_LED_MODE: 398 mini_led_mode_map = mini_led_mode1_map; 399 mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode1_map); 400 break; 401 402 case ASUS_WMI_DEVID_MINI_LED_MODE2: 403 mini_led_mode_map = mini_led_mode2_map; 404 mini_led_mode_map_size = ARRAY_SIZE(mini_led_mode2_map); 405 break; 406 407 default: 408 pr_err("Unrecognized mini-LED devid: %u\n", asus_armoury.mini_led_dev_id); 409 return -EINVAL; 410 } 411 412 if (mode >= mini_led_mode_map_size) { 413 pr_warn("mini-LED mode unrecognized device: %u\n", mode); 414 return -ENODEV; 415 } 416 417 return armoury_attr_uint_store(kobj, attr, buf, count, 418 0, mini_led_mode_map[mode], 419 NULL, asus_armoury.mini_led_dev_id); 420 } 421 422 static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj, 423 struct kobj_attribute *attr, char *buf) 424 { 425 switch (asus_armoury.mini_led_dev_id) { 426 case ASUS_WMI_DEVID_MINI_LED_MODE: 427 return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode1_map)); 428 case ASUS_WMI_DEVID_MINI_LED_MODE2: 429 return armoury_attr_enum_list(buf, ARRAY_SIZE(mini_led_mode2_map)); 430 default: 431 return -ENODEV; 432 } 433 } 434 ASUS_ATTR_GROUP_ENUM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode"); 435 436 static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj, 437 struct kobj_attribute *attr, 438 const char *buf, size_t count) 439 { 440 int result, err; 441 bool optimus; 442 443 err = kstrtobool(buf, &optimus); 444 if (err) 445 return err; 446 447 if (armoury_has_devstate(ASUS_WMI_DEVID_DGPU)) { 448 err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_DGPU); 449 if (err) 450 return err; 451 if (result && !optimus) { 452 pr_warn("Cannot switch MUX to dGPU mode when dGPU is disabled: %02X\n", 453 result); 454 return -ENODEV; 455 } 456 } 457 458 if (armoury_has_devstate(ASUS_WMI_DEVID_EGPU)) { 459 err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU); 460 if (err) 461 return err; 462 if (result && !optimus) { 463 pr_warn("Cannot switch MUX to dGPU mode when eGPU is enabled\n"); 464 return -EBUSY; 465 } 466 } 467 468 err = armoury_set_devstate(attr, optimus ? 1 : 0, NULL, asus_armoury.gpu_mux_dev_id); 469 if (err) 470 return err; 471 472 sysfs_notify(kobj, NULL, attr->attr.name); 473 asus_set_reboot_and_signal_event(); 474 475 return count; 476 } 477 ASUS_WMI_SHOW_INT(gpu_mux_mode_current_value, asus_armoury.gpu_mux_dev_id); 478 ASUS_ATTR_GROUP_BOOL(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode"); 479 480 static ssize_t dgpu_disable_current_value_store(struct kobject *kobj, 481 struct kobj_attribute *attr, const char *buf, 482 size_t count) 483 { 484 int result, err; 485 bool disable; 486 487 err = kstrtobool(buf, &disable); 488 if (err) 489 return err; 490 491 if (asus_armoury.gpu_mux_dev_id) { 492 err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); 493 if (err) 494 return err; 495 if (!result && disable) { 496 pr_warn("Cannot disable dGPU when the MUX is in dGPU mode\n"); 497 return -EBUSY; 498 } 499 } 500 501 scoped_guard(mutex, &asus_armoury.egpu_mutex) { 502 err = armoury_set_devstate(attr, disable ? 1 : 0, NULL, ASUS_WMI_DEVID_DGPU); 503 if (err) 504 return err; 505 } 506 507 sysfs_notify(kobj, NULL, attr->attr.name); 508 509 return count; 510 } 511 ASUS_WMI_SHOW_INT(dgpu_disable_current_value, ASUS_WMI_DEVID_DGPU); 512 ASUS_ATTR_GROUP_BOOL(dgpu_disable, "dgpu_disable", "Disable the dGPU"); 513 514 /* Values map for eGPU activation requests. */ 515 static u32 egpu_status_map[] = { 516 [0] = 0x00000000U, 517 [1] = 0x00000001U, 518 [2] = 0x00000101U, 519 [3] = 0x00000201U, 520 }; 521 522 /* 523 * armoury_pci_rescan() - Performs a PCI rescan 524 * 525 * Bring up any GPU that has been hotplugged in the system. 526 */ 527 static void armoury_pci_rescan(void) 528 { 529 struct pci_bus *b = NULL; 530 531 pci_lock_rescan_remove(); 532 while ((b = pci_find_next_bus(b)) != NULL) 533 pci_rescan_bus(b); 534 pci_unlock_rescan_remove(); 535 } 536 537 /* 538 * The ACPI call to enable the eGPU might also disable the internal dGPU, 539 * but this is not always the case and on certain models enabling the eGPU 540 * when the dGPU is either still active or has been disabled without rebooting 541 * will make both GPUs malfunction and the kernel will detect many 542 * PCI AER unrecoverable errors. 543 */ 544 static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, 545 const char *buf, size_t count) 546 { 547 int err; 548 u32 requested, enable, result; 549 550 err = kstrtou32(buf, 10, &requested); 551 if (err) 552 return err; 553 554 if (requested >= ARRAY_SIZE(egpu_status_map)) 555 return -EINVAL; 556 enable = egpu_status_map[requested]; 557 558 scoped_guard(mutex, &asus_armoury.egpu_mutex) { 559 /* Ensure the eGPU is connected before attempting to activate it. */ 560 if (enable) { 561 err = armoury_get_devstate(NULL, &result, ASUS_WMI_DEVID_EGPU_CONNECTED); 562 if (err) { 563 pr_warn("Failed to get eGPU connection status: %d\n", err); 564 return err; 565 } 566 if (!result) { 567 pr_warn("Cannot activate eGPU while undetected\n"); 568 return -ENOENT; 569 } 570 } 571 572 if (asus_armoury.gpu_mux_dev_id) { 573 err = armoury_get_devstate(NULL, &result, asus_armoury.gpu_mux_dev_id); 574 if (err) 575 return err; 576 577 if (!result && enable) { 578 pr_warn("Cannot enable eGPU when the MUX is in dGPU mode\n"); 579 return -ENODEV; 580 } 581 } 582 583 err = armoury_set_devstate(attr, enable, &result, ASUS_WMI_DEVID_EGPU); 584 if (err) { 585 pr_err("Failed to set %s: %d\n", attr->attr.name, err); 586 return err; 587 } 588 589 /* 590 * ACPI returns value 0x01 on success and 0x02 on a partial activation: 591 * performing a pci rescan will bring up the device in pci-e 3.0 speed, 592 * after a reboot the device will work at full speed. 593 */ 594 switch (result) { 595 case 0x01: 596 /* 597 * When a GPU is in use it does not get disconnected even if 598 * the ACPI call returns a success. 599 */ 600 if (!enable) { 601 err = armoury_get_devstate(attr, &result, ASUS_WMI_DEVID_EGPU); 602 if (err) { 603 pr_warn("Failed to ensure eGPU is deactivated: %d\n", err); 604 return err; 605 } 606 607 if (result != 0) 608 return -EBUSY; 609 } 610 611 pr_debug("Success changing the eGPU status\n"); 612 break; 613 case 0x02: 614 pr_info("Success changing the eGPU status, a reboot is strongly advised\n"); 615 asus_set_reboot_and_signal_event(); 616 break; 617 default: 618 pr_err("Failed to change the eGPU status: wmi result is 0x%x\n", result); 619 return -EIO; 620 } 621 } 622 623 /* 624 * Perform a PCI rescan: on every tested model this is necessary 625 * to make the eGPU visible on the bus without rebooting. 626 */ 627 armoury_pci_rescan(); 628 629 sysfs_notify(kobj, NULL, attr->attr.name); 630 631 return count; 632 } 633 634 static ssize_t egpu_enable_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, 635 char *buf) 636 { 637 int i, err; 638 u32 status; 639 640 scoped_guard(mutex, &asus_armoury.egpu_mutex) { 641 err = armoury_get_devstate(attr, &status, ASUS_WMI_DEVID_EGPU); 642 if (err) 643 return err; 644 } 645 646 for (i = 0; i < ARRAY_SIZE(egpu_status_map); i++) { 647 if (egpu_status_map[i] == status) 648 return sysfs_emit(buf, "%u\n", i); 649 } 650 651 return -EIO; 652 } 653 654 static ssize_t egpu_enable_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, 655 char *buf) 656 { 657 return armoury_attr_enum_list(buf, ARRAY_SIZE(egpu_status_map)); 658 } 659 ASUS_ATTR_GROUP_ENUM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)"); 660 661 /* Device memory available to APU */ 662 663 /* 664 * Values map for APU reserved memory (index + 1 number of GB). 665 * Some looks out of order, but are actually correct. 666 */ 667 static u32 apu_mem_map[] = { 668 [0] = 0x000, /* called "AUTO" on the BIOS, is the minimum available */ 669 [1] = 0x102, 670 [2] = 0x103, 671 [3] = 0x104, 672 [4] = 0x105, 673 [5] = 0x107, 674 [6] = 0x108, 675 [7] = 0x109, 676 [8] = 0x106, 677 }; 678 679 static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr, 680 char *buf) 681 { 682 int err; 683 u32 mem; 684 685 err = armoury_get_devstate(attr, &mem, ASUS_WMI_DEVID_APU_MEM); 686 if (err) 687 return err; 688 689 /* After 0x000 is set, a read will return 0x100 */ 690 if (mem == 0x100) 691 return sysfs_emit(buf, "0\n"); 692 693 for (unsigned int i = 0; i < ARRAY_SIZE(apu_mem_map); i++) { 694 if (apu_mem_map[i] == mem) 695 return sysfs_emit(buf, "%u\n", i); 696 } 697 698 pr_warn("Unrecognised value for APU mem 0x%08x\n", mem); 699 return -EIO; 700 } 701 702 static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr, 703 const char *buf, size_t count) 704 { 705 int result, err; 706 u32 requested, mem; 707 708 result = kstrtou32(buf, 10, &requested); 709 if (result) 710 return result; 711 712 if (requested >= ARRAY_SIZE(apu_mem_map)) 713 return -EINVAL; 714 mem = apu_mem_map[requested]; 715 716 err = armoury_set_devstate(attr, mem, NULL, ASUS_WMI_DEVID_APU_MEM); 717 if (err) { 718 pr_warn("Failed to set apu_mem 0x%x: %d\n", mem, err); 719 return err; 720 } 721 722 pr_info("APU memory changed to %uGB, reboot required\n", requested + 1); 723 sysfs_notify(kobj, NULL, attr->attr.name); 724 725 asus_set_reboot_and_signal_event(); 726 727 return count; 728 } 729 730 static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr, 731 char *buf) 732 { 733 return armoury_attr_enum_list(buf, ARRAY_SIZE(apu_mem_map)); 734 } 735 ASUS_ATTR_GROUP_ENUM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use"); 736 737 /* Define helper to access the current power mode tunable values */ 738 static inline struct rog_tunables *get_current_tunables(void) 739 { 740 if (power_supply_is_system_supplied()) 741 return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; 742 743 return asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]; 744 } 745 746 /* Simple attribute creation */ 747 ASUS_ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2\n", 748 "Show the current mode of charging"); 749 ASUS_ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND, 750 "Set the boot POST sound"); 751 ASUS_ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE, 752 "Set MCU powersaving mode"); 753 ASUS_ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD, 754 "Set the panel refresh overdrive"); 755 ASUS_ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD, 756 "Set the panel HD mode to UHD<0> or FHD<1>"); 757 ASUS_ATTR_GROUP_BOOL_RW(screen_auto_brightness, "screen_auto_brightness", 758 ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS, 759 "Set the panel brightness to Off<0> or On<1>"); 760 ASUS_ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED, 761 "Show the eGPU connection status"); 762 ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, ATTR_PPT_PL1_SPL, ASUS_WMI_DEVID_PPT_PL1_SPL, 763 "Set the CPU slow package limit"); 764 ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, ATTR_PPT_PL2_SPPT, ASUS_WMI_DEVID_PPT_PL2_SPPT, 765 "Set the CPU fast package limit"); 766 ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, ATTR_PPT_PL3_FPPT, ASUS_WMI_DEVID_PPT_PL3_FPPT, 767 "Set the CPU fastest package limit"); 768 ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, ATTR_PPT_APU_SPPT, ASUS_WMI_DEVID_PPT_APU_SPPT, 769 "Set the APU package limit"); 770 ASUS_ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, ATTR_PPT_PLATFORM_SPPT, ASUS_WMI_DEVID_PPT_PLAT_SPPT, 771 "Set the platform package limit"); 772 ASUS_ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, ATTR_NV_DYNAMIC_BOOST, ASUS_WMI_DEVID_NV_DYN_BOOST, 773 "Set the Nvidia dynamic boost limit"); 774 ASUS_ATTR_GROUP_ROG_TUNABLE(nv_temp_target, ATTR_NV_TEMP_TARGET, ASUS_WMI_DEVID_NV_THERM_TARGET, 775 "Set the Nvidia max thermal limit"); 776 ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, 777 "Set the additional TGP on top of the base TGP"); 778 ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, 779 "Read the base TGP value"); 780 781 /* If an attribute does not require any special case handling add it here */ 782 static const struct asus_attr_group armoury_attr_groups[] = { 783 { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, 784 { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU }, 785 { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU }, 786 { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM }, 787 788 { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, 789 { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, 790 { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_PL3_FPPT }, 791 { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, 792 { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, 793 { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, 794 { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, 795 { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, 796 { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, 797 798 { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, 799 { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, 800 { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, 801 { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, 802 { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, 803 { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS }, 804 }; 805 806 /** 807 * is_power_tunable_attr - Determines if an attribute is a power-related tunable 808 * @name: The name of the attribute to check 809 * 810 * This function checks if the given attribute name is related to power tuning. 811 * 812 * Return: true if the attribute is a power-related tunable, false otherwise 813 */ 814 static bool is_power_tunable_attr(const char *name) 815 { 816 static const char * const power_tunable_attrs[] = { 817 ATTR_PPT_PL1_SPL, ATTR_PPT_PL2_SPPT, 818 ATTR_PPT_PL3_FPPT, ATTR_PPT_APU_SPPT, 819 ATTR_PPT_PLATFORM_SPPT, ATTR_NV_DYNAMIC_BOOST, 820 ATTR_NV_TEMP_TARGET, ATTR_NV_BASE_TGP, 821 ATTR_NV_TGP 822 }; 823 824 for (unsigned int i = 0; i < ARRAY_SIZE(power_tunable_attrs); i++) { 825 if (!strcmp(name, power_tunable_attrs[i])) 826 return true; 827 } 828 829 return false; 830 } 831 832 /** 833 * has_valid_limit - Checks if a power-related attribute has a valid limit value 834 * @name: The name of the attribute to check 835 * @limits: Pointer to the power_limits structure containing limit values 836 * 837 * This function checks if a power-related attribute has a valid limit value. 838 * It returns false if limits is NULL or if the corresponding limit value is zero. 839 * 840 * Return: true if the attribute has a valid limit value, false otherwise 841 */ 842 static bool has_valid_limit(const char *name, const struct power_limits *limits) 843 { 844 u32 limit_value = 0; 845 846 if (!limits) 847 return false; 848 849 if (!strcmp(name, ATTR_PPT_PL1_SPL)) 850 limit_value = limits->ppt_pl1_spl_max; 851 else if (!strcmp(name, ATTR_PPT_PL2_SPPT)) 852 limit_value = limits->ppt_pl2_sppt_max; 853 else if (!strcmp(name, ATTR_PPT_PL3_FPPT)) 854 limit_value = limits->ppt_pl3_fppt_max; 855 else if (!strcmp(name, ATTR_PPT_APU_SPPT)) 856 limit_value = limits->ppt_apu_sppt_max; 857 else if (!strcmp(name, ATTR_PPT_PLATFORM_SPPT)) 858 limit_value = limits->ppt_platform_sppt_max; 859 else if (!strcmp(name, ATTR_NV_DYNAMIC_BOOST)) 860 limit_value = limits->nv_dynamic_boost_max; 861 else if (!strcmp(name, ATTR_NV_TEMP_TARGET)) 862 limit_value = limits->nv_temp_target_max; 863 else if (!strcmp(name, ATTR_NV_BASE_TGP) || 864 !strcmp(name, ATTR_NV_TGP)) 865 limit_value = limits->nv_tgp_max; 866 867 return limit_value > 0; 868 } 869 870 static int asus_fw_attr_add(void) 871 { 872 const struct rog_tunables *const ac_rog_tunables = 873 asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]; 874 const struct power_limits *limits; 875 bool should_create; 876 const char *name; 877 int err, i; 878 879 asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), 880 NULL, "%s", DRIVER_NAME); 881 if (IS_ERR(asus_armoury.fw_attr_dev)) { 882 err = PTR_ERR(asus_armoury.fw_attr_dev); 883 goto fail_class_get; 884 } 885 886 asus_armoury.fw_attr_kset = kset_create_and_add("attributes", NULL, 887 &asus_armoury.fw_attr_dev->kobj); 888 if (!asus_armoury.fw_attr_kset) { 889 err = -ENOMEM; 890 goto err_destroy_classdev; 891 } 892 893 err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); 894 if (err) { 895 pr_err("Failed to create sysfs level attributes\n"); 896 goto err_destroy_kset; 897 } 898 899 asus_armoury.mini_led_dev_id = 0; 900 if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE)) 901 asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; 902 else if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE2)) 903 asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2; 904 905 if (asus_armoury.mini_led_dev_id) { 906 err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, 907 &mini_led_mode_attr_group); 908 if (err) { 909 pr_err("Failed to create sysfs-group for mini_led\n"); 910 goto err_remove_file; 911 } 912 } 913 914 asus_armoury.gpu_mux_dev_id = 0; 915 if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX)) 916 asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX; 917 else if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MUX_VIVO)) 918 asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO; 919 920 if (asus_armoury.gpu_mux_dev_id) { 921 err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, 922 &gpu_mux_mode_attr_group); 923 if (err) { 924 pr_err("Failed to create sysfs-group for gpu_mux\n"); 925 goto err_remove_mini_led_group; 926 } 927 } 928 929 for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { 930 if (!armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) 931 continue; 932 933 /* Always create by default, unless PPT is not present */ 934 should_create = true; 935 name = armoury_attr_groups[i].attr_group->name; 936 937 /* Check if this is a power-related tunable requiring limits */ 938 if (ac_rog_tunables && ac_rog_tunables->power_limits && 939 is_power_tunable_attr(name)) { 940 limits = ac_rog_tunables->power_limits; 941 /* Check only AC: if not present then DC won't be either */ 942 should_create = has_valid_limit(name, limits); 943 if (!should_create) 944 pr_debug("Missing max value for tunable %s\n", name); 945 } 946 947 if (should_create) { 948 err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, 949 armoury_attr_groups[i].attr_group); 950 if (err) { 951 pr_err("Failed to create sysfs-group for %s\n", 952 armoury_attr_groups[i].attr_group->name); 953 goto err_remove_groups; 954 } 955 } 956 } 957 958 return 0; 959 960 err_remove_groups: 961 while (i--) { 962 if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) 963 sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, 964 armoury_attr_groups[i].attr_group); 965 } 966 if (asus_armoury.gpu_mux_dev_id) 967 sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); 968 err_remove_mini_led_group: 969 if (asus_armoury.mini_led_dev_id) 970 sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); 971 err_remove_file: 972 sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); 973 err_destroy_kset: 974 kset_unregister(asus_armoury.fw_attr_kset); 975 err_destroy_classdev: 976 fail_class_get: 977 device_destroy(&firmware_attributes_class, MKDEV(0, 0)); 978 return err; 979 } 980 981 /* Init / exit ****************************************************************/ 982 983 /* Set up the min/max and defaults for ROG tunables */ 984 static void init_rog_tunables(void) 985 { 986 const struct power_limits *ac_limits, *dc_limits; 987 struct rog_tunables *ac_rog_tunables = NULL, *dc_rog_tunables = NULL; 988 const struct power_data *power_data; 989 const struct dmi_system_id *dmi_id; 990 991 /* Match the system against the power_limits table */ 992 dmi_id = dmi_first_match(power_limits); 993 if (!dmi_id) { 994 pr_warn("No matching power limits found for this system\n"); 995 return; 996 } 997 998 /* Get the power data for this system */ 999 power_data = dmi_id->driver_data; 1000 if (!power_data) { 1001 pr_info("No power data available for this system\n"); 1002 return; 1003 } 1004 1005 /* Initialize AC power tunables */ 1006 ac_limits = power_data->ac_data; 1007 if (ac_limits) { 1008 ac_rog_tunables = kzalloc(sizeof(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]), 1009 GFP_KERNEL); 1010 if (!ac_rog_tunables) 1011 goto err_nomem; 1012 1013 asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC] = ac_rog_tunables; 1014 ac_rog_tunables->power_limits = ac_limits; 1015 1016 /* Set initial AC values */ 1017 ac_rog_tunables->ppt_pl1_spl = 1018 ac_limits->ppt_pl1_spl_def ? 1019 ac_limits->ppt_pl1_spl_def : 1020 ac_limits->ppt_pl1_spl_max; 1021 1022 ac_rog_tunables->ppt_pl2_sppt = 1023 ac_limits->ppt_pl2_sppt_def ? 1024 ac_limits->ppt_pl2_sppt_def : 1025 ac_limits->ppt_pl2_sppt_max; 1026 1027 ac_rog_tunables->ppt_pl3_fppt = 1028 ac_limits->ppt_pl3_fppt_def ? 1029 ac_limits->ppt_pl3_fppt_def : 1030 ac_limits->ppt_pl3_fppt_max; 1031 1032 ac_rog_tunables->ppt_apu_sppt = 1033 ac_limits->ppt_apu_sppt_def ? 1034 ac_limits->ppt_apu_sppt_def : 1035 ac_limits->ppt_apu_sppt_max; 1036 1037 ac_rog_tunables->ppt_platform_sppt = 1038 ac_limits->ppt_platform_sppt_def ? 1039 ac_limits->ppt_platform_sppt_def : 1040 ac_limits->ppt_platform_sppt_max; 1041 1042 ac_rog_tunables->nv_dynamic_boost = 1043 ac_limits->nv_dynamic_boost_max; 1044 ac_rog_tunables->nv_temp_target = 1045 ac_limits->nv_temp_target_max; 1046 ac_rog_tunables->nv_tgp = ac_limits->nv_tgp_max; 1047 1048 pr_debug("AC power limits initialized for %s\n", dmi_id->matches[0].substr); 1049 } else { 1050 pr_debug("No AC PPT limits defined\n"); 1051 } 1052 1053 /* Initialize DC power tunables */ 1054 dc_limits = power_data->dc_data; 1055 if (dc_limits) { 1056 dc_rog_tunables = kzalloc(sizeof(*asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]), 1057 GFP_KERNEL); 1058 if (!dc_rog_tunables) { 1059 kfree(ac_rog_tunables); 1060 goto err_nomem; 1061 } 1062 1063 asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC] = dc_rog_tunables; 1064 dc_rog_tunables->power_limits = dc_limits; 1065 1066 /* Set initial DC values */ 1067 dc_rog_tunables->ppt_pl1_spl = 1068 dc_limits->ppt_pl1_spl_def ? 1069 dc_limits->ppt_pl1_spl_def : 1070 dc_limits->ppt_pl1_spl_max; 1071 1072 dc_rog_tunables->ppt_pl2_sppt = 1073 dc_limits->ppt_pl2_sppt_def ? 1074 dc_limits->ppt_pl2_sppt_def : 1075 dc_limits->ppt_pl2_sppt_max; 1076 1077 dc_rog_tunables->ppt_pl3_fppt = 1078 dc_limits->ppt_pl3_fppt_def ? 1079 dc_limits->ppt_pl3_fppt_def : 1080 dc_limits->ppt_pl3_fppt_max; 1081 1082 dc_rog_tunables->ppt_apu_sppt = 1083 dc_limits->ppt_apu_sppt_def ? 1084 dc_limits->ppt_apu_sppt_def : 1085 dc_limits->ppt_apu_sppt_max; 1086 1087 dc_rog_tunables->ppt_platform_sppt = 1088 dc_limits->ppt_platform_sppt_def ? 1089 dc_limits->ppt_platform_sppt_def : 1090 dc_limits->ppt_platform_sppt_max; 1091 1092 dc_rog_tunables->nv_dynamic_boost = 1093 dc_limits->nv_dynamic_boost_max; 1094 dc_rog_tunables->nv_temp_target = 1095 dc_limits->nv_temp_target_max; 1096 dc_rog_tunables->nv_tgp = dc_limits->nv_tgp_max; 1097 1098 pr_debug("DC power limits initialized for %s\n", dmi_id->matches[0].substr); 1099 } else { 1100 pr_debug("No DC PPT limits defined\n"); 1101 } 1102 1103 return; 1104 1105 err_nomem: 1106 pr_err("Failed to allocate memory for tunables\n"); 1107 } 1108 1109 static int __init asus_fw_init(void) 1110 { 1111 char *wmi_uid; 1112 1113 wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID); 1114 if (!wmi_uid) 1115 return -ENODEV; 1116 1117 /* 1118 * if equal to "ASUSWMI" then it's DCTS that can't be used for this 1119 * driver, DSTS is required. 1120 */ 1121 if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) 1122 return -ENODEV; 1123 1124 init_rog_tunables(); 1125 1126 /* Must always be last step to ensure data is available */ 1127 return asus_fw_attr_add(); 1128 } 1129 1130 static void __exit asus_fw_exit(void) 1131 { 1132 int i; 1133 1134 for (i = ARRAY_SIZE(armoury_attr_groups) - 1; i >= 0; i--) { 1135 if (armoury_has_devstate(armoury_attr_groups[i].wmi_devid)) 1136 sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, 1137 armoury_attr_groups[i].attr_group); 1138 } 1139 1140 if (asus_armoury.gpu_mux_dev_id) 1141 sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &gpu_mux_mode_attr_group); 1142 1143 if (asus_armoury.mini_led_dev_id) 1144 sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr_group); 1145 1146 sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); 1147 kset_unregister(asus_armoury.fw_attr_kset); 1148 device_destroy(&firmware_attributes_class, MKDEV(0, 0)); 1149 1150 kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_AC]); 1151 kfree(asus_armoury.rog_tunables[ASUS_ROG_TUNABLE_DC]); 1152 } 1153 1154 module_init(asus_fw_init); 1155 module_exit(asus_fw_exit); 1156 1157 MODULE_IMPORT_NS("ASUS_WMI"); 1158 MODULE_AUTHOR("Luke Jones <luke@ljones.dev>"); 1159 MODULE_DESCRIPTION("ASUS BIOS Configuration Driver"); 1160 MODULE_LICENSE("GPL"); 1161 MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID); 1162