intel_acpi.c revision 296548
148734Siwasaki/* 248734Siwasaki * Intel ACPI functions 350472Speter * 448734Siwasaki * _DSM related code stolen from nouveau_acpi.c. 548734Siwasaki */ 648734Siwasaki 748734Siwasaki#include <sys/cdefs.h> 848734Siwasaki__FBSDID("$FreeBSD: head/sys/dev/drm2/i915/intel_acpi.c 296548 2016-03-08 20:33:02Z dumbbell $"); 948734Siwasaki 1048734Siwasaki#include <dev/drm2/drmP.h> 1148734Siwasaki#include <dev/drm2/i915/i915_drv.h> 1248734Siwasaki#include <contrib/dev/acpica/include/acpi.h> 1348734Siwasaki#include <contrib/dev/acpica/include/accommon.h> 1448734Siwasaki#include <dev/acpica/acpivar.h> 1548734Siwasaki 1648734Siwasaki#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ 1748734Siwasaki 1848734Siwasaki#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */ 1948734Siwasaki#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ 2048734Siwasaki 2148734Siwasakistatic struct intel_dsm_priv { 2248734Siwasaki ACPI_HANDLE dhandle; 2348734Siwasaki} intel_dsm_priv; 2448734Siwasaki 2548734Siwasakistatic const u8 intel_dsm_guid[] = { 2648734Siwasaki 0xd3, 0x73, 0xd8, 0x7e, 2748734Siwasaki 0xd0, 0xc2, 2848734Siwasaki 0x4f, 0x4e, 2948734Siwasaki 0xa8, 0x54, 3048734Siwasaki 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c 3148734Siwasaki}; 3248734Siwasaki 3348734Siwasakistatic int intel_dsm(ACPI_HANDLE handle, int func, int arg) 3448734Siwasaki{ 3548734Siwasaki ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL }; 3648734Siwasaki ACPI_OBJECT_LIST input; 3748734Siwasaki ACPI_OBJECT params[4]; 3848734Siwasaki ACPI_OBJECT *obj; 39 u32 result; 40 int ret = 0; 41 42 input.Count = 4; 43 input.Pointer = params; 44 params[0].Type = ACPI_TYPE_BUFFER; 45 params[0].Buffer.Length = sizeof(intel_dsm_guid); 46 params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid); 47 params[1].Type = ACPI_TYPE_INTEGER; 48 params[1].Integer.Value = INTEL_DSM_REVISION_ID; 49 params[2].Type = ACPI_TYPE_INTEGER; 50 params[2].Integer.Value = func; 51 params[3].Type = ACPI_TYPE_INTEGER; 52 params[3].Integer.Value = arg; 53 54 ret = AcpiEvaluateObject(handle, "_DSM", &input, &output); 55 if (ret) { 56 DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); 57 return ret; 58 } 59 60 obj = (ACPI_OBJECT *)output.Pointer; 61 62 result = 0; 63 switch (obj->Type) { 64 case ACPI_TYPE_INTEGER: 65 result = obj->Integer.Value; 66 break; 67 68 case ACPI_TYPE_BUFFER: 69 if (obj->Buffer.Length == 4) { 70 result = (obj->Buffer.Pointer[0] | 71 (obj->Buffer.Pointer[1] << 8) | 72 (obj->Buffer.Pointer[2] << 16) | 73 (obj->Buffer.Pointer[3] << 24)); 74 break; 75 } 76 default: 77 ret = -EINVAL; 78 break; 79 } 80 if (result == 0x80000002) 81 ret = -ENODEV; 82 83 AcpiOsFree(output.Pointer); 84 return ret; 85} 86 87static char *intel_dsm_port_name(u8 id) 88{ 89 switch (id) { 90 case 0: 91 return "Reserved"; 92 case 1: 93 return "Analog VGA"; 94 case 2: 95 return "LVDS"; 96 case 3: 97 return "Reserved"; 98 case 4: 99 return "HDMI/DVI_B"; 100 case 5: 101 return "HDMI/DVI_C"; 102 case 6: 103 return "HDMI/DVI_D"; 104 case 7: 105 return "DisplayPort_A"; 106 case 8: 107 return "DisplayPort_B"; 108 case 9: 109 return "DisplayPort_C"; 110 case 0xa: 111 return "DisplayPort_D"; 112 case 0xb: 113 case 0xc: 114 case 0xd: 115 return "Reserved"; 116 case 0xe: 117 return "WiDi"; 118 default: 119 return "bad type"; 120 } 121} 122 123static char *intel_dsm_mux_type(u8 type) 124{ 125 switch (type) { 126 case 0: 127 return "unknown"; 128 case 1: 129 return "No MUX, iGPU only"; 130 case 2: 131 return "No MUX, dGPU only"; 132 case 3: 133 return "MUXed between iGPU and dGPU"; 134 default: 135 return "bad type"; 136 } 137} 138 139static void intel_dsm_platform_mux_info(void) 140{ 141 ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL }; 142 ACPI_OBJECT_LIST input; 143 ACPI_OBJECT params[4]; 144 ACPI_OBJECT *pkg; 145 int i, ret; 146 147 input.Count = 4; 148 input.Pointer = params; 149 params[0].Type = ACPI_TYPE_BUFFER; 150 params[0].Buffer.Length = sizeof(intel_dsm_guid); 151 params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid); 152 params[1].Type = ACPI_TYPE_INTEGER; 153 params[1].Integer.Value = INTEL_DSM_REVISION_ID; 154 params[2].Type = ACPI_TYPE_INTEGER; 155 params[2].Integer.Value = INTEL_DSM_FN_PLATFORM_MUX_INFO; 156 params[3].Type = ACPI_TYPE_INTEGER; 157 params[3].Integer.Value = 0; 158 159 ret = AcpiEvaluateObject(intel_dsm_priv.dhandle, "_DSM", &input, 160 &output); 161 if (ret) { 162 DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); 163 goto out; 164 } 165 166 pkg = (ACPI_OBJECT *)output.Pointer; 167 168 if (pkg->Type == ACPI_TYPE_PACKAGE) { 169 ACPI_OBJECT *connector_count = &pkg->Package.Elements[0]; 170 DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", 171 (unsigned long long)connector_count->Integer.Value); 172 for (i = 1; i < pkg->Package.Count; i++) { 173 ACPI_OBJECT *obj = &pkg->Package.Elements[i]; 174 ACPI_OBJECT *connector_id = 175 &obj->Package.Elements[0]; 176 ACPI_OBJECT *info = &obj->Package.Elements[1]; 177 DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", 178 (unsigned long long)connector_id->Integer.Value); 179 DRM_DEBUG_DRIVER(" port id: %s\n", 180 intel_dsm_port_name(info->Buffer.Pointer[0])); 181 DRM_DEBUG_DRIVER(" display mux info: %s\n", 182 intel_dsm_mux_type(info->Buffer.Pointer[1])); 183 DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", 184 intel_dsm_mux_type(info->Buffer.Pointer[2])); 185 DRM_DEBUG_DRIVER(" hpd mux info: %s\n", 186 intel_dsm_mux_type(info->Buffer.Pointer[3])); 187 } 188 } 189 190out: 191 AcpiOsFree(output.Pointer); 192} 193 194static bool intel_dsm_pci_probe(device_t dev) 195{ 196 ACPI_HANDLE dhandle, intel_handle; 197 ACPI_STATUS status; 198 int ret; 199 200 dhandle = acpi_get_handle(dev); 201 if (!dhandle) 202 return false; 203 204 status = AcpiGetHandle(dhandle, "_DSM", &intel_handle); 205 if (ACPI_FAILURE(status)) { 206 DRM_DEBUG_KMS("no _DSM method for intel device\n"); 207 return false; 208 } 209 210 ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0); 211 if (ret < 0) { 212 DRM_DEBUG_KMS("failed to get supported _DSM functions\n"); 213 return false; 214 } 215 216 intel_dsm_priv.dhandle = dhandle; 217 218 intel_dsm_platform_mux_info(); 219 return true; 220} 221 222static bool intel_dsm_detect(void) 223{ 224 char acpi_method_name[255] = { 0 }; 225 ACPI_BUFFER buffer = {sizeof(acpi_method_name), acpi_method_name}; 226 device_t dev = NULL; 227 bool has_dsm = false; 228 int vga_count = 0; 229 230#ifdef FREEBSD_WIP 231 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 232#endif /* FREEBSD_WIP */ 233 if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) { 234 vga_count++; 235 has_dsm |= intel_dsm_pci_probe(dev); 236 } 237 238 if (vga_count == 2 && has_dsm) { 239 AcpiGetName(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 240 DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n", 241 acpi_method_name); 242 return true; 243 } 244 245 return false; 246} 247 248void intel_register_dsm_handler(void) 249{ 250 if (!intel_dsm_detect()) 251 return; 252} 253 254void intel_unregister_dsm_handler(void) 255{ 256} 257