[WHAT]
Add KUnit tests for amdgpu_dm_mod_power_update_streams() covering empty
and fast commits plus CRTC enable, replacement, and disable, and for
amdgpu_dm_mod_power_setup_streams() covering empty, modeset, and fast
updates.

[HOW]
Leave dm->power_module NULL and PSR/Replay feature bits clear so the DM
stream transition logic runs without a live power module.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6-Sol
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  10 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   4 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 170 ++++++++++++++++++
 3 files changed, 180 insertions(+), 4 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 2085625f8509..8e62d451e0b1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4341,8 +4341,8 @@ static void dm_clear_writeback(struct 
amdgpu_display_manager *dm,
  * in preparation for hardware programming. See also
  * amdgpu_dm_mod_power_setup_streams() for post-modeset mod_power setup.
  */
-static void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commit *state,
-                                              struct amdgpu_display_manager 
*dm)
+STATIC_IFN_KUNIT void amdgpu_dm_mod_power_update_streams(struct 
drm_atomic_commit *state,
+                                                       struct 
amdgpu_display_manager *dm)
 {
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
        struct drm_crtc_state *old_crtc_state, *new_crtc_state;
@@ -4395,6 +4395,7 @@ static void amdgpu_dm_mod_power_update_streams(struct 
drm_atomic_commit *state,
                }
        }
 }
+EXPORT_IF_KUNIT(amdgpu_dm_mod_power_update_streams);
 
 /**
  * amdgpu_dm_mod_power_setup_streams - setup mod_power stream state post 
modeset
@@ -4404,8 +4405,8 @@ static void amdgpu_dm_mod_power_update_streams(struct 
drm_atomic_commit *state,
  * Notify mod_power of mode_change. This needs to be done after dc_stream
  * updates have been committed, and VRR parameters have been updated.
  */
-static void amdgpu_dm_mod_power_setup_streams(struct drm_atomic_commit *state,
-                                             struct amdgpu_display_manager *dm)
+STATIC_IFN_KUNIT void amdgpu_dm_mod_power_setup_streams(struct 
drm_atomic_commit *state,
+                                                      struct 
amdgpu_display_manager *dm)
 {
        struct dm_crtc_state *dm_new_crtc_state;
        struct drm_crtc_state *new_crtc_state;
@@ -4442,6 +4443,7 @@ static void amdgpu_dm_mod_power_setup_streams(struct 
drm_atomic_commit *state,
        }
 
 }
+EXPORT_IF_KUNIT(amdgpu_dm_mod_power_setup_streams);
 
 static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
                                        struct dc_state *dc_state)
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 35b8725a63af..7308067b4d13 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1205,6 +1205,10 @@ void amdgpu_dm_dump_links_and_sinks(struct amdgpu_device 
*adev);
 void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state);
 int do_aquire_global_lock(struct drm_device *dev,
                          struct drm_atomic_commit *state);
+void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commit *state,
+                                       struct amdgpu_display_manager *dm);
+void amdgpu_dm_mod_power_setup_streams(struct drm_atomic_commit *state,
+                                      struct amdgpu_display_manager *dm);
 int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block);
 int dm_sw_fini(struct amdgpu_ip_block *ip_block);
 int dm_oem_i2c_hw_init(struct amdgpu_device *adev);
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 27182f65e5c3..bb09ebc07435 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
@@ -3040,6 +3040,30 @@ static void 
dm_test_aquire_global_lock_waits_commit(struct kunit *test)
        KUNIT_EXPECT_EQ(test, ret, 0);
 }
 
