1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2010 Red Hat Inc. 4 * Author : Dave Airlie <airlied@redhat.com> 5 * 6 * ATPX support for both Intel/ATI 7 */ 8 #include <linux/vga_switcheroo.h> 9 #include <linux/slab.h> 10 #include <linux/acpi.h> 11 #include <linux/pci.h> 12 #include <linux/delay.h> 13 14 #include "amdgpu.h" 15 #include "amd_acpi.h" 16 17 #define AMDGPU_PX_QUIRK_FORCE_ATPX (1 << 0) 18 19 struct amdgpu_px_quirk { 20 u32 chip_vendor; 21 u32 chip_device; 22 u32 subsys_vendor; 23 u32 subsys_device; 24 u32 px_quirk_flags; 25 }; 26 27 struct amdgpu_atpx_functions { 28 bool px_params; 29 bool power_cntl; 30 bool disp_mux_cntl; 31 bool i2c_mux_cntl; 32 bool switch_start; 33 bool switch_end; 34 bool disp_connectors_mapping; 35 bool disp_detection_ports; 36 }; 37 38 struct amdgpu_atpx { 39 acpi_handle handle; 40 struct amdgpu_atpx_functions functions; 41 bool is_hybrid; 42 bool dgpu_req_power_for_displays; 43 }; 44 45 static struct amdgpu_atpx_priv { 46 bool atpx_detected; 47 bool bridge_pm_usable; 48 unsigned int quirks; 49 /* handle for device - and atpx */ 50 acpi_handle dhandle; 51 acpi_handle other_handle; 52 struct amdgpu_atpx atpx; 53 } amdgpu_atpx_priv; 54 55 struct atpx_verify_interface { 56 u16 size; /* structure size in bytes (includes size field) */ 57 u16 version; /* version */ 58 u32 function_bits; /* supported functions bit vector */ 59 } __packed; 60 61 struct atpx_px_params { 62 u16 size; /* structure size in bytes (includes size field) */ 63 u32 valid_flags; /* which flags are valid */ 64 u32 flags; /* flags */ 65 } __packed; 66 67 struct atpx_power_control { 68 u16 size; 69 u8 dgpu_state; 70 } __packed; 71 72 struct atpx_mux { 73 u16 size; 74 u16 mux; 75 } __packed; 76 77 bool amdgpu_has_atpx(void) 78 { 79 return amdgpu_atpx_priv.atpx_detected; 80 } 81 82 bool amdgpu_has_atpx_dgpu_power_cntl(void) 83 { 84 return amdgpu_atpx_priv.atpx.functions.power_cntl; 85 } 86 87 bool amdgpu_is_atpx_hybrid(void) 88 { 89 return amdgpu_atpx_priv.atpx.is_hybrid; 90 } 91 92 static bool amdgpu_atpx_buffer_validate(const union acpi_object *obj, 93 size_t min_size) 94 { 95 return obj && obj->type == ACPI_TYPE_BUFFER && 96 obj->buffer.length >= sizeof(u16) && 97 obj->buffer.length >= *(u16 *)obj->buffer.pointer && 98 *(u16 *)obj->buffer.pointer >= min_size; 99 } 100 101 /** 102 * amdgpu_atpx_call - call an ATPX method 103 * 104 * @handle: acpi handle 105 * @function: the ATPX function to execute 106 * @params: ATPX function params 107 * 108 * Executes the requested ATPX function (all asics). 109 * Returns a pointer to the acpi output buffer. 110 */ 111 static union acpi_object *amdgpu_atpx_call(acpi_handle handle, int function, 112 struct acpi_buffer *params) 113 { 114 acpi_status status; 115 union acpi_object atpx_arg_elements[2]; 116 struct acpi_object_list atpx_arg; 117 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 118 119 atpx_arg.count = 2; 120 atpx_arg.pointer = &atpx_arg_elements[0]; 121 122 atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; 123 atpx_arg_elements[0].integer.value = function; 124 125 if (params) { 126 atpx_arg_elements[1].type = ACPI_TYPE_BUFFER; 127 atpx_arg_elements[1].buffer.length = params->length; 128 atpx_arg_elements[1].buffer.pointer = params->pointer; 129 } else { 130 /* We need a second fake parameter */ 131 atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; 132 atpx_arg_elements[1].integer.value = 0; 133 } 134 135 status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); 136 137 /* Fail only if calling the method fails and ATPX is supported */ 138 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 139 pr_err("failed to evaluate ATPX got %s\n", 140 acpi_format_exception(status)); 141 kfree(buffer.pointer); 142 return NULL; 143 } 144 145 return buffer.pointer; 146 } 147 148 /** 149 * amdgpu_atpx_parse_functions - parse supported functions 150 * 151 * @f: supported functions struct 152 * @mask: supported functions mask from ATPX 153 * 154 * Use the supported functions mask from ATPX function 155 * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions 156 * are supported (all asics). 157 */ 158 static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mask) 159 { 160 f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED; 161 f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED; 162 f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED; 163 f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED; 164 f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED; 165 f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED; 166 f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED; 167 f->disp_detection_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; 168 } 169 170 /** 171 * amdgpu_atpx_validate - validate ATPX functions 172 * 173 * @atpx: amdgpu atpx struct 174 * 175 * Validate that required functions are enabled (all asics). 176 * returns 0 on success, error on failure. 177 */ 178 static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx) 179 { 180 u32 valid_bits = 0; 181 182 if (atpx->functions.px_params) { 183 union acpi_object *info; 184 struct atpx_px_params output; 185 size_t size; 186 187 info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL); 188 if (!info) 189 return -EIO; 190 191 if (!amdgpu_atpx_buffer_validate(info, sizeof(output))) { 192 pr_err("Invalid ATPX GET_PX_PARAMETERS response\n"); 193 kfree(info); 194 return -EINVAL; 195 } 196 197 memset(&output, 0, sizeof(output)); 198 199 size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer); 200 201 memcpy(&output, info->buffer.pointer, size); 202 203 valid_bits = output.flags & output.valid_flags; 204 205 kfree(info); 206 } 207 208 /* if separate mux flag is set, mux controls are required */ 209 if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) { 210 atpx->functions.i2c_mux_cntl = true; 211 atpx->functions.disp_mux_cntl = true; 212 } 213 /* if any outputs are muxed, mux controls are required */ 214 if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED | 215 ATPX_TV_SIGNAL_MUXED | 216 ATPX_DFP_SIGNAL_MUXED)) 217 atpx->functions.disp_mux_cntl = true; 218 219 220 /* some bioses set these bits rather than flagging power_cntl as supported */ 221 if (valid_bits & (ATPX_DYNAMIC_PX_SUPPORTED | 222 ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED)) 223 atpx->functions.power_cntl = true; 224 225 atpx->is_hybrid = false; 226 if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) { 227 if (amdgpu_atpx_priv.quirks & AMDGPU_PX_QUIRK_FORCE_ATPX) { 228 pr_warn("ATPX Hybrid Graphics, forcing to ATPX\n"); 229 atpx->functions.power_cntl = true; 230 atpx->is_hybrid = false; 231 } else { 232 pr_notice("ATPX Hybrid Graphics\n"); 233 /* 234 * Disable legacy PM methods only when pcie port PM is usable, 235 * otherwise the device might fail to power off or power on. 236 */ 237 atpx->functions.power_cntl = !amdgpu_atpx_priv.bridge_pm_usable; 238 atpx->is_hybrid = true; 239 } 240 } 241 242 atpx->dgpu_req_power_for_displays = false; 243 if (valid_bits & ATPX_DGPU_REQ_POWER_FOR_DISPLAYS) 244 atpx->dgpu_req_power_for_displays = true; 245 246 return 0; 247 } 248 249 /** 250 * amdgpu_atpx_verify_interface - verify ATPX 251 * 252 * @atpx: amdgpu atpx struct 253 * 254 * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function 255 * to initialize ATPX and determine what features are supported 256 * (all asics). 257 * returns 0 on success, error on failure. 258 */ 259 static int amdgpu_atpx_verify_interface(struct amdgpu_atpx *atpx) 260 { 261 union acpi_object *info; 262 struct atpx_verify_interface output; 263 size_t size; 264 int err = 0; 265 266 info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL); 267 if (!info) 268 return -EIO; 269 270 if (!amdgpu_atpx_buffer_validate(info, sizeof(output))) { 271 pr_err("Invalid ATPX VERIFY_INTERFACE response\n"); 272 err = -EINVAL; 273 goto out; 274 } 275 276 memset(&output, 0, sizeof(output)); 277 278 size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer); 279 280 memcpy(&output, info->buffer.pointer, size); 281 282 /* TODO: check version? */ 283 pr_notice("ATPX version %u, functions 0x%08x\n", 284 output.version, output.function_bits); 285 286 amdgpu_atpx_parse_functions(&atpx->functions, output.function_bits); 287 288 out: 289 kfree(info); 290 return err; 291 } 292 293 /** 294 * amdgpu_atpx_set_discrete_state - power up/down discrete GPU 295 * 296 * @atpx: atpx info struct 297 * @state: discrete GPU state (0 = power down, 1 = power up) 298 * 299 * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to 300 * power down/up the discrete GPU (all asics). 301 * Returns 0 on success, error on failure. 302 */ 303 static int amdgpu_atpx_set_discrete_state(struct amdgpu_atpx *atpx, u8 state) 304 { 305 struct acpi_buffer params; 306 union acpi_object *info; 307 struct atpx_power_control input; 308 309 if (atpx->functions.power_cntl) { 310 input.size = 3; 311 input.dgpu_state = state; 312 params.length = input.size; 313 params.pointer = &input; 314 info = amdgpu_atpx_call(atpx->handle, 315 ATPX_FUNCTION_POWER_CONTROL, 316 ¶ms); 317 if (!info) 318 return -EIO; 319 kfree(info); 320 321 /* 200ms delay is required after off */ 322 if (state == 0) 323 msleep(200); 324 } 325 return 0; 326 } 327 328 /** 329 * amdgpu_atpx_switch_disp_mux - switch display mux 330 * 331 * @atpx: atpx info struct 332 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) 333 * 334 * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to 335 * switch the display mux between the discrete GPU and integrated GPU 336 * (all asics). 337 * Returns 0 on success, error on failure. 338 */ 339 static int amdgpu_atpx_switch_disp_mux(struct amdgpu_atpx *atpx, u16 mux_id) 340 { 341 struct acpi_buffer params; 342 union acpi_object *info; 343 struct atpx_mux input; 344 345 if (atpx->functions.disp_mux_cntl) { 346 input.size = 4; 347 input.mux = mux_id; 348 params.length = input.size; 349 params.pointer = &input; 350 info = amdgpu_atpx_call(atpx->handle, 351 ATPX_FUNCTION_DISPLAY_MUX_CONTROL, 352 ¶ms); 353 if (!info) 354 return -EIO; 355 kfree(info); 356 } 357 return 0; 358 } 359 360 /** 361 * amdgpu_atpx_switch_i2c_mux - switch i2c/hpd mux 362 * 363 * @atpx: atpx info struct 364 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) 365 * 366 * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to 367 * switch the i2c/hpd mux between the discrete GPU and integrated GPU 368 * (all asics). 369 * Returns 0 on success, error on failure. 370 */ 371 static int amdgpu_atpx_switch_i2c_mux(struct amdgpu_atpx *atpx, u16 mux_id) 372 { 373 struct acpi_buffer params; 374 union acpi_object *info; 375 struct atpx_mux input; 376 377 if (atpx->functions.i2c_mux_cntl) { 378 input.size = 4; 379 input.mux = mux_id; 380 params.length = input.size; 381 params.pointer = &input; 382 info = amdgpu_atpx_call(atpx->handle, 383 ATPX_FUNCTION_I2C_MUX_CONTROL, 384 ¶ms); 385 if (!info) 386 return -EIO; 387 kfree(info); 388 } 389 return 0; 390 } 391 392 /** 393 * amdgpu_atpx_switch_start - notify the sbios of a GPU switch 394 * 395 * @atpx: atpx info struct 396 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) 397 * 398 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX 399 * function to notify the sbios that a switch between the discrete GPU and 400 * integrated GPU has begun (all asics). 401 * Returns 0 on success, error on failure. 402 */ 403 static int amdgpu_atpx_switch_start(struct amdgpu_atpx *atpx, u16 mux_id) 404 { 405 struct acpi_buffer params; 406 union acpi_object *info; 407 struct atpx_mux input; 408 409 if (atpx->functions.switch_start) { 410 input.size = 4; 411 input.mux = mux_id; 412 params.length = input.size; 413 params.pointer = &input; 414 info = amdgpu_atpx_call(atpx->handle, 415 ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION, 416 ¶ms); 417 if (!info) 418 return -EIO; 419 kfree(info); 420 } 421 return 0; 422 } 423 424 /** 425 * amdgpu_atpx_switch_end - notify the sbios of a GPU switch 426 * 427 * @atpx: atpx info struct 428 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) 429 * 430 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX 431 * function to notify the sbios that a switch between the discrete GPU and 432 * integrated GPU has ended (all asics). 433 * Returns 0 on success, error on failure. 434 */ 435 static int amdgpu_atpx_switch_end(struct amdgpu_atpx *atpx, u16 mux_id) 436 { 437 struct acpi_buffer params; 438 union acpi_object *info; 439 struct atpx_mux input; 440 441 if (atpx->functions.switch_end) { 442 input.size = 4; 443 input.mux = mux_id; 444 params.length = input.size; 445 params.pointer = &input; 446 info = amdgpu_atpx_call(atpx->handle, 447 ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION, 448 ¶ms); 449 if (!info) 450 return -EIO; 451 kfree(info); 452 } 453 return 0; 454 } 455 456 /** 457 * amdgpu_atpx_switchto - switch to the requested GPU 458 * 459 * @id: GPU to switch to 460 * 461 * Execute the necessary ATPX functions to switch between the discrete GPU and 462 * integrated GPU (all asics). 463 * Returns 0 on success, error on failure. 464 */ 465 static int amdgpu_atpx_switchto(enum vga_switcheroo_client_id id) 466 { 467 u16 gpu_id; 468 469 if (id == VGA_SWITCHEROO_IGD) 470 gpu_id = ATPX_INTEGRATED_GPU; 471 else 472 gpu_id = ATPX_DISCRETE_GPU; 473 474 amdgpu_atpx_switch_start(&amdgpu_atpx_priv.atpx, gpu_id); 475 amdgpu_atpx_switch_disp_mux(&amdgpu_atpx_priv.atpx, gpu_id); 476 amdgpu_atpx_switch_i2c_mux(&amdgpu_atpx_priv.atpx, gpu_id); 477 amdgpu_atpx_switch_end(&amdgpu_atpx_priv.atpx, gpu_id); 478 479 return 0; 480 } 481 482 /** 483 * amdgpu_atpx_power_state - power down/up the requested GPU 484 * 485 * @id: GPU to power down/up 486 * @state: requested power state (0 = off, 1 = on) 487 * 488 * Execute the necessary ATPX function to power down/up the discrete GPU 489 * (all asics). 490 * Returns 0 on success, error on failure. 491 */ 492 static int amdgpu_atpx_power_state(enum vga_switcheroo_client_id id, 493 enum vga_switcheroo_state state) 494 { 495 /* on w500 ACPI can't change intel gpu state */ 496 if (id == VGA_SWITCHEROO_IGD) 497 return 0; 498 499 amdgpu_atpx_set_discrete_state(&amdgpu_atpx_priv.atpx, state); 500 return 0; 501 } 502 503 /** 504 * amdgpu_atpx_pci_probe_handle - look up the ATPX handle 505 * 506 * @pdev: pci device 507 * 508 * Look up the ATPX handles (all asics). 509 * Returns true if the handles are found, false if not. 510 */ 511 static bool amdgpu_atpx_pci_probe_handle(struct pci_dev *pdev) 512 { 513 acpi_handle dhandle, atpx_handle; 514 acpi_status status; 515 516 dhandle = ACPI_HANDLE(&pdev->dev); 517 if (!dhandle) 518 return false; 519 520 status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); 521 if (ACPI_FAILURE(status)) { 522 amdgpu_atpx_priv.other_handle = dhandle; 523 return false; 524 } 525 amdgpu_atpx_priv.dhandle = dhandle; 526 amdgpu_atpx_priv.atpx.handle = atpx_handle; 527 return true; 528 } 529 530 /** 531 * amdgpu_atpx_init - verify the ATPX interface 532 * 533 * Verify the ATPX interface (all asics). 534 * Returns 0 on success, error on failure. 535 */ 536 static int amdgpu_atpx_init(void) 537 { 538 int r; 539 540 /* set up the ATPX handle */ 541 r = amdgpu_atpx_verify_interface(&amdgpu_atpx_priv.atpx); 542 if (r) 543 return r; 544 545 /* validate the atpx setup */ 546 r = amdgpu_atpx_validate(&amdgpu_atpx_priv.atpx); 547 if (r) 548 return r; 549 550 return 0; 551 } 552 553 /** 554 * amdgpu_atpx_get_client_id - get the client id 555 * 556 * @pdev: pci device 557 * 558 * look up whether we are the integrated or discrete GPU (all asics). 559 * Returns the client id. 560 */ 561 static enum vga_switcheroo_client_id amdgpu_atpx_get_client_id(struct pci_dev *pdev) 562 { 563 if (amdgpu_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev)) 564 return VGA_SWITCHEROO_IGD; 565 else 566 return VGA_SWITCHEROO_DIS; 567 } 568 569 static const struct vga_switcheroo_handler amdgpu_atpx_handler = { 570 .switchto = amdgpu_atpx_switchto, 571 .power_state = amdgpu_atpx_power_state, 572 .get_client_id = amdgpu_atpx_get_client_id, 573 }; 574 575 static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { 576 /* HG _PR3 doesn't seem to work on this A+A weston board */ 577 { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, 578 { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, 579 { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, 580 { 0x1002, 0x699f, 0x1028, 0x0814, AMDGPU_PX_QUIRK_FORCE_ATPX }, 581 { 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX }, 582 { 0x1002, 0x6900, 0x17AA, 0x3806, AMDGPU_PX_QUIRK_FORCE_ATPX }, 583 { 0, 0, 0, 0, 0 }, 584 }; 585 586 static void amdgpu_atpx_get_quirks(struct pci_dev *pdev) 587 { 588 const struct amdgpu_px_quirk *p = amdgpu_px_quirk_list; 589 590 /* Apply PX quirks */ 591 while (p && p->chip_device != 0) { 592 if (pdev->vendor == p->chip_vendor && 593 pdev->device == p->chip_device && 594 pdev->subsystem_vendor == p->subsys_vendor && 595 pdev->subsystem_device == p->subsys_device) { 596 amdgpu_atpx_priv.quirks |= p->px_quirk_flags; 597 break; 598 } 599 ++p; 600 } 601 } 602 603 /** 604 * amdgpu_atpx_detect - detect whether we have PX 605 * 606 * Check if we have a PX system (all asics). 607 * Returns true if we have a PX system, false if not. 608 */ 609 static bool amdgpu_atpx_detect(void) 610 { 611 char acpi_method_name[255] = { 0 }; 612 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 613 struct pci_dev *pdev = NULL; 614 bool has_atpx = false; 615 int vga_count = 0; 616 bool d3_supported = false; 617 struct pci_dev *parent_pdev; 618 619 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 620 vga_count++; 621 622 has_atpx |= amdgpu_atpx_pci_probe_handle(pdev); 623 624 parent_pdev = pci_upstream_bridge(pdev); 625 d3_supported |= parent_pdev && parent_pdev->bridge_d3; 626 amdgpu_atpx_get_quirks(pdev); 627 } 628 629 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { 630 vga_count++; 631 632 has_atpx |= amdgpu_atpx_pci_probe_handle(pdev); 633 634 parent_pdev = pci_upstream_bridge(pdev); 635 d3_supported |= parent_pdev && parent_pdev->bridge_d3; 636 amdgpu_atpx_get_quirks(pdev); 637 } 638 639 if (has_atpx && vga_count == 2) { 640 acpi_get_name(amdgpu_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer); 641 pr_info("vga_switcheroo: detected switching method %s handle\n", 642 acpi_method_name); 643 amdgpu_atpx_priv.atpx_detected = true; 644 amdgpu_atpx_priv.bridge_pm_usable = d3_supported; 645 amdgpu_atpx_init(); 646 return true; 647 } 648 return false; 649 } 650 651 /** 652 * amdgpu_register_atpx_handler - register with vga_switcheroo 653 * 654 * Register the PX callbacks with vga_switcheroo (all asics). 655 */ 656 void amdgpu_register_atpx_handler(void) 657 { 658 bool r; 659 enum vga_switcheroo_handler_flags_t handler_flags = 0; 660 661 /* detect if we have any ATPX + 2 VGA in the system */ 662 r = amdgpu_atpx_detect(); 663 if (!r) 664 return; 665 666 vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags); 667 } 668 669 /** 670 * amdgpu_unregister_atpx_handler - unregister with vga_switcheroo 671 * 672 * Unregister the PX callbacks with vga_switcheroo (all asics). 673 */ 674 void amdgpu_unregister_atpx_handler(void) 675 { 676 vga_switcheroo_unregister_handler(); 677 } 678