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