From: Davey Hughes <[email protected]> KUnit can't call amdgpu_dm_commit_planes(), so test the flip timing copy through dm_plane_inherit_flip_time(), exposed to KUnit here. Test that a plane reset on the same CRTC keeps its flip timing, and that a newly enabled plane or one moved to another CRTC starts over.
Also flip a reset plane one 60 Hz frame after its last flip on a 48-165 Hz panel with BTR. With the inherited timing BTR stays off; without it FreeSync engages BTR. Signed-off-by: Davey Hughes <[email protected]> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 3 + .../amd/display/amdgpu_dm/tests/amdgpu_dm_test.c | 188 +++++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) 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 7a0afe6d1b8a..b655a3333b7b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3854,7 +3854,7 @@ EXPORT_IF_KUNIT(dm_arm_vblank_event_pre_programming); * this at commit time, not in atomic check: by then the previous commit * has finished writing it. */ -static void +STATIC_IFN_KUNIT void dm_plane_inherit_flip_time(struct dc_plane_state *dc_plane_state, struct drm_plane_state *old_plane_state, struct drm_plane_state *new_plane_state) @@ -3866,6 +3866,7 @@ dm_plane_inherit_flip_time(struct dc_plane_state *dc_plane_state, old_plane_state->crtc == new_plane_state->crtc) dc_plane_state->time = old_dc_plane_state->time; } +EXPORT_IF_KUNIT(dm_plane_inherit_flip_time); static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, struct drm_device *dev, 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 594d275918d5..18dce8244af1 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_plane_state(struct dc *dc, bool enable, bool *lock_and_validation_needed, bool *is_top_most_overlay); +void dm_plane_inherit_flip_time(struct dc_plane_state *dc_plane_state, + struct drm_plane_state *old_plane_state, + struct drm_plane_state *new_plane_state); int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_atomic_commit *state); void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commit *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 a497cce332bb..eb1ce999ed83 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 @@ -34,6 +34,7 @@ #include "atom.h" #include "amdgpu_dm.h" #include "amdgpu_dm_audio.h" +#include "amdgpu_dm_freesync.h" #include "amdgpu_dm_hdcp.h" #include "amdgpu_dm_mst_types.h" #include "amdgpu_dm_kunit_test_helpers.h" @@ -3271,6 +3272,188 @@ static void dm_test_update_plane_state_detached(struct kunit *test) KUNIT_EXPECT_NULL(test, new_plane_state->dc_state); } +/* Tests for dm_plane_inherit_flip_time() */ + +struct dm_test_flip_time_ctx { + struct dm_plane_state *old_plane_state; + struct dm_plane_state *new_plane_state; + struct dc_plane_state *dc_plane_state; +}; + +/* + * A plane reset on one CRTC: the old DC plane has FreeSync flip history and + * the new one is freshly created. + */ +static struct dm_test_flip_time_ctx * +dm_test_flip_time_ctx_alloc(struct kunit *test) +{ + struct dm_test_flip_time_ctx *ctx; + struct dc_plane_state *old_dc; + struct drm_crtc *crtc; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + ctx->old_plane_state = kunit_kzalloc(test, sizeof(*ctx->old_plane_state), + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->old_plane_state); + ctx->new_plane_state = kunit_kzalloc(test, sizeof(*ctx->new_plane_state), + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->new_plane_state); + ctx->dc_plane_state = kunit_kzalloc(test, sizeof(*ctx->dc_plane_state), + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->dc_plane_state); + old_dc = kunit_kzalloc(test, sizeof(*old_dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, old_dc); + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, crtc); + + old_dc->time.time_elapsed_in_us[0] = 16667; + old_dc->time.index = 1; + old_dc->time.prev_update_time_in_us = 1234567; + ctx->old_plane_state->dc_state = old_dc; + ctx->old_plane_state->base.crtc = crtc; + ctx->new_plane_state->base.crtc = crtc; + + return ctx; +} + +static void dm_test_flip_time_inherit(struct dm_test_flip_time_ctx *ctx) +{ + dm_plane_inherit_flip_time(ctx->dc_plane_state, + &ctx->old_plane_state->base, + &ctx->new_plane_state->base); +} + +/** + * dm_test_flip_time_same_crtc - Test a reset plane keeps its flip history + * @test: The KUnit test context + */ +static void dm_test_flip_time_same_crtc(struct kunit *test) +{ + struct dm_test_flip_time_ctx *ctx = dm_test_flip_time_ctx_alloc(test); + + dm_test_flip_time_inherit(ctx); + + KUNIT_EXPECT_MEMEQ(test, &ctx->dc_plane_state->time, + &ctx->old_plane_state->dc_state->time, + sizeof(ctx->dc_plane_state->time)); +} + +/** + * dm_test_flip_time_crtc_changed - Test a plane moved between CRTCs starts over + * @test: The KUnit test context + */ +static void dm_test_flip_time_crtc_changed(struct kunit *test) +{ + struct dm_test_flip_time_ctx *ctx = dm_test_flip_time_ctx_alloc(test); + struct dc_plane_flip_time *time = &ctx->dc_plane_state->time; + struct drm_crtc *other_crtc; + + other_crtc = kunit_kzalloc(test, sizeof(*other_crtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, other_crtc); + ctx->new_plane_state->base.crtc = other_crtc; + + dm_test_flip_time_inherit(ctx); + + KUNIT_EXPECT_NULL(test, memchr_inv(time, 0, sizeof(*time))); +} + +/** + * dm_test_flip_time_no_old_dc_state - Test a newly enabled plane starts over + * @test: The KUnit test context + */ +static void dm_test_flip_time_no_old_dc_state(struct kunit *test) +{ + struct dm_test_flip_time_ctx *ctx = dm_test_flip_time_ctx_alloc(test); + struct dc_plane_flip_time *time = &ctx->dc_plane_state->time; + + ctx->old_plane_state->dc_state = NULL; + + dm_test_flip_time_inherit(ctx); + + KUNIT_EXPECT_NULL(test, memchr_inv(time, 0, sizeof(*time))); +} + +/* + * Flip the reset plane one 60 Hz frame after the old plane's last flip on a + * 48-165 Hz panel with below-the-range compensation, and report whether + * FreeSync engaged BTR. + */ +static bool dm_test_flip_time_btr_active(struct kunit *test, + struct dm_test_flip_time_ctx *ctx) +{ + struct amdgpu_device *adev = dm_kunit_alloc_adev(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); + struct dm_crtc_state *crtc_state; + struct mod_vrr_params *vrr; + struct amdgpu_crtc *acrtc; + u32 flip_time_in_us; + + acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, acrtc); + crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + adev->dm.adev = adev; + /* Only pre-AI flips dereference the module, so a stub will do. */ + adev->family = AMDGPU_FAMILY_NV; + adev->dm.freesync_module = kunit_kzalloc(test, sizeof(struct mod_freesync), + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev->dm.freesync_module); + + /* 165 Hz nominal */ + stream->ctx = dm_kunit_alloc_dc_with_ctx(test)->ctx; + stream->timing.pix_clk_100hz = 4083750; + stream->timing.h_total = 2200; + stream->timing.v_total = 1125; + + crtc_state->base.crtc = &acrtc->base; + crtc_state->base.vrr_enabled = true; + crtc_state->stream = stream; + crtc_state->vrr_supported = true; + crtc_state->freesync_config.min_refresh_in_uhz = 48000000; + crtc_state->freesync_config.max_refresh_in_uhz = 165000000; + crtc_state->freesync_config.btr = true; + + amdgpu_dm_update_stream_irq_parameters(&adev->dm, crtc_state); + + vrr = &acrtc->dm_irq_params.vrr_params; + KUNIT_ASSERT_EQ(test, (int)vrr->state, (int)VRR_STATE_ACTIVE_VARIABLE); + KUNIT_ASSERT_TRUE(test, vrr->btr.btr_enabled); + KUNIT_ASSERT_FALSE(test, vrr->btr.btr_active); + + flip_time_in_us = + ctx->old_plane_state->dc_state->time.prev_update_time_in_us + 16667; + amdgpu_dm_update_freesync_state_on_stream(&adev->dm, crtc_state, stream, + ctx->dc_plane_state, + flip_time_in_us); + + return vrr->btr.btr_active; +} + +/** + * dm_test_flip_time_btr_inherited - Test a reset plane's next flip stays out of BTR + * @test: The KUnit test context + */ +static void dm_test_flip_time_btr_inherited(struct kunit *test) +{ + struct dm_test_flip_time_ctx *ctx = dm_test_flip_time_ctx_alloc(test); + + dm_test_flip_time_inherit(ctx); + + KUNIT_EXPECT_FALSE(test, dm_test_flip_time_btr_active(test, ctx)); +} + +/** + * dm_test_flip_time_btr_no_history - Test a plane without flip history enters BTR + * @test: The KUnit test context + */ +static void dm_test_flip_time_btr_no_history(struct kunit *test) +{ + struct dm_test_flip_time_ctx *ctx = dm_test_flip_time_ctx_alloc(test); + + KUNIT_EXPECT_TRUE(test, dm_test_flip_time_btr_active(test, ctx)); +} + /** * dm_test_mod_power_update_streams_empty - Test an empty commit updates no streams * @test: The KUnit test context @@ -5361,6 +5544,11 @@ static struct kunit_case amdgpu_dm_tests[] = { KUNIT_CASE(dm_test_aquire_global_lock_waits_commit), KUNIT_CASE(dm_test_update_crtc_state_unchanged), KUNIT_CASE(dm_test_update_plane_state_detached), + KUNIT_CASE(dm_test_flip_time_same_crtc), + KUNIT_CASE(dm_test_flip_time_crtc_changed), + KUNIT_CASE(dm_test_flip_time_no_old_dc_state), + KUNIT_CASE(dm_test_flip_time_btr_inherited), + KUNIT_CASE(dm_test_flip_time_btr_no_history), 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), -- 2.56.0
