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