diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_acpi.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 138 |
1 files changed, 38 insertions, 100 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index ba0183fb84f3..3c149617cfcb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c | |||
@@ -1,15 +1,10 @@ | |||
1 | #include <linux/pci.h> | 1 | #include <linux/pci.h> |
2 | #include <linux/acpi.h> | 2 | #include <linux/acpi.h> |
3 | #include <linux/slab.h> | 3 | #include <linux/slab.h> |
4 | #include <acpi/acpi_drivers.h> | ||
5 | #include <acpi/acpi_bus.h> | ||
6 | #include <acpi/video.h> | ||
7 | #include <acpi/acpi.h> | ||
8 | #include <linux/mxm-wmi.h> | 4 | #include <linux/mxm-wmi.h> |
9 | |||
10 | #include <linux/vga_switcheroo.h> | 5 | #include <linux/vga_switcheroo.h> |
11 | |||
12 | #include <drm/drm_edid.h> | 6 | #include <drm/drm_edid.h> |
7 | #include <acpi/video.h> | ||
13 | 8 | ||
14 | #include "nouveau_drm.h" | 9 | #include "nouveau_drm.h" |
15 | #include "nouveau_acpi.h" | 10 | #include "nouveau_acpi.h" |
@@ -78,124 +73,66 @@ static const char nouveau_op_dsm_muid[] = { | |||
78 | 73 | ||
79 | static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 74 | static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result) |
80 | { | 75 | { |
81 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 76 | int i; |
82 | struct acpi_object_list input; | ||
83 | union acpi_object params[4]; | ||
84 | union acpi_object *obj; | 77 | union acpi_object *obj; |
85 | int i, err; | ||
86 | char args_buff[4]; | 78 | char args_buff[4]; |
79 | union acpi_object argv4 = { | ||
80 | .buffer.type = ACPI_TYPE_BUFFER, | ||
81 | .buffer.length = 4, | ||
82 | .buffer.pointer = args_buff | ||
83 | }; | ||
87 | 84 | ||
88 | input.count = 4; | ||
89 | input.pointer = params; | ||
90 | params[0].type = ACPI_TYPE_BUFFER; | ||
91 | params[0].buffer.length = sizeof(nouveau_op_dsm_muid); | ||
92 | params[0].buffer.pointer = (char *)nouveau_op_dsm_muid; | ||
93 | params[1].type = ACPI_TYPE_INTEGER; | ||
94 | params[1].integer.value = 0x00000100; | ||
95 | params[2].type = ACPI_TYPE_INTEGER; | ||
96 | params[2].integer.value = func; | ||
97 | params[3].type = ACPI_TYPE_BUFFER; | ||
98 | params[3].buffer.length = 4; | ||
99 | /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ | 85 | /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ |
100 | for (i = 0; i < 4; i++) | 86 | for (i = 0; i < 4; i++) |
101 | args_buff[i] = (arg >> i * 8) & 0xFF; | 87 | args_buff[i] = (arg >> i * 8) & 0xFF; |
102 | params[3].buffer.pointer = args_buff; | ||
103 | |||
104 | err = acpi_evaluate_object(handle, "_DSM", &input, &output); | ||
105 | if (err) { | ||
106 | printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | obj = (union acpi_object *)output.pointer; | ||
111 | 88 | ||
112 | if (obj->type == ACPI_TYPE_INTEGER) | 89 | *result = 0; |
113 | if (obj->integer.value == 0x80000002) { | 90 | obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100, |
114 | return -ENODEV; | 91 | func, &argv4, ACPI_TYPE_BUFFER); |
115 | } | 92 | if (!obj) { |
116 | 93 | acpi_handle_info(handle, "failed to evaluate _DSM\n"); | |
117 | if (obj->type == ACPI_TYPE_BUFFER) { | 94 | return AE_ERROR; |
118 | if (obj->buffer.length == 4 && result) { | 95 | } else { |
119 | *result = 0; | 96 | if (obj->buffer.length == 4) { |
120 | *result |= obj->buffer.pointer[0]; | 97 | *result |= obj->buffer.pointer[0]; |
121 | *result |= (obj->buffer.pointer[1] << 8); | 98 | *result |= (obj->buffer.pointer[1] << 8); |
122 | *result |= (obj->buffer.pointer[2] << 16); | 99 | *result |= (obj->buffer.pointer[2] << 16); |
123 | *result |= (obj->buffer.pointer[3] << 24); | 100 | *result |= (obj->buffer.pointer[3] << 24); |
124 | } | 101 | } |
102 | ACPI_FREE(obj); | ||
125 | } | 103 | } |
126 | 104 | ||
127 | kfree(output.pointer); | ||
128 | return 0; | 105 | return 0; |
129 | } | 106 | } |
130 | 107 | ||
131 | static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) | 108 | static int nouveau_dsm(acpi_handle handle, int func, int arg) |
132 | { | 109 | { |
133 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 110 | int ret = 0; |
134 | struct acpi_object_list input; | ||
135 | union acpi_object params[4]; | ||
136 | union acpi_object *obj; | 111 | union acpi_object *obj; |
137 | int err; | 112 | union acpi_object argv4 = { |
138 | 113 | .integer.type = ACPI_TYPE_INTEGER, | |
139 | input.count = 4; | 114 | .integer.value = arg, |
140 | input.pointer = params; | 115 | }; |
141 | params[0].type = ACPI_TYPE_BUFFER; | 116 | |
142 | params[0].buffer.length = sizeof(nouveau_dsm_muid); | 117 | obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102, |
143 | params[0].buffer.pointer = (char *)nouveau_dsm_muid; | 118 | func, &argv4, ACPI_TYPE_INTEGER); |
144 | params[1].type = ACPI_TYPE_INTEGER; | 119 | if (!obj) { |
145 | params[1].integer.value = 0x00000102; | 120 | acpi_handle_info(handle, "failed to evaluate _DSM\n"); |
146 | params[2].type = ACPI_TYPE_INTEGER; | 121 | return AE_ERROR; |
147 | params[2].integer.value = func; | 122 | } else { |
148 | params[3].type = ACPI_TYPE_INTEGER; | ||
149 | params[3].integer.value = arg; | ||
150 | |||
151 | err = acpi_evaluate_object(handle, "_DSM", &input, &output); | ||
152 | if (err) { | ||
153 | printk(KERN_INFO "failed to evaluate _DSM: %d\n", err); | ||
154 | return err; | ||
155 | } | ||
156 | |||
157 | obj = (union acpi_object *)output.pointer; | ||
158 | |||
159 | if (obj->type == ACPI_TYPE_INTEGER) | ||
160 | if (obj->integer.value == 0x80000002) | 123 | if (obj->integer.value == 0x80000002) |
161 | return -ENODEV; | 124 | ret = -ENODEV; |
162 | 125 | ACPI_FREE(obj); | |
163 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
164 | if (obj->buffer.length == 4 && result) { | ||
165 | *result = 0; | ||
166 | *result |= obj->buffer.pointer[0]; | ||
167 | *result |= (obj->buffer.pointer[1] << 8); | ||
168 | *result |= (obj->buffer.pointer[2] << 16); | ||
169 | *result |= (obj->buffer.pointer[3] << 24); | ||
170 | } | ||
171 | } | 126 | } |
172 | 127 | ||
173 | kfree(output.pointer); | 128 | return ret; |
174 | return 0; | ||
175 | } | ||
176 | |||
177 | /* Returns 1 if a DSM function is usable and 0 otherwise */ | ||
178 | static int nouveau_test_dsm(acpi_handle test_handle, | ||
179 | int (*dsm_func)(acpi_handle, int, int, uint32_t *), | ||
180 | int sfnc) | ||
181 | { | ||
182 | u32 result = 0; | ||
183 | |||
184 | /* Function 0 returns a Buffer containing available functions. The args | ||
185 | * parameter is ignored for function 0, so just put 0 in it */ | ||
186 | if (dsm_func(test_handle, 0, 0, &result)) | ||
187 | return 0; | ||
188 | |||
189 | /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If | ||
190 | * the n-th bit is enabled, function n is supported */ | ||
191 | return result & 1 && result & (1 << sfnc); | ||
192 | } | 129 | } |
193 | 130 | ||
194 | static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) | 131 | static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) |
195 | { | 132 | { |
196 | mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); | 133 | mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); |
197 | mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); | 134 | mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); |
198 | return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); | 135 | return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id); |
199 | } | 136 | } |
200 | 137 | ||
201 | static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) | 138 | static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state) |
@@ -205,7 +142,7 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero | |||
205 | arg = NOUVEAU_DSM_POWER_SPEED; | 142 | arg = NOUVEAU_DSM_POWER_SPEED; |
206 | else | 143 | else |
207 | arg = NOUVEAU_DSM_POWER_STAMINA; | 144 | arg = NOUVEAU_DSM_POWER_STAMINA; |
208 | nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL); | 145 | nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg); |
209 | return 0; | 146 | return 0; |
210 | } | 147 | } |
211 | 148 | ||
@@ -265,11 +202,12 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) | |||
265 | nouveau_dsm_priv.other_handle = dhandle; | 202 | nouveau_dsm_priv.other_handle = dhandle; |
266 | return false; | 203 | return false; |
267 | } | 204 | } |
268 | if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) | 205 | if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, |
206 | 1 << NOUVEAU_DSM_POWER)) | ||
269 | retval |= NOUVEAU_DSM_HAS_MUX; | 207 | retval |= NOUVEAU_DSM_HAS_MUX; |
270 | 208 | ||
271 | if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, | 209 | if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100, |
272 | NOUVEAU_DSM_OPTIMUS_CAPS)) | 210 | 1 << NOUVEAU_DSM_OPTIMUS_CAPS)) |
273 | retval |= NOUVEAU_DSM_HAS_OPT; | 211 | retval |= NOUVEAU_DSM_HAS_OPT; |
274 | 212 | ||
275 | if (retval & NOUVEAU_DSM_HAS_OPT) { | 213 | if (retval & NOUVEAU_DSM_HAS_OPT) { |