Path: blob/master/drivers/gpu/drm/i915/intel_acpi.c
15113 views
/*1* Intel ACPI functions2*3* _DSM related code stolen from nouveau_acpi.c.4*/5#include <linux/pci.h>6#include <linux/acpi.h>7#include <linux/vga_switcheroo.h>8#include <acpi/acpi_drivers.h>910#include "drmP.h"1112#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */1314#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */15#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */1617static struct intel_dsm_priv {18acpi_handle dhandle;19} intel_dsm_priv;2021static const u8 intel_dsm_guid[] = {220xd3, 0x73, 0xd8, 0x7e,230xd0, 0xc2,240x4f, 0x4e,250xa8, 0x54,260x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c27};2829static int intel_dsm(acpi_handle handle, int func, int arg)30{31struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };32struct acpi_object_list input;33union acpi_object params[4];34union acpi_object *obj;35u32 result;36int ret = 0;3738input.count = 4;39input.pointer = params;40params[0].type = ACPI_TYPE_BUFFER;41params[0].buffer.length = sizeof(intel_dsm_guid);42params[0].buffer.pointer = (char *)intel_dsm_guid;43params[1].type = ACPI_TYPE_INTEGER;44params[1].integer.value = INTEL_DSM_REVISION_ID;45params[2].type = ACPI_TYPE_INTEGER;46params[2].integer.value = func;47params[3].type = ACPI_TYPE_INTEGER;48params[3].integer.value = arg;4950ret = acpi_evaluate_object(handle, "_DSM", &input, &output);51if (ret) {52DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);53return ret;54}5556obj = (union acpi_object *)output.pointer;5758result = 0;59switch (obj->type) {60case ACPI_TYPE_INTEGER:61result = obj->integer.value;62break;6364case ACPI_TYPE_BUFFER:65if (obj->buffer.length == 4) {66result =(obj->buffer.pointer[0] |67(obj->buffer.pointer[1] << 8) |68(obj->buffer.pointer[2] << 16) |69(obj->buffer.pointer[3] << 24));70break;71}72default:73ret = -EINVAL;74break;75}76if (result == 0x80000002)77ret = -ENODEV;7879kfree(output.pointer);80return ret;81}8283static char *intel_dsm_port_name(u8 id)84{85switch (id) {86case 0:87return "Reserved";88case 1:89return "Analog VGA";90case 2:91return "LVDS";92case 3:93return "Reserved";94case 4:95return "HDMI/DVI_B";96case 5:97return "HDMI/DVI_C";98case 6:99return "HDMI/DVI_D";100case 7:101return "DisplayPort_A";102case 8:103return "DisplayPort_B";104case 9:105return "DisplayPort_C";106case 0xa:107return "DisplayPort_D";108case 0xb:109case 0xc:110case 0xd:111return "Reserved";112case 0xe:113return "WiDi";114default:115return "bad type";116}117}118119static char *intel_dsm_mux_type(u8 type)120{121switch (type) {122case 0:123return "unknown";124case 1:125return "No MUX, iGPU only";126case 2:127return "No MUX, dGPU only";128case 3:129return "MUXed between iGPU and dGPU";130default:131return "bad type";132}133}134135static void intel_dsm_platform_mux_info(void)136{137struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };138struct acpi_object_list input;139union acpi_object params[4];140union acpi_object *pkg;141int i, ret;142143input.count = 4;144input.pointer = params;145params[0].type = ACPI_TYPE_BUFFER;146params[0].buffer.length = sizeof(intel_dsm_guid);147params[0].buffer.pointer = (char *)intel_dsm_guid;148params[1].type = ACPI_TYPE_INTEGER;149params[1].integer.value = INTEL_DSM_REVISION_ID;150params[2].type = ACPI_TYPE_INTEGER;151params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;152params[3].type = ACPI_TYPE_INTEGER;153params[3].integer.value = 0;154155ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,156&output);157if (ret) {158DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);159goto out;160}161162pkg = (union acpi_object *)output.pointer;163164if (pkg->type == ACPI_TYPE_PACKAGE) {165union acpi_object *connector_count = &pkg->package.elements[0];166DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",167(unsigned long long)connector_count->integer.value);168for (i = 1; i < pkg->package.count; i++) {169union acpi_object *obj = &pkg->package.elements[i];170union acpi_object *connector_id =171&obj->package.elements[0];172union acpi_object *info = &obj->package.elements[1];173DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",174(unsigned long long)connector_id->integer.value);175DRM_DEBUG_DRIVER(" port id: %s\n",176intel_dsm_port_name(info->buffer.pointer[0]));177DRM_DEBUG_DRIVER(" display mux info: %s\n",178intel_dsm_mux_type(info->buffer.pointer[1]));179DRM_DEBUG_DRIVER(" aux/dc mux info: %s\n",180intel_dsm_mux_type(info->buffer.pointer[2]));181DRM_DEBUG_DRIVER(" hpd mux info: %s\n",182intel_dsm_mux_type(info->buffer.pointer[3]));183}184} else {185DRM_ERROR("MUX INFO call failed\n");186}187188out:189kfree(output.pointer);190}191192static bool intel_dsm_pci_probe(struct pci_dev *pdev)193{194acpi_handle dhandle, intel_handle;195acpi_status status;196int ret;197198dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);199if (!dhandle)200return false;201202status = acpi_get_handle(dhandle, "_DSM", &intel_handle);203if (ACPI_FAILURE(status)) {204DRM_DEBUG_KMS("no _DSM method for intel device\n");205return false;206}207208ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);209if (ret < 0) {210DRM_ERROR("failed to get supported _DSM functions\n");211return false;212}213214intel_dsm_priv.dhandle = dhandle;215216intel_dsm_platform_mux_info();217return true;218}219220static bool intel_dsm_detect(void)221{222char acpi_method_name[255] = { 0 };223struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};224struct pci_dev *pdev = NULL;225bool has_dsm = false;226int vga_count = 0;227228while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {229vga_count++;230has_dsm |= intel_dsm_pci_probe(pdev);231}232233if (vga_count == 2 && has_dsm) {234acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);235DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",236acpi_method_name);237return true;238}239240return false;241}242243void intel_register_dsm_handler(void)244{245if (!intel_dsm_detect())246return;247}248249void intel_unregister_dsm_handler(void)250{251}252253254