1 // SPDX-License-Identifier: GPL-2.0
5 * _DSM related code stolen from nouveau_acpi.c.
9 #include <linux/acpi.h>
12 #include "intel_acpi.h"
13 #include "intel_display_types.h"
15 #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
16 #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
18 static const guid_t intel_dsm_guid
=
19 GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
20 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
22 static char *intel_dsm_port_name(u8 id
)
40 return "DisplayPort_A";
42 return "DisplayPort_B";
44 return "DisplayPort_C";
46 return "DisplayPort_D";
58 static char *intel_dsm_mux_type(u8 type
)
64 return "No MUX, iGPU only";
66 return "No MUX, dGPU only";
68 return "MUXed between iGPU and dGPU";
74 static void intel_dsm_platform_mux_info(acpi_handle dhandle
)
77 union acpi_object
*pkg
, *connector_count
;
79 pkg
= acpi_evaluate_dsm_typed(dhandle
, &intel_dsm_guid
,
80 INTEL_DSM_REVISION_ID
, INTEL_DSM_FN_PLATFORM_MUX_INFO
,
81 NULL
, ACPI_TYPE_PACKAGE
);
83 DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
87 connector_count
= &pkg
->package
.elements
[0];
88 DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
89 (unsigned long long)connector_count
->integer
.value
);
90 for (i
= 1; i
< pkg
->package
.count
; i
++) {
91 union acpi_object
*obj
= &pkg
->package
.elements
[i
];
92 union acpi_object
*connector_id
= &obj
->package
.elements
[0];
93 union acpi_object
*info
= &obj
->package
.elements
[1];
94 DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
95 (unsigned long long)connector_id
->integer
.value
);
96 DRM_DEBUG_DRIVER(" port id: %s\n",
97 intel_dsm_port_name(info
->buffer
.pointer
[0]));
98 DRM_DEBUG_DRIVER(" display mux info: %s\n",
99 intel_dsm_mux_type(info
->buffer
.pointer
[1]));
100 DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",
101 intel_dsm_mux_type(info
->buffer
.pointer
[2]));
102 DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
103 intel_dsm_mux_type(info
->buffer
.pointer
[3]));
109 static acpi_handle
intel_dsm_pci_probe(struct pci_dev
*pdev
)
113 dhandle
= ACPI_HANDLE(&pdev
->dev
);
117 if (!acpi_check_dsm(dhandle
, &intel_dsm_guid
, INTEL_DSM_REVISION_ID
,
118 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO
)) {
119 DRM_DEBUG_KMS("no _DSM method for intel device\n");
123 intel_dsm_platform_mux_info(dhandle
);
128 static bool intel_dsm_detect(void)
130 acpi_handle dhandle
= NULL
;
131 char acpi_method_name
[255] = { 0 };
132 struct acpi_buffer buffer
= {sizeof(acpi_method_name
), acpi_method_name
};
133 struct pci_dev
*pdev
= NULL
;
136 while ((pdev
= pci_get_class(PCI_CLASS_DISPLAY_VGA
<< 8, pdev
)) != NULL
) {
138 dhandle
= intel_dsm_pci_probe(pdev
) ?: dhandle
;
141 if (vga_count
== 2 && dhandle
) {
142 acpi_get_name(dhandle
, ACPI_FULL_PATHNAME
, &buffer
);
143 DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
151 void intel_register_dsm_handler(void)
153 if (!intel_dsm_detect())
157 void intel_unregister_dsm_handler(void)
162 * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
163 * Attached to the Display Adapter).
165 #define ACPI_DISPLAY_INDEX_SHIFT 0
166 #define ACPI_DISPLAY_INDEX_MASK (0xf << 0)
167 #define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4
168 #define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4)
169 #define ACPI_DISPLAY_TYPE_SHIFT 8
170 #define ACPI_DISPLAY_TYPE_MASK (0xf << 8)
171 #define ACPI_DISPLAY_TYPE_OTHER (0 << 8)
172 #define ACPI_DISPLAY_TYPE_VGA (1 << 8)
173 #define ACPI_DISPLAY_TYPE_TV (2 << 8)
174 #define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8)
175 #define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8)
176 #define ACPI_VENDOR_SPECIFIC_SHIFT 12
177 #define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12)
178 #define ACPI_BIOS_CAN_DETECT (1 << 16)
179 #define ACPI_DEPENDS_ON_VGA (1 << 17)
180 #define ACPI_PIPE_ID_SHIFT 18
181 #define ACPI_PIPE_ID_MASK (7 << 18)
182 #define ACPI_DEVICE_ID_SCHEME (1ULL << 31)
184 static u32
acpi_display_type(struct intel_connector
*connector
)
188 switch (connector
->base
.connector_type
) {
189 case DRM_MODE_CONNECTOR_VGA
:
190 case DRM_MODE_CONNECTOR_DVIA
:
191 display_type
= ACPI_DISPLAY_TYPE_VGA
;
193 case DRM_MODE_CONNECTOR_Composite
:
194 case DRM_MODE_CONNECTOR_SVIDEO
:
195 case DRM_MODE_CONNECTOR_Component
:
196 case DRM_MODE_CONNECTOR_9PinDIN
:
197 case DRM_MODE_CONNECTOR_TV
:
198 display_type
= ACPI_DISPLAY_TYPE_TV
;
200 case DRM_MODE_CONNECTOR_DVII
:
201 case DRM_MODE_CONNECTOR_DVID
:
202 case DRM_MODE_CONNECTOR_DisplayPort
:
203 case DRM_MODE_CONNECTOR_HDMIA
:
204 case DRM_MODE_CONNECTOR_HDMIB
:
205 display_type
= ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL
;
207 case DRM_MODE_CONNECTOR_LVDS
:
208 case DRM_MODE_CONNECTOR_eDP
:
209 case DRM_MODE_CONNECTOR_DSI
:
210 display_type
= ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL
;
212 case DRM_MODE_CONNECTOR_Unknown
:
213 case DRM_MODE_CONNECTOR_VIRTUAL
:
214 display_type
= ACPI_DISPLAY_TYPE_OTHER
;
217 MISSING_CASE(connector
->base
.connector_type
);
218 display_type
= ACPI_DISPLAY_TYPE_OTHER
;
225 void intel_acpi_device_id_update(struct drm_i915_private
*dev_priv
)
227 struct drm_device
*drm_dev
= &dev_priv
->drm
;
228 struct intel_connector
*connector
;
229 struct drm_connector_list_iter conn_iter
;
230 u8 display_index
[16] = {};
232 /* Populate the ACPI IDs for all connectors for a given drm_device */
233 drm_connector_list_iter_begin(drm_dev
, &conn_iter
);
234 for_each_intel_connector_iter(connector
, &conn_iter
) {
237 device_id
= acpi_display_type(connector
);
239 /* Use display type specific display index. */
240 type
= (device_id
& ACPI_DISPLAY_TYPE_MASK
)
241 >> ACPI_DISPLAY_TYPE_SHIFT
;
242 device_id
|= display_index
[type
]++ << ACPI_DISPLAY_INDEX_SHIFT
;
244 connector
->acpi_device_id
= device_id
;
246 drm_connector_list_iter_end(&conn_iter
);