1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Architecture-specific ACPI-based support for suspend-to-idle. 4 * 5 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 6 * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 7 * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> 8 * 9 * On platforms supporting the Low Power S0 Idle interface there is an ACPI 10 * device object with the PNP0D80 compatible device ID (System Power Management 11 * Controller) and a specific _DSM method under it. That method, if present, 12 * can be used to indicate to the platform that the OS is transitioning into a 13 * low-power state in which certain types of activity are not desirable or that 14 * it is leaving such a state, which allows the platform to adjust its operation 15 * mode accordingly. 16 */ 17 18 #include <linux/acpi.h> 19 #include <linux/device.h> 20 #include <linux/suspend.h> 21 22 #include "../sleep.h" 23 24 #ifdef CONFIG_SUSPEND 25 26 static bool sleep_no_lps0 __read_mostly; 27 module_param(sleep_no_lps0, bool, 0644); 28 MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface"); 29 30 static const struct acpi_device_id lps0_device_ids[] = { 31 {"PNP0D80", }, 32 {"", }, 33 }; 34 35 #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" 36 37 #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1 38 #define ACPI_LPS0_SCREEN_OFF 3 39 #define ACPI_LPS0_SCREEN_ON 4 40 #define ACPI_LPS0_ENTRY 5 41 #define ACPI_LPS0_EXIT 6 42 43 /* AMD */ 44 #define ACPI_LPS0_DSM_UUID_AMD "e3f32452-febc-43ce-9039-932122d37721" 45 #define ACPI_LPS0_SCREEN_OFF_AMD 4 46 #define ACPI_LPS0_SCREEN_ON_AMD 5 47 48 static acpi_handle lps0_device_handle; 49 static guid_t lps0_dsm_guid; 50 static char lps0_dsm_func_mask; 51 52 /* Device constraint entry structure */ 53 struct lpi_device_info { 54 char *name; 55 int enabled; 56 union acpi_object *package; 57 }; 58 59 /* Constraint package structure */ 60 struct lpi_device_constraint { 61 int uid; 62 int min_dstate; 63 int function_states; 64 }; 65 66 struct lpi_constraints { 67 acpi_handle handle; 68 int min_dstate; 69 }; 70 71 /* AMD */ 72 /* Device constraint entry structure */ 73 struct lpi_device_info_amd { 74 int revision; 75 int count; 76 union acpi_object *package; 77 }; 78 79 /* Constraint package structure */ 80 struct lpi_device_constraint_amd { 81 char *name; 82 int enabled; 83 int function_states; 84 int min_dstate; 85 }; 86 87 static struct lpi_constraints *lpi_constraints_table; 88 static int lpi_constraints_table_size; 89 static int rev_id; 90 91 static void lpi_device_get_constraints_amd(void) 92 { 93 union acpi_object *out_obj; 94 int i, j, k; 95 96 out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, 97 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, 98 NULL, ACPI_TYPE_PACKAGE); 99 100 if (!out_obj) 101 return; 102 103 acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", 104 out_obj ? "successful" : "failed"); 105 106 for (i = 0; i < out_obj->package.count; i++) { 107 union acpi_object *package = &out_obj->package.elements[i]; 108 109 if (package->type == ACPI_TYPE_PACKAGE) { 110 lpi_constraints_table = kcalloc(package->package.count, 111 sizeof(*lpi_constraints_table), 112 GFP_KERNEL); 113 114 if (!lpi_constraints_table) 115 goto free_acpi_buffer; 116 117 acpi_handle_debug(lps0_device_handle, 118 "LPI: constraints list begin:\n"); 119 120 for (j = 0; j < package->package.count; ++j) { 121 union acpi_object *info_obj = &package->package.elements[j]; 122 struct lpi_device_constraint_amd dev_info = {}; 123 struct lpi_constraints *list; 124 acpi_status status; 125 126 for (k = 0; k < info_obj->package.count; ++k) { 127 union acpi_object *obj = &info_obj->package.elements[k]; 128 129 list = &lpi_constraints_table[lpi_constraints_table_size]; 130 list->min_dstate = -1; 131 132 switch (k) { 133 case 0: 134 dev_info.enabled = obj->integer.value; 135 break; 136 case 1: 137 dev_info.name = obj->string.pointer; 138 break; 139 case 2: 140 dev_info.function_states = obj->integer.value; 141 break; 142 case 3: 143 dev_info.min_dstate = obj->integer.value; 144 break; 145 } 146 147 if (!dev_info.enabled || !dev_info.name || 148 !dev_info.min_dstate) 149 continue; 150 151 status = acpi_get_handle(NULL, dev_info.name, 152 &list->handle); 153 if (ACPI_FAILURE(status)) 154 continue; 155 156 acpi_handle_debug(lps0_device_handle, 157 "Name:%s\n", dev_info.name); 158 159 list->min_dstate = dev_info.min_dstate; 160 161 if (list->min_dstate < 0) { 162 acpi_handle_debug(lps0_device_handle, 163 "Incomplete constraint defined\n"); 164 continue; 165 } 166 } 167 lpi_constraints_table_size++; 168 } 169 } 170 } 171 172 acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n"); 173 174 free_acpi_buffer: 175 ACPI_FREE(out_obj); 176 } 177 178 static void lpi_device_get_constraints(void) 179 { 180 union acpi_object *out_obj; 181 int i; 182 183 out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, 184 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, 185 NULL, ACPI_TYPE_PACKAGE); 186 187 acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", 188 out_obj ? "successful" : "failed"); 189 190 if (!out_obj) 191 return; 192 193 lpi_constraints_table = kcalloc(out_obj->package.count, 194 sizeof(*lpi_constraints_table), 195 GFP_KERNEL); 196 if (!lpi_constraints_table) 197 goto free_acpi_buffer; 198 199 acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n"); 200 201 for (i = 0; i < out_obj->package.count; i++) { 202 struct lpi_constraints *constraint; 203 acpi_status status; 204 union acpi_object *package = &out_obj->package.elements[i]; 205 struct lpi_device_info info = { }; 206 int package_count = 0, j; 207 208 if (!package) 209 continue; 210 211 for (j = 0; j < package->package.count; ++j) { 212 union acpi_object *element = 213 &(package->package.elements[j]); 214 215 switch (element->type) { 216 case ACPI_TYPE_INTEGER: 217 info.enabled = element->integer.value; 218 break; 219 case ACPI_TYPE_STRING: 220 info.name = element->string.pointer; 221 break; 222 case ACPI_TYPE_PACKAGE: 223 package_count = element->package.count; 224 info.package = element->package.elements; 225 break; 226 } 227 } 228 229 if (!info.enabled || !info.package || !info.name) 230 continue; 231 232 constraint = &lpi_constraints_table[lpi_constraints_table_size]; 233 234 status = acpi_get_handle(NULL, info.name, &constraint->handle); 235 if (ACPI_FAILURE(status)) 236 continue; 237 238 acpi_handle_debug(lps0_device_handle, 239 "index:%d Name:%s\n", i, info.name); 240 241 constraint->min_dstate = -1; 242 243 for (j = 0; j < package_count; ++j) { 244 union acpi_object *info_obj = &info.package[j]; 245 union acpi_object *cnstr_pkg; 246 union acpi_object *obj; 247 struct lpi_device_constraint dev_info; 248 249 switch (info_obj->type) { 250 case ACPI_TYPE_INTEGER: 251 /* version */ 252 break; 253 case ACPI_TYPE_PACKAGE: 254 if (info_obj->package.count < 2) 255 break; 256 257 cnstr_pkg = info_obj->package.elements; 258 obj = &cnstr_pkg[0]; 259 dev_info.uid = obj->integer.value; 260 obj = &cnstr_pkg[1]; 261 dev_info.min_dstate = obj->integer.value; 262 263 acpi_handle_debug(lps0_device_handle, 264 "uid:%d min_dstate:%s\n", 265 dev_info.uid, 266 acpi_power_state_string(dev_info.min_dstate)); 267 268 constraint->min_dstate = dev_info.min_dstate; 269 break; 270 } 271 } 272 273 if (constraint->min_dstate < 0) { 274 acpi_handle_debug(lps0_device_handle, 275 "Incomplete constraint defined\n"); 276 continue; 277 } 278 279 lpi_constraints_table_size++; 280 } 281 282 acpi_handle_debug(lps0_device_handle, "LPI: constraints list end\n"); 283 284 free_acpi_buffer: 285 ACPI_FREE(out_obj); 286 } 287 288 static void lpi_check_constraints(void) 289 { 290 int i; 291 292 for (i = 0; i < lpi_constraints_table_size; ++i) { 293 acpi_handle handle = lpi_constraints_table[i].handle; 294 struct acpi_device *adev; 295 296 if (!handle || acpi_bus_get_device(handle, &adev)) 297 continue; 298 299 acpi_handle_debug(handle, 300 "LPI: required min power state:%s current power state:%s\n", 301 acpi_power_state_string(lpi_constraints_table[i].min_dstate), 302 acpi_power_state_string(adev->power.state)); 303 304 if (!adev->flags.power_manageable) { 305 acpi_handle_info(handle, "LPI: Device not power manageable\n"); 306 lpi_constraints_table[i].handle = NULL; 307 continue; 308 } 309 310 if (adev->power.state < lpi_constraints_table[i].min_dstate) 311 acpi_handle_info(handle, 312 "LPI: Constraint not met; min power state:%s current power state:%s\n", 313 acpi_power_state_string(lpi_constraints_table[i].min_dstate), 314 acpi_power_state_string(adev->power.state)); 315 } 316 } 317 318 static void acpi_sleep_run_lps0_dsm(unsigned int func) 319 { 320 union acpi_object *out_obj; 321 322 if (!(lps0_dsm_func_mask & (1 << func))) 323 return; 324 325 out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, rev_id, func, NULL); 326 ACPI_FREE(out_obj); 327 328 acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n", 329 func, out_obj ? "successful" : "failed"); 330 } 331 332 static bool acpi_s2idle_vendor_amd(void) 333 { 334 return boot_cpu_data.x86_vendor == X86_VENDOR_AMD; 335 } 336 337 static int lps0_device_attach(struct acpi_device *adev, 338 const struct acpi_device_id *not_used) 339 { 340 union acpi_object *out_obj; 341 342 if (lps0_device_handle) 343 return 0; 344 345 if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) 346 return 0; 347 348 if (acpi_s2idle_vendor_amd()) { 349 guid_parse(ACPI_LPS0_DSM_UUID_AMD, &lps0_dsm_guid); 350 out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 0, 0, NULL); 351 rev_id = 0; 352 } else { 353 guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid); 354 out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL); 355 rev_id = 1; 356 } 357 358 /* Check if the _DSM is present and as expected. */ 359 if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER) { 360 acpi_handle_debug(adev->handle, 361 "_DSM function 0 evaluation failed\n"); 362 return 0; 363 } 364 365 lps0_dsm_func_mask = *(char *)out_obj->buffer.pointer; 366 367 ACPI_FREE(out_obj); 368 369 acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", 370 lps0_dsm_func_mask); 371 372 lps0_device_handle = adev->handle; 373 374 if (acpi_s2idle_vendor_amd()) 375 lpi_device_get_constraints_amd(); 376 else 377 lpi_device_get_constraints(); 378 379 /* 380 * Use suspend-to-idle by default if the default suspend mode was not 381 * set from the command line. 382 */ 383 if (mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) 384 mem_sleep_current = PM_SUSPEND_TO_IDLE; 385 386 /* 387 * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the 388 * EC GPE to be enabled while suspended for certain wakeup devices to 389 * work, so mark it as wakeup-capable. 390 */ 391 acpi_ec_mark_gpe_for_wake(); 392 393 return 0; 394 } 395 396 static struct acpi_scan_handler lps0_handler = { 397 .ids = lps0_device_ids, 398 .attach = lps0_device_attach, 399 }; 400 401 int acpi_s2idle_prepare_late(void) 402 { 403 if (!lps0_device_handle || sleep_no_lps0) 404 return 0; 405 406 if (pm_debug_messages_on) 407 lpi_check_constraints(); 408 409 if (acpi_s2idle_vendor_amd()) { 410 acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD); 411 } else { 412 acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); 413 acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); 414 } 415 416 return 0; 417 } 418 419 void acpi_s2idle_restore_early(void) 420 { 421 if (!lps0_device_handle || sleep_no_lps0) 422 return; 423 424 if (acpi_s2idle_vendor_amd()) { 425 acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD); 426 } else { 427 acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); 428 acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); 429 } 430 } 431 432 static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = { 433 .begin = acpi_s2idle_begin, 434 .prepare = acpi_s2idle_prepare, 435 .prepare_late = acpi_s2idle_prepare_late, 436 .wake = acpi_s2idle_wake, 437 .restore_early = acpi_s2idle_restore_early, 438 .restore = acpi_s2idle_restore, 439 .end = acpi_s2idle_end, 440 }; 441 442 void acpi_s2idle_setup(void) 443 { 444 acpi_scan_add_handler(&lps0_handler); 445 s2idle_set_ops(&acpi_s2idle_ops_lps0); 446 } 447 448 #endif /* CONFIG_SUSPEND */ 449