aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_acpi.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-03-22 00:10:27 -0400
committerDave Airlie <airlied@redhat.com>2011-05-03 23:39:24 -0400
commitf19467c509e36e5ba3498efd7d4072d3581a1d6c (patch)
treec6a20a27a5b0438a7f5b1863ca0c2c80050c1ad8 /drivers/gpu/drm/nouveau/nouveau_acpi.c
parent3448a19da479b6bd1e28e2a2be9fa16c6a6feb39 (diff)
nouveau: add optimus detection to DSM code.
optimus has another DSM GUID, so we check for its existance, also allow the BIOS stuff is we find it. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_acpi.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c104
1 files changed, 89 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 1aa33d96d5d6..e0a885b72e0e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -37,15 +37,71 @@
37 37
38static struct nouveau_dsm_priv { 38static struct nouveau_dsm_priv {
39 bool dsm_detected; 39 bool dsm_detected;
40 bool optimus_detected;
40 acpi_handle dhandle; 41 acpi_handle dhandle;
41 acpi_handle rom_handle; 42 acpi_handle rom_handle;
42} nouveau_dsm_priv; 43} nouveau_dsm_priv;
43 44
45#define NOUVEAU_DSM_HAS_MUX 0x1
46#define NOUVEAU_DSM_HAS_OPT 0x2
47
44static const char nouveau_dsm_muid[] = { 48static const char nouveau_dsm_muid[] = {
45 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, 49 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
46 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, 50 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
47}; 51};
48 52
53static const char nouveau_op_dsm_muid[] = {
54 0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
55 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
56};
57
58static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
59{
60 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
61 struct acpi_object_list input;
62 union acpi_object params[4];
63 union acpi_object *obj;
64 int err;
65
66 input.count = 4;
67 input.pointer = params;
68 params[0].type = ACPI_TYPE_BUFFER;
69 params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
70 params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
71 params[1].type = ACPI_TYPE_INTEGER;
72 params[1].integer.value = 0x00000100;
73 params[2].type = ACPI_TYPE_INTEGER;
74 params[2].integer.value = func;
75 params[3].type = ACPI_TYPE_BUFFER;
76 params[3].buffer.length = 0;
77
78 err = acpi_evaluate_object(handle, "_DSM", &input, &output);
79 if (err) {
80 printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
81 return err;
82 }
83
84 obj = (union acpi_object *)output.pointer;
85
86 if (obj->type == ACPI_TYPE_INTEGER)
87 if (obj->integer.value == 0x80000002) {
88 return -ENODEV;
89 }
90
91 if (obj->type == ACPI_TYPE_BUFFER) {
92 if (obj->buffer.length == 4 && result) {
93 *result = 0;
94 *result |= obj->buffer.pointer[0];
95 *result |= (obj->buffer.pointer[1] << 8);
96 *result |= (obj->buffer.pointer[2] << 16);
97 *result |= (obj->buffer.pointer[3] << 24);
98 }
99 }
100
101 kfree(output.pointer);
102 return 0;
103}
104
49static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) 105static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
50{ 106{
51 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 107 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -151,11 +207,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
151 .get_client_id = nouveau_dsm_get_client_id, 207 .get_client_id = nouveau_dsm_get_client_id,
152}; 208};
153 209
154static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) 210static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
155{ 211{
156 acpi_handle dhandle, nvidia_handle; 212 acpi_handle dhandle, nvidia_handle;
157 acpi_status status; 213 acpi_status status;
158 int ret; 214 int ret, retval = 0;
159 uint32_t result; 215 uint32_t result;
160 216
161 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 217 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -169,11 +225,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
169 225
170 ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, 226 ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
171 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); 227 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
172 if (ret < 0) 228 if (ret == 0)
173 return false; 229 retval |= NOUVEAU_DSM_HAS_MUX;
174 230
175 nouveau_dsm_priv.dhandle = dhandle; 231 ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
176 return true; 232 if (ret == 0)
233 retval |= NOUVEAU_DSM_HAS_OPT;
234
235 if (retval)
236 nouveau_dsm_priv.dhandle = dhandle;
237
238 return retval;
177} 239}
178 240
179static bool nouveau_dsm_detect(void) 241static bool nouveau_dsm_detect(void)
@@ -182,30 +244,42 @@ static bool nouveau_dsm_detect(void)
182 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 244 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
183 struct pci_dev *pdev = NULL; 245 struct pci_dev *pdev = NULL;
184 int has_dsm = 0; 246 int has_dsm = 0;
247 int has_optimus;
185 int vga_count = 0; 248 int vga_count = 0;
186 bool guid_valid; 249 bool guid_valid;
250 int retval;
251 bool ret = false;
187 252
188 /* lookup the GUID */ 253 /* lookup the MXM GUID */
189 guid_valid = mxm_wmi_supported(); 254 guid_valid = mxm_wmi_supported();
190 if (!guid_valid)
191 return false;
192 255
193 printk("MXM GUID detected in BIOS\n"); 256 if (guid_valid)
257 printk("MXM: GUID detected in BIOS\n");
194 258
259 /* now do DSM detection */
195 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 260 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
196 vga_count++; 261 vga_count++;
197 262
198 has_dsm |= (nouveau_dsm_pci_probe(pdev) == true); 263 retval = nouveau_dsm_pci_probe(pdev);
264 printk("ret val is %d\n", retval);
265 if (retval & NOUVEAU_DSM_HAS_MUX)
266 has_dsm |= 1;
267 if (retval & NOUVEAU_DSM_HAS_OPT)
268 has_optimus = 1;
199 } 269 }
200 270
201 if (vga_count == 2 && has_dsm) { 271 if (vga_count == 2 && has_dsm && guid_valid) {
202 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 272 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
203 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", 273 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
204 acpi_method_name); 274 acpi_method_name);
205 nouveau_dsm_priv.dsm_detected = true; 275 nouveau_dsm_priv.dsm_detected = true;
206 return true; 276 ret = true;
207 } 277 }
208 return false; 278
279 if (has_optimus == 1)
280 nouveau_dsm_priv.optimus_detected = true;
281
282 return ret;
209} 283}
210 284
211void nouveau_register_dsm_handler(void) 285void nouveau_register_dsm_handler(void)
@@ -258,7 +332,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
258 acpi_status status; 332 acpi_status status;
259 acpi_handle dhandle, rom_handle; 333 acpi_handle dhandle, rom_handle;
260 334
261 if (!nouveau_dsm_priv.dsm_detected) 335 if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
262 return false; 336 return false;
263 337
264 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 338 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);