1 /*
2 * Copyright 2018 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 #include "igt.h"
24 #include "drmtest.h"
25 #include "igt_kms.h"
26 #include <limits.h>
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <time.h>
34
35 #define BACKLIGHT_PATH "/sys/class/backlight/amdgpu_bl0"
36
37 typedef struct data {
38 igt_display_t display;
39 int drm_fd;
40 int debugfs;
41 uint32_t output_id;
42 uint32_t abm_prop_id;
43 } data_t;
44
read_current_backlight_pwm(int debugfs_dir)45 static int read_current_backlight_pwm(int debugfs_dir)
46 {
47 char buf[20];
48
49 igt_debugfs_simple_read(debugfs_dir, "amdgpu_current_backlight_pwm",
50 buf, sizeof(buf));
51
52 return strtol(buf, NULL, 0);
53 }
54
read_target_backlight_pwm(int debugfs_dir)55 static int read_target_backlight_pwm(int debugfs_dir)
56 {
57 char buf[20];
58
59 igt_debugfs_simple_read(debugfs_dir, "amdgpu_target_backlight_pwm",
60 buf, sizeof(buf));
61
62 return strtol(buf, NULL, 0);
63 }
64
backlight_write_brightness(int value)65 static int backlight_write_brightness(int value)
66 {
67 int fd;
68 char full[PATH_MAX];
69 char src[64];
70 int len;
71
72 igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "brightness") < PATH_MAX);
73 fd = open(full, O_WRONLY);
74 if (fd == -1)
75 return -errno;
76
77 len = snprintf(src, sizeof(src), "%i", value);
78 len = write(fd, src, len);
79 close(fd);
80
81 if (len < 0)
82 return len;
83
84 return 0;
85 }
86
set_abm_level(data_t * data,int level)87 static void set_abm_level(data_t *data, int level)
88 {
89 uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
90 int ret;
91
92 ret = drmModeObjectSetProperty(data->drm_fd, data->output_id, type,
93 data->abm_prop_id, level);
94 igt_assert_eq(ret, 0);
95 }
96
backlight_read_max_brightness(int * result)97 static int backlight_read_max_brightness(int *result)
98 {
99 int fd;
100 char full[PATH_MAX];
101 char dst[64];
102 int r, e;
103
104 igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, "max_brightness") < PATH_MAX);
105
106 fd = open(full, O_RDONLY);
107 if (fd == -1)
108 return -errno;
109
110 r = read(fd, dst, sizeof(dst));
111 e = errno;
112 close(fd);
113
114 if (r < 0)
115 return -e;
116
117 errno = 0;
118 *result = strtol(dst, NULL, 10);
119 return errno;
120 }
121
test_init(data_t * data)122 static void test_init(data_t *data)
123 {
124 igt_display_t *display = &data->display;
125 int ret, i;
126 char buf[20];
127 bool abm_prop_exists;
128 uint32_t type = DRM_MODE_OBJECT_CONNECTOR;
129
130 ret = igt_debugfs_simple_read(data->debugfs, "amdgpu_current_backlight_pwm",
131 buf, sizeof(buf));
132
133 if (ret < 0)
134 igt_skip("No current backlight debugfs entry.\n");
135
136 ret = igt_debugfs_simple_read(data->debugfs, "amdgpu_target_backlight_pwm",
137 buf, sizeof(buf));
138
139 if (ret < 0)
140 igt_skip("No target backlight debugfs entry.\n");
141
142 abm_prop_exists = false;
143
144 for (i = 0; i < display->n_outputs; i++) {
145 data->output_id = display->outputs[i].id;
146
147 abm_prop_exists = kmstest_get_property(
148 data->drm_fd, data->output_id, type, "abm level",
149 &data->abm_prop_id, NULL, NULL);
150
151 if (abm_prop_exists)
152 break;
153 }
154
155 if (!abm_prop_exists)
156 igt_skip("No abm level property on any connector.\n");
157 }
158
159
backlight_dpms_cycle(data_t * data,igt_output_t * output)160 static void backlight_dpms_cycle(data_t *data, igt_output_t *output)
161 {
162 int ret;
163 int max_brightness;
164 int pwm_1, pwm_2;
165
166 ret = backlight_read_max_brightness(&max_brightness);
167 igt_assert_eq(ret, 0);
168
169 set_abm_level(data, 0);
170 backlight_write_brightness(max_brightness / 2);
171 usleep(100000);
172 pwm_1 = read_target_backlight_pwm(data->debugfs);
173
174 kmstest_set_connector_dpms(data->drm_fd, output->config.connector, DRM_MODE_DPMS_OFF);
175 kmstest_set_connector_dpms(data->drm_fd, output->config.connector, DRM_MODE_DPMS_ON);
176 usleep(100000);
177 pwm_2 = read_target_backlight_pwm(data->debugfs);
178 igt_assert_eq(pwm_1, pwm_2);
179 }
180
backlight_monotonic_basic(data_t * data)181 static void backlight_monotonic_basic(data_t *data)
182 {
183 int ret;
184 int max_brightness;
185 int prev_pwm, pwm;
186 int brightness_step;
187 int brightness;
188
189 ret = backlight_read_max_brightness(&max_brightness);
190 igt_assert_eq(ret, 0);
191
192 brightness_step = max_brightness / 10;
193
194 set_abm_level(data, 0);
195 backlight_write_brightness(max_brightness);
196 usleep(100000);
197 prev_pwm = read_target_backlight_pwm(data->debugfs);
198 for (brightness = max_brightness - brightness_step;
199 brightness > 0;
200 brightness -= brightness_step) {
201 backlight_write_brightness(brightness);
202 usleep(100000);
203 pwm = read_target_backlight_pwm(data->debugfs);
204 igt_assert(pwm < prev_pwm);
205 prev_pwm = pwm;
206 }
207
208 }
209
backlight_monotonic_abm(data_t * data)210 static void backlight_monotonic_abm(data_t *data)
211 {
212 int ret, i;
213 int max_brightness;
214 int prev_pwm, pwm;
215 int brightness_step;
216 int brightness;
217
218 ret = backlight_read_max_brightness(&max_brightness);
219 igt_assert_eq(ret, 0);
220
221 brightness_step = max_brightness / 10;
222 for (i = 1; i < 5; i++) {
223 set_abm_level(data, i);
224 backlight_write_brightness(max_brightness);
225 usleep(100000);
226 prev_pwm = read_target_backlight_pwm(data->debugfs);
227 for (brightness = max_brightness - brightness_step;
228 brightness > 0;
229 brightness -= brightness_step) {
230 backlight_write_brightness(brightness);
231 usleep(100000);
232 pwm = read_target_backlight_pwm(data->debugfs);
233 igt_assert(pwm < prev_pwm);
234 prev_pwm = pwm;
235 }
236 }
237 }
238
abm_enabled(data_t * data)239 static void abm_enabled(data_t *data)
240 {
241 int ret, i;
242 int max_brightness;
243 int pwm, prev_pwm, pwm_without_abm;
244
245 ret = backlight_read_max_brightness(&max_brightness);
246 igt_assert_eq(ret, 0);
247
248 set_abm_level(data, 0);
249 backlight_write_brightness(max_brightness);
250 usleep(100000);
251 prev_pwm = read_target_backlight_pwm(data->debugfs);
252 pwm_without_abm = prev_pwm;
253
254 for (i = 1; i < 5; i++) {
255 set_abm_level(data, i);
256 usleep(100000);
257 pwm = read_target_backlight_pwm(data->debugfs);
258 igt_assert(pwm <= prev_pwm);
259 igt_assert(pwm < pwm_without_abm);
260 prev_pwm = pwm;
261 }
262
263 }
264
abm_gradual(data_t * data)265 static void abm_gradual(data_t *data)
266 {
267 int ret, i;
268 int convergence_delay = 15;
269 int prev_pwm, pwm, curr;
270 int max_brightness;
271
272 ret = backlight_read_max_brightness(&max_brightness);
273
274 igt_assert_eq(ret, 0);
275
276 set_abm_level(data, 0);
277 backlight_write_brightness(max_brightness);
278
279 sleep(convergence_delay);
280 prev_pwm = read_target_backlight_pwm(data->debugfs);
281 curr = read_current_backlight_pwm(data->debugfs);
282
283 igt_assert_eq(prev_pwm, curr);
284 set_abm_level(data, 4);
285 for (i = 0; i < 10; i++) {
286 usleep(100000);
287 pwm = read_current_backlight_pwm(data->debugfs);
288 igt_assert(pwm < prev_pwm);
289 prev_pwm = pwm;
290 }
291
292 sleep(convergence_delay - 1);
293
294 prev_pwm = read_target_backlight_pwm(data->debugfs);
295 curr = read_current_backlight_pwm(data->debugfs);
296
297 igt_assert_eq(prev_pwm, curr);
298 }
299
300 igt_main
301 {
302 data_t data = { 0 };
303 enum pipe pipe;
304 igt_output_t *output;
305
306 igt_skip_on_simulation();
307
308 igt_fixture {
309 data.drm_fd = drm_open_driver_master(DRIVER_AMDGPU);
310
311 if (data.drm_fd == -1)
312 igt_skip("Not an amdgpu driver.\n");
313
314 data.debugfs = igt_debugfs_dir(data.drm_fd);
315
316 kmstest_set_vt_graphics_mode();
317
318 igt_display_require(&data.display, data.drm_fd);
319
320 test_init(&data);
321
322 for_each_pipe_with_valid_output(&data.display, pipe, output) {
323 if (output->config.connector->connector_type == DRM_MODE_CONNECTOR_eDP)
324 break;
325 }
326 }
327
328 igt_subtest("dpms_cycle")
329 backlight_dpms_cycle(&data, output);
330 igt_subtest("backlight_monotonic_basic")
331 backlight_monotonic_basic(&data);
332 igt_subtest("backlight_monotonic_abm")
333 backlight_monotonic_abm(&data);
334 igt_subtest("abm_enabled")
335 abm_enabled(&data);
336 igt_subtest("abm_gradual")
337 abm_gradual(&data);
338
339 igt_fixture {
340 igt_display_fini(&data.display);
341 }
342 }
343