diff --git a/tests/kms_flip_tiling.c b/tests/kms_flip_tiling.c
index 8345505..c7fd4de 100644
--- a/tests/kms_flip_tiling.c
+++ b/tests/kms_flip_tiling.c
@@ -35,8 +35,7 @@
 #include "ioctl_wrappers.h"
 #include "intel_chipset.h"
 
-IGT_TEST_DESCRIPTION("Test that a page flip from a tiled buffer to a linear"
-		     " one works correctly.");
+IGT_TEST_DESCRIPTION("Test page flips and tiling scenarios");
 
 typedef struct {
 	int drm_fd;
@@ -44,16 +43,8 @@ typedef struct {
 	int gen;
 } data_t;
 
-/*
- * Test that a page flip from a tiled buffer to a linear one works
- * correctly. First, it sets the crtc with the linear buffer and generate
- * a reference crc for the pipe. Then, the crtc is set with the tiled one
- * and page flip to the linear one issued. A new crc is generated and
- * compared to the rerence one.
- */
-
 static void
-fill_linear_fb(struct igt_fb *fb, data_t *data, drmModeModeInfo *mode)
+fill_fb(struct igt_fb *fb, data_t *data, drmModeModeInfo *mode)
 {
 	cairo_t *cr;
 
@@ -62,67 +53,124 @@ fill_linear_fb(struct igt_fb *fb, data_t *data, drmModeModeInfo *mode)
 	cairo_destroy(cr);
 }
 
+static igt_pipe_crc_t *_pipe_crc;
+
+static igt_pipe_crc_t *pipe_crc_new(int pipe)
+{
+	if (_pipe_crc) {
+		igt_pipe_crc_free(_pipe_crc);
+		_pipe_crc = NULL;
+	}
+
+	_pipe_crc = igt_pipe_crc_new(pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
+	igt_assert(_pipe_crc);
+
+	return _pipe_crc;
+}
+
+static void pipe_crc_free(void)
+{
+	if (_pipe_crc) {
+		igt_pipe_crc_free(_pipe_crc);
+		_pipe_crc = NULL;
+	}
+}
+
+static void wait_for_pageflip(int fd)
+{
+	drmEventContext evctx = { .version = DRM_EVENT_CONTEXT_VERSION };
+	struct timeval timeout = { .tv_sec = 0, .tv_usec = 32000 };
+	fd_set fds;
+	int ret;
+
+	/* Wait for pageflip completion, then consume event on fd */
+	FD_ZERO(&fds);
+	FD_SET(fd, &fds);
+	do {
+		ret = select(fd + 1, &fds, NULL, NULL, &timeout);
+	} while (ret < 0 && errno == EINTR);
+	igt_assert_eq(ret, 1);
+	igt_assert(drmHandleEvent(fd, &evctx) == 0);
+}
+
 static void
-test_flip_changes_tiling(data_t *data, igt_output_t *output, uint64_t tiling)
+test_flip_tiling(data_t *data, igt_output_t *output, uint64_t tiling[2])
 {
-	struct igt_fb linear, tiled;
 	drmModeModeInfo *mode;
 	igt_plane_t *primary;
+	struct igt_fb fb[2];
 	igt_pipe_crc_t *pipe_crc;
 	igt_crc_t reference_crc, crc;
 	int fb_id, pipe, ret, width;
 
 	pipe = output->config.pipe;
-	pipe_crc = igt_pipe_crc_new(pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
+	pipe_crc = pipe_crc_new(pipe);
 	igt_output_set_pipe(output, pipe);
 
 	mode = igt_output_get_mode(output);
 	primary = igt_output_get_plane(output, 0);
 
-	/* Allocate a linear buffer. Since a page flip to a buffer with
-	 * different stride doesn't work, choose width so that the stride of
-	 * both buffers is the same. */
-	width = 512;
-	while (width < mode->hdisplay)
-		width *= 2;
+	width = mode->hdisplay;
+
+	if (tiling[0] != tiling[1] &&
+	    (tiling[0] != LOCAL_DRM_FORMAT_MOD_NONE ||
+	     tiling[1] != LOCAL_DRM_FORMAT_MOD_NONE)) {
+		/*
+		 * Since a page flip to a buffer with different stride
+		 * doesn't work, choose width so that the stride of both
+		 * buffers is the same.
+		 */
+		width = 512;
+		while (width < mode->hdisplay)
+			width *= 2;
+	}
+
 	fb_id = igt_create_fb(data->drm_fd, width, mode->vdisplay,
-			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
-			      &linear);
+			      DRM_FORMAT_XRGB8888, tiling[0],
+			      &fb[0]);
+	igt_assert(fb_id);
+
+	/* Second fb has different background so CRC does not match. */
+	fb_id = igt_create_color_fb(data->drm_fd, width, mode->vdisplay,
+				    DRM_FORMAT_XRGB8888, tiling[1],
+				    0.5, 0.5, 0.5, &fb[1]);
+	igt_assert(fb_id);
 
-	/* fill it with a pattern that will look wrong if tiling is wrong */
-	fill_linear_fb(&linear, data, mode);
+	fill_fb(&fb[0], data, mode);
+	fill_fb(&fb[1], data, mode);
 
-	/* set the crtc and generate a reference crc */
-	igt_plane_set_fb(primary, &linear);
+	/* Set the crtc and generate a reference CRC. */
+	igt_plane_set_fb(primary, &fb[1]);
 	igt_display_commit(&data->display);
 	igt_pipe_crc_collect_crc(pipe_crc, &reference_crc);
 
-	/* allocate a tiled buffer and set the crtc with it */
-	igt_create_color_fb(data->drm_fd, width, mode->vdisplay,
-			    DRM_FORMAT_XRGB8888, tiling,
-			    0.0, 0.0, 0.0, &tiled);
-	igt_plane_set_fb(primary, &tiled);
+	/* Commit the first fb. */
+	igt_plane_set_fb(primary, &fb[0]);
 	igt_display_commit(&data->display);
 
-	/* flip to the linear buffer */
+	/* Flip to the second fb. */
 	ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
-			      fb_id, 0, NULL);
-	igt_assert_eq(ret, 0);
+			      fb[1].fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL);
+	/*
+	 * Page flip should work but some transitions may be temporarily
+	 * on some kernels.
+	 */
+	igt_require(ret == 0);
 
-	igt_wait_for_vblank(data->drm_fd, pipe);
+	wait_for_pageflip(data->drm_fd);
 
-	/* get a crc and compare with the reference */
+	/* Get a crc and compare with the reference. */
 	igt_pipe_crc_collect_crc(pipe_crc, &crc);
 	igt_assert_crc_equal(&reference_crc, &crc);
 
-	/* clean up */
+	/* Clean up. */
 	igt_plane_set_fb(primary, NULL);
-	igt_pipe_crc_free(pipe_crc);
+	pipe_crc_free();
 	igt_output_set_pipe(output, PIPE_ANY);
 	igt_display_commit(&data->display);
 
-	igt_remove_fb(data->drm_fd, &tiled);
-	igt_remove_fb(data->drm_fd, &linear);
+	igt_remove_fb(data->drm_fd, &fb[0]);
+	igt_remove_fb(data->drm_fd, &fb[1]);
 }
 
 static data_t data;
