From: Alex Hung <[email protected]>

[WHAT]
Add KUnit tests for get_freesync_config_for_crtc and
reset_freesync_config_for_crtc using a shared connector/crtc/stream
fixture. Cover the writeback early return, the not-capable and
out-of-range unsupported paths, the active-variable, inactive and
active-fixed states, and the config reset.

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 |   8 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   3 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 197 ++++++++++++++++++
 3 files changed, 205 insertions(+), 3 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 03b9079ce818..fa0add5bcabf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -126,7 +126,7 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
 /* basic init/fini API */
 static int amdgpu_dm_init(struct amdgpu_device *adev);
 static void amdgpu_dm_fini(struct amdgpu_device *adev);
-static void reset_freesync_config_for_crtc(struct dm_crtc_state 
*new_crtc_state);
+STATIC_IFN_KUNIT void reset_freesync_config_for_crtc(struct dm_crtc_state 
*new_crtc_state);
 
 /*
  * initializes drm_device display related structures, based on the information
@@ -5733,7 +5733,7 @@ static int do_aquire_global_lock(struct drm_device *dev,
        return ret < 0 ? ret : 0;
 }
 
-static void get_freesync_config_for_crtc(
+STATIC_IFN_KUNIT void get_freesync_config_for_crtc(
        struct dm_crtc_state *new_crtc_state,
        struct dm_connector_state *new_con_state)
 {
@@ -5776,8 +5776,9 @@ static void get_freesync_config_for_crtc(
 out:
        new_crtc_state->freesync_config = config;
 }
+EXPORT_IF_KUNIT(get_freesync_config_for_crtc);
 
-static void reset_freesync_config_for_crtc(
+STATIC_IFN_KUNIT void reset_freesync_config_for_crtc(
        struct dm_crtc_state *new_crtc_state)
 {
        new_crtc_state->vrr_supported = false;
@@ -5785,6 +5786,7 @@ static void reset_freesync_config_for_crtc(
        memset(&new_crtc_state->vrr_infopacket, 0,
               sizeof(new_crtc_state->vrr_infopacket));
 }
+EXPORT_IF_KUNIT(reset_freesync_config_for_crtc);
 
 STATIC_IFN_KUNIT bool
 is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_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 c508f0be1b55..29cefa4d8468 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,9 @@ 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);
+void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
+void get_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state,
+                                 struct dm_connector_state *new_con_state);
 struct hdcp_workqueue;
 bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
                                     struct drm_crtc_state *old_crtc_state,
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 1caacad43106..1464eeda704b 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
@@ -1650,6 +1650,194 @@ static void dm_test_cp_diff_desired_to_undesired(struct 
kunit *test)
        KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
 }
 
+/* Tests for get_freesync_config_for_crtc() */
+
+struct dm_test_freesync_ctx {
+       struct amdgpu_dm_connector *aconnector;
+       struct dm_crtc_state *crtc_state;
+       struct dm_connector_state *conn_state;
+       struct dc_stream_state *stream;
+};
+
+static struct dm_test_freesync_ctx *dm_test_freesync_ctx_alloc(struct kunit 
*test)
+{
+       struct dm_test_freesync_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->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+       ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
+       ctx->stream = dm_kunit_alloc_stream(test, NULL);
+
+       ctx->conn_state->base.connector = &ctx->aconnector->base;
+       ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_DisplayPort;
+       ctx->crtc_state->stream = ctx->stream;
+
+       /* 1080p60 timing so drm_mode_vrefresh() == 60 */
+       ctx->crtc_state->base.mode.clock = 148500;
+       ctx->crtc_state->base.mode.htotal = 2200;
+       ctx->crtc_state->base.mode.vtotal = 1125;
+
+       return ctx;
+}
+
+/**
+ * dm_test_freesync_config_writeback - Test writeback connector is left 
untouched
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_writeback(struct kunit *test)
+{
+       struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+       ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_WRITEBACK;
+       ctx->conn_state->freesync_capable = true;
+       ctx->aconnector->min_vfreq = 48;
+       ctx->aconnector->max_vfreq = 120;
+       ctx->crtc_state->vrr_supported = true;  /* sentinel: must stay set */
+
+       get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+       /* Writeback: early return leaves vrr_supported sentinel untouched */
+       KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+}
+
+/**
+ * dm_test_freesync_config_not_capable - Test a non-freesync sink reports 
UNSUPPORTED
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_not_capable(struct kunit *test)
+{
+       struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+       ctx->conn_state->freesync_capable = false;
+       ctx->aconnector->min_vfreq = 48;
+       ctx->aconnector->max_vfreq = 120;
+
+       get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+       KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
+       KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+                       (int)VRR_STATE_UNSUPPORTED);
+}
+
+/**
+ * dm_test_freesync_config_out_of_range - Test a refresh outside the range is 
UNSUPPORTED
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_out_of_range(struct kunit *test)
+{
+       struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+       ctx->conn_state->freesync_capable = true;
+       ctx->aconnector->min_vfreq = 90;        /* 60 < 90 -> out of range */
+       ctx->aconnector->max_vfreq = 120;
+
+       get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+       KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
+       KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+                       (int)VRR_STATE_UNSUPPORTED);
+}
+
+/**
+ * dm_test_freesync_config_active_variable - Test vrr_enabled yields 
ACTIVE_VARIABLE
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_active_variable(struct kunit *test)
+{
+       struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+       ctx->conn_state->freesync_capable = true;
+       ctx->aconnector->min_vfreq = 48;
+       ctx->aconnector->max_vfreq = 120;
+       ctx->crtc_state->base.vrr_enabled = true;
+
+       get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+       KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+       KUNIT_EXPECT_TRUE(test, ctx->stream->ignore_msa_timing_param);
+       KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+                       (int)VRR_STATE_ACTIVE_VARIABLE);
+       KUNIT_EXPECT_EQ(test, 
ctx->crtc_state->freesync_config.min_refresh_in_uhz,
+                       48000000U);
+       KUNIT_EXPECT_EQ(test, 
ctx->crtc_state->freesync_config.max_refresh_in_uhz,
+                       120000000U);
+       KUNIT_EXPECT_TRUE(test, 
ctx->crtc_state->freesync_config.vsif_supported);
+       KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.btr);
+}
+
+/**
+ * dm_test_freesync_config_inactive - Test supported-but-off yields INACTIVE
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_inactive(struct kunit *test)
+{
+       struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+       ctx->conn_state->freesync_capable = true;
+       ctx->aconnector->min_vfreq = 48;
+       ctx->aconnector->max_vfreq = 120;
+       ctx->crtc_state->base.vrr_enabled = false;
+
+       get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+       KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+       KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+                       (int)VRR_STATE_INACTIVE);
+}
+
+/**
+ * dm_test_freesync_config_active_fixed - Test freesync-video mode yields 
ACTIVE_FIXED
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_config_active_fixed(struct kunit *test)
+{
+       struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
+
+       ctx->conn_state->freesync_capable = true;
+       ctx->aconnector->min_vfreq = 48;
+       ctx->aconnector->max_vfreq = 120;
+       /* Pre-set fixed state selects the freesync-video (fixed) path */
+       ctx->crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
+       ctx->crtc_state->freesync_config.fixed_refresh_in_uhz = 60000000;
+       ctx->crtc_state->base.vrr_enabled = true;       /* ignored on the fixed 
path */
+
+       get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
+
+       KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
+       KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
+                       (int)VRR_STATE_ACTIVE_FIXED);
+       KUNIT_EXPECT_EQ(test, 
ctx->crtc_state->freesync_config.fixed_refresh_in_uhz,
+                       60000000U);
+}
+
+/* Tests for reset_freesync_config_for_crtc() */
+
+/**
+ * dm_test_reset_freesync_config - Test reset clears vrr support and info 
packet
+ * @test: The KUnit test context
+ */
+static void dm_test_reset_freesync_config(struct kunit *test)
+{
+       struct dm_crtc_state *crtc_state;
+
+       crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, crtc_state);
+
+       crtc_state->vrr_supported = true;
+       crtc_state->vrr_infopacket.valid = true;
+
+       reset_freesync_config_for_crtc(crtc_state);
+
+       KUNIT_EXPECT_FALSE(test, crtc_state->vrr_supported);
+       KUNIT_EXPECT_FALSE(test, crtc_state->vrr_infopacket.valid);
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
        /* Simple DM callbacks */
        KUNIT_CASE(dm_test_is_idle),
@@ -1742,6 +1930,15 @@ static struct kunit_case amdgpu_dm_tests[] = {
        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),
+       /* get_freesync_config_for_crtc */
+       KUNIT_CASE(dm_test_freesync_config_writeback),
+       KUNIT_CASE(dm_test_freesync_config_not_capable),
+       KUNIT_CASE(dm_test_freesync_config_out_of_range),
+       KUNIT_CASE(dm_test_freesync_config_active_variable),
+       KUNIT_CASE(dm_test_freesync_config_inactive),
+       KUNIT_CASE(dm_test_freesync_config_active_fixed),
+       /* reset_freesync_config_for_crtc */
+       KUNIT_CASE(dm_test_reset_freesync_config),
        {}
 };
 
-- 
2.43.0

Reply via email to