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 18 static 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 24 static const guid_t intel_dsm_guid2 = 25 GUID_INIT(0x3e5b41c6, 0xeb1d, 0x4260, 26 0x9d, 0x15, 0xc7, 0x1f, 0xba, 0xda, 0xe4, 0x14); 27 28 static 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 64 static 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 80 static 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 133 static 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 152 static 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 175 void intel_register_dsm_handler(void) 176 { 177 if (!intel_dsm_detect()) 178 return; 179 } 180 181 void intel_unregister_dsm_handler(void) 182 { 183 } 184 185 void 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 190 dhandle = ACPI_HANDLE(&pdev->dev); 191 if (!dhandle) 192 return; 193 194 acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID, 195 INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL); 196 } 197 198 /* 199 * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices 200 * Attached to the Display Adapter). 201 */ 202 #define ACPI_DISPLAY_INDEX_SHIFT 0 203 #define ACPI_DISPLAY_INDEX_MASK (0xf << 0) 204 #define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT 4 205 #define ACPI_DISPLAY_PORT_ATTACHMENT_MASK (0xf << 4) 206 #define ACPI_DISPLAY_TYPE_SHIFT 8 207 #define ACPI_DISPLAY_TYPE_MASK (0xf << 8) 208 #define ACPI_DISPLAY_TYPE_OTHER (0 << 8) 209 #define ACPI_DISPLAY_TYPE_VGA (1 << 8) 210 #define ACPI_DISPLAY_TYPE_TV (2 << 8) 211 #define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL (3 << 8) 212 #define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL (4 << 8) 213 #define ACPI_VENDOR_SPECIFIC_SHIFT 12 214 #define ACPI_VENDOR_SPECIFIC_MASK (0xf << 12) 215 #define ACPI_BIOS_CAN_DETECT (1 << 16) 216 #define ACPI_DEPENDS_ON_VGA (1 << 17) 217 #define ACPI_PIPE_ID_SHIFT 18 218 #define ACPI_PIPE_ID_MASK (7 << 18) 219 #define ACPI_DEVICE_ID_SCHEME (1ULL << 31) 220 221 static u32 acpi_display_type(struct intel_connector *connector) 222 { 223 u32 display_type; 224 225 switch (connector->base.connector_type) { 226 case DRM_MODE_CONNECTOR_VGA: 227 case DRM_MODE_CONNECTOR_DVIA: 228 display_type = ACPI_DISPLAY_TYPE_VGA; 229 break; 230 case DRM_MODE_CONNECTOR_Composite: 231 case DRM_MODE_CONNECTOR_SVIDEO: 232 case DRM_MODE_CONNECTOR_Component: 233 case DRM_MODE_CONNECTOR_9PinDIN: 234 case DRM_MODE_CONNECTOR_TV: 235 display_type = ACPI_DISPLAY_TYPE_TV; 236 break; 237 case DRM_MODE_CONNECTOR_DVII: 238 case DRM_MODE_CONNECTOR_DVID: 239 case DRM_MODE_CONNECTOR_DisplayPort: 240 case DRM_MODE_CONNECTOR_HDMIA: 241 case DRM_MODE_CONNECTOR_HDMIB: 242 display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL; 243 break; 244 case DRM_MODE_CONNECTOR_LVDS: 245 case DRM_MODE_CONNECTOR_eDP: 246 case DRM_MODE_CONNECTOR_DSI: 247 display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL; 248 break; 249 case DRM_MODE_CONNECTOR_Unknown: 250 case DRM_MODE_CONNECTOR_VIRTUAL: 251 display_type = ACPI_DISPLAY_TYPE_OTHER; 252 break; 253 default: 254 MISSING_CASE(connector->base.connector_type); 255 display_type = ACPI_DISPLAY_TYPE_OTHER; 256 break; 257 } 258 259 return display_type; 260 } 261 262 void intel_acpi_device_id_update(struct drm_i915_private *dev_priv) 263 { 264 struct drm_device *drm_dev = &dev_priv->drm; 265 struct intel_connector *connector; 266 struct drm_connector_list_iter conn_iter; 267 u8 display_index[16] = {}; 268 269 /* Populate the ACPI IDs for all connectors for a given drm_device */ 270 drm_connector_list_iter_begin(drm_dev, &conn_iter); 271 for_each_intel_connector_iter(connector, &conn_iter) { 272 u32 device_id, type; 273 274 device_id = acpi_display_type(connector); 275 276 /* Use display type specific display index. */ 277 type = (device_id & ACPI_DISPLAY_TYPE_MASK) 278 >> ACPI_DISPLAY_TYPE_SHIFT; 279 device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT; 280 281 connector->acpi_device_id = device_id; 282 } 283 drm_connector_list_iter_end(&conn_iter); 284 } 285