kms_psr_sink_crc.c 13.9 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 28 29 30 31 32 33
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include "intel_bufmgr.h"

34
#define CRC_BLACK "000000000000"
35
#define CRC_LEN 12
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
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];
}
61

62 63
typedef struct {
	int drm_fd;
64
	int debugfs_fd;
65
	enum operations op;
66 67 68
	uint32_t devid;
	uint32_t crtc_id;
	igt_display_t display;
69 70
	drm_intel_bufmgr *bufmgr;
	struct igt_fb fb_green, fb_white;
71
	igt_plane_t *test_plane;
72
	int mod_size;
73
	int mod_stride;
74 75
	drmModeModeInfo *mode;
	igt_output_t *output;
76
	bool with_psr_disabled;
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 117
static void display_init(data_t *data)
{
	igt_display_init(&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 160
}

161
static void fill_render(data_t *data, uint32_t handle, unsigned char color)
162 163 164 165 166 167 168 169 170 171 172 173
{
	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);

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

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

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

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

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

	intel_batchbuffer_free(batch);

	gem_bo_busy(data->drm_fd, handle);
}

194
static bool sink_support(data_t *data)
195
{
196
	char buf[512];
197

198
	igt_debugfs_read(data->drm_fd, "i915_edp_psr_status", buf);
199

200
	return data->with_psr_disabled ||
201
		strstr(buf, "Sink_Support: yes\n");
202 203
}

204
static bool psr_enabled(data_t *data)
205
{
206
	char buf[512];
207

208
	igt_debugfs_read(data->drm_fd, "i915_edp_psr_status", buf);
209

210
	return data->with_psr_disabled ||
211
		strstr(buf, "HW Enabled & Active bit: yes\n");
212 213
}

214
static bool wait_psr_entry(data_t *data)
215
{
216
	int timeout = 5;
217
	while (timeout--) {
218
		if (psr_enabled(data))
219 220 221 222 223 224
			return true;
		sleep(1);
	}
	return false;
}

225 226
static void get_sink_crc(data_t *data, char *crc)
{
227 228 229
	if (igt_interactive_debug)
		return;

230 231
	igt_require_f(igt_sysfs_read(data->debugfs_fd, "i915_sink_crc_eDP1",
				     crc, CRC_LEN) == CRC_LEN,
232
		      "Sink CRC is unreliable on this machine. Try manual debug with --interactive-debug=no-crc\n");
233
	igt_debug("sink CRC: %.*s\n", CRC_LEN, crc);
234 235

	/* Black screen is always invalid */
236
	igt_assert(strncmp(crc, CRC_BLACK, CRC_LEN));
237 238 239 240
}

static bool is_green(char *crc)
{
241 242
	const char *mask = "0000FFFF0000";
	uint32_t *p = (uint32_t *)crc, *mask_p = (uint32_t *)mask;
243 244 245
	if (igt_interactive_debug)
		return false;

246 247 248
	/* Check R and B components are 0 and G is non-zero */
	return *p == *mask_p && *(p + 2) == *(mask_p + 2) &&
	       (*(p + 1) & *(mask_p + 1)) != 0;
249 250
}

251 252
static void assert_or_manual(bool condition, const char *expected)
{
253
	igt_debug_manual_check("no-crc", expected);
254 255 256
	igt_assert(igt_interactive_debug || condition);
}

257 258 259 260 261 262
static bool drrs_disabled(data_t *data)
{
	char buf[512];

	igt_debugfs_read(data->drm_fd, "i915_drrs_status", buf);

263
	return !strstr(buf, "DRRS Supported: Yes\n");
264 265
}

266
static void run_test(data_t *data)
267
{
268
	uint32_t handle = data->fb_white.gem_handle;
269
	igt_plane_t *test_plane = data->test_plane;
270
	void *ptr;
271 272
	char ref_crc[CRC_LEN];
	char crc[CRC_LEN];
273
	const char *expected = "";
274

275 276
	/* Confirm that screen became Green */
	get_sink_crc(data, ref_crc);
277
	assert_or_manual(is_green(ref_crc), "screen GREEN");
278 279

	/* Confirm screen stays Green after PSR got active */
280
	igt_assert(wait_psr_entry(data));
281
	get_sink_crc(data, ref_crc);
282
	assert_or_manual(is_green(ref_crc), "screen GREEN");
283

284 285 286
	/* Setting a secondary fb/plane */
	igt_plane_set_fb(test_plane, &data->fb_white);
	igt_display_commit(&data->display);
287

288
	/* Confirm it is not Green anymore */
289
	igt_assert(wait_psr_entry(data));
290
	get_sink_crc(data, ref_crc);
291
	if (test_plane->type == DRM_PLANE_TYPE_PRIMARY)
292 293 294
		assert_or_manual(!is_green(ref_crc), "screen WHITE");
	else
		assert_or_manual(!is_green(ref_crc), "GREEN background with WHITE box");
295

296 297
	switch (data->op) {
	case PAGE_FLIP:
298
		/* Only in use when testing primary plane */
299
		igt_assert(drmModePageFlip(data->drm_fd, data->crtc_id,
300
					   data->fb_green.fb_id, 0, NULL) == 0);
301
		get_sink_crc(data, crc);
302 303
		assert_or_manual(is_green(crc), "screen GREEN");
		expected = "still GREEN";
304
		break;
305
	case MMAP_GTT:
306
		ptr = gem_mmap__gtt(data->drm_fd, handle, data->mod_size,
307
				    PROT_WRITE);
308
		gem_set_domain(data->drm_fd, handle,
309
			       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
310 311
		memset(ptr, 0xcc, data->mod_size);
		munmap(ptr, data->mod_size);
312
		expected = "BLACK or TRANSPARENT mark on top of plane in test";
313
		break;
314
	case MMAP_CPU:
315 316
		ptr = gem_mmap__cpu(data->drm_fd, handle, 0, data->mod_size,
				    PROT_WRITE);
317 318
		gem_set_domain(data->drm_fd, handle,
			       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
319 320
		memset(ptr, 0, data->mod_size);
		munmap(ptr, data->mod_size);
321
		gem_sw_finish(data->drm_fd, handle);
322
		expected = "BLACK or TRANSPARENT mark on top of plane in test";
323
		break;
324
	case BLT:
325
		fill_blt(data, handle, 0);
326
		expected = "BLACK or TRANSPARENT mark on top of plane in test";
327
		break;
328
	case RENDER:
329
		fill_render(data, handle, 0);
330
		expected = "BLACK or TRANSPARENT mark on top of plane in test";
331
		break;
332
	case PLANE_MOVE:
333
		/* Only in use when testing Sprite and Cursor */
334
		igt_plane_set_position(test_plane, 500, 500);
335
		igt_display_commit(&data->display);
336
		expected = "White box moved to 500x500";
337
		break;
338
	case PLANE_ONOFF:
339 340
		/* Only in use when testing Sprite and Cursor */
		igt_plane_set_fb(test_plane, NULL);
341
		igt_display_commit(&data->display);
342
		expected = "screen GREEN";
343 344 345
		break;
	}
	get_sink_crc(data, crc);
346
	assert_or_manual(strncmp(ref_crc, crc, CRC_LEN) != 0, expected);
347 348
}

349
static void test_cleanup(data_t *data) {
350
	igt_plane_t *primary;
351

352 353 354 355
	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);
356
	igt_display_commit(&data->display);
357

358 359
	igt_remove_fb(data->drm_fd, &data->fb_green);
	igt_remove_fb(data->drm_fd, &data->fb_white);
360 361
}

362
static void setup_test_plane(data_t *data, int test_plane)
363
{
364
	uint32_t white_h, white_v;
365
	igt_plane_t *primary, *sprite, *cursor;
366

367 368 369 370 371 372
	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);
373

374 375 376 377
	primary = igt_output_get_plane_type(data->output,
					    DRM_PLANE_TYPE_PRIMARY);
	igt_plane_set_fb(primary, NULL);
	data->test_plane = primary;
378

379 380
	white_h = data->mode->hdisplay;
	white_v = data->mode->vdisplay;
381

382 383
	/* Ignoring pitch and bpp to avoid changing full screen */
	data->mod_size = white_h * white_v;
384
	data->mod_stride = white_h * 4;
385

386
	switch (test_plane) {
387
	case DRM_PLANE_TYPE_OVERLAY:
388 389 390
		sprite = igt_output_get_plane_type(data->output,
						   DRM_PLANE_TYPE_OVERLAY);
		igt_plane_set_fb(sprite, NULL);
391 392
		white_h = white_h/2;
		white_v = white_v/2;
393
		data->test_plane = sprite;
394
	case DRM_PLANE_TYPE_PRIMARY:
395
		igt_create_color_fb(data->drm_fd,
396
				    white_h, white_v,
397 398
				    DRM_FORMAT_XRGB8888,
				    LOCAL_I915_FORMAT_MOD_X_TILED,
399 400 401
				    1.0, 1.0, 1.0,
				    &data->fb_white);
		break;
402
	case DRM_PLANE_TYPE_CURSOR:
403 404 405
		cursor = igt_output_get_plane_type(data->output,
						   DRM_PLANE_TYPE_CURSOR);
		igt_plane_set_fb(cursor, NULL);
406
		create_cursor_fb(data);
407
		igt_plane_set_position(cursor, 0, 0);
408

409 410
		/* Cursor is 64 x 64, ignoring pitch and bbp again */
		data->mod_size = 64 * 64;
411
		data->test_plane = cursor;
412 413
		break;
	}
414

415
	igt_display_commit(&data->display);
416

417
	igt_plane_set_fb(primary, &data->fb_green);
418
	igt_display_commit(&data->display);
419 420
}

421
static void dpms_off_on(data_t *data)
422
{
423
	kmstest_set_connector_dpms(data->drm_fd, data->output->config.connector,
424
				   DRM_MODE_DPMS_OFF);
425
	kmstest_set_connector_dpms(data->drm_fd, data->output->config.connector,
426 427 428
				   DRM_MODE_DPMS_ON);
}

429
static int opt_handler(int opt, int opt_index, void *_data)
430
{
431 432
	data_t *data = _data;

433 434
	switch (opt) {
	case 'n':
435
		data->with_psr_disabled = true;
436 437 438 439
		break;
	default:
		igt_assert(0);
	}
440

441 442
	return 0;
}
443

444 445 446 447 448 449 450 451 452 453
int main(int argc, char *argv[])
{
	const char *help_str =
	       "  --no-psr\tRun test without PSR to check the CRC test logic.";
	static struct option long_options[] = {
		{"no-psr", 0, 0, 'n'},
		{ 0, 0, 0, 0 }
	};
	data_t data = {};
	enum operations op;
454

455
	igt_subtest_init_parse_opts(&argc, argv, "", long_options,
456
				    help_str, opt_handler, &data);
457 458 459
	igt_skip_on_simulation();

	igt_fixture {
460
		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
461
		data.debugfs_fd = igt_debugfs_dir(data.drm_fd);
462
		kmstest_set_vt_graphics_mode();
463 464
		data.devid = intel_get_drm_devid(data.drm_fd);

465
		igt_set_module_param_int("enable_psr", data.with_psr_disabled ?
466
					 0 : 1);
467 468
		igt_require_f(sink_support(&data),
			      "Sink does not support PSR\n");
469 470 471 472 473 474 475 476

		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);
	}

477
	igt_subtest("basic") {
478
		setup_test_plane(&data, DRM_PLANE_TYPE_PRIMARY);
479
		igt_assert(wait_psr_entry(&data));
480
		test_cleanup(&data);
481 482
	}

483
	igt_subtest("no_drrs") {
484
		setup_test_plane(&data, DRM_PLANE_TYPE_PRIMARY);
485
		igt_assert(wait_psr_entry(&data));
486
		igt_assert(drrs_disabled(&data));
487
		test_cleanup(&data);
488 489
	}

490 491 492
	for (op = PAGE_FLIP; op <= RENDER; op++) {
		igt_subtest_f("primary_%s", op_str(op)) {
			data.op = op;
493
			setup_test_plane(&data, DRM_PLANE_TYPE_PRIMARY);
494
			igt_assert(wait_psr_entry(&data));
495
			run_test(&data);
496
			test_cleanup(&data);
497 498 499
		}
	}

500
	for (op = MMAP_GTT; op <= PLANE_ONOFF; op++) {
501 502
		igt_subtest_f("sprite_%s", op_str(op)) {
			data.op = op;
503
			setup_test_plane(&data, DRM_PLANE_TYPE_OVERLAY);
504
			igt_assert(wait_psr_entry(&data));
505
			run_test(&data);
506
			test_cleanup(&data);
507 508 509
		}
	}

510
	for (op = MMAP_GTT; op <= PLANE_ONOFF; op++) {
511 512
		igt_subtest_f("cursor_%s", op_str(op)) {
			data.op = op;
513
			setup_test_plane(&data, DRM_PLANE_TYPE_CURSOR);
514
			igt_assert(wait_psr_entry(&data));
515
			run_test(&data);
516
			test_cleanup(&data);
517 518 519
		}
	}

520
	igt_subtest_f("dpms") {
521
		data.op = RENDER;
522
		setup_test_plane(&data, DRM_PLANE_TYPE_PRIMARY);
523
		igt_assert(wait_psr_entry(&data));
524
		dpms_off_on(&data);
525 526 527 528
		run_test(&data);
		test_cleanup(&data);
	}

529
	igt_subtest_f("suspend") {
530
		data.op = PLANE_ONOFF;
531
		setup_test_plane(&data, DRM_PLANE_TYPE_CURSOR);
532
		igt_assert(wait_psr_entry(&data));
533 534
		igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
					      SUSPEND_TEST_NONE);
535 536 537 538 539
		igt_assert(wait_psr_entry(&data));
		run_test(&data);
		test_cleanup(&data);
	}

540
	igt_fixture {
541
		close(data.debugfs_fd);
542 543 544
		drm_intel_bufmgr_destroy(data.bufmgr);
		display_fini(&data);
	}
545 546

	igt_exit();
547
}