[PATCH 35/70] drm/amd/display: add KUnit tests for freesync config

Wayne Lin <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
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
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.