15d0b1887SFrançois Tigeot /* 25d0b1887SFrançois Tigeot * Intel ACPI functions 35d0b1887SFrançois Tigeot * 45d0b1887SFrançois Tigeot * _DSM related code stolen from nouveau_acpi.c. 55d0b1887SFrançois Tigeot */ 65d0b1887SFrançois Tigeot #include <linux/pci.h> 75d0b1887SFrançois Tigeot 85d0b1887SFrançois Tigeot #include <drm/drmP.h> 95d0b1887SFrançois Tigeot #include "i915_drv.h" 105d0b1887SFrançois Tigeot 115d0b1887SFrançois Tigeot #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ 125d0b1887SFrançois Tigeot #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ 135d0b1887SFrançois Tigeot 145d0b1887SFrançois Tigeot #if 0 155d0b1887SFrançois Tigeot static struct intel_dsm_priv { 165d0b1887SFrançois Tigeot acpi_handle dhandle; 175d0b1887SFrançois Tigeot } intel_dsm_priv; 185d0b1887SFrançois Tigeot 195d0b1887SFrançois Tigeot static const u8 intel_dsm_guid[] = { 205d0b1887SFrançois Tigeot 0xd3, 0x73, 0xd8, 0x7e, 215d0b1887SFrançois Tigeot 0xd0, 0xc2, 225d0b1887SFrançois Tigeot 0x4f, 0x4e, 235d0b1887SFrançois Tigeot 0xa8, 0x54, 245d0b1887SFrançois Tigeot 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c 255d0b1887SFrançois Tigeot }; 265d0b1887SFrançois Tigeot 275d0b1887SFrançois Tigeot static char *intel_dsm_port_name(u8 id) 285d0b1887SFrançois Tigeot { 295d0b1887SFrançois Tigeot switch (id) { 305d0b1887SFrançois Tigeot case 0: 315d0b1887SFrançois Tigeot return "Reserved"; 325d0b1887SFrançois Tigeot case 1: 335d0b1887SFrançois Tigeot return "Analog VGA"; 345d0b1887SFrançois Tigeot case 2: 355d0b1887SFrançois Tigeot return "LVDS"; 365d0b1887SFrançois Tigeot case 3: 375d0b1887SFrançois Tigeot return "Reserved"; 385d0b1887SFrançois Tigeot case 4: 395d0b1887SFrançois Tigeot return "HDMI/DVI_B"; 405d0b1887SFrançois Tigeot case 5: 415d0b1887SFrançois Tigeot return "HDMI/DVI_C"; 425d0b1887SFrançois Tigeot case 6: 435d0b1887SFrançois Tigeot return "HDMI/DVI_D"; 445d0b1887SFrançois Tigeot case 7: 455d0b1887SFrançois Tigeot return "DisplayPort_A"; 465d0b1887SFrançois Tigeot case 8: 475d0b1887SFrançois Tigeot return "DisplayPort_B"; 485d0b1887SFrançois Tigeot case 9: 495d0b1887SFrançois Tigeot return "DisplayPort_C"; 505d0b1887SFrançois Tigeot case 0xa: 515d0b1887SFrançois Tigeot return "DisplayPort_D"; 525d0b1887SFrançois Tigeot case 0xb: 535d0b1887SFrançois Tigeot case 0xc: 545d0b1887SFrançois Tigeot case 0xd: 555d0b1887SFrançois Tigeot return "Reserved"; 565d0b1887SFrançois Tigeot case 0xe: 575d0b1887SFrançois Tigeot return "WiDi"; 585d0b1887SFrançois Tigeot default: 595d0b1887SFrançois Tigeot return "bad type"; 605d0b1887SFrançois Tigeot } 615d0b1887SFrançois Tigeot } 625d0b1887SFrançois Tigeot 635d0b1887SFrançois Tigeot static char *intel_dsm_mux_type(u8 type) 645d0b1887SFrançois Tigeot { 655d0b1887SFrançois Tigeot switch (type) { 665d0b1887SFrançois Tigeot case 0: 675d0b1887SFrançois Tigeot return "unknown"; 685d0b1887SFrançois Tigeot case 1: 695d0b1887SFrançois Tigeot return "No MUX, iGPU only"; 705d0b1887SFrançois Tigeot case 2: 715d0b1887SFrançois Tigeot return "No MUX, dGPU only"; 725d0b1887SFrançois Tigeot case 3: 735d0b1887SFrançois Tigeot return "MUXed between iGPU and dGPU"; 745d0b1887SFrançois Tigeot default: 755d0b1887SFrançois Tigeot return "bad type"; 765d0b1887SFrançois Tigeot } 775d0b1887SFrançois Tigeot } 785d0b1887SFrançois Tigeot 795d0b1887SFrançois Tigeot static void intel_dsm_platform_mux_info(void) 805d0b1887SFrançois Tigeot { 81*9edbd4a0SFrançois Tigeot int i; 82*9edbd4a0SFrançois Tigeot union acpi_object *pkg, *connector_count; 835d0b1887SFrançois Tigeot 84*9edbd4a0SFrançois Tigeot pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid, 85*9edbd4a0SFrançois Tigeot INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, 86*9edbd4a0SFrançois Tigeot NULL, ACPI_TYPE_PACKAGE); 87*9edbd4a0SFrançois Tigeot if (!pkg) { 88*9edbd4a0SFrançois Tigeot DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); 89*9edbd4a0SFrançois Tigeot return; 905d0b1887SFrançois Tigeot } 915d0b1887SFrançois Tigeot 92*9edbd4a0SFrançois Tigeot connector_count = &pkg->package.elements[0]; 935d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", 945d0b1887SFrançois Tigeot (unsigned long long)connector_count->integer.value); 955d0b1887SFrançois Tigeot for (i = 1; i < pkg->package.count; i++) { 965d0b1887SFrançois Tigeot union acpi_object *obj = &pkg->package.elements[i]; 97*9edbd4a0SFrançois Tigeot union acpi_object *connector_id = &obj->package.elements[0]; 985d0b1887SFrançois Tigeot union acpi_object *info = &obj->package.elements[1]; 995d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", 1005d0b1887SFrançois Tigeot (unsigned long long)connector_id->integer.value); 1015d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" port id: %s\n", 1025d0b1887SFrançois Tigeot intel_dsm_port_name(info->buffer.pointer[0])); 1035d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" display mux info: %s\n", 1045d0b1887SFrançois Tigeot intel_dsm_mux_type(info->buffer.pointer[1])); 1055d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", 1065d0b1887SFrançois Tigeot intel_dsm_mux_type(info->buffer.pointer[2])); 1075d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER(" hpd mux info: %s\n", 1085d0b1887SFrançois Tigeot intel_dsm_mux_type(info->buffer.pointer[3])); 1095d0b1887SFrançois Tigeot } 1105d0b1887SFrançois Tigeot 111*9edbd4a0SFrançois Tigeot ACPI_FREE(pkg); 1125d0b1887SFrançois Tigeot } 1135d0b1887SFrançois Tigeot 1145d0b1887SFrançois Tigeot static bool intel_dsm_pci_probe(struct pci_dev *pdev) 1155d0b1887SFrançois Tigeot { 116*9edbd4a0SFrançois Tigeot acpi_handle dhandle; 1175d0b1887SFrançois Tigeot 118*9edbd4a0SFrançois Tigeot dhandle = ACPI_HANDLE(&pdev->dev); 1195d0b1887SFrançois Tigeot if (!dhandle) 1205d0b1887SFrançois Tigeot return false; 1215d0b1887SFrançois Tigeot 122*9edbd4a0SFrançois Tigeot if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID, 123*9edbd4a0SFrançois Tigeot 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { 1245d0b1887SFrançois Tigeot DRM_DEBUG_KMS("no _DSM method for intel device\n"); 1255d0b1887SFrançois Tigeot return false; 1265d0b1887SFrançois Tigeot } 1275d0b1887SFrançois Tigeot 1285d0b1887SFrançois Tigeot intel_dsm_priv.dhandle = dhandle; 1295d0b1887SFrançois Tigeot intel_dsm_platform_mux_info(); 130*9edbd4a0SFrançois Tigeot 1315d0b1887SFrançois Tigeot return true; 1325d0b1887SFrançois Tigeot } 1335d0b1887SFrançois Tigeot 1345d0b1887SFrançois Tigeot static bool intel_dsm_detect(void) 1355d0b1887SFrançois Tigeot { 1365d0b1887SFrançois Tigeot char acpi_method_name[255] = { 0 }; 1375d0b1887SFrançois Tigeot struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 1385d0b1887SFrançois Tigeot struct pci_dev *pdev = NULL; 1395d0b1887SFrançois Tigeot bool has_dsm = false; 1405d0b1887SFrançois Tigeot int vga_count = 0; 1415d0b1887SFrançois Tigeot 1425d0b1887SFrançois Tigeot while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 1435d0b1887SFrançois Tigeot vga_count++; 1445d0b1887SFrançois Tigeot has_dsm |= intel_dsm_pci_probe(pdev); 1455d0b1887SFrançois Tigeot } 1465d0b1887SFrançois Tigeot 1475d0b1887SFrançois Tigeot if (vga_count == 2 && has_dsm) { 1485d0b1887SFrançois Tigeot acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 1495d0b1887SFrançois Tigeot DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n", 1505d0b1887SFrançois Tigeot acpi_method_name); 1515d0b1887SFrançois Tigeot return true; 1525d0b1887SFrançois Tigeot } 1535d0b1887SFrançois Tigeot 1545d0b1887SFrançois Tigeot return false; 1555d0b1887SFrançois Tigeot } 1565d0b1887SFrançois Tigeot 1575d0b1887SFrançois Tigeot void intel_register_dsm_handler(void) 1585d0b1887SFrançois Tigeot { 1595d0b1887SFrançois Tigeot if (!intel_dsm_detect()) 1605d0b1887SFrançois Tigeot return; 1615d0b1887SFrançois Tigeot } 1625d0b1887SFrançois Tigeot #endif 1635d0b1887SFrançois Tigeot 1645d0b1887SFrançois Tigeot void intel_unregister_dsm_handler(void) 1655d0b1887SFrançois Tigeot { 1665d0b1887SFrançois Tigeot } 167