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