drm/radeon: implement radeon_atif_verify_interface
[platform/kernel/linux-arm64.git] / drivers / gpu / drm / radeon / radeon_acpi.c
1 /*
2  * Copyright 2012 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23
24 #include <linux/pci.h>
25 #include <linux/acpi.h>
26 #include <linux/slab.h>
27 #include <acpi/acpi_drivers.h>
28 #include <acpi/acpi_bus.h>
29
30 #include "drmP.h"
31 #include "drm.h"
32 #include "drm_sarea.h"
33 #include "drm_crtc_helper.h"
34 #include "radeon.h"
35 #include "radeon_acpi.h"
36
37 #include <linux/vga_switcheroo.h>
38
39 struct atif_verify_interface {
40         u16 size;               /* structure size in bytes (includes size field) */
41         u16 version;            /* version */
42         u32 notification_mask;  /* supported notifications mask */
43         u32 function_bits;      /* supported functions bit vector */
44 } __packed;
45
46 /* Call the ATIF method
47  */
48 static union acpi_object *radeon_atif_call(acpi_handle handle, int function,
49                 struct acpi_buffer *params)
50 {
51         acpi_status status;
52         union acpi_object atif_arg_elements[2];
53         struct acpi_object_list atif_arg;
54         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
55
56         atif_arg.count = 2;
57         atif_arg.pointer = &atif_arg_elements[0];
58
59         atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
60         atif_arg_elements[0].integer.value = function;
61
62         if (params) {
63                 atif_arg_elements[1].type = ACPI_TYPE_BUFFER;
64                 atif_arg_elements[1].buffer.length = params->length;
65                 atif_arg_elements[1].buffer.pointer = params->pointer;
66         } else {
67                 /* We need a second fake parameter */
68                 atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
69                 atif_arg_elements[1].integer.value = 0;
70         }
71
72         status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
73
74         /* Fail only if calling the method fails and ATIF is supported */
75         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
76                 DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
77                                  acpi_format_exception(status));
78                 kfree(buffer.pointer);
79                 return NULL;
80         }
81
82         return buffer.pointer;
83 }
84
85 static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask)
86 {
87         n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED;
88         n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED;
89         n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
90         n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
91         n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
92         n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED;
93         n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED;
94         n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
95         n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
96 }
97
98 static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask)
99 {
100         f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
101         f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
102         f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
103         f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED;
104         f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
105         f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
106         f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
107         f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
108         f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
109         f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED;
110 }
111
112 static int radeon_atif_verify_interface(acpi_handle handle,
113                 struct radeon_atif *atif)
114 {
115         union acpi_object *info;
116         struct atif_verify_interface output;
117         size_t size;
118         int err = 0;
119
120         info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
121         if (!info)
122                 return -EIO;
123
124         memset(&output, 0, sizeof(output));
125
126         size = *(u16 *) info->buffer.pointer;
127         if (size < 12) {
128                 DRM_INFO("ATIF buffer is too small: %lu\n", size);
129                 err = -EINVAL;
130                 goto out;
131         }
132         size = min(sizeof(output), size);
133
134         memcpy(&output, info->buffer.pointer, size);
135
136         /* TODO: check version? */
137         DRM_DEBUG_DRIVER("ATIF version %u\n", output.version);
138
139         radeon_atif_parse_notification(&atif->notifications, output.notification_mask);
140         radeon_atif_parse_functions(&atif->functions, output.function_bits);
141
142 out:
143         kfree(info);
144         return err;
145 }
146
147 /* Call all ACPI methods here */
148 int radeon_acpi_init(struct radeon_device *rdev)
149 {
150         acpi_handle handle;
151         int ret;
152
153         /* Get the device handle */
154         handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
155
156         /* No need to proceed if we're sure that ATIF is not supported */
157         if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle)
158                 return 0;
159
160         /* Call the ATIF method */
161         ret = radeon_atif_verify_interface(handle, &rdev->atif);
162         if (ret)
163                 DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret);
164
165         return ret;
166 }
167