linux/drivers/gpu/drm/i915/intel_acpi.c
<<
>>
Prefs
   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 <drm/drmP.h>
  10#include "i915_drv.h"
  11
  12#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
  13#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
  14
  15static struct intel_dsm_priv {
  16        acpi_handle dhandle;
  17} intel_dsm_priv;
  18
  19static const u8 intel_dsm_guid[] = {
  20        0xd3, 0x73, 0xd8, 0x7e,
  21        0xd0, 0xc2,
  22        0x4f, 0x4e,
  23        0xa8, 0x54,
  24        0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
  25};
  26
  27static char *intel_dsm_port_name(u8 id)
  28{
  29        switch (id) {
  30        case 0:
  31                return "Reserved";
  32        case 1:
  33                return "Analog VGA";
  34        case 2:
  35                return "LVDS";
  36        case 3:
  37                return "Reserved";
  38        case 4:
  39                return "HDMI/DVI_B";
  40        case 5:
  41                return "HDMI/DVI_C";
  42        case 6:
  43                return "HDMI/DVI_D";
  44        case 7:
  45                return "DisplayPort_A";
  46        case 8:
  47                return "DisplayPort_B";
  48        case 9:
  49                return "DisplayPort_C";
  50        case 0xa:
  51                return "DisplayPort_D";
  52        case 0xb:
  53        case 0xc:
  54        case 0xd:
  55                return "Reserved";
  56        case 0xe:
  57                return "WiDi";
  58        default:
  59                return "bad type";
  60        }
  61}
  62
  63static char *intel_dsm_mux_type(u8 type)
  64{
  65        switch (type) {
  66        case 0:
  67                return "unknown";
  68        case 1:
  69                return "No MUX, iGPU only";
  70        case 2:
  71                return "No MUX, dGPU only";
  72        case 3:
  73                return "MUXed between iGPU and dGPU";
  74        default:
  75                return "bad type";
  76        }
  77}
  78
  79static void intel_dsm_platform_mux_info(void)
  80{
  81        int i;
  82        union acpi_object *pkg, *connector_count;
  83
  84        pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid,
  85                        INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
  86                        NULL, ACPI_TYPE_PACKAGE);
  87        if (!pkg) {
  88                DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
  89                return;
  90        }
  91
  92        connector_count = &pkg->package.elements[0];
  93        DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
  94                  (unsigned long long)connector_count->integer.value);
  95        for (i = 1; i < pkg->package.count; i++) {
  96                union acpi_object *obj = &pkg->package.elements[i];
  97                union acpi_object *connector_id = &obj->package.elements[0];
  98                union acpi_object *info = &obj->package.elements[1];
  99                DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
 100                          (unsigned long long)connector_id->integer.value);
 101                DRM_DEBUG_DRIVER("  port id: %s\n",
 102                       intel_dsm_port_name(info->buffer.pointer[0]));
 103                DRM_DEBUG_DRIVER("  display mux info: %s\n",
 104                       intel_dsm_mux_type(info->buffer.pointer[1]));
 105                DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
 106                       intel_dsm_mux_type(info->buffer.pointer[2]));
 107                DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
 108                       intel_dsm_mux_type(info->buffer.pointer[3]));
 109        }
 110
 111        ACPI_FREE(pkg);
 112}
 113
 114static bool intel_dsm_pci_probe(struct pci_dev *pdev)
 115{
 116        acpi_handle dhandle;
 117
 118        dhandle = ACPI_HANDLE(&pdev->dev);
 119        if (!dhandle)
 120                return false;
 121
 122        if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID,
 123                            1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
 124                DRM_DEBUG_KMS("no _DSM method for intel device\n");
 125                return false;
 126        }
 127
 128        intel_dsm_priv.dhandle = dhandle;
 129        intel_dsm_platform_mux_info();
 130
 131        return true;
 132}
 133
 134static bool intel_dsm_detect(void)
 135{
 136        char acpi_method_name[255] = { 0 };
 137        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 138        struct pci_dev *pdev = NULL;
 139        bool has_dsm = false;
 140        int vga_count = 0;
 141
 142        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 143                vga_count++;
 144                has_dsm |= intel_dsm_pci_probe(pdev);
 145        }
 146
 147        if (vga_count == 2 && has_dsm) {
 148                acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
 149                DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
 150                                 acpi_method_name);
 151                return true;
 152        }
 153
 154        return false;
 155}
 156
 157void intel_register_dsm_handler(void)
 158{
 159        if (!intel_dsm_detect())
 160                return;
 161}
 162
 163void intel_unregister_dsm_handler(void)
 164{
 165}
 166