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