+/**
+ * dm_test_mod_power_update_streams_empty - Test an empty commit updates no 
streams
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_update_streams_empty(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       amdgpu_dm_mod_power_update_streams(dm_test_alloc_commit(test, adev),
+                                          &adev->dm);
+}
+
+/**
+ * dm_test_mod_power_setup_streams_empty - Test an empty commit sets up no 
streams
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_setup_streams_empty(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+       amdgpu_dm_mod_power_setup_streams(dm_test_alloc_commit(test, adev),
+                                         &adev->dm);
+}
+
 /* Tests for amdgpu_dm_trigger_timing_sync() */
 
 /**
@@ -3174,6 +3198,144 @@ static void 
dm_test_emulated_link_detect_bad_signal(struct kunit *test)
        KUNIT_EXPECT_NULL(test, link->local_sink);
 }
 
+/* Tests for the mod_power modeset helpers */
+
+struct dm_test_modeset_ctx {
+       struct amdgpu_device *adev;
+       struct drm_atomic_commit *state;
+       struct amdgpu_crtc *acrtc;
+       struct dm_crtc_state *old_crtc_state;
+       struct dm_crtc_state *new_crtc_state;
+};
+
+/*
+ * A modeset commit on one CRTC with an old and a new stream. dm->power_module
+ * stays NULL, which every mod_power entry point treats as a no-op, so the DM
+ * side of the modeset can be walked without a live power module.
+ */
+static struct dm_test_modeset_ctx *dm_test_modeset_ctx_alloc(struct kunit 
*test)
+{
+       struct amdgpu_dm_connector *aconnector;
+       struct dm_test_modeset_ctx *ctx;
+       struct dc_link *link;
+
+       ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+       ctx->adev = dm_kunit_alloc_adev(test);
+       ctx->state = dm_test_alloc_commit(test, ctx->adev);
+       ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc);
+       ctx->old_crtc_state = kunit_kzalloc(test, sizeof(*ctx->old_crtc_state),
+                                           GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->old_crtc_state);
+       ctx->new_crtc_state = kunit_kzalloc(test, sizeof(*ctx->new_crtc_state),
+                                           GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->new_crtc_state);
+       ctx->state->crtcs = kunit_kzalloc(test, sizeof(*ctx->state->crtcs),
+                                         GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs);
+       aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+       link = dm_kunit_alloc_link(test);
+       ctx->old_crtc_state->stream = dm_kunit_alloc_stream(test, link);
+       ctx->new_crtc_state->stream = dm_kunit_alloc_stream(test, link);
+       ctx->new_crtc_state->stream->dm_stream_context = aconnector;
+
+       ctx->adev->ddev.mode_config.num_crtc = 1;
+       ctx->adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
+       mutex_init(&ctx->adev->dm.dc_lock);
+       ctx->new_crtc_state->base.mode_changed = true;
+       ctx->new_crtc_state->base.state = ctx->state;
+       ctx->state->crtcs[0].ptr = &ctx->acrtc->base;
+       ctx->state->crtcs[0].old_state = &ctx->old_crtc_state->base;
+       ctx->state->crtcs[0].new_state = &ctx->new_crtc_state->base;
+
+       return ctx;
+}
+
+/**
+ * dm_test_mod_power_update_streams_no_modeset - Test fast updates are skipped
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_update_streams_no_modeset(struct kunit *test)
+{
+       struct dm_test_modeset_ctx *ctx = dm_test_modeset_ctx_alloc(test);
+
+       ctx->new_crtc_state->base.mode_changed = false;
+       ctx->new_crtc_state->base.active = true;
+
+       amdgpu_dm_mod_power_update_streams(ctx->state, &ctx->adev->dm);
+}
+
+/**
+ * dm_test_mod_power_update_streams_enable - Test enabling a CRTC adds the 
stream
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_update_streams_enable(struct kunit *test)
+{
+       struct dm_test_modeset_ctx *ctx = dm_test_modeset_ctx_alloc(test);
+
+       ctx->new_crtc_state->base.active = true;
+
+       amdgpu_dm_mod_power_update_streams(ctx->state, &ctx->adev->dm);
+}
+
+/**
+ * dm_test_mod_power_update_streams_replace - Test a re-modeset replaces the 
stream
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_update_streams_replace(struct kunit *test)
+{
+       struct dm_test_modeset_ctx *ctx = dm_test_modeset_ctx_alloc(test);
+
+       ctx->old_crtc_state->base.active = true;
+       ctx->new_crtc_state->base.active = true;
+
+       amdgpu_dm_mod_power_update_streams(ctx->state, &ctx->adev->dm);
+}
+
+/**
+ * dm_test_mod_power_update_streams_disable - Test disabling a CRTC removes 
the stream
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_update_streams_disable(struct kunit *test)
+{
+       struct dm_test_modeset_ctx *ctx = dm_test_modeset_ctx_alloc(test);
+
+       ctx->old_crtc_state->base.active = true;
+
+       amdgpu_dm_mod_power_update_streams(ctx->state, &ctx->adev->dm);
+}
+
+/**
+ * dm_test_mod_power_setup_streams_modeset - Test a modeset sets up the new 
stream
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_setup_streams_modeset(struct kunit *test)
+{
+       struct dm_test_modeset_ctx *ctx = dm_test_modeset_ctx_alloc(test);
+
+       ctx->new_crtc_state->base.active = true;
+
+       amdgpu_dm_mod_power_setup_streams(ctx->state, &ctx->adev->dm);
+}
+
+/**
+ * dm_test_mod_power_setup_streams_no_modeset - Test fast updates set up no 
streams
+ * @test: The KUnit test context
+ */
+static void dm_test_mod_power_setup_streams_no_modeset(struct kunit *test)
+{
+       struct dm_test_modeset_ctx *ctx = dm_test_modeset_ctx_alloc(test);
+
+       ctx->new_crtc_state->base.mode_changed = false;
+       ctx->new_crtc_state->base.active = true;
+
+       amdgpu_dm_mod_power_setup_streams(ctx->state, &ctx->adev->dm);
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
        /* Simple DM callbacks */
        KUNIT_CASE(dm_test_wait_for_idle),
@@ -3323,6 +3485,14 @@ static struct kunit_case amdgpu_dm_tests[] = {
        KUNIT_CASE(dm_test_aquire_global_lock_no_crtc),
        KUNIT_CASE(dm_test_aquire_global_lock_no_commit),
        KUNIT_CASE(dm_test_aquire_global_lock_waits_commit),
+       KUNIT_CASE(dm_test_mod_power_update_streams_empty),
+       KUNIT_CASE(dm_test_mod_power_update_streams_no_modeset),
+       KUNIT_CASE(dm_test_mod_power_update_streams_enable),
+       KUNIT_CASE(dm_test_mod_power_update_streams_replace),
+       KUNIT_CASE(dm_test_mod_power_update_streams_disable),
+       KUNIT_CASE(dm_test_mod_power_setup_streams_empty),
+       KUNIT_CASE(dm_test_mod_power_setup_streams_modeset),
+       KUNIT_CASE(dm_test_mod_power_setup_streams_no_modeset),
        /* amdgpu_dm_trigger_timing_sync */
        KUNIT_CASE(dm_test_trigger_timing_sync_no_state),
        KUNIT_CASE(dm_test_trigger_timing_sync_streams),
-- 
2.43.0

Reply via email to