PD#158474: add chromiumos drm-tests

Change-Id: I33b220ec40c8147bc6e6228cecff164f8555582f
Signed-off-by: Yalong Liu <yalong.liu@amlogic.com>
diff --git a/drm-tests/mmap_test.c b/drm-tests/mmap_test.c
new file mode 100644
index 0000000..321e33e
--- /dev/null
+++ b/drm-tests/mmap_test.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <getopt.h>
+
+#include "bs_drm.h"
+
+#define BUFFERS 2
+#define NUM_FRAMES 0x40
+
+struct framebuffer {
+	struct gbm_bo *bo;
+	uint32_t id;
+};
+
+struct context {
+	int display_fd;
+	uint32_t crtc_id;
+
+	struct framebuffer fbs[BUFFERS];
+	struct bs_mapper *mapper;
+
+	int vgem_device_fd;
+};
+
+static void disable_psr()
+{
+	const char psr_path[] = "/sys/module/i915/parameters/enable_psr";
+	int psr_fd = open(psr_path, O_WRONLY);
+
+	if (psr_fd < 0)
+		return;
+
+	if (write(psr_fd, "0", 1) == -1) {
+		bs_debug_error("failed to disable psr");
+	} else {
+		printf("disabled psr");
+	}
+
+	close(psr_fd);
+}
+
+static void do_fixes()
+{
+	disable_psr();
+}
+
+#define STEP_SKIP 0
+#define STEP_MMAP 1
+#define STEP_FAULT 2
+#define STEP_FLIP 3
+#define STEP_DRAW 4
+
+static void show_sequence(const int *sequence)
+{
+	int sequence_subindex;
+	printf("starting sequence: ");
+	for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
+		switch (sequence[sequence_subindex]) {
+			case STEP_SKIP:
+				break;
+			case STEP_MMAP:
+				printf("mmap ");
+				break;
+			case STEP_FAULT:
+				printf("fault ");
+				break;
+			case STEP_FLIP:
+				printf("flip ");
+				break;
+			case STEP_DRAW:
+				printf("draw ");
+				break;
+			default:
+				bs_debug_error("<unknown step %d> (aborting!)",
+					       sequence[sequence_subindex]);
+				abort();
+				break;
+		}
+	}
+	printf("\n");
+}
+
+static void draw(struct context *ctx)
+{
+	// Run the drawing routine with the key driver events in different
+	// sequences.
+	const int sequences[4][4] = {
+		{ STEP_MMAP, STEP_FAULT, STEP_FLIP, STEP_DRAW },
+		{ STEP_MMAP, STEP_FLIP, STEP_DRAW, STEP_SKIP },
+		{ STEP_MMAP, STEP_DRAW, STEP_FLIP, STEP_SKIP },
+		{ STEP_FLIP, STEP_MMAP, STEP_DRAW, STEP_SKIP },
+	};
+
+	int sequence_index = 0;
+	int sequence_subindex = 0;
+
+	int fb_idx = 1;
+
+	for (sequence_index = 0; sequence_index < 4; sequence_index++) {
+		show_sequence(sequences[sequence_index]);
+		for (int frame_index = 0; frame_index < NUM_FRAMES; frame_index++) {
+			struct framebuffer *fb = &ctx->fbs[fb_idx];
+			size_t bo_stride = gbm_bo_get_plane_stride(fb->bo, 0);
+			size_t bo_size = gbm_bo_get_plane_size(fb->bo, 0);
+			const uint32_t width = gbm_bo_get_width(fb->bo);
+			const uint32_t height = gbm_bo_get_height(fb->bo);
+			uint32_t *bo_ptr;
+			volatile uint32_t *ptr;
+			void *map_data;
+
+			for (sequence_subindex = 0; sequence_subindex < 4; sequence_subindex++) {
+				switch (sequences[sequence_index][sequence_subindex]) {
+					case STEP_MMAP:
+						bo_ptr = bs_mapper_map(ctx->mapper, fb->bo, 0,
+								       &map_data);
+						if (bo_ptr == MAP_FAILED)
+							bs_debug_error("failed to mmap gbm bo");
+
+						ptr = bo_ptr;
+						break;
+
+					case STEP_FAULT:
+						*ptr = 1234567;
+						break;
+
+					case STEP_FLIP:
+						drmModePageFlip(ctx->display_fd, ctx->crtc_id,
+								ctx->fbs[fb_idx].id, 0, NULL);
+						break;
+
+					case STEP_DRAW:
+						for (ptr = bo_ptr;
+						     ptr < bo_ptr + (bo_size / sizeof(*bo_ptr));
+						     ptr++) {
+							int y = ((void *)ptr - (void *)bo_ptr) /
+								bo_stride;
+							int x = ((void *)ptr - (void *)bo_ptr -
+								 bo_stride * y) /
+								sizeof(*ptr);
+							x -= frame_index * (width / NUM_FRAMES);
+							y -= frame_index * (height / NUM_FRAMES);
+							*ptr = 0xff000000;
+							if (x * x + y * y <
+							    frame_index * frame_index)
+								*ptr |= (frame_index % 0x100) << 8;
+							else
+								*ptr |= 0xff |
+									(sequence_index * 64 << 16);
+						}
+						break;
+
+					case STEP_SKIP:
+					default:
+						break;
+				}
+			}
+
+			bs_mapper_unmap(ctx->mapper, fb->bo, map_data);
+
+			usleep(1e6 / 120); /* 120 Hz */
+
+			fb_idx = fb_idx ^ 1;
+		}
+	}
+}
+
+static const struct option longopts[] = {
+	{ "help", no_argument, NULL, 'h' },
+	{ "dma-buf", no_argument, NULL, 'b' },
+	{ "gem", no_argument, NULL, 'g' },
+	{ "dumb", no_argument, NULL, 'd' },
+	{ "vgem", no_argument, NULL, 'v' },
+	{ "scanout", no_argument, NULL, 's' },
+	{ 0, 0, 0, 0 },
+};
+
+static void print_help(const char *argv0)
+{
+	printf("Usage: %s [OPTIONS]\n", argv0);
+	printf(" -h, --help     Print help.\n");
+	printf(" -b, --dma-buf  Use dma-buf mmap (by default).\n");
+	printf(" -g, --gem      Use GEM map.\n");
+	printf(" -d, --dumb     Use dump map.\n");
+	printf(" -v, --vgem     Use vgem dump map.\n");
+	printf(" -s, --scanout  Use buffer optimized for scanout.\n");
+}
+
+int main(int argc, char **argv)
+{
+	struct context ctx = { 0 };
+
+	do_fixes();
+
+	ctx.display_fd = bs_drm_open_main_display();
+	if (ctx.display_fd < 0) {
+		bs_debug_error("failed to open card for display");
+		return 1;
+	}
+
+	struct gbm_device *gbm = gbm_create_device(ctx.display_fd);
+	if (!gbm) {
+		bs_debug_error("failed to create gbm device");
+		return 1;
+	}
+
+	int c;
+	uint32_t flags = GBM_BO_USE_SCANOUT;
+	while ((c = getopt_long(argc, argv, "bgdvsh", longopts, NULL)) != -1) {
+		switch (c) {
+			case 'b':
+				ctx.mapper = bs_mapper_dma_buf_new();
+				flags |= GBM_BO_USE_LINEAR;
+				printf("started dma-buf mmap.\n");
+				break;
+			case 'g':
+				ctx.mapper = bs_mapper_gem_new();
+				flags |= GBM_BO_USE_SW_READ_OFTEN | GBM_BO_USE_SW_WRITE_OFTEN;
+				printf("started GEM map.\n");
+				break;
+			case 'd':
+				ctx.mapper = bs_mapper_dumb_new(gbm_device_get_fd(gbm));
+				flags |= GBM_BO_USE_LINEAR;
+				printf("started dumb map.\n");
+				break;
+			case 'v':
+				ctx.vgem_device_fd = bs_drm_open_vgem();
+				ctx.mapper = bs_mapper_dumb_new(ctx.vgem_device_fd);
+				printf("started vgem map.\n");
+				break;
+			case 's':
+				flags = GBM_BO_USE_SCANOUT;
+				break;
+			case 'h':
+			default:
+				print_help(argv[0]);
+				return 1;
+		}
+	}
+
+	// Use dma-buf mmap by default, in case any arguments aren't selected.
+	if (!ctx.mapper) {
+		ctx.mapper = bs_mapper_dma_buf_new();
+		printf("started dma-buf mmap.\n");
+	}
+
+	if (ctx.mapper == NULL) {
+		bs_debug_error("failed to create mapper object");
+		return 1;
+	}
+
+	struct bs_drm_pipe pipe = { 0 };
+	if (!bs_drm_pipe_make(ctx.display_fd, &pipe)) {
+		bs_debug_error("failed to make pipe");
+		return 1;
+	}
+
+	drmModeConnector *connector = drmModeGetConnector(ctx.display_fd, pipe.connector_id);
+	drmModeModeInfo *mode = &connector->modes[0];
+	ctx.crtc_id = pipe.crtc_id;
+
+	printf("display size: %ux%u\n", mode->hdisplay, mode->vdisplay);
+
+	for (size_t fb_index = 0; fb_index < BUFFERS; ++fb_index) {
+		struct framebuffer *fb = &ctx.fbs[fb_index];
+		fb->bo =
+		    gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, GBM_FORMAT_XRGB8888, flags);
+
+		if (!fb->bo) {
+			bs_debug_error("failed to create buffer object");
+			return 1;
+		}
+
+		fb->id = bs_drm_fb_create_gbm(fb->bo);
+		if (fb->id == 0) {
+			bs_debug_error("failed to create fb");
+			return 1;
+		}
+	}
+
+	if (drmModeSetCrtc(ctx.display_fd, pipe.crtc_id, ctx.fbs[0].id, 0, 0, &pipe.connector_id, 1,
+			   mode)) {
+		bs_debug_error("failed to set CRTC");
+		return 1;
+	}
+
+	draw(&ctx);
+
+	return 0;
+}