diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 6e07d93..40d7446 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -114,6 +114,7 @@ TESTS_progs_M = \
 	kms_plane \
 	kms_plane_multiple \
 	kms_plane_lowres \
+	kms_concurrent \
 	kms_properties \
 	kms_psr_sink_crc \
 	kms_render \
diff --git a/tests/kms_concurrent.c b/tests/kms_concurrent.c
new file mode 100644
index 0000000..b999dbe
--- /dev/null
+++ b/tests/kms_concurrent.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "drmtest.h"
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+
+IGT_TEST_DESCRIPTION("Test atomic mode setting concurrently with multiple planes and screen resolution");
+
+#define SIZE_PLANE      256
+#define SIZE_CURSOR     128
+#define LOOP_FOREVER     -1
+
+typedef struct {
+	float red;
+	float green;
+	float blue;
+} color_t;
+
+typedef struct {
+	int drm_fd;
+	uint32_t crtc_id;
+	uint32_t connector_id;
+	igt_display_t display;
+	igt_output_t *output;
+	int pipe;
+	igt_plane_t **plane;
+	struct igt_fb *fb;
+} data_t;
+
+typedef struct {
+	data_t *data;
+	igt_crc_t reference_crc;
+} test_position_t;
+
+/* Command line parameters. */
+struct {
+	int iterations;
+	bool user_seed;
+	int seed;
+	bool run;
+} opt = {
+	.iterations = 32,
+	.user_seed = false,
+	.seed = 1,
+	.run = true,
+};
+
+/*
+ * Common code across all tests, acting on data_t
+ */
+static void test_init(data_t *data, int n_planes)
+{
+	data->plane = calloc(n_planes, sizeof(data->plane));
+	igt_assert_f(data->plane != NULL, "Failed to allocate memory for planes\n");
+
+	data->fb = calloc(n_planes, sizeof(struct igt_fb));
+	igt_assert_f(data->fb != NULL, "Failed to allocate memory for FBs\n");
+}
+
+static void test_fini(data_t *data, igt_output_t *output, int n_planes)
+{
+	int i;
+
+	for (i = 0; i < n_planes; i++) {
+		igt_plane_t *plane = data->plane[i];
+
+		if (!plane)
+			continue;
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			continue;
+		igt_plane_set_fb(plane, NULL);
+		data->plane[i] = NULL;
+	}
+
+	/* reset the constraint on the pipe */
+	igt_output_set_pipe(output, PIPE_ANY);
+
+	free(data->plane);
+	data->plane = NULL;
+	free(data->fb);
+	data->fb = NULL;
+}
+
+static int
+display_commit_mode(data_t *data, igt_crc_t *crc)
+{
+	char buf[256];
+	struct drm_event *e = (void *)buf;
+	int n, ret;
+	int flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_NONBLOCK;
+
+	ret = igt_display_try_commit_atomic(&data->display,
+					    flags,
+					    NULL);
+	igt_skip_on(ret != 0);
+
+	igt_set_timeout(1, "Stuck on page flip");
+	ret = read(data->display.drm_fd, buf, sizeof(buf));
+	igt_assert(ret >= 0);
+
+	igt_assert_eq(e->type, DRM_EVENT_FLIP_COMPLETE);
+	igt_reset_timeout();
+
+	return n;
+}
+
+static void
+test_grab_crc(data_t *data, color_t *color, igt_crc_t *crc /* out */)
+{
+	drmModeModeInfo *mode;
+	igt_plane_t *primary;
+	int ret;
+
+	igt_output_set_pipe(data->output, data->pipe);
+
+	primary = igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_PRIMARY);
+	data->plane[primary->index] = primary;
+
+	mode = igt_output_get_mode(data->output);
+
+	igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+			    DRM_FORMAT_XRGB8888,
+			    LOCAL_I915_FORMAT_MOD_X_TILED,
+			    color->red, color->green, color->blue,
+			    &data->fb[primary->index]);
+
+	igt_plane_set_fb(data->plane[primary->index], &data->fb[primary->index]);
+
+	ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
+	igt_skip_on(ret != 0);
+}
+
+/*
+ * Multiple plane position test.
+ *   - We start by grabbing a reference CRC of a full blue fb being scanned
+ *     out on the primary plane
+ *   - Then we scannout number of planes:
+ *      * the primary plane uses a blue fb with a black rectangle hole
+ *      * planes, on top of the primary plane, with a blue fb that is set-up
+ *        to cover the black rectangles of the primary plane fb
+ *     The resulting CRC should be identical to the reference CRC
+ */
+
+static void
+create_fb_for_mode_position(data_t *data, drmModeModeInfo *mode,
+			    color_t *color, int *rect_x, int *rect_y,
+			    int *rect_w, int *rect_h, uint64_t tiling,
+			    int max_planes)
+{
+	unsigned int fb_id;
+	cairo_t *cr;
+	igt_plane_t *primary;
+
+	primary = igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_PRIMARY);
+
+	fb_id = igt_create_fb(data->drm_fd,
+			      mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XRGB8888,
+			      tiling,
+			      &data->fb[primary->index]);
+	igt_assert(fb_id);
+
+	cr = igt_get_cairo_ctx(data->drm_fd, &data->fb[primary->index]);
+	igt_paint_color(cr, rect_x[0], rect_y[0],
+			mode->hdisplay, mode->vdisplay,
+			color->red, color->green, color->blue);
+
+	for (int i = 0; i < max_planes; i++) {
+		if (data->plane[i]->type == DRM_PLANE_TYPE_PRIMARY)
+			continue;
+		igt_paint_color(cr, rect_x[i], rect_y[i],
+				rect_w[i], rect_h[i], 0.0, 0.0, 0.0);
+	}
+
+	igt_assert(cairo_status(cr) == 0);
+	cairo_destroy(cr);
+}
+
+static void
+prepare_planes(data_t *data, color_t *color, int max_planes)
+{
+	drmModeModeInfo *mode;
+	igt_pipe_t *pipe;
+	igt_plane_t *primary;
+	int *x;
+	int *y;
+	int *size;
+	int i;
+
+	igt_output_set_pipe(data->output, data->pipe);
+	primary = igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_PRIMARY);
+	pipe = primary->pipe;
+
+	x = malloc(pipe->n_planes * sizeof(*x));
+	igt_assert_f(x, "Failed to allocate %ld bytes for variable x\n", (long int) (pipe->n_planes * sizeof(*x)));
+	y = malloc(pipe->n_planes * sizeof(*y));
+	igt_assert_f(y, "Failed to allocate %ld bytes for variable y\n", (long int) (pipe->n_planes * sizeof(*y)));
+	size = malloc(pipe->n_planes * sizeof(*size));
+	igt_assert_f(size, "Failed to allocate %ld bytes for variable size\n", (long int) (pipe->n_planes * sizeof(*size)));
+
+	mode = igt_output_get_mode(data->output);
+
+	/* planes with random positions */
+	x[primary->index] = 0;
+	y[primary->index] = 0;
+	for (i = 0; i < max_planes; i++) {
+		igt_plane_t *plane = igt_output_get_plane(data->output, i);
+
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			continue;
+		else if (plane->type == DRM_PLANE_TYPE_CURSOR)
+			size[i] = SIZE_CURSOR;
+		else
+			size[i] = SIZE_PLANE;
+
+		x[i] = rand() % (mode->hdisplay - size[i]);
+		y[i] = rand() % (mode->vdisplay - size[i]);
+
+		data->plane[i] = plane;
+
+		igt_create_color_fb(data->drm_fd,
+				    size[i], size[i],
+				    data->plane[i]->type == DRM_PLANE_TYPE_CURSOR ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888,
+				    data->plane[i]->type == DRM_PLANE_TYPE_CURSOR ? LOCAL_DRM_FORMAT_MOD_NONE : LOCAL_I915_FORMAT_MOD_X_TILED,
+				    color->red, color->green, color->blue,
+				    &data->fb[i]);
+
+		igt_plane_set_position(data->plane[i], x[i], y[i]);
+		igt_plane_set_fb(data->plane[i], &data->fb[i]);
+	}
+
+	/* primary plane */
+	data->plane[primary->index] = primary;
+	create_fb_for_mode_position(data, mode, color, x, y, size, size,
+				    LOCAL_I915_FORMAT_MOD_X_TILED, max_planes);
+	igt_plane_set_fb(data->plane[primary->index], &data->fb[primary->index]);
+}
+
+static void *
+test_plane_position_with_output(void *args)
+{
+	data_t *data = (data_t *)args;
+	igt_crc_t *crc;
+	color_t blue  = { 0.0f, 0.0f, 1.0f };
+	int i;
+	int iterations = opt.iterations < 1 ? 1 : opt.iterations;
+	bool loop_forever;
+	char info[256];
+	int max_planes = data->display.pipes[data->pipe].n_planes;
+
+	if (opt.iterations == LOOP_FOREVER) {
+		loop_forever = true;
+		sprintf(info, "forever");
+	} else {
+		loop_forever = false;
+		sprintf(info, "for %d %s",
+			iterations, iterations > 1 ? "iterations" : "iteration");
+	}
+
+	igt_info("Testing connector %s using pipe %s with %d planes %s with seed %d\n",
+		 igt_output_name(data->output), kmstest_pipe_name(data->pipe), max_planes,
+		 info, opt.seed);
+
+	i = 0;
+	while (i < iterations || loop_forever) {
+		prepare_planes(data, &blue, max_planes);
+
+		display_commit_mode(data, crc);
+
+		i++;
+	}
+
+	opt.run = false;
+
+	return NULL;
+}
+
+static drmModeConnector *
+get_connector_connected(int drm_fd)
+{
+	drmModeRes *resources = drmModeGetResources(drm_fd);
+	drmModeConnector *connector;
+	int i;
+
+	for (i = 0; i < resources->count_connectors; i++) {
+		connector = drmModeGetConnector(drm_fd,
+						resources->connectors[i]);
+
+		if (connector->connection == DRM_MODE_CONNECTED)
+			break;
+
+		drmModeFreeConnector(connector);
+		connector = NULL;
+	}
+
+	drmModeFreeResources(resources);
+
+	return connector;
+}
+
+static int get_crtc_for_encoder(drmModeRes *resources,
+				drmModeEncoder *encoder)
+{
+	int mask, id;
+	int i;
+	bool found;
+
+	for (i = 0; i < resources->count_crtcs; i++) {
+		mask = 1 << i;
+		id = resources->crtcs[i];
+
+		found = encoder->possible_crtcs & mask;
+		if (found)
+			break;
+	}
+
+	if (!found)
+		return -EINVAL;
+
+	return id;
+}
+
+static int get_crtc_for_connector(int drm_fd, drmModeRes *resources,
+				  drmModeConnector *connector)
+{
+	drmModeEncoder *encoder;
+	int encoder_id;
+	int crtc_id;
+	int i;
+
+	for (i = 0; i < connector->count_encoders; i++) {
+		encoder_id = connector->encoders[i];
+		encoder = drmModeGetEncoder(drm_fd, encoder_id);
+
+		if (encoder) {
+			crtc_id = get_crtc_for_encoder(resources, encoder);
+
+			drmModeFreeEncoder(encoder);
+
+			if (crtc_id != 0)
+				break;
+		}
+	}
+
+	if (crtc_id == 0)
+		return -EINVAL;
+
+	return crtc_id;
+}
+
+static int get_crtc(int drm_fd)
+{
+	drmModeRes *resources;
+	drmModeConnector *connector;
+	drmModeEncoder *encoder;
+	int i, id;
+
+	resources = drmModeGetResources(drm_fd);
+	connector = get_connector_connected(drm_fd);
+
+	for (i = 0; i < resources->count_encoders; i++) {
+		encoder = drmModeGetEncoder(drm_fd, resources->encoders[i]);
+
+		if (encoder->encoder_id == connector->encoder_id)
+			break;
+
+		drmModeFreeEncoder(encoder);
+		encoder = NULL;
+	}
+
+	if (encoder)
+		return encoder->crtc_id;
+
+	id = get_crtc_for_connector(drm_fd, resources, connector);
+	igt_assert(id != 0);
+
+	return id;
+}
+
+static drmModeModeInfo *
+get_lowres_mode(data_t *data, drmModeModeInfo *mode_default)
+{
+	drmModeRes *resources = drmModeGetResources(data->drm_fd);
+	drmModeModeInfo std_1024_mode = {
+		.clock = 65000,
+		.hdisplay = 1024,
+		.hsync_start = 1048,
+		.hsync_end = 1184,
+		.htotal = 1344,
+		.hskew = 0,
+		.vdisplay = 768,
+		.vsync_start = 771,
+		.vsync_end = 777,
+		.vtotal = 806,
+		.vscan = 0,
+		.vrefresh = 60,
+		.flags = 0xA,
+		.type = 0x40,
+		.name = "Custom 1024x768",
+	};
+	drmModeModeInfo *mode;
+	drmModeConnector *connector;
+	bool found;
+	int limit = mode_default->vdisplay-SIZE_PLANE;
+	int i, j;
+
+	if (!resources) {
+		igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
+		return mode;
+	}
+
+	found = false;
+	for (i = 0; i < resources->count_connectors; i++) {
+
+		connector = drmModeGetConnectorCurrent(data->drm_fd,
+						       resources->connectors[i]);
+
+		if (!connector) {
+			igt_warn("could not get connector %i: %s\n",
+				 resources->connectors[i], strerror(errno));
+			continue;
+		}
+
+		if (!connector->count_modes)
+			continue;
+
+		for (j = 0; j < connector->count_modes; j++) {
+			mode = &connector->modes[j];
+
+			if (mode->vdisplay < limit) {
+				found = true;
+				break;
+			}
+		}
+
+		drmModeFreeConnector(connector);
+	}
+
+	drmModeFreeResources(resources);
+
+	if (!found)
+		mode = &std_1024_mode;
+
+	return mode;
+}
+
+static void *
+test_resolution_with_output(void *args)
+{
+	data_t *data = (data_t *)args;
+	drmModeModeInfo *mode_hi, *mode_lo;
+	int ret;
+	int min = 20;
+	int max = 50;
+	int t;
+
+	igt_info("Testing resolution with connector %s using pipe %s with seed %d\n",
+		 igt_output_name(data->output), kmstest_pipe_name(data->pipe), opt.seed);
+
+	mode_hi = igt_output_get_mode(data->output);
+	mode_lo = get_lowres_mode(data, mode_hi);
+
+	while (opt.run) {
+		/* switch to lower resolution */
+		ret = drmModeSetCrtc(data->drm_fd, data->crtc_id, data->fb->fb_id, 0, 0,
+				     &data->connector_id, 1, mode_lo);
+		igt_assert_eq(ret, 0);
+
+		/* random timeout in ms */
+		t = (rand() % (max + 1 - min)) + min;
+		usleep(t * 1000);
+
+		/* switch back to higher resolution */
+		ret = drmModeSetCrtc(data->drm_fd, data->crtc_id, data->fb->fb_id, 0, 0,
+				     &data->connector_id, 1, mode_hi);
+		igt_assert_eq(ret, 0);
+	}
+
+	return NULL;
+}
+
+static void
+run_test(data_t *data, enum pipe pipe)
+{
+	pthread_t plane_thread;
+	pthread_t res_thread;
+	void *plane_ret, *res_ret;
+	color_t blue  = { 0.0f, 0.0f, 1.0f };
+	test_position_t test = { .data = data };
+	int connected_outs;
+	int max_planes = data->display.pipes[data->pipe].n_planes;
+
+	if (!opt.user_seed)
+		opt.seed = time(NULL);
+
+	connected_outs = 0;
+	for_each_valid_output_on_pipe(&data->display, pipe, data->output) {
+		data->pipe = pipe;
+
+		data->connector_id = get_connector_connected(data->drm_fd)->connector_id;
+		igt_assert(data->connector_id != -EINVAL);
+
+		data->crtc_id = get_crtc(data->drm_fd);
+		igt_assert(data->crtc_id != -EINVAL);
+
+		test_init(data, max_planes);
+
+		test_grab_crc(data, &blue, &test.reference_crc);
+
+		if (pthread_create(&plane_thread, NULL, test_plane_position_with_output, data))
+			igt_assert(false);
+
+		if (pthread_create(&res_thread, NULL, test_resolution_with_output, data))
+			igt_assert(false);
+
+		if (pthread_join(plane_thread, (void **)&plane_ret))
+			igt_assert(false);
+
+		if (pthread_join(res_thread, (void **)&res_ret))
+			igt_assert(false);
+
+		test_fini(data, data->output, max_planes);
+
+		connected_outs++;
+	}
+
+	igt_skip_on(connected_outs == 0);
+}
+
+static void
+run_tests_for_pipe(data_t *data, enum pipe pipe)
+{
+	igt_output_t *output;
+
+	igt_fixture {
+		int valid_tests = 0;
+
+		igt_skip_on(pipe >= data->display.n_pipes);
+
+		for_each_valid_output_on_pipe(&data->display, pipe, output)
+			valid_tests++;
+
+		igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
+		igt_require(data->display.pipes[pipe].n_planes > 0);
+		igt_require(data->display.is_atomic);
+	}
+
+	igt_subtest_f("pipe-%s-basic", kmstest_pipe_name(pipe))
+		for_each_valid_output_on_pipe(&data->display, pipe, output)
+			run_test(data, pipe);
+}
+
+static int opt_handler(int option, int option_index, void *input)
+{
+	switch (option) {
+	case 'i':
+		opt.iterations = strtol(optarg, NULL, 0);
+
+		if (opt.iterations < LOOP_FOREVER || opt.iterations == 0) {
+			igt_info("incorrect number of iterations\n");
+			igt_assert(false);
+		}
+
+		break;
+	case 's':
+		opt.user_seed = true;
+		opt.seed = strtol(optarg, NULL, 0);
+		break;
+	default:
+		igt_assert(false);
+	}
+
+	return 0;
+}
+
+const char *help_str =
+	"  --iterations Number of iterations for test coverage. -1 loop forever, default 64 iterations\n"
+	"  --seed       Seed for random number generator\n";
+
+static data_t data;
+
+int main(int argc, char *argv[])
+{
+	struct option long_options[] = {
+		{ "iterations", required_argument, NULL, 'i'},
+		{ "seed",    required_argument, NULL, 's'},
+		{ 0, 0, 0, 0 }
+	};
+
+	igt_subtest_init_parse_opts(&argc, argv, "", long_options, help_str,
+				    opt_handler, NULL);
+
+	igt_skip_on_simulation();
+
+	igt_fixture {
+		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+		kmstest_set_vt_graphics_mode();
+		igt_display_init(&data.display, data.drm_fd);
+		igt_require(data.display.n_pipes > 0);
+	}
+
+	for (int pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
+		igt_subtest_group
+			run_tests_for_pipe(&data, pipe);
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+	}
+
+	igt_exit();
+}
