drm/nouveau: Don't register backlight when another backlight should be used (v2)
[linux-2.6-block.git] / drivers / gpu / drm / nouveau / nouveau_acpi.c
CommitLineData
b7019ac5 1// SPDX-License-Identifier: MIT
6ee73861
BS
2#include <linux/pci.h>
3#include <linux/acpi.h>
5a0e3ad6 4#include <linux/slab.h>
8116188f 5#include <linux/mxm-wmi.h>
6a9ee8af 6#include <linux/vga_switcheroo.h>
612a9aab 7#include <drm/drm_edid.h>
8b48463f 8#include <acpi/video.h>
c0077061 9
4dc28134 10#include "nouveau_drv.h"
c0077061
BS
11#include "nouveau_acpi.h"
12
6ee73861
BS
13#define NOUVEAU_DSM_LED 0x02
14#define NOUVEAU_DSM_LED_STATE 0x00
15#define NOUVEAU_DSM_LED_OFF 0x10
16#define NOUVEAU_DSM_LED_STAMINA 0x11
17#define NOUVEAU_DSM_LED_SPEED 0x12
18
19#define NOUVEAU_DSM_POWER 0x03
20#define NOUVEAU_DSM_POWER_STATE 0x00
21#define NOUVEAU_DSM_POWER_SPEED 0x01
22#define NOUVEAU_DSM_POWER_STAMINA 0x02
23
5addcf0a
DA
24#define NOUVEAU_DSM_OPTIMUS_CAPS 0x1A
25#define NOUVEAU_DSM_OPTIMUS_FLAGS 0x1B
26
27#define NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 (3 << 24)
28#define NOUVEAU_DSM_OPTIMUS_NO_POWERDOWN_PS3 (2 << 24)
29#define NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED (1)
30
31#define NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN (NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 | NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED)
32
33/* result of the optimus caps function */
34#define OPTIMUS_ENABLED (1 << 0)
35#define OPTIMUS_STATUS_MASK (3 << 3)
36#define OPTIMUS_STATUS_OFF (0 << 3)
37#define OPTIMUS_STATUS_ON_ENABLED (1 << 3)
38#define OPTIMUS_STATUS_PWR_STABLE (3 << 3)
39#define OPTIMUS_DISPLAY_HOTPLUG (1 << 6)
40#define OPTIMUS_CAPS_MASK (7 << 24)
41#define OPTIMUS_DYNAMIC_PWR_CAP (1 << 24)
42
43#define OPTIMUS_AUDIO_CAPS_MASK (3 << 27)
44#define OPTIMUS_HDA_CODEC_MASK (2 << 27) /* hda bios control */
d099230c 45
6a9ee8af
DA
46static struct nouveau_dsm_priv {
47 bool dsm_detected;
f19467c5 48 bool optimus_detected;
cba97805 49 bool optimus_flags_detected;
692a17dc 50 bool optimus_skip_dsm;
6a9ee8af 51 acpi_handle dhandle;
6a9ee8af
DA
52} nouveau_dsm_priv;
53
c839d748
DA
54bool nouveau_is_optimus(void) {
55 return nouveau_dsm_priv.optimus_detected;
56}
57
58bool nouveau_is_v1_dsm(void) {
59 return nouveau_dsm_priv.dsm_detected;
60}
61
d0ce7b85 62#ifdef CONFIG_VGA_SWITCHEROO
94116f81
AS
63static const guid_t nouveau_dsm_muid =
64 GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
65 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
6ee73861 66
94116f81
AS
67static const guid_t nouveau_op_dsm_muid =
68 GUID_INIT(0xA486D8F8, 0x0BDA, 0x471B,
69 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0);
f19467c5
DA
70
71static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
72{
b072e53b 73 int i;
f19467c5 74 union acpi_object *obj;
d099230c 75 char args_buff[4];
b072e53b
JL
76 union acpi_object argv4 = {
77 .buffer.type = ACPI_TYPE_BUFFER,
78 .buffer.length = 4,
79 .buffer.pointer = args_buff
80 };
f19467c5 81
d099230c
PL
82 /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
83 for (i = 0; i < 4; i++)
84 args_buff[i] = (arg >> i * 8) & 0xFF;
f19467c5 85
b072e53b 86 *result = 0;
94116f81 87 obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100,
b072e53b
JL
88 func, &argv4, ACPI_TYPE_BUFFER);
89 if (!obj) {
90 acpi_handle_info(handle, "failed to evaluate _DSM\n");
91 return AE_ERROR;
92 } else {
93 if (obj->buffer.length == 4) {
f19467c5
DA
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 }
b072e53b 99 ACPI_FREE(obj);
f19467c5
DA
100 }
101
f19467c5
DA
102 return 0;
103}
104
e284175a
JL
105/*
106 * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
107 * requirements on the fourth parameter, so a private implementation
108 * instead of using acpi_check_dsm().
109 */
a12e78dd 110static int nouveau_dsm_get_optimus_functions(acpi_handle handle)
e284175a
JL
111{
112 int result;
113
114 /*
115 * Function 0 returns a Buffer containing available functions.
116 * The args parameter is ignored for function 0, so just put 0 in it
117 */
118 if (nouveau_optimus_dsm(handle, 0, 0, &result))
119 return 0;
120
121 /*
122 * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
123 * If the n-th bit is enabled, function n is supported
124 */
a12e78dd
PW
125 if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS))
126 return result;
127 return 0;
e284175a
JL
128}
129
b072e53b 130static int nouveau_dsm(acpi_handle handle, int func, int arg)
6a9ee8af 131{
b072e53b 132 int ret = 0;
6ee73861 133 union acpi_object *obj;
b072e53b
JL
134 union acpi_object argv4 = {
135 .integer.type = ACPI_TYPE_INTEGER,
136 .integer.value = arg,
137 };
138
94116f81 139 obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102,
b072e53b
JL
140 func, &argv4, ACPI_TYPE_INTEGER);
141 if (!obj) {
142 acpi_handle_info(handle, "failed to evaluate _DSM\n");
143 return AE_ERROR;
144 } else {
6ee73861 145 if (obj->integer.value == 0x80000002)
b072e53b
JL
146 ret = -ENODEV;
147 ACPI_FREE(obj);
6ee73861
BS
148 }
149
b072e53b 150 return ret;
9075e85f
PL
151}
152
6a9ee8af 153static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
6ee73861 154{
000703f4 155 mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
8116188f 156 mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
b072e53b 157 return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id);
6a9ee8af
DA
158}
159
160static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
161{
162 int arg;
163 if (state == VGA_SWITCHEROO_ON)
164 arg = NOUVEAU_DSM_POWER_SPEED;
165 else
166 arg = NOUVEAU_DSM_POWER_STAMINA;
b072e53b 167 nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg);
6a9ee8af
DA
168 return 0;
169}
170
171static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
172{
c839d748 173 if (!nouveau_dsm_priv.dsm_detected)
d099230c 174 return 0;
6a9ee8af 175 if (id == VGA_SWITCHEROO_IGD)
fc5ea29d 176 return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
6a9ee8af 177 else
fc5ea29d 178 return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED);
6a9ee8af 179}
6ee73861 180
6a9ee8af
DA
181static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
182 enum vga_switcheroo_state state)
183{
184 if (id == VGA_SWITCHEROO_IGD)
185 return 0;
186
d099230c
PL
187 /* Optimus laptops have the card already disabled in
188 * nouveau_switcheroo_set_state */
c839d748 189 if (!nouveau_dsm_priv.dsm_detected)
d099230c
PL
190 return 0;
191
fc5ea29d 192 return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
6a9ee8af
DA
193}
194
f43cda5c 195static enum vga_switcheroo_client_id nouveau_dsm_get_client_id(struct pci_dev *pdev)
6ee73861 196{
d1fbd923
DA
197 /* easy option one - intel vendor ID means Integrated */
198 if (pdev->vendor == PCI_VENDOR_ID_INTEL)
6a9ee8af 199 return VGA_SWITCHEROO_IGD;
d1fbd923
DA
200
201 /* is this device on Bus 0? - this may need improving */
202 if (pdev->bus->number == 0)
203 return VGA_SWITCHEROO_IGD;
204
205 return VGA_SWITCHEROO_DIS;
6a9ee8af
DA
206}
207
5d170139 208static const struct vga_switcheroo_handler nouveau_dsm_handler = {
6a9ee8af
DA
209 .switchto = nouveau_dsm_switchto,
210 .power_state = nouveau_dsm_power_state,
6a9ee8af
DA
211 .get_client_id = nouveau_dsm_get_client_id,
212};
6ee73861 213
df42194a 214static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
cba97805 215 bool *has_mux, bool *has_opt,
692a17dc 216 bool *has_opt_flags, bool *has_pr3)
6a9ee8af 217{
187b5b5d 218 acpi_handle dhandle;
df42194a 219 bool supports_mux;
a12e78dd 220 int optimus_funcs;
ccfc2d5c
KHF
221 struct pci_dev *parent_pdev;
222
223 *has_pr3 = false;
224 parent_pdev = pci_upstream_bridge(pdev);
225 if (parent_pdev) {
226 if (parent_pdev->bridge_d3)
227 *has_pr3 = pci_pr3_present(parent_pdev);
228 else
229 pci_d3cold_disable(pdev);
230 }
6a9ee8af 231
3a83f992 232 dhandle = ACPI_HANDLE(&pdev->dev);
6a9ee8af 233 if (!dhandle)
df42194a 234 return;
afeb3e11 235
f91ce35e 236 if (!acpi_has_method(dhandle, "_DSM"))
df42194a
PW
237 return;
238
94116f81 239 supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102,
df42194a 240 1 << NOUVEAU_DSM_POWER);
a12e78dd 241 optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
f91ce35e 242
df42194a 243 /* Does not look like a Nvidia device. */
a12e78dd 244 if (!supports_mux && !optimus_funcs)
df42194a 245 return;
f19467c5 246
df42194a
PW
247 *dhandle_out = dhandle;
248 *has_mux = supports_mux;
a12e78dd 249 *has_opt = !!optimus_funcs;
cba97805 250 *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
f19467c5 251
a12e78dd 252 if (optimus_funcs) {
5addcf0a
DA
253 uint32_t result;
254 nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0,
255 &result);
256 dev_info(&pdev->dev, "optimus capabilities: %s, status %s%s\n",
257 (result & OPTIMUS_ENABLED) ? "enabled" : "disabled",
258 (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "",
259 (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : "");
260 }
6ee73861 261}
6a9ee8af
DA
262
263static bool nouveau_dsm_detect(void)
264{
265 char acpi_method_name[255] = { 0 };
266 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
267 struct pci_dev *pdev = NULL;
df42194a
PW
268 acpi_handle dhandle = NULL;
269 bool has_mux = false;
270 bool has_optimus = false;
cba97805 271 bool has_optimus_flags = false;
692a17dc 272 bool has_power_resources = false;
6a9ee8af 273 int vga_count = 0;
8116188f 274 bool guid_valid;
f19467c5 275 bool ret = false;
8116188f 276
f19467c5 277 /* lookup the MXM GUID */
8116188f 278 guid_valid = mxm_wmi_supported();
8116188f 279
f19467c5
DA
280 if (guid_valid)
281 printk("MXM: GUID detected in BIOS\n");
afeb3e11 282
f19467c5 283 /* now do DSM detection */
6a9ee8af
DA
284 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
285 vga_count++;
286
cba97805 287 nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
692a17dc 288 &has_optimus_flags, &has_power_resources);
6a9ee8af
DA
289 }
290
4c60fac1
EV
291 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
292 vga_count++;
293
cba97805 294 nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
692a17dc 295 &has_optimus_flags, &has_power_resources);
4c60fac1
EV
296 }
297
c839d748 298 /* find the optimus DSM or the old v1 DSM */
df42194a
PW
299 if (has_optimus) {
300 nouveau_dsm_priv.dhandle = dhandle;
d099230c
PL
301 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
302 &buffer);
8dfe162a 303 pr_info("VGA switcheroo: detected Optimus DSM method %s handle\n",
d099230c 304 acpi_method_name);
692a17dc
PW
305 if (has_power_resources)
306 pr_info("nouveau: detected PR support, will not use DSM\n");
c839d748 307 nouveau_dsm_priv.optimus_detected = true;
cba97805 308 nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
692a17dc 309 nouveau_dsm_priv.optimus_skip_dsm = has_power_resources;
f19467c5 310 ret = true;
df42194a
PW
311 } else if (vga_count == 2 && has_mux && guid_valid) {
312 nouveau_dsm_priv.dhandle = dhandle;
d099230c
PL
313 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
314 &buffer);
8dfe162a 315 pr_info("VGA switcheroo: detected DSM switching method %s handle\n",
d099230c 316 acpi_method_name);
c839d748 317 nouveau_dsm_priv.dsm_detected = true;
d099230c
PL
318 ret = true;
319 }
f19467c5 320
c839d748 321
f19467c5 322 return ret;
6a9ee8af
DA
323}
324
325void nouveau_register_dsm_handler(void)
326{
327 bool r;
328
329 r = nouveau_dsm_detect();
330 if (!r)
331 return;
332
156d7d41 333 vga_switcheroo_register_handler(&nouveau_dsm_handler, 0);
6a9ee8af
DA
334}
335
d099230c
PL
336/* Must be called for Optimus models before the card can be turned off */
337void nouveau_switcheroo_optimus_dsm(void)
338{
339 u32 result = 0;
692a17dc 340 if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm)
d099230c
PL
341 return;
342
cba97805
PW
343 if (nouveau_dsm_priv.optimus_flags_detected)
344 nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
345 0x3, &result);
5addcf0a
DA
346
347 nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS,
348 NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result);
349
d099230c
PL
350}
351
6a9ee8af
DA
352void nouveau_unregister_dsm_handler(void)
353{
2f3787aa
AH
354 if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected)
355 vga_switcheroo_unregister_handler();
6a9ee8af 356}
d0ce7b85
JM
357#else
358void nouveau_register_dsm_handler(void) {}
359void nouveau_unregister_dsm_handler(void) {}
360void nouveau_switcheroo_optimus_dsm(void) {}
361#endif
afeb3e11 362
c0077061 363void *
a6ed76d7
BS
364nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
365{
a6ed76d7 366 struct acpi_device *acpidev;
a6ed76d7
BS
367 int type, ret;
368 void *edid;
369
370 switch (connector->connector_type) {
371 case DRM_MODE_CONNECTOR_LVDS:
372 case DRM_MODE_CONNECTOR_eDP:
373 type = ACPI_VIDEO_DISPLAY_LCD;
374 break;
375 default:
c0077061 376 return NULL;
a6ed76d7
BS
377 }
378
ae364fd9
RW
379 acpidev = ACPI_COMPANION(dev->dev);
380 if (!acpidev)
c0077061 381 return NULL;
a6ed76d7
BS
382
383 ret = acpi_video_get_edid(acpidev, type, -1, &edid);
384 if (ret < 0)
c0077061 385 return NULL;
a6ed76d7 386
c0077061 387 return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
a6ed76d7 388}
7f908d33
HG
389
390bool nouveau_acpi_video_backlight_use_native(void)
391{
392 return acpi_video_backlight_use_native();
393}