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