From 6815b3ebc4f3e98cb0343937e039a2dabc06fd88 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 13 Aug 2026 14:00:33 -0600 Subject: [PATCH] drm/amd/display: Test vblank counter and scanout position [WHAT] Add KUnit tests for dm_vblank_get_counter() and dm_crtc_get_scanoutpos() covering a CRTC whose stream is not owned by any pipe in the resource context, and the branch that disables idle optimizations before reading the scanout position. [HOW] Wire a DC context, a current DC state and a logger to the device so both callbacks walk the resource context instead of returning early. Assisted-by: Copilot:Claude-Opus-5 GPT-5.6-Sol Reviewed-by: Bhawanpreet Lakha Signed-off-by: Alex Hung Tested-by: Dan Wheeler Signed-off-by: Alex Deucher --- .../display/amdgpu_dm/tests/amdgpu_dm_test.c | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) 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 a0f90b0bd74a..33cca3f01b5b 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 @@ -8,13 +8,23 @@ #include #include #include +#include #include #include +#include +#include #include +#include +#include +#include +#include #include #include "dc.h" +#include "dm_services_types.h" +#include "dmub/dmub_srv.h" #include "inc/core_types.h" +#include "logger_types.h" #include "amd_shared.h" #include "amdgpu.h" #include "amdgpu_mode.h" @@ -1141,6 +1151,87 @@ static void dm_test_apply_delay_nonzero_wait(struct kunit *test) amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, sink); } +/* + * Attach a DC stream to CRTC 0 of @adev so the scanout helpers walk the DC + * resource context instead of bailing out early. + */ +static void dm_test_crtc_with_stream(struct kunit *test, + struct amdgpu_device *adev, struct dc *dc) +{ + struct dc_stream_state *stream; + struct amdgpu_crtc *acrtc; + struct dal_logger *logger; + + acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, acrtc); + + logger = kunit_kzalloc(test, sizeof(*logger), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, logger); + logger->dev = &adev->ddev; + dc->ctx->logger = logger; + + dc->current_state = dm_kunit_alloc_dc_state(test); + KUNIT_ASSERT_NOT_NULL(test, dc->current_state); + + stream = dm_kunit_alloc_stream(test, NULL); + stream->ctx = dc->ctx; + + adev->dm.dc = dc; + adev->mode_info.num_crtc = 1; + adev->mode_info.crtcs[0] = acrtc; + acrtc->dm_irq_params.stream = stream; +} + +/** + * dm_test_vblank_get_counter_unmapped_stream - Test a stream without a pipe returns zero + * @test: The KUnit test context + */ +static void dm_test_vblank_get_counter_unmapped_stream(struct kunit *test) +{ + struct amdgpu_device *adev = dm_kunit_alloc_adev(test); + struct dc *dc = dm_kunit_alloc_dc_with_ctx(test); + + dm_test_crtc_with_stream(test, adev, dc); + + KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 0), 0U); +} + +/** + * dm_test_crtc_get_scanoutpos_unmapped_stream - Test scanout position for an unmapped stream + * @test: The KUnit test context + */ +static void dm_test_crtc_get_scanoutpos_unmapped_stream(struct kunit *test) +{ + struct amdgpu_device *adev = dm_kunit_alloc_adev(test); + struct dc *dc = dm_kunit_alloc_dc_with_ctx(test); + u32 vbl = 0xdeadbeef; + u32 position = 0xdeadbeef; + + dm_test_crtc_with_stream(test, adev, dc); + + KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 0, &vbl, &position), 0); + KUNIT_EXPECT_EQ(test, vbl, 0U); + KUNIT_EXPECT_EQ(test, position, 0U); +} + +/** + * dm_test_crtc_get_scanoutpos_exits_idle - Test idle optimizations are disabled first + * @test: The KUnit test context + */ +static void dm_test_crtc_get_scanoutpos_exits_idle(struct kunit *test) +{ + struct amdgpu_device *adev = dm_kunit_alloc_adev(test); + struct dc *dc = dm_kunit_alloc_dc_with_ctx(test); + u32 vbl = 0; + u32 position = 0; + + dm_test_crtc_with_stream(test, adev, dc); + dc->caps.ips_support = true; + dc->idle_optimizations_allowed = true; + + KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 0, &vbl, &position), 0); +} + static struct kunit_case amdgpu_dm_tests[] = { /* Simple DM callbacks */ KUNIT_CASE(dm_test_wait_for_idle), @@ -1207,6 +1298,10 @@ static struct kunit_case amdgpu_dm_tests[] = { KUNIT_CASE(dm_test_apply_delay_null_sink), KUNIT_CASE(dm_test_apply_delay_zero_wait), KUNIT_CASE(dm_test_apply_delay_nonzero_wait), + /* dm_vblank_get_counter / dm_crtc_get_scanoutpos with a stream */ + KUNIT_CASE(dm_test_vblank_get_counter_unmapped_stream), + KUNIT_CASE(dm_test_crtc_get_scanoutpos_unmapped_stream), + KUNIT_CASE(dm_test_crtc_get_scanoutpos_exits_idle), {} };