1*770c9d53Sriastradh /* $NetBSD: amdgpu_acpi.c,v 1.6 2024/04/16 14:34:01 riastradh Exp $ */
2efa246c0Sriastradh
3efa246c0Sriastradh /*
4efa246c0Sriastradh * Copyright 2012 Advanced Micro Devices, Inc.
5efa246c0Sriastradh *
6efa246c0Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
7efa246c0Sriastradh * copy of this software and associated documentation files (the "Software"),
8efa246c0Sriastradh * to deal in the Software without restriction, including without limitation
9efa246c0Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10efa246c0Sriastradh * and/or sell copies of the Software, and to permit persons to whom the
11efa246c0Sriastradh * Software is furnished to do so, subject to the following conditions:
12efa246c0Sriastradh *
13efa246c0Sriastradh * The above copyright notice and this permission notice shall be included in
14efa246c0Sriastradh * all copies or substantial portions of the Software.
15efa246c0Sriastradh *
16efa246c0Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17efa246c0Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18efa246c0Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19efa246c0Sriastradh * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20efa246c0Sriastradh * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21efa246c0Sriastradh * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22efa246c0Sriastradh * OTHER DEALINGS IN THE SOFTWARE.
23efa246c0Sriastradh *
24efa246c0Sriastradh */
25efa246c0Sriastradh
26efa246c0Sriastradh #include <sys/cdefs.h>
27*770c9d53Sriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_acpi.c,v 1.6 2024/04/16 14:34:01 riastradh Exp $");
28efa246c0Sriastradh
29efa246c0Sriastradh #include <linux/pci.h>
30efa246c0Sriastradh #include <linux/acpi.h>
31efa246c0Sriastradh #include <linux/slab.h>
32efa246c0Sriastradh #include <linux/power_supply.h>
3341ec0267Sriastradh #include <linux/pm_runtime.h>
34efa246c0Sriastradh #include <acpi/video.h>
3541ec0267Sriastradh
36efa246c0Sriastradh #include <drm/drm_crtc_helper.h>
37efa246c0Sriastradh #include "amdgpu.h"
380d50c49dSriastradh #include "amdgpu_pm.h"
3941ec0267Sriastradh #include "amdgpu_display.h"
4041ec0267Sriastradh #include "amd_acpi.h"
41efa246c0Sriastradh #include "atom.h"
42efa246c0Sriastradh
43*770c9d53Sriastradh #ifdef __NetBSD__
44*770c9d53Sriastradh #include <dev/acpi/acpi_pci.h>
45*770c9d53Sriastradh #include <dev/acpi/acpireg.h>
46*770c9d53Sriastradh #define _COMPONENT ACPI_DISPLAY_COMPONENT
47*770c9d53Sriastradh ACPI_MODULE_NAME("radeon_acpi")
48*770c9d53Sriastradh #include <linux/nbsd-namespace-acpi.h>
49*770c9d53Sriastradh #endif
50*770c9d53Sriastradh
5141ec0267Sriastradh struct amdgpu_atif_notification_cfg {
5241ec0267Sriastradh bool enabled;
5341ec0267Sriastradh int command_code;
5441ec0267Sriastradh };
55efa246c0Sriastradh
5641ec0267Sriastradh struct amdgpu_atif_notifications {
5741ec0267Sriastradh bool thermal_state;
5841ec0267Sriastradh bool forced_power_state;
5941ec0267Sriastradh bool system_power_state;
6041ec0267Sriastradh bool brightness_change;
6141ec0267Sriastradh bool dgpu_display_event;
6241ec0267Sriastradh bool gpu_package_power_limit;
6341ec0267Sriastradh };
64efa246c0Sriastradh
6541ec0267Sriastradh struct amdgpu_atif_functions {
6641ec0267Sriastradh bool system_params;
6741ec0267Sriastradh bool sbios_requests;
6841ec0267Sriastradh bool temperature_change;
6941ec0267Sriastradh bool query_backlight_transfer_characteristics;
7041ec0267Sriastradh bool ready_to_undock;
7141ec0267Sriastradh bool external_gpu_information;
7241ec0267Sriastradh };
73efa246c0Sriastradh
7441ec0267Sriastradh struct amdgpu_atif {
7541ec0267Sriastradh acpi_handle handle;
76efa246c0Sriastradh
7741ec0267Sriastradh struct amdgpu_atif_notifications notifications;
7841ec0267Sriastradh struct amdgpu_atif_functions functions;
7941ec0267Sriastradh struct amdgpu_atif_notification_cfg notification_cfg;
8041ec0267Sriastradh struct amdgpu_encoder *encoder_for_bl;
8141ec0267Sriastradh struct amdgpu_dm_backlight_caps backlight_caps;
8241ec0267Sriastradh };
83efa246c0Sriastradh
84efa246c0Sriastradh /* Call the ATIF method
85efa246c0Sriastradh */
86efa246c0Sriastradh /**
87efa246c0Sriastradh * amdgpu_atif_call - call an ATIF method
88efa246c0Sriastradh *
89efa246c0Sriastradh * @handle: acpi handle
90efa246c0Sriastradh * @function: the ATIF function to execute
91efa246c0Sriastradh * @params: ATIF function params
92efa246c0Sriastradh *
93efa246c0Sriastradh * Executes the requested ATIF function (all asics).
94efa246c0Sriastradh * Returns a pointer to the acpi output buffer.
95efa246c0Sriastradh */
amdgpu_atif_call(struct amdgpu_atif * atif,int function,struct acpi_buffer * params)9641ec0267Sriastradh static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif,
9741ec0267Sriastradh int function,
98efa246c0Sriastradh struct acpi_buffer *params)
99efa246c0Sriastradh {
100efa246c0Sriastradh acpi_status status;
101efa246c0Sriastradh union acpi_object atif_arg_elements[2];
102efa246c0Sriastradh struct acpi_object_list atif_arg;
103efa246c0Sriastradh struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
104efa246c0Sriastradh
105efa246c0Sriastradh atif_arg.count = 2;
106efa246c0Sriastradh atif_arg.pointer = &atif_arg_elements[0];
107efa246c0Sriastradh
108efa246c0Sriastradh atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
109efa246c0Sriastradh atif_arg_elements[0].integer.value = function;
110efa246c0Sriastradh
111efa246c0Sriastradh if (params) {
112efa246c0Sriastradh atif_arg_elements[1].type = ACPI_TYPE_BUFFER;
113efa246c0Sriastradh atif_arg_elements[1].buffer.length = params->length;
114efa246c0Sriastradh atif_arg_elements[1].buffer.pointer = params->pointer;
115efa246c0Sriastradh } else {
116efa246c0Sriastradh /* We need a second fake parameter */
117efa246c0Sriastradh atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
118efa246c0Sriastradh atif_arg_elements[1].integer.value = 0;
119efa246c0Sriastradh }
120efa246c0Sriastradh
12141ec0267Sriastradh status = acpi_evaluate_object(atif->handle, NULL, &atif_arg,
12241ec0267Sriastradh &buffer);
123efa246c0Sriastradh
124efa246c0Sriastradh /* Fail only if calling the method fails and ATIF is supported */
125efa246c0Sriastradh if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
126efa246c0Sriastradh DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
127efa246c0Sriastradh acpi_format_exception(status));
128d7495136Sriastradh ACPI_FREE(buffer.pointer);
129efa246c0Sriastradh return NULL;
130efa246c0Sriastradh }
131efa246c0Sriastradh
132efa246c0Sriastradh return buffer.pointer;
133efa246c0Sriastradh }
134efa246c0Sriastradh
135efa246c0Sriastradh /**
136efa246c0Sriastradh * amdgpu_atif_parse_notification - parse supported notifications
137efa246c0Sriastradh *
138efa246c0Sriastradh * @n: supported notifications struct
139efa246c0Sriastradh * @mask: supported notifications mask from ATIF
140efa246c0Sriastradh *
141efa246c0Sriastradh * Use the supported notifications mask from ATIF function
142efa246c0Sriastradh * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications
143efa246c0Sriastradh * are supported (all asics).
144efa246c0Sriastradh */
amdgpu_atif_parse_notification(struct amdgpu_atif_notifications * n,u32 mask)145efa246c0Sriastradh static void amdgpu_atif_parse_notification(struct amdgpu_atif_notifications *n, u32 mask)
146efa246c0Sriastradh {
147efa246c0Sriastradh n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
148efa246c0Sriastradh n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
149efa246c0Sriastradh n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
150efa246c0Sriastradh n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
151efa246c0Sriastradh n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
15241ec0267Sriastradh n->gpu_package_power_limit = mask & ATIF_GPU_PACKAGE_POWER_LIMIT_REQUEST_SUPPORTED;
153efa246c0Sriastradh }
154efa246c0Sriastradh
155efa246c0Sriastradh /**
156efa246c0Sriastradh * amdgpu_atif_parse_functions - parse supported functions
157efa246c0Sriastradh *
158efa246c0Sriastradh * @f: supported functions struct
159efa246c0Sriastradh * @mask: supported functions mask from ATIF
160efa246c0Sriastradh *
161efa246c0Sriastradh * Use the supported functions mask from ATIF function
162efa246c0Sriastradh * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions
163efa246c0Sriastradh * are supported (all asics).
164efa246c0Sriastradh */
amdgpu_atif_parse_functions(struct amdgpu_atif_functions * f,u32 mask)165efa246c0Sriastradh static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mask)
166efa246c0Sriastradh {
167efa246c0Sriastradh f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
168efa246c0Sriastradh f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
169efa246c0Sriastradh f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
17041ec0267Sriastradh f->query_backlight_transfer_characteristics =
17141ec0267Sriastradh mask & ATIF_QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS_SUPPORTED;
17241ec0267Sriastradh f->ready_to_undock = mask & ATIF_READY_TO_UNDOCK_NOTIFICATION_SUPPORTED;
17341ec0267Sriastradh f->external_gpu_information = mask & ATIF_GET_EXTERNAL_GPU_INFORMATION_SUPPORTED;
174efa246c0Sriastradh }
175efa246c0Sriastradh
176efa246c0Sriastradh /**
177efa246c0Sriastradh * amdgpu_atif_verify_interface - verify ATIF
178efa246c0Sriastradh *
179efa246c0Sriastradh * @handle: acpi handle
180efa246c0Sriastradh * @atif: amdgpu atif struct
181efa246c0Sriastradh *
182efa246c0Sriastradh * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function
183efa246c0Sriastradh * to initialize ATIF and determine what features are supported
184efa246c0Sriastradh * (all asics).
185efa246c0Sriastradh * returns 0 on success, error on failure.
186efa246c0Sriastradh */
amdgpu_atif_verify_interface(struct amdgpu_atif * atif)18741ec0267Sriastradh static int amdgpu_atif_verify_interface(struct amdgpu_atif *atif)
188efa246c0Sriastradh {
189efa246c0Sriastradh union acpi_object *info;
190efa246c0Sriastradh struct atif_verify_interface output;
191efa246c0Sriastradh size_t size;
192efa246c0Sriastradh int err = 0;
193efa246c0Sriastradh
19441ec0267Sriastradh info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
195efa246c0Sriastradh if (!info)
196efa246c0Sriastradh return -EIO;
197efa246c0Sriastradh
198efa246c0Sriastradh memset(&output, 0, sizeof(output));
199efa246c0Sriastradh
200efa246c0Sriastradh size = *(u16 *) info->buffer.pointer;
201efa246c0Sriastradh if (size < 12) {
202efa246c0Sriastradh DRM_INFO("ATIF buffer is too small: %zu\n", size);
203efa246c0Sriastradh err = -EINVAL;
204efa246c0Sriastradh goto out;
205efa246c0Sriastradh }
206efa246c0Sriastradh size = min(sizeof(output), size);
207efa246c0Sriastradh
208efa246c0Sriastradh memcpy(&output, info->buffer.pointer, size);
209efa246c0Sriastradh
210efa246c0Sriastradh /* TODO: check version? */
211efa246c0Sriastradh DRM_DEBUG_DRIVER("ATIF version %u\n", output.version);
212efa246c0Sriastradh
213efa246c0Sriastradh amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask);
214efa246c0Sriastradh amdgpu_atif_parse_functions(&atif->functions, output.function_bits);
215efa246c0Sriastradh
216efa246c0Sriastradh out:
217d7495136Sriastradh ACPI_FREE(info);
218efa246c0Sriastradh return err;
219efa246c0Sriastradh }
220efa246c0Sriastradh
amdgpu_atif_probe_handle(acpi_handle dhandle)22141ec0267Sriastradh static acpi_handle amdgpu_atif_probe_handle(acpi_handle dhandle)
22241ec0267Sriastradh {
22341ec0267Sriastradh acpi_handle handle = NULL;
22441ec0267Sriastradh char acpi_method_name[255] = { 0 };
22541ec0267Sriastradh struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name };
22641ec0267Sriastradh acpi_status status;
22741ec0267Sriastradh
22841ec0267Sriastradh /* For PX/HG systems, ATIF and ATPX are in the iGPU's namespace, on dGPU only
22941ec0267Sriastradh * systems, ATIF is in the dGPU's namespace.
23041ec0267Sriastradh */
23141ec0267Sriastradh status = acpi_get_handle(dhandle, "ATIF", &handle);
23241ec0267Sriastradh if (ACPI_SUCCESS(status))
23341ec0267Sriastradh goto out;
23441ec0267Sriastradh
23541ec0267Sriastradh if (amdgpu_has_atpx()) {
23641ec0267Sriastradh status = acpi_get_handle(amdgpu_atpx_get_dhandle(), "ATIF",
23741ec0267Sriastradh &handle);
23841ec0267Sriastradh if (ACPI_SUCCESS(status))
23941ec0267Sriastradh goto out;
24041ec0267Sriastradh }
24141ec0267Sriastradh
24241ec0267Sriastradh DRM_DEBUG_DRIVER("No ATIF handle found\n");
24341ec0267Sriastradh return NULL;
24441ec0267Sriastradh out:
24541ec0267Sriastradh acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
24641ec0267Sriastradh DRM_DEBUG_DRIVER("Found ATIF handle %s\n", acpi_method_name);
24741ec0267Sriastradh return handle;
24841ec0267Sriastradh }
24941ec0267Sriastradh
250efa246c0Sriastradh /**
251efa246c0Sriastradh * amdgpu_atif_get_notification_params - determine notify configuration
252efa246c0Sriastradh *
253efa246c0Sriastradh * @handle: acpi handle
254efa246c0Sriastradh * @n: atif notification configuration struct
255efa246c0Sriastradh *
256efa246c0Sriastradh * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function
257efa246c0Sriastradh * to determine if a notifier is used and if so which one
258efa246c0Sriastradh * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n)
259efa246c0Sriastradh * where n is specified in the result if a notifier is used.
260efa246c0Sriastradh * Returns 0 on success, error on failure.
261efa246c0Sriastradh */
amdgpu_atif_get_notification_params(struct amdgpu_atif * atif)26241ec0267Sriastradh static int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif)
263efa246c0Sriastradh {
264efa246c0Sriastradh union acpi_object *info;
26541ec0267Sriastradh struct amdgpu_atif_notification_cfg *n = &atif->notification_cfg;
266efa246c0Sriastradh struct atif_system_params params;
267efa246c0Sriastradh size_t size;
268efa246c0Sriastradh int err = 0;
269efa246c0Sriastradh
27041ec0267Sriastradh info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS,
27141ec0267Sriastradh NULL);
272efa246c0Sriastradh if (!info) {
273efa246c0Sriastradh err = -EIO;
274efa246c0Sriastradh goto out;
275efa246c0Sriastradh }
276efa246c0Sriastradh
277efa246c0Sriastradh size = *(u16 *) info->buffer.pointer;
278efa246c0Sriastradh if (size < 10) {
279efa246c0Sriastradh err = -EINVAL;
280efa246c0Sriastradh goto out;
281efa246c0Sriastradh }
282efa246c0Sriastradh
283efa246c0Sriastradh memset(¶ms, 0, sizeof(params));
284efa246c0Sriastradh size = min(sizeof(params), size);
285efa246c0Sriastradh memcpy(¶ms, info->buffer.pointer, size);
286efa246c0Sriastradh
287efa246c0Sriastradh DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n",
288efa246c0Sriastradh params.flags, params.valid_mask);
289efa246c0Sriastradh params.flags = params.flags & params.valid_mask;
290efa246c0Sriastradh
291efa246c0Sriastradh if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) {
292efa246c0Sriastradh n->enabled = false;
293efa246c0Sriastradh n->command_code = 0;
294efa246c0Sriastradh } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) {
295efa246c0Sriastradh n->enabled = true;
296efa246c0Sriastradh n->command_code = 0x81;
297efa246c0Sriastradh } else {
298efa246c0Sriastradh if (size < 11) {
299efa246c0Sriastradh err = -EINVAL;
300efa246c0Sriastradh goto out;
301efa246c0Sriastradh }
302efa246c0Sriastradh n->enabled = true;
303efa246c0Sriastradh n->command_code = params.command_code;
304efa246c0Sriastradh }
305efa246c0Sriastradh
306efa246c0Sriastradh out:
307efa246c0Sriastradh DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n",
308efa246c0Sriastradh (n->enabled ? "enabled" : "disabled"),
309efa246c0Sriastradh n->command_code);
310d7495136Sriastradh ACPI_FREE(info);
311efa246c0Sriastradh return err;
312efa246c0Sriastradh }
313efa246c0Sriastradh
314efa246c0Sriastradh /**
31541ec0267Sriastradh * amdgpu_atif_query_backlight_caps - get min and max backlight input signal
31641ec0267Sriastradh *
31741ec0267Sriastradh * @handle: acpi handle
31841ec0267Sriastradh *
31941ec0267Sriastradh * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function
32041ec0267Sriastradh * to determine the acceptable range of backlight values
32141ec0267Sriastradh *
32241ec0267Sriastradh * Backlight_caps.caps_valid will be set to true if the query is successful
32341ec0267Sriastradh *
32441ec0267Sriastradh * The input signals are in range 0-255
32541ec0267Sriastradh *
32641ec0267Sriastradh * This function assumes the display with backlight is the first LCD
32741ec0267Sriastradh *
32841ec0267Sriastradh * Returns 0 on success, error on failure.
32941ec0267Sriastradh */
amdgpu_atif_query_backlight_caps(struct amdgpu_atif * atif)33041ec0267Sriastradh static int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif)
33141ec0267Sriastradh {
33241ec0267Sriastradh union acpi_object *info;
33341ec0267Sriastradh struct atif_qbtc_output characteristics;
33441ec0267Sriastradh struct atif_qbtc_arguments arguments;
33541ec0267Sriastradh struct acpi_buffer params;
33641ec0267Sriastradh size_t size;
33741ec0267Sriastradh int err = 0;
33841ec0267Sriastradh
33941ec0267Sriastradh arguments.size = sizeof(arguments);
34041ec0267Sriastradh arguments.requested_display = ATIF_QBTC_REQUEST_LCD1;
34141ec0267Sriastradh
34241ec0267Sriastradh params.length = sizeof(arguments);
34341ec0267Sriastradh params.pointer = (void *)&arguments;
34441ec0267Sriastradh
34541ec0267Sriastradh info = amdgpu_atif_call(atif,
34641ec0267Sriastradh ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS,
34741ec0267Sriastradh ¶ms);
34841ec0267Sriastradh if (!info) {
34941ec0267Sriastradh err = -EIO;
35041ec0267Sriastradh goto out;
35141ec0267Sriastradh }
35241ec0267Sriastradh
35341ec0267Sriastradh size = *(u16 *) info->buffer.pointer;
35441ec0267Sriastradh if (size < 10) {
35541ec0267Sriastradh err = -EINVAL;
35641ec0267Sriastradh goto out;
35741ec0267Sriastradh }
35841ec0267Sriastradh
35941ec0267Sriastradh memset(&characteristics, 0, sizeof(characteristics));
36041ec0267Sriastradh size = min(sizeof(characteristics), size);
36141ec0267Sriastradh memcpy(&characteristics, info->buffer.pointer, size);
36241ec0267Sriastradh
36341ec0267Sriastradh atif->backlight_caps.caps_valid = true;
36441ec0267Sriastradh atif->backlight_caps.min_input_signal =
36541ec0267Sriastradh characteristics.min_input_signal;
36641ec0267Sriastradh atif->backlight_caps.max_input_signal =
36741ec0267Sriastradh characteristics.max_input_signal;
36841ec0267Sriastradh out:
369d7495136Sriastradh ACPI_FREE(info);
37041ec0267Sriastradh return err;
37141ec0267Sriastradh }
37241ec0267Sriastradh
373*770c9d53Sriastradh #ifndef __NetBSD__ /* XXX amdgpu acpi */
374*770c9d53Sriastradh
37541ec0267Sriastradh /**
376efa246c0Sriastradh * amdgpu_atif_get_sbios_requests - get requested sbios event
377efa246c0Sriastradh *
378efa246c0Sriastradh * @handle: acpi handle
379efa246c0Sriastradh * @req: atif sbios request struct
380efa246c0Sriastradh *
381efa246c0Sriastradh * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function
382efa246c0Sriastradh * to determine what requests the sbios is making to the driver
383efa246c0Sriastradh * (all asics).
384efa246c0Sriastradh * Returns 0 on success, error on failure.
385efa246c0Sriastradh */
amdgpu_atif_get_sbios_requests(struct amdgpu_atif * atif,struct atif_sbios_requests * req)38641ec0267Sriastradh static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif,
387efa246c0Sriastradh struct atif_sbios_requests *req)
388efa246c0Sriastradh {
389efa246c0Sriastradh union acpi_object *info;
390efa246c0Sriastradh size_t size;
391efa246c0Sriastradh int count = 0;
392efa246c0Sriastradh
39341ec0267Sriastradh info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS,
39441ec0267Sriastradh NULL);
395efa246c0Sriastradh if (!info)
396efa246c0Sriastradh return -EIO;
397efa246c0Sriastradh
398efa246c0Sriastradh size = *(u16 *)info->buffer.pointer;
399efa246c0Sriastradh if (size < 0xd) {
400efa246c0Sriastradh count = -EINVAL;
401efa246c0Sriastradh goto out;
402efa246c0Sriastradh }
403efa246c0Sriastradh memset(req, 0, sizeof(*req));
404efa246c0Sriastradh
405efa246c0Sriastradh size = min(sizeof(*req), size);
406efa246c0Sriastradh memcpy(req, info->buffer.pointer, size);
407efa246c0Sriastradh DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending);
408efa246c0Sriastradh
409efa246c0Sriastradh count = hweight32(req->pending);
410efa246c0Sriastradh
411efa246c0Sriastradh out:
412d7495136Sriastradh ACPI_FREE(info);
413efa246c0Sriastradh return count;
414efa246c0Sriastradh }
415efa246c0Sriastradh
416efa246c0Sriastradh /**
417efa246c0Sriastradh * amdgpu_atif_handler - handle ATIF notify requests
418efa246c0Sriastradh *
419efa246c0Sriastradh * @adev: amdgpu_device pointer
420efa246c0Sriastradh * @event: atif sbios request struct
421efa246c0Sriastradh *
422efa246c0Sriastradh * Checks the acpi event and if it matches an atif event,
423efa246c0Sriastradh * handles it.
42441ec0267Sriastradh *
42541ec0267Sriastradh * Returns:
42641ec0267Sriastradh * NOTIFY_BAD or NOTIFY_DONE, depending on the event.
427efa246c0Sriastradh */
amdgpu_atif_handler(struct amdgpu_device * adev,struct acpi_bus_event * event)42841ec0267Sriastradh static int amdgpu_atif_handler(struct amdgpu_device *adev,
429efa246c0Sriastradh struct acpi_bus_event *event)
430efa246c0Sriastradh {
43141ec0267Sriastradh struct amdgpu_atif *atif = adev->atif;
432efa246c0Sriastradh int count;
433efa246c0Sriastradh
434efa246c0Sriastradh DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n",
435efa246c0Sriastradh event->device_class, event->type);
436efa246c0Sriastradh
437efa246c0Sriastradh if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
438efa246c0Sriastradh return NOTIFY_DONE;
439efa246c0Sriastradh
44041ec0267Sriastradh /* Is this actually our event? */
44141ec0267Sriastradh if (!atif ||
44241ec0267Sriastradh !atif->notification_cfg.enabled ||
44341ec0267Sriastradh event->type != atif->notification_cfg.command_code) {
44441ec0267Sriastradh /* These events will generate keypresses otherwise */
44541ec0267Sriastradh if (event->type == ACPI_VIDEO_NOTIFY_PROBE)
44641ec0267Sriastradh return NOTIFY_BAD;
44741ec0267Sriastradh else
448efa246c0Sriastradh return NOTIFY_DONE;
44941ec0267Sriastradh }
45041ec0267Sriastradh
45141ec0267Sriastradh if (atif->functions.sbios_requests) {
45241ec0267Sriastradh struct atif_sbios_requests req;
453efa246c0Sriastradh
454efa246c0Sriastradh /* Check pending SBIOS requests */
45541ec0267Sriastradh count = amdgpu_atif_get_sbios_requests(atif, &req);
456efa246c0Sriastradh
457efa246c0Sriastradh if (count <= 0)
45841ec0267Sriastradh return NOTIFY_BAD;
459efa246c0Sriastradh
460efa246c0Sriastradh DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n", count);
461efa246c0Sriastradh
46241ec0267Sriastradh /* todo: add DC handling */
46341ec0267Sriastradh if ((req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) &&
46441ec0267Sriastradh !amdgpu_device_has_dc_support(adev)) {
465efa246c0Sriastradh struct amdgpu_encoder *enc = atif->encoder_for_bl;
466efa246c0Sriastradh
467efa246c0Sriastradh if (enc) {
468efa246c0Sriastradh struct amdgpu_encoder_atom_dig *dig = enc->enc_priv;
469efa246c0Sriastradh
470efa246c0Sriastradh DRM_DEBUG_DRIVER("Changing brightness to %d\n",
471efa246c0Sriastradh req.backlight_level);
472efa246c0Sriastradh
473efa246c0Sriastradh amdgpu_display_backlight_set_level(adev, enc, req.backlight_level);
474efa246c0Sriastradh
475efa246c0Sriastradh #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
476efa246c0Sriastradh backlight_force_update(dig->bl_dev,
477efa246c0Sriastradh BACKLIGHT_UPDATE_HOTKEY);
478efa246c0Sriastradh #endif
479efa246c0Sriastradh }
480efa246c0Sriastradh }
48141ec0267Sriastradh if (req.pending & ATIF_DGPU_DISPLAY_EVENT) {
48241ec0267Sriastradh if (adev->flags & AMD_IS_PX) {
48341ec0267Sriastradh pm_runtime_get_sync(adev->ddev->dev);
48441ec0267Sriastradh /* Just fire off a uevent and let userspace tell us what to do */
48541ec0267Sriastradh drm_helper_hpd_irq_event(adev->ddev);
48641ec0267Sriastradh pm_runtime_mark_last_busy(adev->ddev->dev);
48741ec0267Sriastradh pm_runtime_put_autosuspend(adev->ddev->dev);
48841ec0267Sriastradh }
48941ec0267Sriastradh }
490efa246c0Sriastradh /* TODO: check other events */
49141ec0267Sriastradh }
492efa246c0Sriastradh
493efa246c0Sriastradh /* We've handled the event, stop the notifier chain. The ACPI interface
494efa246c0Sriastradh * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to
495efa246c0Sriastradh * userspace if the event was generated only to signal a SBIOS
496efa246c0Sriastradh * request.
497efa246c0Sriastradh */
498efa246c0Sriastradh return NOTIFY_BAD;
499efa246c0Sriastradh }
500efa246c0Sriastradh
501*770c9d53Sriastradh #endif /* __NetBSD__ */
502*770c9d53Sriastradh
503efa246c0Sriastradh /* Call the ATCS method
504efa246c0Sriastradh */
505efa246c0Sriastradh /**
506efa246c0Sriastradh * amdgpu_atcs_call - call an ATCS method
507efa246c0Sriastradh *
508efa246c0Sriastradh * @handle: acpi handle
509efa246c0Sriastradh * @function: the ATCS function to execute
510efa246c0Sriastradh * @params: ATCS function params
511efa246c0Sriastradh *
512efa246c0Sriastradh * Executes the requested ATCS function (all asics).
513efa246c0Sriastradh * Returns a pointer to the acpi output buffer.
514efa246c0Sriastradh */
amdgpu_atcs_call(acpi_handle handle,int function,struct acpi_buffer * params)515efa246c0Sriastradh static union acpi_object *amdgpu_atcs_call(acpi_handle handle, int function,
516efa246c0Sriastradh struct acpi_buffer *params)
517efa246c0Sriastradh {
518efa246c0Sriastradh acpi_status status;
519efa246c0Sriastradh union acpi_object atcs_arg_elements[2];
520efa246c0Sriastradh struct acpi_object_list atcs_arg;
521efa246c0Sriastradh struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
522efa246c0Sriastradh
523efa246c0Sriastradh atcs_arg.count = 2;
524efa246c0Sriastradh atcs_arg.pointer = &atcs_arg_elements[0];
525efa246c0Sriastradh
526efa246c0Sriastradh atcs_arg_elements[0].type = ACPI_TYPE_INTEGER;
527efa246c0Sriastradh atcs_arg_elements[0].integer.value = function;
528efa246c0Sriastradh
529efa246c0Sriastradh if (params) {
530efa246c0Sriastradh atcs_arg_elements[1].type = ACPI_TYPE_BUFFER;
531efa246c0Sriastradh atcs_arg_elements[1].buffer.length = params->length;
532efa246c0Sriastradh atcs_arg_elements[1].buffer.pointer = params->pointer;
533efa246c0Sriastradh } else {
534efa246c0Sriastradh /* We need a second fake parameter */
535efa246c0Sriastradh atcs_arg_elements[1].type = ACPI_TYPE_INTEGER;
536efa246c0Sriastradh atcs_arg_elements[1].integer.value = 0;
537efa246c0Sriastradh }
538efa246c0Sriastradh
539efa246c0Sriastradh status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer);
540efa246c0Sriastradh
541efa246c0Sriastradh /* Fail only if calling the method fails and ATIF is supported */
542efa246c0Sriastradh if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
543efa246c0Sriastradh DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n",
544efa246c0Sriastradh acpi_format_exception(status));
545d7495136Sriastradh ACPI_FREE(buffer.pointer);
546efa246c0Sriastradh return NULL;
547efa246c0Sriastradh }
548efa246c0Sriastradh
549efa246c0Sriastradh return buffer.pointer;
550efa246c0Sriastradh }
551efa246c0Sriastradh
552efa246c0Sriastradh /**
553efa246c0Sriastradh * amdgpu_atcs_parse_functions - parse supported functions
554efa246c0Sriastradh *
555efa246c0Sriastradh * @f: supported functions struct
556efa246c0Sriastradh * @mask: supported functions mask from ATCS
557efa246c0Sriastradh *
558efa246c0Sriastradh * Use the supported functions mask from ATCS function
559efa246c0Sriastradh * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions
560efa246c0Sriastradh * are supported (all asics).
561efa246c0Sriastradh */
amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions * f,u32 mask)562efa246c0Sriastradh static void amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions *f, u32 mask)
563efa246c0Sriastradh {
564efa246c0Sriastradh f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED;
565efa246c0Sriastradh f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED;
566efa246c0Sriastradh f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED;
567efa246c0Sriastradh f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED;
568efa246c0Sriastradh }
569efa246c0Sriastradh
570efa246c0Sriastradh /**
571efa246c0Sriastradh * amdgpu_atcs_verify_interface - verify ATCS
572efa246c0Sriastradh *
573efa246c0Sriastradh * @handle: acpi handle
574efa246c0Sriastradh * @atcs: amdgpu atcs struct
575efa246c0Sriastradh *
576efa246c0Sriastradh * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function
577efa246c0Sriastradh * to initialize ATCS and determine what features are supported
578efa246c0Sriastradh * (all asics).
579efa246c0Sriastradh * returns 0 on success, error on failure.
580efa246c0Sriastradh */
amdgpu_atcs_verify_interface(acpi_handle handle,struct amdgpu_atcs * atcs)581efa246c0Sriastradh static int amdgpu_atcs_verify_interface(acpi_handle handle,
582efa246c0Sriastradh struct amdgpu_atcs *atcs)
583efa246c0Sriastradh {
584efa246c0Sriastradh union acpi_object *info;
585efa246c0Sriastradh struct atcs_verify_interface output;
586efa246c0Sriastradh size_t size;
587efa246c0Sriastradh int err = 0;
588efa246c0Sriastradh
589efa246c0Sriastradh info = amdgpu_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL);
590efa246c0Sriastradh if (!info)
591efa246c0Sriastradh return -EIO;
592efa246c0Sriastradh
593efa246c0Sriastradh memset(&output, 0, sizeof(output));
594efa246c0Sriastradh
595efa246c0Sriastradh size = *(u16 *) info->buffer.pointer;
596efa246c0Sriastradh if (size < 8) {
597efa246c0Sriastradh DRM_INFO("ATCS buffer is too small: %zu\n", size);
598efa246c0Sriastradh err = -EINVAL;
599efa246c0Sriastradh goto out;
600efa246c0Sriastradh }
601efa246c0Sriastradh size = min(sizeof(output), size);
602efa246c0Sriastradh
603efa246c0Sriastradh memcpy(&output, info->buffer.pointer, size);
604efa246c0Sriastradh
605efa246c0Sriastradh /* TODO: check version? */
606efa246c0Sriastradh DRM_DEBUG_DRIVER("ATCS version %u\n", output.version);
607efa246c0Sriastradh
608efa246c0Sriastradh amdgpu_atcs_parse_functions(&atcs->functions, output.function_bits);
609efa246c0Sriastradh
610efa246c0Sriastradh out:
611d7495136Sriastradh ACPI_FREE(info);
612efa246c0Sriastradh return err;
613efa246c0Sriastradh }
614efa246c0Sriastradh
615efa246c0Sriastradh /**
616efa246c0Sriastradh * amdgpu_acpi_is_pcie_performance_request_supported
617efa246c0Sriastradh *
618efa246c0Sriastradh * @adev: amdgpu_device pointer
619efa246c0Sriastradh *
620efa246c0Sriastradh * Check if the ATCS pcie_perf_req and pcie_dev_rdy methods
621efa246c0Sriastradh * are supported (all asics).
622efa246c0Sriastradh * returns true if supported, false if not.
623efa246c0Sriastradh */
amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device * adev)624efa246c0Sriastradh bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev)
625efa246c0Sriastradh {
626efa246c0Sriastradh struct amdgpu_atcs *atcs = &adev->atcs;
627efa246c0Sriastradh
628efa246c0Sriastradh if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy)
629efa246c0Sriastradh return true;
630efa246c0Sriastradh
631efa246c0Sriastradh return false;
632efa246c0Sriastradh }
633efa246c0Sriastradh
634efa246c0Sriastradh /**
635efa246c0Sriastradh * amdgpu_acpi_pcie_notify_device_ready
636efa246c0Sriastradh *
637efa246c0Sriastradh * @adev: amdgpu_device pointer
638efa246c0Sriastradh *
639efa246c0Sriastradh * Executes the PCIE_DEVICE_READY_NOTIFICATION method
640efa246c0Sriastradh * (all asics).
641efa246c0Sriastradh * returns 0 on success, error on failure.
642efa246c0Sriastradh */
amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device * adev)643efa246c0Sriastradh int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev)
644efa246c0Sriastradh {
645efa246c0Sriastradh acpi_handle handle;
646efa246c0Sriastradh union acpi_object *info;
647efa246c0Sriastradh struct amdgpu_atcs *atcs = &adev->atcs;
648efa246c0Sriastradh
649efa246c0Sriastradh /* Get the device handle */
650*770c9d53Sriastradh #ifdef __NetBSD__
651*770c9d53Sriastradh const struct pci_attach_args *pa = &adev->pdev->pd_pa;
652*770c9d53Sriastradh struct acpi_devnode *const d =
653*770c9d53Sriastradh acpi_pcidev_find(pci_get_segment(pa->pa_pc),
654*770c9d53Sriastradh pa->pa_bus, pa->pa_device, pa->pa_function);
655*770c9d53Sriastradh if (d == NULL)
656*770c9d53Sriastradh return -EINVAL;
657*770c9d53Sriastradh handle = d->ad_handle;
658*770c9d53Sriastradh #else
659efa246c0Sriastradh handle = ACPI_HANDLE(&adev->pdev->dev);
660*770c9d53Sriastradh #endif
661efa246c0Sriastradh if (!handle)
662efa246c0Sriastradh return -EINVAL;
663efa246c0Sriastradh
664efa246c0Sriastradh if (!atcs->functions.pcie_dev_rdy)
665efa246c0Sriastradh return -EINVAL;
666efa246c0Sriastradh
667efa246c0Sriastradh info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL);
668efa246c0Sriastradh if (!info)
669efa246c0Sriastradh return -EIO;
670efa246c0Sriastradh
671d7495136Sriastradh ACPI_FREE(info);
672efa246c0Sriastradh
673efa246c0Sriastradh return 0;
674efa246c0Sriastradh }
675efa246c0Sriastradh
676efa246c0Sriastradh /**
677efa246c0Sriastradh * amdgpu_acpi_pcie_performance_request
678efa246c0Sriastradh *
679efa246c0Sriastradh * @adev: amdgpu_device pointer
680efa246c0Sriastradh * @perf_req: requested perf level (pcie gen speed)
681efa246c0Sriastradh * @advertise: set advertise caps flag if set
682efa246c0Sriastradh *
683efa246c0Sriastradh * Executes the PCIE_PERFORMANCE_REQUEST method to
684efa246c0Sriastradh * change the pcie gen speed (all asics).
685efa246c0Sriastradh * returns 0 on success, error on failure.
686efa246c0Sriastradh */
amdgpu_acpi_pcie_performance_request(struct amdgpu_device * adev,u8 perf_req,bool advertise)687efa246c0Sriastradh int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
688efa246c0Sriastradh u8 perf_req, bool advertise)
689efa246c0Sriastradh {
690efa246c0Sriastradh acpi_handle handle;
691efa246c0Sriastradh union acpi_object *info;
692efa246c0Sriastradh struct amdgpu_atcs *atcs = &adev->atcs;
693efa246c0Sriastradh struct atcs_pref_req_input atcs_input;
694efa246c0Sriastradh struct atcs_pref_req_output atcs_output;
695efa246c0Sriastradh struct acpi_buffer params;
696efa246c0Sriastradh size_t size;
697efa246c0Sriastradh u32 retry = 3;
698efa246c0Sriastradh
699efa246c0Sriastradh if (amdgpu_acpi_pcie_notify_device_ready(adev))
700efa246c0Sriastradh return -EINVAL;
701efa246c0Sriastradh
702efa246c0Sriastradh /* Get the device handle */
703*770c9d53Sriastradh #ifdef __NetBSD__
704*770c9d53Sriastradh const struct pci_attach_args *pa = &adev->pdev->pd_pa;
705*770c9d53Sriastradh struct acpi_devnode *const d =
706*770c9d53Sriastradh acpi_pcidev_find(pci_get_segment(pa->pa_pc),
707*770c9d53Sriastradh pa->pa_bus, pa->pa_device, pa->pa_function);
708*770c9d53Sriastradh if (d == NULL)
709*770c9d53Sriastradh return -EINVAL;
710*770c9d53Sriastradh handle = d->ad_handle;
711*770c9d53Sriastradh #else
712efa246c0Sriastradh handle = ACPI_HANDLE(&adev->pdev->dev);
713*770c9d53Sriastradh #endif
714efa246c0Sriastradh if (!handle)
715efa246c0Sriastradh return -EINVAL;
716efa246c0Sriastradh
717efa246c0Sriastradh if (!atcs->functions.pcie_perf_req)
718efa246c0Sriastradh return -EINVAL;
719efa246c0Sriastradh
720efa246c0Sriastradh atcs_input.size = sizeof(struct atcs_pref_req_input);
721efa246c0Sriastradh /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */
722efa246c0Sriastradh atcs_input.client_id = adev->pdev->devfn | (adev->pdev->bus->number << 8);
723efa246c0Sriastradh atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK;
724efa246c0Sriastradh atcs_input.flags = ATCS_WAIT_FOR_COMPLETION;
725efa246c0Sriastradh if (advertise)
726efa246c0Sriastradh atcs_input.flags |= ATCS_ADVERTISE_CAPS;
727efa246c0Sriastradh atcs_input.req_type = ATCS_PCIE_LINK_SPEED;
728efa246c0Sriastradh atcs_input.perf_req = perf_req;
729efa246c0Sriastradh
730efa246c0Sriastradh params.length = sizeof(struct atcs_pref_req_input);
731efa246c0Sriastradh params.pointer = &atcs_input;
732efa246c0Sriastradh
733efa246c0Sriastradh while (retry--) {
734efa246c0Sriastradh info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms);
735efa246c0Sriastradh if (!info)
736efa246c0Sriastradh return -EIO;
737efa246c0Sriastradh
738efa246c0Sriastradh memset(&atcs_output, 0, sizeof(atcs_output));
739efa246c0Sriastradh
740efa246c0Sriastradh size = *(u16 *) info->buffer.pointer;
741efa246c0Sriastradh if (size < 3) {
742efa246c0Sriastradh DRM_INFO("ATCS buffer is too small: %zu\n", size);
743d7495136Sriastradh ACPI_FREE(info);
744efa246c0Sriastradh return -EINVAL;
745efa246c0Sriastradh }
746efa246c0Sriastradh size = min(sizeof(atcs_output), size);
747efa246c0Sriastradh
748efa246c0Sriastradh memcpy(&atcs_output, info->buffer.pointer, size);
749efa246c0Sriastradh
750d7495136Sriastradh ACPI_FREE(info);
751efa246c0Sriastradh
752efa246c0Sriastradh switch (atcs_output.ret_val) {
753efa246c0Sriastradh case ATCS_REQUEST_REFUSED:
754efa246c0Sriastradh default:
755efa246c0Sriastradh return -EINVAL;
756efa246c0Sriastradh case ATCS_REQUEST_COMPLETE:
757efa246c0Sriastradh return 0;
758efa246c0Sriastradh case ATCS_REQUEST_IN_PROGRESS:
759efa246c0Sriastradh udelay(10);
760efa246c0Sriastradh break;
761efa246c0Sriastradh }
762efa246c0Sriastradh }
763efa246c0Sriastradh
764efa246c0Sriastradh return 0;
765efa246c0Sriastradh }
766efa246c0Sriastradh
767efa246c0Sriastradh /**
768efa246c0Sriastradh * amdgpu_acpi_event - handle notify events
769efa246c0Sriastradh *
770efa246c0Sriastradh * @nb: notifier block
771efa246c0Sriastradh * @val: val
772efa246c0Sriastradh * @data: acpi event
773efa246c0Sriastradh *
774efa246c0Sriastradh * Calls relevant amdgpu functions in response to various
775efa246c0Sriastradh * acpi events.
776efa246c0Sriastradh * Returns NOTIFY code
777efa246c0Sriastradh */
778*770c9d53Sriastradh #ifndef __NetBSD__ /* XXX amdgpu acpi */
amdgpu_acpi_event(struct notifier_block * nb,unsigned long val,void * data)779efa246c0Sriastradh static int amdgpu_acpi_event(struct notifier_block *nb,
780efa246c0Sriastradh unsigned long val,
781efa246c0Sriastradh void *data)
782efa246c0Sriastradh {
783efa246c0Sriastradh struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, acpi_nb);
784efa246c0Sriastradh struct acpi_bus_event *entry = (struct acpi_bus_event *)data;
785efa246c0Sriastradh
786efa246c0Sriastradh if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) {
787efa246c0Sriastradh if (power_supply_is_system_supplied() > 0)
788efa246c0Sriastradh DRM_DEBUG_DRIVER("pm: AC\n");
789efa246c0Sriastradh else
790efa246c0Sriastradh DRM_DEBUG_DRIVER("pm: DC\n");
791efa246c0Sriastradh
792efa246c0Sriastradh amdgpu_pm_acpi_event_handler(adev);
793efa246c0Sriastradh }
794efa246c0Sriastradh
795efa246c0Sriastradh /* Check for pending SBIOS requests */
796efa246c0Sriastradh return amdgpu_atif_handler(adev, entry);
797efa246c0Sriastradh }
798*770c9d53Sriastradh #endif
799efa246c0Sriastradh
800efa246c0Sriastradh /* Call all ACPI methods here */
801efa246c0Sriastradh /**
802efa246c0Sriastradh * amdgpu_acpi_init - init driver acpi support
803efa246c0Sriastradh *
804efa246c0Sriastradh * @adev: amdgpu_device pointer
805efa246c0Sriastradh *
806efa246c0Sriastradh * Verifies the AMD ACPI interfaces and registers with the acpi
807efa246c0Sriastradh * notifier chain (all asics).
808efa246c0Sriastradh * Returns 0 on success, error on failure.
809efa246c0Sriastradh */
amdgpu_acpi_init(struct amdgpu_device * adev)810efa246c0Sriastradh int amdgpu_acpi_init(struct amdgpu_device *adev)
811efa246c0Sriastradh {
81241ec0267Sriastradh acpi_handle handle, atif_handle;
81341ec0267Sriastradh struct amdgpu_atif *atif;
814efa246c0Sriastradh struct amdgpu_atcs *atcs = &adev->atcs;
815efa246c0Sriastradh int ret;
816efa246c0Sriastradh
817efa246c0Sriastradh /* Get the device handle */
818*770c9d53Sriastradh #ifdef __NetBSD__
819*770c9d53Sriastradh const struct pci_attach_args *pa = &adev->pdev->pd_pa;
820*770c9d53Sriastradh struct acpi_devnode *const d =
821*770c9d53Sriastradh acpi_pcidev_find(pci_get_segment(pa->pa_pc),
822*770c9d53Sriastradh pa->pa_bus, pa->pa_device, pa->pa_function);
823*770c9d53Sriastradh if (d == NULL)
824*770c9d53Sriastradh return -EINVAL;
825*770c9d53Sriastradh handle = d->ad_handle;
826*770c9d53Sriastradh #else
827efa246c0Sriastradh handle = ACPI_HANDLE(&adev->pdev->dev);
828*770c9d53Sriastradh #endif
829efa246c0Sriastradh
830efa246c0Sriastradh if (!adev->bios || !handle)
831efa246c0Sriastradh return 0;
832efa246c0Sriastradh
833efa246c0Sriastradh /* Call the ATCS method */
834efa246c0Sriastradh ret = amdgpu_atcs_verify_interface(handle, atcs);
835efa246c0Sriastradh if (ret) {
836efa246c0Sriastradh DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret);
837efa246c0Sriastradh }
838efa246c0Sriastradh
83941ec0267Sriastradh /* Probe for ATIF, and initialize it if found */
84041ec0267Sriastradh atif_handle = amdgpu_atif_probe_handle(handle);
84141ec0267Sriastradh if (!atif_handle)
84241ec0267Sriastradh goto out;
84341ec0267Sriastradh
84441ec0267Sriastradh atif = kzalloc(sizeof(*atif), GFP_KERNEL);
84541ec0267Sriastradh if (!atif) {
84641ec0267Sriastradh DRM_WARN("Not enough memory to initialize ATIF\n");
847efa246c0Sriastradh goto out;
848efa246c0Sriastradh }
84941ec0267Sriastradh atif->handle = atif_handle;
85041ec0267Sriastradh
85141ec0267Sriastradh /* Call the ATIF method */
85241ec0267Sriastradh ret = amdgpu_atif_verify_interface(atif);
85341ec0267Sriastradh if (ret) {
85441ec0267Sriastradh DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret);
85541ec0267Sriastradh kfree(atif);
85641ec0267Sriastradh goto out;
85741ec0267Sriastradh }
85841ec0267Sriastradh adev->atif = atif;
859efa246c0Sriastradh
860efa246c0Sriastradh if (atif->notifications.brightness_change) {
861efa246c0Sriastradh struct drm_encoder *tmp;
862efa246c0Sriastradh
863efa246c0Sriastradh /* Find the encoder controlling the brightness */
864efa246c0Sriastradh list_for_each_entry(tmp, &adev->ddev->mode_config.encoder_list,
865efa246c0Sriastradh head) {
866efa246c0Sriastradh struct amdgpu_encoder *enc = to_amdgpu_encoder(tmp);
867efa246c0Sriastradh
868efa246c0Sriastradh if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
869efa246c0Sriastradh enc->enc_priv) {
870efa246c0Sriastradh struct amdgpu_encoder_atom_dig *dig = enc->enc_priv;
871efa246c0Sriastradh if (dig->bl_dev) {
872efa246c0Sriastradh atif->encoder_for_bl = enc;
873efa246c0Sriastradh break;
874efa246c0Sriastradh }
875efa246c0Sriastradh }
876efa246c0Sriastradh }
877efa246c0Sriastradh }
878efa246c0Sriastradh
879efa246c0Sriastradh if (atif->functions.sbios_requests && !atif->functions.system_params) {
880efa246c0Sriastradh /* XXX check this workraround, if sbios request function is
881efa246c0Sriastradh * present we have to see how it's configured in the system
882efa246c0Sriastradh * params
883efa246c0Sriastradh */
884efa246c0Sriastradh atif->functions.system_params = true;
885efa246c0Sriastradh }
886efa246c0Sriastradh
887efa246c0Sriastradh if (atif->functions.system_params) {
88841ec0267Sriastradh ret = amdgpu_atif_get_notification_params(atif);
889efa246c0Sriastradh if (ret) {
890efa246c0Sriastradh DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n",
891efa246c0Sriastradh ret);
892efa246c0Sriastradh /* Disable notification */
893efa246c0Sriastradh atif->notification_cfg.enabled = false;
894efa246c0Sriastradh }
895efa246c0Sriastradh }
896efa246c0Sriastradh
89741ec0267Sriastradh if (atif->functions.query_backlight_transfer_characteristics) {
89841ec0267Sriastradh ret = amdgpu_atif_query_backlight_caps(atif);
89941ec0267Sriastradh if (ret) {
90041ec0267Sriastradh DRM_DEBUG_DRIVER("Call to QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS failed: %d\n",
90141ec0267Sriastradh ret);
90241ec0267Sriastradh atif->backlight_caps.caps_valid = false;
90341ec0267Sriastradh }
90441ec0267Sriastradh } else {
90541ec0267Sriastradh atif->backlight_caps.caps_valid = false;
90641ec0267Sriastradh }
90741ec0267Sriastradh
908efa246c0Sriastradh out:
909*770c9d53Sriastradh #ifndef __NetBSD__ /* XXX amdgpu acpi */
910efa246c0Sriastradh adev->acpi_nb.notifier_call = amdgpu_acpi_event;
911efa246c0Sriastradh register_acpi_notifier(&adev->acpi_nb);
912*770c9d53Sriastradh #endif
913efa246c0Sriastradh
914efa246c0Sriastradh return ret;
915efa246c0Sriastradh }
916efa246c0Sriastradh
amdgpu_acpi_get_backlight_caps(struct amdgpu_device * adev,struct amdgpu_dm_backlight_caps * caps)91741ec0267Sriastradh void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev,
91841ec0267Sriastradh struct amdgpu_dm_backlight_caps *caps)
91941ec0267Sriastradh {
92041ec0267Sriastradh if (!adev->atif) {
92141ec0267Sriastradh caps->caps_valid = false;
92241ec0267Sriastradh return;
92341ec0267Sriastradh }
92441ec0267Sriastradh caps->caps_valid = adev->atif->backlight_caps.caps_valid;
92541ec0267Sriastradh caps->min_input_signal = adev->atif->backlight_caps.min_input_signal;
92641ec0267Sriastradh caps->max_input_signal = adev->atif->backlight_caps.max_input_signal;
92741ec0267Sriastradh }
92841ec0267Sriastradh
929efa246c0Sriastradh /**
930efa246c0Sriastradh * amdgpu_acpi_fini - tear down driver acpi support
931efa246c0Sriastradh *
932efa246c0Sriastradh * @adev: amdgpu_device pointer
933efa246c0Sriastradh *
934efa246c0Sriastradh * Unregisters with the acpi notifier chain (all asics).
935efa246c0Sriastradh */
amdgpu_acpi_fini(struct amdgpu_device * adev)936efa246c0Sriastradh void amdgpu_acpi_fini(struct amdgpu_device *adev)
937efa246c0Sriastradh {
938*770c9d53Sriastradh #ifndef __NetBSD__ /* XXX radeon acpi */
939efa246c0Sriastradh unregister_acpi_notifier(&adev->acpi_nb);
940*770c9d53Sriastradh #endif
94141ec0267Sriastradh kfree(adev->atif);
942efa246c0Sriastradh }
943