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