linux/drivers/gpu/drm/nouveau/nouveau_acpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/pci.h>
   3#include <linux/acpi.h>
   4#include <linux/slab.h>
   5#include <linux/mxm-wmi.h>
   6#include <linux/vga_switcheroo.h>
   7#include <drm/drm_edid.h>
   8#include <acpi/video.h>
   9
  10#include "nouveau_drv.h"
  11#include "nouveau_acpi.h"
  12
  13#define NOUVEAU_DSM_LED 0x02
  14#define NOUVEAU_DSM_LED_STATE 0x00
  15#define NOUVEAU_DSM_LED_OFF 0x10
  16#define NOUVEAU_DSM_LED_STAMINA 0x11
  17#define NOUVEAU_DSM_LED_SPEED 0x12
  18
  19#define NOUVEAU_DSM_POWER 0x03
  20#define NOUVEAU_DSM_POWER_STATE 0x00
  21#define NOUVEAU_DSM_POWER_SPEED 0x01
  22#define NOUVEAU_DSM_POWER_STAMINA 0x02
  23
  24#define NOUVEAU_DSM_OPTIMUS_CAPS 0x1A
  25#define NOUVEAU_DSM_OPTIMUS_FLAGS 0x1B
  26
  27#define NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 (3 << 24)
  28#define NOUVEAU_DSM_OPTIMUS_NO_POWERDOWN_PS3 (2 << 24)
  29#define NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED (1)
  30
  31#define NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN (NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 | NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED)
  32
  33/* result of the optimus caps function */
  34#define OPTIMUS_ENABLED (1 << 0)
  35#define OPTIMUS_STATUS_MASK (3 << 3)
  36#define OPTIMUS_STATUS_OFF  (0 << 3)
  37#define OPTIMUS_STATUS_ON_ENABLED  (1 << 3)
  38#define OPTIMUS_STATUS_PWR_STABLE  (3 << 3)
  39#define OPTIMUS_DISPLAY_HOTPLUG (1 << 6)
  40#define OPTIMUS_CAPS_MASK (7 << 24)
  41#define OPTIMUS_DYNAMIC_PWR_CAP (1 << 24)
  42
  43#define OPTIMUS_AUDIO_CAPS_MASK (3 << 27)
  44#define OPTIMUS_HDA_CODEC_MASK (2 << 27) /* hda bios control */
  45
  46static struct nouveau_dsm_priv {
  47        bool dsm_detected;
  48        bool optimus_detected;
  49        bool optimus_flags_detected;
  50        bool optimus_skip_dsm;
  51        acpi_handle dhandle;
  52        acpi_handle rom_handle;
  53} nouveau_dsm_priv;
  54
  55bool nouveau_is_optimus(void) {
  56        return nouveau_dsm_priv.optimus_detected;
  57}
  58
  59bool nouveau_is_v1_dsm(void) {
  60        return nouveau_dsm_priv.dsm_detected;
  61}
  62
  63#ifdef CONFIG_VGA_SWITCHEROO
  64static const guid_t nouveau_dsm_muid =
  65        GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
  66                  0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
  67
  68static const guid_t nouveau_op_dsm_muid =
  69        GUID_INIT(0xA486D8F8, 0x0BDA, 0x471B,
  70                  0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0);
  71
  72static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
  73{
  74        int i;
  75        union acpi_object *obj;
  76        char args_buff[4];
  77        union acpi_object argv4 = {
  78                .buffer.type = ACPI_TYPE_BUFFER,
  79                .buffer.length = 4,
  80                .buffer.pointer = args_buff
  81        };
  82
  83        /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
  84        for (i = 0; i < 4; i++)
  85                args_buff[i] = (arg >> i * 8) & 0xFF;
  86
  87        *result = 0;
  88        obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100,
  89                                      func, &argv4, ACPI_TYPE_BUFFER);
  90        if (!obj) {
  91                acpi_handle_info(handle, "failed to evaluate _DSM\n");
  92                return AE_ERROR;
  93        } else {
  94                if (obj->buffer.length == 4) {
  95                        *result |= obj->buffer.pointer[0];
  96                        *result |= (obj->buffer.pointer[1] << 8);
  97                        *result |= (obj->buffer.pointer[2] << 16);
  98                        *result |= (obj->buffer.pointer[3] << 24);
  99                }
 100                ACPI_FREE(obj);
 101        }
 102
 103        return 0;
 104}
 105
 106/*
 107 * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
 108 * requirements on the fourth parameter, so a private implementation
 109 * instead of using acpi_check_dsm().
 110 */
 111static int nouveau_dsm_get_optimus_functions(acpi_handle handle)
 112{
 113        int result;
 114
 115        /*
 116         * Function 0 returns a Buffer containing available functions.
 117         * The args parameter is ignored for function 0, so just put 0 in it
 118         */
 119        if (nouveau_optimus_dsm(handle, 0, 0, &result))
 120                return 0;
 121
 122        /*
 123         * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
 124         * If the n-th bit is enabled, function n is supported
 125         */
 126        if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS))
 127                return result;
 128        return 0;
 129}
 130
 131static int nouveau_dsm(acpi_handle handle, int func, int arg)
 132{
 133        int ret = 0;
 134        union acpi_object *obj;
 135        union acpi_object argv4 = {
 136                .integer.type = ACPI_TYPE_INTEGER,
 137                .integer.value = arg,
 138        };
 139
 140        obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102,
 141                                      func, &argv4, ACPI_TYPE_INTEGER);
 142        if (!obj) {
 143                acpi_handle_info(handle, "failed to evaluate _DSM\n");
 144                return AE_ERROR;
 145        } else {
 146                if (obj->integer.value == 0x80000002)
 147                        ret = -ENODEV;
 148                ACPI_FREE(obj);
 149        }
 150
 151        return ret;
 152}
 153
 154static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 155{
 156        mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
 157        mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
 158        return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id);
 159}
 160
 161static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
 162{
 163        int arg;
 164        if (state == VGA_SWITCHEROO_ON)
 165                arg = NOUVEAU_DSM_POWER_SPEED;
 166        else
 167                arg = NOUVEAU_DSM_POWER_STAMINA;
 168        nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg);
 169        return 0;
 170}
 171
 172static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
 173{
 174        if (!nouveau_dsm_priv.dsm_detected)
 175                return 0;
 176        if (id == VGA_SWITCHEROO_IGD)
 177                return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
 178        else
 179                return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED);
 180}
 181
 182static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
 183                                   enum vga_switcheroo_state state)
 184{
 185        if (id == VGA_SWITCHEROO_IGD)
 186                return 0;
 187
 188        /* Optimus laptops have the card already disabled in
 189         * nouveau_switcheroo_set_state */
 190        if (!nouveau_dsm_priv.dsm_detected)
 191                return 0;
 192
 193        return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 194}
 195
 196static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 197{
 198        /* easy option one - intel vendor ID means Integrated */
 199        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
 200                return VGA_SWITCHEROO_IGD;
 201
 202        /* is this device on Bus 0? - this may need improving */
 203        if (pdev->bus->number == 0)
 204                return VGA_SWITCHEROO_IGD;
 205
 206        return VGA_SWITCHEROO_DIS;
 207}
 208
 209static const struct vga_switcheroo_handler nouveau_dsm_handler = {
 210        .switchto = nouveau_dsm_switchto,
 211        .power_state = nouveau_dsm_power_state,
 212        .get_client_id = nouveau_dsm_get_client_id,
 213};
 214
 215/*
 216 * Firmware supporting Windows 8 or later do not use _DSM to put the device into
 217 * D3cold, they instead rely on disabling power resources on the parent.
 218 */
 219static bool nouveau_pr3_present(struct pci_dev *pdev)
 220{
 221        struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
 222        struct acpi_device *parent_adev;
 223
 224        if (!parent_pdev)
 225                return false;
 226
 227        if (!parent_pdev->bridge_d3) {
 228                /*
 229                 * Parent PCI bridge is currently not power managed.
 230                 * Since userspace can change these afterwards to be on
 231                 * the safe side we stick with _DSM and prevent usage of
 232                 * _PR3 from the bridge.
 233                 */
 234                pci_d3cold_disable(pdev);
 235                return false;
 236        }
 237
 238        parent_adev = ACPI_COMPANION(&parent_pdev->dev);
 239        if (!parent_adev)
 240                return false;
 241
 242        return parent_adev->power.flags.power_resources &&
 243                acpi_has_method(parent_adev->handle, "_PR3");
 244}
 245
 246static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
 247                                  bool *has_mux, bool *has_opt,
 248                                  bool *has_opt_flags, bool *has_pr3)
 249{
 250        acpi_handle dhandle;
 251        bool supports_mux;
 252        int optimus_funcs;
 253
 254        dhandle = ACPI_HANDLE(&pdev->dev);
 255        if (!dhandle)
 256                return;
 257
 258        if (!acpi_has_method(dhandle, "_DSM"))
 259                return;
 260
 261        supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102,
 262                                      1 << NOUVEAU_DSM_POWER);
 263        optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
 264
 265        /* Does not look like a Nvidia device. */
 266        if (!supports_mux && !optimus_funcs)
 267                return;
 268
 269        *dhandle_out = dhandle;
 270        *has_mux = supports_mux;
 271        *has_opt = !!optimus_funcs;
 272        *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
 273        *has_pr3 = false;
 274
 275        if (optimus_funcs) {
 276                uint32_t result;
 277                nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0,
 278                                    &result);
 279                dev_info(&pdev->dev, "optimus capabilities: %s, status %s%s\n",
 280                         (result & OPTIMUS_ENABLED) ? "enabled" : "disabled",
 281                         (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "",
 282                         (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : "");
 283
 284                *has_pr3 = nouveau_pr3_present(pdev);
 285        }
 286}
 287
 288static bool nouveau_dsm_detect(void)
 289{
 290        char acpi_method_name[255] = { 0 };
 291        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 292        struct pci_dev *pdev = NULL;
 293        acpi_handle dhandle = NULL;
 294        bool has_mux = false;
 295        bool has_optimus = false;
 296        bool has_optimus_flags = false;
 297        bool has_power_resources = false;
 298        int vga_count = 0;
 299        bool guid_valid;
 300        bool ret = false;
 301
 302        /* lookup the MXM GUID */
 303        guid_valid = mxm_wmi_supported();
 304
 305        if (guid_valid)
 306                printk("MXM: GUID detected in BIOS\n");
 307
 308        /* now do DSM detection */
 309        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 310                vga_count++;
 311
 312                nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
 313                                      &has_optimus_flags, &has_power_resources);
 314        }
 315
 316        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
 317                vga_count++;
 318
 319                nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
 320                                      &has_optimus_flags, &has_power_resources);
 321        }
 322
 323        /* find the optimus DSM or the old v1 DSM */
 324        if (has_optimus) {
 325                nouveau_dsm_priv.dhandle = dhandle;
 326                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
 327                        &buffer);
 328                pr_info("VGA switcheroo: detected Optimus DSM method %s handle\n",
 329                        acpi_method_name);
 330                if (has_power_resources)
 331                        pr_info("nouveau: detected PR support, will not use DSM\n");
 332                nouveau_dsm_priv.optimus_detected = true;
 333                nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
 334                nouveau_dsm_priv.optimus_skip_dsm = has_power_resources;
 335                ret = true;
 336        } else if (vga_count == 2 && has_mux && guid_valid) {
 337                nouveau_dsm_priv.dhandle = dhandle;
 338                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
 339                        &buffer);
 340                pr_info("VGA switcheroo: detected DSM switching method %s handle\n",
 341                        acpi_method_name);
 342                nouveau_dsm_priv.dsm_detected = true;
 343                ret = true;
 344        }
 345
 346
 347        return ret;
 348}
 349
 350void nouveau_register_dsm_handler(void)
 351{
 352        bool r;
 353
 354        r = nouveau_dsm_detect();
 355        if (!r)
 356                return;
 357
 358        vga_switcheroo_register_handler(&nouveau_dsm_handler, 0);
 359}
 360
 361/* Must be called for Optimus models before the card can be turned off */
 362void nouveau_switcheroo_optimus_dsm(void)
 363{
 364        u32 result = 0;
 365        if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm)
 366                return;
 367
 368        if (nouveau_dsm_priv.optimus_flags_detected)
 369                nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
 370                                    0x3, &result);
 371
 372        nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS,
 373                NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result);
 374
 375}
 376
 377void nouveau_unregister_dsm_handler(void)
 378{
 379        if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected)
 380                vga_switcheroo_unregister_handler();
 381}
 382#else
 383void nouveau_register_dsm_handler(void) {}
 384void nouveau_unregister_dsm_handler(void) {}
 385void nouveau_switcheroo_optimus_dsm(void) {}
 386#endif
 387
 388/* retrieve the ROM in 4k blocks */
 389static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
 390                            int offset, int len)
 391{
 392        acpi_status status;
 393        union acpi_object rom_arg_elements[2], *obj;
 394        struct acpi_object_list rom_arg;
 395        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
 396
 397        rom_arg.count = 2;
 398        rom_arg.pointer = &rom_arg_elements[0];
 399
 400        rom_arg_elements[0].type = ACPI_TYPE_INTEGER;
 401        rom_arg_elements[0].integer.value = offset;
 402
 403        rom_arg_elements[1].type = ACPI_TYPE_INTEGER;
 404        rom_arg_elements[1].integer.value = len;
 405
 406        status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer);
 407        if (ACPI_FAILURE(status)) {
 408                pr_info("failed to evaluate ROM got %s\n",
 409                        acpi_format_exception(status));
 410                return -ENODEV;
 411        }
 412        obj = (union acpi_object *)buffer.pointer;
 413        len = min(len, (int)obj->buffer.length);
 414        memcpy(bios+offset, obj->buffer.pointer, len);
 415        kfree(buffer.pointer);
 416        return len;
 417}
 418
 419bool nouveau_acpi_rom_supported(struct device *dev)
 420{
 421        acpi_status status;
 422        acpi_handle dhandle, rom_handle;
 423
 424        dhandle = ACPI_HANDLE(dev);
 425        if (!dhandle)
 426                return false;
 427
 428        status = acpi_get_handle(dhandle, "_ROM", &rom_handle);
 429        if (ACPI_FAILURE(status))
 430                return false;
 431
 432        nouveau_dsm_priv.rom_handle = rom_handle;
 433        return true;
 434}
 435
 436int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
 437{
 438        return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
 439}
 440
 441void *
 442nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
 443{
 444        struct acpi_device *acpidev;
 445        acpi_handle handle;
 446        int type, ret;
 447        void *edid;
 448
 449        switch (connector->connector_type) {
 450        case DRM_MODE_CONNECTOR_LVDS:
 451        case DRM_MODE_CONNECTOR_eDP:
 452                type = ACPI_VIDEO_DISPLAY_LCD;
 453                break;
 454        default:
 455                return NULL;
 456        }
 457
 458        handle = ACPI_HANDLE(&dev->pdev->dev);
 459        if (!handle)
 460                return NULL;
 461
 462        ret = acpi_bus_get_device(handle, &acpidev);
 463        if (ret)
 464                return NULL;
 465
 466        ret = acpi_video_get_edid(acpidev, type, -1, &edid);
 467        if (ret < 0)
 468                return NULL;
 469
 470        return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
 471}
 472