1 /* 2 * Intel ACPI functions 3 * 4 * _DSM related code stolen from nouveau_acpi.c. 5 */ 6 #include <linux/pci.h> 7 #include <linux/acpi.h> 8 #include <drm/drmP.h> 9 #include "i915_drv.h" 10 11 #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ 12 #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ 13 14 #if 0 15 static struct intel_dsm_priv { 16 acpi_handle dhandle; 17 } intel_dsm_priv; 18 19 static const guid_t intel_dsm_guid = 20 GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f, 21 0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c); 22 23 static char *intel_dsm_port_name(u8 id) 24 { 25 switch (id) { 26 case 0: 27 return "Reserved"; 28 case 1: 29 return "Analog VGA"; 30 case 2: 31 return "LVDS"; 32 case 3: 33 return "Reserved"; 34 case 4: 35 return "HDMI/DVI_B"; 36 case 5: 37 return "HDMI/DVI_C"; 38 case 6: 39 return "HDMI/DVI_D"; 40 case 7: 41 return "DisplayPort_A"; 42 case 8: 43 return "DisplayPort_B"; 44 case 9: 45 return "DisplayPort_C"; 46 case 0xa: 47 return "DisplayPort_D"; 48 case 0xb: 49 case 0xc: 50 case 0xd: 51 return "Reserved"; 52 case 0xe: 53 return "WiDi"; 54 default: 55 return "bad type"; 56 } 57 } 58 59 static char *intel_dsm_mux_type(u8 type) 60 { 61 switch (type) { 62 case 0: 63 return "unknown"; 64 case 1: 65 return "No MUX, iGPU only"; 66 case 2: 67 return "No MUX, dGPU only"; 68 case 3: 69 return "MUXed between iGPU and dGPU"; 70 default: 71 return "bad type"; 72 } 73 } 74 75 static void intel_dsm_platform_mux_info(void) 76 { 77 int i; 78 union acpi_object *pkg, *connector_count; 79 80 pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, &intel_dsm_guid, 81 INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO, 82 NULL, ACPI_TYPE_PACKAGE); 83 if (!pkg) { 84 DRM_DEBUG_DRIVER("failed to evaluate _DSM\n"); 85 return; 86 } 87 88 connector_count = &pkg->package.elements[0]; 89 DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", 90 (unsigned long long)connector_count->integer.value); 91 for (i = 1; i < pkg->package.count; i++) { 92 union acpi_object *obj = &pkg->package.elements[i]; 93 union acpi_object *connector_id = &obj->package.elements[0]; 94 union acpi_object *info = &obj->package.elements[1]; 95 DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", 96 (unsigned long long)connector_id->integer.value); 97 DRM_DEBUG_DRIVER(" port id: %s\n", 98 intel_dsm_port_name(info->buffer.pointer[0])); 99 DRM_DEBUG_DRIVER(" display mux info: %s\n", 100 intel_dsm_mux_type(info->buffer.pointer[1])); 101 DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", 102 intel_dsm_mux_type(info->buffer.pointer[2])); 103 DRM_DEBUG_DRIVER(" hpd mux info: %s\n", 104 intel_dsm_mux_type(info->buffer.pointer[3])); 105 } 106 107 ACPI_FREE(pkg); 108 } 109 110 static bool intel_dsm_pci_probe(struct pci_dev *pdev) 111 { 112 acpi_handle dhandle; 113 114 dhandle = ACPI_HANDLE(&pdev->dev); 115 if (!dhandle) 116 return false; 117 118 if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID, 119 1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) { 120 DRM_DEBUG_KMS("no _DSM method for intel device\n"); 121 return false; 122 } 123 124 intel_dsm_priv.dhandle = dhandle; 125 intel_dsm_platform_mux_info(); 126 127 return true; 128 } 129 130 static bool intel_dsm_detect(void) 131 { 132 char acpi_method_name[255] = { 0 }; 133 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 134 struct pci_dev *pdev = NULL; 135 bool has_dsm = false; 136 int vga_count = 0; 137 138 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 139 vga_count++; 140 has_dsm |= intel_dsm_pci_probe(pdev); 141 } 142 143 if (vga_count == 2 && has_dsm) { 144 acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 145 DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n", 146 acpi_method_name); 147 return true; 148 } 149 150 return false; 151 } 152 153 void intel_register_dsm_handler(void) 154 { 155 if (!intel_dsm_detect()) 156 return; 157 } 158 #endif 159 160 void intel_unregister_dsm_handler(void) 161 { 162 } 163