1 #include <linux/pci.h> 2 #include <linux/acpi.h> 3 #include <acpi/acpi_drivers.h> 4 #include <acpi/acpi_bus.h> 5 6 #include "drmP.h" 7 #include "drm.h" 8 #include "drm_sarea.h" 9 #include "drm_crtc_helper.h" 10 #include "nouveau_drv.h" 11 #include "nouveau_drm.h" 12 #include "nv50_display.h" 13 14 #define NOUVEAU_DSM_SUPPORTED 0x00 15 #define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00 16 17 #define NOUVEAU_DSM_ACTIVE 0x01 18 #define NOUVEAU_DSM_ACTIVE_QUERY 0x00 19 20 #define NOUVEAU_DSM_LED 0x02 21 #define NOUVEAU_DSM_LED_STATE 0x00 22 #define NOUVEAU_DSM_LED_OFF 0x10 23 #define NOUVEAU_DSM_LED_STAMINA 0x11 24 #define NOUVEAU_DSM_LED_SPEED 0x12 25 26 #define NOUVEAU_DSM_POWER 0x03 27 #define NOUVEAU_DSM_POWER_STATE 0x00 28 #define NOUVEAU_DSM_POWER_SPEED 0x01 29 #define NOUVEAU_DSM_POWER_STAMINA 0x02 30 31 static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result) 32 { 33 static char muid[] = { 34 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, 35 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, 36 }; 37 38 struct pci_dev *pdev = dev->pdev; 39 struct acpi_handle *handle; 40 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 41 struct acpi_object_list input; 42 union acpi_object params[4]; 43 union acpi_object *obj; 44 int err; 45 46 handle = DEVICE_ACPI_HANDLE(&pdev->dev); 47 48 if (!handle) 49 return -ENODEV; 50 51 input.count = 4; 52 input.pointer = params; 53 params[0].type = ACPI_TYPE_BUFFER; 54 params[0].buffer.length = sizeof(muid); 55 params[0].buffer.pointer = (char *)muid; 56 params[1].type = ACPI_TYPE_INTEGER; 57 params[1].integer.value = 0x00000102; 58 params[2].type = ACPI_TYPE_INTEGER; 59 params[2].integer.value = func; 60 params[3].type = ACPI_TYPE_INTEGER; 61 params[3].integer.value = arg; 62 63 err = acpi_evaluate_object(handle, "_DSM", &input, &output); 64 if (err) { 65 NV_INFO(dev, "failed to evaluate _DSM: %d\n", err); 66 return err; 67 } 68 69 obj = (union acpi_object *)output.pointer; 70 71 if (obj->type == ACPI_TYPE_INTEGER) 72 if (obj->integer.value == 0x80000002) 73 return -ENODEV; 74 75 if (obj->type == ACPI_TYPE_BUFFER) { 76 if (obj->buffer.length == 4 && result) { 77 *result = 0; 78 *result |= obj->buffer.pointer[0]; 79 *result |= (obj->buffer.pointer[1] << 8); 80 *result |= (obj->buffer.pointer[2] << 16); 81 *result |= (obj->buffer.pointer[3] << 24); 82 } 83 } 84 85 kfree(output.pointer); 86 return 0; 87 } 88 89 int nouveau_hybrid_setup(struct drm_device *dev) 90 { 91 int result; 92 93 if (nouveau_dsm(dev, NOUVEAU_DSM_ACTIVE, NOUVEAU_DSM_ACTIVE_QUERY, 94 &result)) 95 return -ENODEV; 96 97 NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result); 98 99 if (result & 0x1) { /* Stamina mode - disable the external GPU */ 100 nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA, 101 NULL); 102 nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA, 103 NULL); 104 } else { /* Ensure that the external GPU is enabled */ 105 nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL); 106 nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED, 107 NULL); 108 } 109 110 return 0; 111 } 112 113 bool nouveau_dsm_probe(struct drm_device *dev) 114 { 115 int support = 0; 116 117 if (nouveau_dsm(dev, NOUVEAU_DSM_SUPPORTED, 118 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support)) 119 return false; 120 121 if (!support) 122 return false; 123 124 return true; 125 } 126