1254885Sdumbbell/* 2254885Sdumbbell * Copyright 2012 Advanced Micro Devices, Inc. 3254885Sdumbbell * 4254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a 5254885Sdumbbell * copy of this software and associated documentation files (the "Software"), 6254885Sdumbbell * to deal in the Software without restriction, including without limitation 7254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the 9254885Sdumbbell * Software is furnished to do so, subject to the following conditions: 10254885Sdumbbell * 11254885Sdumbbell * The above copyright notice and this permission notice shall be included in 12254885Sdumbbell * all copies or substantial portions of the Software. 13254885Sdumbbell * 14254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE. 21254885Sdumbbell * 22254885Sdumbbell */ 23254885Sdumbbell 24254885Sdumbbell#include <sys/cdefs.h> 25254885Sdumbbell__FBSDID("$FreeBSD: releng/10.2/sys/dev/drm2/radeon/radeon_acpi.c 282199 2015-04-28 19:35:05Z dumbbell $"); 26254885Sdumbbell 27254885Sdumbbell#include <dev/drm2/drmP.h> 28254885Sdumbbell#include <dev/drm2/drm_crtc_helper.h> 29254885Sdumbbell#include "radeon.h" 30254885Sdumbbell#include "radeon_acpi.h" 31254885Sdumbbell#include "atom.h" 32254885Sdumbbell 33254885Sdumbbell#define ACPI_AC_CLASS "ac_adapter" 34254885Sdumbbell 35282199Sdumbbellextern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); 36282199Sdumbbell 37254885Sdumbbellstruct atif_verify_interface { 38254885Sdumbbell u16 size; /* structure size in bytes (includes size field) */ 39254885Sdumbbell u16 version; /* version */ 40254885Sdumbbell u32 notification_mask; /* supported notifications mask */ 41254885Sdumbbell u32 function_bits; /* supported functions bit vector */ 42254885Sdumbbell} __packed; 43254885Sdumbbell 44254885Sdumbbellstruct atif_system_params { 45254885Sdumbbell u16 size; /* structure size in bytes (includes size field) */ 46254885Sdumbbell u32 valid_mask; /* valid flags mask */ 47254885Sdumbbell u32 flags; /* flags */ 48254885Sdumbbell u8 command_code; /* notify command code */ 49254885Sdumbbell} __packed; 50254885Sdumbbell 51254885Sdumbbellstruct atif_sbios_requests { 52254885Sdumbbell u16 size; /* structure size in bytes (includes size field) */ 53254885Sdumbbell u32 pending; /* pending sbios requests */ 54254885Sdumbbell u8 panel_exp_mode; /* panel expansion mode */ 55254885Sdumbbell u8 thermal_gfx; /* thermal state: target gfx controller */ 56254885Sdumbbell u8 thermal_state; /* thermal state: state id (0: exit state, non-0: state) */ 57254885Sdumbbell u8 forced_power_gfx; /* forced power state: target gfx controller */ 58254885Sdumbbell u8 forced_power_state; /* forced power state: state id */ 59254885Sdumbbell u8 system_power_src; /* system power source */ 60254885Sdumbbell u8 backlight_level; /* panel backlight level (0-255) */ 61254885Sdumbbell} __packed; 62254885Sdumbbell 63254885Sdumbbell#define ATIF_NOTIFY_MASK 0x3 64254885Sdumbbell#define ATIF_NOTIFY_NONE 0 65254885Sdumbbell#define ATIF_NOTIFY_81 1 66254885Sdumbbell#define ATIF_NOTIFY_N 2 67254885Sdumbbell 68254885Sdumbbellstruct atcs_verify_interface { 69254885Sdumbbell u16 size; /* structure size in bytes (includes size field) */ 70254885Sdumbbell u16 version; /* version */ 71254885Sdumbbell u32 function_bits; /* supported functions bit vector */ 72254885Sdumbbell} __packed; 73254885Sdumbbell 74254885Sdumbbell/* Call the ATIF method 75254885Sdumbbell */ 76254885Sdumbbell/** 77254885Sdumbbell * radeon_atif_call - call an ATIF method 78254885Sdumbbell * 79254885Sdumbbell * @handle: acpi handle 80254885Sdumbbell * @function: the ATIF function to execute 81254885Sdumbbell * @params: ATIF function params 82254885Sdumbbell * 83254885Sdumbbell * Executes the requested ATIF function (all asics). 84254885Sdumbbell * Returns a pointer to the acpi output buffer. 85254885Sdumbbell */ 86254885Sdumbbellstatic ACPI_OBJECT *radeon_atif_call(ACPI_HANDLE handle, int function, 87254885Sdumbbell ACPI_BUFFER *params) 88254885Sdumbbell{ 89254885Sdumbbell ACPI_STATUS status; 90254885Sdumbbell ACPI_OBJECT atif_arg_elements[2]; 91254885Sdumbbell ACPI_OBJECT_LIST atif_arg; 92254885Sdumbbell ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 93254885Sdumbbell 94254885Sdumbbell atif_arg.Count = 2; 95254885Sdumbbell atif_arg.Pointer = &atif_arg_elements[0]; 96254885Sdumbbell 97254885Sdumbbell atif_arg_elements[0].Type = ACPI_TYPE_INTEGER; 98254885Sdumbbell atif_arg_elements[0].Integer.Value = function; 99254885Sdumbbell 100254885Sdumbbell if (params) { 101254885Sdumbbell atif_arg_elements[1].Type = ACPI_TYPE_BUFFER; 102254885Sdumbbell atif_arg_elements[1].Buffer.Length = params->Length; 103254885Sdumbbell atif_arg_elements[1].Buffer.Pointer = params->Pointer; 104254885Sdumbbell } else { 105254885Sdumbbell /* We need a second fake parameter */ 106254885Sdumbbell atif_arg_elements[1].Type = ACPI_TYPE_INTEGER; 107254885Sdumbbell atif_arg_elements[1].Integer.Value = 0; 108254885Sdumbbell } 109254885Sdumbbell 110254885Sdumbbell status = AcpiEvaluateObject(handle, "ATIF", &atif_arg, &buffer); 111254885Sdumbbell 112254885Sdumbbell /* Fail only if calling the method fails and ATIF is supported */ 113254885Sdumbbell if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 114254885Sdumbbell DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", 115254885Sdumbbell AcpiFormatException(status)); 116254885Sdumbbell AcpiOsFree(buffer.Pointer); 117254885Sdumbbell return NULL; 118254885Sdumbbell } 119254885Sdumbbell 120254885Sdumbbell return buffer.Pointer; 121254885Sdumbbell} 122254885Sdumbbell 123254885Sdumbbell/** 124254885Sdumbbell * radeon_atif_parse_notification - parse supported notifications 125254885Sdumbbell * 126254885Sdumbbell * @n: supported notifications struct 127254885Sdumbbell * @mask: supported notifications mask from ATIF 128254885Sdumbbell * 129254885Sdumbbell * Use the supported notifications mask from ATIF function 130254885Sdumbbell * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications 131254885Sdumbbell * are supported (all asics). 132254885Sdumbbell */ 133254885Sdumbbellstatic void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask) 134254885Sdumbbell{ 135254885Sdumbbell n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED; 136254885Sdumbbell n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED; 137254885Sdumbbell n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; 138254885Sdumbbell n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; 139254885Sdumbbell n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; 140254885Sdumbbell n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED; 141254885Sdumbbell n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED; 142254885Sdumbbell n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; 143254885Sdumbbell n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; 144254885Sdumbbell} 145254885Sdumbbell 146254885Sdumbbell/** 147254885Sdumbbell * radeon_atif_parse_functions - parse supported functions 148254885Sdumbbell * 149254885Sdumbbell * @f: supported functions struct 150254885Sdumbbell * @mask: supported functions mask from ATIF 151254885Sdumbbell * 152254885Sdumbbell * Use the supported functions mask from ATIF function 153254885Sdumbbell * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions 154254885Sdumbbell * are supported (all asics). 155254885Sdumbbell */ 156254885Sdumbbellstatic void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask) 157254885Sdumbbell{ 158254885Sdumbbell f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; 159254885Sdumbbell f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; 160254885Sdumbbell f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED; 161254885Sdumbbell f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED; 162254885Sdumbbell f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED; 163254885Sdumbbell f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED; 164254885Sdumbbell f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED; 165254885Sdumbbell f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED; 166254885Sdumbbell f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; 167254885Sdumbbell f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED; 168254885Sdumbbell} 169254885Sdumbbell 170254885Sdumbbell/** 171254885Sdumbbell * radeon_atif_verify_interface - verify ATIF 172254885Sdumbbell * 173254885Sdumbbell * @handle: acpi handle 174254885Sdumbbell * @atif: radeon atif struct 175254885Sdumbbell * 176254885Sdumbbell * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function 177254885Sdumbbell * to initialize ATIF and determine what features are supported 178254885Sdumbbell * (all asics). 179254885Sdumbbell * returns 0 on success, error on failure. 180254885Sdumbbell */ 181254885Sdumbbellstatic int radeon_atif_verify_interface(ACPI_HANDLE handle, 182254885Sdumbbell struct radeon_atif *atif) 183254885Sdumbbell{ 184254885Sdumbbell ACPI_OBJECT *info; 185254885Sdumbbell struct atif_verify_interface output; 186254885Sdumbbell size_t size; 187254885Sdumbbell int err = 0; 188254885Sdumbbell 189254885Sdumbbell info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); 190254885Sdumbbell if (!info) 191254885Sdumbbell return -EIO; 192254885Sdumbbell 193254885Sdumbbell memset(&output, 0, sizeof(output)); 194254885Sdumbbell 195254885Sdumbbell size = *(u16 *) info->Buffer.Pointer; 196254885Sdumbbell if (size < 12) { 197254885Sdumbbell DRM_INFO("ATIF buffer is too small: %zu\n", size); 198254885Sdumbbell err = -EINVAL; 199254885Sdumbbell goto out; 200254885Sdumbbell } 201254885Sdumbbell size = min(sizeof(output), size); 202254885Sdumbbell 203254885Sdumbbell memcpy(&output, info->Buffer.Pointer, size); 204254885Sdumbbell 205254885Sdumbbell /* TODO: check version? */ 206254885Sdumbbell DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); 207254885Sdumbbell 208254885Sdumbbell radeon_atif_parse_notification(&atif->notifications, output.notification_mask); 209254885Sdumbbell radeon_atif_parse_functions(&atif->functions, output.function_bits); 210254885Sdumbbell 211254885Sdumbbellout: 212254885Sdumbbell AcpiOsFree(info); 213254885Sdumbbell return err; 214254885Sdumbbell} 215254885Sdumbbell 216254885Sdumbbell/** 217254885Sdumbbell * radeon_atif_get_notification_params - determine notify configuration 218254885Sdumbbell * 219254885Sdumbbell * @handle: acpi handle 220254885Sdumbbell * @n: atif notification configuration struct 221254885Sdumbbell * 222254885Sdumbbell * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function 223254885Sdumbbell * to determine if a notifier is used and if so which one 224254885Sdumbbell * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) 225254885Sdumbbell * where n is specified in the result if a notifier is used. 226254885Sdumbbell * Returns 0 on success, error on failure. 227254885Sdumbbell */ 228254885Sdumbbellstatic int radeon_atif_get_notification_params(ACPI_HANDLE handle, 229254885Sdumbbell struct radeon_atif_notification_cfg *n) 230254885Sdumbbell{ 231254885Sdumbbell ACPI_OBJECT *info; 232254885Sdumbbell struct atif_system_params params; 233254885Sdumbbell size_t size; 234254885Sdumbbell int err = 0; 235254885Sdumbbell 236254885Sdumbbell info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL); 237254885Sdumbbell if (!info) { 238254885Sdumbbell err = -EIO; 239254885Sdumbbell goto out; 240254885Sdumbbell } 241254885Sdumbbell 242254885Sdumbbell size = *(u16 *) info->Buffer.Pointer; 243254885Sdumbbell if (size < 10) { 244254885Sdumbbell err = -EINVAL; 245254885Sdumbbell goto out; 246254885Sdumbbell } 247254885Sdumbbell 248254885Sdumbbell memset(¶ms, 0, sizeof(params)); 249254885Sdumbbell size = min(sizeof(params), size); 250254885Sdumbbell memcpy(¶ms, info->Buffer.Pointer, size); 251254885Sdumbbell 252254885Sdumbbell DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", 253254885Sdumbbell params.flags, params.valid_mask); 254254885Sdumbbell params.flags = params.flags & params.valid_mask; 255254885Sdumbbell 256254885Sdumbbell if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { 257254885Sdumbbell n->enabled = false; 258254885Sdumbbell n->command_code = 0; 259254885Sdumbbell } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { 260254885Sdumbbell n->enabled = true; 261254885Sdumbbell n->command_code = 0x81; 262254885Sdumbbell } else { 263254885Sdumbbell if (size < 11) { 264254885Sdumbbell err = -EINVAL; 265254885Sdumbbell goto out; 266254885Sdumbbell } 267254885Sdumbbell n->enabled = true; 268254885Sdumbbell n->command_code = params.command_code; 269254885Sdumbbell } 270254885Sdumbbell 271254885Sdumbbellout: 272254885Sdumbbell DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", 273254885Sdumbbell (n->enabled ? "enabled" : "disabled"), 274254885Sdumbbell n->command_code); 275254885Sdumbbell AcpiOsFree(info); 276254885Sdumbbell return err; 277254885Sdumbbell} 278254885Sdumbbell 279254885Sdumbbell/** 280254885Sdumbbell * radeon_atif_get_sbios_requests - get requested sbios event 281254885Sdumbbell * 282254885Sdumbbell * @handle: acpi handle 283254885Sdumbbell * @req: atif sbios request struct 284254885Sdumbbell * 285254885Sdumbbell * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function 286254885Sdumbbell * to determine what requests the sbios is making to the driver 287254885Sdumbbell * (all asics). 288254885Sdumbbell * Returns 0 on success, error on failure. 289254885Sdumbbell */ 290254885Sdumbbellstatic int radeon_atif_get_sbios_requests(ACPI_HANDLE handle, 291254885Sdumbbell struct atif_sbios_requests *req) 292254885Sdumbbell{ 293254885Sdumbbell ACPI_OBJECT *info; 294254885Sdumbbell size_t size; 295254885Sdumbbell int count = 0; 296254885Sdumbbell 297254885Sdumbbell info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, NULL); 298254885Sdumbbell if (!info) 299254885Sdumbbell return -EIO; 300254885Sdumbbell 301254885Sdumbbell size = *(u16 *)info->Buffer.Pointer; 302254885Sdumbbell if (size < 0xd) { 303254885Sdumbbell count = -EINVAL; 304254885Sdumbbell goto out; 305254885Sdumbbell } 306254885Sdumbbell memset(req, 0, sizeof(*req)); 307254885Sdumbbell 308254885Sdumbbell size = min(sizeof(*req), size); 309254885Sdumbbell memcpy(req, info->Buffer.Pointer, size); 310254885Sdumbbell DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); 311254885Sdumbbell 312254885Sdumbbell count = hweight32(req->pending); 313254885Sdumbbell 314254885Sdumbbellout: 315254885Sdumbbell AcpiOsFree(info); 316254885Sdumbbell return count; 317254885Sdumbbell} 318254885Sdumbbell 319254885Sdumbbell/** 320254885Sdumbbell * radeon_atif_handler - handle ATIF notify requests 321254885Sdumbbell * 322254885Sdumbbell * @rdev: radeon_device pointer 323254885Sdumbbell * @event: atif sbios request struct 324254885Sdumbbell * 325254885Sdumbbell * Checks the acpi event and if it matches an atif event, 326254885Sdumbbell * handles it. 327254885Sdumbbell * Returns NOTIFY code 328254885Sdumbbell */ 329254885Sdumbbellvoid radeon_atif_handler(struct radeon_device *rdev, 330254885Sdumbbell UINT32 type) 331254885Sdumbbell{ 332254885Sdumbbell struct radeon_atif *atif = &rdev->atif; 333254885Sdumbbell struct atif_sbios_requests req; 334254885Sdumbbell ACPI_HANDLE handle; 335254885Sdumbbell int count; 336254885Sdumbbell 337254885Sdumbbell DRM_DEBUG_DRIVER("event, type = %#x\n", 338254885Sdumbbell type); 339254885Sdumbbell 340254885Sdumbbell if (!atif->notification_cfg.enabled || 341254885Sdumbbell type != atif->notification_cfg.command_code) 342254885Sdumbbell /* Not our event */ 343254885Sdumbbell return; 344254885Sdumbbell 345254885Sdumbbell /* Check pending SBIOS requests */ 346254885Sdumbbell handle = rdev->acpi.handle; 347254885Sdumbbell count = radeon_atif_get_sbios_requests(handle, &req); 348254885Sdumbbell 349254885Sdumbbell if (count <= 0) 350254885Sdumbbell return; 351254885Sdumbbell 352254885Sdumbbell DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); 353254885Sdumbbell 354254885Sdumbbell if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { 355254885Sdumbbell struct radeon_encoder *enc = atif->encoder_for_bl; 356254885Sdumbbell 357254885Sdumbbell if (enc) { 358254885Sdumbbell DRM_DEBUG_DRIVER("Changing brightness to %d\n", 359254885Sdumbbell req.backlight_level); 360254885Sdumbbell 361254885Sdumbbell radeon_set_backlight_level(rdev, enc, req.backlight_level); 362254885Sdumbbell 363282199Sdumbbell#ifdef FREEBSD_WIP 364254885Sdumbbell if (rdev->is_atom_bios) { 365254885Sdumbbell struct radeon_encoder_atom_dig *dig = enc->enc_priv; 366254885Sdumbbell backlight_force_update(dig->bl_dev, 367254885Sdumbbell BACKLIGHT_UPDATE_HOTKEY); 368254885Sdumbbell } else { 369254885Sdumbbell struct radeon_encoder_lvds *dig = enc->enc_priv; 370254885Sdumbbell backlight_force_update(dig->bl_dev, 371254885Sdumbbell BACKLIGHT_UPDATE_HOTKEY); 372254885Sdumbbell } 373282199Sdumbbell#endif /* FREEBSD_WIP */ 374254885Sdumbbell } 375254885Sdumbbell } 376254885Sdumbbell /* TODO: check other events */ 377254885Sdumbbell 378254885Sdumbbell /* We've handled the event, stop the notifier chain. The ACPI interface 379254885Sdumbbell * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to 380254885Sdumbbell * userspace if the event was generated only to signal a SBIOS 381254885Sdumbbell * request. 382254885Sdumbbell */ 383254885Sdumbbell} 384254885Sdumbbell 385254885Sdumbbell/* Call the ATCS method 386254885Sdumbbell */ 387254885Sdumbbell/** 388254885Sdumbbell * radeon_atcs_call - call an ATCS method 389254885Sdumbbell * 390254885Sdumbbell * @handle: acpi handle 391254885Sdumbbell * @function: the ATCS function to execute 392254885Sdumbbell * @params: ATCS function params 393254885Sdumbbell * 394254885Sdumbbell * Executes the requested ATCS function (all asics). 395254885Sdumbbell * Returns a pointer to the acpi output buffer. 396254885Sdumbbell */ 397254885Sdumbbellstatic union acpi_object *radeon_atcs_call(ACPI_HANDLE handle, int function, 398254885Sdumbbell ACPI_BUFFER *params) 399254885Sdumbbell{ 400254885Sdumbbell ACPI_STATUS status; 401254885Sdumbbell ACPI_OBJECT atcs_arg_elements[2]; 402254885Sdumbbell ACPI_OBJECT_LIST atcs_arg; 403254885Sdumbbell ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 404254885Sdumbbell 405254885Sdumbbell atcs_arg.Count = 2; 406254885Sdumbbell atcs_arg.Pointer = &atcs_arg_elements[0]; 407254885Sdumbbell 408254885Sdumbbell atcs_arg_elements[0].Type = ACPI_TYPE_INTEGER; 409254885Sdumbbell atcs_arg_elements[0].Integer.Value = function; 410254885Sdumbbell 411254885Sdumbbell if (params) { 412254885Sdumbbell atcs_arg_elements[1].Type = ACPI_TYPE_BUFFER; 413254885Sdumbbell atcs_arg_elements[1].Buffer.Length = params->Length; 414254885Sdumbbell atcs_arg_elements[1].Buffer.Pointer = params->Pointer; 415254885Sdumbbell } else { 416254885Sdumbbell /* We need a second fake parameter */ 417254885Sdumbbell atcs_arg_elements[1].Type = ACPI_TYPE_INTEGER; 418254885Sdumbbell atcs_arg_elements[1].Integer.Value = 0; 419254885Sdumbbell } 420254885Sdumbbell 421254885Sdumbbell status = AcpiEvaluateObject(handle, "ATCS", &atcs_arg, &buffer); 422254885Sdumbbell 423254885Sdumbbell /* Fail only if calling the method fails and ATIF is supported */ 424254885Sdumbbell if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 425254885Sdumbbell DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n", 426254885Sdumbbell AcpiFormatException(status)); 427254885Sdumbbell AcpiOsFree(buffer.Pointer); 428254885Sdumbbell return NULL; 429254885Sdumbbell } 430254885Sdumbbell 431254885Sdumbbell return buffer.Pointer; 432254885Sdumbbell} 433254885Sdumbbell 434254885Sdumbbell/** 435254885Sdumbbell * radeon_atcs_parse_functions - parse supported functions 436254885Sdumbbell * 437254885Sdumbbell * @f: supported functions struct 438254885Sdumbbell * @mask: supported functions mask from ATCS 439254885Sdumbbell * 440254885Sdumbbell * Use the supported functions mask from ATCS function 441254885Sdumbbell * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions 442254885Sdumbbell * are supported (all asics). 443254885Sdumbbell */ 444254885Sdumbbellstatic void radeon_atcs_parse_functions(struct radeon_atcs_functions *f, u32 mask) 445254885Sdumbbell{ 446254885Sdumbbell f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; 447254885Sdumbbell f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; 448254885Sdumbbell f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; 449254885Sdumbbell f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; 450254885Sdumbbell} 451254885Sdumbbell 452254885Sdumbbell/** 453254885Sdumbbell * radeon_atcs_verify_interface - verify ATCS 454254885Sdumbbell * 455254885Sdumbbell * @handle: acpi handle 456254885Sdumbbell * @atcs: radeon atcs struct 457254885Sdumbbell * 458254885Sdumbbell * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function 459254885Sdumbbell * to initialize ATCS and determine what features are supported 460254885Sdumbbell * (all asics). 461254885Sdumbbell * returns 0 on success, error on failure. 462254885Sdumbbell */ 463254885Sdumbbellstatic int radeon_atcs_verify_interface(ACPI_HANDLE handle, 464254885Sdumbbell struct radeon_atcs *atcs) 465254885Sdumbbell{ 466254885Sdumbbell ACPI_OBJECT *info; 467254885Sdumbbell struct atcs_verify_interface output; 468254885Sdumbbell size_t size; 469254885Sdumbbell int err = 0; 470254885Sdumbbell 471254885Sdumbbell info = radeon_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); 472254885Sdumbbell if (!info) 473254885Sdumbbell return -EIO; 474254885Sdumbbell 475254885Sdumbbell memset(&output, 0, sizeof(output)); 476254885Sdumbbell 477254885Sdumbbell size = *(u16 *) info->Buffer.Pointer; 478254885Sdumbbell if (size < 8) { 479254885Sdumbbell DRM_INFO("ATCS buffer is too small: %zu\n", size); 480254885Sdumbbell err = -EINVAL; 481254885Sdumbbell goto out; 482254885Sdumbbell } 483254885Sdumbbell size = min(sizeof(output), size); 484254885Sdumbbell 485254885Sdumbbell memcpy(&output, info->Buffer.Pointer, size); 486254885Sdumbbell 487254885Sdumbbell /* TODO: check version? */ 488254885Sdumbbell DRM_DEBUG_DRIVER("ATCS version %u\n", output.version); 489254885Sdumbbell 490254885Sdumbbell radeon_atcs_parse_functions(&atcs->functions, output.function_bits); 491254885Sdumbbell 492254885Sdumbbellout: 493254885Sdumbbell AcpiOsFree(info); 494254885Sdumbbell return err; 495254885Sdumbbell} 496254885Sdumbbell 497254885Sdumbbell/** 498254885Sdumbbell * radeon_acpi_event - handle notify events 499254885Sdumbbell * 500254885Sdumbbell * @nb: notifier block 501254885Sdumbbell * @val: val 502254885Sdumbbell * @data: acpi event 503254885Sdumbbell * 504254885Sdumbbell * Calls relevant radeon functions in response to various 505254885Sdumbbell * acpi events. 506254885Sdumbbell * Returns NOTIFY code 507254885Sdumbbell */ 508254885Sdumbbellstatic void radeon_acpi_event(ACPI_HANDLE handle, UINT32 type, 509254885Sdumbbell void *context) 510254885Sdumbbell{ 511254885Sdumbbell struct radeon_device *rdev = (struct radeon_device *)context; 512254885Sdumbbell 513282199Sdumbbell#ifdef FREEBSD_WIP 514254885Sdumbbell if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { 515254885Sdumbbell if (power_supply_is_system_supplied() > 0) 516254885Sdumbbell DRM_DEBUG_DRIVER("pm: AC\n"); 517254885Sdumbbell else 518254885Sdumbbell DRM_DEBUG_DRIVER("pm: DC\n"); 519254885Sdumbbell 520254885Sdumbbell radeon_pm_acpi_event_handler(rdev); 521254885Sdumbbell } 522282199Sdumbbell#endif /* FREEBSD_WIP */ 523254885Sdumbbell 524254885Sdumbbell /* Check for pending SBIOS requests */ 525254885Sdumbbell radeon_atif_handler(rdev, type); 526254885Sdumbbell} 527254885Sdumbbell 528254885Sdumbbell/* Call all ACPI methods here */ 529254885Sdumbbell/** 530254885Sdumbbell * radeon_acpi_init - init driver acpi support 531254885Sdumbbell * 532254885Sdumbbell * @rdev: radeon_device pointer 533254885Sdumbbell * 534254885Sdumbbell * Verifies the AMD ACPI interfaces and registers with the acpi 535254885Sdumbbell * notifier chain (all asics). 536254885Sdumbbell * Returns 0 on success, error on failure. 537254885Sdumbbell */ 538254885Sdumbbellint radeon_acpi_init(struct radeon_device *rdev) 539254885Sdumbbell{ 540254885Sdumbbell ACPI_HANDLE handle; 541254885Sdumbbell struct radeon_atif *atif = &rdev->atif; 542254885Sdumbbell struct radeon_atcs *atcs = &rdev->atcs; 543254885Sdumbbell int ret; 544254885Sdumbbell 545254885Sdumbbell /* Get the device handle */ 546254885Sdumbbell handle = acpi_get_handle(rdev->dev); 547254885Sdumbbell 548254885Sdumbbell /* No need to proceed if we're sure that ATIF is not supported */ 549254885Sdumbbell if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) 550254885Sdumbbell return 0; 551254885Sdumbbell 552254885Sdumbbell /* Call the ATCS method */ 553254885Sdumbbell ret = radeon_atcs_verify_interface(handle, atcs); 554254885Sdumbbell if (ret) { 555254885Sdumbbell DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); 556254885Sdumbbell } 557254885Sdumbbell 558254885Sdumbbell /* Call the ATIF method */ 559254885Sdumbbell ret = radeon_atif_verify_interface(handle, atif); 560254885Sdumbbell if (ret) { 561254885Sdumbbell DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); 562254885Sdumbbell goto out; 563254885Sdumbbell } 564254885Sdumbbell 565254885Sdumbbell if (atif->notifications.brightness_change) { 566254885Sdumbbell struct drm_encoder *tmp; 567254885Sdumbbell struct radeon_encoder *target = NULL; 568254885Sdumbbell 569254885Sdumbbell /* Find the encoder controlling the brightness */ 570254885Sdumbbell list_for_each_entry(tmp, &rdev->ddev->mode_config.encoder_list, 571254885Sdumbbell head) { 572254885Sdumbbell struct radeon_encoder *enc = to_radeon_encoder(tmp); 573254885Sdumbbell 574254885Sdumbbell if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 575254885Sdumbbell enc->enc_priv) { 576254885Sdumbbell if (rdev->is_atom_bios) { 577254885Sdumbbell struct radeon_encoder_atom_dig *dig = enc->enc_priv; 578254885Sdumbbell if (dig->bl_dev) { 579254885Sdumbbell target = enc; 580254885Sdumbbell break; 581254885Sdumbbell } 582254885Sdumbbell } else { 583254885Sdumbbell struct radeon_encoder_lvds *dig = enc->enc_priv; 584254885Sdumbbell if (dig->bl_dev) { 585254885Sdumbbell target = enc; 586254885Sdumbbell break; 587254885Sdumbbell } 588254885Sdumbbell } 589254885Sdumbbell } 590254885Sdumbbell } 591254885Sdumbbell 592254885Sdumbbell atif->encoder_for_bl = target; 593254885Sdumbbell if (!target) { 594254885Sdumbbell /* Brightness change notification is enabled, but we 595254885Sdumbbell * didn't find a backlight controller, this should 596254885Sdumbbell * never happen. 597254885Sdumbbell */ 598254885Sdumbbell DRM_ERROR("Cannot find a backlight controller\n"); 599254885Sdumbbell } 600254885Sdumbbell } 601254885Sdumbbell 602254885Sdumbbell if (atif->functions.sbios_requests && !atif->functions.system_params) { 603254885Sdumbbell /* XXX check this workraround, if sbios request function is 604254885Sdumbbell * present we have to see how it's configured in the system 605254885Sdumbbell * params 606254885Sdumbbell */ 607254885Sdumbbell atif->functions.system_params = true; 608254885Sdumbbell } 609254885Sdumbbell 610254885Sdumbbell if (atif->functions.system_params) { 611254885Sdumbbell ret = radeon_atif_get_notification_params(handle, 612254885Sdumbbell &atif->notification_cfg); 613254885Sdumbbell if (ret) { 614254885Sdumbbell DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", 615254885Sdumbbell ret); 616254885Sdumbbell /* Disable notification */ 617254885Sdumbbell atif->notification_cfg.enabled = false; 618254885Sdumbbell } 619254885Sdumbbell } 620254885Sdumbbell 621254885Sdumbbellout: 622254885Sdumbbell rdev->acpi.handle = handle; 623254885Sdumbbell rdev->acpi.notifier_call = radeon_acpi_event; 624254885Sdumbbell AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, 625254885Sdumbbell rdev->acpi.notifier_call, rdev); 626254885Sdumbbell 627254885Sdumbbell return ret; 628254885Sdumbbell} 629254885Sdumbbell 630254885Sdumbbell/** 631254885Sdumbbell * radeon_acpi_fini - tear down driver acpi support 632254885Sdumbbell * 633254885Sdumbbell * @rdev: radeon_device pointer 634254885Sdumbbell * 635254885Sdumbbell * Unregisters with the acpi notifier chain (all asics). 636254885Sdumbbell */ 637254885Sdumbbellvoid radeon_acpi_fini(struct radeon_device *rdev) 638254885Sdumbbell{ 639254885Sdumbbell AcpiRemoveNotifyHandler(rdev->acpi.handle, ACPI_DEVICE_NOTIFY, 640254885Sdumbbell rdev->acpi.notifier_call); 641254885Sdumbbell} 642