[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 <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  12 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   5 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 132 ++++++++++++++++++
 3 files changed, 144 insertions(+), 5 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 0393ec122f26..cd9f44326ae3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -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);
 
 
 /*
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 c662c39416d8..19c6b29947f6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -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__ */
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 432e4cd2803d..58472b4d5388 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
@@ -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),
        {}
 };
 
-- 
2.43.0

Reply via email to