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 13 #define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */ 14 #define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ 15 16 #if 0 17 static struct intel_dsm_priv { 18 acpi_handle dhandle; 19 } intel_dsm_priv; 20 21 static const u8 intel_dsm_guid[] = { 22 0xd3, 0x73, 0xd8, 0x7e, 23 0xd0, 0xc2, 24 0x4f, 0x4e, 25 0xa8, 0x54, 26 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c 27 }; 28 29 static int intel_dsm(acpi_handle handle, int func, int arg) 30 { 31 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 32 struct acpi_object_list input; 33 union acpi_object params[4]; 34 union acpi_object *obj; 35 u32 result; 36 int ret = 0; 37 38 input.count = 4; 39 input.pointer = params; 40 params[0].type = ACPI_TYPE_BUFFER; 41 params[0].buffer.length = sizeof(intel_dsm_guid); 42 params[0].buffer.pointer = (char *)intel_dsm_guid; 43 params[1].type = ACPI_TYPE_INTEGER; 44 params[1].integer.value = INTEL_DSM_REVISION_ID; 45 params[2].type = ACPI_TYPE_INTEGER; 46 params[2].integer.value = func; 47 params[3].type = ACPI_TYPE_INTEGER; 48 params[3].integer.value = arg; 49 50 ret = acpi_evaluate_object(handle, "_DSM", &input, &output); 51 if (ret) { 52 DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); 53 return ret; 54 } 55 56 obj = (union acpi_object *)output.pointer; 57 58 result = 0; 59 switch (obj->type) { 60 case ACPI_TYPE_INTEGER: 61 result = obj->integer.value; 62 break; 63 64 case ACPI_TYPE_BUFFER: 65 if (obj->buffer.length == 4) { 66 result = (obj->buffer.pointer[0] | 67 (obj->buffer.pointer[1] << 8) | 68 (obj->buffer.pointer[2] << 16) | 69 (obj->buffer.pointer[3] << 24)); 70 break; 71 } 72 default: 73 ret = -EINVAL; 74 break; 75 } 76 if (result == 0x80000002) 77 ret = -ENODEV; 78 79 kfree(output.pointer); 80 return ret; 81 } 82 83 static char *intel_dsm_port_name(u8 id) 84 { 85 switch (id) { 86 case 0: 87 return "Reserved"; 88 case 1: 89 return "Analog VGA"; 90 case 2: 91 return "LVDS"; 92 case 3: 93 return "Reserved"; 94 case 4: 95 return "HDMI/DVI_B"; 96 case 5: 97 return "HDMI/DVI_C"; 98 case 6: 99 return "HDMI/DVI_D"; 100 case 7: 101 return "DisplayPort_A"; 102 case 8: 103 return "DisplayPort_B"; 104 case 9: 105 return "DisplayPort_C"; 106 case 0xa: 107 return "DisplayPort_D"; 108 case 0xb: 109 case 0xc: 110 case 0xd: 111 return "Reserved"; 112 case 0xe: 113 return "WiDi"; 114 default: 115 return "bad type"; 116 } 117 } 118 119 static char *intel_dsm_mux_type(u8 type) 120 { 121 switch (type) { 122 case 0: 123 return "unknown"; 124 case 1: 125 return "No MUX, iGPU only"; 126 case 2: 127 return "No MUX, dGPU only"; 128 case 3: 129 return "MUXed between iGPU and dGPU"; 130 default: 131 return "bad type"; 132 } 133 } 134 135 static void intel_dsm_platform_mux_info(void) 136 { 137 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 138 struct acpi_object_list input; 139 union acpi_object params[4]; 140 union acpi_object *pkg; 141 int i, ret; 142 143 input.count = 4; 144 input.pointer = params; 145 params[0].type = ACPI_TYPE_BUFFER; 146 params[0].buffer.length = sizeof(intel_dsm_guid); 147 params[0].buffer.pointer = (char *)intel_dsm_guid; 148 params[1].type = ACPI_TYPE_INTEGER; 149 params[1].integer.value = INTEL_DSM_REVISION_ID; 150 params[2].type = ACPI_TYPE_INTEGER; 151 params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO; 152 params[3].type = ACPI_TYPE_INTEGER; 153 params[3].integer.value = 0; 154 155 ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input, 156 &output); 157 if (ret) { 158 DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); 159 goto out; 160 } 161 162 pkg = (union acpi_object *)output.pointer; 163 164 if (pkg->type == ACPI_TYPE_PACKAGE) { 165 union acpi_object *connector_count = &pkg->package.elements[0]; 166 DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", 167 (unsigned long long)connector_count->integer.value); 168 for (i = 1; i < pkg->package.count; i++) { 169 union acpi_object *obj = &pkg->package.elements[i]; 170 union acpi_object *connector_id = 171 &obj->package.elements[0]; 172 union acpi_object *info = &obj->package.elements[1]; 173 DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", 174 (unsigned long long)connector_id->integer.value); 175 DRM_DEBUG_DRIVER(" port id: %s\n", 176 intel_dsm_port_name(info->buffer.pointer[0])); 177 DRM_DEBUG_DRIVER(" display mux info: %s\n", 178 intel_dsm_mux_type(info->buffer.pointer[1])); 179 DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", 180 intel_dsm_mux_type(info->buffer.pointer[2])); 181 DRM_DEBUG_DRIVER(" hpd mux info: %s\n", 182 intel_dsm_mux_type(info->buffer.pointer[3])); 183 } 184 } 185 186 out: 187 kfree(output.pointer); 188 } 189 190 static bool intel_dsm_pci_probe(struct pci_dev *pdev) 191 { 192 acpi_handle dhandle, intel_handle; 193 acpi_status status; 194 int ret; 195 196 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 197 if (!dhandle) 198 return false; 199 200 status = acpi_get_handle(dhandle, "_DSM", &intel_handle); 201 if (ACPI_FAILURE(status)) { 202 DRM_DEBUG_KMS("no _DSM method for intel device\n"); 203 return false; 204 } 205 206 ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0); 207 if (ret < 0) { 208 DRM_DEBUG_KMS("failed to get supported _DSM functions\n"); 209 return false; 210 } 211 212 intel_dsm_priv.dhandle = dhandle; 213 214 intel_dsm_platform_mux_info(); 215 return true; 216 } 217 218 static bool intel_dsm_detect(void) 219 { 220 char acpi_method_name[255] = { 0 }; 221 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 222 struct pci_dev *pdev = NULL; 223 bool has_dsm = false; 224 int vga_count = 0; 225 226 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 227 vga_count++; 228 has_dsm |= intel_dsm_pci_probe(pdev); 229 } 230 231 if (vga_count == 2 && has_dsm) { 232 acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 233 DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n", 234 acpi_method_name); 235 return true; 236 } 237 238 return false; 239 } 240 241 void intel_register_dsm_handler(void) 242 { 243 if (!intel_dsm_detect()) 244 return; 245 } 246 #endif 247 248 void intel_unregister_dsm_handler(void) 249 { 250 } 251