1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Intel ACPI functions
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * _DSM related code stolen from nouveau_acpi.c.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/pci.h>
9*4882a593Smuzhiyun #include <linux/acpi.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include "i915_drv.h"
12*4882a593Smuzhiyun #include "intel_acpi.h"
13*4882a593Smuzhiyun #include "intel_display_types.h"
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
16*4882a593Smuzhiyun #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun static const guid_t intel_dsm_guid =
19*4882a593Smuzhiyun GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
20*4882a593Smuzhiyun 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
21*4882a593Smuzhiyun
intel_dsm_port_name(u8 id)22*4882a593Smuzhiyun static char *intel_dsm_port_name(u8 id)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun switch (id) {
25*4882a593Smuzhiyun case 0:
26*4882a593Smuzhiyun return "Reserved";
27*4882a593Smuzhiyun case 1:
28*4882a593Smuzhiyun return "Analog VGA";
29*4882a593Smuzhiyun case 2:
30*4882a593Smuzhiyun return "LVDS";
31*4882a593Smuzhiyun case 3:
32*4882a593Smuzhiyun return "Reserved";
33*4882a593Smuzhiyun case 4:
34*4882a593Smuzhiyun return "HDMI/DVI_B";
35*4882a593Smuzhiyun case 5:
36*4882a593Smuzhiyun return "HDMI/DVI_C";
37*4882a593Smuzhiyun case 6:
38*4882a593Smuzhiyun return "HDMI/DVI_D";
39*4882a593Smuzhiyun case 7:
40*4882a593Smuzhiyun return "DisplayPort_A";
41*4882a593Smuzhiyun case 8:
42*4882a593Smuzhiyun return "DisplayPort_B";
43*4882a593Smuzhiyun case 9:
44*4882a593Smuzhiyun return "DisplayPort_C";
45*4882a593Smuzhiyun case 0xa:
46*4882a593Smuzhiyun return "DisplayPort_D";
47*4882a593Smuzhiyun case 0xb:
48*4882a593Smuzhiyun case 0xc:
49*4882a593Smuzhiyun case 0xd:
50*4882a593Smuzhiyun return "Reserved";
51*4882a593Smuzhiyun case 0xe:
52*4882a593Smuzhiyun return "WiDi";
53*4882a593Smuzhiyun default:
54*4882a593Smuzhiyun return "bad type";
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
intel_dsm_mux_type(u8 type)58*4882a593Smuzhiyun static char *intel_dsm_mux_type(u8 type)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun switch (type) {
61*4882a593Smuzhiyun case 0:
62*4882a593Smuzhiyun return "unknown";
63*4882a593Smuzhiyun case 1:
64*4882a593Smuzhiyun return "No MUX, iGPU only";
65*4882a593Smuzhiyun case 2:
66*4882a593Smuzhiyun return "No MUX, dGPU only";
67*4882a593Smuzhiyun case 3:
68*4882a593Smuzhiyun return "MUXed between iGPU and dGPU";
69*4882a593Smuzhiyun default:
70*4882a593Smuzhiyun return "bad type";
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
intel_dsm_platform_mux_info(acpi_handle dhandle)74*4882a593Smuzhiyun static void intel_dsm_platform_mux_info(acpi_handle dhandle)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun int i;
77*4882a593Smuzhiyun union acpi_object *pkg, *connector_count;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid,
80*4882a593Smuzhiyun INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
81*4882a593Smuzhiyun NULL, ACPI_TYPE_PACKAGE);
82*4882a593Smuzhiyun if (!pkg) {
83*4882a593Smuzhiyun DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
84*4882a593Smuzhiyun return;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (!pkg->package.count) {
88*4882a593Smuzhiyun DRM_DEBUG_DRIVER("no connection in _DSM\n");
89*4882a593Smuzhiyun return;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun connector_count = &pkg->package.elements[0];
93*4882a593Smuzhiyun DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
94*4882a593Smuzhiyun (unsigned long long)connector_count->integer.value);
95*4882a593Smuzhiyun for (i = 1; i < pkg->package.count; i++) {
96*4882a593Smuzhiyun union acpi_object *obj = &pkg->package.elements[i];
97*4882a593Smuzhiyun union acpi_object *connector_id;
98*4882a593Smuzhiyun union acpi_object *info;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
101*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Invalid object for MUX #%d\n", i);
102*4882a593Smuzhiyun continue;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun connector_id = &obj->package.elements[0];
106*4882a593Smuzhiyun info = &obj->package.elements[1];
107*4882a593Smuzhiyun if (info->type != ACPI_TYPE_BUFFER || info->buffer.length < 4) {
108*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Invalid info for MUX obj #%d\n", i);
109*4882a593Smuzhiyun continue;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
113*4882a593Smuzhiyun (unsigned long long)connector_id->integer.value);
114*4882a593Smuzhiyun DRM_DEBUG_DRIVER(" port id: %s\n",
115*4882a593Smuzhiyun intel_dsm_port_name(info->buffer.pointer[0]));
116*4882a593Smuzhiyun DRM_DEBUG_DRIVER(" display mux info: %s\n",
117*4882a593Smuzhiyun intel_dsm_mux_type(info->buffer.pointer[1]));
118*4882a593Smuzhiyun DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
119*4882a593Smuzhiyun intel_dsm_mux_type(info->buffer.pointer[2]));
120*4882a593Smuzhiyun DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
121*4882a593Smuzhiyun intel_dsm_mux_type(info->buffer.pointer[3]));
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun ACPI_FREE(pkg);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
intel_dsm_pci_probe(struct pci_dev * pdev)127*4882a593Smuzhiyun static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun acpi_handle dhandle;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun dhandle = ACPI_HANDLE(&pdev->dev);
132*4882a593Smuzhiyun if (!dhandle)
133*4882a593Smuzhiyun return NULL;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
136*4882a593Smuzhiyun 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
137*4882a593Smuzhiyun DRM_DEBUG_KMS("no _DSM method for intel device\n");
138*4882a593Smuzhiyun return NULL;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun intel_dsm_platform_mux_info(dhandle);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return dhandle;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
intel_dsm_detect(void)146*4882a593Smuzhiyun static bool intel_dsm_detect(void)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun acpi_handle dhandle = NULL;
149*4882a593Smuzhiyun char acpi_method_name[255] = { 0 };
150*4882a593Smuzhiyun struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
151*4882a593Smuzhiyun struct pci_dev *pdev = NULL;
152*4882a593Smuzhiyun int vga_count = 0;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
155*4882a593Smuzhiyun vga_count++;
156*4882a593Smuzhiyun dhandle = intel_dsm_pci_probe(pdev) ?: dhandle;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if (vga_count == 2 && dhandle) {
160*4882a593Smuzhiyun acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer);
161*4882a593Smuzhiyun DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
162*4882a593Smuzhiyun acpi_method_name);
163*4882a593Smuzhiyun return true;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun return false;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
intel_register_dsm_handler(void)169*4882a593Smuzhiyun void intel_register_dsm_handler(void)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun if (!intel_dsm_detect())
172*4882a593Smuzhiyun return;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
intel_unregister_dsm_handler(void)175*4882a593Smuzhiyun void intel_unregister_dsm_handler(void)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
181*4882a593Smuzhiyun * Attached to the Display Adapter).
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun #define ACPI_DISPLAY_INDEX_SHIFT 0
184*4882a593Smuzhiyun #define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
185*4882a593Smuzhiyun #define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
186*4882a593Smuzhiyun #define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
187*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_SHIFT 8
188*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
189*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
190*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_VGA (1 << 8)
191*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_TV (2 << 8)
192*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
193*4882a593Smuzhiyun #define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
194*4882a593Smuzhiyun #define ACPI_VENDOR_SPECIFIC_SHIFT 12
195*4882a593Smuzhiyun #define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
196*4882a593Smuzhiyun #define ACPI_BIOS_CAN_DETECT (1 << 16)
197*4882a593Smuzhiyun #define ACPI_DEPENDS_ON_VGA (1 << 17)
198*4882a593Smuzhiyun #define ACPI_PIPE_ID_SHIFT 18
199*4882a593Smuzhiyun #define ACPI_PIPE_ID_MASK (7 << 18)
200*4882a593Smuzhiyun #define ACPI_DEVICE_ID_SCHEME (1ULL << 31)
201*4882a593Smuzhiyun
acpi_display_type(struct intel_connector * connector)202*4882a593Smuzhiyun static u32 acpi_display_type(struct intel_connector *connector)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun u32 display_type;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun switch (connector->base.connector_type) {
207*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_VGA:
208*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DVIA:
209*4882a593Smuzhiyun display_type = ACPI_DISPLAY_TYPE_VGA;
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_Composite:
212*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_SVIDEO:
213*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_Component:
214*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_9PinDIN:
215*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_TV:
216*4882a593Smuzhiyun display_type = ACPI_DISPLAY_TYPE_TV;
217*4882a593Smuzhiyun break;
218*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DVII:
219*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DVID:
220*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DisplayPort:
221*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_HDMIA:
222*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_HDMIB:
223*4882a593Smuzhiyun display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
224*4882a593Smuzhiyun break;
225*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_LVDS:
226*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_eDP:
227*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_DSI:
228*4882a593Smuzhiyun display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
229*4882a593Smuzhiyun break;
230*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_Unknown:
231*4882a593Smuzhiyun case DRM_MODE_CONNECTOR_VIRTUAL:
232*4882a593Smuzhiyun display_type = ACPI_DISPLAY_TYPE_OTHER;
233*4882a593Smuzhiyun break;
234*4882a593Smuzhiyun default:
235*4882a593Smuzhiyun MISSING_CASE(connector->base.connector_type);
236*4882a593Smuzhiyun display_type = ACPI_DISPLAY_TYPE_OTHER;
237*4882a593Smuzhiyun break;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun return display_type;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
intel_acpi_device_id_update(struct drm_i915_private * dev_priv)243*4882a593Smuzhiyun void intel_acpi_device_id_update(struct drm_i915_private *dev_priv)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun struct drm_device *drm_dev = &dev_priv->drm;
246*4882a593Smuzhiyun struct intel_connector *connector;
247*4882a593Smuzhiyun struct drm_connector_list_iter conn_iter;
248*4882a593Smuzhiyun u8 display_index[16] = {};
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* Populate the ACPI IDs for all connectors for a given drm_device */
251*4882a593Smuzhiyun drm_connector_list_iter_begin(drm_dev, &conn_iter);
252*4882a593Smuzhiyun for_each_intel_connector_iter(connector, &conn_iter) {
253*4882a593Smuzhiyun u32 device_id, type;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun device_id = acpi_display_type(connector);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* Use display type specific display index. */
258*4882a593Smuzhiyun type = (device_id & ACPI_DISPLAY_TYPE_MASK)
259*4882a593Smuzhiyun >> ACPI_DISPLAY_TYPE_SHIFT;
260*4882a593Smuzhiyun device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun connector->acpi_device_id = device_id;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun drm_connector_list_iter_end(&conn_iter);
265*4882a593Smuzhiyun }
266