intel_acpi.c (8782B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Intel ACPI functions 4 * 5 * _DSM related code stolen from nouveau_acpi.c. 6 */ 7 8#include <linux/pci.h> 9#include <linux/acpi.h> 10 11#include "i915_drv.h" 12#include "intel_acpi.h" 13#include "intel_display_types.h" 14 15#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ 16#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ 17 18static const guid_t intel_dsm_guid = 19 GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f, 20 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c); 21 22#define INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED 0 /* No args */ 23 24static const guid_t intel_dsm_guid2 = 25 GUID_INIT(0x3e5b41c6, 0xeb1d, 0x4260, 26 0x9d, 0x15, 0xc7, 0x1f, 0xba, 0xda, 0xe4, 0x14); 27 28static char *intel_dsm_port_name(u8 id) 29{ 30 switch (id) { 31 case 0: 32 return "Reserved"; 33 case 1: 34 return "Analog VGA"; 35 case 2: 36 return "LVDS"; 37 case 3: 38 return "Reserved"; 39 case 4: 40 return "HDMI/DVI_B"; 41 case 5: 42 return "HDMI/DVI_C"; 43 case 6: 44 return "HDMI/DVI_D"; 45 case 7: 46 return "DisplayPort_A"; 47 case 8: 48 return "DisplayPort_B"; 49 case 9: 50 return "DisplayPort_C"; 51 case 0xa: 52 return "DisplayPort_D"; 53 case 0xb: 54 case 0xc: 55 case 0xd: 56 return "Reserved"; 57 case 0xe: 58 return "WiDi"; 59 default: 60 return "bad type"; 61 } 62} 63 64static char *intel_dsm_mux_type(u8 type) 65{ 66 switch (type) { 67 case 0: 68 return "unknown"; 69 case 1: 70 return "No MUX, iGPU only"; 71 case 2: 72 return "No MUX, dGPU only"; 73 case 3: 74 return "MUXed between iGPU and dGPU"; 75 default: 76 return "bad type"; 77 } 78} 79 80static void intel_dsm_platform_mux_info(acpi_handle dhandle) 81{ 82 int i; 83 union acpi_object *pkg, *connector_count; 84 85 pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid, 86 INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, 87 NULL, ACPI_TYPE_PACKAGE); 88 if (!pkg) { 89 DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); 90 return; 91 } 92 93 if (!pkg->package.count) { 94 DRM_DEBUG_DRIVER("no connection in _DSM\n"); 95 return; 96 } 97 98 connector_count = &pkg->package.elements[0]; 99 DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", 100 (unsigned long long)connector_count->integer.value); 101 for (i = 1; i < pkg->package.count; i++) { 102 union acpi_object *obj = &pkg->package.elements[i]; 103 union acpi_object *connector_id; 104 union acpi_object *info; 105 106 if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) { 107 DRM_DEBUG_DRIVER("Invalid object for MUX #%d\n", i); 108 continue; 109 } 110 111 connector_id = &obj->package.elements[0]; 112 info = &obj->package.elements[1]; 113 if (info->type != ACPI_TYPE_BUFFER || info->buffer.length < 4) { 114 DRM_DEBUG_DRIVER("Invalid info for MUX obj #%d\n", i); 115 continue; 116 } 117 118 DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", 119 (unsigned long long)connector_id->integer.value); 120 DRM_DEBUG_DRIVER(" port id: %s\n", 121 intel_dsm_port_name(info->buffer.pointer[0])); 122 DRM_DEBUG_DRIVER(" display mux info: %s\n", 123 intel_dsm_mux_type(info->buffer.pointer[1])); 124 DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", 125 intel_dsm_mux_type(info->buffer.pointer[2])); 126 DRM_DEBUG_DRIVER(" hpd mux info: %s\n", 127 intel_dsm_mux_type(info->buffer.pointer[3])); 128 } 129 130 ACPI_FREE(pkg); 131} 132 133static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev) 134{ 135 acpi_handle dhandle; 136 137 dhandle = ACPI_HANDLE(&pdev->dev); 138 if (!dhandle) 139 return NULL; 140 141 if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID, 142 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { 143 DRM_DEBUG_KMS("no _DSM method for intel device\n"); 144 return NULL; 145 } 146 147 intel_dsm_platform_mux_info(dhandle); 148 149 return dhandle; 150} 151 152static bool intel_dsm_detect(void) 153{ 154 acpi_handle dhandle = NULL; 155 char acpi_method_name[255] = { 0 }; 156 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 157 struct pci_dev *pdev = NULL; 158 int vga_count = 0; 159 160 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 161 vga_count++; 162 dhandle = intel_dsm_pci_probe(pdev) ?: dhandle; 163 } 164 165 if (vga_count == 2 && dhandle) { 166 acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer); 167 DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n", 168 acpi_method_name); 169 return true; 170 } 171 172 return false; 173} 174 175void intel_register_dsm_handler(void) 176{ 177 if (!intel_dsm_detect()) 178 return; 179} 180 181void intel_unregister_dsm_handler(void) 182{ 183} 184 185void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915) 186{ 187 struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 188 acpi_handle dhandle; 189 union acpi_object *obj; 190 191 dhandle = ACPI_HANDLE(&pdev->dev); 192 if (!dhandle) 193 return; 194 195 obj = acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID, 196 INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL); 197 if (obj) 198 ACPI_FREE(obj); 199} 200 201/* 202 * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices 203 * Attached to the Display Adapter). 204 */ 205#define ACPI_DISPLAY_INDEX_SHIFT 0 206#define ACPI_DISPLAY_INDEX_MASK (0xf << 0) 207#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4 208#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4) 209#define ACPI_DISPLAY_TYPE_SHIFT 8 210#define ACPI_DISPLAY_TYPE_MASK (0xf << 8) 211#define ACPI_DISPLAY_TYPE_OTHER (0 << 8) 212#define ACPI_DISPLAY_TYPE_VGA (1 << 8) 213#define ACPI_DISPLAY_TYPE_TV (2 << 8) 214#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8) 215#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8) 216#define ACPI_VENDOR_SPECIFIC_SHIFT 12 217#define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12) 218#define ACPI_BIOS_CAN_DETECT (1 << 16) 219#define ACPI_DEPENDS_ON_VGA (1 << 17) 220#define ACPI_PIPE_ID_SHIFT 18 221#define ACPI_PIPE_ID_MASK (7 << 18) 222#define ACPI_DEVICE_ID_SCHEME (1ULL << 31) 223 224static u32 acpi_display_type(struct intel_connector *connector) 225{ 226 u32 display_type; 227 228 switch (connector->base.connector_type) { 229 case DRM_MODE_CONNECTOR_VGA: 230 case DRM_MODE_CONNECTOR_DVIA: 231 display_type = ACPI_DISPLAY_TYPE_VGA; 232 break; 233 case DRM_MODE_CONNECTOR_Composite: 234 case DRM_MODE_CONNECTOR_SVIDEO: 235 case DRM_MODE_CONNECTOR_Component: 236 case DRM_MODE_CONNECTOR_9PinDIN: 237 case DRM_MODE_CONNECTOR_TV: 238 display_type = ACPI_DISPLAY_TYPE_TV; 239 break; 240 case DRM_MODE_CONNECTOR_DVII: 241 case DRM_MODE_CONNECTOR_DVID: 242 case DRM_MODE_CONNECTOR_DisplayPort: 243 case DRM_MODE_CONNECTOR_HDMIA: 244 case DRM_MODE_CONNECTOR_HDMIB: 245 display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL; 246 break; 247 case DRM_MODE_CONNECTOR_LVDS: 248 case DRM_MODE_CONNECTOR_eDP: 249 case DRM_MODE_CONNECTOR_DSI: 250 display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL; 251 break; 252 case DRM_MODE_CONNECTOR_Unknown: 253 case DRM_MODE_CONNECTOR_VIRTUAL: 254 display_type = ACPI_DISPLAY_TYPE_OTHER; 255 break; 256 default: 257 MISSING_CASE(connector->base.connector_type); 258 display_type = ACPI_DISPLAY_TYPE_OTHER; 259 break; 260 } 261 262 return display_type; 263} 264 265void intel_acpi_device_id_update(struct drm_i915_private *dev_priv) 266{ 267 struct drm_device *drm_dev = &dev_priv->drm; 268 struct intel_connector *connector; 269 struct drm_connector_list_iter conn_iter; 270 u8 display_index[16] = {}; 271 272 /* Populate the ACPI IDs for all connectors for a given drm_device */ 273 drm_connector_list_iter_begin(drm_dev, &conn_iter); 274 for_each_intel_connector_iter(connector, &conn_iter) { 275 u32 device_id, type; 276 277 device_id = acpi_display_type(connector); 278 279 /* Use display type specific display index. */ 280 type = (device_id & ACPI_DISPLAY_TYPE_MASK) 281 >> ACPI_DISPLAY_TYPE_SHIFT; 282 device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT; 283 284 connector->acpi_device_id = device_id; 285 } 286 drm_connector_list_iter_end(&conn_iter); 287} 288 289/* NOTE: The connector order must be final before this is called. */ 290void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) 291{ 292 struct drm_connector_list_iter conn_iter; 293 struct drm_device *drm_dev = &i915->drm; 294 struct fwnode_handle *fwnode = NULL; 295 struct drm_connector *connector; 296 struct acpi_device *adev; 297 298 drm_connector_list_iter_begin(drm_dev, &conn_iter); 299 drm_for_each_connector_iter(connector, &conn_iter) { 300 /* Always getting the next, even when the last was not used. */ 301 fwnode = device_get_next_child_node(drm_dev->dev, fwnode); 302 if (!fwnode) 303 break; 304 305 switch (connector->connector_type) { 306 case DRM_MODE_CONNECTOR_LVDS: 307 case DRM_MODE_CONNECTOR_eDP: 308 case DRM_MODE_CONNECTOR_DSI: 309 /* 310 * Integrated displays have a specific address 0x1f on 311 * most Intel platforms, but not on all of them. 312 */ 313 adev = acpi_find_child_device(ACPI_COMPANION(drm_dev->dev), 314 0x1f, 0); 315 if (adev) { 316 connector->fwnode = 317 fwnode_handle_get(acpi_fwnode_handle(adev)); 318 break; 319 } 320 fallthrough; 321 default: 322 connector->fwnode = fwnode_handle_get(fwnode); 323 break; 324 } 325 } 326 drm_connector_list_iter_end(&conn_iter); 327 /* 328 * device_get_next_child_node() takes a reference on the fwnode, if 329 * we stopped iterating because we are out of connectors we need to 330 * put this, otherwise fwnode is NULL and the put is a no-op. 331 */ 332 fwnode_handle_put(fwnode); 333}