Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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