1efd4e418SAlex Deucher /* 2efd4e418SAlex Deucher * Copyright 2012 Advanced Micro Devices, Inc. 3efd4e418SAlex Deucher * 4efd4e418SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a 5efd4e418SAlex Deucher * copy of this software and associated documentation files (the "Software"), 6efd4e418SAlex Deucher * to deal in the Software without restriction, including without limitation 7efd4e418SAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8efd4e418SAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the 9efd4e418SAlex Deucher * Software is furnished to do so, subject to the following conditions: 10efd4e418SAlex Deucher * 11efd4e418SAlex Deucher * The above copyright notice and this permission notice shall be included in 12efd4e418SAlex Deucher * all copies or substantial portions of the Software. 13efd4e418SAlex Deucher * 14efd4e418SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15efd4e418SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16efd4e418SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17efd4e418SAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18efd4e418SAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19efd4e418SAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20efd4e418SAlex Deucher * OTHER DEALINGS IN THE SOFTWARE. 21efd4e418SAlex Deucher * 22efd4e418SAlex Deucher */ 23efd4e418SAlex Deucher 24d7a2952fSAlberto Milone #include <linux/pci.h> 25d7a2952fSAlberto Milone #include <linux/acpi.h> 26d7a2952fSAlberto Milone #include <linux/slab.h> 27c4917074SAlex Deucher #include <linux/power_supply.h> 28d7a2952fSAlberto Milone #include <acpi/acpi_drivers.h> 29d7a2952fSAlberto Milone #include <acpi/acpi_bus.h> 30fda4b25cSLuca Tettamanti #include <acpi/video.h> 31d7a2952fSAlberto Milone 32760285e7SDavid Howells #include <drm/drmP.h> 33760285e7SDavid Howells #include <drm/drm_crtc_helper.h> 34d7a2952fSAlberto Milone #include "radeon.h" 359e05b2f4SAlex Deucher #include "radeon_acpi.h" 36fda4b25cSLuca Tettamanti #include "atom.h" 37d7a2952fSAlberto Milone 38d7a2952fSAlberto Milone #include <linux/vga_switcheroo.h> 39d7a2952fSAlberto Milone 40c4917074SAlex Deucher #define ACPI_AC_CLASS "ac_adapter" 41c4917074SAlex Deucher 42c4917074SAlex Deucher extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); 43c4917074SAlex Deucher 44fd64ca8aSLuca Tettamanti struct atif_verify_interface { 45fd64ca8aSLuca Tettamanti u16 size; /* structure size in bytes (includes size field) */ 46fd64ca8aSLuca Tettamanti u16 version; /* version */ 47fd64ca8aSLuca Tettamanti u32 notification_mask; /* supported notifications mask */ 48fd64ca8aSLuca Tettamanti u32 function_bits; /* supported functions bit vector */ 49fd64ca8aSLuca Tettamanti } __packed; 50fd64ca8aSLuca Tettamanti 51ce3cf821SLuca Tettamanti struct atif_system_params { 52fda4b25cSLuca Tettamanti u16 size; /* structure size in bytes (includes size field) */ 53fda4b25cSLuca Tettamanti u32 valid_mask; /* valid flags mask */ 54fda4b25cSLuca Tettamanti u32 flags; /* flags */ 55fda4b25cSLuca Tettamanti u8 command_code; /* notify command code */ 56fda4b25cSLuca Tettamanti } __packed; 57fda4b25cSLuca Tettamanti 58fda4b25cSLuca Tettamanti struct atif_sbios_requests { 59fda4b25cSLuca Tettamanti u16 size; /* structure size in bytes (includes size field) */ 60fda4b25cSLuca Tettamanti u32 pending; /* pending sbios requests */ 61fda4b25cSLuca Tettamanti u8 panel_exp_mode; /* panel expansion mode */ 62fda4b25cSLuca Tettamanti u8 thermal_gfx; /* thermal state: target gfx controller */ 63fda4b25cSLuca Tettamanti u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ 64fda4b25cSLuca Tettamanti u8 forced_power_gfx; /* forced power state: target gfx controller */ 65fda4b25cSLuca Tettamanti u8 forced_power_state; /* forced power state: state id */ 66fda4b25cSLuca Tettamanti u8 system_power_src; /* system power source */ 67fda4b25cSLuca Tettamanti u8 backlight_level; /* panel backlight level (0-255) */ 68ce3cf821SLuca Tettamanti } __packed; 69ce3cf821SLuca Tettamanti 70ce3cf821SLuca Tettamanti #define ATIF_NOTIFY_MASK 0x3 71ce3cf821SLuca Tettamanti #define ATIF_NOTIFY_NONE 0 72ce3cf821SLuca Tettamanti #define ATIF_NOTIFY_81 1 73ce3cf821SLuca Tettamanti #define ATIF_NOTIFY_N 2 74ce3cf821SLuca Tettamanti 75e3a15920SAlex Deucher struct atcs_verify_interface { 76e3a15920SAlex Deucher u16 size; /* structure size in bytes (includes size field) */ 77e3a15920SAlex Deucher u16 version; /* version */ 78e3a15920SAlex Deucher u32 function_bits; /* supported functions bit vector */ 79e3a15920SAlex Deucher } __packed; 80e3a15920SAlex Deucher 81*e37e6a0eSAlex Deucher #define ATCS_VALID_FLAGS_MASK 0x3 82dc50ba7fSAlex Deucher 83*e37e6a0eSAlex Deucher struct atcs_pref_req_input { 84*e37e6a0eSAlex Deucher u16 size; /* structure size in bytes (includes size field) */ 85*e37e6a0eSAlex Deucher u16 client_id; /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ 86*e37e6a0eSAlex Deucher u16 valid_flags_mask; /* valid flags mask */ 87*e37e6a0eSAlex Deucher u16 flags; /* flags */ 88*e37e6a0eSAlex Deucher u8 req_type; /* request type */ 89*e37e6a0eSAlex Deucher u8 perf_req; /* performance request */ 90*e37e6a0eSAlex Deucher } __packed; 91dc50ba7fSAlex Deucher 92*e37e6a0eSAlex Deucher struct atcs_pref_req_output { 93*e37e6a0eSAlex Deucher u16 size; /* structure size in bytes (includes size field) */ 94*e37e6a0eSAlex Deucher u8 ret_val; /* return value */ 95*e37e6a0eSAlex Deucher } __packed; 96dc50ba7fSAlex Deucher 97d7a2952fSAlberto Milone /* Call the ATIF method 98d7a2952fSAlberto Milone */ 99c3c65160SAlex Deucher /** 100c3c65160SAlex Deucher * radeon_atif_call - call an ATIF method 101c3c65160SAlex Deucher * 102c3c65160SAlex Deucher * @handle: acpi handle 103c3c65160SAlex Deucher * @function: the ATIF function to execute 104c3c65160SAlex Deucher * @params: ATIF function params 105c3c65160SAlex Deucher * 106c3c65160SAlex Deucher * Executes the requested ATIF function (all asics). 107c3c65160SAlex Deucher * Returns a pointer to the acpi output buffer. 108c3c65160SAlex Deucher */ 10986504672SLuca Tettamanti static union acpi_object *radeon_atif_call(acpi_handle handle, int function, 11086504672SLuca Tettamanti struct acpi_buffer *params) 111d7a2952fSAlberto Milone { 112d7a2952fSAlberto Milone acpi_status status; 113d7a2952fSAlberto Milone union acpi_object atif_arg_elements[2]; 114d7a2952fSAlberto Milone struct acpi_object_list atif_arg; 115d7a2952fSAlberto Milone struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 116d7a2952fSAlberto Milone 117d7a2952fSAlberto Milone atif_arg.count = 2; 118d7a2952fSAlberto Milone atif_arg.pointer = &atif_arg_elements[0]; 119d7a2952fSAlberto Milone 120d7a2952fSAlberto Milone atif_arg_elements[0].type = ACPI_TYPE_INTEGER; 12186504672SLuca Tettamanti atif_arg_elements[0].integer.value = function; 12286504672SLuca Tettamanti 12386504672SLuca Tettamanti if (params) { 12486504672SLuca Tettamanti atif_arg_elements[1].type = ACPI_TYPE_BUFFER; 12586504672SLuca Tettamanti atif_arg_elements[1].buffer.length = params->length; 12686504672SLuca Tettamanti atif_arg_elements[1].buffer.pointer = params->pointer; 12786504672SLuca Tettamanti } else { 12886504672SLuca Tettamanti /* We need a second fake parameter */ 129d7a2952fSAlberto Milone atif_arg_elements[1].type = ACPI_TYPE_INTEGER; 130d7a2952fSAlberto Milone atif_arg_elements[1].integer.value = 0; 13186504672SLuca Tettamanti } 132d7a2952fSAlberto Milone 133d7a2952fSAlberto Milone status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); 134d7a2952fSAlberto Milone 135d7a2952fSAlberto Milone /* Fail only if calling the method fails and ATIF is supported */ 136d7a2952fSAlberto Milone if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 137bc96f942SJean Delvare DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", 138bc96f942SJean Delvare acpi_format_exception(status)); 139d7a2952fSAlberto Milone kfree(buffer.pointer); 14086504672SLuca Tettamanti return NULL; 141d7a2952fSAlberto Milone } 142d7a2952fSAlberto Milone 14386504672SLuca Tettamanti return buffer.pointer; 144d7a2952fSAlberto Milone } 145d7a2952fSAlberto Milone 146c3c65160SAlex Deucher /** 147c3c65160SAlex Deucher * radeon_atif_parse_notification - parse supported notifications 148c3c65160SAlex Deucher * 149c3c65160SAlex Deucher * @n: supported notifications struct 150c3c65160SAlex Deucher * @mask: supported notifications mask from ATIF 151c3c65160SAlex Deucher * 152c3c65160SAlex Deucher * Use the supported notifications mask from ATIF function 153c3c65160SAlex Deucher * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications 154c3c65160SAlex Deucher * are supported (all asics). 155c3c65160SAlex Deucher */ 156fd64ca8aSLuca Tettamanti static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) 157fd64ca8aSLuca Tettamanti { 158fd64ca8aSLuca Tettamanti n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; 159fd64ca8aSLuca Tettamanti n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED; 160fd64ca8aSLuca Tettamanti n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; 161fd64ca8aSLuca Tettamanti n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; 162fd64ca8aSLuca Tettamanti n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; 163fd64ca8aSLuca Tettamanti n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED; 164fd64ca8aSLuca Tettamanti n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED; 165fd64ca8aSLuca Tettamanti n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; 166fd64ca8aSLuca Tettamanti n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; 167fd64ca8aSLuca Tettamanti } 168fd64ca8aSLuca Tettamanti 169c3c65160SAlex Deucher /** 170c3c65160SAlex Deucher * radeon_atif_parse_functions - parse supported functions 171c3c65160SAlex Deucher * 172c3c65160SAlex Deucher * @f: supported functions struct 173c3c65160SAlex Deucher * @mask: supported functions mask from ATIF 174c3c65160SAlex Deucher * 175c3c65160SAlex Deucher * Use the supported functions mask from ATIF function 176c3c65160SAlex Deucher * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions 177c3c65160SAlex Deucher * are supported (all asics). 178c3c65160SAlex Deucher */ 179fd64ca8aSLuca Tettamanti static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) 180fd64ca8aSLuca Tettamanti { 181fd64ca8aSLuca Tettamanti f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; 182fd64ca8aSLuca Tettamanti f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; 183fd64ca8aSLuca Tettamanti f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED; 184fd64ca8aSLuca Tettamanti f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED; 185fd64ca8aSLuca Tettamanti f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED; 186fd64ca8aSLuca Tettamanti f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED; 187fd64ca8aSLuca Tettamanti f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED; 188fd64ca8aSLuca Tettamanti f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED; 189fd64ca8aSLuca Tettamanti f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; 190fd64ca8aSLuca Tettamanti f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; 191fd64ca8aSLuca Tettamanti } 192fd64ca8aSLuca Tettamanti 193c3c65160SAlex Deucher /** 194c3c65160SAlex Deucher * radeon_atif_verify_interface - verify ATIF 195c3c65160SAlex Deucher * 196c3c65160SAlex Deucher * @handle: acpi handle 197c3c65160SAlex Deucher * @atif: radeon atif struct 198c3c65160SAlex Deucher * 199c3c65160SAlex Deucher * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function 200c3c65160SAlex Deucher * to initialize ATIF and determine what features are supported 201c3c65160SAlex Deucher * (all asics). 202c3c65160SAlex Deucher * returns 0 on success, error on failure. 203c3c65160SAlex Deucher */ 204fd64ca8aSLuca Tettamanti static int radeon_atif_verify_interface(acpi_handle handle, 205fd64ca8aSLuca Tettamanti struct radeon_atif *atif) 206fd64ca8aSLuca Tettamanti { 207fd64ca8aSLuca Tettamanti union acpi_object *info; 208fd64ca8aSLuca Tettamanti struct atif_verify_interface output; 209fd64ca8aSLuca Tettamanti size_t size; 210fd64ca8aSLuca Tettamanti int err = 0; 211fd64ca8aSLuca Tettamanti 212fd64ca8aSLuca Tettamanti info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); 213fd64ca8aSLuca Tettamanti if (!info) 214fd64ca8aSLuca Tettamanti return -EIO; 215fd64ca8aSLuca Tettamanti 216fd64ca8aSLuca Tettamanti memset(&output, 0, sizeof(output)); 217fd64ca8aSLuca Tettamanti 218fd64ca8aSLuca Tettamanti size = *(u16 *) info->buffer.pointer; 219fd64ca8aSLuca Tettamanti if (size < 12) { 220a1871936SLuca Tettamanti DRM_INFO("ATIF buffer is too small: %zu\n", size); 221fd64ca8aSLuca Tettamanti err = -EINVAL; 222fd64ca8aSLuca Tettamanti goto out; 223fd64ca8aSLuca Tettamanti } 224fd64ca8aSLuca Tettamanti size = min(sizeof(output), size); 225fd64ca8aSLuca Tettamanti 226fd64ca8aSLuca Tettamanti memcpy(&output, info->buffer.pointer, size); 227fd64ca8aSLuca Tettamanti 228fd64ca8aSLuca Tettamanti /* TODO: check version? */ 229fd64ca8aSLuca Tettamanti DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); 230fd64ca8aSLuca Tettamanti 231fd64ca8aSLuca Tettamanti radeon_atif_parse_notification(&atif->notifications, output.notification_mask); 232fd64ca8aSLuca Tettamanti radeon_atif_parse_functions(&atif->functions, output.function_bits); 233fd64ca8aSLuca Tettamanti 234fd64ca8aSLuca Tettamanti out: 235fd64ca8aSLuca Tettamanti kfree(info); 236fd64ca8aSLuca Tettamanti return err; 237fd64ca8aSLuca Tettamanti } 238fd64ca8aSLuca Tettamanti 239c3c65160SAlex Deucher /** 240c3c65160SAlex Deucher * radeon_atif_get_notification_params - determine notify configuration 241c3c65160SAlex Deucher * 242c3c65160SAlex Deucher * @handle: acpi handle 243c3c65160SAlex Deucher * @n: atif notification configuration struct 244c3c65160SAlex Deucher * 245c3c65160SAlex Deucher * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function 246c3c65160SAlex Deucher * to determine if a notifier is used and if so which one 247c3c65160SAlex Deucher * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) 248c3c65160SAlex Deucher * where n is specified in the result if a notifier is used. 249c3c65160SAlex Deucher * Returns 0 on success, error on failure. 250c3c65160SAlex Deucher */ 251ce3cf821SLuca Tettamanti static int radeon_atif_get_notification_params(acpi_handle handle, 252ce3cf821SLuca Tettamanti struct radeon_atif_notification_cfg *n) 253ce3cf821SLuca Tettamanti { 254ce3cf821SLuca Tettamanti union acpi_object *info; 255ce3cf821SLuca Tettamanti struct atif_system_params params; 256ce3cf821SLuca Tettamanti size_t size; 257ce3cf821SLuca Tettamanti int err = 0; 258ce3cf821SLuca Tettamanti 259ce3cf821SLuca Tettamanti info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); 260ce3cf821SLuca Tettamanti if (!info) { 261ce3cf821SLuca Tettamanti err = -EIO; 262ce3cf821SLuca Tettamanti goto out; 263ce3cf821SLuca Tettamanti } 264ce3cf821SLuca Tettamanti 265ce3cf821SLuca Tettamanti size = *(u16 *) info->buffer.pointer; 266ce3cf821SLuca Tettamanti if (size < 10) { 267ce3cf821SLuca Tettamanti err = -EINVAL; 268ce3cf821SLuca Tettamanti goto out; 269ce3cf821SLuca Tettamanti } 270ce3cf821SLuca Tettamanti 271ce3cf821SLuca Tettamanti memset(¶ms, 0, sizeof(params)); 272ce3cf821SLuca Tettamanti size = min(sizeof(params), size); 273ce3cf821SLuca Tettamanti memcpy(¶ms, info->buffer.pointer, size); 274ce3cf821SLuca Tettamanti 275fda4b25cSLuca Tettamanti DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", 276fda4b25cSLuca Tettamanti params.flags, params.valid_mask); 277ce3cf821SLuca Tettamanti params.flags = params.flags & params.valid_mask; 278ce3cf821SLuca Tettamanti 279ce3cf821SLuca Tettamanti if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { 280ce3cf821SLuca Tettamanti n->enabled = false; 281ce3cf821SLuca Tettamanti n->command_code = 0; 282ce3cf821SLuca Tettamanti } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { 283ce3cf821SLuca Tettamanti n->enabled = true; 284ce3cf821SLuca Tettamanti n->command_code = 0x81; 285ce3cf821SLuca Tettamanti } else { 286ce3cf821SLuca Tettamanti if (size < 11) { 287ce3cf821SLuca Tettamanti err = -EINVAL; 288ce3cf821SLuca Tettamanti goto out; 289ce3cf821SLuca Tettamanti } 290ce3cf821SLuca Tettamanti n->enabled = true; 291ce3cf821SLuca Tettamanti n->command_code = params.command_code; 292ce3cf821SLuca Tettamanti } 293ce3cf821SLuca Tettamanti 294ce3cf821SLuca Tettamanti out: 295fda4b25cSLuca Tettamanti DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", 296fda4b25cSLuca Tettamanti (n->enabled ? "enabled" : "disabled"), 297fda4b25cSLuca Tettamanti n->command_code); 298ce3cf821SLuca Tettamanti kfree(info); 299ce3cf821SLuca Tettamanti return err; 300ce3cf821SLuca Tettamanti } 301ce3cf821SLuca Tettamanti 302c3c65160SAlex Deucher /** 303c3c65160SAlex Deucher * radeon_atif_get_sbios_requests - get requested sbios event 304c3c65160SAlex Deucher * 305c3c65160SAlex Deucher * @handle: acpi handle 306c3c65160SAlex Deucher * @req: atif sbios request struct 307c3c65160SAlex Deucher * 308c3c65160SAlex Deucher * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function 309c3c65160SAlex Deucher * to determine what requests the sbios is making to the driver 310c3c65160SAlex Deucher * (all asics). 311c3c65160SAlex Deucher * Returns 0 on success, error on failure. 312c3c65160SAlex Deucher */ 313fda4b25cSLuca Tettamanti static int radeon_atif_get_sbios_requests(acpi_handle handle, 314fda4b25cSLuca Tettamanti struct atif_sbios_requests *req) 315fda4b25cSLuca Tettamanti { 316fda4b25cSLuca Tettamanti union acpi_object *info; 317fda4b25cSLuca Tettamanti size_t size; 318fda4b25cSLuca Tettamanti int count = 0; 319fda4b25cSLuca Tettamanti 320fda4b25cSLuca Tettamanti info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); 321fda4b25cSLuca Tettamanti if (!info) 322fda4b25cSLuca Tettamanti return -EIO; 323fda4b25cSLuca Tettamanti 324fda4b25cSLuca Tettamanti size = *(u16 *)info->buffer.pointer; 325fda4b25cSLuca Tettamanti if (size < 0xd) { 326fda4b25cSLuca Tettamanti count = -EINVAL; 327fda4b25cSLuca Tettamanti goto out; 328fda4b25cSLuca Tettamanti } 329fda4b25cSLuca Tettamanti memset(req, 0, sizeof(*req)); 330fda4b25cSLuca Tettamanti 331fda4b25cSLuca Tettamanti size = min(sizeof(*req), size); 332fda4b25cSLuca Tettamanti memcpy(req, info->buffer.pointer, size); 333fda4b25cSLuca Tettamanti DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); 334fda4b25cSLuca Tettamanti 335fda4b25cSLuca Tettamanti count = hweight32(req->pending); 336fda4b25cSLuca Tettamanti 337fda4b25cSLuca Tettamanti out: 338fda4b25cSLuca Tettamanti kfree(info); 339fda4b25cSLuca Tettamanti return count; 340fda4b25cSLuca Tettamanti } 341fda4b25cSLuca Tettamanti 342c3c65160SAlex Deucher /** 343c3c65160SAlex Deucher * radeon_atif_handler - handle ATIF notify requests 344c3c65160SAlex Deucher * 345c3c65160SAlex Deucher * @rdev: radeon_device pointer 346c3c65160SAlex Deucher * @event: atif sbios request struct 347c3c65160SAlex Deucher * 348c3c65160SAlex Deucher * Checks the acpi event and if it matches an atif event, 349c3c65160SAlex Deucher * handles it. 350c3c65160SAlex Deucher * Returns NOTIFY code 351c3c65160SAlex Deucher */ 352fda4b25cSLuca Tettamanti int radeon_atif_handler(struct radeon_device *rdev, 353fda4b25cSLuca Tettamanti struct acpi_bus_event *event) 354fda4b25cSLuca Tettamanti { 355fda4b25cSLuca Tettamanti struct radeon_atif *atif = &rdev->atif; 356fda4b25cSLuca Tettamanti struct atif_sbios_requests req; 357fda4b25cSLuca Tettamanti acpi_handle handle; 358fda4b25cSLuca Tettamanti int count; 359fda4b25cSLuca Tettamanti 360fda4b25cSLuca Tettamanti DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", 361fda4b25cSLuca Tettamanti event->device_class, event->type); 362fda4b25cSLuca Tettamanti 363fda4b25cSLuca Tettamanti if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) 364fda4b25cSLuca Tettamanti return NOTIFY_DONE; 365fda4b25cSLuca Tettamanti 366fda4b25cSLuca Tettamanti if (!atif->notification_cfg.enabled || 367fda4b25cSLuca Tettamanti event->type != atif->notification_cfg.command_code) 368fda4b25cSLuca Tettamanti /* Not our event */ 369fda4b25cSLuca Tettamanti return NOTIFY_DONE; 370fda4b25cSLuca Tettamanti 371fda4b25cSLuca Tettamanti /* Check pending SBIOS requests */ 372fda4b25cSLuca Tettamanti handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); 373fda4b25cSLuca Tettamanti count = radeon_atif_get_sbios_requests(handle, &req); 374fda4b25cSLuca Tettamanti 375fda4b25cSLuca Tettamanti if (count <= 0) 376fda4b25cSLuca Tettamanti return NOTIFY_DONE; 377fda4b25cSLuca Tettamanti 378fda4b25cSLuca Tettamanti DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); 379fda4b25cSLuca Tettamanti 380fda4b25cSLuca Tettamanti if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { 38137e9b6a6SAlex Deucher struct radeon_encoder *enc = atif->encoder_for_bl; 382fda4b25cSLuca Tettamanti 383fda4b25cSLuca Tettamanti if (enc) { 384fda4b25cSLuca Tettamanti DRM_DEBUG_DRIVER("Changing brightness to %d\n", 385fda4b25cSLuca Tettamanti req.backlight_level); 386fda4b25cSLuca Tettamanti 38737e9b6a6SAlex Deucher radeon_set_backlight_level(rdev, enc, req.backlight_level); 388fda4b25cSLuca Tettamanti 389cd23492aSAlex Deucher #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 39037e9b6a6SAlex Deucher if (rdev->is_atom_bios) { 39137e9b6a6SAlex Deucher struct radeon_encoder_atom_dig *dig = enc->enc_priv; 392fda4b25cSLuca Tettamanti backlight_force_update(dig->bl_dev, 393fda4b25cSLuca Tettamanti BACKLIGHT_UPDATE_HOTKEY); 39437e9b6a6SAlex Deucher } else { 39537e9b6a6SAlex Deucher struct radeon_encoder_lvds *dig = enc->enc_priv; 39637e9b6a6SAlex Deucher backlight_force_update(dig->bl_dev, 39737e9b6a6SAlex Deucher BACKLIGHT_UPDATE_HOTKEY); 39837e9b6a6SAlex Deucher } 399cd23492aSAlex Deucher #endif 400fda4b25cSLuca Tettamanti } 401fda4b25cSLuca Tettamanti } 402fda4b25cSLuca Tettamanti /* TODO: check other events */ 403fda4b25cSLuca Tettamanti 40492fdf89aSLuca Tettamanti /* We've handled the event, stop the notifier chain. The ACPI interface 40592fdf89aSLuca Tettamanti * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to 40692fdf89aSLuca Tettamanti * userspace if the event was generated only to signal a SBIOS 40792fdf89aSLuca Tettamanti * request. 40892fdf89aSLuca Tettamanti */ 40992fdf89aSLuca Tettamanti return NOTIFY_BAD; 410fda4b25cSLuca Tettamanti } 411fda4b25cSLuca Tettamanti 412e3a15920SAlex Deucher /* Call the ATCS method 413e3a15920SAlex Deucher */ 414e3a15920SAlex Deucher /** 415e3a15920SAlex Deucher * radeon_atcs_call - call an ATCS method 416e3a15920SAlex Deucher * 417e3a15920SAlex Deucher * @handle: acpi handle 418e3a15920SAlex Deucher * @function: the ATCS function to execute 419e3a15920SAlex Deucher * @params: ATCS function params 420e3a15920SAlex Deucher * 421e3a15920SAlex Deucher * Executes the requested ATCS function (all asics). 422e3a15920SAlex Deucher * Returns a pointer to the acpi output buffer. 423e3a15920SAlex Deucher */ 424e3a15920SAlex Deucher static union acpi_object *radeon_atcs_call(acpi_handle handle, int function, 425e3a15920SAlex Deucher struct acpi_buffer *params) 426e3a15920SAlex Deucher { 427e3a15920SAlex Deucher acpi_status status; 428e3a15920SAlex Deucher union acpi_object atcs_arg_elements[2]; 429e3a15920SAlex Deucher struct acpi_object_list atcs_arg; 430e3a15920SAlex Deucher struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 431e3a15920SAlex Deucher 432e3a15920SAlex Deucher atcs_arg.count = 2; 433e3a15920SAlex Deucher atcs_arg.pointer = &atcs_arg_elements[0]; 434e3a15920SAlex Deucher 435e3a15920SAlex Deucher atcs_arg_elements[0].type = ACPI_TYPE_INTEGER; 436e3a15920SAlex Deucher atcs_arg_elements[0].integer.value = function; 437e3a15920SAlex Deucher 438e3a15920SAlex Deucher if (params) { 439e3a15920SAlex Deucher atcs_arg_elements[1].type = ACPI_TYPE_BUFFER; 440e3a15920SAlex Deucher atcs_arg_elements[1].buffer.length = params->length; 441e3a15920SAlex Deucher atcs_arg_elements[1].buffer.pointer = params->pointer; 442e3a15920SAlex Deucher } else { 443e3a15920SAlex Deucher /* We need a second fake parameter */ 444e3a15920SAlex Deucher atcs_arg_elements[1].type = ACPI_TYPE_INTEGER; 445e3a15920SAlex Deucher atcs_arg_elements[1].integer.value = 0; 446e3a15920SAlex Deucher } 447e3a15920SAlex Deucher 448e3a15920SAlex Deucher status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer); 449e3a15920SAlex Deucher 450e3a15920SAlex Deucher /* Fail only if calling the method fails and ATIF is supported */ 451e3a15920SAlex Deucher if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 452e3a15920SAlex Deucher DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n", 453e3a15920SAlex Deucher acpi_format_exception(status)); 454d7a2952fSAlberto Milone kfree(buffer.pointer); 455e3a15920SAlex Deucher return NULL; 456e3a15920SAlex Deucher } 457e3a15920SAlex Deucher 458e3a15920SAlex Deucher return buffer.pointer; 459e3a15920SAlex Deucher } 460e3a15920SAlex Deucher 461e3a15920SAlex Deucher /** 462e3a15920SAlex Deucher * radeon_atcs_parse_functions - parse supported functions 463e3a15920SAlex Deucher * 464e3a15920SAlex Deucher * @f: supported functions struct 465e3a15920SAlex Deucher * @mask: supported functions mask from ATCS 466e3a15920SAlex Deucher * 467e3a15920SAlex Deucher * Use the supported functions mask from ATCS function 468e3a15920SAlex Deucher * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions 469e3a15920SAlex Deucher * are supported (all asics). 470e3a15920SAlex Deucher */ 471e3a15920SAlex Deucher static void radeon_atcs_parse_functions(struct radeon_atcs_functions *f, u32 mask) 472e3a15920SAlex Deucher { 473e3a15920SAlex Deucher f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; 474e3a15920SAlex Deucher f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; 475e3a15920SAlex Deucher f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; 476e3a15920SAlex Deucher f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; 477e3a15920SAlex Deucher } 478e3a15920SAlex Deucher 479e3a15920SAlex Deucher /** 480e3a15920SAlex Deucher * radeon_atcs_verify_interface - verify ATCS 481e3a15920SAlex Deucher * 482e3a15920SAlex Deucher * @handle: acpi handle 483e3a15920SAlex Deucher * @atcs: radeon atcs struct 484e3a15920SAlex Deucher * 485e3a15920SAlex Deucher * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function 486e3a15920SAlex Deucher * to initialize ATCS and determine what features are supported 487e3a15920SAlex Deucher * (all asics). 488e3a15920SAlex Deucher * returns 0 on success, error on failure. 489e3a15920SAlex Deucher */ 490e3a15920SAlex Deucher static int radeon_atcs_verify_interface(acpi_handle handle, 491e3a15920SAlex Deucher struct radeon_atcs *atcs) 492e3a15920SAlex Deucher { 493e3a15920SAlex Deucher union acpi_object *info; 494e3a15920SAlex Deucher struct atcs_verify_interface output; 495e3a15920SAlex Deucher size_t size; 496e3a15920SAlex Deucher int err = 0; 497e3a15920SAlex Deucher 498e3a15920SAlex Deucher info = radeon_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); 499e3a15920SAlex Deucher if (!info) 500e3a15920SAlex Deucher return -EIO; 501e3a15920SAlex Deucher 502e3a15920SAlex Deucher memset(&output, 0, sizeof(output)); 503e3a15920SAlex Deucher 504e3a15920SAlex Deucher size = *(u16 *) info->buffer.pointer; 505e3a15920SAlex Deucher if (size < 8) { 506a1871936SLuca Tettamanti DRM_INFO("ATCS buffer is too small: %zu\n", size); 507e3a15920SAlex Deucher err = -EINVAL; 508e3a15920SAlex Deucher goto out; 509e3a15920SAlex Deucher } 510e3a15920SAlex Deucher size = min(sizeof(output), size); 511e3a15920SAlex Deucher 512e3a15920SAlex Deucher memcpy(&output, info->buffer.pointer, size); 513e3a15920SAlex Deucher 514e3a15920SAlex Deucher /* TODO: check version? */ 515e3a15920SAlex Deucher DRM_DEBUG_DRIVER("ATCS version %u\n", output.version); 516e3a15920SAlex Deucher 517e3a15920SAlex Deucher radeon_atcs_parse_functions(&atcs->functions, output.function_bits); 518e3a15920SAlex Deucher 519e3a15920SAlex Deucher out: 520e3a15920SAlex Deucher kfree(info); 521e3a15920SAlex Deucher return err; 522e3a15920SAlex Deucher } 523e3a15920SAlex Deucher 524c3c65160SAlex Deucher /** 525*e37e6a0eSAlex Deucher * radeon_acpi_is_pcie_performance_request_supported 526*e37e6a0eSAlex Deucher * 527*e37e6a0eSAlex Deucher * @rdev: radeon_device pointer 528*e37e6a0eSAlex Deucher * 529*e37e6a0eSAlex Deucher * Check if the ATCS pcie_perf_req and pcie_dev_rdy methods 530*e37e6a0eSAlex Deucher * are supported (all asics). 531*e37e6a0eSAlex Deucher * returns true if supported, false if not. 532*e37e6a0eSAlex Deucher */ 533*e37e6a0eSAlex Deucher bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev) 534*e37e6a0eSAlex Deucher { 535*e37e6a0eSAlex Deucher struct radeon_atcs *atcs = &rdev->atcs; 536*e37e6a0eSAlex Deucher 537*e37e6a0eSAlex Deucher if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy) 538*e37e6a0eSAlex Deucher return true; 539*e37e6a0eSAlex Deucher 540*e37e6a0eSAlex Deucher return false; 541*e37e6a0eSAlex Deucher } 542*e37e6a0eSAlex Deucher 543*e37e6a0eSAlex Deucher /** 544*e37e6a0eSAlex Deucher * radeon_acpi_pcie_notify_device_ready 545*e37e6a0eSAlex Deucher * 546*e37e6a0eSAlex Deucher * @rdev: radeon_device pointer 547*e37e6a0eSAlex Deucher * 548*e37e6a0eSAlex Deucher * Executes the PCIE_DEVICE_READY_NOTIFICATION method 549*e37e6a0eSAlex Deucher * (all asics). 550*e37e6a0eSAlex Deucher * returns 0 on success, error on failure. 551*e37e6a0eSAlex Deucher */ 552*e37e6a0eSAlex Deucher int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev) 553*e37e6a0eSAlex Deucher { 554*e37e6a0eSAlex Deucher acpi_handle handle; 555*e37e6a0eSAlex Deucher union acpi_object *info; 556*e37e6a0eSAlex Deucher struct radeon_atcs *atcs = &rdev->atcs; 557*e37e6a0eSAlex Deucher 558*e37e6a0eSAlex Deucher /* Get the device handle */ 559*e37e6a0eSAlex Deucher handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); 560*e37e6a0eSAlex Deucher if (!handle) 561*e37e6a0eSAlex Deucher return -EINVAL; 562*e37e6a0eSAlex Deucher 563*e37e6a0eSAlex Deucher if (!atcs->functions.pcie_dev_rdy) 564*e37e6a0eSAlex Deucher return -EINVAL; 565*e37e6a0eSAlex Deucher 566*e37e6a0eSAlex Deucher info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL); 567*e37e6a0eSAlex Deucher if (!info) 568*e37e6a0eSAlex Deucher return -EIO; 569*e37e6a0eSAlex Deucher 570*e37e6a0eSAlex Deucher kfree(info); 571*e37e6a0eSAlex Deucher 572*e37e6a0eSAlex Deucher return 0; 573*e37e6a0eSAlex Deucher } 574*e37e6a0eSAlex Deucher 575*e37e6a0eSAlex Deucher /** 576*e37e6a0eSAlex Deucher * radeon_acpi_pcie_performance_request 577*e37e6a0eSAlex Deucher * 578*e37e6a0eSAlex Deucher * @rdev: radeon_device pointer 579*e37e6a0eSAlex Deucher * @perf_req: requested perf level (pcie gen speed) 580*e37e6a0eSAlex Deucher * @advertise: set advertise caps flag if set 581*e37e6a0eSAlex Deucher * 582*e37e6a0eSAlex Deucher * Executes the PCIE_PERFORMANCE_REQUEST method to 583*e37e6a0eSAlex Deucher * change the pcie gen speed (all asics). 584*e37e6a0eSAlex Deucher * returns 0 on success, error on failure. 585*e37e6a0eSAlex Deucher */ 586*e37e6a0eSAlex Deucher int radeon_acpi_pcie_performance_request(struct radeon_device *rdev, 587*e37e6a0eSAlex Deucher u8 perf_req, bool advertise) 588*e37e6a0eSAlex Deucher { 589*e37e6a0eSAlex Deucher acpi_handle handle; 590*e37e6a0eSAlex Deucher union acpi_object *info; 591*e37e6a0eSAlex Deucher struct radeon_atcs *atcs = &rdev->atcs; 592*e37e6a0eSAlex Deucher struct atcs_pref_req_input atcs_input; 593*e37e6a0eSAlex Deucher struct atcs_pref_req_output atcs_output; 594*e37e6a0eSAlex Deucher struct acpi_buffer params; 595*e37e6a0eSAlex Deucher size_t size; 596*e37e6a0eSAlex Deucher u32 retry = 3; 597*e37e6a0eSAlex Deucher 598*e37e6a0eSAlex Deucher /* Get the device handle */ 599*e37e6a0eSAlex Deucher handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); 600*e37e6a0eSAlex Deucher if (!handle) 601*e37e6a0eSAlex Deucher return -EINVAL; 602*e37e6a0eSAlex Deucher 603*e37e6a0eSAlex Deucher if (!atcs->functions.pcie_perf_req) 604*e37e6a0eSAlex Deucher return -EINVAL; 605*e37e6a0eSAlex Deucher 606*e37e6a0eSAlex Deucher atcs_input.size = sizeof(struct atcs_pref_req_input); 607*e37e6a0eSAlex Deucher /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ 608*e37e6a0eSAlex Deucher atcs_input.client_id = rdev->pdev->devfn | (rdev->pdev->bus->number << 8); 609*e37e6a0eSAlex Deucher atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK; 610*e37e6a0eSAlex Deucher atcs_input.flags = ATCS_WAIT_FOR_COMPLETION; 611*e37e6a0eSAlex Deucher if (advertise) 612*e37e6a0eSAlex Deucher atcs_input.flags |= ATCS_ADVERTISE_CAPS; 613*e37e6a0eSAlex Deucher atcs_input.req_type = ATCS_PCIE_LINK_SPEED; 614*e37e6a0eSAlex Deucher atcs_input.perf_req = perf_req; 615*e37e6a0eSAlex Deucher 616*e37e6a0eSAlex Deucher params.length = sizeof(struct atcs_pref_req_input); 617*e37e6a0eSAlex Deucher params.pointer = &atcs_input; 618*e37e6a0eSAlex Deucher 619*e37e6a0eSAlex Deucher while (retry--) { 620*e37e6a0eSAlex Deucher info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms); 621*e37e6a0eSAlex Deucher if (!info) 622*e37e6a0eSAlex Deucher return -EIO; 623*e37e6a0eSAlex Deucher 624*e37e6a0eSAlex Deucher memset(&atcs_output, 0, sizeof(atcs_output)); 625*e37e6a0eSAlex Deucher 626*e37e6a0eSAlex Deucher size = *(u16 *) info->buffer.pointer; 627*e37e6a0eSAlex Deucher if (size < 3) { 628*e37e6a0eSAlex Deucher DRM_INFO("ATCS buffer is too small: %zu\n", size); 629*e37e6a0eSAlex Deucher kfree(info); 630*e37e6a0eSAlex Deucher return -EINVAL; 631*e37e6a0eSAlex Deucher } 632*e37e6a0eSAlex Deucher size = min(sizeof(atcs_output), size); 633*e37e6a0eSAlex Deucher 634*e37e6a0eSAlex Deucher memcpy(&atcs_output, info->buffer.pointer, size); 635*e37e6a0eSAlex Deucher 636*e37e6a0eSAlex Deucher kfree(info); 637*e37e6a0eSAlex Deucher 638*e37e6a0eSAlex Deucher switch (atcs_output.ret_val) { 639*e37e6a0eSAlex Deucher case ATCS_REQUEST_REFUSED: 640*e37e6a0eSAlex Deucher default: 641*e37e6a0eSAlex Deucher return -EINVAL; 642*e37e6a0eSAlex Deucher case ATCS_REQUEST_COMPLETE: 643*e37e6a0eSAlex Deucher return 0; 644*e37e6a0eSAlex Deucher case ATCS_REQUEST_IN_PROGRESS: 645*e37e6a0eSAlex Deucher udelay(10); 646*e37e6a0eSAlex Deucher break; 647*e37e6a0eSAlex Deucher } 648*e37e6a0eSAlex Deucher } 649*e37e6a0eSAlex Deucher 650*e37e6a0eSAlex Deucher return 0; 651*e37e6a0eSAlex Deucher } 652*e37e6a0eSAlex Deucher 653*e37e6a0eSAlex Deucher /** 654c3c65160SAlex Deucher * radeon_acpi_event - handle notify events 655c3c65160SAlex Deucher * 656c3c65160SAlex Deucher * @nb: notifier block 657c3c65160SAlex Deucher * @val: val 658c3c65160SAlex Deucher * @data: acpi event 659c3c65160SAlex Deucher * 660c3c65160SAlex Deucher * Calls relevant radeon functions in response to various 661c3c65160SAlex Deucher * acpi events. 662c3c65160SAlex Deucher * Returns NOTIFY code 663c3c65160SAlex Deucher */ 664c4917074SAlex Deucher static int radeon_acpi_event(struct notifier_block *nb, 665c4917074SAlex Deucher unsigned long val, 666c4917074SAlex Deucher void *data) 667c4917074SAlex Deucher { 668c4917074SAlex Deucher struct radeon_device *rdev = container_of(nb, struct radeon_device, acpi_nb); 669c4917074SAlex Deucher struct acpi_bus_event *entry = (struct acpi_bus_event *)data; 670c4917074SAlex Deucher 671c4917074SAlex Deucher if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { 672c4917074SAlex Deucher if (power_supply_is_system_supplied() > 0) 673c4917074SAlex Deucher DRM_DEBUG_DRIVER("pm: AC\n"); 674c4917074SAlex Deucher else 675c4917074SAlex Deucher DRM_DEBUG_DRIVER("pm: DC\n"); 676c4917074SAlex Deucher 677c4917074SAlex Deucher radeon_pm_acpi_event_handler(rdev); 678c4917074SAlex Deucher } 679c4917074SAlex Deucher 680c4917074SAlex Deucher /* Check for pending SBIOS requests */ 681c4917074SAlex Deucher return radeon_atif_handler(rdev, entry); 682d7a2952fSAlberto Milone } 683d7a2952fSAlberto Milone 684d7a2952fSAlberto Milone /* Call all ACPI methods here */ 685c3c65160SAlex Deucher /** 686c3c65160SAlex Deucher * radeon_acpi_init - init driver acpi support 687c3c65160SAlex Deucher * 688c3c65160SAlex Deucher * @rdev: radeon_device pointer 689c3c65160SAlex Deucher * 690c3c65160SAlex Deucher * Verifies the AMD ACPI interfaces and registers with the acpi 691c3c65160SAlex Deucher * notifier chain (all asics). 692c3c65160SAlex Deucher * Returns 0 on success, error on failure. 693c3c65160SAlex Deucher */ 694d7a2952fSAlberto Milone int radeon_acpi_init(struct radeon_device *rdev) 695d7a2952fSAlberto Milone { 696d7a2952fSAlberto Milone acpi_handle handle; 697ce3cf821SLuca Tettamanti struct radeon_atif *atif = &rdev->atif; 698e3a15920SAlex Deucher struct radeon_atcs *atcs = &rdev->atcs; 699d7a2952fSAlberto Milone int ret; 700d7a2952fSAlberto Milone 701d7a2952fSAlberto Milone /* Get the device handle */ 702d7a2952fSAlberto Milone handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); 703d7a2952fSAlberto Milone 70448cc9b2cSJean Delvare /* No need to proceed if we're sure that ATIF is not supported */ 70548cc9b2cSJean Delvare if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) 70648cc9b2cSJean Delvare return 0; 70748cc9b2cSJean Delvare 708e3a15920SAlex Deucher /* Call the ATCS method */ 709e3a15920SAlex Deucher ret = radeon_atcs_verify_interface(handle, atcs); 710e3a15920SAlex Deucher if (ret) { 711e3a15920SAlex Deucher DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); 712d7a2952fSAlberto Milone } 713d7a2952fSAlberto Milone 714d7a2952fSAlberto Milone /* Call the ATIF method */ 715ce3cf821SLuca Tettamanti ret = radeon_atif_verify_interface(handle, atif); 716ce3cf821SLuca Tettamanti if (ret) { 717e3a15920SAlex Deucher DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); 718ce3cf821SLuca Tettamanti goto out; 719ce3cf821SLuca Tettamanti } 720d7a2952fSAlberto Milone 721fda4b25cSLuca Tettamanti if (atif->notifications.brightness_change) { 722fda4b25cSLuca Tettamanti struct drm_encoder *tmp; 723fda4b25cSLuca Tettamanti struct radeon_encoder *target = NULL; 724fda4b25cSLuca Tettamanti 725fda4b25cSLuca Tettamanti /* Find the encoder controlling the brightness */ 726fda4b25cSLuca Tettamanti list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, 727fda4b25cSLuca Tettamanti head) { 728fda4b25cSLuca Tettamanti struct radeon_encoder *enc = to_radeon_encoder(tmp); 729fda4b25cSLuca Tettamanti 730fda4b25cSLuca Tettamanti if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 73137e9b6a6SAlex Deucher enc->enc_priv) { 73237e9b6a6SAlex Deucher if (rdev->is_atom_bios) { 73337e9b6a6SAlex Deucher struct radeon_encoder_atom_dig *dig = enc->enc_priv; 73437e9b6a6SAlex Deucher if (dig->bl_dev) { 73537e9b6a6SAlex Deucher target = enc; 73637e9b6a6SAlex Deucher break; 73737e9b6a6SAlex Deucher } 73837e9b6a6SAlex Deucher } else { 73937e9b6a6SAlex Deucher struct radeon_encoder_lvds *dig = enc->enc_priv; 74037e9b6a6SAlex Deucher if (dig->bl_dev) { 741fda4b25cSLuca Tettamanti target = enc; 742fda4b25cSLuca Tettamanti break; 743fda4b25cSLuca Tettamanti } 744fda4b25cSLuca Tettamanti } 74537e9b6a6SAlex Deucher } 74637e9b6a6SAlex Deucher } 747fda4b25cSLuca Tettamanti 74837e9b6a6SAlex Deucher atif->encoder_for_bl = target; 749fda4b25cSLuca Tettamanti if (!target) { 750fda4b25cSLuca Tettamanti /* Brightness change notification is enabled, but we 751fda4b25cSLuca Tettamanti * didn't find a backlight controller, this should 752fda4b25cSLuca Tettamanti * never happen. 753fda4b25cSLuca Tettamanti */ 754fda4b25cSLuca Tettamanti DRM_ERROR("Cannot find a backlight controller\n"); 755fda4b25cSLuca Tettamanti } 756fda4b25cSLuca Tettamanti } 757fda4b25cSLuca Tettamanti 758ce3cf821SLuca Tettamanti if (atif->functions.sbios_requests && !atif->functions.system_params) { 759ce3cf821SLuca Tettamanti /* XXX check this workraround, if sbios request function is 760ce3cf821SLuca Tettamanti * present we have to see how it's configured in the system 761ce3cf821SLuca Tettamanti * params 762ce3cf821SLuca Tettamanti */ 763ce3cf821SLuca Tettamanti atif->functions.system_params = true; 764ce3cf821SLuca Tettamanti } 765ce3cf821SLuca Tettamanti 766ce3cf821SLuca Tettamanti if (atif->functions.system_params) { 767ce3cf821SLuca Tettamanti ret = radeon_atif_get_notification_params(handle, 768ce3cf821SLuca Tettamanti &atif->notification_cfg); 769ce3cf821SLuca Tettamanti if (ret) { 770ce3cf821SLuca Tettamanti DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", 771ce3cf821SLuca Tettamanti ret); 772ce3cf821SLuca Tettamanti /* Disable notification */ 773ce3cf821SLuca Tettamanti atif->notification_cfg.enabled = false; 774ce3cf821SLuca Tettamanti } 775ce3cf821SLuca Tettamanti } 776ce3cf821SLuca Tettamanti 777ce3cf821SLuca Tettamanti out: 778c4917074SAlex Deucher rdev->acpi_nb.notifier_call = radeon_acpi_event; 779c4917074SAlex Deucher register_acpi_notifier(&rdev->acpi_nb); 780c4917074SAlex Deucher 78186504672SLuca Tettamanti return ret; 782d7a2952fSAlberto Milone } 783d7a2952fSAlberto Milone 784c3c65160SAlex Deucher /** 785c3c65160SAlex Deucher * radeon_acpi_fini - tear down driver acpi support 786c3c65160SAlex Deucher * 787c3c65160SAlex Deucher * @rdev: radeon_device pointer 788c3c65160SAlex Deucher * 789c3c65160SAlex Deucher * Unregisters with the acpi notifier chain (all asics). 790c3c65160SAlex Deucher */ 791c4917074SAlex Deucher void radeon_acpi_fini(struct radeon_device *rdev) 792c4917074SAlex Deucher { 793c4917074SAlex Deucher unregister_acpi_notifier(&rdev->acpi_nb); 794c4917074SAlex Deucher } 795