drm/radeon: document radeon_atpx_handler.c (v2)
[linux-2.6-block.git] / drivers / gpu / drm / radeon / radeon_acpi.c
CommitLineData
efd4e418
AD
1/*
2 * Copyright 2012 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
d7a2952f
AM
24#include <linux/pci.h>
25#include <linux/acpi.h>
26#include <linux/slab.h>
c4917074 27#include <linux/power_supply.h>
d7a2952f
AM
28#include <acpi/acpi_drivers.h>
29#include <acpi/acpi_bus.h>
fda4b25c 30#include <acpi/video.h>
d7a2952f
AM
31
32#include "drmP.h"
33#include "drm.h"
34#include "drm_sarea.h"
35#include "drm_crtc_helper.h"
36#include "radeon.h"
9e05b2f4 37#include "radeon_acpi.h"
fda4b25c 38#include "atom.h"
d7a2952f
AM
39
40#include <linux/vga_switcheroo.h>
41
c4917074
AD
42#define ACPI_AC_CLASS "ac_adapter"
43
44extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev);
45
fd64ca8a
LT
46struct atif_verify_interface {
47 u16 size; /* structure size in bytes (includes size field) */
48 u16 version; /* version */
49 u32 notification_mask; /* supported notifications mask */
50 u32 function_bits; /* supported functions bit vector */
51} __packed;
52
ce3cf821 53struct atif_system_params {
fda4b25c
LT
54 u16 size; /* structure size in bytes (includes size field) */
55 u32 valid_mask; /* valid flags mask */
56 u32 flags; /* flags */
57 u8 command_code; /* notify command code */
58} __packed;
59
60struct atif_sbios_requests {
61 u16 size; /* structure size in bytes (includes size field) */
62 u32 pending; /* pending sbios requests */
63 u8 panel_exp_mode; /* panel expansion mode */
64 u8 thermal_gfx; /* thermal state: target gfx controller */
65 u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */
66 u8 forced_power_gfx; /* forced power state: target gfx controller */
67 u8 forced_power_state; /* forced power state: state id */
68 u8 system_power_src; /* system power source */
69 u8 backlight_level; /* panel backlight level (0-255) */
ce3cf821
LT
70} __packed;
71
72#define ATIF_NOTIFY_MASK 0x3
73#define ATIF_NOTIFY_NONE 0
74#define ATIF_NOTIFY_81 1
75#define ATIF_NOTIFY_N 2
76
d7a2952f 77/* Call the ATIF method
d7a2952f 78 */
c3c65160
AD
79/**
80 * radeon_atif_call - call an ATIF method
81 *
82 * @handle: acpi handle
83 * @function: the ATIF function to execute
84 * @params: ATIF function params
85 *
86 * Executes the requested ATIF function (all asics).
87 * Returns a pointer to the acpi output buffer.
88 */
86504672
LT
89static union acpi_object *radeon_atif_call(acpi_handle handle, int function,
90 struct acpi_buffer *params)
d7a2952f
AM
91{
92 acpi_status status;
93 union acpi_object atif_arg_elements[2];
94 struct acpi_object_list atif_arg;
86504672 95 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
d7a2952f
AM
96
97 atif_arg.count = 2;
98 atif_arg.pointer = &atif_arg_elements[0];
99
100 atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
86504672
LT
101 atif_arg_elements[0].integer.value = function;
102
103 if (params) {
104 atif_arg_elements[1].type = ACPI_TYPE_BUFFER;
105 atif_arg_elements[1].buffer.length = params->length;
106 atif_arg_elements[1].buffer.pointer = params->pointer;
107 } else {
108 /* We need a second fake parameter */
109 atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
110 atif_arg_elements[1].integer.value = 0;
111 }
d7a2952f
AM
112
113 status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
114
115 /* Fail only if calling the method fails and ATIF is supported */
116 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
bc96f942
JD
117 DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
118 acpi_format_exception(status));
d7a2952f 119 kfree(buffer.pointer);
86504672 120 return NULL;
d7a2952f
AM
121 }
122
86504672 123 return buffer.pointer;
d7a2952f
AM
124}
125
c3c65160
AD
126/**
127 * radeon_atif_parse_notification - parse supported notifications
128 *
129 * @n: supported notifications struct
130 * @mask: supported notifications mask from ATIF
131 *
132 * Use the supported notifications mask from ATIF function
133 * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications
134 * are supported (all asics).
135 */
fd64ca8a
LT
136static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask)
137{
138 n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED;
139 n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED;
140 n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
141 n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
142 n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
143 n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED;
144 n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED;
145 n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
146 n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
147}
148
c3c65160
AD
149/**
150 * radeon_atif_parse_functions - parse supported functions
151 *
152 * @f: supported functions struct
153 * @mask: supported functions mask from ATIF
154 *
155 * Use the supported functions mask from ATIF function
156 * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions
157 * are supported (all asics).
158 */
fd64ca8a
LT
159static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask)
160{
161 f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
162 f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
163 f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
164 f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED;
165 f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
166 f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
167 f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
168 f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
169 f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
170 f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED;
171}
172
c3c65160
AD
173/**
174 * radeon_atif_verify_interface - verify ATIF
175 *
176 * @handle: acpi handle
177 * @atif: radeon atif struct
178 *
179 * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function
180 * to initialize ATIF and determine what features are supported
181 * (all asics).
182 * returns 0 on success, error on failure.
183 */
fd64ca8a
LT
184static int radeon_atif_verify_interface(acpi_handle handle,
185 struct radeon_atif *atif)
186{
187 union acpi_object *info;
188 struct atif_verify_interface output;
189 size_t size;
190 int err = 0;
191
192 info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
193 if (!info)
194 return -EIO;
195
196 memset(&output, 0, sizeof(output));
197
198 size = *(u16 *) info->buffer.pointer;
199 if (size < 12) {
200 DRM_INFO("ATIF buffer is too small: %lu\n", size);
201 err = -EINVAL;
202 goto out;
203 }
204 size = min(sizeof(output), size);
205
206 memcpy(&output, info->buffer.pointer, size);
207
208 /* TODO: check version? */
209 DRM_DEBUG_DRIVER("ATIF version %u\n", output.version);
210
211 radeon_atif_parse_notification(&atif->notifications, output.notification_mask);
212 radeon_atif_parse_functions(&atif->functions, output.function_bits);
213
214out:
215 kfree(info);
216 return err;
217}
218
c3c65160
AD
219/**
220 * radeon_atif_get_notification_params - determine notify configuration
221 *
222 * @handle: acpi handle
223 * @n: atif notification configuration struct
224 *
225 * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function
226 * to determine if a notifier is used and if so which one
227 * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n)
228 * where n is specified in the result if a notifier is used.
229 * Returns 0 on success, error on failure.
230 */
ce3cf821
LT
231static int radeon_atif_get_notification_params(acpi_handle handle,
232 struct radeon_atif_notification_cfg *n)
233{
234 union acpi_object *info;
235 struct atif_system_params params;
236 size_t size;
237 int err = 0;
238
239 info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL);
240 if (!info) {
241 err = -EIO;
242 goto out;
243 }
244
245 size = *(u16 *) info->buffer.pointer;
246 if (size < 10) {
247 err = -EINVAL;
248 goto out;
249 }
250
251 memset(&params, 0, sizeof(params));
252 size = min(sizeof(params), size);
253 memcpy(&params, info->buffer.pointer, size);
254
fda4b25c
LT
255 DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n",
256 params.flags, params.valid_mask);
ce3cf821
LT
257 params.flags = params.flags & params.valid_mask;
258
259 if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) {
260 n->enabled = false;
261 n->command_code = 0;
262 } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) {
263 n->enabled = true;
264 n->command_code = 0x81;
265 } else {
266 if (size < 11) {
267 err = -EINVAL;
268 goto out;
269 }
270 n->enabled = true;
271 n->command_code = params.command_code;
272 }
273
274out:
fda4b25c
LT
275 DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n",
276 (n->enabled ? "enabled" : "disabled"),
277 n->command_code);
ce3cf821
LT
278 kfree(info);
279 return err;
280}
281
c3c65160
AD
282/**
283 * radeon_atif_get_sbios_requests - get requested sbios event
284 *
285 * @handle: acpi handle
286 * @req: atif sbios request struct
287 *
288 * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function
289 * to determine what requests the sbios is making to the driver
290 * (all asics).
291 * Returns 0 on success, error on failure.
292 */
fda4b25c
LT
293static int radeon_atif_get_sbios_requests(acpi_handle handle,
294 struct atif_sbios_requests *req)
295{
296 union acpi_object *info;
297 size_t size;
298 int count = 0;
299
300 info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL);
301 if (!info)
302 return -EIO;
303
304 size = *(u16 *)info->buffer.pointer;
305 if (size < 0xd) {
306 count = -EINVAL;
307 goto out;
308 }
309 memset(req, 0, sizeof(*req));
310
311 size = min(sizeof(*req), size);
312 memcpy(req, info->buffer.pointer, size);
313 DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending);
314
315 count = hweight32(req->pending);
316
317out:
318 kfree(info);
319 return count;
320}
321
c3c65160
AD
322/**
323 * radeon_atif_handler - handle ATIF notify requests
324 *
325 * @rdev: radeon_device pointer
326 * @event: atif sbios request struct
327 *
328 * Checks the acpi event and if it matches an atif event,
329 * handles it.
330 * Returns NOTIFY code
331 */
fda4b25c
LT
332int radeon_atif_handler(struct radeon_device *rdev,
333 struct acpi_bus_event *event)
334{
335 struct radeon_atif *atif = &rdev->atif;
336 struct atif_sbios_requests req;
337 acpi_handle handle;
338 int count;
339
340 DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n",
341 event->device_class, event->type);
342
343 if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
344 return NOTIFY_DONE;
345
346 if (!atif->notification_cfg.enabled ||
347 event->type != atif->notification_cfg.command_code)
348 /* Not our event */
349 return NOTIFY_DONE;
350
351 /* Check pending SBIOS requests */
352 handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
353 count = radeon_atif_get_sbios_requests(handle, &req);
354
355 if (count <= 0)
356 return NOTIFY_DONE;
357
358 DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count);
359
360 if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) {
361 struct radeon_encoder *enc = atif->backlight_ctl;
362
363 if (enc) {
364 struct radeon_encoder_atom_dig *dig = enc->enc_priv;
365 dig->backlight_level = req.backlight_level;
366
367 DRM_DEBUG_DRIVER("Changing brightness to %d\n",
368 req.backlight_level);
369
370 atombios_set_panel_brightness(enc);
371
372 backlight_force_update(dig->bl_dev,
373 BACKLIGHT_UPDATE_HOTKEY);
374 }
375 }
376 /* TODO: check other events */
377
92fdf89a
LT
378 /* We've handled the event, stop the notifier chain. The ACPI interface
379 * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to
380 * userspace if the event was generated only to signal a SBIOS
381 * request.
382 */
383 return NOTIFY_BAD;
fda4b25c
LT
384}
385
c3c65160
AD
386/**
387 * radeon_acpi_event - handle notify events
388 *
389 * @nb: notifier block
390 * @val: val
391 * @data: acpi event
392 *
393 * Calls relevant radeon functions in response to various
394 * acpi events.
395 * Returns NOTIFY code
396 */
c4917074
AD
397static int radeon_acpi_event(struct notifier_block *nb,
398 unsigned long val,
399 void *data)
400{
401 struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb);
402 struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
403
404 if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
405 if (power_supply_is_system_supplied() > 0)
406 DRM_DEBUG_DRIVER("pm: AC\n");
407 else
408 DRM_DEBUG_DRIVER("pm: DC\n");
409
410 radeon_pm_acpi_event_handler(rdev);
411 }
412
413 /* Check for pending SBIOS requests */
414 return radeon_atif_handler(rdev, entry);
415}
416
d7a2952f 417/* Call all ACPI methods here */
c3c65160
AD
418/**
419 * radeon_acpi_init - init driver acpi support
420 *
421 * @rdev: radeon_device pointer
422 *
423 * Verifies the AMD ACPI interfaces and registers with the acpi
424 * notifier chain (all asics).
425 * Returns 0 on success, error on failure.
426 */
d7a2952f
AM
427int radeon_acpi_init(struct radeon_device *rdev)
428{
429 acpi_handle handle;
ce3cf821 430 struct radeon_atif *atif = &rdev->atif;
fd64ca8a 431 int ret;
d7a2952f 432
d7a2952f
AM
433 /* Get the device handle */
434 handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
435
48cc9b2c
JD
436 /* No need to proceed if we're sure that ATIF is not supported */
437 if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle)
438 return 0;
439
d7a2952f 440 /* Call the ATIF method */
ce3cf821
LT
441 ret = radeon_atif_verify_interface(handle, atif);
442 if (ret) {
fd64ca8a 443 DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret);
ce3cf821
LT
444 goto out;
445 }
446
fda4b25c
LT
447 if (atif->notifications.brightness_change) {
448 struct drm_encoder *tmp;
449 struct radeon_encoder *target = NULL;
450
451 /* Find the encoder controlling the brightness */
452 list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list,
453 head) {
454 struct radeon_encoder *enc = to_radeon_encoder(tmp);
455 struct radeon_encoder_atom_dig *dig = enc->enc_priv;
456
457 if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
458 dig->bl_dev != NULL) {
459 target = enc;
460 break;
461 }
462 }
463
464 atif->backlight_ctl = target;
465 if (!target) {
466 /* Brightness change notification is enabled, but we
467 * didn't find a backlight controller, this should
468 * never happen.
469 */
470 DRM_ERROR("Cannot find a backlight controller\n");
471 }
472 }
473
ce3cf821
LT
474 if (atif->functions.sbios_requests && !atif->functions.system_params) {
475 /* XXX check this workraround, if sbios request function is
476 * present we have to see how it's configured in the system
477 * params
478 */
479 atif->functions.system_params = true;
480 }
481
482 if (atif->functions.system_params) {
483 ret = radeon_atif_get_notification_params(handle,
484 &atif->notification_cfg);
485 if (ret) {
486 DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n",
487 ret);
488 /* Disable notification */
489 atif->notification_cfg.enabled = false;
490 }
491 }
d7a2952f 492
ce3cf821 493out:
c4917074
AD
494 rdev->acpi_nb.notifier_call = radeon_acpi_event;
495 register_acpi_notifier(&rdev->acpi_nb);
496
86504672 497 return ret;
d7a2952f
AM
498}
499
c3c65160
AD
500/**
501 * radeon_acpi_fini - tear down driver acpi support
502 *
503 * @rdev: radeon_device pointer
504 *
505 * Unregisters with the acpi notifier chain (all asics).
506 */
c4917074
AD
507void radeon_acpi_fini(struct radeon_device *rdev)
508{
509 unregister_acpi_notifier(&rdev->acpi_nb);
510}