diff options
| author | Alex Hung <alex.hung@amd.com> | 2026-08-13 21:00:45 -0600 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-09-10 11:59:45 -0400 |
| commit | 519ba75dcd1a4061909d2bf74230b84136dae2cc (patch) | |
| tree | c175bfd83086017562a3ca344360e80272c8aa7a | |
| parent | 767ae341b68193fda5fdbc510b2d77e3e8938039 (diff) | |
| download | linux-next-519ba75dcd1a4061909d2bf74230b84136dae2cc.tar.gz linux-next-519ba75dcd1a4061909d2bf74230b84136dae2cc.zip | |
drm/amd/display: Test self refresh entry
[Why]
Add KUnit tests for amdgpu_dm_enable_self_refresh(), covering the full
update and unsupported link blocks, the skip count gating, the damage
settle window, and a Replay capable link.
[How]
The power module stays NULL, which every mod_power entry point treats as
a no-op, so the event updates can be reached without a live power
module.
Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
| -rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c | 148 |
3 files changed, 156 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 0ec8ef881fc1..b31f4e090790 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3722,10 +3722,10 @@ STATIC_IFN_KUNIT void amdgpu_dm_update_cursor(struct drm_plane *plane, } EXPORT_IF_KUNIT(amdgpu_dm_update_cursor); -static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm, - struct amdgpu_crtc *acrtc_attach, - const struct dm_crtc_state *acrtc_state, - const u64 current_ts) +STATIC_IFN_KUNIT void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm, + struct amdgpu_crtc *acrtc_attach, + const struct dm_crtc_state *acrtc_state, + const u64 current_ts) { struct psr_settings *psr = &acrtc_state->stream->link->psr_settings; struct replay_settings *pr = &acrtc_state->stream->link->replay_settings; @@ -3761,6 +3761,7 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm, acrtc_attach->dm_irq_params.allow_sr_entry = false; } } +EXPORT_IF_KUNIT(amdgpu_dm_enable_self_refresh); STATIC_IFN_KUNIT void dm_arm_vblank_event(struct amdgpu_crtc *acrtc, struct dm_crtc_state *acrtc_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 ad72dc182e93..9399f71c528e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -1266,6 +1266,9 @@ int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state, struct dc_ struct dsc_mst_fairness_vars *vars); void manage_dm_interrupts(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc, struct dm_crtc_state *acrtc_state); +void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm, + struct amdgpu_crtc *acrtc_attach, + const struct dm_crtc_state *acrtc_state, const u64 current_ts); int load_dmcu_fw(struct amdgpu_device *adev); int dm_sw_init(struct amdgpu_ip_block *ip_block); int dm_late_init(struct amdgpu_ip_block *ip_block); 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 4daa187fbd0a..3c975ca2710d 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 @@ -3803,6 +3803,147 @@ static void dm_test_plane_info_layer_and_blending(struct kunit *test) KUNIT_EXPECT_EQ(test, ctx->plane_info.global_alpha_value, 0x7f); } +/* Tests for amdgpu_dm_enable_self_refresh() */ + +struct dm_test_sr_ctx { + struct amdgpu_display_manager *dm; + struct amdgpu_crtc *acrtc; + struct dm_crtc_state *acrtc_state; + struct amdgpu_dm_connector *aconn; + struct dc_link *link; +}; + +/* + * A fast-update CRTC whose stream has a self-refresh capable link. The power + * module stays NULL, which every mod_power entry point treats as a no-op. + */ +static struct dm_test_sr_ctx *dm_test_sr_ctx_alloc(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + ctx->dm = dm_kunit_alloc_dm(test); + ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc); + ctx->acrtc_state = kunit_kzalloc(test, sizeof(*ctx->acrtc_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc_state); + ctx->aconn = kunit_kzalloc(test, sizeof(*ctx->aconn), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->aconn); + + ctx->link = dm_kunit_alloc_link(test); + ctx->acrtc_state->stream = dm_kunit_alloc_stream(test, ctx->link); + ctx->acrtc_state->stream->dm_stream_context = ctx->aconn; + ctx->acrtc_state->update_type = UPDATE_TYPE_FAST; + + return ctx; +} + +static void dm_test_enable_sr(struct dm_test_sr_ctx *ctx, u64 current_ts) +{ + amdgpu_dm_enable_self_refresh(ctx->dm, ctx->acrtc, ctx->acrtc_state, + current_ts); +} + +/** + * dm_test_self_refresh_full_update - Test a full update blocks self refresh + * @test: The KUnit test context + */ +static void dm_test_self_refresh_full_update(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test); + + ctx->acrtc_state->update_type = UPDATE_TYPE_FULL; + ctx->link->psr_settings.psr_feature_enabled = true; + ctx->acrtc->dm_irq_params.allow_sr_entry = true; + + dm_test_enable_sr(ctx, 0); + + KUNIT_EXPECT_FALSE(test, ctx->acrtc->dm_irq_params.allow_sr_entry); +} + +/** + * dm_test_self_refresh_unsupported_link - Test a link without PSR or Replay + * @test: The KUnit test context + */ +static void dm_test_self_refresh_unsupported_link(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test); + + ctx->acrtc->dm_irq_params.allow_sr_entry = true; + + dm_test_enable_sr(ctx, 0); + + KUNIT_EXPECT_FALSE(test, ctx->acrtc->dm_irq_params.allow_sr_entry); +} + +/** + * dm_test_self_refresh_decrements_skip_count - Test the skip count gates entry + * @test: The KUnit test context + */ +static void dm_test_self_refresh_decrements_skip_count(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test); + + ctx->link->psr_settings.psr_feature_enabled = true; + ctx->aconn->sr_skip_count = 2; + + dm_test_enable_sr(ctx, 0); + + KUNIT_EXPECT_EQ(test, ctx->aconn->sr_skip_count, 1); + KUNIT_EXPECT_FALSE(test, ctx->acrtc->dm_irq_params.allow_sr_entry); +} + +/** + * dm_test_self_refresh_allows_entry - Test a drained skip count allows entry + * @test: The KUnit test context + */ +static void dm_test_self_refresh_allows_entry(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test); + + ctx->link->psr_settings.psr_feature_enabled = true; + ctx->aconn->sr_skip_count = 1; + + /* Well past the 500ms settle window, so the events are cleared. */ + dm_test_enable_sr(ctx, 2ULL * NSEC_PER_SEC); + + KUNIT_EXPECT_EQ(test, ctx->aconn->sr_skip_count, 0); + KUNIT_EXPECT_TRUE(test, ctx->acrtc->dm_irq_params.allow_sr_entry); +} + +/** + * dm_test_self_refresh_within_settle_window - Test a recent damage change holds off + * @test: The KUnit test context + */ +static void dm_test_self_refresh_within_settle_window(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test); + + ctx->link->psr_settings.psr_feature_enabled = true; + ctx->link->psr_settings.psr_dirty_rects_change_timestamp_ns = 1; + + dm_test_enable_sr(ctx, 2); + + KUNIT_EXPECT_TRUE(test, ctx->acrtc->dm_irq_params.allow_sr_entry); +} + +/** + * dm_test_self_refresh_replay_link - Test a Replay capable link takes the same path + * @test: The KUnit test context + */ +static void dm_test_self_refresh_replay_link(struct kunit *test) +{ + struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test); + + ctx->link->replay_settings.replay_feature_enabled = true; + + dm_test_enable_sr(ctx, 2ULL * NSEC_PER_SEC); + + KUNIT_EXPECT_TRUE(test, ctx->acrtc->dm_irq_params.allow_sr_entry); +} + /* Tests for manage_dm_interrupts() */ struct dm_test_irq_mgmt_ctx { @@ -4836,6 +4977,13 @@ static struct kunit_case amdgpu_dm_tests[] = { KUNIT_CASE(dm_test_plane_info_bad_color_encoding), KUNIT_CASE(dm_test_plane_info_rotations), KUNIT_CASE(dm_test_plane_info_layer_and_blending), + /* amdgpu_dm_enable_self_refresh */ + KUNIT_CASE(dm_test_self_refresh_full_update), + KUNIT_CASE(dm_test_self_refresh_unsupported_link), + KUNIT_CASE(dm_test_self_refresh_decrements_skip_count), + KUNIT_CASE(dm_test_self_refresh_allows_entry), + KUNIT_CASE(dm_test_self_refresh_within_settle_window), + KUNIT_CASE(dm_test_self_refresh_replay_link), /* manage_dm_interrupts */ KUNIT_CASE(dm_test_manage_interrupts_offdelay), KUNIT_CASE(dm_test_manage_interrupts_offdelay_fallback), |
