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 <acpi/acpi_drivers.h>
  10
  11#include "drmP.h"
  12
  13#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
  14
  15#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
  16#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
  17
  18static struct intel_dsm_priv {
  19        acpi_handle dhandle;
  20} intel_dsm_priv;
  21
  22static const u8 intel_dsm_guid[] = {
  23        0xd3, 0x73, 0xd8, 0x7e,
  24        0xd0, 0xc2,
  25        0x4f, 0x4e,
  26        0xa8, 0x54,
  27        0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
  28};
  29
  30static int intel_dsm(acpi_handle handle, int func, int arg)
  31{
  32        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
  33        struct acpi_object_list input;
  34        union acpi_object params[4];
  35        union acpi_object *obj;
  36        u32 result;
  37        int ret = 0;
  38
  39        input.count = 4;
  40        input.pointer = params;
  41        params[0].type = ACPI_TYPE_BUFFER;
  42        params[0].buffer.length = sizeof(intel_dsm_guid);
  43        params[0].buffer.pointer = (char *)intel_dsm_guid;
  44        params[1].type = ACPI_TYPE_INTEGER;
  45        params[1].integer.value = INTEL_DSM_REVISION_ID;
  46        params[2].type = ACPI_TYPE_INTEGER;
  47        params[2].integer.value = func;
  48        params[3].type = ACPI_TYPE_INTEGER;
  49        params[3].integer.value = arg;
  50
  51        ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
  52        if (ret) {
  53                DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
  54                return ret;
  55        }
  56
  57        obj = (union acpi_object *)output.pointer;
  58
  59        result = 0;
  60        switch (obj->type) {
  61        case ACPI_TYPE_INTEGER:
  62                result = obj->integer.value;
  63                break;
  64
  65        case ACPI_TYPE_BUFFER:
  66                if (obj->buffer.length == 4) {
  67                        result =(obj->buffer.pointer[0] |
  68                                (obj->buffer.pointer[1] <<  8) |
  69                                (obj->buffer.pointer[2] << 16) |
  70                                (obj->buffer.pointer[3] << 24));
  71                        break;
  72                }
  73        default:
  74                ret = -EINVAL;
  75                break;
  76        }
  77        if (result == 0x80000002)
  78                ret = -ENODEV;
  79
  80        kfree(output.pointer);
  81        return ret;
  82}
  83
  84static char *intel_dsm_port_name(u8 id)
  85{
  86        switch (id) {
  87        case 0:
  88                return "Reserved";
  89        case 1:
  90                return "Analog VGA";
  91        case 2:
  92                return "LVDS";
  93        case 3:
  94                return "Reserved";
  95        case 4:
  96                return "HDMI/DVI_B";
  97        case 5:
  98                return "HDMI/DVI_C";
  99        case 6:
 100                return "HDMI/DVI_D";
 101        case 7:
 102                return "DisplayPort_A";
 103        case 8:
 104                return "DisplayPort_B";
 105        case 9:
 106                return "DisplayPort_C";
 107        case 0xa:
 108                return "DisplayPort_D";
 109        case 0xb:
 110        case 0xc:
 111        case 0xd:
 112                return "Reserved";
 113        case 0xe:
 114                return "WiDi";
 115        default:
 116                return "bad type";
 117        }
 118}
 119
 120static char *intel_dsm_mux_type(u8 type)
 121{
 122        switch (type) {
 123        case 0:
 124                return "unknown";
 125        case 1:
 126                return "No MUX, iGPU only";
 127        case 2:
 128                return "No MUX, dGPU only";
 129        case 3:
 130                return "MUXed between iGPU and dGPU";
 131        default:
 132                return "bad type";
 133        }
 134}
 135
 136static void intel_dsm_platform_mux_info(void)
 137{
 138        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 139        struct acpi_object_list input;
 140        union acpi_object params[4];
 141        union acpi_object *pkg;
 142        int i, ret;
 143
 144        input.count = 4;
 145        input.pointer = params;
 146        params[0].type = ACPI_TYPE_BUFFER;
 147        params[0].buffer.length = sizeof(intel_dsm_guid);
 148        params[0].buffer.pointer = (char *)intel_dsm_guid;
 149        params[1].type = ACPI_TYPE_INTEGER;
 150        params[1].integer.value = INTEL_DSM_REVISION_ID;
 151        params[2].type = ACPI_TYPE_INTEGER;
 152        params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
 153        params[3].type = ACPI_TYPE_INTEGER;
 154        params[3].integer.value = 0;
 155
 156        ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
 157                                   &output);
 158        if (ret) {
 159                DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
 160                goto out;
 161        }
 162
 163        pkg = (union acpi_object *)output.pointer;
 164
 165        if (pkg->type == ACPI_TYPE_PACKAGE) {
 166                union acpi_object *connector_count = &pkg->package.elements[0];
 167                DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
 168                          (unsigned long long)connector_count->integer.value);
 169                for (i = 1; i < pkg->package.count; i++) {
 170                        union acpi_object *obj = &pkg->package.elements[i];
 171                        union acpi_object *connector_id =
 172                                &obj->package.elements[0];
 173                        union acpi_object *info = &obj->package.elements[1];
 174                        DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
 175                                  (unsigned long long)connector_id->integer.value);
 176                        DRM_DEBUG_DRIVER("  port id: %s\n",
 177                               intel_dsm_port_name(info->buffer.pointer[0]));
 178                        DRM_DEBUG_DRIVER("  display mux info: %s\n",
 179                               intel_dsm_mux_type(info->buffer.pointer[1]));
 180                        DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
 181                               intel_dsm_mux_type(info->buffer.pointer[2]));
 182                        DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
 183                               intel_dsm_mux_type(info->buffer.pointer[3]));
 184                }
 185        } else {
 186                DRM_ERROR("MUX INFO call failed\n");
 187        }
 188
 189out:
 190        kfree(output.pointer);
 191}
 192
 193static bool intel_dsm_pci_probe(struct pci_dev *pdev)
 194{
 195        acpi_handle dhandle, intel_handle;
 196        acpi_status status;
 197        int ret;
 198
 199        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
 200        if (!dhandle)
 201                return false;
 202
 203        status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
 204        if (ACPI_FAILURE(status)) {
 205                DRM_DEBUG_KMS("no _DSM method for intel device\n");
 206                return false;
 207        }
 208
 209        ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
 210        if (ret < 0) {
 211                DRM_ERROR("failed to get supported _DSM functions\n");
 212                return false;
 213        }
 214
 215        intel_dsm_priv.dhandle = dhandle;
 216
 217        intel_dsm_platform_mux_info();
 218        return true;
 219}
 220
 221static bool intel_dsm_detect(void)
 222{
 223        char acpi_method_name[255] = { 0 };
 224        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 225        struct pci_dev *pdev = NULL;
 226        bool has_dsm = false;
 227        int vga_count = 0;
 228
 229        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 230                vga_count++;
 231                has_dsm |= intel_dsm_pci_probe(pdev);
 232        }
 233
 234        if (vga_count == 2 && has_dsm) {
 235                acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
 236                DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
 237                                 acpi_method_name);
 238                return true;
 239        }
 240
 241        return false;
 242}
 243
 244void intel_register_dsm_handler(void)
 245{
 246        if (!intel_dsm_detect())
 247                return;
 248}
 249
 250void intel_unregister_dsm_handler(void)
 251{
 252}
 253