<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <br>
    <div class="moz-cite-prefix">On Friday 14 July 2017 02:21 AM, Paulo
      Zanoni wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:1499979097.2649.28.camel@intel.com">
      <pre wrap="">Em Qua, 2017-06-21 às 13:40 +0530, Lohith BS escreveu:
</pre>
      <blockquote type="cite">
        <pre wrap="">Idleness DRRS:
        By default the DRRS state will be at DRRS_HIGH_RR. When a
Display
        content is Idle for more than 1Sec Idleness will be declared
and
        DRRS_LOW_RR will be invoked, changing the refresh rate to the
        lower most refresh rate supported by the panel. As soon as
there
        is a display content change there will be a DRRS state
transition
        as DRRS_LOW_RR--> DRRS_HIGH_RR, changing the refresh rate to
the
        highest refresh rate supported by the panel.

To test this, Idleness DRRS IGT will probe the DRRS state at below
instances and compare with the expected state.

        Instance                                        Expected State
1. Immediately after rendering the still image          DRRS_HI
GH_RR
2. After a delay of 1.2Sec                              DRRS_LOW_RR
3. After changing the frame buffer                      DRRS_HIGH_R
R
4. After a delay of 1.2Sec                              DRRS_LOW_RR
5. After changing the frame buffer                      DRRS_HIGH_R
R
6. After a delay of 1.2Sec                              DRRS_LOW_RR

The test checks the driver DRRS state from the debugfs entry. To
check the
actual refresh-rate, the number of vblanks received per sec.
The refresh-rate calculated is checked against the expected refresh-
rate
with a tolerance value of 2.

This patch is a continuation of the earlier work
<a class="moz-txt-link-freetext" href="https://patchwork.freedesktop.org/patch/45472/">https://patchwork.freedesktop.org/patch/45472/</a> towards igt for
idleness

DRRS. The code is tested on Broxton BXT_T platform.

v2: Addressed the comments and suggestions from Vlad, Marius.
The signoff details from the earlier work are also included.

v3: Modified vblank rate calculation by using reply-sequence,
provided by
drmWaitVBlank, as suggested by Chris Wilson.

v4: As suggested from Chris Wilson and Daniel Vetter
        1) Avoided using pthread for calculating vblank refresh rate,
           instead used drmWaitVBlank reply sequence.
        2) Avoided using kernel-specific info like transitional delays,
           instead polling mechanism with timeout is used.
        3) Included edp-DRRS as a subtest in
kms_frontbuffer_tracking.c,
           instead of having a separate test.
</pre>
      </blockquote>
      <pre wrap="">
I completely disagree with the way this part was implemented. The code
added to kms_frontbuffer_tracking.c uses pretty much zero of the
infrastructure provided by the file. This patch adds a completely
unrelated set of functions to kms_frontbuffer_tracking.c. If we're not
going to use the current subtests & infrastructure, please make it a
separate test.</pre>
    </blockquote>
    <font size="-1">Agreed Paulo. As per daniel's suggestion we tried to
      reuse the infrastructure<br>
      provided by frontbuffer tracking igt. But we couldn't as the test
      case requirements<br>
      were not matching.<br>
      <br>
      If we are fine with implementation of the test, we are good to
      separate<br>
      the test into separate igt.<br>
      <br>
      Daniel, hope this is sounding good to you too.<br>
      <br>
      With respect to other review comments, In this version, We have
      tried to address all chris's<br>
      review comments. please review them too.<br>
      <br>
      Thanks a lot</font><br>
    <font size="-1">--Ram</font><br>
    <blockquote type="cite"
      cite="mid:1499979097.2649.28.camel@intel.com">
      <pre wrap="">


</pre>
      <blockquote type="cite">
        <pre wrap="">
This is in continuation of last patch <a class="moz-txt-link-rfc2396E" href="https://patchwork.freedesktop.org/patch/117149/">"https://patchwork.freedesktop.
org/patch/117149/"</a>

Signed-off-by: Lohith BS <a class="moz-txt-link-rfc2396E" href="mailto:lohith.bs@intel.com"><lohith.bs@intel.com></a>
Signed-off-by: Ramalingam C <a class="moz-txt-link-rfc2396E" href="mailto:ramalingam.c@intel.com"><ramalingam.c@intel.com></a>
Signed-off-by: Vandana Kannan <a class="moz-txt-link-rfc2396E" href="mailto:vandana.kannan@intel.com"><vandana.kannan@intel.com></a>
Signed-off-by: aknautiy <a class="moz-txt-link-rfc2396E" href="mailto:ankit.k.nautiyal@intel.com"><ankit.k.nautiyal@intel.com></a>
---
 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-
</pre>
        <blockquote type="cite">
          <pre wrap="">tv_usec)/1000.00);
</pre>
        </blockquote>
        <pre wrap="">+}
+
+/*
+ * 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-
</pre>
        <blockquote type="cite">
          <pre wrap="">pipe);
</pre>
        </blockquote>
        <pre wrap="">+
+       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-
</pre>
        <blockquote type="cite">
          <pre wrap="">pipe);
</pre>
        </blockquote>
        <pre wrap="">+
+       /* 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-
</pre>
        <blockquote type="cite">
          <pre wrap="">output) {
</pre>
        </blockquote>
        <pre wrap="">+          drmModeConnectorPtr c = data->output-
</pre>
        <blockquote type="cite">
          <pre wrap="">config.connector;
</pre>
        </blockquote>
        <pre wrap="">+
+               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-
</pre>
        <blockquote type="cite">
          <pre wrap="">pipe),
</pre>
        </blockquote>
        <pre wrap="">+                                  igt_output_name(data-
</pre>
        <blockquote type="cite">
          <pre wrap="">output));
</pre>
        </blockquote>
        <pre wrap="">+
+               igt_fail_on_f(ret == 1,
+                               "%s on pipe %s, connector
%s:FAILED\n",
+                                       igt_subtest_name(),
+                                       kmstest_pipe_name(data-
</pre>
        <blockquote type="cite">
          <pre wrap="">pipe),
</pre>
        </blockquote>
        <pre wrap="">+                                  igt_output_name(data-
</pre>
        <blockquote type="cite">
          <pre wrap="">output));
</pre>
        </blockquote>
        <pre wrap="">+
+               igt_assert_f(ret == 0,
+                               "%s on pipe %s, connector %s:
PASSED\n",
+                                       igt_subtest_name(),
+                                       kmstest_pipe_name(data-
</pre>
        <blockquote type="cite">
          <pre wrap="">pipe),
</pre>
        </blockquote>
        <pre wrap="">+                                  igt_output_name(data-
</pre>
        <blockquote type="cite">
          <pre wrap="">output));
</pre>
        </blockquote>
        <pre wrap="">+
+               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;
</pre>
      </blockquote>
    </blockquote>
    <br>
  </body>
</html>