Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radeon_atpx_handler.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 Red Hat Inc.
3  * Author : Dave Airlie <[email protected]>
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 <acpi/acpi.h>
12 #include <acpi/acpi_bus.h>
13 #include <linux/pci.h>
14 
15 #include "radeon_acpi.h"
16 
18  bool px_params;
19  bool power_cntl;
23  bool switch_end;
26 };
27 
28 struct radeon_atpx {
31 };
32 
33 static struct radeon_atpx_priv {
34  bool atpx_detected;
35  /* handle for device - and atpx */
36  acpi_handle dhandle;
37  struct radeon_atpx atpx;
38 } radeon_atpx_priv;
39 
41  u16 size; /* structure size in bytes (includes size field) */
42  u16 version; /* version */
43  u32 function_bits; /* supported functions bit vector */
44 } __packed;
45 
49 } __packed;
50 
51 struct atpx_mux {
54 } __packed;
55 
66 static union acpi_object *radeon_atpx_call(acpi_handle handle, int function,
67  struct acpi_buffer *params)
68 {
70  union acpi_object atpx_arg_elements[2];
71  struct acpi_object_list atpx_arg;
72  struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
73 
74  atpx_arg.count = 2;
75  atpx_arg.pointer = &atpx_arg_elements[0];
76 
77  atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
78  atpx_arg_elements[0].integer.value = function;
79 
80  if (params) {
81  atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
82  atpx_arg_elements[1].buffer.length = params->length;
83  atpx_arg_elements[1].buffer.pointer = params->pointer;
84  } else {
85  /* We need a second fake parameter */
86  atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
87  atpx_arg_elements[1].integer.value = 0;
88  }
89 
90  status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
91 
92  /* Fail only if calling the method fails and ATPX is supported */
93  if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
94  printk("failed to evaluate ATPX got %s\n",
95  acpi_format_exception(status));
96  kfree(buffer.pointer);
97  return NULL;
98  }
99 
100  return buffer.pointer;
101 }
102 
113 static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mask)
114 {
123 }
124 
136 static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
137 {
138  union acpi_object *info;
140  size_t size;
141  int err = 0;
142 
143  info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL);
144  if (!info)
145  return -EIO;
146 
147  memset(&output, 0, sizeof(output));
148 
149  size = *(u16 *) info->buffer.pointer;
150  if (size < 8) {
151  printk("ATPX buffer is too small: %zu\n", size);
152  err = -EINVAL;
153  goto out;
154  }
155  size = min(sizeof(output), size);
156 
157  memcpy(&output, info->buffer.pointer, size);
158 
159  /* TODO: check version? */
160  printk("ATPX version %u\n", output.version);
161 
162  radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
163 
164 out:
165  kfree(info);
166  return err;
167 }
168 
179 static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state)
180 {
181  struct acpi_buffer params;
182  union acpi_object *info;
183  struct atpx_power_control input;
184 
185  if (atpx->functions.power_cntl) {
186  input.size = 3;
187  input.dgpu_state = state;
188  params.length = input.size;
189  params.pointer = &input;
190  info = radeon_atpx_call(atpx->handle,
192  &params);
193  if (!info)
194  return -EIO;
195  kfree(info);
196  }
197  return 0;
198 }
199 
211 static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id)
212 {
213  struct acpi_buffer params;
214  union acpi_object *info;
215  struct atpx_mux input;
216 
217  if (atpx->functions.disp_mux_cntl) {
218  input.size = 4;
219  input.mux = mux_id;
220  params.length = input.size;
221  params.pointer = &input;
222  info = radeon_atpx_call(atpx->handle,
224  &params);
225  if (!info)
226  return -EIO;
227  kfree(info);
228  }
229  return 0;
230 }
231 
243 static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id)
244 {
245  struct acpi_buffer params;
246  union acpi_object *info;
247  struct atpx_mux input;
248 
249  if (atpx->functions.i2c_mux_cntl) {
250  input.size = 4;
251  input.mux = mux_id;
252  params.length = input.size;
253  params.pointer = &input;
254  info = radeon_atpx_call(atpx->handle,
256  &params);
257  if (!info)
258  return -EIO;
259  kfree(info);
260  }
261  return 0;
262 }
263 
275 static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id)
276 {
277  struct acpi_buffer params;
278  union acpi_object *info;
279  struct atpx_mux input;
280 
281  if (atpx->functions.switch_start) {
282  input.size = 4;
283  input.mux = mux_id;
284  params.length = input.size;
285  params.pointer = &input;
286  info = radeon_atpx_call(atpx->handle,
288  &params);
289  if (!info)
290  return -EIO;
291  kfree(info);
292  }
293  return 0;
294 }
295 
307 static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id)
308 {
309  struct acpi_buffer params;
310  union acpi_object *info;
311  struct atpx_mux input;
312 
313  if (atpx->functions.switch_end) {
314  input.size = 4;
315  input.mux = mux_id;
316  params.length = input.size;
317  params.pointer = &input;
318  info = radeon_atpx_call(atpx->handle,
320  &params);
321  if (!info)
322  return -EIO;
323  kfree(info);
324  }
325  return 0;
326 }
327 
337 static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
338 {
339  u16 gpu_id;
340 
341  if (id == VGA_SWITCHEROO_IGD)
342  gpu_id = ATPX_INTEGRATED_GPU;
343  else
344  gpu_id = ATPX_DISCRETE_GPU;
345 
346  radeon_atpx_switch_start(&radeon_atpx_priv.atpx, gpu_id);
347  radeon_atpx_switch_disp_mux(&radeon_atpx_priv.atpx, gpu_id);
348  radeon_atpx_switch_i2c_mux(&radeon_atpx_priv.atpx, gpu_id);
349  radeon_atpx_switch_end(&radeon_atpx_priv.atpx, gpu_id);
350 
351  return 0;
352 }
353 
364 static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
365  enum vga_switcheroo_state state)
366 {
367  /* on w500 ACPI can't change intel gpu state */
368  if (id == VGA_SWITCHEROO_IGD)
369  return 0;
370 
371  radeon_atpx_set_discrete_state(&radeon_atpx_priv.atpx, state);
372  return 0;
373 }
374 
383 static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
384 {
385  acpi_handle dhandle, atpx_handle;
387 
388  dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
389  if (!dhandle)
390  return false;
391 
392  status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
393  if (ACPI_FAILURE(status))
394  return false;
395 
396  radeon_atpx_priv.dhandle = dhandle;
397  radeon_atpx_priv.atpx.handle = atpx_handle;
398  return true;
399 }
400 
407 static int radeon_atpx_init(void)
408 {
409  /* set up the ATPX handle */
410  return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx);
411 }
412 
421 static int radeon_atpx_get_client_id(struct pci_dev *pdev)
422 {
423  if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
424  return VGA_SWITCHEROO_IGD;
425  else
426  return VGA_SWITCHEROO_DIS;
427 }
428 
429 static struct vga_switcheroo_handler radeon_atpx_handler = {
430  .switchto = radeon_atpx_switchto,
431  .power_state = radeon_atpx_power_state,
432  .init = radeon_atpx_init,
433  .get_client_id = radeon_atpx_get_client_id,
434 };
435 
442 static bool radeon_atpx_detect(void)
443 {
444  char acpi_method_name[255] = { 0 };
445  struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
446  struct pci_dev *pdev = NULL;
447  bool has_atpx = false;
448  int vga_count = 0;
449 
450  while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
451  vga_count++;
452 
453  has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
454  }
455 
456  if (has_atpx && vga_count == 2) {
457  acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
458  printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
459  acpi_method_name);
460  radeon_atpx_priv.atpx_detected = true;
461  return true;
462  }
463  return false;
464 }
465 
472 {
473  bool r;
474 
475  /* detect if we have any ATPX + 2 VGA in the system */
476  r = radeon_atpx_detect();
477  if (!r)
478  return;
479 
480  vga_switcheroo_register_handler(&radeon_atpx_handler);
481 }
482 
489 {
491 }