kms_psr.c 13.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 */

25
#include "igt.h"
26
#include "igt_sysfs.h"
27
#include "igt_psr.h"
28 29 30 31 32 33
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "intel_bufmgr.h"

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
enum operations {
	PAGE_FLIP,
	MMAP_GTT,
	MMAP_CPU,
	BLT,
	RENDER,
	PLANE_MOVE,
	PLANE_ONOFF,
};

static const char *op_str(enum operations op)
{
	static const char * const name[] = {
		[PAGE_FLIP] = "page_flip",
		[MMAP_GTT] = "mmap_gtt",
		[MMAP_CPU] = "mmap_cpu",
		[BLT] = "blt",
		[RENDER] = "render",
		[PLANE_MOVE] = "plane_move",
		[PLANE_ONOFF] = "plane_onoff",
	};

	return name[op];
}
58

59 60
typedef struct {
	int drm_fd;
61
	int debugfs_fd;
62
	enum operations op;
63
	int test_plane_id;
64
	enum psr_mode op_psr_mode;
65 66 67
	uint32_t devid;
	uint32_t crtc_id;
	igt_display_t display;
68 69
	drm_intel_bufmgr *bufmgr;
	struct igt_fb fb_green, fb_white;
70
	igt_plane_t *test_plane;
71
	int mod_size;
72
	int mod_stride;
73 74
	drmModeModeInfo *mode;
	igt_output_t *output;
75
	bool with_psr_disabled;
76
	bool supports_psr2;
77 78
} data_t;

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 88
	igt_assert(fb_id);

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
}

94 95 96 97
static void setup_output(data_t *data)
{
	igt_display_t *display = &data->display;
	igt_output_t *output;
98
	enum pipe pipe;
99

100
	for_each_pipe_with_valid_output(display, pipe, output) {
101 102
		drmModeConnectorPtr c = output->config.connector;

103
		if (c->connector_type != DRM_MODE_CONNECTOR_eDP)
104 105
			continue;

106
		igt_output_set_pipe(output, pipe);
107 108 109 110 111 112 113 114
		data->crtc_id = output->config.crtc->crtc_id;
		data->output = output;
		data->mode = igt_output_get_mode(output);

		return;
	}
}

115 116
static void display_init(data_t *data)
{
117
	igt_display_require(&data->display, data->drm_fd);
118
	setup_output(data);
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
}

static void display_fini(data_t *data)
{
	igt_display_fini(&data->display);
}

static void fill_blt(data_t *data, uint32_t handle, unsigned char color)
{
	drm_intel_bo *dst = gem_handle_to_libdrm_bo(data->bufmgr,
						    data->drm_fd,
						    "", handle);
	struct intel_batchbuffer *batch;

	batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
	igt_assert(batch);

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 141 142 143 144 145 146 147 148 149
	OUT_RELOC(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
	OUT_BATCH(color);
	ADVANCE_BATCH();

	intel_batchbuffer_flush(batch);
	intel_batchbuffer_free(batch);

	gem_bo_busy(data->drm_fd, handle);
}

150 151
static void scratch_buf_init(struct igt_buf *buf, drm_intel_bo *bo,
			     int size, int stride)
152
{
153 154
	memset(buf, 0, sizeof(*buf));

155
	buf->bo = bo;
156
	buf->stride = stride;
157
	buf->tiling = I915_TILING_X;
158
	buf->size = size;
159
	buf->bpp = 32;
160 161
}

162
static void fill_render(data_t *data, uint32_t handle, unsigned char color)
163 164 165 166 167 168 169 170 171 172 173 174
{
	drm_intel_bo *src, *dst;
	struct intel_batchbuffer *batch;
	struct igt_buf src_buf, dst_buf;
	const uint8_t buf[4] = { color, color, color, color };
	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(data->devid);

	igt_skip_on(!rendercopy);

	dst = gem_handle_to_libdrm_bo(data->bufmgr, data->drm_fd, "", handle);
	igt_assert(dst);

175
	src = drm_intel_bo_alloc(data->bufmgr, "", data->mod_size, 4096);
176 177 178 179
	igt_assert(src);

	gem_write(data->drm_fd, src->handle, 0, buf, 4);

180 181
	scratch_buf_init(&src_buf, src, data->mod_size, data->mod_stride);
	scratch_buf_init(&dst_buf, dst, data->mod_size, data->mod_stride);
182 183 184 185

	batch = intel_batchbuffer_alloc(data->bufmgr, data->devid);
	igt_assert(batch);

186
	rendercopy(batch, NULL,
187
		   &src_buf, 0, 0, 0xff, 0xff,
188 189 190 191 192 193 194
		   &dst_buf, 0, 0);

	intel_batchbuffer_free(batch);

	gem_bo_busy(data->drm_fd, handle);
}

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
}

