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
