[igt-dev] [PATCH i-g-t v2] kms_content_protection: Add Content Protection test
Ramalingam C
ramalingam.c at intel.com
Fri Oct 12 14:02:09 UTC 2018
Pretty simple test:
- picks the hdcp capable output with suitable pipe and apply modeset.
- apply a FB and wait for the flip completion.
- clears the content protection property
- verifies that it clears
- sets the content protection property to desired
- verifies that it transitions to enabled
- incase of timeout three reattempts are implemented
- clear the content protection property and modeset on the crtc
v2:
dynamic subtests are dropped [Daniel]
Above steps are repeated on all HDCP capable connectors for both
legacy and atomic subtests.
Signed-off-by: Sean Paul <seanpaul at chromium.org>
Signed-off-by: Ramalingam C <ramalingam.c at intel.com>
---
lib/igt_kms.c | 1 +
lib/igt_kms.h | 1 +
tests/Makefile.sources | 1 +
tests/kms_content_protection.c | 282 +++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
5 files changed, 286 insertions(+)
create mode 100644 tests/kms_content_protection.c
diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index 62d8468415c6..4231996c65ca 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -194,6 +194,7 @@ const char * const igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = {
[IGT_CONNECTOR_CRTC_ID] = "CRTC_ID",
[IGT_CONNECTOR_DPMS] = "DPMS",
[IGT_CONNECTOR_BROADCAST_RGB] = "Broadcast RGB",
+ [IGT_CONNECTOR_CONTENT_PROTECTION] = "Content Protection",
};
/*
diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index 3a12f2782eed..aa068e58e607 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -120,6 +120,7 @@ enum igt_atomic_connector_properties {
IGT_CONNECTOR_CRTC_ID,
IGT_CONNECTOR_DPMS,
IGT_CONNECTOR_BROADCAST_RGB,
+ IGT_CONNECTOR_CONTENT_PROTECTION,
IGT_NUM_CONNECTOR_PROPS
};
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index c84933f1d971..5af68a61df51 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -174,6 +174,7 @@ TESTS_progs = \
kms_chv_cursor_fail \
kms_color \
kms_concurrent \
+ kms_content_protection\
kms_crtc_background_color \
kms_cursor_crc \
kms_cursor_legacy \
diff --git a/tests/kms_content_protection.c b/tests/kms_content_protection.c
new file mode 100644
index 000000000000..6afc4e26bcb2
--- /dev/null
+++ b/tests/kms_content_protection.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright © 2018 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.
+ *
+ */
+
+#include <poll.h>
+#include "igt.h"
+
+IGT_TEST_DESCRIPTION("Test content protection (HDCP)");
+
+typedef struct {
+ int drm_fd;
+ igt_display_t display;
+} data_t;
+
+static void flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
+ unsigned int tv_usec, void *data)
+{
+ igt_debug("Flip event received.\n");
+}
+
+static int wait_flip_event(data_t *data)
+{
+ int rc;
+ drmEventContext evctx;
+ struct pollfd pfd;
+
+ evctx.version = 2;
+ evctx.vblank_handler = NULL;
+ evctx.page_flip_handler = flip_handler;
+
+ pfd.fd = data->drm_fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+
+ rc = poll(&pfd, 1, 1000);
+ switch (rc) {
+ case 0:
+ igt_info("Poll timeout. 1Sec.\n");
+ rc = -ETIMEDOUT;
+ break;
+ case 1:
+ rc = drmHandleEvent(data->drm_fd, &evctx);
+ igt_assert_eq(rc, 0);
+ rc = 0;
+ break;
+ default:
+ igt_info("Unexpected poll rc %d\n", rc);
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+static bool
+wait_for_prop_value(igt_output_t *output, uint64_t expected,
+ uint32_t timeout_mSec)
+{
+ uint64_t val;
+ int i;
+
+ for (i = 0; i < timeout_mSec; i++) {
+ val = igt_output_get_prop(output,
+ IGT_CONNECTOR_CONTENT_PROTECTION);
+ if (val == expected)
+ return true;
+ usleep(1000);
+ }
+ igt_info("prop_value mismatch %ld != %ld\n", val, expected);
+
+ return false;
+}
+
+static void
+commit_display_and_wait_for_flip(data_t *data, igt_display_t *display,
+ enum igt_commit_style s)
+{
+ int ret;
+ uint32_t flag;
+
+ if (s == COMMIT_ATOMIC) {
+ flag = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_ALLOW_MODESET;
+ igt_display_commit_atomic(display, flag, NULL);
+
+ ret = wait_flip_event(data);
+ igt_assert_f(!ret, "wait_flip_event failed. %d\n", ret);
+ } else {
+ igt_display_commit2(display, s);
+
+ /* Wait for 50mSec */
+ usleep(50 * 1000);
+ }
+}
+
+static void
+test_pipe_output(data_t *data, const enum pipe pipe, igt_output_t *output,
+ enum igt_commit_style s)
+{
+ igt_display_t *display = &data->display;
+ drmModeModeInfo mode;
+ igt_plane_t *primary;
+ struct igt_fb red, green;
+ bool ret;
+ int retry = 3;
+
+ igt_assert(kmstest_get_connector_default_mode(
+ display->drm_fd, output->config.connector, &mode));
+
+ igt_output_override_mode(output, &mode);
+ igt_output_set_pipe(output, pipe);
+
+ igt_create_color_fb(display->drm_fd, mode.hdisplay, mode.vdisplay,
+ DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+ 1.f, 0.f, 0.f, &red);
+ igt_create_color_fb(display->drm_fd, mode.hdisplay, mode.vdisplay,
+ DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+ 0.f, 1.f, 0.f, &green);
+
+ primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+ igt_display_commit2(display, s);
+
+ igt_plane_set_fb(primary, &red);
+
+ /* Wait for Flip completion before starting the HDCP authentication */
+ commit_display_and_wait_for_flip(data, display, s);
+
+ do {
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_CONTENT_PROTECTION, 0);
+ igt_display_commit2(display, s);
+
+ /* Wait for HDCP to be disabled for fresh start. */
+ ret = wait_for_prop_value(output, 0, 1000);
+ igt_assert_f(ret, "Content Protection not cleared\n");
+
+ igt_output_set_prop_value(output,
+ IGT_CONNECTOR_CONTENT_PROTECTION, 1);
+ igt_display_commit2(display, s);
+
+ /* Wait for 18000mSec (3 authentication * 6Sec) */
+ ret = wait_for_prop_value(output, 2, 18000);
+ if (ret) {
+ igt_plane_set_fb(primary, &green);
+ igt_display_commit2(display, s);
+ }
+
+ if (!ret && --retry)
+ igt_debug("Retry (%d/2) ...\n", 3 - retry);
+ } while (retry && !ret);
+
+ igt_assert_f(ret, "Content Protection not enabled\n");
+
+ igt_output_set_prop_value(output, IGT_CONNECTOR_CONTENT_PROTECTION, 0);
+ igt_plane_set_fb(primary, &red);
+ igt_display_commit2(display, s);
+
+ /* Wait for HDCP to be disabled, before crtc off */
+ wait_for_prop_value(output, 0, 1000);
+
+ igt_plane_set_fb(primary, NULL);
+ igt_output_set_pipe(output, PIPE_NONE);
+}
+
+static bool igt_pipe_is_free(igt_display_t *display, enum pipe pipe)
+{
+ int i;
+
+ for (i = 0; i < display->n_outputs; i++)
+ if (display->outputs[i].pending_pipe == pipe)
+ return false;
+
+ return true;
+}
+
+static void
+test_content_protection_on_output(data_t *data, igt_output_t *output,
+ enum igt_commit_style s)
+{
+ igt_display_t *display = &data->display;
+ enum pipe pipe;
+
+ for_each_pipe(display, pipe) {
+ if (!igt_pipe_connector_valid(pipe, output))
+ continue;
+
+ /*
+ * If previous subtest of connector failed, pipe
+ * attached to that connector is not released.
+ * Because of that we have to choose the non
+ * attached pipe for this subtest.
+ */
+ if (!igt_pipe_is_free(display, pipe))
+ continue;
+
+ /* To indicate the connector and pipe under test */
+ igt_debug("CP Test execution on %s:PIPE-%s\n", output->name,
+ kmstest_pipe_name(pipe));
+
+ test_pipe_output(data, pipe, output, s);
+
+ /*
+ * Testing a output with a pipe is enough for HDCP
+ * testing. No ROI in testing the connector with other
+ * pipes. So Break the loop on pipe.
+ */
+ break;
+ }
+
+}
+
+static void
+test_content_protection(data_t *data, enum igt_commit_style s)
+{
+ igt_display_t *display = &data->display;
+ igt_output_t *output;
+ int valid_tests = 0;
+
+ for_each_connected_output(display, output) {
+
+ if (!output->props[IGT_CONNECTOR_CONTENT_PROTECTION])
+ continue;
+
+ /*
+ * TODO: Skip the connector if the connected sink is
+ * not capable of HDCP, to avoid false alarm of hdcp
+ * failure on this connector.
+ * Possibly do a aux or I2C Transfer to detect the
+ * sink's HDCP capability. Other possibility is run the
+ * kms_content_protection on the connectors where known
+ * HDCP sinks are connected.
+ */
+
+ test_content_protection_on_output(data, output, s);
+ valid_tests++;
+ }
+
+ igt_require_f(valid_tests, "No connector found with HDCP capability\n");
+}
+
+igt_main
+{
+ data_t data = {};
+
+ igt_fixture {
+ igt_skip_on_simulation();
+
+ data.drm_fd = drm_open_driver(DRIVER_ANY);
+
+ igt_display_init(&data.display, data.drm_fd);
+ }
+
+ igt_subtest("legacy")
+ test_content_protection(&data, COMMIT_LEGACY);
+
+ igt_subtest("atomic") {
+ igt_require(data.display.is_atomic);
+ test_content_protection(&data, COMMIT_ATOMIC);
+ }
+
+ igt_fixture
+ igt_display_fini(&data.display);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 17deb945ec95..a74de4ff0ece 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -149,6 +149,7 @@ test_progs = [
'kms_chv_cursor_fail',
'kms_color',
'kms_concurrent',
+ 'kms_content_protection',
'kms_crtc_background_color',
'kms_cursor_crc',
'kms_cursor_legacy',
--
2.7.4
More information about the igt-dev
mailing list