diff --git a/tests/.gitignore b/tests/.gitignore
index c31b22a..0af0899 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -131,6 +131,7 @@ kms_addfb
 kms_cursor_crc
 kms_draw_crc
 kms_fbc_crc
+kms_fbcon_fbt
 kms_fence_pin_leak
 kms_flip
 kms_flip_event_leak
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index b9479cc..c94714b 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -65,6 +65,7 @@ TESTS_progs_M = \
 	kms_cursor_crc \
 	kms_draw_crc \
 	kms_fbc_crc \
+	kms_fbcon_fbt \
 	kms_flip \
 	kms_flip_event_leak \
 	kms_flip_tiling \
diff --git a/tests/kms_fbcon_fbt.c b/tests/kms_fbcon_fbt.c
new file mode 100644
index 0000000..e5d2d33
--- /dev/null
+++ b/tests/kms_fbcon_fbt.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright © 2015 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.
+ *
+ * Authors:
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "drmtest.h"
+#include "igt_aux.h"
+#include "igt_debugfs.h"
+#include "igt_draw.h"
+#include "igt_kms.h"
+
+IGT_TEST_DESCRIPTION("Test the relationship between fbcon and the frontbuffer "
+		     "tracking infrastructure.");
+
+#define MAX_CONNECTORS 32
+#define DEBUGFS_MSG_SIZE 256
+
+static bool do_wait_user = false;
+
+struct drm_info {
+	int fd;
+	drmModeResPtr res;
+	drmModeConnectorPtr connectors[MAX_CONNECTORS];
+};
+
+struct fbc_info {
+	int fd;
+};
+
+struct psr_info {
+	int fd;
+};
+
+enum feature_status {
+	ENABLED,
+	DISABLED,
+};
+
+static void wait_user(const char *msg)
+{
+	if (!do_wait_user)
+		return;
+
+	igt_info("%s Press enter...\n", msg);
+	while (getchar() != '\n')
+		;
+}
+
+static void setup_drm(struct drm_info *drm)
+{
+	int i;
+
+	drm->fd = drm_open_any_master();
+
+	drm->res = drmModeGetResources(drm->fd);
+	igt_assert(drm->res->count_connectors <= MAX_CONNECTORS);
+
+	for (i = 0; i < drm->res->count_connectors; i++)
+		drm->connectors[i] = drmModeGetConnector(drm->fd,
+						drm->res->connectors[i]);
+
+	kmstest_set_vt_graphics_mode();
+}
+
+static void teardown_drm(struct drm_info *drm)
+{
+	int i;
+
+	kmstest_restore_vt_mode();
+
+	for (i = 0; i < drm->res->count_connectors; i++)
+		drmModeFreeConnector(drm->connectors[i]);
+
+	drmModeFreeResources(drm->res);
+	igt_assert(close(drm->fd) == 0);
+}
+
+static void get_debugfs_string(int fd, char *buf)
+{
+	ssize_t n_read;
+
+	lseek(fd, 0, SEEK_SET);
+
+	n_read = read(fd, buf, DEBUGFS_MSG_SIZE -1);
+	igt_assert(n_read >= 0);
+	buf[n_read] = '\0';
+}
+
+static bool fbc_supported_on_chipset(int fd)
+{
+	char buf[DEBUGFS_MSG_SIZE];
+
+	get_debugfs_string(fd, buf);
+	return !strstr(buf, "FBC unsupported on this chipset\n");
+}
+
+static void setup_fbc(struct fbc_info *fbc)
+{
+	fbc->fd = igt_debugfs_open("i915_fbc_status", O_RDONLY);
+	igt_assert(fbc->fd >= 0);
+
+	igt_require_f(fbc_supported_on_chipset(fbc->fd),
+		      "Can't test FBC: not supported on this chipset\n");
+
+	igt_set_module_param_int("enable_fbc", 1);
+}
+
+static void teardown_fbc(struct fbc_info *fbc)
+{
+	igt_assert(close(fbc->fd) == 0);
+}
+
+static bool connector_can_fbc(drmModeConnectorPtr connector)
+{
+	return true;
+}
+
+static bool fbc_get_status(int fd)
+{
+	char buf[DEBUGFS_MSG_SIZE];
+
+	get_debugfs_string(fd, buf);
+
+	if (strstr(buf, "FBC enabled\n"))
+		return ENABLED;
+	else
+		return DISABLED;
+}
+
+static bool fbc_wait_for_status(struct fbc_info *fbc,
+				enum feature_status status)
+{
+	return igt_wait(fbc_get_status(fbc->fd) == status, 5000, 1);
+}
+
+typedef bool (*connector_possible_fn)(drmModeConnectorPtr connector);
+
+static void set_mode_for_one_screen(struct drm_info *drm, struct igt_fb *fb,
+				    connector_possible_fn connector_possible)
+{
+	int i, rc;
+	uint32_t connector_id = 0, crtc_id;
+	drmModeModeInfoPtr mode;
+	uint32_t buffer_id;
+	drmModeConnectorPtr c = NULL;
+
+	for (i = 0; i < drm->res->count_connectors; i++) {
+		c = drm->connectors[i];
+
+		if (c->connection == DRM_MODE_CONNECTED && c->count_modes &&
+		    connector_possible(c)) {
+			connector_id = c->connector_id;
+			mode = &c->modes[0];
+			break;
+		}
+	}
+	igt_require_f(connector_id, "No connector available\n");
+
+	crtc_id = drm->res->crtcs[0];
+
+	buffer_id = igt_create_fb(drm->fd, mode->hdisplay, mode->vdisplay,
+				  DRM_FORMAT_XRGB8888,
+				  LOCAL_I915_FORMAT_MOD_X_TILED, fb);
+	igt_draw_fill_fb(drm->fd, fb, 0xFF);
+
+	igt_info("Setting %dx%d mode for %s connector\n",
+		 mode->hdisplay, mode->vdisplay,
+		 kmstest_connector_type_str(c->connector_type));
+
+	rc = drmModeSetCrtc(drm->fd, crtc_id, buffer_id, 0, 0, &connector_id, 1,
+			    mode);
+	igt_assert_eq(rc, 0);
+}
+
+static void fbc_subtest(void)
+{
+	struct drm_info drm;
+	struct fbc_info fbc;
+	struct igt_fb fb;
+
+	setup_fbc(&fbc);
+
+	setup_drm(&drm);
+
+	kmstest_unset_all_crtcs(drm.fd, drm.res);
+	wait_user("Modes unset.");
+	igt_assert(fbc_wait_for_status(&fbc, DISABLED));
+
+	set_mode_for_one_screen(&drm, &fb, connector_can_fbc);
+	wait_user("FBC screen set.");
+	igt_assert(fbc_wait_for_status(&fbc, ENABLED));
+
+	igt_remove_fb(drm.fd, &fb);
+	teardown_drm(&drm);
+
+	/* Wait for fbcon to restore itself. */
+	sleep(5);
+
+	wait_user("Back to fbcon.");
+	igt_assert(fbc_wait_for_status(&fbc, DISABLED));
+
+	teardown_fbc(&fbc);
+}
+
+static bool psr_supported_on_chipset(int fd)
+{
+	char buf[DEBUGFS_MSG_SIZE];
+
+	get_debugfs_string(fd, buf);
+
+	return strstr(buf, "Sink_Support: yes\n");
+}
+
+static void setup_psr(struct psr_info *psr)
+{
+	psr->fd = igt_debugfs_open("i915_edp_psr_status", O_RDONLY);
+	igt_assert(psr->fd >= 0);
+
+	igt_require_f(psr_supported_on_chipset(psr->fd),
+		      "Can't test PSR: not supported on this chipset\n");
+
+	igt_set_module_param_int("enable_psr", 1);
+}
+
+static void teardown_psr(struct psr_info *psr)
+{
+	igt_assert(close(psr->fd) == 0);
+}
+
+static bool connector_can_psr(drmModeConnectorPtr connector)
+{
+	return (connector->connector_type == DRM_MODE_CONNECTOR_eDP);
+}
+
+static bool psr_get_status(int fd)
+{
+	char buf[DEBUGFS_MSG_SIZE];
+
+	get_debugfs_string(fd, buf);
+
+	if (strstr(buf, "\nActive: yes\n"))
+		return ENABLED;
+	else
+		return DISABLED;
+}
+
+static bool psr_wait_for_status(struct psr_info *psr,
+				enum feature_status status)
+{
+	return igt_wait(psr_get_status(psr->fd) == status, 5000, 1);
+}
+
+static void psr_subtest(void)
+{
+	struct drm_info drm;
+	struct psr_info psr;
+	struct igt_fb fb;
+
+	setup_psr(&psr);
+
+	setup_drm(&drm);
+
+	kmstest_unset_all_crtcs(drm.fd, drm.res);
+	wait_user("Modes unset.");
+	igt_assert(psr_wait_for_status(&psr, DISABLED));
+
+	set_mode_for_one_screen(&drm, &fb, connector_can_psr);
+	wait_user("PSR screen set.");
+	igt_assert(psr_wait_for_status(&psr, ENABLED));
+
+	igt_remove_fb(drm.fd, &fb);
+	teardown_drm(&drm);
+
+	/* Wait for fbcon to restore itself. */
+	sleep(5);
+
+	wait_user("Back to fbcon.");
+	igt_assert(psr_wait_for_status(&psr, DISABLED));
+
+	teardown_psr(&psr);
+}
+
+static void setup_environment(void)
+{
+	int drm_fd;
+
+	drm_fd = drm_open_any_master();
+	igt_require(drm_fd >= 0);
+	igt_assert(close(drm_fd) == 0);
+}
+
+static void teardown_environment(void)
+{
+}
+
+igt_main
+{
+	igt_fixture
+		setup_environment();
+
+	igt_subtest("fbc")
+		fbc_subtest();
+	igt_subtest("psr")
+		psr_subtest();
+
+	igt_fixture
+		teardown_environment();
+}
