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