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