201
static bool psr_wait_entry_if_enabled(data_t *data)
202
{
203 204
	if (data->with_psr_disabled)
		return true;
205

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
	return psr_wait_entry(data->debugfs_fd, data->op_psr_mode);
}

static bool psr_wait_update_if_enabled(data_t *data)
{
	if (data->with_psr_disabled)
		return true;

	return psr_wait_update(data->debugfs_fd, data->op_psr_mode);
}

static bool psr_enable_if_enabled(data_t *data)
{
	if (data->with_psr_disabled)
		return true;

	return psr_enable(data->debugfs_fd, data->op_psr_mode);
223 224
}

225
static inline void manual(const char *expected)
226
{
227
	igt_debug_manual_check("all", expected);
228 229
}

230 231 232 233
static bool drrs_disabled(data_t *data)
{
	char buf[512];

234 235
	igt_debugfs_simple_read(data->debugfs_fd, "i915_drrs_status",
			 buf, sizeof(buf));
236

237
	return !strstr(buf, "DRRS Supported: Yes\n");
238 239
}

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 255 256
	/* Setting a secondary fb/plane */
	igt_plane_set_fb(test_plane, &data->fb_white);
	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 266
	switch (data->op) {
	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 278
		memset(ptr, 0xcc, data->mod_size);
		munmap(ptr, data->mod_size);
279
		expected = "BLACK or TRANSPARENT mark on top of plane in test";
280
		break;
281
	case MMAP_CPU:
282 283
		ptr = gem_mmap__cpu(data->drm_fd, handle, 0, data->mod_size,
				    PROT_WRITE);
284 285
		gem_set_domain(data->drm_fd, handle,
			       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
286 287
		memset(ptr, 0, data->mod_size);
		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 307
		/* Only in use when testing Sprite and Cursor */
		igt_plane_set_fb(test_plane, NULL);
308
		igt_display_commit(&data->display);
309
		expected = "screen GREEN";
310 311
		break;
	}
312
	igt_assert(psr_wait_update_if_enabled(data));
313
	manual(expected);
314 315
}

316
static void test_cleanup(data_t *data) {
317
	igt_plane_t *primary;
318

319 320 321 322
	primary = igt_output_get_plane_type(data->output,
					    DRM_PLANE_TYPE_PRIMARY);
	igt_plane_set_fb(primary, NULL);
	igt_plane_set_fb(data->test_plane, NULL);
323
	igt_display_commit(&data->display);
324

325 326
	igt_remove_fb(data->drm_fd, &data->fb_green);
	igt_remove_fb(data->drm_fd, &data->fb_white);
327 328
}

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 335 336 337 338 339
	igt_create_color_fb(data->drm_fd,
			    data->mode->hdisplay, data->mode->vdisplay,
			    DRM_FORMAT_XRGB8888,
			    LOCAL_I915_FORMAT_MOD_X_TILED,
			    0.0, 1.0, 0.0,
			    &data->fb_green);
340

341 342 343 344
	primary = igt_output_get_plane_type(data->output,
					    DRM_PLANE_TYPE_PRIMARY);
	igt_plane_set_fb(primary, NULL);
	data->test_plane = primary;
345

346 347
	white_h = data->mode->hdisplay;
	white_v = data->mode->vdisplay;
348

349 350
	/* Ignoring pitch and bpp to avoid changing full screen */
	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 356 357
		sprite = igt_output_get_plane_type(data->output,
						   DRM_PLANE_TYPE_OVERLAY);
		igt_plane_set_fb(sprite, NULL);
358 359
		white_h = white_h/2;
		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 365
				    DRM_FORMAT_XRGB8888,
				    LOCAL_I915_FORMAT_MOD_X_TILED,
366 367 368
				    1.0, 1.0, 1.0,
				    &data->fb_white);
		break;
369
	case DRM_PLANE_TYPE_CURSOR:
370 371 372
		cursor = igt_output_get_plane_type(data->output,
						   DRM_PLANE_TYPE_CURSOR);
		igt_plane_set_fb(cursor, NULL);
373
		create_cursor_fb(data);
374
		igt_plane_set_position(cursor, 0, 0);
375

376 377
		/* Cursor is 64 x 64, ignoring pitch and bbp again */
		data->mod_size = 64 * 64;
378
		data->test_plane = cursor;
379 380
		break;
	}
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
}

