blob: 0454eccc9c032751707771c34f5925a446c751f5 [file] [log] [blame]
Alex Deucherefd4e412012-07-31 17:18:17 -04001/*
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
Alberto Miloned7a29522010-07-06 11:40:24 -040024#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"
Alex Deucher9e05b2f2012-07-18 13:28:52 -040035#include "radeon_acpi.h"
Alberto Miloned7a29522010-07-06 11:40:24 -040036
37#include <linux/vga_switcheroo.h>
38
Luca Tettamantifd64ca82012-08-16 11:11:18 -040039struct 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
Luca Tettamantice3cf822012-07-30 21:16:06 +020046struct atif_system_params {
47 u16 size;
48 u32 valid_mask;
49 u32 flags;
50 u8 command_code;
51} __packed;
52
53#define ATIF_NOTIFY_MASK 0x3
54#define ATIF_NOTIFY_NONE 0
55#define ATIF_NOTIFY_81 1
56#define ATIF_NOTIFY_N 2
57
Alberto Miloned7a29522010-07-06 11:40:24 -040058/* Call the ATIF method
Alberto Miloned7a29522010-07-06 11:40:24 -040059 */
Luca Tettamanti86504672012-07-29 17:04:43 +020060static union acpi_object *radeon_atif_call(acpi_handle handle, int function,
61 struct acpi_buffer *params)
Alberto Miloned7a29522010-07-06 11:40:24 -040062{
63 acpi_status status;
64 union acpi_object atif_arg_elements[2];
65 struct acpi_object_list atif_arg;
Luca Tettamanti86504672012-07-29 17:04:43 +020066 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
Alberto Miloned7a29522010-07-06 11:40:24 -040067
68 atif_arg.count = 2;
69 atif_arg.pointer = &atif_arg_elements[0];
70
71 atif_arg_elements[0].type = ACPI_TYPE_INTEGER;
Luca Tettamanti86504672012-07-29 17:04:43 +020072 atif_arg_elements[0].integer.value = function;
73
74 if (params) {
75 atif_arg_elements[1].type = ACPI_TYPE_BUFFER;
76 atif_arg_elements[1].buffer.length = params->length;
77 atif_arg_elements[1].buffer.pointer = params->pointer;
78 } else {
79 /* We need a second fake parameter */
80 atif_arg_elements[1].type = ACPI_TYPE_INTEGER;
81 atif_arg_elements[1].integer.value = 0;
82 }
Alberto Miloned7a29522010-07-06 11:40:24 -040083
84 status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer);
85
86 /* Fail only if calling the method fails and ATIF is supported */
87 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
Jean Delvarebc96f942011-11-30 17:26:36 +010088 DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n",
89 acpi_format_exception(status));
Alberto Miloned7a29522010-07-06 11:40:24 -040090 kfree(buffer.pointer);
Luca Tettamanti86504672012-07-29 17:04:43 +020091 return NULL;
Alberto Miloned7a29522010-07-06 11:40:24 -040092 }
93
Luca Tettamanti86504672012-07-29 17:04:43 +020094 return buffer.pointer;
Alberto Miloned7a29522010-07-06 11:40:24 -040095}
96
Luca Tettamantifd64ca82012-08-16 11:11:18 -040097static void radeon_atif_parse_notification(struct radeon_atif_notifications *n, u32 mask)
98{
99 n->display_switch = mask & ATIF_DISPLAY_SWITCH_REQUEST_SUPPORTED;
100 n->expansion_mode_change = mask & ATIF_EXPANSION_MODE_CHANGE_REQUEST_SUPPORTED;
101 n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED;
102 n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED;
103 n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED;
104 n->display_conf_change = mask & ATIF_DISPLAY_CONF_CHANGE_REQUEST_SUPPORTED;
105 n->px_gfx_switch = mask & ATIF_PX_GFX_SWITCH_REQUEST_SUPPORTED;
106 n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED;
107 n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED;
108}
109
110static void radeon_atif_parse_functions(struct radeon_atif_functions *f, u32 mask)
111{
112 f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED;
113 f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED;
114 f->select_active_disp = mask & ATIF_SELECT_ACTIVE_DISPLAYS_SUPPORTED;
115 f->lid_state = mask & ATIF_GET_LID_STATE_SUPPORTED;
116 f->get_tv_standard = mask & ATIF_GET_TV_STANDARD_FROM_CMOS_SUPPORTED;
117 f->set_tv_standard = mask & ATIF_SET_TV_STANDARD_IN_CMOS_SUPPORTED;
118 f->get_panel_expansion_mode = mask & ATIF_GET_PANEL_EXPANSION_MODE_FROM_CMOS_SUPPORTED;
119 f->set_panel_expansion_mode = mask & ATIF_SET_PANEL_EXPANSION_MODE_IN_CMOS_SUPPORTED;
120 f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED;
121 f->graphics_device_types = mask & ATIF_GET_GRAPHICS_DEVICE_TYPES_SUPPORTED;
122}
123
124static int radeon_atif_verify_interface(acpi_handle handle,
125 struct radeon_atif *atif)
126{
127 union acpi_object *info;
128 struct atif_verify_interface output;
129 size_t size;
130 int err = 0;
131
132 info = radeon_atif_call(handle, ATIF_FUNCTION_VERIFY_INTERFACE, NULL);
133 if (!info)
134 return -EIO;
135
136 memset(&output, 0, sizeof(output));
137
138 size = *(u16 *) info->buffer.pointer;
139 if (size < 12) {
140 DRM_INFO("ATIF buffer is too small: %lu\n", size);
141 err = -EINVAL;
142 goto out;
143 }
144 size = min(sizeof(output), size);
145
146 memcpy(&output, info->buffer.pointer, size);
147
148 /* TODO: check version? */
149 DRM_DEBUG_DRIVER("ATIF version %u\n", output.version);
150
151 radeon_atif_parse_notification(&atif->notifications, output.notification_mask);
152 radeon_atif_parse_functions(&atif->functions, output.function_bits);
153
154out:
155 kfree(info);
156 return err;
157}
158
Luca Tettamantice3cf822012-07-30 21:16:06 +0200159static int radeon_atif_get_notification_params(acpi_handle handle,
160 struct radeon_atif_notification_cfg *n)
161{
162 union acpi_object *info;
163 struct atif_system_params params;
164 size_t size;
165 int err = 0;
166
167 info = radeon_atif_call(handle, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, NULL);
168 if (!info) {
169 err = -EIO;
170 goto out;
171 }
172
173 size = *(u16 *) info->buffer.pointer;
174 if (size < 10) {
175 err = -EINVAL;
176 goto out;
177 }
178
179 memset(&params, 0, sizeof(params));
180 size = min(sizeof(params), size);
181 memcpy(&params, info->buffer.pointer, size);
182
183 params.flags = params.flags & params.valid_mask;
184
185 if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) {
186 n->enabled = false;
187 n->command_code = 0;
188 } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) {
189 n->enabled = true;
190 n->command_code = 0x81;
191 } else {
192 if (size < 11) {
193 err = -EINVAL;
194 goto out;
195 }
196 n->enabled = true;
197 n->command_code = params.command_code;
198 }
199
200out:
201 kfree(info);
202 return err;
203}
204
Alberto Miloned7a29522010-07-06 11:40:24 -0400205/* Call all ACPI methods here */
206int radeon_acpi_init(struct radeon_device *rdev)
207{
208 acpi_handle handle;
Luca Tettamantice3cf822012-07-30 21:16:06 +0200209 struct radeon_atif *atif = &rdev->atif;
Luca Tettamantifd64ca82012-08-16 11:11:18 -0400210 int ret;
Alberto Miloned7a29522010-07-06 11:40:24 -0400211
Alberto Miloned7a29522010-07-06 11:40:24 -0400212 /* Get the device handle */
213 handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
214
Jean Delvare48cc9b22011-11-30 17:36:39 +0100215 /* No need to proceed if we're sure that ATIF is not supported */
216 if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle)
217 return 0;
218
Alberto Miloned7a29522010-07-06 11:40:24 -0400219 /* Call the ATIF method */
Luca Tettamantice3cf822012-07-30 21:16:06 +0200220 ret = radeon_atif_verify_interface(handle, atif);
221 if (ret) {
Luca Tettamantifd64ca82012-08-16 11:11:18 -0400222 DRM_DEBUG_DRIVER("Call to verify_interface failed: %d\n", ret);
Luca Tettamantice3cf822012-07-30 21:16:06 +0200223 goto out;
224 }
Alberto Miloned7a29522010-07-06 11:40:24 -0400225
Luca Tettamantice3cf822012-07-30 21:16:06 +0200226 if (atif->functions.sbios_requests && !atif->functions.system_params) {
227 /* XXX check this workraround, if sbios request function is
228 * present we have to see how it's configured in the system
229 * params
230 */
231 atif->functions.system_params = true;
232 }
233
234 if (atif->functions.system_params) {
235 ret = radeon_atif_get_notification_params(handle,
236 &atif->notification_cfg);
237 if (ret) {
238 DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n",
239 ret);
240 /* Disable notification */
241 atif->notification_cfg.enabled = false;
242 }
243 }
244
245out:
Luca Tettamanti86504672012-07-29 17:04:43 +0200246 return ret;
Alberto Miloned7a29522010-07-06 11:40:24 -0400247}
248