@@ -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
@@ -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 \
new file mode 100644
@@ -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();
+}