1 /*
2  * Copyright © 2013 Intel Corporation
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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 
25 #include "igt.h"
26 #include "igt_sysfs.h"
27 #include "igt_psr.h"
28 #include <errno.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include "intel_bufmgr.h"
33 
34 enum operations {
35 	PAGE_FLIP,
36 	MMAP_GTT,
37 	MMAP_CPU,
38 	BLT,
39 	RENDER,
40 	PLANE_MOVE,
41 	PLANE_ONOFF,
42 };
43 
op_str(enum operations op)44 static const char *op_str(enum operations op)
45 {
46 	static const char * const name[] = {
47 		[PAGE_FLIP] = "page_flip",
48 		[MMAP_GTT] = "mmap_gtt",
49 		[MMAP_CPU] = "mmap_cpu",
50 		[BLT] = "blt",
51 		[RENDER] = "render",
52 		[PLANE_MOVE] = "plane_move",
53 		[PLANE_ONOFF] = "plane_onoff",
54 	};
55 
56 	return name[op];
57 }
58 
59 typedef struct {
60 	int drm_fd;
61 	int debugfs_fd;
62 	enum operations op;
63 	int test_plane_id;
64 	enum psr_mode op_psr_mode;
65 	uint32_t devid;
66 	uint32_t crtc_id;
67 	igt_display_t display;
68 	drm_intel_bufmgr *bufmgr;
69 	struct igt_fb fb_green, fb_white;
70 	igt_plane_t *test_plane;
71 	int mod_size;
72 	int mod_stride;
73 	drmModeModeInfo *mode;
74 	igt_output_t *output;
75 	bool with_psr_disabled;
76 	bool supports_psr2;
77 } data_t;
78 
create_cursor_fb(data_t * data)79 static void create_cursor_fb(data_t *data)
80 {
81 	cairo_t *cr;
82 	uint32_t fb_id;
83 
84 	fb_id = igt_create_fb(data->drm_fd, 64, 64,
85 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
86 			      &data->fb_white);
87 	igt_assert(fb_id);
88 
89 	cr = igt_get_cairo_ctx(data->drm_fd, &data->fb_white);
90 	igt_paint_color_alpha(cr, 0, 0, 64, 64, 1.0, 1.0, 1.0, 1.0);
91 	igt_put_cairo_ctx(data->drm_fd, &data->fb_white, cr);
92 }
93 
setup_output(data_t * data)94 static void setup_output(data_t *data)
95 {
96 	igt_display_t *display = &data->display;
97 	igt_output_t *output;
98 	enum pipe pipe;
99 
100 	for_each_pipe_with_valid_output(display, pipe, output) {
101 		drmModeConnectorPtr c = output->config.connector;
102 
103 		if (c->connector_type != DRM_MODE_CONNECTOR_eDP)
104 			continue;
105 
106 		igt_output_set_pipe(output, pipe);
107 		data->crtc_id = output->config.crtc->crtc_id;
108 		data->output = output;
109 		data->mode = igt_output_get_mode(output);
110 
111 		return;
112 	}
113 }
114 
display_init(data_t * data)115 static void display_init(data_t *data)
116 {
117 	igt_display_require(&data->display, data->drm_fd);
118 	setup_output(data);
119 }
120 
display_fini(data_t * data)121 static void display_fini(data_t *data)
122 {
123 	igt_display_fini(&data->display);
124 }
125 
fill_blt(data_t * data,uint32_t handle,unsigned char color)126 static void fill_blt(data_t *data, uint32_t handle, unsigned char color)
127 {
128 	drm_intel_bo *dst = gem_handle_to_libdrm_bo(data->bufmgr,
129 						    data->drm_fd,
130 						    "", handle);
131 	struct intel_batchbuffer *batch;
132 
133 	batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
134 	igt_assert(batch);
135 
136 	COLOR_BLIT_COPY_BATCH_START(0);
137 	OUT_BATCH((1 << 24) | (0xf0 << 16) | 0);
138 	OUT_BATCH(0);
139 	OUT_BATCH(0xfff << 16 | 0xfff);
140 	OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
141 	OUT_BATCH(color);
142 	ADVANCE_BATCH();
143 
144 	intel_batchbuffer_flush(batch);
145 	intel_batchbuffer_free(batch);
146 
147 	gem_bo_busy(data->drm_fd, handle);
148 }
149 
scratch_buf_init(struct igt_buf * buf,drm_intel_bo * bo,int size,int stride)150 static void scratch_buf_init(struct igt_buf *buf, drm_intel_bo *bo,
151 			     int size, int stride)
152 {
153 	memset(buf, 0, sizeof(*buf));
154 
155 	buf->bo = bo;
156 	buf->stride = stride;
157 	buf->tiling = I915_TILING_X;
158 	buf->size = size;
159 	buf->bpp = 32;
160 }
161 
fill_render(data_t * data,uint32_t handle,unsigned char color)162 static void fill_render(data_t *data, uint32_t handle, unsigned char color)
163 {
164 	drm_intel_bo *src, *dst;
165 	struct intel_batchbuffer *batch;
166 	struct igt_buf src_buf, dst_buf;
167 	const uint8_t buf[4] = { color, color, color, color };
168 	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(data->devid);
169 
170 	igt_skip_on(!rendercopy);
171 
172 	dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
173 	igt_assert(dst);
174 
175 	src = drm_intel_bo_alloc(data->bufmgr, "", data->mod_size, 4096);
176 	igt_assert(src);
177 
178 	gem_write(data->drm_fd, src->handle, 0, buf, 4);
179 
180 	scratch_buf_init(&src_buf, src, data->mod_size, data->mod_stride);
181 	scratch_buf_init(&dst_buf, dst, data->mod_size, data->mod_stride);
182 
183 	batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
184 	igt_assert(batch);
185 
186 	rendercopy(batch, NULL,
187 		   &src_buf, 0, 0, 0xff, 0xff,
188 		   &dst_buf, 0, 0);
189 
190 	intel_batchbuffer_free(batch);
191 
192 	gem_bo_busy(data->drm_fd, handle);
193 }
194 
sink_support(data_t * data,enum psr_mode mode)195 static bool sink_support(data_t *data, enum psr_mode mode)
196 {
197 	return data->with_psr_disabled ||
198 	       psr_sink_support(data->debugfs_fd, mode);
199 }
200 
psr_wait_entry_if_enabled(data_t * data)201 static bool psr_wait_entry_if_enabled(data_t *data)
202 {
203 	if (data->with_psr_disabled)
204 		return true;
205 
206 	return psr_wait_entry(data->debugfs_fd, data->op_psr_mode);
207 }
208 
psr_wait_update_if_enabled(data_t * data)209 static bool psr_wait_update_if_enabled(data_t *data)
210 {
211 	if (data->with_psr_disabled)
212 		return true;
213 
214 	return psr_wait_update(data->debugfs_fd, data->op_psr_mode);
215 }
216 
psr_enable_if_enabled(data_t * data)217 static bool psr_enable_if_enabled(data_t *data)
218 {
219 	if (data->with_psr_disabled)
220 		return true;
221 
222 	return psr_enable(data->debugfs_fd, data->op_psr_mode);
223 }
224 
manual(const char * expected)225 static inline void manual(const char *expected)
226 {
227 	igt_debug_manual_check("all", expected);
228 }
229 
drrs_disabled(data_t * data)230 static bool drrs_disabled(data_t *data)
231 {
232 	char buf[512];
233 
234 	igt_debugfs_simple_read(data->debugfs_fd, "i915_drrs_status",
235 			 buf, sizeof(buf));
236 
237 	return !strstr(buf, "DRRS Supported: Yes\n");
238 }
239 
run_test(data_t * data)240 static void run_test(data_t *data)
241 {
242 	uint32_t handle = data->fb_white.gem_handle;
243 	igt_plane_t *test_plane = data->test_plane;
244 	void *ptr;
245 	const char *expected = "";
246 
247 	/* Confirm that screen became Green */
248 	manual("screen GREEN");
249 
250 	/* Confirm screen stays Green after PSR got active */
251 	igt_assert(psr_wait_entry_if_enabled(data));
252 	manual("screen GREEN");
253 
254 	/* Setting a secondary fb/plane */
255 	igt_plane_set_fb(test_plane, &data->fb_white);
256 	igt_display_commit(&data->display);
257 
258 	/* Confirm it is not Green anymore */
259 	if (test_plane->type == DRM_PLANE_TYPE_PRIMARY)
260 		manual("screen WHITE");
261 	else
262 		manual("GREEN background with WHITE box");
263 
264 	igt_assert(psr_wait_entry_if_enabled(data));
265 	switch (data->op) {
266 	case PAGE_FLIP:
267 		/* Only in use when testing primary plane */
268 		igt_assert(drmModePageFlip(data->drm_fd, data->crtc_id,
269 					   data->fb_green.fb_id, 0, NULL) == 0);
270 		expected = "GREEN";
271 		break;
272 	case MMAP_GTT:
273 		ptr = gem_mmap__gtt(data->drm_fd, handle, data->mod_size,
274 				    PROT_WRITE);
275 		gem_set_domain(data->drm_fd, handle,
276 			       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
277 		memset(ptr, 0xcc, data->mod_size);
278 		munmap(ptr, data->mod_size);
279 		expected = "BLACK or TRANSPARENT mark on top of plane in test";
280 		break;
281 	case MMAP_CPU:
282 		ptr = gem_mmap__cpu(data->drm_fd, handle, 0, data->mod_size,
283 				    PROT_WRITE);
284 		gem_set_domain(data->drm_fd, handle,
285 			       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
286 		memset(ptr, 0, data->mod_size);
287 		munmap(ptr, data->mod_size);
288 		gem_sw_finish(data->drm_fd, handle);
289 		expected = "BLACK or TRANSPARENT mark on top of plane in test";
290 		break;
291 	case BLT:
292 		fill_blt(data, handle, 0);
293 		expected = "BLACK or TRANSPARENT mark on top of plane in test";
294 		break;
295 	case RENDER:
296 		fill_render(data, handle, 0);
297 		expected = "BLACK or TRANSPARENT mark on top of plane in test";
298 		break;
299 	case PLANE_MOVE:
300 		/* Only in use when testing Sprite and Cursor */
301 		igt_plane_set_position(test_plane, 500, 500);
302 		igt_display_commit(&data->display);
303 		expected = "White box moved to 500x500";
304 		break;
305 	case PLANE_ONOFF:
306 		/* Only in use when testing Sprite and Cursor */
307 		igt_plane_set_fb(test_plane, NULL);
308 		igt_display_commit(&data->display);
309 		expected = "screen GREEN";
310 		break;
311 	}
312 	igt_assert(psr_wait_update_if_enabled(data));
313 	manual(expected);
314 }
315 
test_cleanup(data_t * data)316 static void test_cleanup(data_t *data) {
317 	igt_plane_t *primary;
318 
319 	primary = igt_output_get_plane_type(data->output,
320 					    DRM_PLANE_TYPE_PRIMARY);
321 	igt_plane_set_fb(primary, NULL);
322 	igt_plane_set_fb(data->test_plane, NULL);
323 	igt_display_commit(&data->display);
324 
325 	igt_remove_fb(data->drm_fd, &data->fb_green);
326 	igt_remove_fb(data->drm_fd, &data->fb_white);
327 }
328 
setup_test_plane(data_t * data,int test_plane)329 static void setup_test_plane(data_t *data, int test_plane)
330 {
331 	uint32_t white_h, white_v;
332 	igt_plane_t *primary, *sprite, *cursor;
333 
334 	igt_create_color_fb(data->drm_fd,
335 			    data->mode->hdisplay, data->mode->vdisplay,
336 			    DRM_FORMAT_XRGB8888,
337 			    LOCAL_I915_FORMAT_MOD_X_TILED,
338 			    0.0, 1.0, 0.0,
339 			    &data->fb_green);
340 
341 	primary = igt_output_get_plane_type(data->output,
342 					    DRM_PLANE_TYPE_PRIMARY);
343 	igt_plane_set_fb(primary, NULL);
344 	data->test_plane = primary;
345 
346 	white_h = data->mode->hdisplay;
347 	white_v = data->mode->vdisplay;
348 
349 	/* Ignoring pitch and bpp to avoid changing full screen */
350 	data->mod_size = white_h * white_v;
351 	data->mod_stride = white_h * 4;
352 
353 	switch (test_plane) {
354 	case DRM_PLANE_TYPE_OVERLAY:
355 		sprite = igt_output_get_plane_type(data->output,
356 						   DRM_PLANE_TYPE_OVERLAY);
357 		igt_plane_set_fb(sprite, NULL);
358 		white_h = white_h/2;
359 		white_v = white_v/2;
360 		data->test_plane = sprite;
361 	case DRM_PLANE_TYPE_PRIMARY:
362 		igt_create_color_fb(data->drm_fd,
363 				    white_h, white_v,
364 				    DRM_FORMAT_XRGB8888,
365 				    LOCAL_I915_FORMAT_MOD_X_TILED,
366 				    1.0, 1.0, 1.0,
367 				    &data->fb_white);
368 		break;
369 	case DRM_PLANE_TYPE_CURSOR:
370 		cursor = igt_output_get_plane_type(data->output,
371 						   DRM_PLANE_TYPE_CURSOR);
372 		igt_plane_set_fb(cursor, NULL);
373 		create_cursor_fb(data);
374 		igt_plane_set_position(cursor, 0, 0);
375 
376 		/* Cursor is 64 x 64, ignoring pitch and bbp again */
377 		data->mod_size = 64 * 64;
378 		data->test_plane = cursor;
379 		break;
380 	}
381 
382 	igt_display_commit(&data->display);
383 
384 	igt_plane_set_fb(primary, &data->fb_green);
385 	igt_display_commit(&data->display);
386 }
387 
test_setup(data_t * data)388 static void test_setup(data_t *data)
389 {
390 	if (data->op_psr_mode == PSR_MODE_2)
391 		igt_require(data->supports_psr2);
392 	psr_enable_if_enabled(data);
393 	setup_test_plane(data, data->test_plane_id);
394 	igt_assert(psr_wait_entry_if_enabled(data));
395 }
396 
dpms_off_on(data_t * data)397 static void dpms_off_on(data_t *data)
398 {
399 	kmstest_set_connector_dpms(data->drm_fd, data->output->config.connector,
400 				   DRM_MODE_DPMS_OFF);
401 	kmstest_set_connector_dpms(data->drm_fd, data->output->config.connector,
402 				   DRM_MODE_DPMS_ON);
403 }
404 
opt_handler(int opt,int opt_index,void * _data)405 static int opt_handler(int opt, int opt_index, void *_data)
406 {
407 	data_t *data = _data;
408 
409 	switch (opt) {
410 	case 'n':
411 		data->with_psr_disabled = true;
412 		break;
413 	default:
414 		return IGT_OPT_HANDLER_ERROR;
415 	}
416 
417 	return IGT_OPT_HANDLER_SUCCESS;
418 }
419 
420 const char *help_str =
421 	"  --no-psr\tRun test without PSR/PSR2.";
422 static struct option long_options[] = {
423 	{"no-psr", 0, 0, 'n'},
424 	{ 0, 0, 0, 0 }
425 };
426 data_t data = {};
427 
428 igt_main_args("", long_options, help_str, opt_handler, &data)
429 {
430 	enum operations op;
431 	const char *append_subtest_name[2] = {
432 		"",
433 		"psr2_"
434 	};
435 
436 	igt_skip_on_simulation();
437 
438 	igt_fixture {
439 		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
440 		data.debugfs_fd = igt_debugfs_dir(data.drm_fd);
441 		kmstest_set_vt_graphics_mode();
442 		data.devid = intel_get_drm_devid(data.drm_fd);
443 
444 		igt_require_f(sink_support(&data, PSR_MODE_1),
445 			      "Sink does not support PSR\n");
446 
447 		data.supports_psr2 = sink_support(&data, PSR_MODE_2);
448 
449 		data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096);
450 		igt_assert(data.bufmgr);
451 		drm_intel_bufmgr_gem_enable_reuse(data.bufmgr);
452 
453 		display_init(&data);
454 	}
455 
456 	for (data.op_psr_mode = PSR_MODE_1; data.op_psr_mode <= PSR_MODE_2;
457 	     data.op_psr_mode++) {
458 
459 		igt_subtest_f("%sbasic", append_subtest_name[data.op_psr_mode]) {
460 			data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
461 			test_setup(&data);
462 			test_cleanup(&data);
463 		}
464 
465 		igt_subtest_f("%sno_drrs", append_subtest_name[data.op_psr_mode]) {
466 			data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
467 			test_setup(&data);
468 			igt_assert(drrs_disabled(&data));
469 			test_cleanup(&data);
470 		}
471 
472 		for (op = PAGE_FLIP; op <= RENDER; op++) {
473 			igt_subtest_f("%sprimary_%s",
474 				      append_subtest_name[data.op_psr_mode],
475 				      op_str(op)) {
476 				data.op = op;
477 				data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
478 				test_setup(&data);
479 				run_test(&data);
480 				test_cleanup(&data);
481 			}
482 		}
483 
484 		for (op = MMAP_GTT; op <= PLANE_ONOFF; op++) {
485 			igt_subtest_f("%ssprite_%s",
486 				      append_subtest_name[data.op_psr_mode],
487 				      op_str(op)) {
488 				data.op = op;
489 				data.test_plane_id = DRM_PLANE_TYPE_OVERLAY;
490 				test_setup(&data);
491 				run_test(&data);
492 				test_cleanup(&data);
493 			}
494 
495 			igt_subtest_f("%scursor_%s",
496 				      append_subtest_name[data.op_psr_mode],
497 				      op_str(op)) {
498 				data.op = op;
499 				data.test_plane_id = DRM_PLANE_TYPE_CURSOR;
500 				test_setup(&data);
501 				run_test(&data);
502 				test_cleanup(&data);
503 			}
504 		}
505 
506 		igt_subtest_f("%sdpms", append_subtest_name[data.op_psr_mode]) {
507 			data.op = RENDER;
508 			data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
509 			test_setup(&data);
510 			dpms_off_on(&data);
511 			run_test(&data);
512 			test_cleanup(&data);
513 		}
514 
515 		igt_subtest_f("%ssuspend", append_subtest_name[data.op_psr_mode]) {
516 			data.op = PLANE_ONOFF;
517 			data.test_plane_id = DRM_PLANE_TYPE_CURSOR;
518 			test_setup(&data);
519 			igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
520 						      SUSPEND_TEST_NONE);
521 			igt_assert(psr_wait_entry_if_enabled(&data));
522 			run_test(&data);
523 			test_cleanup(&data);
524 		}
525 	}
526 
527 	igt_fixture {
528 		if (!data.with_psr_disabled)
529 			psr_disable(data.debugfs_fd);
530 
531 		close(data.debugfs_fd);
532 		drm_intel_bufmgr_destroy(data.bufmgr);
533 		display_fini(&data);
534 	}
535 }
536