[PATCH 34/70] drm/amd/display: add KUnit tests for HDCP state diffing

Wayne Lin <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Alex Hung <[email protected]>

[WHAT]
Add KUnit tests for is_content_protection_different using a shared
connector/crtc fixture. Cover the content-type change, ENABLED->DESIRED
re-enable (with and without modeset), UNDESIRED and DESIRED steady
states, the update_hdcp hot-plug and stream re-enable paths, and the
S3/DESIRED/UNDESIRED enable transitions.

Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Wayne Lin <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  14 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   7 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 237 ++++++++++++++++++
 3 files changed, 252 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index fc1a73435203..03b9079ce818 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3653,12 +3653,13 @@ is_scaling_state_different(const struct dm_connector_state *dm_state,
 }
 EXPORT_IF_KUNIT(is_scaling_state_different);
 
-static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
-					    struct drm_crtc_state *old_crtc_state,
-					    struct drm_connector_state *new_conn_state,
-					    struct drm_connector_state *old_conn_state,
-					    const struct drm_connector *connector,
-					    struct hdcp_workqueue *hdcp_w)
+STATIC_IFN_KUNIT bool
+is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+				struct drm_crtc_state *old_crtc_state,
+				struct drm_connector_state *new_conn_state,
+				struct drm_connector_state *old_conn_state,
+				const struct drm_connector *connector,
+				struct hdcp_workqueue *hdcp_w)
 {
 	struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
 	struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
@@ -3772,6 +3773,7 @@ static bool is_content_protection_different(struct drm_crtc_state *new_crtc_stat
 	pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__);
 	return false;
 }
+EXPORT_IF_KUNIT(is_content_protection_different);
 
 static void remove_stream(struct amdgpu_device *adev,
 			  struct amdgpu_crtc *acrtc,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index bef9663caf6e..c508f0be1b55 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1178,6 +1178,13 @@ bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
 				struct dm_crtc_state *new_state);
 void set_multisync_trigger_params(struct dc_stream_state *stream);
 void set_master_stream(struct dc_stream_state *stream_set[], int stream_count);
+struct hdcp_workqueue;
+bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+				     struct drm_crtc_state *old_crtc_state,
+				     struct drm_connector_state *new_conn_state,
+				     struct drm_connector_state *old_conn_state,
+				     const struct drm_connector *connector,
+				     struct hdcp_workqueue *hdcp_w);
 #endif
 
 #endif /* __AMDGPU_DM_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
index 724d03db2736..1caacad43106 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
@@ -1425,6 +1425,231 @@ static void dm_test_update_scaling_underscan(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, stream->dst.height, 1048);
 }
 
