1b7019ac5SIlia Mirkin // SPDX-License-Identifier: MIT 26ee73861SBen Skeggs #include <linux/pci.h> 36ee73861SBen Skeggs #include <linux/acpi.h> 45a0e3ad6STejun Heo #include <linux/slab.h> 58116188fSDave Airlie #include <linux/mxm-wmi.h> 66a9ee8afSDave Airlie #include <linux/vga_switcheroo.h> 7612a9aabSLinus Torvalds #include <drm/drm_edid.h> 88b48463fSLv Zheng #include <acpi/video.h> 9c0077061SBen Skeggs 104dc28134SBen Skeggs #include "nouveau_drv.h" 11c0077061SBen Skeggs #include "nouveau_acpi.h" 12c0077061SBen Skeggs 136ee73861SBen Skeggs #define NOUVEAU_DSM_LED 0x02 146ee73861SBen Skeggs #define NOUVEAU_DSM_LED_STATE 0x00 156ee73861SBen Skeggs #define NOUVEAU_DSM_LED_OFF 0x10 166ee73861SBen Skeggs #define NOUVEAU_DSM_LED_STAMINA 0x11 176ee73861SBen Skeggs #define NOUVEAU_DSM_LED_SPEED 0x12 186ee73861SBen Skeggs 196ee73861SBen Skeggs #define NOUVEAU_DSM_POWER 0x03 206ee73861SBen Skeggs #define NOUVEAU_DSM_POWER_STATE 0x00 216ee73861SBen Skeggs #define NOUVEAU_DSM_POWER_SPEED 0x01 226ee73861SBen Skeggs #define NOUVEAU_DSM_POWER_STAMINA 0x02 236ee73861SBen Skeggs 245addcf0aSDave Airlie #define NOUVEAU_DSM_OPTIMUS_CAPS 0x1A 255addcf0aSDave Airlie #define NOUVEAU_DSM_OPTIMUS_FLAGS 0x1B 265addcf0aSDave Airlie 275addcf0aSDave Airlie #define NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 (3 << 24) 285addcf0aSDave Airlie #define NOUVEAU_DSM_OPTIMUS_NO_POWERDOWN_PS3 (2 << 24) 295addcf0aSDave Airlie #define NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED (1) 305addcf0aSDave Airlie 315addcf0aSDave Airlie #define NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN (NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 | NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED) 325addcf0aSDave Airlie 335addcf0aSDave Airlie /* result of the optimus caps function */ 345addcf0aSDave Airlie #define OPTIMUS_ENABLED (1 << 0) 355addcf0aSDave Airlie #define OPTIMUS_STATUS_MASK (3 << 3) 365addcf0aSDave Airlie #define OPTIMUS_STATUS_OFF (0 << 3) 375addcf0aSDave Airlie #define OPTIMUS_STATUS_ON_ENABLED (1 << 3) 385addcf0aSDave Airlie #define OPTIMUS_STATUS_PWR_STABLE (3 << 3) 395addcf0aSDave Airlie #define OPTIMUS_DISPLAY_HOTPLUG (1 << 6) 405addcf0aSDave Airlie #define OPTIMUS_CAPS_MASK (7 << 24) 415addcf0aSDave Airlie #define OPTIMUS_DYNAMIC_PWR_CAP (1 << 24) 425addcf0aSDave Airlie 435addcf0aSDave Airlie #define OPTIMUS_AUDIO_CAPS_MASK (3 << 27) 445addcf0aSDave Airlie #define OPTIMUS_HDA_CODEC_MASK (2 << 27) /* hda bios control */ 45d099230cSPeter Lekensteyn 466a9ee8afSDave Airlie static struct nouveau_dsm_priv { 476a9ee8afSDave Airlie bool dsm_detected; 48f19467c5SDave Airlie bool optimus_detected; 49cba97805SPeter Wu bool optimus_flags_detected; 50692a17dcSPeter Wu bool optimus_skip_dsm; 516a9ee8afSDave Airlie acpi_handle dhandle; 526a9ee8afSDave Airlie } nouveau_dsm_priv; 536a9ee8afSDave Airlie 54c839d748SDave Airlie bool nouveau_is_optimus(void) { 55c839d748SDave Airlie return nouveau_dsm_priv.optimus_detected; 56c839d748SDave Airlie } 57c839d748SDave Airlie 58c839d748SDave Airlie bool nouveau_is_v1_dsm(void) { 59c839d748SDave Airlie return nouveau_dsm_priv.dsm_detected; 60c839d748SDave Airlie } 61c839d748SDave Airlie 62d0ce7b85SJeff Mahoney #ifdef CONFIG_VGA_SWITCHEROO 6394116f81SAndy Shevchenko static const guid_t nouveau_dsm_muid = 6494116f81SAndy Shevchenko GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48, 6594116f81SAndy Shevchenko 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4); 666ee73861SBen Skeggs 6794116f81SAndy Shevchenko static const guid_t nouveau_op_dsm_muid = 6894116f81SAndy Shevchenko GUID_INIT(0xA486D8F8, 0x0BDA, 0x471B, 6994116f81SAndy Shevchenko 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0); 70f19467c5SDave Airlie 71f19467c5SDave Airlie static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) 72f19467c5SDave Airlie { 73b072e53bSJiang Liu int i; 74f19467c5SDave Airlie union acpi_object *obj; 75d099230cSPeter Lekensteyn char args_buff[4]; 76b072e53bSJiang Liu union acpi_object argv4 = { 77b072e53bSJiang Liu .buffer.type = ACPI_TYPE_BUFFER, 78b072e53bSJiang Liu .buffer.length = 4, 79b072e53bSJiang Liu .buffer.pointer = args_buff 80b072e53bSJiang Liu }; 81f19467c5SDave Airlie 82d099230cSPeter Lekensteyn /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ 83d099230cSPeter Lekensteyn for (i = 0; i < 4; i++) 84d099230cSPeter Lekensteyn args_buff[i] = (arg >> i * 8) & 0xFF; 85f19467c5SDave Airlie 86f19467c5SDave Airlie *result = 0; 8794116f81SAndy Shevchenko obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100, 88b072e53bSJiang Liu func, &argv4, ACPI_TYPE_BUFFER); 89b072e53bSJiang Liu if (!obj) { 90b072e53bSJiang Liu acpi_handle_info(handle, "failed to evaluate _DSM\n"); 91b072e53bSJiang Liu return AE_ERROR; 92b072e53bSJiang Liu } else { 93b072e53bSJiang Liu if (obj->buffer.length == 4) { 94f19467c5SDave Airlie *result |= obj->buffer.pointer[0]; 95f19467c5SDave Airlie *result |= (obj->buffer.pointer[1] << 8); 96f19467c5SDave Airlie *result |= (obj->buffer.pointer[2] << 16); 97f19467c5SDave Airlie *result |= (obj->buffer.pointer[3] << 24); 98f19467c5SDave Airlie } 99b072e53bSJiang Liu ACPI_FREE(obj); 100f19467c5SDave Airlie } 101f19467c5SDave Airlie 102f19467c5SDave Airlie return 0; 103f19467c5SDave Airlie } 104f19467c5SDave Airlie 105e284175aSJiang Liu /* 106e284175aSJiang Liu * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special 107e284175aSJiang Liu * requirements on the fourth parameter, so a private implementation 108e284175aSJiang Liu * instead of using acpi_check_dsm(). 109e284175aSJiang Liu */ 110a12e78ddSPeter Wu static int nouveau_dsm_get_optimus_functions(acpi_handle handle) 111e284175aSJiang Liu { 112e284175aSJiang Liu int result; 113e284175aSJiang Liu 114e284175aSJiang Liu /* 115e284175aSJiang Liu * Function 0 returns a Buffer containing available functions. 116e284175aSJiang Liu * The args parameter is ignored for function 0, so just put 0 in it 117e284175aSJiang Liu */ 118e284175aSJiang Liu if (nouveau_optimus_dsm(handle, 0, 0, &result)) 119e284175aSJiang Liu return 0; 120e284175aSJiang Liu 121e284175aSJiang Liu /* 122e284175aSJiang Liu * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. 123e284175aSJiang Liu * If the n-th bit is enabled, function n is supported 124e284175aSJiang Liu */ 125a12e78ddSPeter Wu if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS)) 126a12e78ddSPeter Wu return result; 127a12e78ddSPeter Wu return 0; 128e284175aSJiang Liu } 129e284175aSJiang Liu 130b072e53bSJiang Liu static int nouveau_dsm(acpi_handle handle, int func, int arg) 1316a9ee8afSDave Airlie { 132b072e53bSJiang Liu int ret = 0; 1336ee73861SBen Skeggs union acpi_object *obj; 134b072e53bSJiang Liu union acpi_object argv4 = { 135b072e53bSJiang Liu .integer.type = ACPI_TYPE_INTEGER, 136b072e53bSJiang Liu .integer.value = arg, 137b072e53bSJiang Liu }; 1386ee73861SBen Skeggs 13994116f81SAndy Shevchenko obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102, 140b072e53bSJiang Liu func, &argv4, ACPI_TYPE_INTEGER); 141b072e53bSJiang Liu if (!obj) { 142b072e53bSJiang Liu acpi_handle_info(handle, "failed to evaluate _DSM\n"); 143b072e53bSJiang Liu return AE_ERROR; 144b072e53bSJiang Liu } else { 1456ee73861SBen Skeggs if (obj->integer.value == 0x80000002) 146b072e53bSJiang Liu ret = -ENODEV; 147b072e53bSJiang Liu ACPI_FREE(obj); 1486ee73861SBen Skeggs } 1496ee73861SBen Skeggs 150b072e53bSJiang Liu return ret; 1519075e85fSPeter Lekensteyn } 1529075e85fSPeter Lekensteyn 1536a9ee8afSDave Airlie static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) 1546ee73861SBen Skeggs { 155000703f4SDave Airlie mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); 1568116188fSDave Airlie mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); 157b072e53bSJiang Liu return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id); 1586ee73861SBen Skeggs } 1596ee73861SBen Skeggs 1606a9ee8afSDave Airlie static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) 1616a9ee8afSDave Airlie { 1626a9ee8afSDave Airlie int arg; 1636a9ee8afSDave Airlie if (state == VGA_SWITCHEROO_ON) 1646a9ee8afSDave Airlie arg = NOUVEAU_DSM_POWER_SPEED; 1656a9ee8afSDave Airlie else 1666a9ee8afSDave Airlie arg = NOUVEAU_DSM_POWER_STAMINA; 167b072e53bSJiang Liu nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg); 1686ee73861SBen Skeggs return 0; 1696ee73861SBen Skeggs } 1706ee73861SBen Skeggs 1716a9ee8afSDave Airlie static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) 1726ee73861SBen Skeggs { 173c839d748SDave Airlie if (!nouveau_dsm_priv.dsm_detected) 174d099230cSPeter Lekensteyn return 0; 1756a9ee8afSDave Airlie if (id == VGA_SWITCHEROO_IGD) 176fc5ea29dSDave Airlie return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); 1776a9ee8afSDave Airlie else 178fc5ea29dSDave Airlie return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED); 1796a9ee8afSDave Airlie } 1806ee73861SBen Skeggs 1816a9ee8afSDave Airlie static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, 1826a9ee8afSDave Airlie enum vga_switcheroo_state state) 1836a9ee8afSDave Airlie { 1846a9ee8afSDave Airlie if (id == VGA_SWITCHEROO_IGD) 1856a9ee8afSDave Airlie return 0; 1866a9ee8afSDave Airlie 187d099230cSPeter Lekensteyn /* Optimus laptops have the card already disabled in 188d099230cSPeter Lekensteyn * nouveau_switcheroo_set_state */ 189c839d748SDave Airlie if (!nouveau_dsm_priv.dsm_detected) 190d099230cSPeter Lekensteyn return 0; 191d099230cSPeter Lekensteyn 192fc5ea29dSDave Airlie return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); 1936a9ee8afSDave Airlie } 1946a9ee8afSDave Airlie 195f43cda5cSLuc Van Oostenryck static enum vga_switcheroo_client_id nouveau_dsm_get_client_id(struct pci_dev *pdev) 1966a9ee8afSDave Airlie { 197d1fbd923SDave Airlie /* easy option one - intel vendor ID means Integrated */ 198d1fbd923SDave Airlie if (pdev->vendor == PCI_VENDOR_ID_INTEL) 1996a9ee8afSDave Airlie return VGA_SWITCHEROO_IGD; 200d1fbd923SDave Airlie 201d1fbd923SDave Airlie /* is this device on Bus 0? - this may need improving */ 202d1fbd923SDave Airlie if (pdev->bus->number == 0) 203d1fbd923SDave Airlie return VGA_SWITCHEROO_IGD; 204d1fbd923SDave Airlie 2056a9ee8afSDave Airlie return VGA_SWITCHEROO_DIS; 2066a9ee8afSDave Airlie } 2076a9ee8afSDave Airlie 2085d170139SLukas Wunner static const struct vga_switcheroo_handler nouveau_dsm_handler = { 2096a9ee8afSDave Airlie .switchto = nouveau_dsm_switchto, 2106a9ee8afSDave Airlie .power_state = nouveau_dsm_power_state, 2116a9ee8afSDave Airlie .get_client_id = nouveau_dsm_get_client_id, 2126a9ee8afSDave Airlie }; 2136a9ee8afSDave Airlie 214df42194aSPeter Wu static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out, 215cba97805SPeter Wu bool *has_mux, bool *has_opt, 216692a17dcSPeter Wu bool *has_opt_flags, bool *has_pr3) 2176a9ee8afSDave Airlie { 218187b5b5dSZhang Rui acpi_handle dhandle; 219df42194aSPeter Wu bool supports_mux; 220a12e78ddSPeter Wu int optimus_funcs; 221*ccfc2d5cSKai-Heng Feng struct pci_dev *parent_pdev; 222*ccfc2d5cSKai-Heng Feng 223*ccfc2d5cSKai-Heng Feng *has_pr3 = false; 224*ccfc2d5cSKai-Heng Feng parent_pdev = pci_upstream_bridge(pdev); 225*ccfc2d5cSKai-Heng Feng if (parent_pdev) { 226*ccfc2d5cSKai-Heng Feng if (parent_pdev->bridge_d3) 227*ccfc2d5cSKai-Heng Feng *has_pr3 = pci_pr3_present(parent_pdev); 228*ccfc2d5cSKai-Heng Feng else 229*ccfc2d5cSKai-Heng Feng pci_d3cold_disable(pdev); 230*ccfc2d5cSKai-Heng Feng } 2316a9ee8afSDave Airlie 2323a83f992SRafael J. Wysocki dhandle = ACPI_HANDLE(&pdev->dev); 2336a9ee8afSDave Airlie if (!dhandle) 234df42194aSPeter Wu return; 235afeb3e11SDave Airlie 236f91ce35eSBjorn Helgaas if (!acpi_has_method(dhandle, "_DSM")) 237df42194aSPeter Wu return; 238f91ce35eSBjorn Helgaas 23994116f81SAndy Shevchenko supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102, 240df42194aSPeter Wu 1 << NOUVEAU_DSM_POWER); 241a12e78ddSPeter Wu optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle); 2426ee73861SBen Skeggs 243df42194aSPeter Wu /* Does not look like a Nvidia device. */ 244a12e78ddSPeter Wu if (!supports_mux && !optimus_funcs) 245df42194aSPeter Wu return; 246f19467c5SDave Airlie 247df42194aSPeter Wu *dhandle_out = dhandle; 248df42194aSPeter Wu *has_mux = supports_mux; 249a12e78ddSPeter Wu *has_opt = !!optimus_funcs; 250cba97805SPeter Wu *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS); 251df42194aSPeter Wu 252a12e78ddSPeter Wu if (optimus_funcs) { 2535addcf0aSDave Airlie uint32_t result; 2545addcf0aSDave Airlie nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0, 2555addcf0aSDave Airlie &result); 2565addcf0aSDave Airlie dev_info(&pdev->dev, "optimus capabilities: %s, status %s%s\n", 2575addcf0aSDave Airlie (result & OPTIMUS_ENABLED) ? "enabled" : "disabled", 2585addcf0aSDave Airlie (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "", 2595addcf0aSDave Airlie (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : ""); 2605addcf0aSDave Airlie } 2616ee73861SBen Skeggs } 2626a9ee8afSDave Airlie 2636a9ee8afSDave Airlie static bool nouveau_dsm_detect(void) 2646a9ee8afSDave Airlie { 2656a9ee8afSDave Airlie char acpi_method_name[255] = { 0 }; 2666a9ee8afSDave Airlie struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 2676a9ee8afSDave Airlie struct pci_dev *pdev = NULL; 268df42194aSPeter Wu acpi_handle dhandle = NULL; 269df42194aSPeter Wu bool has_mux = false; 270df42194aSPeter Wu bool has_optimus = false; 271cba97805SPeter Wu bool has_optimus_flags = false; 272692a17dcSPeter Wu bool has_power_resources = false; 2736a9ee8afSDave Airlie int vga_count = 0; 2748116188fSDave Airlie bool guid_valid; 275f19467c5SDave Airlie bool ret = false; 2768116188fSDave Airlie 277f19467c5SDave Airlie /* lookup the MXM GUID */ 2788116188fSDave Airlie guid_valid = mxm_wmi_supported(); 2798116188fSDave Airlie 280f19467c5SDave Airlie if (guid_valid) 281f19467c5SDave Airlie printk("MXM: GUID detected in BIOS\n"); 282afeb3e11SDave Airlie 283f19467c5SDave Airlie /* now do DSM detection */ 2846a9ee8afSDave Airlie while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 2856a9ee8afSDave Airlie vga_count++; 2866a9ee8afSDave Airlie 287cba97805SPeter Wu nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus, 288692a17dcSPeter Wu &has_optimus_flags, &has_power_resources); 2896a9ee8afSDave Airlie } 2906a9ee8afSDave Airlie 2914c60fac1SEmil Velikov while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) { 2924c60fac1SEmil Velikov vga_count++; 2934c60fac1SEmil Velikov 294cba97805SPeter Wu nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus, 295692a17dcSPeter Wu &has_optimus_flags, &has_power_resources); 2964c60fac1SEmil Velikov } 2974c60fac1SEmil Velikov 298c839d748SDave Airlie /* find the optimus DSM or the old v1 DSM */ 299df42194aSPeter Wu if (has_optimus) { 300df42194aSPeter Wu nouveau_dsm_priv.dhandle = dhandle; 301c839d748SDave Airlie acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, 302c839d748SDave Airlie &buffer); 3038dfe162aSJoe Perches pr_info("VGA switcheroo: detected Optimus DSM method %s handle\n", 304c839d748SDave Airlie acpi_method_name); 305692a17dcSPeter Wu if (has_power_resources) 306692a17dcSPeter Wu pr_info("nouveau: detected PR support, will not use DSM\n"); 307c839d748SDave Airlie nouveau_dsm_priv.optimus_detected = true; 308cba97805SPeter Wu nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags; 309692a17dcSPeter Wu nouveau_dsm_priv.optimus_skip_dsm = has_power_resources; 310c839d748SDave Airlie ret = true; 311df42194aSPeter Wu } else if (vga_count == 2 && has_mux && guid_valid) { 312df42194aSPeter Wu nouveau_dsm_priv.dhandle = dhandle; 313d099230cSPeter Lekensteyn acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, 314d099230cSPeter Lekensteyn &buffer); 3158dfe162aSJoe Perches pr_info("VGA switcheroo: detected DSM switching method %s handle\n", 3166a9ee8afSDave Airlie acpi_method_name); 3176a9ee8afSDave Airlie nouveau_dsm_priv.dsm_detected = true; 318f19467c5SDave Airlie ret = true; 3196a9ee8afSDave Airlie } 320f19467c5SDave Airlie 321f19467c5SDave Airlie 322f19467c5SDave Airlie return ret; 3236a9ee8afSDave Airlie } 3246a9ee8afSDave Airlie 3256a9ee8afSDave Airlie void nouveau_register_dsm_handler(void) 3266a9ee8afSDave Airlie { 3276a9ee8afSDave Airlie bool r; 3286a9ee8afSDave Airlie 3296a9ee8afSDave Airlie r = nouveau_dsm_detect(); 3306a9ee8afSDave Airlie if (!r) 3316a9ee8afSDave Airlie return; 3326a9ee8afSDave Airlie 333156d7d41SLukas Wunner vga_switcheroo_register_handler(&nouveau_dsm_handler, 0); 3346a9ee8afSDave Airlie } 3356a9ee8afSDave Airlie 336d099230cSPeter Lekensteyn /* Must be called for Optimus models before the card can be turned off */ 337d099230cSPeter Lekensteyn void nouveau_switcheroo_optimus_dsm(void) 338d099230cSPeter Lekensteyn { 339d099230cSPeter Lekensteyn u32 result = 0; 340692a17dcSPeter Wu if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm) 341d099230cSPeter Lekensteyn return; 342d099230cSPeter Lekensteyn 343cba97805SPeter Wu if (nouveau_dsm_priv.optimus_flags_detected) 3445addcf0aSDave Airlie nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS, 3455addcf0aSDave Airlie 0x3, &result); 3465addcf0aSDave Airlie 3475addcf0aSDave Airlie nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 3485addcf0aSDave Airlie NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result); 3495addcf0aSDave Airlie 350d099230cSPeter Lekensteyn } 351d099230cSPeter Lekensteyn 3526a9ee8afSDave Airlie void nouveau_unregister_dsm_handler(void) 3536a9ee8afSDave Airlie { 3542f3787aaSAndreas Heider if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected) 3556a9ee8afSDave Airlie vga_switcheroo_unregister_handler(); 3566a9ee8afSDave Airlie } 357d0ce7b85SJeff Mahoney #else 358d0ce7b85SJeff Mahoney void nouveau_register_dsm_handler(void) {} 359d0ce7b85SJeff Mahoney void nouveau_unregister_dsm_handler(void) {} 360d0ce7b85SJeff Mahoney void nouveau_switcheroo_optimus_dsm(void) {} 361d0ce7b85SJeff Mahoney #endif 362afeb3e11SDave Airlie 363c0077061SBen Skeggs void * 364a6ed76d7SBen Skeggs nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) 365a6ed76d7SBen Skeggs { 366a6ed76d7SBen Skeggs struct acpi_device *acpidev; 367a6ed76d7SBen Skeggs acpi_handle handle; 368a6ed76d7SBen Skeggs int type, ret; 369a6ed76d7SBen Skeggs void *edid; 370a6ed76d7SBen Skeggs 371a6ed76d7SBen Skeggs switch (connector->connector_type) { 372a6ed76d7SBen Skeggs case DRM_MODE_CONNECTOR_LVDS: 373a6ed76d7SBen Skeggs case DRM_MODE_CONNECTOR_eDP: 374a6ed76d7SBen Skeggs type = ACPI_VIDEO_DISPLAY_LCD; 375a6ed76d7SBen Skeggs break; 376a6ed76d7SBen Skeggs default: 377c0077061SBen Skeggs return NULL; 378a6ed76d7SBen Skeggs } 379a6ed76d7SBen Skeggs 3803a83f992SRafael J. Wysocki handle = ACPI_HANDLE(&dev->pdev->dev); 381a6ed76d7SBen Skeggs if (!handle) 382c0077061SBen Skeggs return NULL; 383a6ed76d7SBen Skeggs 384a6ed76d7SBen Skeggs ret = acpi_bus_get_device(handle, &acpidev); 385a6ed76d7SBen Skeggs if (ret) 386c0077061SBen Skeggs return NULL; 387a6ed76d7SBen Skeggs 388a6ed76d7SBen Skeggs ret = acpi_video_get_edid(acpidev, type, -1, &edid); 389a6ed76d7SBen Skeggs if (ret < 0) 390c0077061SBen Skeggs return NULL; 391a6ed76d7SBen Skeggs 392c0077061SBen Skeggs return kmemdup(edid, EDID_LENGTH, GFP_KERNEL); 393a6ed76d7SBen Skeggs } 394