drm/amd/display: Test mode and plane init

[WHAT]
Add KUnit tests for amdgpu_dm_mode_config_init() and initialize_plane(),
covering the mode config defaults, the Hawaii preferred shadow quirk,
the DM private object state, and primary and overlay plane creation.

[HOW]
drm_atomic_private_obj_init() builds the private state through
dm_atomic_create_state(), so a current DC state is enough to exercise
it. Audio is disabled for the duration of the test so no audio component
is left registered on the mock device.

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>
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-08-13 21:00:44 -06:00 committed by Alex Deucher
parent 207964daac
commit 69ec2e82fb
3 changed files with 144 additions and 5 deletions

View File

@ -2253,7 +2253,7 @@ static struct drm_private_state_funcs dm_atomic_state_funcs = {
.atomic_destroy_state = dm_atomic_destroy_state,
};
static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
STATIC_IFN_KUNIT int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
{
int r;
@ -2293,11 +2293,12 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_mode_config_init);
static int initialize_plane(struct amdgpu_display_manager *dm,
struct amdgpu_mode_info *mode_info, int plane_id,
enum drm_plane_type plane_type,
const struct dc_plane_cap *plane_cap)
STATIC_IFN_KUNIT int initialize_plane(struct amdgpu_display_manager *dm,
struct amdgpu_mode_info *mode_info, int plane_id,
enum drm_plane_type plane_type,
const struct dc_plane_cap *plane_cap)
{
struct drm_plane *plane;
unsigned long possible_crtcs;
@ -2333,6 +2334,7 @@ static int initialize_plane(struct amdgpu_display_manager *dm,
return ret;
}
EXPORT_IF_KUNIT(initialize_plane);
/*

View File

@ -1249,6 +1249,7 @@ struct amdgpu_dm_kunit_ops {
void amdgpu_dm_kunit_set_ops(const struct amdgpu_dm_kunit_ops *ops);
struct dc_phy_addr_space_config;
struct dc_plane_cap;
void mmhub_read_system_context(struct amdgpu_device *adev,
struct dc_phy_addr_space_config *pa_config);
@ -1256,6 +1257,10 @@ int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm);
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);
int amdgpu_dm_mode_config_init(struct amdgpu_device *adev);
int initialize_plane(struct amdgpu_display_manager *dm, struct amdgpu_mode_info *mode_info,
int plane_id, enum drm_plane_type plane_type,
const struct dc_plane_cap *plane_cap);
#endif
#endif /* __AMDGPU_DM_H__ */

View File

@ -31,6 +31,7 @@
#include "amdgpu.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_audio.h"
#include "amdgpu_dm_hdcp.h"
#include "amdgpu_dm_kunit_test_helpers.h"
@ -3785,6 +3786,131 @@ static void dm_test_late_init_boot_crc_disabled(struct kunit *test)
KUNIT_EXPECT_NULL(test, adev->dm.boot_time_crc_info.bo_ptr);
}
/* Tests for amdgpu_dm_mode_config_init() */
static void dm_test_fini_atomic_obj(void *ctx)
{
drm_atomic_private_obj_fini(ctx);
}
static void dm_test_restore_audio_param(void *ctx)
{
amdgpu_dm_audio_set_param((long)ctx);
}
/*
* A device ready for mode config init: DM creates its private object state
* from the current DC state, and audio is disabled so no audio component is
* left registered on the mock device.
*/
static struct amdgpu_device *dm_test_mode_config_adev(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
long saved_audio = amdgpu_dm_audio_get_param();
adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
adev->dm.dc->current_state = dm_kunit_alloc_dc_state(test);
KUNIT_ASSERT_NOT_NULL(test, adev->dm.dc->current_state);
amdgpu_dm_audio_set_param(0);
KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_restore_audio_param,
(void *)saved_audio), 0);
return adev;
}
/**
* dm_test_mode_config_init - Test the mode config and DM private object are set up
* @test: The KUnit test context
*/
static void dm_test_mode_config_init(struct kunit *test)
{
struct amdgpu_device *adev = dm_test_mode_config_adev(test);
struct dm_atomic_state *dm_state;
KUNIT_ASSERT_EQ(test, amdgpu_dm_mode_config_init(adev), 0);
KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_fini_atomic_obj,
&adev->dm.atomic_obj), 0);
KUNIT_EXPECT_TRUE(test, adev->mode_info.mode_config_initialized);
KUNIT_EXPECT_EQ(test, adev->ddev.mode_config.max_width, 16384);
KUNIT_EXPECT_EQ(test, adev->ddev.mode_config.max_height, 16384);
KUNIT_EXPECT_EQ(test, adev->ddev.mode_config.preferred_depth, 24);
KUNIT_EXPECT_EQ(test, adev->ddev.mode_config.prefer_shadow, 1);
KUNIT_EXPECT_TRUE(test, adev->ddev.mode_config.async_page_flip);
/* drm_atomic_private_obj_init() creates the state through DM. */
dm_state = to_dm_atomic_state(adev->dm.atomic_obj.state);
KUNIT_ASSERT_NOT_NULL(test, dm_state);
KUNIT_EXPECT_NOT_NULL(test, dm_state->context);
}
/**
* dm_test_mode_config_init_hawaii - Test Hawaii disables the preferred shadow
* @test: The KUnit test context
*/
static void dm_test_mode_config_init_hawaii(struct kunit *test)
{
struct amdgpu_device *adev = dm_test_mode_config_adev(test);
adev->asic_type = CHIP_HAWAII;
KUNIT_ASSERT_EQ(test, amdgpu_dm_mode_config_init(adev), 0);
KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_fini_atomic_obj,
&adev->dm.atomic_obj), 0);
KUNIT_EXPECT_EQ(test, adev->ddev.mode_config.prefer_shadow, 0);
}
/* Tests for initialize_plane() */
/**
* dm_test_initialize_plane_primary - Test a primary plane is stored in mode info
* @test: The KUnit test context
*/
static void dm_test_initialize_plane_primary(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
struct amdgpu_mode_info *mode_info = &adev->mode_info;
adev->family = AMDGPU_FAMILY_NV;
adev->dm.adev = adev;
adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
adev->dm.dc->caps.max_streams = 1;
KUNIT_ASSERT_EQ(test, initialize_plane(&adev->dm, mode_info, 0,
DRM_PLANE_TYPE_PRIMARY, NULL), 0);
KUNIT_ASSERT_NOT_NULL(test, mode_info->planes[0]);
KUNIT_EXPECT_EQ(test, (int)mode_info->planes[0]->type,
(int)DRM_PLANE_TYPE_PRIMARY);
KUNIT_EXPECT_EQ(test, mode_info->planes[0]->possible_crtcs, 1U);
}
/**
* dm_test_initialize_plane_overlay - Test an overlay plane can target any CRTC
* @test: The KUnit test context
*/
static void dm_test_initialize_plane_overlay(struct kunit *test)
{
struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
struct dc_plane_cap *plane_cap;
plane_cap = kunit_kzalloc(test, sizeof(*plane_cap), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, plane_cap);
adev->family = AMDGPU_FAMILY_NV;
adev->dm.adev = adev;
adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
adev->dm.dc->caps.max_streams = 1;
plane_cap->per_pixel_alpha = true;
plane_cap->pixel_format_support.nv12 = true;
/* Plane id at or above max_streams is never a primary, so any CRTC works. */
KUNIT_ASSERT_EQ(test, initialize_plane(&adev->dm, NULL, 1,
DRM_PLANE_TYPE_OVERLAY, plane_cap), 0);
}
static struct kunit_case amdgpu_dm_tests[] = {
/* Simple DM callbacks */
KUNIT_CASE(dm_test_wait_for_idle),
@ -3978,6 +4104,12 @@ static struct kunit_case amdgpu_dm_tests[] = {
KUNIT_CASE(dm_test_late_init_no_dmcu),
KUNIT_CASE(dm_test_late_init_boot_crc_no_dmub),
KUNIT_CASE(dm_test_late_init_boot_crc_disabled),
/* amdgpu_dm_mode_config_init */
KUNIT_CASE(dm_test_mode_config_init),
KUNIT_CASE(dm_test_mode_config_init_hawaii),
/* initialize_plane */
KUNIT_CASE(dm_test_initialize_plane_primary),
KUNIT_CASE(dm_test_initialize_plane_overlay),
{}
};