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(&params, 0, sizeof(params));
2738c2ecf20Sopenharmony_ci	size = min(sizeof(params), size);
2748c2ecf20Sopenharmony_ci	memcpy(&params, 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		&params);
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, &params);
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