1296548Sdumbbell/* 2296548Sdumbbell * Intel ACPI functions 3296548Sdumbbell * 4296548Sdumbbell * _DSM related code stolen from nouveau_acpi.c. 5296548Sdumbbell */ 6296548Sdumbbell 7296548Sdumbbell#include <sys/cdefs.h> 8296548Sdumbbell__FBSDID("$FreeBSD$"); 9296548Sdumbbell 10296548Sdumbbell#include <dev/drm2/drmP.h> 11296548Sdumbbell#include <dev/drm2/i915/i915_drv.h> 12296548Sdumbbell#include <contrib/dev/acpica/include/acpi.h> 13296548Sdumbbell#include <contrib/dev/acpica/include/accommon.h> 14296548Sdumbbell#include <dev/acpica/acpivar.h> 15296548Sdumbbell 16296548Sdumbbell#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ 17296548Sdumbbell 18296548Sdumbbell#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */ 19296548Sdumbbell#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */ 20296548Sdumbbell 21296548Sdumbbellstatic struct intel_dsm_priv { 22296548Sdumbbell ACPI_HANDLE dhandle; 23296548Sdumbbell} intel_dsm_priv; 24296548Sdumbbell 25296548Sdumbbellstatic const u8 intel_dsm_guid[] = { 26296548Sdumbbell 0xd3, 0x73, 0xd8, 0x7e, 27296548Sdumbbell 0xd0, 0xc2, 28296548Sdumbbell 0x4f, 0x4e, 29296548Sdumbbell 0xa8, 0x54, 30296548Sdumbbell 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c 31296548Sdumbbell}; 32296548Sdumbbell 33296548Sdumbbellstatic int intel_dsm(ACPI_HANDLE handle, int func, int arg) 34296548Sdumbbell{ 35296548Sdumbbell ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL }; 36296548Sdumbbell ACPI_OBJECT_LIST input; 37296548Sdumbbell ACPI_OBJECT params[4]; 38296548Sdumbbell ACPI_OBJECT *obj; 39296548Sdumbbell u32 result; 40296548Sdumbbell int ret = 0; 41296548Sdumbbell 42296548Sdumbbell input.Count = 4; 43296548Sdumbbell input.Pointer = params; 44296548Sdumbbell params[0].Type = ACPI_TYPE_BUFFER; 45296548Sdumbbell params[0].Buffer.Length = sizeof(intel_dsm_guid); 46296548Sdumbbell params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid); 47296548Sdumbbell params[1].Type = ACPI_TYPE_INTEGER; 48296548Sdumbbell params[1].Integer.Value = INTEL_DSM_REVISION_ID; 49296548Sdumbbell params[2].Type = ACPI_TYPE_INTEGER; 50296548Sdumbbell params[2].Integer.Value = func; 51296548Sdumbbell params[3].Type = ACPI_TYPE_INTEGER; 52296548Sdumbbell params[3].Integer.Value = arg; 53296548Sdumbbell 54296548Sdumbbell ret = AcpiEvaluateObject(handle, "_DSM", &input, &output); 55296548Sdumbbell if (ret) { 56296548Sdumbbell DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); 57296548Sdumbbell return ret; 58296548Sdumbbell } 59296548Sdumbbell 60296548Sdumbbell obj = (ACPI_OBJECT *)output.Pointer; 61296548Sdumbbell 62296548Sdumbbell result = 0; 63296548Sdumbbell switch (obj->Type) { 64296548Sdumbbell case ACPI_TYPE_INTEGER: 65296548Sdumbbell result = obj->Integer.Value; 66296548Sdumbbell break; 67296548Sdumbbell 68296548Sdumbbell case ACPI_TYPE_BUFFER: 69296548Sdumbbell if (obj->Buffer.Length == 4) { 70296548Sdumbbell result = (obj->Buffer.Pointer[0] | 71296548Sdumbbell (obj->Buffer.Pointer[1] << 8) | 72296548Sdumbbell (obj->Buffer.Pointer[2] << 16) | 73296548Sdumbbell (obj->Buffer.Pointer[3] << 24)); 74296548Sdumbbell break; 75296548Sdumbbell } 76296548Sdumbbell default: 77296548Sdumbbell ret = -EINVAL; 78296548Sdumbbell break; 79296548Sdumbbell } 80296548Sdumbbell if (result == 0x80000002) 81296548Sdumbbell ret = -ENODEV; 82296548Sdumbbell 83296548Sdumbbell AcpiOsFree(output.Pointer); 84296548Sdumbbell return ret; 85296548Sdumbbell} 86296548Sdumbbell 87296548Sdumbbellstatic char *intel_dsm_port_name(u8 id) 88296548Sdumbbell{ 89296548Sdumbbell switch (id) { 90296548Sdumbbell case 0: 91296548Sdumbbell return "Reserved"; 92296548Sdumbbell case 1: 93296548Sdumbbell return "Analog VGA"; 94296548Sdumbbell case 2: 95296548Sdumbbell return "LVDS"; 96296548Sdumbbell case 3: 97296548Sdumbbell return "Reserved"; 98296548Sdumbbell case 4: 99296548Sdumbbell return "HDMI/DVI_B"; 100296548Sdumbbell case 5: 101296548Sdumbbell return "HDMI/DVI_C"; 102296548Sdumbbell case 6: 103296548Sdumbbell return "HDMI/DVI_D"; 104296548Sdumbbell case 7: 105296548Sdumbbell return "DisplayPort_A"; 106296548Sdumbbell case 8: 107296548Sdumbbell return "DisplayPort_B"; 108296548Sdumbbell case 9: 109296548Sdumbbell return "DisplayPort_C"; 110296548Sdumbbell case 0xa: 111296548Sdumbbell return "DisplayPort_D"; 112296548Sdumbbell case 0xb: 113296548Sdumbbell case 0xc: 114296548Sdumbbell case 0xd: 115296548Sdumbbell return "Reserved"; 116296548Sdumbbell case 0xe: 117296548Sdumbbell return "WiDi"; 118296548Sdumbbell default: 119296548Sdumbbell return "bad type"; 120296548Sdumbbell } 121296548Sdumbbell} 122296548Sdumbbell 123296548Sdumbbellstatic char *intel_dsm_mux_type(u8 type) 124296548Sdumbbell{ 125296548Sdumbbell switch (type) { 126296548Sdumbbell case 0: 127296548Sdumbbell return "unknown"; 128296548Sdumbbell case 1: 129296548Sdumbbell return "No MUX, iGPU only"; 130296548Sdumbbell case 2: 131296548Sdumbbell return "No MUX, dGPU only"; 132296548Sdumbbell case 3: 133296548Sdumbbell return "MUXed between iGPU and dGPU"; 134296548Sdumbbell default: 135296548Sdumbbell return "bad type"; 136296548Sdumbbell } 137296548Sdumbbell} 138296548Sdumbbell 139296548Sdumbbellstatic void intel_dsm_platform_mux_info(void) 140296548Sdumbbell{ 141296548Sdumbbell ACPI_BUFFER output = { ACPI_ALLOCATE_BUFFER, NULL }; 142296548Sdumbbell ACPI_OBJECT_LIST input; 143296548Sdumbbell ACPI_OBJECT params[4]; 144296548Sdumbbell ACPI_OBJECT *pkg; 145296548Sdumbbell int i, ret; 146296548Sdumbbell 147296548Sdumbbell input.Count = 4; 148296548Sdumbbell input.Pointer = params; 149296548Sdumbbell params[0].Type = ACPI_TYPE_BUFFER; 150296548Sdumbbell params[0].Buffer.Length = sizeof(intel_dsm_guid); 151296548Sdumbbell params[0].Buffer.Pointer = __DECONST(char *, intel_dsm_guid); 152296548Sdumbbell params[1].Type = ACPI_TYPE_INTEGER; 153296548Sdumbbell params[1].Integer.Value = INTEL_DSM_REVISION_ID; 154296548Sdumbbell params[2].Type = ACPI_TYPE_INTEGER; 155296548Sdumbbell params[2].Integer.Value = INTEL_DSM_FN_PLATFORM_MUX_INFO; 156296548Sdumbbell params[3].Type = ACPI_TYPE_INTEGER; 157296548Sdumbbell params[3].Integer.Value = 0; 158296548Sdumbbell 159296548Sdumbbell ret = AcpiEvaluateObject(intel_dsm_priv.dhandle, "_DSM", &input, 160296548Sdumbbell &output); 161296548Sdumbbell if (ret) { 162296548Sdumbbell DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret); 163296548Sdumbbell goto out; 164296548Sdumbbell } 165296548Sdumbbell 166296548Sdumbbell pkg = (ACPI_OBJECT *)output.Pointer; 167296548Sdumbbell 168296548Sdumbbell if (pkg->Type == ACPI_TYPE_PACKAGE) { 169296548Sdumbbell ACPI_OBJECT *connector_count = &pkg->Package.Elements[0]; 170296548Sdumbbell DRM_DEBUG_DRIVER("MUX info connectors: %lld\n", 171296548Sdumbbell (unsigned long long)connector_count->Integer.Value); 172296548Sdumbbell for (i = 1; i < pkg->Package.Count; i++) { 173296548Sdumbbell ACPI_OBJECT *obj = &pkg->Package.Elements[i]; 174296548Sdumbbell ACPI_OBJECT *connector_id = 175296548Sdumbbell &obj->Package.Elements[0]; 176296548Sdumbbell ACPI_OBJECT *info = &obj->Package.Elements[1]; 177296548Sdumbbell DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n", 178296548Sdumbbell (unsigned long long)connector_id->Integer.Value); 179296548Sdumbbell DRM_DEBUG_DRIVER(" port id: %s\n", 180296548Sdumbbell intel_dsm_port_name(info->Buffer.Pointer[0])); 181296548Sdumbbell DRM_DEBUG_DRIVER(" display mux info: %s\n", 182296548Sdumbbell intel_dsm_mux_type(info->Buffer.Pointer[1])); 183296548Sdumbbell DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n", 184296548Sdumbbell intel_dsm_mux_type(info->Buffer.Pointer[2])); 185296548Sdumbbell DRM_DEBUG_DRIVER(" hpd mux info: %s\n", 186296548Sdumbbell intel_dsm_mux_type(info->Buffer.Pointer[3])); 187296548Sdumbbell } 188296548Sdumbbell } 189296548Sdumbbell 190296548Sdumbbellout: 191296548Sdumbbell AcpiOsFree(output.Pointer); 192296548Sdumbbell} 193296548Sdumbbell 194296548Sdumbbellstatic bool intel_dsm_pci_probe(device_t dev) 195296548Sdumbbell{ 196296548Sdumbbell ACPI_HANDLE dhandle, intel_handle; 197296548Sdumbbell ACPI_STATUS status; 198296548Sdumbbell int ret; 199296548Sdumbbell 200296548Sdumbbell dhandle = acpi_get_handle(dev); 201296548Sdumbbell if (!dhandle) 202296548Sdumbbell return false; 203296548Sdumbbell 204296548Sdumbbell status = AcpiGetHandle(dhandle, "_DSM", &intel_handle); 205296548Sdumbbell if (ACPI_FAILURE(status)) { 206296548Sdumbbell DRM_DEBUG_KMS("no _DSM method for intel device\n"); 207296548Sdumbbell return false; 208296548Sdumbbell } 209296548Sdumbbell 210296548Sdumbbell ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0); 211296548Sdumbbell if (ret < 0) { 212296548Sdumbbell DRM_DEBUG_KMS("failed to get supported _DSM functions\n"); 213296548Sdumbbell return false; 214296548Sdumbbell } 215296548Sdumbbell 216296548Sdumbbell intel_dsm_priv.dhandle = dhandle; 217296548Sdumbbell 218296548Sdumbbell intel_dsm_platform_mux_info(); 219296548Sdumbbell return true; 220296548Sdumbbell} 221296548Sdumbbell 222296548Sdumbbellstatic bool intel_dsm_detect(void) 223296548Sdumbbell{ 224296548Sdumbbell char acpi_method_name[255] = { 0 }; 225296548Sdumbbell ACPI_BUFFER buffer = {sizeof(acpi_method_name), acpi_method_name}; 226296548Sdumbbell device_t dev = NULL; 227296548Sdumbbell bool has_dsm = false; 228296548Sdumbbell int vga_count = 0; 229296548Sdumbbell 230296548Sdumbbell#ifdef FREEBSD_WIP 231296548Sdumbbell while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 232296548Sdumbbell#endif /* FREEBSD_WIP */ 233296548Sdumbbell if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) { 234296548Sdumbbell vga_count++; 235296548Sdumbbell has_dsm |= intel_dsm_pci_probe(dev); 236296548Sdumbbell } 237296548Sdumbbell 238296548Sdumbbell if (vga_count == 2 && has_dsm) { 239296548Sdumbbell AcpiGetName(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 240296548Sdumbbell DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n", 241296548Sdumbbell acpi_method_name); 242296548Sdumbbell return true; 243296548Sdumbbell } 244296548Sdumbbell 245296548Sdumbbell return false; 246296548Sdumbbell} 247296548Sdumbbell 248296548Sdumbbellvoid intel_register_dsm_handler(void) 249296548Sdumbbell{ 250296548Sdumbbell if (!intel_dsm_detect()) 251296548Sdumbbell return; 252296548Sdumbbell} 253296548Sdumbbell 254296548Sdumbbellvoid intel_unregister_dsm_handler(void) 255296548Sdumbbell{ 256296548Sdumbbell} 257