| 
									
										
										
										
											2012-07-31 17:18:17 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright 2012 Advanced Micro Devices, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a | 
					
						
							|  |  |  |  * copy of this software and associated documentation files (the "Software"), | 
					
						
							|  |  |  |  * to deal in the Software without restriction, including without limitation | 
					
						
							|  |  |  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
					
						
							|  |  |  |  * and/or sell copies of the Software, and to permit persons to whom the | 
					
						
							|  |  |  |  * Software is furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | 
					
						
							|  |  |  |  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 
					
						
							|  |  |  |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | 
					
						
							|  |  |  |  * OTHER DEALINGS IN THE SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  | #include <linux/acpi.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-31 17:14:35 -04:00
										 |  |  | #include <linux/power_supply.h>
 | 
					
						
							| 
									
										
										
										
											2013-12-03 08:49:16 +08:00
										 |  |  | #include <linux/vga_switcheroo.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | #include <acpi/video.h>
 | 
					
						
							| 
									
										
										
										
											2012-10-02 18:01:07 +01:00
										 |  |  | #include <drm/drmP.h>
 | 
					
						
							|  |  |  | #include <drm/drm_crtc_helper.h>
 | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | #include "radeon.h"
 | 
					
						
							| 
									
										
										
										
											2012-07-18 13:28:52 -04:00
										 |  |  | #include "radeon_acpi.h"
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | #include "atom.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-31 17:14:35 -04:00
										 |  |  | #define ACPI_AC_CLASS           "ac_adapter"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-16 11:11:18 -04:00
										 |  |  | struct atif_verify_interface { | 
					
						
							|  |  |  | 	u16 size;		/* structure size in bytes (includes size field) */ | 
					
						
							|  |  |  | 	u16 version;		/* version */ | 
					
						
							|  |  |  | 	u32 notification_mask;	/* supported notifications mask */ | 
					
						
							|  |  |  | 	u32 function_bits;	/* supported functions bit vector */ | 
					
						
							|  |  |  | } __packed; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | struct atif_system_params { | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 	u16 size;		/* structure size in bytes (includes size field) */ | 
					
						
							|  |  |  | 	u32 valid_mask;		/* valid flags mask */ | 
					
						
							|  |  |  | 	u32 flags;		/* flags */ | 
					
						
							|  |  |  | 	u8 command_code;	/* notify command code */ | 
					
						
							|  |  |  | } __packed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct atif_sbios_requests { | 
					
						
							|  |  |  | 	u16 size;		/* structure size in bytes (includes size field) */ | 
					
						
							|  |  |  | 	u32 pending;		/* pending sbios requests */ | 
					
						
							|  |  |  | 	u8 panel_exp_mode;	/* panel expansion mode */ | 
					
						
							|  |  |  | 	u8 thermal_gfx;		/* thermal state: target gfx controller */ | 
					
						
							|  |  |  | 	u8 thermal_state;	/* thermal state: state id (0: exit state, non-0: state) */ | 
					
						
							|  |  |  | 	u8 forced_power_gfx;	/* forced power state: target gfx controller */ | 
					
						
							|  |  |  | 	u8 forced_power_state;	/* forced power state: state id */ | 
					
						
							|  |  |  | 	u8 system_power_src;	/* system power source */ | 
					
						
							|  |  |  | 	u8 backlight_level;	/* panel backlight level (0-255) */ | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | } __packed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ATIF_NOTIFY_MASK	0x3
 | 
					
						
							|  |  |  | #define ATIF_NOTIFY_NONE	0
 | 
					
						
							|  |  |  | #define ATIF_NOTIFY_81		1
 | 
					
						
							|  |  |  | #define ATIF_NOTIFY_N		2
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-16 11:13:43 -04:00
										 |  |  | struct atcs_verify_interface { | 
					
						
							|  |  |  | 	u16 size;		/* structure size in bytes (includes size field) */ | 
					
						
							|  |  |  | 	u16 version;		/* version */ | 
					
						
							|  |  |  | 	u32 function_bits;	/* supported functions bit vector */ | 
					
						
							|  |  |  | } __packed; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-13 15:47:24 -05:00
										 |  |  | #define ATCS_VALID_FLAGS_MASK	0x3
 | 
					
						
							| 
									
										
										
										
											2013-06-26 00:33:35 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-13 15:47:24 -05:00
										 |  |  | struct atcs_pref_req_input { | 
					
						
							|  |  |  | 	u16 size;		/* structure size in bytes (includes size field) */ | 
					
						
							|  |  |  | 	u16 client_id;		/* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ | 
					
						
							|  |  |  | 	u16 valid_flags_mask;	/* valid flags mask */ | 
					
						
							|  |  |  | 	u16 flags;		/* flags */ | 
					
						
							|  |  |  | 	u8 req_type;		/* request type */ | 
					
						
							|  |  |  | 	u8 perf_req;		/* performance request */ | 
					
						
							|  |  |  | } __packed; | 
					
						
							| 
									
										
										
										
											2013-06-26 00:33:35 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-13 15:47:24 -05:00
										 |  |  | struct atcs_pref_req_output { | 
					
						
							|  |  |  | 	u16 size;		/* structure size in bytes (includes size field) */ | 
					
						
							|  |  |  | 	u8 ret_val;		/* return value */ | 
					
						
							|  |  |  | } __packed; | 
					
						
							| 
									
										
										
										
											2013-06-26 00:33:35 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | /* Call the ATIF method
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_call - call an ATIF method | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  |  * @handle: acpi handle | 
					
						
							|  |  |  |  * @function: the ATIF function to execute | 
					
						
							|  |  |  |  * @params: ATIF function params | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Executes the requested ATIF function (all asics). | 
					
						
							|  |  |  |  * Returns a pointer to the acpi output buffer. | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-07-29 17:04:43 +02:00
										 |  |  | static union acpi_object *radeon_atif_call(acpi_handle handle, int function, | 
					
						
							|  |  |  | 		struct acpi_buffer *params) | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	acpi_status status; | 
					
						
							|  |  |  | 	union acpi_object atif_arg_elements[2]; | 
					
						
							|  |  |  | 	struct acpi_object_list atif_arg; | 
					
						
							| 
									
										
										
										
											2012-07-29 17:04:43 +02:00
										 |  |  | 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	atif_arg.count = 2; | 
					
						
							|  |  |  | 	atif_arg.pointer = &atif_arg_elements[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	atif_arg_elements[0].type = ACPI_TYPE_INTEGER; | 
					
						
							| 
									
										
										
										
											2012-07-29 17:04:43 +02:00
										 |  |  | 	atif_arg_elements[0].integer.value = function; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (params) { | 
					
						
							|  |  |  | 		atif_arg_elements[1].type = ACPI_TYPE_BUFFER; | 
					
						
							|  |  |  | 		atif_arg_elements[1].buffer.length = params->length; | 
					
						
							|  |  |  | 		atif_arg_elements[1].buffer.pointer = params->pointer; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		/* We need a second fake parameter */ | 
					
						
							|  |  |  | 		atif_arg_elements[1].type = ACPI_TYPE_INTEGER; | 
					
						
							|  |  |  | 		atif_arg_elements[1].integer.value = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Fail only if calling the method fails and ATIF is supported */ | 
					
						
							|  |  |  | 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 
					
						
							| 
									
										
										
										
											2011-11-30 17:26:36 +01:00
										 |  |  | 		DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", | 
					
						
							|  |  |  | 				 acpi_format_exception(status)); | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 		kfree(buffer.pointer); | 
					
						
							| 
									
										
										
										
											2012-07-29 17:04:43 +02:00
										 |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-29 17:04:43 +02:00
										 |  |  | 	return buffer.pointer; | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_parse_notification - parse supported notifications | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @n: supported notifications struct | 
					
						
							|  |  |  |  * @mask: supported notifications mask from ATIF | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use the supported notifications mask from ATIF function | 
					
						
							|  |  |  |  * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications | 
					
						
							|  |  |  |  * are supported (all asics). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-08-16 11:11:18 -04:00
										 |  |  | static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_parse_functions - parse supported functions | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @f: supported functions struct | 
					
						
							|  |  |  |  * @mask: supported functions mask from ATIF | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use the supported functions mask from ATIF function | 
					
						
							|  |  |  |  * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions | 
					
						
							|  |  |  |  * are supported (all asics). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-08-16 11:11:18 -04:00
										 |  |  | static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; | 
					
						
							|  |  |  | 	f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; | 
					
						
							|  |  |  | 	f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED; | 
					
						
							|  |  |  | 	f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED; | 
					
						
							|  |  |  | 	f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED; | 
					
						
							|  |  |  | 	f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED; | 
					
						
							|  |  |  | 	f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED; | 
					
						
							|  |  |  | 	f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED; | 
					
						
							|  |  |  | 	f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; | 
					
						
							|  |  |  | 	f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_verify_interface - verify ATIF | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @handle: acpi handle | 
					
						
							|  |  |  |  * @atif: radeon atif struct | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function | 
					
						
							|  |  |  |  * to initialize ATIF and determine what features are supported | 
					
						
							|  |  |  |  * (all asics). | 
					
						
							|  |  |  |  * returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-08-16 11:11:18 -04:00
										 |  |  | static int radeon_atif_verify_interface(acpi_handle handle, | 
					
						
							|  |  |  | 		struct radeon_atif *atif) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	union acpi_object *info; | 
					
						
							|  |  |  | 	struct atif_verify_interface output; | 
					
						
							|  |  |  | 	size_t size; | 
					
						
							|  |  |  | 	int err = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); | 
					
						
							|  |  |  | 	if (!info) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&output, 0, sizeof(output)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = *(u16 *) info->buffer.pointer; | 
					
						
							|  |  |  | 	if (size < 12) { | 
					
						
							| 
									
										
										
										
											2012-10-03 15:00:19 +02:00
										 |  |  | 		DRM_INFO("ATIF buffer is too small: %zu\n", size); | 
					
						
							| 
									
										
										
										
											2012-08-16 11:11:18 -04:00
										 |  |  | 		err = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	size = min(sizeof(output), size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(&output, info->buffer.pointer, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* TODO: check version? */ | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	radeon_atif_parse_notification(&atif->notifications, output.notification_mask); | 
					
						
							|  |  |  | 	radeon_atif_parse_functions(&atif->functions, output.function_bits); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	kfree(info); | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_get_notification_params - determine notify configuration | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @handle: acpi handle | 
					
						
							|  |  |  |  * @n: atif notification configuration struct | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function | 
					
						
							|  |  |  |  * to determine if a notifier is used and if so which one | 
					
						
							|  |  |  |  * (all asics).  This is either Notify(VGA, 0x81) or Notify(VGA, n) | 
					
						
							|  |  |  |  * where n is specified in the result if a notifier is used. | 
					
						
							|  |  |  |  * Returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | static int radeon_atif_get_notification_params(acpi_handle handle, | 
					
						
							|  |  |  | 		struct radeon_atif_notification_cfg *n) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	union acpi_object *info; | 
					
						
							|  |  |  | 	struct atif_system_params params; | 
					
						
							|  |  |  | 	size_t size; | 
					
						
							|  |  |  | 	int err = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); | 
					
						
							|  |  |  | 	if (!info) { | 
					
						
							|  |  |  | 		err = -EIO; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = *(u16 *) info->buffer.pointer; | 
					
						
							|  |  |  | 	if (size < 10) { | 
					
						
							|  |  |  | 		err = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(¶ms, 0, sizeof(params)); | 
					
						
							|  |  |  | 	size = min(sizeof(params), size); | 
					
						
							|  |  |  | 	memcpy(¶ms, info->buffer.pointer, size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 	DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", | 
					
						
							|  |  |  | 			params.flags, params.valid_mask); | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | 	params.flags = params.flags & params.valid_mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { | 
					
						
							|  |  |  | 		n->enabled = false; | 
					
						
							|  |  |  | 		n->command_code = 0; | 
					
						
							|  |  |  | 	} else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { | 
					
						
							|  |  |  | 		n->enabled = true; | 
					
						
							|  |  |  | 		n->command_code = 0x81; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (size < 11) { | 
					
						
							|  |  |  | 			err = -EINVAL; | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		n->enabled = true; | 
					
						
							|  |  |  | 		n->command_code = params.command_code; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 	DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", | 
					
						
							|  |  |  | 			(n->enabled ? "enabled" : "disabled"), | 
					
						
							|  |  |  | 			n->command_code); | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | 	kfree(info); | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_get_sbios_requests - get requested sbios event | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @handle: acpi handle | 
					
						
							|  |  |  |  * @req: atif sbios request struct | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function | 
					
						
							|  |  |  |  * to determine what requests the sbios is making to the driver | 
					
						
							|  |  |  |  * (all asics). | 
					
						
							|  |  |  |  * Returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | static int radeon_atif_get_sbios_requests(acpi_handle handle, | 
					
						
							|  |  |  | 		struct atif_sbios_requests *req) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	union acpi_object *info; | 
					
						
							|  |  |  | 	size_t size; | 
					
						
							|  |  |  | 	int count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); | 
					
						
							|  |  |  | 	if (!info) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = *(u16 *)info->buffer.pointer; | 
					
						
							|  |  |  | 	if (size < 0xd) { | 
					
						
							|  |  |  | 		count = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memset(req, 0, sizeof(*req)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = min(sizeof(*req), size); | 
					
						
							|  |  |  | 	memcpy(req, info->buffer.pointer, size); | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	count = hweight32(req->pending); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	kfree(info); | 
					
						
							|  |  |  | 	return count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atif_handler - handle ATIF notify requests | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @rdev: radeon_device pointer | 
					
						
							|  |  |  |  * @event: atif sbios request struct | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Checks the acpi event and if it matches an atif event, | 
					
						
							|  |  |  |  * handles it. | 
					
						
							|  |  |  |  * Returns NOTIFY code | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | int radeon_atif_handler(struct radeon_device *rdev, | 
					
						
							|  |  |  | 		struct acpi_bus_event *event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct radeon_atif *atif = &rdev->atif; | 
					
						
							|  |  |  | 	struct atif_sbios_requests req; | 
					
						
							|  |  |  | 	acpi_handle handle; | 
					
						
							|  |  |  | 	int count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", | 
					
						
							|  |  |  | 			event->device_class, event->type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) | 
					
						
							|  |  |  | 		return NOTIFY_DONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!atif->notification_cfg.enabled || | 
					
						
							|  |  |  | 			event->type != atif->notification_cfg.command_code) | 
					
						
							|  |  |  | 		/* Not our event */ | 
					
						
							|  |  |  | 		return NOTIFY_DONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Check pending SBIOS requests */ | 
					
						
							| 
									
										
										
										
											2013-11-14 23:17:21 +01:00
										 |  |  | 	handle = ACPI_HANDLE(&rdev->pdev->dev); | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 	count = radeon_atif_get_sbios_requests(handle, &req); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (count <= 0) | 
					
						
							|  |  |  | 		return NOTIFY_DONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { | 
					
						
							| 
									
										
										
										
											2012-08-03 11:39:43 -04:00
										 |  |  | 		struct radeon_encoder *enc = atif->encoder_for_bl; | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (enc) { | 
					
						
							|  |  |  | 			DRM_DEBUG_DRIVER("Changing brightness to %d\n", | 
					
						
							|  |  |  | 					req.backlight_level); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-03 11:39:43 -04:00
										 |  |  | 			radeon_set_backlight_level(rdev, enc, req.backlight_level); | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 09:10:10 -04:00
										 |  |  | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
 | 
					
						
							| 
									
										
										
										
											2012-08-03 11:39:43 -04:00
										 |  |  | 			if (rdev->is_atom_bios) { | 
					
						
							|  |  |  | 				struct radeon_encoder_atom_dig *dig = enc->enc_priv; | 
					
						
							|  |  |  | 				backlight_force_update(dig->bl_dev, | 
					
						
							|  |  |  | 						       BACKLIGHT_UPDATE_HOTKEY); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				struct radeon_encoder_lvds *dig = enc->enc_priv; | 
					
						
							|  |  |  | 				backlight_force_update(dig->bl_dev, | 
					
						
							|  |  |  | 						       BACKLIGHT_UPDATE_HOTKEY); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-10-04 09:10:10 -04:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* TODO: check other events */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 11:39:38 -04:00
										 |  |  | 	/* We've handled the event, stop the notifier chain. The ACPI interface
 | 
					
						
							|  |  |  | 	 * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to | 
					
						
							|  |  |  | 	 * userspace if the event was generated only to signal a SBIOS | 
					
						
							|  |  |  | 	 * request. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	return NOTIFY_BAD; | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-16 11:13:43 -04:00
										 |  |  | /* Call the ATCS method
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atcs_call - call an ATCS method | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @handle: acpi handle | 
					
						
							|  |  |  |  * @function: the ATCS function to execute | 
					
						
							|  |  |  |  * @params: ATCS function params | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Executes the requested ATCS function (all asics). | 
					
						
							|  |  |  |  * Returns a pointer to the acpi output buffer. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static union acpi_object *radeon_atcs_call(acpi_handle handle, int function, | 
					
						
							|  |  |  | 					   struct acpi_buffer *params) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	acpi_status status; | 
					
						
							|  |  |  | 	union acpi_object atcs_arg_elements[2]; | 
					
						
							|  |  |  | 	struct acpi_object_list atcs_arg; | 
					
						
							|  |  |  | 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	atcs_arg.count = 2; | 
					
						
							|  |  |  | 	atcs_arg.pointer = &atcs_arg_elements[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	atcs_arg_elements[0].type = ACPI_TYPE_INTEGER; | 
					
						
							|  |  |  | 	atcs_arg_elements[0].integer.value = function; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (params) { | 
					
						
							|  |  |  | 		atcs_arg_elements[1].type = ACPI_TYPE_BUFFER; | 
					
						
							|  |  |  | 		atcs_arg_elements[1].buffer.length = params->length; | 
					
						
							|  |  |  | 		atcs_arg_elements[1].buffer.pointer = params->pointer; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		/* We need a second fake parameter */ | 
					
						
							|  |  |  | 		atcs_arg_elements[1].type = ACPI_TYPE_INTEGER; | 
					
						
							|  |  |  | 		atcs_arg_elements[1].integer.value = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Fail only if calling the method fails and ATIF is supported */ | 
					
						
							|  |  |  | 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 
					
						
							|  |  |  | 		DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n", | 
					
						
							|  |  |  | 				 acpi_format_exception(status)); | 
					
						
							|  |  |  | 		kfree(buffer.pointer); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return buffer.pointer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atcs_parse_functions - parse supported functions | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @f: supported functions struct | 
					
						
							|  |  |  |  * @mask: supported functions mask from ATCS | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use the supported functions mask from ATCS function | 
					
						
							|  |  |  |  * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions | 
					
						
							|  |  |  |  * are supported (all asics). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void radeon_atcs_parse_functions(struct radeon_atcs_functions *f, u32 mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; | 
					
						
							|  |  |  | 	f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; | 
					
						
							|  |  |  | 	f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; | 
					
						
							|  |  |  | 	f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_atcs_verify_interface - verify ATCS | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @handle: acpi handle | 
					
						
							|  |  |  |  * @atcs: radeon atcs struct | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function | 
					
						
							|  |  |  |  * to initialize ATCS and determine what features are supported | 
					
						
							|  |  |  |  * (all asics). | 
					
						
							|  |  |  |  * returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int radeon_atcs_verify_interface(acpi_handle handle, | 
					
						
							|  |  |  | 					struct radeon_atcs *atcs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	union acpi_object *info; | 
					
						
							|  |  |  | 	struct atcs_verify_interface output; | 
					
						
							|  |  |  | 	size_t size; | 
					
						
							|  |  |  | 	int err = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info = radeon_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); | 
					
						
							|  |  |  | 	if (!info) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(&output, 0, sizeof(output)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = *(u16 *) info->buffer.pointer; | 
					
						
							|  |  |  | 	if (size < 8) { | 
					
						
							| 
									
										
										
										
											2012-10-03 15:00:19 +02:00
										 |  |  | 		DRM_INFO("ATCS buffer is too small: %zu\n", size); | 
					
						
							| 
									
										
										
										
											2012-08-16 11:13:43 -04:00
										 |  |  | 		err = -EINVAL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	size = min(sizeof(output), size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(&output, info->buffer.pointer, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* TODO: check version? */ | 
					
						
							|  |  |  | 	DRM_DEBUG_DRIVER("ATCS version %u\n", output.version); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	radeon_atcs_parse_functions(&atcs->functions, output.function_bits); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	kfree(info); | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-13 15:47:24 -05:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_acpi_is_pcie_performance_request_supported | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @rdev: radeon_device pointer | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Check if the ATCS pcie_perf_req and pcie_dev_rdy methods | 
					
						
							|  |  |  |  * are supported (all asics). | 
					
						
							|  |  |  |  * returns true if supported, false if not. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct radeon_atcs *atcs = &rdev->atcs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy) | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_acpi_pcie_notify_device_ready | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @rdev: radeon_device pointer | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Executes the PCIE_DEVICE_READY_NOTIFICATION method | 
					
						
							|  |  |  |  * (all asics). | 
					
						
							|  |  |  |  * returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	acpi_handle handle; | 
					
						
							|  |  |  | 	union acpi_object *info; | 
					
						
							|  |  |  | 	struct radeon_atcs *atcs = &rdev->atcs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Get the device handle */ | 
					
						
							| 
									
										
										
										
											2013-11-14 23:17:21 +01:00
										 |  |  | 	handle = ACPI_HANDLE(&rdev->pdev->dev); | 
					
						
							| 
									
										
										
										
											2013-02-13 15:47:24 -05:00
										 |  |  | 	if (!handle) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!atcs->functions.pcie_dev_rdy) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL); | 
					
						
							|  |  |  | 	if (!info) | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_acpi_pcie_performance_request | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @rdev: radeon_device pointer | 
					
						
							|  |  |  |  * @perf_req: requested perf level (pcie gen speed) | 
					
						
							|  |  |  |  * @advertise: set advertise caps flag if set | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Executes the PCIE_PERFORMANCE_REQUEST method to | 
					
						
							|  |  |  |  * change the pcie gen speed (all asics). | 
					
						
							|  |  |  |  * returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int radeon_acpi_pcie_performance_request(struct radeon_device *rdev, | 
					
						
							|  |  |  | 					 u8 perf_req, bool advertise) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	acpi_handle handle; | 
					
						
							|  |  |  | 	union acpi_object *info; | 
					
						
							|  |  |  | 	struct radeon_atcs *atcs = &rdev->atcs; | 
					
						
							|  |  |  | 	struct atcs_pref_req_input atcs_input; | 
					
						
							|  |  |  | 	struct atcs_pref_req_output atcs_output; | 
					
						
							|  |  |  | 	struct acpi_buffer params; | 
					
						
							|  |  |  | 	size_t size; | 
					
						
							|  |  |  | 	u32 retry = 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Get the device handle */ | 
					
						
							| 
									
										
										
										
											2013-11-14 23:17:21 +01:00
										 |  |  | 	handle = ACPI_HANDLE(&rdev->pdev->dev); | 
					
						
							| 
									
										
										
										
											2013-02-13 15:47:24 -05:00
										 |  |  | 	if (!handle) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!atcs->functions.pcie_perf_req) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	atcs_input.size = sizeof(struct atcs_pref_req_input); | 
					
						
							|  |  |  | 	/* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ | 
					
						
							|  |  |  | 	atcs_input.client_id = rdev->pdev->devfn | (rdev->pdev->bus->number << 8); | 
					
						
							|  |  |  | 	atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK; | 
					
						
							|  |  |  | 	atcs_input.flags = ATCS_WAIT_FOR_COMPLETION; | 
					
						
							|  |  |  | 	if (advertise) | 
					
						
							|  |  |  | 		atcs_input.flags |= ATCS_ADVERTISE_CAPS; | 
					
						
							|  |  |  | 	atcs_input.req_type = ATCS_PCIE_LINK_SPEED; | 
					
						
							|  |  |  | 	atcs_input.perf_req = perf_req; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	params.length = sizeof(struct atcs_pref_req_input); | 
					
						
							|  |  |  | 	params.pointer = &atcs_input; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (retry--) { | 
					
						
							|  |  |  | 		info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms); | 
					
						
							|  |  |  | 		if (!info) | 
					
						
							|  |  |  | 			return -EIO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		memset(&atcs_output, 0, sizeof(atcs_output)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		size = *(u16 *) info->buffer.pointer; | 
					
						
							|  |  |  | 		if (size < 3) { | 
					
						
							|  |  |  | 			DRM_INFO("ATCS buffer is too small: %zu\n", size); | 
					
						
							|  |  |  | 			kfree(info); | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		size = min(sizeof(atcs_output), size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		memcpy(&atcs_output, info->buffer.pointer, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		kfree(info); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (atcs_output.ret_val) { | 
					
						
							|  |  |  | 		case ATCS_REQUEST_REFUSED: | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		case ATCS_REQUEST_COMPLETE: | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		case ATCS_REQUEST_IN_PROGRESS: | 
					
						
							|  |  |  | 			udelay(10); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_acpi_event - handle notify events | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @nb: notifier block | 
					
						
							|  |  |  |  * @val: val | 
					
						
							|  |  |  |  * @data: acpi event | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Calls relevant radeon functions in response to various | 
					
						
							|  |  |  |  * acpi events. | 
					
						
							|  |  |  |  * Returns NOTIFY code | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-07-31 17:14:35 -04:00
										 |  |  | static int radeon_acpi_event(struct notifier_block *nb, | 
					
						
							|  |  |  | 			     unsigned long val, | 
					
						
							|  |  |  | 			     void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); | 
					
						
							|  |  |  | 	struct acpi_bus_event *entry = (struct acpi_bus_event *)data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { | 
					
						
							|  |  |  | 		if (power_supply_is_system_supplied() > 0) | 
					
						
							|  |  |  | 			DRM_DEBUG_DRIVER("pm: AC\n"); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			DRM_DEBUG_DRIVER("pm: DC\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		radeon_pm_acpi_event_handler(rdev); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Check for pending SBIOS requests */ | 
					
						
							|  |  |  | 	return radeon_atif_handler(rdev, entry); | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Call all ACPI methods here */ | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_acpi_init - init driver acpi support | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @rdev: radeon_device pointer | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Verifies the AMD ACPI interfaces and registers with the acpi | 
					
						
							|  |  |  |  * notifier chain (all asics). | 
					
						
							|  |  |  |  * Returns 0 on success, error on failure. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | int radeon_acpi_init(struct radeon_device *rdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	acpi_handle handle; | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | 	struct radeon_atif *atif = &rdev->atif; | 
					
						
							| 
									
										
										
										
											2012-08-16 11:13:43 -04:00
										 |  |  | 	struct radeon_atcs *atcs = &rdev->atcs; | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Get the device handle */ | 
					
						
							| 
									
										
										
										
											2013-11-14 23:17:21 +01:00
										 |  |  | 	handle = ACPI_HANDLE(&rdev->pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-30 17:36:39 +01:00
										 |  |  | 	/* No need to proceed if we're sure that ATIF is not supported */ | 
					
						
							|  |  |  | 	if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-16 11:13:43 -04:00
										 |  |  | 	/* Call the ATCS method */ | 
					
						
							|  |  |  | 	ret = radeon_atcs_verify_interface(handle, atcs); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 	/* Call the ATIF method */ | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | 	ret = radeon_atif_verify_interface(handle, atif); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							| 
									
										
										
										
											2012-08-16 11:13:43 -04:00
										 |  |  | 		DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 	if (atif->notifications.brightness_change) { | 
					
						
							|  |  |  | 		struct drm_encoder *tmp; | 
					
						
							|  |  |  | 		struct radeon_encoder *target = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Find the encoder controlling the brightness */ | 
					
						
							|  |  |  | 		list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, | 
					
						
							|  |  |  | 				head) { | 
					
						
							|  |  |  | 			struct radeon_encoder *enc = to_radeon_encoder(tmp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && | 
					
						
							| 
									
										
										
										
											2012-08-03 11:39:43 -04:00
										 |  |  | 			    enc->enc_priv) { | 
					
						
							|  |  |  | 				if (rdev->is_atom_bios) { | 
					
						
							|  |  |  | 					struct radeon_encoder_atom_dig *dig = enc->enc_priv; | 
					
						
							|  |  |  | 					if (dig->bl_dev) { | 
					
						
							|  |  |  | 						target = enc; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					struct radeon_encoder_lvds *dig = enc->enc_priv; | 
					
						
							|  |  |  | 					if (dig->bl_dev) { | 
					
						
							|  |  |  | 						target = enc; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-03 11:39:43 -04:00
										 |  |  | 		atif->encoder_for_bl = target; | 
					
						
							| 
									
										
										
										
											2012-07-30 21:20:35 +02:00
										 |  |  | 		if (!target) { | 
					
						
							|  |  |  | 			/* Brightness change notification is enabled, but we
 | 
					
						
							|  |  |  | 			 * didn't find a backlight controller, this should | 
					
						
							|  |  |  | 			 * never happen. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			DRM_ERROR("Cannot find a backlight controller\n"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | 	if (atif->functions.sbios_requests && !atif->functions.system_params) { | 
					
						
							|  |  |  | 		/* XXX check this workraround, if sbios request function is
 | 
					
						
							|  |  |  | 		 * present we have to see how it's configured in the system | 
					
						
							|  |  |  | 		 * params | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		atif->functions.system_params = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (atif->functions.system_params) { | 
					
						
							|  |  |  | 		ret = radeon_atif_get_notification_params(handle, | 
					
						
							|  |  |  | 				&atif->notification_cfg); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", | 
					
						
							|  |  |  | 					ret); | 
					
						
							|  |  |  | 			/* Disable notification */ | 
					
						
							|  |  |  | 			atif->notification_cfg.enabled = false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-30 21:16:06 +02:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2012-07-31 17:14:35 -04:00
										 |  |  | 	rdev->acpi_nb.notifier_call = radeon_acpi_event; | 
					
						
							|  |  |  | 	register_acpi_notifier(&rdev->acpi_nb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-29 17:04:43 +02:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2010-07-06 11:40:24 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 12:30:49 -04:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * radeon_acpi_fini - tear down driver acpi support | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @rdev: radeon_device pointer | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unregisters with the acpi notifier chain (all asics). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-07-31 17:14:35 -04:00
										 |  |  | void radeon_acpi_fini(struct radeon_device *rdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unregister_acpi_notifier(&rdev->acpi_nb); | 
					
						
							|  |  |  | } |