drm/amd/display: add KUnit tests for DM CRTC vblank/scanout

[WHAT]
Add KUnit tests for the DM CRTC helpers: the no-writeback and
non-pending writeback paths of amdgpu_dm_crtc_complete_writeback, the
out-of-range and no-stream paths of dm_vblank_get_counter, and the
invalid-CRTC and no-stream paths of dm_crtc_get_scanoutpos.

Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Wayne Lin <wayne.lin@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Alex Hung 2026-07-06 19:23:04 -06:00 committed by Alex Deucher
parent 02b3e22145
commit 9e5b9ead75
3 changed files with 121 additions and 3 deletions

View File

@ -169,7 +169,7 @@ static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
* @return
* Counter for vertical blanks
*/
static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
STATIC_IFN_KUNIT u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
{
struct amdgpu_crtc *acrtc = NULL;
@ -186,9 +186,10 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
return dc_stream_get_vblank_counter(acrtc->dm_irq_params.stream);
}
EXPORT_IF_KUNIT(dm_vblank_get_counter);
static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
u32 *vbl, u32 *position)
STATIC_IFN_KUNIT int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
u32 *vbl, u32 *position)
{
u32 v_blank_start = 0, v_blank_end = 0, h_position = 0, v_position = 0;
struct amdgpu_crtc *acrtc = NULL;
@ -223,6 +224,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
return 0;
}
EXPORT_IF_KUNIT(dm_crtc_get_scanoutpos);
STATIC_IFN_KUNIT bool dm_is_idle(struct amdgpu_ip_block *ip_block)
{
@ -4688,6 +4690,7 @@ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc)
return true;
}
EXPORT_IF_KUNIT(amdgpu_dm_crtc_complete_writeback);
static void dm_clear_writeback(struct amdgpu_display_manager *dm,
struct amdgpu_crtc *acrtc,

View File

@ -1149,6 +1149,9 @@ int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
enum amd_powergating_state state);
void dm_bandwidth_update(struct amdgpu_device *adev);
u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc);
int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
u32 *vbl, u32 *position);
int dm_plane_layer_index_cmp(const void *a, const void *b);
int fill_plane_color_attributes(const struct drm_plane_state *plane_state,
const enum surface_pixel_format format,

View File

@ -77,6 +77,112 @@ static void dm_test_bandwidth_update(struct kunit *test)
dm_bandwidth_update(NULL);
}
/**
* dm_test_crtc_complete_writeback_no_connector - Test no writeback connector returns false
* @test: The KUnit test context
*/
static void dm_test_crtc_complete_writeback_no_connector(struct kunit *test)
{
struct amdgpu_crtc *acrtc;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, acrtc);
KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_complete_writeback(acrtc));
}
/**
* dm_test_crtc_complete_writeback_not_pending - Test non-pending writeback returns false
* @test: The KUnit test context
*/
static void dm_test_crtc_complete_writeback_not_pending(struct kunit *test)
{
struct amdgpu_crtc *acrtc;
struct drm_writeback_connector *wb_conn;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, acrtc);
wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, wb_conn);
spin_lock_init(&wb_conn->job_lock);
acrtc->wb_conn = wb_conn;
acrtc->wb_pending = false;
KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_complete_writeback(acrtc));
}
/**
* dm_test_vblank_get_counter_out_of_range - Test out-of-range CRTC returns zero
* @test: The KUnit test context
*/
static void dm_test_vblank_get_counter_out_of_range(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
adev->mode_info.num_crtc = 1;
KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 1), 0U);
}
/**
* dm_test_vblank_get_counter_no_stream - Test missing stream returns zero
* @test: The KUnit test context
*/
static void dm_test_vblank_get_counter_no_stream(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
struct amdgpu_crtc *acrtc;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, acrtc);
adev->mode_info.num_crtc = 1;
adev->mode_info.crtcs[0] = acrtc;
KUNIT_EXPECT_EQ(test, dm_vblank_get_counter(adev, 0), 0U);
}
/**
* dm_test_crtc_get_scanoutpos_invalid_crtc - Test invalid CRTC returns -EINVAL
* @test: The KUnit test context
*/
static void dm_test_crtc_get_scanoutpos_invalid_crtc(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
u32 vbl = 0;
u32 position = 0;
adev->mode_info.num_crtc = 1;
KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, -1, &vbl, &position),
-EINVAL);
KUNIT_EXPECT_EQ(test, dm_crtc_get_scanoutpos(adev, 1, &vbl, &position),
-EINVAL);
}
/**
* dm_test_crtc_get_scanoutpos_no_stream - Test missing stream returns zero
* @test: The KUnit test context
*/
static void dm_test_crtc_get_scanoutpos_no_stream(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
struct amdgpu_crtc *acrtc;
u32 vbl = 0;
u32 position = 0;
acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, acrtc);
adev->mode_info.num_crtc = 1;
adev->mode_info.crtcs[0] = acrtc;
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);
}
/* Tests for dm_plane_layer_index_cmp() */
/**
@ -957,6 +1063,12 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_set_clockgating_state),
KUNIT_CASE(dm_test_set_powergating_state),
KUNIT_CASE(dm_test_bandwidth_update),
KUNIT_CASE(dm_test_crtc_complete_writeback_no_connector),
KUNIT_CASE(dm_test_crtc_complete_writeback_not_pending),
KUNIT_CASE(dm_test_vblank_get_counter_out_of_range),
KUNIT_CASE(dm_test_vblank_get_counter_no_stream),
KUNIT_CASE(dm_test_crtc_get_scanoutpos_invalid_crtc),
KUNIT_CASE(dm_test_crtc_get_scanoutpos_no_stream),
/* dm_plane_layer_index_cmp */
KUNIT_CASE(dm_test_plane_layer_index_cmp_equal),
KUNIT_CASE(dm_test_plane_layer_index_cmp_descending),