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

Reply via email to