18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2012 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/pci.h> 258c2ecf20Sopenharmony_ci#include <linux/acpi.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 298c2ecf20Sopenharmony_ci#include <acpi/video.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h> 328c2ecf20Sopenharmony_ci#include "amdgpu.h" 338c2ecf20Sopenharmony_ci#include "amdgpu_pm.h" 348c2ecf20Sopenharmony_ci#include "amdgpu_display.h" 358c2ecf20Sopenharmony_ci#include "amd_acpi.h" 368c2ecf20Sopenharmony_ci#include "atom.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct amdgpu_atif_notification_cfg { 398c2ecf20Sopenharmony_ci bool enabled; 408c2ecf20Sopenharmony_ci int command_code; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct amdgpu_atif_notifications { 448c2ecf20Sopenharmony_ci bool thermal_state; 458c2ecf20Sopenharmony_ci bool forced_power_state; 468c2ecf20Sopenharmony_ci bool system_power_state; 478c2ecf20Sopenharmony_ci bool brightness_change; 488c2ecf20Sopenharmony_ci bool dgpu_display_event; 498c2ecf20Sopenharmony_ci bool gpu_package_power_limit; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct amdgpu_atif_functions { 538c2ecf20Sopenharmony_ci bool system_params; 548c2ecf20Sopenharmony_ci bool sbios_requests; 558c2ecf20Sopenharmony_ci bool temperature_change; 568c2ecf20Sopenharmony_ci bool query_backlight_transfer_characteristics; 578c2ecf20Sopenharmony_ci bool ready_to_undock; 588c2ecf20Sopenharmony_ci bool external_gpu_information; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct amdgpu_atif { 628c2ecf20Sopenharmony_ci acpi_handle handle; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci struct amdgpu_atif_notifications notifications; 658c2ecf20Sopenharmony_ci struct amdgpu_atif_functions functions; 668c2ecf20Sopenharmony_ci struct amdgpu_atif_notification_cfg notification_cfg; 678c2ecf20Sopenharmony_ci#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 688c2ecf20Sopenharmony_ci struct backlight_device *bd; 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci struct amdgpu_dm_backlight_caps backlight_caps; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Call the ATIF method 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci/** 768c2ecf20Sopenharmony_ci * amdgpu_atif_call - call an ATIF method 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * @handle: acpi handle 798c2ecf20Sopenharmony_ci * @function: the ATIF function to execute 808c2ecf20Sopenharmony_ci * @params: ATIF function params 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * Executes the requested ATIF function (all asics). 838c2ecf20Sopenharmony_ci * Returns a pointer to the acpi output buffer. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, 868c2ecf20Sopenharmony_ci int function, 878c2ecf20Sopenharmony_ci struct acpi_buffer *params) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci acpi_status status; 908c2ecf20Sopenharmony_ci union acpi_object atif_arg_elements[2]; 918c2ecf20Sopenharmony_ci struct acpi_object_list atif_arg; 928c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci atif_arg.count = 2; 958c2ecf20Sopenharmony_ci atif_arg.pointer = &atif_arg_elements[0]; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci atif_arg_elements[0].type = ACPI_TYPE_INTEGER; 988c2ecf20Sopenharmony_ci atif_arg_elements[0].integer.value = function; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (params) { 1018c2ecf20Sopenharmony_ci atif_arg_elements[1].type = ACPI_TYPE_BUFFER; 1028c2ecf20Sopenharmony_ci atif_arg_elements[1].buffer.length = params->length; 1038c2ecf20Sopenharmony_ci atif_arg_elements[1].buffer.pointer = params->pointer; 1048c2ecf20Sopenharmony_ci } else { 1058c2ecf20Sopenharmony_ci /* We need a second fake parameter */ 1068c2ecf20Sopenharmony_ci atif_arg_elements[1].type = ACPI_TYPE_INTEGER; 1078c2ecf20Sopenharmony_ci atif_arg_elements[1].integer.value = 0; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci status = acpi_evaluate_object(atif->handle, NULL, &atif_arg, 1118c2ecf20Sopenharmony_ci &buffer); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* Fail only if calling the method fails and ATIF is supported */ 1148c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 1158c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", 1168c2ecf20Sopenharmony_ci acpi_format_exception(status)); 1178c2ecf20Sopenharmony_ci kfree(buffer.pointer); 1188c2ecf20Sopenharmony_ci return NULL; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return buffer.pointer; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * amdgpu_atif_parse_notification - parse supported notifications 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * @n: supported notifications struct 1288c2ecf20Sopenharmony_ci * @mask: supported notifications mask from ATIF 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Use the supported notifications mask from ATIF function 1318c2ecf20Sopenharmony_ci * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications 1328c2ecf20Sopenharmony_ci * are supported (all asics). 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic void amdgpu_atif_parse_notification(struct amdgpu_atif_notifications *n, u32 mask) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; 1378c2ecf20Sopenharmony_ci n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; 1388c2ecf20Sopenharmony_ci n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; 1398c2ecf20Sopenharmony_ci n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; 1408c2ecf20Sopenharmony_ci n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; 1418c2ecf20Sopenharmony_ci n->gpu_package_power_limit = mask & ATIF_GPU_PACKAGE_POWER_LIMIT_REQUEST_SUPPORTED; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * amdgpu_atif_parse_functions - parse supported functions 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * @f: supported functions struct 1488c2ecf20Sopenharmony_ci * @mask: supported functions mask from ATIF 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Use the supported functions mask from ATIF function 1518c2ecf20Sopenharmony_ci * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions 1528c2ecf20Sopenharmony_ci * are supported (all asics). 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_cistatic void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mask) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; 1578c2ecf20Sopenharmony_ci f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; 1588c2ecf20Sopenharmony_ci f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; 1598c2ecf20Sopenharmony_ci f->query_backlight_transfer_characteristics = 1608c2ecf20Sopenharmony_ci mask & ATIF_QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS_SUPPORTED; 1618c2ecf20Sopenharmony_ci f->ready_to_undock = mask & ATIF_READY_TO_UNDOCK_NOTIFICATION_SUPPORTED; 1628c2ecf20Sopenharmony_ci f->external_gpu_information = mask & ATIF_GET_EXTERNAL_GPU_INFORMATION_SUPPORTED; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * amdgpu_atif_verify_interface - verify ATIF 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * @handle: acpi handle 1698c2ecf20Sopenharmony_ci * @atif: amdgpu atif struct 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function 1728c2ecf20Sopenharmony_ci * to initialize ATIF and determine what features are supported 1738c2ecf20Sopenharmony_ci * (all asics). 1748c2ecf20Sopenharmony_ci * returns 0 on success, error on failure. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistatic int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci union acpi_object *info; 1798c2ecf20Sopenharmony_ci struct atif_verify_interface output; 1808c2ecf20Sopenharmony_ci size_t size; 1818c2ecf20Sopenharmony_ci int err = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); 1848c2ecf20Sopenharmony_ci if (!info) 1858c2ecf20Sopenharmony_ci return -EIO; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci memset(&output, 0, sizeof(output)); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci size = *(u16 *) info->buffer.pointer; 1908c2ecf20Sopenharmony_ci if (size < 12) { 1918c2ecf20Sopenharmony_ci DRM_INFO("ATIF buffer is too small: %zu\n", size); 1928c2ecf20Sopenharmony_ci err = -EINVAL; 1938c2ecf20Sopenharmony_ci goto out; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci size = min(sizeof(output), size); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci memcpy(&output, info->buffer.pointer, size); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* TODO: check version? */ 2008c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("ATIF version %u\n", output.version); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask); 2038c2ecf20Sopenharmony_ci amdgpu_atif_parse_functions(&atif->functions, output.function_bits); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciout: 2068c2ecf20Sopenharmony_ci kfree(info); 2078c2ecf20Sopenharmony_ci return err; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic acpi_handle amdgpu_atif_probe_handle(acpi_handle dhandle) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci acpi_handle handle = NULL; 2138c2ecf20Sopenharmony_ci char acpi_method_name[255] = { 0 }; 2148c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name }; 2158c2ecf20Sopenharmony_ci acpi_status status; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* For PX/HG systems, ATIF and ATPX are in the iGPU's namespace, on dGPU only 2188c2ecf20Sopenharmony_ci * systems, ATIF is in the dGPU's namespace. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci status = acpi_get_handle(dhandle, "ATIF", &handle); 2218c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 2228c2ecf20Sopenharmony_ci goto out; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (amdgpu_has_atpx()) { 2258c2ecf20Sopenharmony_ci status = acpi_get_handle(amdgpu_atpx_get_dhandle(), "ATIF", 2268c2ecf20Sopenharmony_ci &handle); 2278c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 2288c2ecf20Sopenharmony_ci goto out; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("No ATIF handle found\n"); 2328c2ecf20Sopenharmony_ci return NULL; 2338c2ecf20Sopenharmony_ciout: 2348c2ecf20Sopenharmony_ci acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 2358c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Found ATIF handle %s\n", acpi_method_name); 2368c2ecf20Sopenharmony_ci return handle; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * amdgpu_atif_get_notification_params - determine notify configuration 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * @handle: acpi handle 2438c2ecf20Sopenharmony_ci * @n: atif notification configuration struct 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function 2468c2ecf20Sopenharmony_ci * to determine if a notifier is used and if so which one 2478c2ecf20Sopenharmony_ci * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) 2488c2ecf20Sopenharmony_ci * where n is specified in the result if a notifier is used. 2498c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_cistatic int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci union acpi_object *info; 2548c2ecf20Sopenharmony_ci struct amdgpu_atif_notification_cfg *n = &atif->notification_cfg; 2558c2ecf20Sopenharmony_ci struct atif_system_params params; 2568c2ecf20Sopenharmony_ci size_t size; 2578c2ecf20Sopenharmony_ci int err = 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, 2608c2ecf20Sopenharmony_ci NULL); 2618c2ecf20Sopenharmony_ci if (!info) { 2628c2ecf20Sopenharmony_ci err = -EIO; 2638c2ecf20Sopenharmony_ci goto out; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci size = *(u16 *) info->buffer.pointer; 2678c2ecf20Sopenharmony_ci if (size < 10) { 2688c2ecf20Sopenharmony_ci err = -EINVAL; 2698c2ecf20Sopenharmony_ci goto out; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 2738c2ecf20Sopenharmony_ci size = min(sizeof(params), size); 2748c2ecf20Sopenharmony_ci memcpy(¶ms, info->buffer.pointer, size); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", 2778c2ecf20Sopenharmony_ci params.flags, params.valid_mask); 2788c2ecf20Sopenharmony_ci params.flags = params.flags & params.valid_mask; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { 2818c2ecf20Sopenharmony_ci n->enabled = false; 2828c2ecf20Sopenharmony_ci n->command_code = 0; 2838c2ecf20Sopenharmony_ci } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { 2848c2ecf20Sopenharmony_ci n->enabled = true; 2858c2ecf20Sopenharmony_ci n->command_code = 0x81; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci if (size < 11) { 2888c2ecf20Sopenharmony_ci err = -EINVAL; 2898c2ecf20Sopenharmony_ci goto out; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci n->enabled = true; 2928c2ecf20Sopenharmony_ci n->command_code = params.command_code; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciout: 2968c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n", 2978c2ecf20Sopenharmony_ci (n->enabled ? "enabled" : "disabled"), 2988c2ecf20Sopenharmony_ci n->command_code); 2998c2ecf20Sopenharmony_ci kfree(info); 3008c2ecf20Sopenharmony_ci return err; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/** 3048c2ecf20Sopenharmony_ci * amdgpu_atif_query_backlight_caps - get min and max backlight input signal 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * @handle: acpi handle 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function 3098c2ecf20Sopenharmony_ci * to determine the acceptable range of backlight values 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci * Backlight_caps.caps_valid will be set to true if the query is successful 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * The input signals are in range 0-255 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * This function assumes the display with backlight is the first LCD 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_cistatic int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci union acpi_object *info; 3228c2ecf20Sopenharmony_ci struct atif_qbtc_output characteristics; 3238c2ecf20Sopenharmony_ci struct atif_qbtc_arguments arguments; 3248c2ecf20Sopenharmony_ci struct acpi_buffer params; 3258c2ecf20Sopenharmony_ci size_t size; 3268c2ecf20Sopenharmony_ci int err = 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci arguments.size = sizeof(arguments); 3298c2ecf20Sopenharmony_ci arguments.requested_display = ATIF_QBTC_REQUEST_LCD1; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci params.length = sizeof(arguments); 3328c2ecf20Sopenharmony_ci params.pointer = (void *)&arguments; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci info = amdgpu_atif_call(atif, 3358c2ecf20Sopenharmony_ci ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS, 3368c2ecf20Sopenharmony_ci ¶ms); 3378c2ecf20Sopenharmony_ci if (!info) { 3388c2ecf20Sopenharmony_ci err = -EIO; 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci size = *(u16 *) info->buffer.pointer; 3438c2ecf20Sopenharmony_ci if (size < 10) { 3448c2ecf20Sopenharmony_ci err = -EINVAL; 3458c2ecf20Sopenharmony_ci goto out; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci memset(&characteristics, 0, sizeof(characteristics)); 3498c2ecf20Sopenharmony_ci size = min(sizeof(characteristics), size); 3508c2ecf20Sopenharmony_ci memcpy(&characteristics, info->buffer.pointer, size); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci atif->backlight_caps.caps_valid = true; 3538c2ecf20Sopenharmony_ci atif->backlight_caps.min_input_signal = 3548c2ecf20Sopenharmony_ci characteristics.min_input_signal; 3558c2ecf20Sopenharmony_ci atif->backlight_caps.max_input_signal = 3568c2ecf20Sopenharmony_ci characteristics.max_input_signal; 3578c2ecf20Sopenharmony_ciout: 3588c2ecf20Sopenharmony_ci kfree(info); 3598c2ecf20Sopenharmony_ci return err; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/** 3638c2ecf20Sopenharmony_ci * amdgpu_atif_get_sbios_requests - get requested sbios event 3648c2ecf20Sopenharmony_ci * 3658c2ecf20Sopenharmony_ci * @handle: acpi handle 3668c2ecf20Sopenharmony_ci * @req: atif sbios request struct 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function 3698c2ecf20Sopenharmony_ci * to determine what requests the sbios is making to the driver 3708c2ecf20Sopenharmony_ci * (all asics). 3718c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_cistatic int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif, 3748c2ecf20Sopenharmony_ci struct atif_sbios_requests *req) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci union acpi_object *info; 3778c2ecf20Sopenharmony_ci size_t size; 3788c2ecf20Sopenharmony_ci int count = 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, 3818c2ecf20Sopenharmony_ci NULL); 3828c2ecf20Sopenharmony_ci if (!info) 3838c2ecf20Sopenharmony_ci return -EIO; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci size = *(u16 *)info->buffer.pointer; 3868c2ecf20Sopenharmony_ci if (size < 0xd) { 3878c2ecf20Sopenharmony_ci count = -EINVAL; 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci memset(req, 0, sizeof(*req)); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci size = min(sizeof(*req), size); 3938c2ecf20Sopenharmony_ci memcpy(req, info->buffer.pointer, size); 3948c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci count = hweight32(req->pending); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciout: 3998c2ecf20Sopenharmony_ci kfree(info); 4008c2ecf20Sopenharmony_ci return count; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/** 4048c2ecf20Sopenharmony_ci * amdgpu_atif_handler - handle ATIF notify requests 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 4078c2ecf20Sopenharmony_ci * @event: atif sbios request struct 4088c2ecf20Sopenharmony_ci * 4098c2ecf20Sopenharmony_ci * Checks the acpi event and if it matches an atif event, 4108c2ecf20Sopenharmony_ci * handles it. 4118c2ecf20Sopenharmony_ci * 4128c2ecf20Sopenharmony_ci * Returns: 4138c2ecf20Sopenharmony_ci * NOTIFY_BAD or NOTIFY_DONE, depending on the event. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_cistatic int amdgpu_atif_handler(struct amdgpu_device *adev, 4168c2ecf20Sopenharmony_ci struct acpi_bus_event *event) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct amdgpu_atif *atif = adev->atif; 4198c2ecf20Sopenharmony_ci int count; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", 4228c2ecf20Sopenharmony_ci event->device_class, event->type); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) 4258c2ecf20Sopenharmony_ci return NOTIFY_DONE; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Is this actually our event? */ 4288c2ecf20Sopenharmony_ci if (!atif || 4298c2ecf20Sopenharmony_ci !atif->notification_cfg.enabled || 4308c2ecf20Sopenharmony_ci event->type != atif->notification_cfg.command_code) { 4318c2ecf20Sopenharmony_ci /* These events will generate keypresses otherwise */ 4328c2ecf20Sopenharmony_ci if (event->type == ACPI_VIDEO_NOTIFY_PROBE) 4338c2ecf20Sopenharmony_ci return NOTIFY_BAD; 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci return NOTIFY_DONE; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (atif->functions.sbios_requests) { 4398c2ecf20Sopenharmony_ci struct atif_sbios_requests req; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Check pending SBIOS requests */ 4428c2ecf20Sopenharmony_ci count = amdgpu_atif_get_sbios_requests(atif, &req); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (count <= 0) 4458c2ecf20Sopenharmony_ci return NOTIFY_BAD; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { 4508c2ecf20Sopenharmony_ci#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 4518c2ecf20Sopenharmony_ci if (atif->bd) { 4528c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Changing brightness to %d\n", 4538c2ecf20Sopenharmony_ci req.backlight_level); 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * XXX backlight_device_set_brightness() is 4568c2ecf20Sopenharmony_ci * hardwired to post BACKLIGHT_UPDATE_SYSFS. 4578c2ecf20Sopenharmony_ci * It probably should accept 'reason' parameter. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci backlight_device_set_brightness(atif->bd, req.backlight_level); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci#endif 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (req.pending & ATIF_DGPU_DISPLAY_EVENT) { 4658c2ecf20Sopenharmony_ci if (adev->flags & AMD_IS_PX) { 4668c2ecf20Sopenharmony_ci pm_runtime_get_sync(adev_to_drm(adev)->dev); 4678c2ecf20Sopenharmony_ci /* Just fire off a uevent and let userspace tell us what to do */ 4688c2ecf20Sopenharmony_ci drm_helper_hpd_irq_event(adev_to_drm(adev)); 4698c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 4708c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci /* TODO: check other events */ 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* We've handled the event, stop the notifier chain. The ACPI interface 4778c2ecf20Sopenharmony_ci * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to 4788c2ecf20Sopenharmony_ci * userspace if the event was generated only to signal a SBIOS 4798c2ecf20Sopenharmony_ci * request. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci return NOTIFY_BAD; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* Call the ATCS method 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * amdgpu_atcs_call - call an ATCS method 4888c2ecf20Sopenharmony_ci * 4898c2ecf20Sopenharmony_ci * @handle: acpi handle 4908c2ecf20Sopenharmony_ci * @function: the ATCS function to execute 4918c2ecf20Sopenharmony_ci * @params: ATCS function params 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * Executes the requested ATCS function (all asics). 4948c2ecf20Sopenharmony_ci * Returns a pointer to the acpi output buffer. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_cistatic union acpi_object *amdgpu_atcs_call(acpi_handle handle, int function, 4978c2ecf20Sopenharmony_ci struct acpi_buffer *params) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci acpi_status status; 5008c2ecf20Sopenharmony_ci union acpi_object atcs_arg_elements[2]; 5018c2ecf20Sopenharmony_ci struct acpi_object_list atcs_arg; 5028c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci atcs_arg.count = 2; 5058c2ecf20Sopenharmony_ci atcs_arg.pointer = &atcs_arg_elements[0]; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci atcs_arg_elements[0].type = ACPI_TYPE_INTEGER; 5088c2ecf20Sopenharmony_ci atcs_arg_elements[0].integer.value = function; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (params) { 5118c2ecf20Sopenharmony_ci atcs_arg_elements[1].type = ACPI_TYPE_BUFFER; 5128c2ecf20Sopenharmony_ci atcs_arg_elements[1].buffer.length = params->length; 5138c2ecf20Sopenharmony_ci atcs_arg_elements[1].buffer.pointer = params->pointer; 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci /* We need a second fake parameter */ 5168c2ecf20Sopenharmony_ci atcs_arg_elements[1].type = ACPI_TYPE_INTEGER; 5178c2ecf20Sopenharmony_ci atcs_arg_elements[1].integer.value = 0; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* Fail only if calling the method fails and ATIF is supported */ 5238c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 5248c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n", 5258c2ecf20Sopenharmony_ci acpi_format_exception(status)); 5268c2ecf20Sopenharmony_ci kfree(buffer.pointer); 5278c2ecf20Sopenharmony_ci return NULL; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return buffer.pointer; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/** 5348c2ecf20Sopenharmony_ci * amdgpu_atcs_parse_functions - parse supported functions 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * @f: supported functions struct 5378c2ecf20Sopenharmony_ci * @mask: supported functions mask from ATCS 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * Use the supported functions mask from ATCS function 5408c2ecf20Sopenharmony_ci * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions 5418c2ecf20Sopenharmony_ci * are supported (all asics). 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_cistatic void amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions *f, u32 mask) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; 5468c2ecf20Sopenharmony_ci f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; 5478c2ecf20Sopenharmony_ci f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; 5488c2ecf20Sopenharmony_ci f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/** 5528c2ecf20Sopenharmony_ci * amdgpu_atcs_verify_interface - verify ATCS 5538c2ecf20Sopenharmony_ci * 5548c2ecf20Sopenharmony_ci * @handle: acpi handle 5558c2ecf20Sopenharmony_ci * @atcs: amdgpu atcs struct 5568c2ecf20Sopenharmony_ci * 5578c2ecf20Sopenharmony_ci * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function 5588c2ecf20Sopenharmony_ci * to initialize ATCS and determine what features are supported 5598c2ecf20Sopenharmony_ci * (all asics). 5608c2ecf20Sopenharmony_ci * returns 0 on success, error on failure. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_cistatic int amdgpu_atcs_verify_interface(acpi_handle handle, 5638c2ecf20Sopenharmony_ci struct amdgpu_atcs *atcs) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci union acpi_object *info; 5668c2ecf20Sopenharmony_ci struct atcs_verify_interface output; 5678c2ecf20Sopenharmony_ci size_t size; 5688c2ecf20Sopenharmony_ci int err = 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci info = amdgpu_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); 5718c2ecf20Sopenharmony_ci if (!info) 5728c2ecf20Sopenharmony_ci return -EIO; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci memset(&output, 0, sizeof(output)); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci size = *(u16 *) info->buffer.pointer; 5778c2ecf20Sopenharmony_ci if (size < 8) { 5788c2ecf20Sopenharmony_ci DRM_INFO("ATCS buffer is too small: %zu\n", size); 5798c2ecf20Sopenharmony_ci err = -EINVAL; 5808c2ecf20Sopenharmony_ci goto out; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci size = min(sizeof(output), size); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci memcpy(&output, info->buffer.pointer, size); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* TODO: check version? */ 5878c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("ATCS version %u\n", output.version); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci amdgpu_atcs_parse_functions(&atcs->functions, output.function_bits); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ciout: 5928c2ecf20Sopenharmony_ci kfree(info); 5938c2ecf20Sopenharmony_ci return err; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/** 5978c2ecf20Sopenharmony_ci * amdgpu_acpi_is_pcie_performance_request_supported 5988c2ecf20Sopenharmony_ci * 5998c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci * Check if the ATCS pcie_perf_req and pcie_dev_rdy methods 6028c2ecf20Sopenharmony_ci * are supported (all asics). 6038c2ecf20Sopenharmony_ci * returns true if supported, false if not. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_cibool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct amdgpu_atcs *atcs = &adev->atcs; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy) 6108c2ecf20Sopenharmony_ci return true; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return false; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci/** 6168c2ecf20Sopenharmony_ci * amdgpu_acpi_pcie_notify_device_ready 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 6198c2ecf20Sopenharmony_ci * 6208c2ecf20Sopenharmony_ci * Executes the PCIE_DEVICE_READY_NOTIFICATION method 6218c2ecf20Sopenharmony_ci * (all asics). 6228c2ecf20Sopenharmony_ci * returns 0 on success, error on failure. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_ciint amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci acpi_handle handle; 6278c2ecf20Sopenharmony_ci union acpi_object *info; 6288c2ecf20Sopenharmony_ci struct amdgpu_atcs *atcs = &adev->atcs; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* Get the device handle */ 6318c2ecf20Sopenharmony_ci handle = ACPI_HANDLE(&adev->pdev->dev); 6328c2ecf20Sopenharmony_ci if (!handle) 6338c2ecf20Sopenharmony_ci return -EINVAL; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (!atcs->functions.pcie_dev_rdy) 6368c2ecf20Sopenharmony_ci return -EINVAL; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL); 6398c2ecf20Sopenharmony_ci if (!info) 6408c2ecf20Sopenharmony_ci return -EIO; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci kfree(info); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/** 6488c2ecf20Sopenharmony_ci * amdgpu_acpi_pcie_performance_request 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 6518c2ecf20Sopenharmony_ci * @perf_req: requested perf level (pcie gen speed) 6528c2ecf20Sopenharmony_ci * @advertise: set advertise caps flag if set 6538c2ecf20Sopenharmony_ci * 6548c2ecf20Sopenharmony_ci * Executes the PCIE_PERFORMANCE_REQUEST method to 6558c2ecf20Sopenharmony_ci * change the pcie gen speed (all asics). 6568c2ecf20Sopenharmony_ci * returns 0 on success, error on failure. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_ciint amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, 6598c2ecf20Sopenharmony_ci u8 perf_req, bool advertise) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci acpi_handle handle; 6628c2ecf20Sopenharmony_ci union acpi_object *info; 6638c2ecf20Sopenharmony_ci struct amdgpu_atcs *atcs = &adev->atcs; 6648c2ecf20Sopenharmony_ci struct atcs_pref_req_input atcs_input; 6658c2ecf20Sopenharmony_ci struct atcs_pref_req_output atcs_output; 6668c2ecf20Sopenharmony_ci struct acpi_buffer params; 6678c2ecf20Sopenharmony_ci size_t size; 6688c2ecf20Sopenharmony_ci u32 retry = 3; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (amdgpu_acpi_pcie_notify_device_ready(adev)) 6718c2ecf20Sopenharmony_ci return -EINVAL; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Get the device handle */ 6748c2ecf20Sopenharmony_ci handle = ACPI_HANDLE(&adev->pdev->dev); 6758c2ecf20Sopenharmony_ci if (!handle) 6768c2ecf20Sopenharmony_ci return -EINVAL; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (!atcs->functions.pcie_perf_req) 6798c2ecf20Sopenharmony_ci return -EINVAL; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci atcs_input.size = sizeof(struct atcs_pref_req_input); 6828c2ecf20Sopenharmony_ci /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ 6838c2ecf20Sopenharmony_ci atcs_input.client_id = adev->pdev->devfn | (adev->pdev->bus->number << 8); 6848c2ecf20Sopenharmony_ci atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK; 6858c2ecf20Sopenharmony_ci atcs_input.flags = ATCS_WAIT_FOR_COMPLETION; 6868c2ecf20Sopenharmony_ci if (advertise) 6878c2ecf20Sopenharmony_ci atcs_input.flags |= ATCS_ADVERTISE_CAPS; 6888c2ecf20Sopenharmony_ci atcs_input.req_type = ATCS_PCIE_LINK_SPEED; 6898c2ecf20Sopenharmony_ci atcs_input.perf_req = perf_req; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci params.length = sizeof(struct atcs_pref_req_input); 6928c2ecf20Sopenharmony_ci params.pointer = &atcs_input; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci while (retry--) { 6958c2ecf20Sopenharmony_ci info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms); 6968c2ecf20Sopenharmony_ci if (!info) 6978c2ecf20Sopenharmony_ci return -EIO; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci memset(&atcs_output, 0, sizeof(atcs_output)); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci size = *(u16 *) info->buffer.pointer; 7028c2ecf20Sopenharmony_ci if (size < 3) { 7038c2ecf20Sopenharmony_ci DRM_INFO("ATCS buffer is too small: %zu\n", size); 7048c2ecf20Sopenharmony_ci kfree(info); 7058c2ecf20Sopenharmony_ci return -EINVAL; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci size = min(sizeof(atcs_output), size); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci memcpy(&atcs_output, info->buffer.pointer, size); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci kfree(info); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci switch (atcs_output.ret_val) { 7148c2ecf20Sopenharmony_ci case ATCS_REQUEST_REFUSED: 7158c2ecf20Sopenharmony_ci default: 7168c2ecf20Sopenharmony_ci return -EINVAL; 7178c2ecf20Sopenharmony_ci case ATCS_REQUEST_COMPLETE: 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci case ATCS_REQUEST_IN_PROGRESS: 7208c2ecf20Sopenharmony_ci udelay(10); 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/** 7298c2ecf20Sopenharmony_ci * amdgpu_acpi_event - handle notify events 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * @nb: notifier block 7328c2ecf20Sopenharmony_ci * @val: val 7338c2ecf20Sopenharmony_ci * @data: acpi event 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * Calls relevant amdgpu functions in response to various 7368c2ecf20Sopenharmony_ci * acpi events. 7378c2ecf20Sopenharmony_ci * Returns NOTIFY code 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_cistatic int amdgpu_acpi_event(struct notifier_block *nb, 7408c2ecf20Sopenharmony_ci unsigned long val, 7418c2ecf20Sopenharmony_ci void *data) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, acpi_nb); 7448c2ecf20Sopenharmony_ci struct acpi_bus_event *entry = (struct acpi_bus_event *)data; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { 7478c2ecf20Sopenharmony_ci if (power_supply_is_system_supplied() > 0) 7488c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("pm: AC\n"); 7498c2ecf20Sopenharmony_ci else 7508c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("pm: DC\n"); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci amdgpu_pm_acpi_event_handler(adev); 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Check for pending SBIOS requests */ 7568c2ecf20Sopenharmony_ci return amdgpu_atif_handler(adev, entry); 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* Call all ACPI methods here */ 7608c2ecf20Sopenharmony_ci/** 7618c2ecf20Sopenharmony_ci * amdgpu_acpi_init - init driver acpi support 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7648c2ecf20Sopenharmony_ci * 7658c2ecf20Sopenharmony_ci * Verifies the AMD ACPI interfaces and registers with the acpi 7668c2ecf20Sopenharmony_ci * notifier chain (all asics). 7678c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ciint amdgpu_acpi_init(struct amdgpu_device *adev) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci acpi_handle handle, atif_handle; 7728c2ecf20Sopenharmony_ci struct amdgpu_atif *atif; 7738c2ecf20Sopenharmony_ci struct amdgpu_atcs *atcs = &adev->atcs; 7748c2ecf20Sopenharmony_ci int ret; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* Get the device handle */ 7778c2ecf20Sopenharmony_ci handle = ACPI_HANDLE(&adev->pdev->dev); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (!adev->bios || !handle) 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* Call the ATCS method */ 7838c2ecf20Sopenharmony_ci ret = amdgpu_atcs_verify_interface(handle, atcs); 7848c2ecf20Sopenharmony_ci if (ret) { 7858c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* Probe for ATIF, and initialize it if found */ 7898c2ecf20Sopenharmony_ci atif_handle = amdgpu_atif_probe_handle(handle); 7908c2ecf20Sopenharmony_ci if (!atif_handle) 7918c2ecf20Sopenharmony_ci goto out; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci atif = kzalloc(sizeof(*atif), GFP_KERNEL); 7948c2ecf20Sopenharmony_ci if (!atif) { 7958c2ecf20Sopenharmony_ci DRM_WARN("Not enough memory to initialize ATIF\n"); 7968c2ecf20Sopenharmony_ci goto out; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci atif->handle = atif_handle; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* Call the ATIF method */ 8018c2ecf20Sopenharmony_ci ret = amdgpu_atif_verify_interface(atif); 8028c2ecf20Sopenharmony_ci if (ret) { 8038c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); 8048c2ecf20Sopenharmony_ci kfree(atif); 8058c2ecf20Sopenharmony_ci goto out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci adev->atif = atif; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) 8108c2ecf20Sopenharmony_ci if (atif->notifications.brightness_change) { 8118c2ecf20Sopenharmony_ci if (amdgpu_device_has_dc_support(adev)) { 8128c2ecf20Sopenharmony_ci#if defined(CONFIG_DRM_AMD_DC) 8138c2ecf20Sopenharmony_ci struct amdgpu_display_manager *dm = &adev->dm; 8148c2ecf20Sopenharmony_ci atif->bd = dm->backlight_dev; 8158c2ecf20Sopenharmony_ci#endif 8168c2ecf20Sopenharmony_ci } else { 8178c2ecf20Sopenharmony_ci struct drm_encoder *tmp; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Find the encoder controlling the brightness */ 8208c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &adev_to_drm(adev)->mode_config.encoder_list, 8218c2ecf20Sopenharmony_ci head) { 8228c2ecf20Sopenharmony_ci struct amdgpu_encoder *enc = to_amdgpu_encoder(tmp); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && 8258c2ecf20Sopenharmony_ci enc->enc_priv) { 8268c2ecf20Sopenharmony_ci struct amdgpu_encoder_atom_dig *dig = enc->enc_priv; 8278c2ecf20Sopenharmony_ci if (dig->bl_dev) { 8288c2ecf20Sopenharmony_ci atif->bd = dig->bl_dev; 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci#endif 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (atif->functions.sbios_requests && !atif->functions.system_params) { 8388c2ecf20Sopenharmony_ci /* XXX check this workraround, if sbios request function is 8398c2ecf20Sopenharmony_ci * present we have to see how it's configured in the system 8408c2ecf20Sopenharmony_ci * params 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_ci atif->functions.system_params = true; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (atif->functions.system_params) { 8468c2ecf20Sopenharmony_ci ret = amdgpu_atif_get_notification_params(atif); 8478c2ecf20Sopenharmony_ci if (ret) { 8488c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n", 8498c2ecf20Sopenharmony_ci ret); 8508c2ecf20Sopenharmony_ci /* Disable notification */ 8518c2ecf20Sopenharmony_ci atif->notification_cfg.enabled = false; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (atif->functions.query_backlight_transfer_characteristics) { 8568c2ecf20Sopenharmony_ci ret = amdgpu_atif_query_backlight_caps(atif); 8578c2ecf20Sopenharmony_ci if (ret) { 8588c2ecf20Sopenharmony_ci DRM_DEBUG_DRIVER("Call to QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS failed: %d\n", 8598c2ecf20Sopenharmony_ci ret); 8608c2ecf20Sopenharmony_ci atif->backlight_caps.caps_valid = false; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } else { 8638c2ecf20Sopenharmony_ci atif->backlight_caps.caps_valid = false; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ciout: 8678c2ecf20Sopenharmony_ci adev->acpi_nb.notifier_call = amdgpu_acpi_event; 8688c2ecf20Sopenharmony_ci register_acpi_notifier(&adev->acpi_nb); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return ret; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_civoid amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev, 8748c2ecf20Sopenharmony_ci struct amdgpu_dm_backlight_caps *caps) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci if (!adev->atif) { 8778c2ecf20Sopenharmony_ci caps->caps_valid = false; 8788c2ecf20Sopenharmony_ci return; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci caps->caps_valid = adev->atif->backlight_caps.caps_valid; 8818c2ecf20Sopenharmony_ci caps->min_input_signal = adev->atif->backlight_caps.min_input_signal; 8828c2ecf20Sopenharmony_ci caps->max_input_signal = adev->atif->backlight_caps.max_input_signal; 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci/** 8868c2ecf20Sopenharmony_ci * amdgpu_acpi_fini - tear down driver acpi support 8878c2ecf20Sopenharmony_ci * 8888c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 8898c2ecf20Sopenharmony_ci * 8908c2ecf20Sopenharmony_ci * Unregisters with the acpi notifier chain (all asics). 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_civoid amdgpu_acpi_fini(struct amdgpu_device *adev) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci unregister_acpi_notifier(&adev->acpi_nb); 8958c2ecf20Sopenharmony_ci kfree(adev->atif); 8968c2ecf20Sopenharmony_ci} 897