388 389
static void test_setup(data_t *data)
{
390 391 392
	if (data->op_psr_mode == PSR_MODE_2)
		igt_require(data->supports_psr2);
	psr_enable_if_enabled(data);
393 394 395 396
	setup_test_plane(data, data->test_plane_id);
	igt_assert(psr_wait_entry_if_enabled(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 403 404
				   DRM_MODE_DPMS_ON);
}

405
static int opt_handler(int opt, int opt_index, void *_data)
406
{
407 408
	data_t *data = _data;

409 410
	switch (opt) {
	case 'n':
411
		data->with_psr_disabled = true;
412 413 414 415
		break;
	default:
		igt_assert(0);
	}
416

417 418
	return 0;
}
419

420 421 422
int main(int argc, char *argv[])
{
	const char *help_str =
423
	       "  --no-psr\tRun test without PSR/PSR2.";
424 425 426 427 428 429
	static struct option long_options[] = {
		{"no-psr", 0, 0, 'n'},
		{ 0, 0, 0, 0 }
	};
	data_t data = {};
	enum operations op;
430 431 432 433
	const char *append_subtest_name[2] = {
		"",
		"psr2_"
	};
434

435
	igt_subtest_init_parse_opts(&argc, argv, "", long_options,
436
				    help_str, opt_handler, &data);
437 438 439
	igt_skip_on_simulation();

	igt_fixture {
440
		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
441
		data.debugfs_fd = igt_debugfs_dir(data.drm_fd);
442
		kmstest_set_vt_graphics_mode();
443 444
		data.devid = intel_get_drm_devid(data.drm_fd);

445
		igt_require_f(sink_support(&data, PSR_MODE_1),
446
			      "Sink does not support PSR\n");
447

448 449
		data.supports_psr2 = sink_support(&data, PSR_MODE_2);

450 451 452 453 454 455 456
		data.bufmgr = drm_intel_bufmgr_gem_init(data.drm_fd, 4096);
		igt_assert(data.bufmgr);
		drm_intel_bufmgr_gem_enable_reuse(data.bufmgr);

		display_init(&data);
	}

457 458
	for (data.op_psr_mode = PSR_MODE_1; data.op_psr_mode <= PSR_MODE_2;
	     data.op_psr_mode++) {
459

460 461 462 463 464
		igt_subtest_f("%sbasic", append_subtest_name[data.op_psr_mode]) {
			data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
			test_setup(&data);
			test_cleanup(&data);
		}
465

466
		igt_subtest_f("%sno_drrs", append_subtest_name[data.op_psr_mode]) {
467 468
			data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
			test_setup(&data);
469
			igt_assert(drrs_disabled(&data));
470
			test_cleanup(&data);
471 472
		}

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
		for (op = PAGE_FLIP; op <= RENDER; op++) {
			igt_subtest_f("%sprimary_%s",
				      append_subtest_name[data.op_psr_mode],
				      op_str(op)) {
				data.op = op;
				data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
				test_setup(&data);
				run_test(&data);
				test_cleanup(&data);
			}
		}

		for (op = MMAP_GTT; op <= PLANE_ONOFF; op++) {
			igt_subtest_f("%ssprite_%s",
				      append_subtest_name[data.op_psr_mode],
				      op_str(op)) {
				data.op = op;
				data.test_plane_id = DRM_PLANE_TYPE_OVERLAY;
				test_setup(&data);
				run_test(&data);
				test_cleanup(&data);
			}

			igt_subtest_f("%scursor_%s",
				      append_subtest_name[data.op_psr_mode],
				      op_str(op)) {
				data.op = op;
				data.test_plane_id = DRM_PLANE_TYPE_CURSOR;
				test_setup(&data);
				run_test(&data);
				test_cleanup(&data);
			}
		}

		igt_subtest_f("%sdpms", append_subtest_name[data.op_psr_mode]) {
			data.op = RENDER;
			data.test_plane_id = DRM_PLANE_TYPE_PRIMARY;
510
			test_setup(&data);
511
			dpms_off_on(&data);
512
			run_test(&data);
513
			test_cleanup(&data);
514 515
		}

516 517
		igt_subtest_f("%ssuspend", append_subtest_name[data.op_psr_mode]) {
			data.op = PLANE_ONOFF;
518 519
			data.test_plane_id = DRM_PLANE_TYPE_CURSOR;
			test_setup(&data);
520 521 522
			igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
						      SUSPEND_TEST_NONE);
			igt_assert(psr_wait_entry_if_enabled(&data));
523
			run_test(&data);
524
			test_cleanup(&data);
525 526 527 528
		}
	}

	igt_fixture {
529 530 531
		if (!data.with_psr_disabled)
			psr_disable(data.debugfs_fd);

532
		close(data.debugfs_fd);
533 534 535
		drm_intel_bufmgr_destroy(data.bufmgr);
		display_fini(&data);
	}
536 537

	igt_exit();
538
}