This is in continuation of last patch "https://patchwork.freedesktop.
org/patch/117149/"
Signed-off-by: Lohith BS <[email protected]>
Signed-off-by: Ramalingam C <[email protected]>
Signed-off-by: Vandana Kannan <[email protected]>
Signed-off-by: aknautiy <[email protected]>
---
tests/kms_frontbuffer_tracking.c | 453
++++++++++++++++++++++++++++++++++++++-
1 file changed, 452 insertions(+), 1 deletion(-)
diff --git a/tests/kms_frontbuffer_tracking.c
b/tests/kms_frontbuffer_tracking.c
index c24e4a8..4d46e1e 100644
--- a/tests/kms_frontbuffer_tracking.c
+++ b/tests/kms_frontbuffer_tracking.c
@@ -32,9 +32,18 @@
#include <poll.h>
#include <pthread.h>
+#include "drmtest.h"
+#include "igt_debugfs.h"
+#include "igt_kms.h"
+#include "intel_chipset.h"
+#include "intel_batchbuffer.h"
+#include "ioctl_wrappers.h"
+#include <time.h>
+#include <stdlib.h>
+#include <sys/time.h>
IGT_TEST_DESCRIPTION("Test the Kernel's frontbuffer tracking
mechanism and "
- "its related features: FBC and PSR");
+ "its related features: DRRS, FBC and PSR");
/*
* One of the aspects of this test is that, for every subtest, we
try different
@@ -327,6 +336,41 @@ drmModeModeInfo std_1024_mode = {
.name = "Custom 1024x768",
};
+#define DRRS_TOLERANCE_THRESHOLD 2
+#define DRRS_POLL_TIMEOUT_PERIOD_MS 5000
+#define DRRS_STATUS_BYTES_CNT 1000
+#define DRRS_MAX_ITERATION 3
+
+/*
+ * Struct to hold drrs test related data
+ */
+typedef struct {
+ uint32_t devid;
+ uint32_t handle[2];
+ igt_display_t display;
+ igt_output_t *output;
+ enum pipe pipe;
+ igt_plane_t *primary;
+ struct igt_fb fb[2];
+ uint32_t fb_id[2];
+} drrs_data_t;
+
+/*
+ * Structure to count vblank and note the starting time of the
counter
+ */
+typedef struct {
+ unsigned int vbl_count;
+ struct timeval start;
+} vbl_info;
+
+/*
+ * Structure for refresh rate type
+ */
+typedef struct{
+ int rate;
+ const char *name;
+} refresh_rate_t;
+
static drmModeModeInfoPtr
get_connector_smallest_mode(drmModeConnectorPtr c)
{
int i;
@@ -3415,6 +3459,410 @@ static const char *flip_str(enum flip_type
flip)
#define TEST_MODE_ITER_END } } } } } }
+static inline uint32_t pipe_select(int pipe)
+{
+ if (pipe > 1)
+ return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
+ else if (pipe > 0)
+ return DRM_VBLANK_SECONDARY;
+ else
+ return DRM_VBLANK_ABSOLUTE;
+}
+
+/*
+ * Calculates the total no. of millisec elapsed since timeval start
+ */
+static double igt_millisec_elapsed(const struct timeval *start)
+{
+ struct timeval curr;
+
+ gettimeofday(&curr, NULL);
+ return (1e3*(curr.tv_sec - start->tv_sec) +
+ (curr.tv_usec - start-
tv_usec)/1000.00);
+}
+
+/*
+ * Func to read the DRRS status from debugfs
+ */
+static bool read_drrs_status(char *str)
+{
+ FILE *fp;
+ int fd;
+ int cnt;
+
+ fd = igt_debugfs_open(drm.fd, "i915_drrs_status", O_RDONLY);
+ igt_assert(fd);
+ fp = fdopen(fd, "r");
+ igt_require(fp);
+ cnt = fread(str, DRRS_STATUS_BYTES_CNT - 1, 1, fp);
+
+ if (!cnt) {
+ if (!feof(fp)) {
+ igt_critical("Failed to read
i915_drrs_status:%d \n",
+ ferror(fp));
+ return false;
+ }
+ clearerr(fp);
+ }
+ fclose(fp);
+
+ return true;
+}
+
+/*
+ * Func to check for DRRS support
+ */
+static bool is_drrs_supported(void)
+{
+ char str[DRRS_STATUS_BYTES_CNT] = {};
+
+ if (!read_drrs_status(str))
+ return false;
+
+ return strstr(str, "DRRS Supported: Yes") != NULL;
+}
+
+/*
+ * Func to check if DRRS is enabled by driver.
+ */
+static bool is_drrs_enabled(void)
+{
+ char str[DRRS_STATUS_BYTES_CNT] = {};
+
+ if (!read_drrs_status(str))
+ return false;
+
+ return strstr(str, "Idleness DRRS: Disabled") == NULL;
+}
+
+
+/*
+ * vbl_rate = vbl_count/time taken
+ */
+static double vbl_rate(const union drm_wait_vblank *start,
+ const union drm_wait_vblank *end)
+{
+ double s, e;
+
+ s = start->reply.tval_sec + 1e-6 * start->reply.tval_usec;
+ e = end->reply.tval_sec + 1e-6 * end->reply.tval_usec;
+ return ((end->reply.sequence - start->reply.sequence) / (e -
s));
+}
+
+/*
+ * refresh_rate = (20 vblanks) /(time for 20vblanks)
+ */
+int calculate_refresh_rate(drrs_data_t *data)
+{
+ union drm_wait_vblank start, end;
+ struct timeval start_tv;
+ int refresh_rate;
+
+ memset(&start, 0, sizeof(start));
+ start.request.type = DRM_VBLANK_RELATIVE | pipe_select(data-
pipe);
+
+ if (drmWaitVBlank(drm.fd, &start) != 0) {
+ igt_critical("drmWaitVBlank Failed!\n");
+ return -1;
+ }
+ gettimeofday(&start_tv, NULL);
+ memset(&end, 0, sizeof(end));
+ end.request.type = DRM_VBLANK_RELATIVE | pipe_select(data-
pipe);
+
+ /* Configured to wait for 20 vblank events*/
+ end.request.sequence = 20;
+
+ if (drmWaitVBlank(drm.fd, &end) != 0) {
+ igt_critical("drmWaitVBlank Failed!\n");
+ return -1;
+ }
+ refresh_rate = vbl_rate(&start, &end);
+
+ return refresh_rate;
+}
+
+/*
+ * Poll for DRRS transition from high to low with 5 seconds time
out.
+ */
+int wait_for_drrs_switch_to_low(drrs_data_t *data)
+{
+ char drrs_status[DRRS_STATUS_BYTES_CNT] = {};
+ const char *drrs_low_name = "DRRS_LOW_RR";
+ int status = 1;
+ struct timeval start_tv;
+
+ gettimeofday(&start_tv, NULL);
+
+ while (igt_millisec_elapsed(&start_tv) <
DRRS_POLL_TIMEOUT_PERIOD_MS) {
+
+ if (!read_drrs_status(drrs_status)) {
+ status = -1;
+ break;
+ }
+
+ if (strstr(drrs_status, drrs_low_name) != NULL)
+ break;
+ }
+
+ if (igt_millisec_elapsed(&start_tv) >
DRRS_POLL_TIMEOUT_PERIOD_MS) {
+
+ igt_critical("DRRS failed to switch refresh rate
from "
+ "higher to lower\n");
+
+ status = -1;
+ }
+
+ return status;
+}
+
+/*
+ * Check if calulated refresh rate is same as expected refresh rate
+ * Returns 0 in case of pass , 1 in case of failure, and -1 for
error.
+ */
+static int check_refresh_rate(drrs_data_t *data, refresh_rate_t
*expected_rr)
+{
+ int refresh_rate = -1;
+ char drrs_status[DRRS_STATUS_BYTES_CNT] = {};
+
+ /* Get the DRRS Status from the debugfs entry */
+ if (!read_drrs_status(drrs_status))
+ return -1;
+
+ refresh_rate = calculate_refresh_rate(data);
+
+ if (refresh_rate < 0) {
+ igt_critical("Refresh rate calculation FAILED\n");
+ return -1;
+ }
+
+ /* Compare with Expected Refresh Rate */
+ if (strstr(drrs_status, expected_rr->name) != NULL
+ && abs(refresh_rate - expected_rr->rate) <=
DRRS_TOLERANCE_THRESHOLD) {
+ return 0;
+ }
+ igt_critical("Expected %s : FAILED.\n", expected_rr->name);
+
+ return 1;
+}
+
+/*
+ * This function
+ * 1. Creates framebuffers
+ * 2. Apply framebuffers alternatively and count the vblank refresh
rate
+ * which should be equal to highest refresh rate supported.
+ * 3. Poll for DRRS to toggle from DRRS_HIGH_RR -> DRRS_LOW_RR with
5sec
+ * timeout using kernel debugfs entry(i915_drrs_status).
+ * 4. Once DRRS switches to LOW we count the vblank refresh rate
which
+ * should be equal to lowest refresh rate supported.
+ * 5. The above calculated vblank refresh rates can have a tolerance
of 2.
+ */
+static int execute_test(drrs_data_t *data)
+{
+ igt_display_t *display = &data->display;
+ igt_output_t *output = data->output;
+ drmModeModeInfo *mode, *supported_modes;
+ int test_failed = 0;
+ int ret, i, i_mod, count_modes;
+ refresh_rate_t high_rr, low_rr;
+
+ high_rr.name = "DRRS_HIGH_RR";
+ high_rr.rate = 0;
+ low_rr.name = "DRRS_LOW_RR";
+ low_rr.rate = 0;
+
+ /* get the max and min supported refresh rates for the
display */
+ supported_modes = output->config.connector->modes;
+ count_modes = output->config.connector->count_modes;
+
+ /* minimum 2 modes are required for DRRS */
+ igt_assert_f(count_modes >= 2, "Minimum 2 modes required for
DRRS\n");
+
+ for (i = 0; i < count_modes; i++) {
+ int rr = supported_modes[i].vrefresh;
+
+ if (i == 0) {
+ high_rr.rate = low_rr.rate = rr;
+ continue;
+ }
+
+ if (high_rr.rate < rr)
+ high_rr.rate = rr;
+
+ if (low_rr.rate > rr)
+ low_rr.rate = rr;
+ }
+
+ igt_output_set_pipe(output, data->pipe);
+ data->primary = igt_output_get_plane(data->output,
+ DRM_PLANE_TYPE_OVERLAY);
+ mode = igt_output_get_mode(data->output);
+ data->fb_id[0] = igt_create_color_fb(drm.fd, mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD
_NONE,
+ 0.0, 100.1, 0.0,
&data->fb[0]);
+
+ igt_assert(data->fb_id[0]);
+ data->fb_id[1] = igt_create_color_fb(drm.fd, mode->hdisplay,
+ mode->vdisplay,
+ DRM_FORMAT_XRGB8888,
+ LOCAL_DRM_FORMAT_MOD
_NONE,
+ 100.1, 0.0, 0.0,
+ &data->fb[1]);
+
+ igt_assert(data->fb_id[1]);
+ data->handle[0] = data->fb[0].gem_handle;
+ data->handle[1] = data->fb[1].gem_handle;
+
+ for (i = 1; i <= DRRS_MAX_ITERATION; i++) {
+ i_mod = i % 2;
+ igt_plane_set_fb(data->primary, &data->fb[i_mod]);
+ igt_display_commit(display);
+
+ if (!is_drrs_enabled()) {
+ igt_critical("DRRS not enabled\n");
+ igt_plane_set_fb(data->primary, NULL);
+ igt_output_set_pipe(output, PIPE_ANY);
+ igt_display_commit(display);
+ igt_remove_fb(drm.fd, &data->fb[0]);
+ igt_remove_fb(drm.fd, &data->fb[1]);
+ return -1;
+ }
+
+ /* expecting High RR */
+ ret = check_refresh_rate(data, &high_rr);
+
+ if (ret == -1)
+ return -1;
+
+ if (ret == 1)
+ test_failed = 1;
+
+ /*
+ * Poll kernel debugfs entry for DRRS
+ * transition from High to Low
+ */
+ ret = wait_for_drrs_switch_to_low(data);
+
+ if (ret == -1)
+ return 1;
+
+ /* expecting Low RR */
+ ret = check_refresh_rate(data, &low_rr);
+
+ if (ret == -1)
+ return -1;
+
+ if (ret == 1)
+ test_failed = 1;
+ }
+
+ return test_failed;
+}
+
+/*
+ * Func to free the framebuffers after the test completion.
+ */
+static void finish_crtc(drrs_data_t *data)
+{
+ igt_plane_set_fb(data->primary, NULL);
+ igt_output_set_pipe(data->output, PIPE_ANY);
+ igt_display_commit(&data->display);
+
+ igt_remove_fb(drm.fd, &data->fb[0]);
+ igt_remove_fb(drm.fd, &data->fb[1]);
+}
+
+/*
+ * Func to reset the display structures after the test completion.
+ */
+static void reset_display(drrs_data_t *data)
+{
+ igt_display_t *display = &data->display;
+ enum pipe pipe_id;
+
+ for_each_pipe(display, pipe_id) {
+ igt_pipe_t *pipe = &display->pipes[pipe_id];
+ igt_plane_t *plane = igt_pipe_get_plane_type(pipe,
+ DRM_PLANE_TYPE_PRIMARY);
+
+ if (plane->fb)
+ igt_plane_set_fb(plane, NULL);
+ }
+
+ for_each_connected_output(display, data->output)
+ igt_output_set_pipe(data->output, PIPE_ANY);
+}
+
+/*
+ * Func to run the drrs test for the eDP display.
+ */
+static void run_test(drrs_data_t *data)
+{
+ int ret;
+ igt_display_t *display = &data->display;
+
+ reset_display(data);
+
+ for_each_pipe_with_valid_output(display, data->pipe, data-
output) {
+ drmModeConnectorPtr c = data->output-
config.connector;
+
+ if (c->connector_type != DRM_MODE_CONNECTOR_eDP ||
+ c->connection != DRM_MODE_CONNECTED)
+ continue;
+
+ ret = execute_test(data);
+
+ igt_skip_on_f(ret == -1,
+ "%s on pipe %s, connector
%s:SKIPPED\n",
+ igt_subtest_name(),
+ kmstest_pipe_name(data-
pipe),
+ igt_output_name(data-
output));
+
+ igt_fail_on_f(ret == 1,
+ "%s on pipe %s, connector
%s:FAILED\n",
+ igt_subtest_name(),
+ kmstest_pipe_name(data-
pipe),
+ igt_output_name(data-
output));
+
+ igt_assert_f(ret == 0,
+ "%s on pipe %s, connector %s:
PASSED\n",
+ igt_subtest_name(),
+ kmstest_pipe_name(data-
pipe),
+ igt_output_name(data-
output));
+
+ finish_crtc(data);
+ }
+}
+
+/*
+ * Function to test edp-DRRS feature.Exits from the function if PSR
is enabled
+ */
+void edp_drrs_test(void)
+{
+ drrs_data_t data = {};
+
+ igt_assert_f(!psr.can_test,
+ "DRRS cannot be tested as PSR is
enabled\n");
+ igt_skip_on_simulation();
+
+ /*
+ * Using the same drm.fd which was opened during
setup_environment
+ */
+ igt_assert_f(drm.fd != -1, "Invalid fd\n");
+ data.devid = intel_get_drm_devid(drm.fd);
+ igt_assert_f(data.devid >= 0, "Invalid dev id\n");
+
+ /*
+ * Check if the DRRS is supported.If yes call the Idleness
DRRS test
+ */
+ igt_require_f(is_drrs_supported(),
+ "DRRS not supported:check VBT/panel
caps\n");
+ igt_display_init(&data.display, drm.fd);
+ run_test(&data);
+ igt_display_fini(&data.display);
+}
+
int main(int argc, char *argv[])
{
struct test_mode t;
@@ -3628,6 +4076,9 @@ int main(int argc, char *argv[])
suspend_subtest(&t);
TEST_MODE_ITER_END
+ igt_subtest_f("edp-DRRS")
+ edp_drrs_test();
+
t.pipes = PIPE_SINGLE;
t.screen = SCREEN_PRIM;
t.plane = PLANE_PRI;