+/* Tests for is_content_protection_different() */
+
+struct dm_test_cp_ctx {
+	struct amdgpu_dm_connector *aconnector;
+	struct dm_connector_state *new_dm;	/* also connector->state */
+	struct dm_connector_state *old_dm;
+	struct drm_crtc_state *new_crtc;
+	struct drm_crtc_state *old_crtc;
+};
+
+static struct dm_test_cp_ctx *dm_test_cp_ctx_alloc(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx;
+
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+	ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+	ctx->new_dm = kunit_kzalloc(test, sizeof(*ctx->new_dm), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->new_dm);
+	ctx->old_dm = kunit_kzalloc(test, sizeof(*ctx->old_dm), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->old_dm);
+	ctx->new_crtc = kunit_kzalloc(test, sizeof(*ctx->new_crtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->new_crtc);
+	ctx->old_crtc = kunit_kzalloc(test, sizeof(*ctx->old_crtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->old_crtc);
+
+	/* connector->state must be the new dm connector state */
+	ctx->aconnector->base.state = &ctx->new_dm->base;
+	ctx->aconnector->base.dpms = DRM_MODE_DPMS_ON;
+
+	return ctx;
+}
+
+static bool dm_test_cp_diff(struct dm_test_cp_ctx *ctx)
+{
+	return is_content_protection_different(ctx->new_crtc, ctx->old_crtc,
+					       &ctx->new_dm->base,
+					       &ctx->old_dm->base,
+					       &ctx->aconnector->base, NULL);
+}
+
+/**
+ * dm_test_cp_diff_hdcp_type_change - Test an HDCP content-type change forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_hdcp_type_change(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.hdcp_content_type = 0;
+	ctx->new_dm->base.hdcp_content_type = 1;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+	KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+			(int)DRM_MODE_CONTENT_PROTECTION_DESIRED);
+}
+
+/**
+ * dm_test_cp_diff_reenable_mode_changed - Test ENABLED->DESIRED with modeset forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_reenable_mode_changed(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_crtc->mode_changed = true;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+	KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+			(int)DRM_MODE_CONTENT_PROTECTION_DESIRED);
+}
+
+/**
+ * dm_test_cp_diff_reenable_no_change - Test ENABLED->DESIRED without modeset restores ENABLED
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_reenable_no_change(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_crtc->mode_changed = false;
+
+	KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+	KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+			(int)DRM_MODE_CONTENT_PROTECTION_ENABLED);
+}
+
+/**
+ * dm_test_cp_diff_undesired - Test UNDESIRED->UNDESIRED needs no update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_undesired(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+
+	KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_desired_mode_changed - Test DESIRED->DESIRED with modeset forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_mode_changed(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_crtc->mode_changed = true;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_desired_no_change - Test steady DESIRED->DESIRED needs no update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_no_change(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_crtc->mode_changed = false;
+
+	KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_update_hdcp_hotplug - Test the update_hdcp hot-plug path forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_update_hdcp_hotplug(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+	struct dc_sink *sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+
+	KUNIT_ASSERT_NOT_NULL(test, sink);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->update_hdcp = true;
+	ctx->aconnector->base.dpms = DRM_MODE_DPMS_ON;
+	ctx->aconnector->dc_sink = sink;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+	KUNIT_EXPECT_FALSE(test, ctx->new_dm->update_hdcp);
+}
+
+/**
+ * dm_test_cp_diff_stream_reenabled - Test the stream removed-and-re-enabled path forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_stream_reenabled(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+	struct drm_crtc *crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+
+	KUNIT_ASSERT_NOT_NULL(test, crtc);
+	crtc->enabled = true;
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->update_hdcp = true;
+	ctx->old_dm->base.crtc = NULL;
+	ctx->new_dm->base.crtc = crtc;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+	KUNIT_EXPECT_FALSE(test, ctx->new_dm->update_hdcp);
+}
+
+/**
+ * dm_test_cp_diff_s3_undesired_to_enabled - Test the S3 UNDESIRED->ENABLED path forces true
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_s3_undesired_to_enabled(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+	KUNIT_EXPECT_EQ(test, (int)ctx->new_dm->base.content_protection,
+			(int)DRM_MODE_CONTENT_PROTECTION_DESIRED);
+}
+
+/**
+ * dm_test_cp_diff_desired_to_enabled - Test DESIRED->ENABLED needs no update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_to_enabled(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+	KUNIT_EXPECT_FALSE(test, dm_test_cp_diff(ctx));
+}
+
+/**
+ * dm_test_cp_diff_desired_to_undesired - Test DESIRED->UNDESIRED forces update
+ * @test: The KUnit test context
+ */
+static void dm_test_cp_diff_desired_to_undesired(struct kunit *test)
+{
+	struct dm_test_cp_ctx *ctx = dm_test_cp_ctx_alloc(test);
+
+	ctx->old_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+	ctx->new_dm->base.content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+
+	KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
 	/* Simple DM callbacks */
 	KUNIT_CASE(dm_test_is_idle),
@@ -1505,6 +1730,18 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_update_scaling_rmx_aspect_letterbox),
 	KUNIT_CASE(dm_test_update_scaling_rmx_center),
 	KUNIT_CASE(dm_test_update_scaling_underscan),
+	/* is_content_protection_different */
+	KUNIT_CASE(dm_test_cp_diff_hdcp_type_change),
+	KUNIT_CASE(dm_test_cp_diff_reenable_mode_changed),
+	KUNIT_CASE(dm_test_cp_diff_reenable_no_change),
+	KUNIT_CASE(dm_test_cp_diff_undesired),
+	KUNIT_CASE(dm_test_cp_diff_desired_mode_changed),
+	KUNIT_CASE(dm_test_cp_diff_desired_no_change),
+	KUNIT_CASE(dm_test_cp_diff_update_hdcp_hotplug),
+	KUNIT_CASE(dm_test_cp_diff_stream_reenabled),
+	KUNIT_CASE(dm_test_cp_diff_s3_undesired_to_enabled),
+	KUNIT_CASE(dm_test_cp_diff_desired_to_enabled),
+	KUNIT_CASE(dm_test_cp_diff_desired_to_undesired),
 	{}
 };
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.