[PATCH 51/59] drm/amd/display: Test mode and plane init

Alex Hung <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.