linux/drivers/gpu/drm/i915/display/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
   8#include <linux/pci.h>
   9#include <linux/acpi.h>
  10
  11#include "i915_drv.h"
  12#include "intel_acpi.h"
  13#include "intel_display_types.h"
  14
  15#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
  16#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
  17
  18static const guid_t intel_dsm_guid =
  19        GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
  20                  0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
  21
  22#define INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED 0 /* No args */
  23
  24static const guid_t intel_dsm_guid2 =
  25        GUID_INIT(0x3e5b41c6, 0xeb1d, 0x4260,
  26                  0x9d, 0x15, 0xc7, 0x1f, 0xba, 0xda, 0xe4, 0x14);
  27
  28static char *intel_dsm_port_name(u8 id)
  29{
  30        switch (id) {
  31        case 0:
  32                return "Reserved";
  33        case 1:
  34                return "Analog VGA";
  35        case 2:
  36                return "LVDS";
  37        case 3:
  38                return "Reserved";
  39        case 4:
  40                return "HDMI/DVI_B";
  41        case 5:
  42                return "HDMI/DVI_C";
  43        case 6:
  44                return "HDMI/DVI_D";
  45        case 7:
  46                return "DisplayPort_A";
  47        case 8:
  48                return "DisplayPort_B";
  49        case 9:
  50                return "DisplayPort_C";
  51        case 0xa:
  52                return "DisplayPort_D";
  53        case 0xb:
  54        case 0xc:
  55        case 0xd:
  56                return "Reserved";
  57        case 0xe:
  58                return "WiDi";
  59        default:
  60                return "bad type";
  61        }
  62}
  63
  64static char *intel_dsm_mux_type(u8 type)
  65{
  66        switch (type) {
  67        case 0:
  68                return "unknown";
  69        case 1:
  70                return "No MUX, iGPU only";
  71        case 2:
  72                return "No MUX, dGPU only";
  73        case 3:
  74                return "MUXed between iGPU and dGPU";
  75        default:
  76                return "bad type";
  77        }
  78}
  79
  80static void intel_dsm_platform_mux_info(acpi_handle dhandle)
  81{
  82        int i;
  83        union acpi_object *pkg, *connector_count;
  84
  85        pkg = acpi_evaluate_dsm_typed(dhandle, &intel_dsm_guid,
  86                        INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
  87                        NULL, ACPI_TYPE_PACKAGE);
  88        if (!pkg) {
  89                DRM_DEBUG_DRIVER("failed to evaluate _DSM\n");
  90                return;
  91        }
  92
  93        if (!pkg->package.count) {
  94                DRM_DEBUG_DRIVER("no connection in _DSM\n");
  95                return;
  96        }
  97
  98        connector_count = &pkg->package.elements[0];
  99        DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
 100                  (unsigned long long)connector_count->integer.value);
 101        for (i = 1; i < pkg->package.count; i++) {
 102                union acpi_object *obj = &pkg->package.elements[i];
 103                union acpi_object *connector_id;
 104                union acpi_object *info;
 105
 106                if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
 107                        DRM_DEBUG_DRIVER("Invalid object for MUX #%d\n", i);
 108                        continue;
 109                }
 110
 111                connector_id = &obj->package.elements[0];
 112                info = &obj->package.elements[1];
 113                if (info->type != ACPI_TYPE_BUFFER || info->buffer.length < 4) {
 114                        DRM_DEBUG_DRIVER("Invalid info for MUX obj #%d\n", i);
 115                        continue;
 116                }
 117
 118                DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
 119                          (unsigned long long)connector_id->integer.value);
 120                DRM_DEBUG_DRIVER("  port id: %s\n",
 121                       intel_dsm_port_name(info->buffer.pointer[0]));
 122                DRM_DEBUG_DRIVER("  display mux info: %s\n",
 123                       intel_dsm_mux_type(info->buffer.pointer[1]));
 124                DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
 125                       intel_dsm_mux_type(info->buffer.pointer[2]));
 126                DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
 127                       intel_dsm_mux_type(info->buffer.pointer[3]));
 128        }
 129
 130        ACPI_FREE(pkg);
 131}
 132
 133static acpi_handle intel_dsm_pci_probe(struct pci_dev *pdev)
 134{
 135        acpi_handle dhandle;
 136
 137        dhandle = ACPI_HANDLE(&pdev->dev);
 138        if (!dhandle)
 139                return NULL;
 140
 141        if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
 142                            1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
 143                DRM_DEBUG_KMS("no _DSM method for intel device\n");
 144                return NULL;
 145        }
 146
 147        intel_dsm_platform_mux_info(dhandle);
 148
 149        return dhandle;
 150}
 151
 152static bool intel_dsm_detect(void)
 153{
 154        acpi_handle dhandle = NULL;
 155        char acpi_method_name[255] = { 0 };
 156        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 157        struct pci_dev *pdev = NULL;
 158        int vga_count = 0;
 159
 160        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 161                vga_count++;
 162                dhandle = intel_dsm_pci_probe(pdev) ?: dhandle;
 163        }
 164
 165        if (vga_count == 2 && dhandle) {
 166                acpi_get_name(dhandle, ACPI_FULL_PATHNAME, &buffer);
 167                DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
 168                                 acpi_method_name);
 169                return true;
 170        }
 171
 172        return false;
 173}
 174
 175void intel_register_dsm_handler(void)
 176{
 177        if (!intel_dsm_detect())
 178                return;
 179}
 180
 181void intel_unregister_dsm_handler(void)
 182{
 183}
 184
 185void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915)
 186{
 187        struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
 188        acpi_handle dhandle;
 189        union acpi_object *obj;
 190
 191        dhandle = ACPI_HANDLE(&pdev->dev);
 192        if (!dhandle)
 193                return;
 194
 195        obj = acpi_evaluate_dsm(dhandle, &intel_dsm_guid2, INTEL_DSM_REVISION_ID,
 196                                INTEL_DSM_FN_GET_BIOS_DATA_FUNCS_SUPPORTED, NULL);
 197        if (obj)
 198                ACPI_FREE(obj);
 199}
 200
 201/*
 202 * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
 203 * Attached to the Display Adapter).
 204 */
 205#define ACPI_DISPLAY_INDEX_SHIFT                0
 206#define ACPI_DISPLAY_INDEX_MASK                 (0xf << 0)
 207#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT      4
 208#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK       (0xf << 4)
 209#define ACPI_DISPLAY_TYPE_SHIFT                 8
 210#define ACPI_DISPLAY_TYPE_MASK                  (0xf << 8)
 211#define ACPI_DISPLAY_TYPE_OTHER                 (0 << 8)
 212#define ACPI_DISPLAY_TYPE_VGA                   (1 << 8)
 213#define ACPI_DISPLAY_TYPE_TV                    (2 << 8)
 214#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL      (3 << 8)
 215#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL      (4 << 8)
 216#define ACPI_VENDOR_SPECIFIC_SHIFT              12
 217#define ACPI_VENDOR_SPECIFIC_MASK               (0xf << 12)
 218#define ACPI_BIOS_CAN_DETECT                    (1 << 16)
 219#define ACPI_DEPENDS_ON_VGA                     (1 << 17)
 220#define ACPI_PIPE_ID_SHIFT                      18
 221#define ACPI_PIPE_ID_MASK                       (7 << 18)
 222#define ACPI_DEVICE_ID_SCHEME                   (1ULL << 31)
 223
 224static u32 acpi_display_type(struct intel_connector *connector)
 225{
 226        u32 display_type;
 227
 228        switch (connector->base.connector_type) {
 229        case DRM_MODE_CONNECTOR_VGA:
 230        case DRM_MODE_CONNECTOR_DVIA:
 231                display_type = ACPI_DISPLAY_TYPE_VGA;
 232                break;
 233        case DRM_MODE_CONNECTOR_Composite:
 234        case DRM_MODE_CONNECTOR_SVIDEO:
 235        case DRM_MODE_CONNECTOR_Component:
 236        case DRM_MODE_CONNECTOR_9PinDIN:
 237        case DRM_MODE_CONNECTOR_TV:
 238                display_type = ACPI_DISPLAY_TYPE_TV;
 239                break;
 240        case DRM_MODE_CONNECTOR_DVII:
 241        case DRM_MODE_CONNECTOR_DVID:
 242        case DRM_MODE_CONNECTOR_DisplayPort:
 243        case DRM_MODE_CONNECTOR_HDMIA:
 244        case DRM_MODE_CONNECTOR_HDMIB:
 245                display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
 246                break;
 247        case DRM_MODE_CONNECTOR_LVDS:
 248        case DRM_MODE_CONNECTOR_eDP:
 249        case DRM_MODE_CONNECTOR_DSI:
 250                display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
 251                break;
 252        case DRM_MODE_CONNECTOR_Unknown:
 253        case DRM_MODE_CONNECTOR_VIRTUAL:
 254                display_type = ACPI_DISPLAY_TYPE_OTHER;
 255                break;
 256        default:
 257                MISSING_CASE(connector->base.connector_type);
 258                display_type = ACPI_DISPLAY_TYPE_OTHER;
 259                break;
 260        }
 261
 262        return display_type;
 263}
 264
 265void intel_acpi_device_id_update(struct drm_i915_private *dev_priv)
 266{
 267        struct drm_device *drm_dev = &dev_priv->drm;
 268        struct intel_connector *connector;
 269        struct drm_connector_list_iter conn_iter;
 270        u8 display_index[16] = {};
 271
 272        /* Populate the ACPI IDs for all connectors for a given drm_device */
 273        drm_connector_list_iter_begin(drm_dev, &conn_iter);
 274        for_each_intel_connector_iter(connector, &conn_iter) {
 275                u32 device_id, type;
 276
 277                device_id = acpi_display_type(connector);
 278
 279                /* Use display type specific display index. */
 280                type = (device_id & ACPI_DISPLAY_TYPE_MASK)
 281                        >> ACPI_DISPLAY_TYPE_SHIFT;
 282                device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
 283
 284                connector->acpi_device_id = device_id;
 285        }
 286        drm_connector_list_iter_end(&conn_iter);
 287}
 288