Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 #include <linux/pci.h>
0003 #include <linux/acpi.h>
0004 #include <linux/slab.h>
0005 #include <linux/mxm-wmi.h>
0006 #include <linux/vga_switcheroo.h>
0007 #include <drm/drm_edid.h>
0008 #include <acpi/video.h>
0009 
0010 #include "nouveau_drv.h"
0011 #include "nouveau_acpi.h"
0012 
0013 #define NOUVEAU_DSM_LED 0x02
0014 #define NOUVEAU_DSM_LED_STATE 0x00
0015 #define NOUVEAU_DSM_LED_OFF 0x10
0016 #define NOUVEAU_DSM_LED_STAMINA 0x11
0017 #define NOUVEAU_DSM_LED_SPEED 0x12
0018 
0019 #define NOUVEAU_DSM_POWER 0x03
0020 #define NOUVEAU_DSM_POWER_STATE 0x00
0021 #define NOUVEAU_DSM_POWER_SPEED 0x01
0022 #define NOUVEAU_DSM_POWER_STAMINA 0x02
0023 
0024 #define NOUVEAU_DSM_OPTIMUS_CAPS 0x1A
0025 #define NOUVEAU_DSM_OPTIMUS_FLAGS 0x1B
0026 
0027 #define NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 (3 << 24)
0028 #define NOUVEAU_DSM_OPTIMUS_NO_POWERDOWN_PS3 (2 << 24)
0029 #define NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED (1)
0030 
0031 #define NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN (NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 | NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED)
0032 
0033 /* result of the optimus caps function */
0034 #define OPTIMUS_ENABLED (1 << 0)
0035 #define OPTIMUS_STATUS_MASK (3 << 3)
0036 #define OPTIMUS_STATUS_OFF  (0 << 3)
0037 #define OPTIMUS_STATUS_ON_ENABLED  (1 << 3)
0038 #define OPTIMUS_STATUS_PWR_STABLE  (3 << 3)
0039 #define OPTIMUS_DISPLAY_HOTPLUG (1 << 6)
0040 #define OPTIMUS_CAPS_MASK (7 << 24)
0041 #define OPTIMUS_DYNAMIC_PWR_CAP (1 << 24)
0042 
0043 #define OPTIMUS_AUDIO_CAPS_MASK (3 << 27)
0044 #define OPTIMUS_HDA_CODEC_MASK (2 << 27) /* hda bios control */
0045 
0046 static struct nouveau_dsm_priv {
0047     bool dsm_detected;
0048     bool optimus_detected;
0049     bool optimus_flags_detected;
0050     bool optimus_skip_dsm;
0051     acpi_handle dhandle;
0052 } nouveau_dsm_priv;
0053 
0054 bool nouveau_is_optimus(void) {
0055     return nouveau_dsm_priv.optimus_detected;
0056 }
0057 
0058 bool nouveau_is_v1_dsm(void) {
0059     return nouveau_dsm_priv.dsm_detected;
0060 }
0061 
0062 #ifdef CONFIG_VGA_SWITCHEROO
0063 static const guid_t nouveau_dsm_muid =
0064     GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
0065           0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
0066 
0067 static const guid_t nouveau_op_dsm_muid =
0068     GUID_INIT(0xA486D8F8, 0x0BDA, 0x471B,
0069           0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0);
0070 
0071 static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
0072 {
0073     int i;
0074     union acpi_object *obj;
0075     char args_buff[4];
0076     union acpi_object argv4 = {
0077         .buffer.type = ACPI_TYPE_BUFFER,
0078         .buffer.length = 4,
0079         .buffer.pointer = args_buff
0080     };
0081 
0082     /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
0083     for (i = 0; i < 4; i++)
0084         args_buff[i] = (arg >> i * 8) & 0xFF;
0085 
0086     *result = 0;
0087     obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100,
0088                       func, &argv4, ACPI_TYPE_BUFFER);
0089     if (!obj) {
0090         acpi_handle_info(handle, "failed to evaluate _DSM\n");
0091         return AE_ERROR;
0092     } else {
0093         if (obj->buffer.length == 4) {
0094             *result |= obj->buffer.pointer[0];
0095             *result |= (obj->buffer.pointer[1] << 8);
0096             *result |= (obj->buffer.pointer[2] << 16);
0097             *result |= (obj->buffer.pointer[3] << 24);
0098         }
0099         ACPI_FREE(obj);
0100     }
0101 
0102     return 0;
0103 }
0104 
0105 /*
0106  * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
0107  * requirements on the fourth parameter, so a private implementation
0108  * instead of using acpi_check_dsm().
0109  */
0110 static int nouveau_dsm_get_optimus_functions(acpi_handle handle)
0111 {
0112     int result;
0113 
0114     /*
0115      * Function 0 returns a Buffer containing available functions.
0116      * The args parameter is ignored for function 0, so just put 0 in it
0117      */
0118     if (nouveau_optimus_dsm(handle, 0, 0, &result))
0119         return 0;
0120 
0121     /*
0122      * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
0123      * If the n-th bit is enabled, function n is supported
0124      */
0125     if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS))
0126         return result;
0127     return 0;
0128 }
0129 
0130 static int nouveau_dsm(acpi_handle handle, int func, int arg)
0131 {
0132     int ret = 0;
0133     union acpi_object *obj;
0134     union acpi_object argv4 = {
0135         .integer.type = ACPI_TYPE_INTEGER,
0136         .integer.value = arg,
0137     };
0138 
0139     obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102,
0140                       func, &argv4, ACPI_TYPE_INTEGER);
0141     if (!obj) {
0142         acpi_handle_info(handle, "failed to evaluate _DSM\n");
0143         return AE_ERROR;
0144     } else {
0145         if (obj->integer.value == 0x80000002)
0146             ret = -ENODEV;
0147         ACPI_FREE(obj);
0148     }
0149 
0150     return ret;
0151 }
0152 
0153 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
0154 {
0155     mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
0156     mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
0157     return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id);
0158 }
0159 
0160 static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
0161 {
0162     int arg;
0163     if (state == VGA_SWITCHEROO_ON)
0164         arg = NOUVEAU_DSM_POWER_SPEED;
0165     else
0166         arg = NOUVEAU_DSM_POWER_STAMINA;
0167     nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg);
0168     return 0;
0169 }
0170 
0171 static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
0172 {
0173     if (!nouveau_dsm_priv.dsm_detected)
0174         return 0;
0175     if (id == VGA_SWITCHEROO_IGD)
0176         return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
0177     else
0178         return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED);
0179 }
0180 
0181 static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
0182                    enum vga_switcheroo_state state)
0183 {
0184     if (id == VGA_SWITCHEROO_IGD)
0185         return 0;
0186 
0187     /* Optimus laptops have the card already disabled in
0188      * nouveau_switcheroo_set_state */
0189     if (!nouveau_dsm_priv.dsm_detected)
0190         return 0;
0191 
0192     return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
0193 }
0194 
0195 static enum vga_switcheroo_client_id nouveau_dsm_get_client_id(struct pci_dev *pdev)
0196 {
0197     /* easy option one - intel vendor ID means Integrated */
0198     if (pdev->vendor == PCI_VENDOR_ID_INTEL)
0199         return VGA_SWITCHEROO_IGD;
0200 
0201     /* is this device on Bus 0? - this may need improving */
0202     if (pdev->bus->number == 0)
0203         return VGA_SWITCHEROO_IGD;
0204 
0205     return VGA_SWITCHEROO_DIS;
0206 }
0207 
0208 static const struct vga_switcheroo_handler nouveau_dsm_handler = {
0209     .switchto = nouveau_dsm_switchto,
0210     .power_state = nouveau_dsm_power_state,
0211     .get_client_id = nouveau_dsm_get_client_id,
0212 };
0213 
0214 static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
0215                   bool *has_mux, bool *has_opt,
0216                   bool *has_opt_flags, bool *has_pr3)
0217 {
0218     acpi_handle dhandle;
0219     bool supports_mux;
0220     int optimus_funcs;
0221     struct pci_dev *parent_pdev;
0222 
0223     *has_pr3 = false;
0224     parent_pdev = pci_upstream_bridge(pdev);
0225     if (parent_pdev) {
0226         if (parent_pdev->bridge_d3)
0227             *has_pr3 = pci_pr3_present(parent_pdev);
0228         else
0229             pci_d3cold_disable(pdev);
0230     }
0231 
0232     dhandle = ACPI_HANDLE(&pdev->dev);
0233     if (!dhandle)
0234         return;
0235 
0236     if (!acpi_has_method(dhandle, "_DSM"))
0237         return;
0238 
0239     supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102,
0240                       1 << NOUVEAU_DSM_POWER);
0241     optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
0242 
0243     /* Does not look like a Nvidia device. */
0244     if (!supports_mux && !optimus_funcs)
0245         return;
0246 
0247     *dhandle_out = dhandle;
0248     *has_mux = supports_mux;
0249     *has_opt = !!optimus_funcs;
0250     *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
0251 
0252     if (optimus_funcs) {
0253         uint32_t result;
0254         nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0,
0255                     &result);
0256         dev_info(&pdev->dev, "optimus capabilities: %s, status %s%s\n",
0257              (result & OPTIMUS_ENABLED) ? "enabled" : "disabled",
0258              (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "",
0259              (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : "");
0260     }
0261 }
0262 
0263 static bool nouveau_dsm_detect(void)
0264 {
0265     char acpi_method_name[255] = { 0 };
0266     struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
0267     struct pci_dev *pdev = NULL;
0268     acpi_handle dhandle = NULL;
0269     bool has_mux = false;
0270     bool has_optimus = false;
0271     bool has_optimus_flags = false;
0272     bool has_power_resources = false;
0273     int vga_count = 0;
0274     bool guid_valid;
0275     bool ret = false;
0276 
0277     /* lookup the MXM GUID */
0278     guid_valid = mxm_wmi_supported();
0279 
0280     if (guid_valid)
0281         printk("MXM: GUID detected in BIOS\n");
0282 
0283     /* now do DSM detection */
0284     while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
0285         vga_count++;
0286 
0287         nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
0288                       &has_optimus_flags, &has_power_resources);
0289     }
0290 
0291     while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
0292         vga_count++;
0293 
0294         nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
0295                       &has_optimus_flags, &has_power_resources);
0296     }
0297 
0298     /* find the optimus DSM or the old v1 DSM */
0299     if (has_optimus) {
0300         nouveau_dsm_priv.dhandle = dhandle;
0301         acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
0302             &buffer);
0303         pr_info("VGA switcheroo: detected Optimus DSM method %s handle\n",
0304             acpi_method_name);
0305         if (has_power_resources)
0306             pr_info("nouveau: detected PR support, will not use DSM\n");
0307         nouveau_dsm_priv.optimus_detected = true;
0308         nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
0309         nouveau_dsm_priv.optimus_skip_dsm = has_power_resources;
0310         ret = true;
0311     } else if (vga_count == 2 && has_mux && guid_valid) {
0312         nouveau_dsm_priv.dhandle = dhandle;
0313         acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
0314             &buffer);
0315         pr_info("VGA switcheroo: detected DSM switching method %s handle\n",
0316             acpi_method_name);
0317         nouveau_dsm_priv.dsm_detected = true;
0318         ret = true;
0319     }
0320 
0321 
0322     return ret;
0323 }
0324 
0325 void nouveau_register_dsm_handler(void)
0326 {
0327     bool r;
0328 
0329     r = nouveau_dsm_detect();
0330     if (!r)
0331         return;
0332 
0333     vga_switcheroo_register_handler(&nouveau_dsm_handler, 0);
0334 }
0335 
0336 /* Must be called for Optimus models before the card can be turned off */
0337 void nouveau_switcheroo_optimus_dsm(void)
0338 {
0339     u32 result = 0;
0340     if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm)
0341         return;
0342 
0343     if (nouveau_dsm_priv.optimus_flags_detected)
0344         nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
0345                     0x3, &result);
0346 
0347     nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS,
0348         NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result);
0349 
0350 }
0351 
0352 void nouveau_unregister_dsm_handler(void)
0353 {
0354     if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected)
0355         vga_switcheroo_unregister_handler();
0356 }
0357 #else
0358 void nouveau_register_dsm_handler(void) {}
0359 void nouveau_unregister_dsm_handler(void) {}
0360 void nouveau_switcheroo_optimus_dsm(void) {}
0361 #endif
0362 
0363 void *
0364 nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
0365 {
0366     struct acpi_device *acpidev;
0367     int type, ret;
0368     void *edid;
0369 
0370     switch (connector->connector_type) {
0371     case DRM_MODE_CONNECTOR_LVDS:
0372     case DRM_MODE_CONNECTOR_eDP:
0373         type = ACPI_VIDEO_DISPLAY_LCD;
0374         break;
0375     default:
0376         return NULL;
0377     }
0378 
0379     acpidev = ACPI_COMPANION(dev->dev);
0380     if (!acpidev)
0381         return NULL;
0382 
0383     ret = acpi_video_get_edid(acpidev, type, -1, &edid);
0384     if (ret < 0)
0385         return NULL;
0386 
0387     return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
0388 }