@@ -142,28 +190,118 @@ igt_main
 		igt_display_init(&data.display, data.drm_fd);
 	}
 
+	/*
+	 * Test that a page flip from a tiled buffer to a linear one works
+	 * correctly. First, it sets the crtc with the linear buffer and
+	 * generates a reference crc for the pipe. Then, the crtc is set with
+	 * the tiled one and page flip to the linear one issued. A new crc is
+	 * generated and compared to the reference one.
+	 */
+
 	igt_subtest_f("flip-changes-tiling") {
+		uint64_t tiling[2] = { LOCAL_I915_FORMAT_MOD_X_TILED,
+				       LOCAL_DRM_FORMAT_MOD_NONE };
+
 		for_each_connected_output(&data.display, output)
-			test_flip_changes_tiling(&data, output,
-						LOCAL_I915_FORMAT_MOD_X_TILED);
+			test_flip_tiling(&data, output, tiling);
 	}
 
 	igt_subtest_f("flip-changes-tiling-Y") {
+		uint64_t tiling[2] = { LOCAL_I915_FORMAT_MOD_Y_TILED,
+				       LOCAL_DRM_FORMAT_MOD_NONE };
+
 		igt_require_fb_modifiers(data.drm_fd);
 		igt_require(data.gen >= 9);
 
 		for_each_connected_output(&data.display, output)
-			test_flip_changes_tiling(&data, output,
-						LOCAL_I915_FORMAT_MOD_Y_TILED);
+			test_flip_tiling(&data, output, tiling);
 	}
 
 	igt_subtest_f("flip-changes-tiling-Yf") {
+		uint64_t tiling[2] = { LOCAL_I915_FORMAT_MOD_Yf_TILED,
+				       LOCAL_DRM_FORMAT_MOD_NONE };
+
+		igt_require_fb_modifiers(data.drm_fd);
+		igt_require(data.gen >= 9);
+
+		for_each_connected_output(&data.display, output)
+			test_flip_tiling(&data, output, tiling);
+	}
+
+	/*
+	 * Test that a page flip from a tiled buffer to another tiled one works
+	 * correctly. First, it sets the crtc with the tiled buffer and
+	 * generates a reference crc for the pipe. Then a page flip to second
+	 * tiled buffer is issued. A new crc is generated and compared to the
+	 * reference one.
+	 */
+
+	igt_subtest_f("flip-X-tiled") {
+		uint64_t tiling[2] = { LOCAL_I915_FORMAT_MOD_X_TILED,
+				       LOCAL_I915_FORMAT_MOD_X_TILED };
+
+		for_each_connected_output(&data.display, output)
+			test_flip_tiling(&data, output, tiling);
+	}
+
+	igt_subtest_f("flip-Y-tiled") {
+		uint64_t tiling[2] = { LOCAL_I915_FORMAT_MOD_Y_TILED,
+				       LOCAL_I915_FORMAT_MOD_Y_TILED };
+
+		igt_require_fb_modifiers(data.drm_fd);
+		igt_require(data.gen >= 9);
+
+		for_each_connected_output(&data.display, output)
+			test_flip_tiling(&data, output, tiling);
+	}
+
+	igt_subtest_f("flip-Yf-tiled") {
+		uint64_t tiling[2] = { LOCAL_I915_FORMAT_MOD_Yf_TILED,
+				       LOCAL_I915_FORMAT_MOD_Yf_TILED };
+
+		igt_require_fb_modifiers(data.drm_fd);
+		igt_require(data.gen >= 9);
+
+		for_each_connected_output(&data.display, output)
+			test_flip_tiling(&data, output, tiling);
+	}
+
+	/*
+	 * Test that a page flip from a linear buffer to a tiled one works
+	 * correctly. First, it sets the crtc with the linear buffer and
+	 * generates a reference crc for the pipe. Then a page flip to a tiled
+	 * buffer is issued. A new crc is generated and compared to the
+	 * reference one.
+	 */
+
+	igt_subtest_f("flip-to-X-tiled") {
+		uint64_t tiling[2] = { LOCAL_DRM_FORMAT_MOD_NONE,
+				       LOCAL_I915_FORMAT_MOD_X_TILED };
+
+		for_each_connected_output(&data.display, output)
+			test_flip_tiling(&data, output, tiling);
+	}
+
+	igt_subtest_f("flip-to-Y-tiled") {
+		uint64_t tiling[2] = { LOCAL_DRM_FORMAT_MOD_NONE,
+				       LOCAL_I915_FORMAT_MOD_Y_TILED };
+
+		igt_require_fb_modifiers(data.drm_fd);
+		igt_require(data.gen >= 9);
+
+		for_each_connected_output(&data.display, output)
+			test_flip_tiling(&data, output, tiling);
+	}
+
+	igt_subtest_f("flip-to-Yf-tiled") {
+		uint64_t tiling[2] = { LOCAL_DRM_FORMAT_MOD_NONE,
+				       LOCAL_I915_FORMAT_MOD_Yf_TILED };
+
 		igt_require_fb_modifiers(data.drm_fd);
 		igt_require(data.gen >= 9);
 
 		for_each_connected_output(&data.display, output)
-			test_flip_changes_tiling(&data, output,
-						LOCAL_I915_FORMAT_MOD_Yf_TILED);
+			test_flip_tiling(&data, output, tiling);
 	}
 
 	igt_fixture {
