blob: 7b11af1d8c4f5aa1d65507160f472a95e755c8ad [file] [log] [blame]
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001/*
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>
Alex Deucherf81eb1a2016-06-01 12:54:33 -040013#include <linux/delay.h>
Alex Deucherd38ceaf2015-04-20 16:55:21 -040014
Rex Zhu66dc0dd2015-09-18 16:35:17 +080015#include "amd_acpi.h"
Alex Deucherd38ceaf2015-04-20 16:55:21 -040016
17struct amdgpu_atpx_functions {
18 bool px_params;
19 bool power_cntl;
20 bool disp_mux_cntl;
21 bool i2c_mux_cntl;
22 bool switch_start;
23 bool switch_end;
24 bool disp_connectors_mapping;
25 bool disp_detetion_ports;
26};
27
28struct amdgpu_atpx {
29 acpi_handle handle;
30 struct amdgpu_atpx_functions functions;
31};
32
33static struct amdgpu_atpx_priv {
34 bool atpx_detected;
35 /* handle for device - and atpx */
36 acpi_handle dhandle;
37 acpi_handle other_handle;
38 struct amdgpu_atpx atpx;
39} amdgpu_atpx_priv;
40
41struct atpx_verify_interface {
42 u16 size; /* structure size in bytes (includes size field) */
43 u16 version; /* version */
44 u32 function_bits; /* supported functions bit vector */
45} __packed;
46
47struct atpx_px_params {
48 u16 size; /* structure size in bytes (includes size field) */
49 u32 valid_flags; /* which flags are valid */
50 u32 flags; /* flags */
51} __packed;
52
53struct atpx_power_control {
54 u16 size;
55 u8 dgpu_state;
56} __packed;
57
58struct atpx_mux {
59 u16 size;
60 u16 mux;
61} __packed;
62
63bool amdgpu_has_atpx(void) {
64 return amdgpu_atpx_priv.atpx_detected;
65}
66
Alex Deuchera78fe132016-06-01 13:08:21 -040067bool amdgpu_has_atpx_dgpu_power_cntl(void) {
68 return amdgpu_atpx_priv.atpx.functions.power_cntl;
69}
70
Alex Deucherd38ceaf2015-04-20 16:55:21 -040071/**
72 * amdgpu_atpx_call - call an ATPX method
73 *
74 * @handle: acpi handle
75 * @function: the ATPX function to execute
76 * @params: ATPX function params
77 *
78 * Executes the requested ATPX function (all asics).
79 * Returns a pointer to the acpi output buffer.
80 */
81static union acpi_object *amdgpu_atpx_call(acpi_handle handle, int function,
82 struct acpi_buffer *params)
83{
84 acpi_status status;
85 union acpi_object atpx_arg_elements[2];
86 struct acpi_object_list atpx_arg;
87 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
88
89 atpx_arg.count = 2;
90 atpx_arg.pointer = &atpx_arg_elements[0];
91
92 atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
93 atpx_arg_elements[0].integer.value = function;
94
95 if (params) {
96 atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
97 atpx_arg_elements[1].buffer.length = params->length;
98 atpx_arg_elements[1].buffer.pointer = params->pointer;
99 } else {
100 /* We need a second fake parameter */
101 atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
102 atpx_arg_elements[1].integer.value = 0;
103 }
104
105 status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
106
107 /* Fail only if calling the method fails and ATPX is supported */
108 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
109 printk("failed to evaluate ATPX got %s\n",
110 acpi_format_exception(status));
111 kfree(buffer.pointer);
112 return NULL;
113 }
114
115 return buffer.pointer;
116}
117
118/**
119 * amdgpu_atpx_parse_functions - parse supported functions
120 *
121 * @f: supported functions struct
122 * @mask: supported functions mask from ATPX
123 *
124 * Use the supported functions mask from ATPX function
125 * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions
126 * are supported (all asics).
127 */
128static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mask)
129{
130 f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED;
131 f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED;
132 f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED;
133 f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED;
134 f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED;
135 f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED;
136 f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED;
137 f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
138}
139
140/**
141 * amdgpu_atpx_validate_functions - validate ATPX functions
142 *
143 * @atpx: amdgpu atpx struct
144 *
145 * Validate that required functions are enabled (all asics).
146 * returns 0 on success, error on failure.
147 */
148static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx)
149{
Alex Deucher8d45f802016-06-01 12:42:35 -0400150 u32 valid_bits = 0;
Alex Deuchere9bef452016-04-25 13:12:18 -0400151
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400152 if (atpx->functions.px_params) {
153 union acpi_object *info;
154 struct atpx_px_params output;
155 size_t size;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400156
157 info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
158 if (!info)
159 return -EIO;
160
161 memset(&output, 0, sizeof(output));
162
163 size = *(u16 *) info->buffer.pointer;
164 if (size < 10) {
165 printk("ATPX buffer is too small: %zu\n", size);
166 kfree(info);
167 return -EINVAL;
168 }
169 size = min(sizeof(output), size);
170
171 memcpy(&output, info->buffer.pointer, size);
172
173 valid_bits = output.flags & output.valid_flags;
Alex Deucher5c614792016-06-01 12:28:13 -0400174
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400175 kfree(info);
176 }
Alex Deucher8d45f802016-06-01 12:42:35 -0400177
178 /* if separate mux flag is set, mux controls are required */
179 if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
180 atpx->functions.i2c_mux_cntl = true;
181 atpx->functions.disp_mux_cntl = true;
182 }
183 /* if any outputs are muxed, mux controls are required */
184 if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
185 ATPX_TV_SIGNAL_MUXED |
186 ATPX_DFP_SIGNAL_MUXED))
187 atpx->functions.disp_mux_cntl = true;
188
189
190 /* some bioses set these bits rather than flagging power_cntl as supported */
191 if (valid_bits & (ATPX_DYNAMIC_PX_SUPPORTED |
192 ATPX_DYNAMIC_DGPU_POWER_OFF_SUPPORTED))
193 atpx->functions.power_cntl = true;
194
195 if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) {
196 printk("Hybrid Graphics, ATPX dGPU power cntl disabled\n");
197 atpx->functions.power_cntl = false;
198 } else if (atpx->functions.power_cntl == false) {
199 /* make sure required functions are enabled */
200 /* dGPU power control is required */
201 printk("ATPX dGPU power cntl not present, forcing\n");
202 atpx->functions.power_cntl = true;
203 }
204
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400205 return 0;
206}
207
208/**
209 * amdgpu_atpx_verify_interface - verify ATPX
210 *
211 * @atpx: amdgpu atpx struct
212 *
213 * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
214 * to initialize ATPX and determine what features are supported
215 * (all asics).
216 * returns 0 on success, error on failure.
217 */
218static int amdgpu_atpx_verify_interface(struct amdgpu_atpx *atpx)
219{
220 union acpi_object *info;
221 struct atpx_verify_interface output;
222 size_t size;
223 int err = 0;
224
225 info = amdgpu_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL);
226 if (!info)
227 return -EIO;
228
229 memset(&output, 0, sizeof(output));
230
231 size = *(u16 *) info->buffer.pointer;
232 if (size < 8) {
233 printk("ATPX buffer is too small: %zu\n", size);
234 err = -EINVAL;
235 goto out;
236 }
237 size = min(sizeof(output), size);
238
239 memcpy(&output, info->buffer.pointer, size);
240
241 /* TODO: check version? */
242 printk("ATPX version %u, functions 0x%08x\n",
243 output.version, output.function_bits);
244
245 amdgpu_atpx_parse_functions(&atpx->functions, output.function_bits);
246
247out:
248 kfree(info);
249 return err;
250}
251
252/**
253 * amdgpu_atpx_set_discrete_state - power up/down discrete GPU
254 *
255 * @atpx: atpx info struct
256 * @state: discrete GPU state (0 = power down, 1 = power up)
257 *
258 * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to
259 * power down/up the discrete GPU (all asics).
260 * Returns 0 on success, error on failure.
261 */
262static int amdgpu_atpx_set_discrete_state(struct amdgpu_atpx *atpx, u8 state)
263{
264 struct acpi_buffer params;
265 union acpi_object *info;
266 struct atpx_power_control input;
267
268 if (atpx->functions.power_cntl) {
269 input.size = 3;
270 input.dgpu_state = state;
271 params.length = input.size;
272 params.pointer = &input;
273 info = amdgpu_atpx_call(atpx->handle,
274 ATPX_FUNCTION_POWER_CONTROL,
275 &params);
276 if (!info)
277 return -EIO;
278 kfree(info);
Alex Deucherf81eb1a2016-06-01 12:54:33 -0400279
280 /* 200ms delay is required after off */
281 if (state == 0)
282 msleep(200);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400283 }
284 return 0;
285}
286
287/**
288 * amdgpu_atpx_switch_disp_mux - switch display mux
289 *
290 * @atpx: atpx info struct
291 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
292 *
293 * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to
294 * switch the display mux between the discrete GPU and integrated GPU
295 * (all asics).
296 * Returns 0 on success, error on failure.
297 */
298static int amdgpu_atpx_switch_disp_mux(struct amdgpu_atpx *atpx, u16 mux_id)
299{
300 struct acpi_buffer params;
301 union acpi_object *info;
302 struct atpx_mux input;
303
304 if (atpx->functions.disp_mux_cntl) {
305 input.size = 4;
306 input.mux = mux_id;
307 params.length = input.size;
308 params.pointer = &input;
309 info = amdgpu_atpx_call(atpx->handle,
310 ATPX_FUNCTION_DISPLAY_MUX_CONTROL,
311 &params);
312 if (!info)
313 return -EIO;
314 kfree(info);
315 }
316 return 0;
317}
318
319/**
320 * amdgpu_atpx_switch_i2c_mux - switch i2c/hpd mux
321 *
322 * @atpx: atpx info struct
323 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
324 *
325 * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to
326 * switch the i2c/hpd mux between the discrete GPU and integrated GPU
327 * (all asics).
328 * Returns 0 on success, error on failure.
329 */
330static int amdgpu_atpx_switch_i2c_mux(struct amdgpu_atpx *atpx, u16 mux_id)
331{
332 struct acpi_buffer params;
333 union acpi_object *info;
334 struct atpx_mux input;
335
336 if (atpx->functions.i2c_mux_cntl) {
337 input.size = 4;
338 input.mux = mux_id;
339 params.length = input.size;
340 params.pointer = &input;
341 info = amdgpu_atpx_call(atpx->handle,
342 ATPX_FUNCTION_I2C_MUX_CONTROL,
343 &params);
344 if (!info)
345 return -EIO;
346 kfree(info);
347 }
348 return 0;
349}
350
351/**
352 * amdgpu_atpx_switch_start - notify the sbios of a GPU switch
353 *
354 * @atpx: atpx info struct
355 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
356 *
357 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX
358 * function to notify the sbios that a switch between the discrete GPU and
359 * integrated GPU has begun (all asics).
360 * Returns 0 on success, error on failure.
361 */
362static int amdgpu_atpx_switch_start(struct amdgpu_atpx *atpx, u16 mux_id)
363{
364 struct acpi_buffer params;
365 union acpi_object *info;
366 struct atpx_mux input;
367
368 if (atpx->functions.switch_start) {
369 input.size = 4;
370 input.mux = mux_id;
371 params.length = input.size;
372 params.pointer = &input;
373 info = amdgpu_atpx_call(atpx->handle,
374 ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION,
375 &params);
376 if (!info)
377 return -EIO;
378 kfree(info);
379 }
380 return 0;
381}
382
383/**
384 * amdgpu_atpx_switch_end - notify the sbios of a GPU switch
385 *
386 * @atpx: atpx info struct
387 * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU)
388 *
389 * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX
390 * function to notify the sbios that a switch between the discrete GPU and
391 * integrated GPU has ended (all asics).
392 * Returns 0 on success, error on failure.
393 */
394static int amdgpu_atpx_switch_end(struct amdgpu_atpx *atpx, u16 mux_id)
395{
396 struct acpi_buffer params;
397 union acpi_object *info;
398 struct atpx_mux input;
399
400 if (atpx->functions.switch_end) {
401 input.size = 4;
402 input.mux = mux_id;
403 params.length = input.size;
404 params.pointer = &input;
405 info = amdgpu_atpx_call(atpx->handle,
406 ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION,
407 &params);
408 if (!info)
409 return -EIO;
410 kfree(info);
411 }
412 return 0;
413}
414
415/**
416 * amdgpu_atpx_switchto - switch to the requested GPU
417 *
418 * @id: GPU to switch to
419 *
420 * Execute the necessary ATPX functions to switch between the discrete GPU and
421 * integrated GPU (all asics).
422 * Returns 0 on success, error on failure.
423 */
424static int amdgpu_atpx_switchto(enum vga_switcheroo_client_id id)
425{
426 u16 gpu_id;
427
428 if (id == VGA_SWITCHEROO_IGD)
429 gpu_id = ATPX_INTEGRATED_GPU;
430 else
431 gpu_id = ATPX_DISCRETE_GPU;
432
433 amdgpu_atpx_switch_start(&amdgpu_atpx_priv.atpx, gpu_id);
434 amdgpu_atpx_switch_disp_mux(&amdgpu_atpx_priv.atpx, gpu_id);
435 amdgpu_atpx_switch_i2c_mux(&amdgpu_atpx_priv.atpx, gpu_id);
436 amdgpu_atpx_switch_end(&amdgpu_atpx_priv.atpx, gpu_id);
437
438 return 0;
439}
440
441/**
442 * amdgpu_atpx_power_state - power down/up the requested GPU
443 *
444 * @id: GPU to power down/up
445 * @state: requested power state (0 = off, 1 = on)
446 *
447 * Execute the necessary ATPX function to power down/up the discrete GPU
448 * (all asics).
449 * Returns 0 on success, error on failure.
450 */
451static int amdgpu_atpx_power_state(enum vga_switcheroo_client_id id,
452 enum vga_switcheroo_state state)
453{
454 /* on w500 ACPI can't change intel gpu state */
455 if (id == VGA_SWITCHEROO_IGD)
456 return 0;
457
458 amdgpu_atpx_set_discrete_state(&amdgpu_atpx_priv.atpx, state);
459 return 0;
460}
461
462/**
463 * amdgpu_atpx_pci_probe_handle - look up the ATPX handle
464 *
465 * @pdev: pci device
466 *
467 * Look up the ATPX handles (all asics).
468 * Returns true if the handles are found, false if not.
469 */
470static bool amdgpu_atpx_pci_probe_handle(struct pci_dev *pdev)
471{
472 acpi_handle dhandle, atpx_handle;
473 acpi_status status;
474
475 dhandle = ACPI_HANDLE(&pdev->dev);
476 if (!dhandle)
477 return false;
478
479 status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
480 if (ACPI_FAILURE(status)) {
481 amdgpu_atpx_priv.other_handle = dhandle;
482 return false;
483 }
484 amdgpu_atpx_priv.dhandle = dhandle;
485 amdgpu_atpx_priv.atpx.handle = atpx_handle;
486 return true;
487}
488
489/**
490 * amdgpu_atpx_init - verify the ATPX interface
491 *
492 * Verify the ATPX interface (all asics).
493 * Returns 0 on success, error on failure.
494 */
495static int amdgpu_atpx_init(void)
496{
497 int r;
498
499 /* set up the ATPX handle */
500 r = amdgpu_atpx_verify_interface(&amdgpu_atpx_priv.atpx);
501 if (r)
502 return r;
503
504 /* validate the atpx setup */
505 r = amdgpu_atpx_validate(&amdgpu_atpx_priv.atpx);
506 if (r)
507 return r;
508
509 return 0;
510}
511
512/**
513 * amdgpu_atpx_get_client_id - get the client id
514 *
515 * @pdev: pci device
516 *
517 * look up whether we are the integrated or discrete GPU (all asics).
518 * Returns the client id.
519 */
520static int amdgpu_atpx_get_client_id(struct pci_dev *pdev)
521{
522 if (amdgpu_atpx_priv.dhandle == ACPI_HANDLE(&pdev->dev))
523 return VGA_SWITCHEROO_IGD;
524 else
525 return VGA_SWITCHEROO_DIS;
526}
527
Lukas Wunner5d170132015-10-18 13:05:40 +0200528static const struct vga_switcheroo_handler amdgpu_atpx_handler = {
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400529 .switchto = amdgpu_atpx_switchto,
530 .power_state = amdgpu_atpx_power_state,
531 .init = amdgpu_atpx_init,
532 .get_client_id = amdgpu_atpx_get_client_id,
533};
534
535/**
536 * amdgpu_atpx_detect - detect whether we have PX
537 *
538 * Check if we have a PX system (all asics).
539 * Returns true if we have a PX system, false if not.
540 */
541static bool amdgpu_atpx_detect(void)
542{
543 char acpi_method_name[255] = { 0 };
544 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
545 struct pci_dev *pdev = NULL;
546 bool has_atpx = false;
547 int vga_count = 0;
548
549 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
550 vga_count++;
551
552 has_atpx |= (amdgpu_atpx_pci_probe_handle(pdev) == true);
553 }
554
555 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
556 vga_count++;
557
558 has_atpx |= (amdgpu_atpx_pci_probe_handle(pdev) == true);
559 }
560
561 if (has_atpx && vga_count == 2) {
562 acpi_get_name(amdgpu_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
Lukas Wunner16944672015-09-05 11:17:35 +0200563 printk(KERN_INFO "vga_switcheroo: detected switching method %s handle\n",
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400564 acpi_method_name);
565 amdgpu_atpx_priv.atpx_detected = true;
566 return true;
567 }
568 return false;
569}
570
571/**
572 * amdgpu_register_atpx_handler - register with vga_switcheroo
573 *
574 * Register the PX callbacks with vga_switcheroo (all asics).
575 */
576void amdgpu_register_atpx_handler(void)
577{
578 bool r;
Lukas Wunner156d7d42016-01-11 20:09:20 +0100579 enum vga_switcheroo_handler_flags_t handler_flags = 0;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400580
581 /* detect if we have any ATPX + 2 VGA in the system */
582 r = amdgpu_atpx_detect();
583 if (!r)
584 return;
585
Lukas Wunner156d7d42016-01-11 20:09:20 +0100586 vga_switcheroo_register_handler(&amdgpu_atpx_handler, handler_flags);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400587}
588
589/**
590 * amdgpu_unregister_atpx_handler - unregister with vga_switcheroo
591 *
592 * Unregister the PX callbacks with vga_switcheroo (all asics).
593 */
594void amdgpu_unregister_atpx_handler(void)
595{
596 vga_switcheroo_unregister_handler();
597}