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