diff options
author | Dave Airlie <airlied@redhat.com> | 2011-03-22 00:10:27 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-05-03 23:39:24 -0400 |
commit | f19467c509e36e5ba3498efd7d4072d3581a1d6c (patch) | |
tree | c6a20a27a5b0438a7f5b1863ca0c2c80050c1ad8 /drivers/gpu/drm/nouveau/nouveau_acpi.c | |
parent | 3448a19da479b6bd1e28e2a2be9fa16c6a6feb39 (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.c | 104 |
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 | ||
38 | static struct nouveau_dsm_priv { | 38 | static 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 | |||
44 | static const char nouveau_dsm_muid[] = { | 48 | static 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 | ||
53 | static 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 | |||
58 | static 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 | |||
49 | static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 105 | static 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 | ||
154 | static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) | 210 | static 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 | ||
179 | static bool nouveau_dsm_detect(void) | 241 | static 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 | ||
211 | void nouveau_register_dsm_handler(void) | 285 | void 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); |