Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
intel_acpi.c
Go to the documentation of this file.
1 /*
2  * Intel ACPI functions
3  *
4  * _DSM related code stolen from nouveau_acpi.c.
5  */
6 #include <linux/pci.h>
7 #include <linux/acpi.h>
8 #include <linux/vga_switcheroo.h>
9 #include <acpi/acpi_drivers.h>
10 
11 #include <drm/drmP.h>
12 #include "i915_drv.h"
13 
14 #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
15 
16 #define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
17 #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
18 
19 static struct intel_dsm_priv {
20  acpi_handle dhandle;
21 } intel_dsm_priv;
22 
23 static const u8 intel_dsm_guid[] = {
24  0xd3, 0x73, 0xd8, 0x7e,
25  0xd0, 0xc2,
26  0x4f, 0x4e,
27  0xa8, 0x54,
28  0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
29 };
30 
31 static int intel_dsm(acpi_handle handle, int func, int arg)
32 {
34  struct acpi_object_list input;
35  union acpi_object params[4];
36  union acpi_object *obj;
37  u32 result;
38  int ret = 0;
39 
40  input.count = 4;
41  input.pointer = params;
42  params[0].type = ACPI_TYPE_BUFFER;
43  params[0].buffer.length = sizeof(intel_dsm_guid);
44  params[0].buffer.pointer = (char *)intel_dsm_guid;
45  params[1].type = ACPI_TYPE_INTEGER;
46  params[1].integer.value = INTEL_DSM_REVISION_ID;
47  params[2].type = ACPI_TYPE_INTEGER;
48  params[2].integer.value = func;
49  params[3].type = ACPI_TYPE_INTEGER;
50  params[3].integer.value = arg;
51 
52  ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
53  if (ret) {
54  DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
55  return ret;
56  }
57 
58  obj = (union acpi_object *)output.pointer;
59 
60  result = 0;
61  switch (obj->type) {
62  case ACPI_TYPE_INTEGER:
63  result = obj->integer.value;
64  break;
65 
66  case ACPI_TYPE_BUFFER:
67  if (obj->buffer.length == 4) {
68  result = (obj->buffer.pointer[0] |
69  (obj->buffer.pointer[1] << 8) |
70  (obj->buffer.pointer[2] << 16) |
71  (obj->buffer.pointer[3] << 24));
72  break;
73  }
74  default:
75  ret = -EINVAL;
76  break;
77  }
78  if (result == 0x80000002)
79  ret = -ENODEV;
80 
81  kfree(output.pointer);
82  return ret;
83 }
84 
85 static char *intel_dsm_port_name(u8 id)
86 {
87  switch (id) {
88  case 0:
89  return "Reserved";
90  case 1:
91  return "Analog VGA";
92  case 2:
93  return "LVDS";
94  case 3:
95  return "Reserved";
96  case 4:
97  return "HDMI/DVI_B";
98  case 5:
99  return "HDMI/DVI_C";
100  case 6:
101  return "HDMI/DVI_D";
102  case 7:
103  return "DisplayPort_A";
104  case 8:
105  return "DisplayPort_B";
106  case 9:
107  return "DisplayPort_C";
108  case 0xa:
109  return "DisplayPort_D";
110  case 0xb:
111  case 0xc:
112  case 0xd:
113  return "Reserved";
114  case 0xe:
115  return "WiDi";
116  default:
117  return "bad type";
118  }
119 }
120 
121 static char *intel_dsm_mux_type(u8 type)
122 {
123  switch (type) {
124  case 0:
125  return "unknown";
126  case 1:
127  return "No MUX, iGPU only";
128  case 2:
129  return "No MUX, dGPU only";
130  case 3:
131  return "MUXed between iGPU and dGPU";
132  default:
133  return "bad type";
134  }
135 }
136 
137 static void intel_dsm_platform_mux_info(void)
138 {
139  struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
140  struct acpi_object_list input;
141  union acpi_object params[4];
142  union acpi_object *pkg;
143  int i, ret;
144 
145  input.count = 4;
146  input.pointer = params;
147  params[0].type = ACPI_TYPE_BUFFER;
148  params[0].buffer.length = sizeof(intel_dsm_guid);
149  params[0].buffer.pointer = (char *)intel_dsm_guid;
150  params[1].type = ACPI_TYPE_INTEGER;
151  params[1].integer.value = INTEL_DSM_REVISION_ID;
152  params[2].type = ACPI_TYPE_INTEGER;
153  params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
154  params[3].type = ACPI_TYPE_INTEGER;
155  params[3].integer.value = 0;
156 
157  ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
158  &output);
159  if (ret) {
160  DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
161  goto out;
162  }
163 
164  pkg = (union acpi_object *)output.pointer;
165 
166  if (pkg->type == ACPI_TYPE_PACKAGE) {
167  union acpi_object *connector_count = &pkg->package.elements[0];
168  DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
169  (unsigned long long)connector_count->integer.value);
170  for (i = 1; i < pkg->package.count; i++) {
171  union acpi_object *obj = &pkg->package.elements[i];
172  union acpi_object *connector_id =
173  &obj->package.elements[0];
174  union acpi_object *info = &obj->package.elements[1];
175  DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
176  (unsigned long long)connector_id->integer.value);
177  DRM_DEBUG_DRIVER(" port id: %s\n",
178  intel_dsm_port_name(info->buffer.pointer[0]));
179  DRM_DEBUG_DRIVER(" display mux info: %s\n",
180  intel_dsm_mux_type(info->buffer.pointer[1]));
181  DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
182  intel_dsm_mux_type(info->buffer.pointer[2]));
183  DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
184  intel_dsm_mux_type(info->buffer.pointer[3]));
185  }
186  }
187 
188 out:
189  kfree(output.pointer);
190 }
191 
192 static bool intel_dsm_pci_probe(struct pci_dev *pdev)
193 {
194  acpi_handle dhandle, intel_handle;
196  int ret;
197 
198  dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
199  if (!dhandle)
200  return false;
201 
202  status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
203  if (ACPI_FAILURE(status)) {
204  DRM_DEBUG_KMS("no _DSM method for intel device\n");
205  return false;
206  }
207 
208  ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
209  if (ret < 0) {
210  DRM_DEBUG_KMS("failed to get supported _DSM functions\n");
211  return false;
212  }
213 
214  intel_dsm_priv.dhandle = dhandle;
215 
216  intel_dsm_platform_mux_info();
217  return true;
218 }
219 
220 static bool intel_dsm_detect(void)
221 {
222  char acpi_method_name[255] = { 0 };
223  struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
224  struct pci_dev *pdev = NULL;
225  bool has_dsm = false;
226  int vga_count = 0;
227 
228  while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
229  vga_count++;
230  has_dsm |= intel_dsm_pci_probe(pdev);
231  }
232 
233  if (vga_count == 2 && has_dsm) {
234  acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
235  DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
236  acpi_method_name);
237  return true;
238  }
239 
240  return false;
241 }
242 
244 {
245  if (!intel_dsm_detect())
246  return;
247 }
248 
250 {
251 }