[PATCH 52/59] drm/amd/display: Test DM early init

Alex Hung <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
[WHAT]
Add KUnit tests for dm_early_init(), covering the display counts of the
legacy ASICs and the DCN IP versions, a BIOS without an object header,
and an unsupported IP version.

[HOW]
Add a fake ATOM BIOS image whose master data table reports a present
entry, which is all amdgpu_atom_parse_data_header() checks here. Only IP
versions without DMUB firmware are used, so dm_init_microcode() does not
reach a firmware request.

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 |   5 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   1 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 168 ++++++++++++++++++
 3 files changed, 172 insertions(+), 2 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 cd9f44326ae3..0ac4711b62e7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -307,7 +307,7 @@ STATIC_IFN_KUNIT int dm_set_powergating_state(struct amdgpu_ip_block *ip_block,
 EXPORT_IF_KUNIT(dm_set_powergating_state);
 
 /* Prototypes of private functions */
-static int dm_early_init(struct amdgpu_ip_block *ip_block);
+STATIC_IFN_KUNIT int dm_early_init(struct amdgpu_ip_block *ip_block);
 
 #if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
 static const struct amdgpu_dm_kunit_ops amdgpu_dm_default_ops = {
@@ -2751,7 +2751,7 @@ DEVICE_ATTR_WO(s3_debug);
 
 #endif
 
-static int dm_early_init(struct amdgpu_ip_block *ip_block)
+STATIC_IFN_KUNIT int dm_early_init(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
@@ -2901,6 +2901,7 @@ static int dm_early_init(struct amdgpu_ip_block *ip_block)
 
 	return dm_init_microcode(adev);
 }
+EXPORT_IF_KUNIT(dm_early_init);
 
 STATIC_IFN_KUNIT bool modereset_required(struct drm_crtc_state *crtc_state)
 {
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 19c6b29947f6..88fa4292c5cf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1254,6 +1254,7 @@ struct dc_plane_cap;
 void mmhub_read_system_context(struct amdgpu_device *adev,
 			       struct dc_phy_addr_space_config *pa_config);
 int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm);
+int dm_early_init(struct amdgpu_ip_block *ip_block);
 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);
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 58472b4d5388..7d0b5d8f06a1 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
@@ -30,6 +30,7 @@
 #include "amd_shared.h"
 #include "amdgpu.h"
 #include "amdgpu_mode.h"
+#include "atom.h"
 #include "amdgpu_dm.h"
 #include "amdgpu_dm_audio.h"
 #include "amdgpu_dm_hdcp.h"
@@ -3562,6 +3563,168 @@ static void dm_test_init_power_module_alloc_failure(struct kunit *test)
 	KUNIT_EXPECT_NULL(test, adev->dm.power_module);
 }
 
+/* Tests for dm_early_init() */
+
+#define DM_TEST_ATOM_BIOS_SIZE	512
+
+/*
+ * A fake ATOM BIOS image. Every byte is non-zero, so the master data table
+ * reports a present entry for whichever index the object header lives at,
+ * which is all amdgpu_atom_parse_data_header() checks here.
+ */
+static struct atom_context *dm_test_alloc_atom_context(struct kunit *test,
+						       bool object_header)
+{
+	struct atom_context *ctx;
+	void *bios;
+
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx);
+	bios = kunit_kzalloc(test, DM_TEST_ATOM_BIOS_SIZE, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, bios);
+
+	if (object_header)
+		memset(bios, 0x01, DM_TEST_ATOM_BIOS_SIZE);
+
+	ctx->bios = bios;
+	ctx->bios_size = DM_TEST_ATOM_BIOS_SIZE;
+	ctx->data_table = 0;
+
+	return ctx;
+}
+
+static struct amdgpu_device *dm_test_early_init_adev(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+	adev->mode_info.atom_context = dm_test_alloc_atom_context(test, true);
+
+	return adev;
+}
+
+static int dm_test_run_early_init(struct amdgpu_device *adev)
+{
+	struct amdgpu_ip_block ip_block = { .adev = adev };
+
+	return dm_early_init(&ip_block);
+}
+
+/**
+ * dm_test_early_init_no_object_header - Test a BIOS without an object header
+ * @test: The KUnit test context
+ */
+static void dm_test_early_init_no_object_header(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+	adev->mode_info.atom_context = dm_test_alloc_atom_context(test, false);
+
+	KUNIT_EXPECT_EQ(test, dm_test_run_early_init(adev), -ENOENT);
+	KUNIT_EXPECT_TRUE(test, adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK);
+	KUNIT_EXPECT_FALSE(test, adev->dc_enabled);
+}
+
+/**
+ * dm_test_early_init_legacy_asics - Test the display counts of legacy ASICs
+ * @test: The KUnit test context
+ */
+static void dm_test_early_init_legacy_asics(struct kunit *test)
+{
+	static const struct {
+		enum amd_asic_type asic_type;
+		u32 num_crtc;
+		u32 num_hpd;
+		u32 num_dig;
+	} cases[] = {
+		{ CHIP_BONAIRE, 6, 6, 6 },
+		{ CHIP_HAWAII, 6, 6, 6 },
+		{ CHIP_KAVERI, 4, 6, 7 },
+		{ CHIP_KABINI, 2, 6, 6 },
+		{ CHIP_MULLINS, 2, 6, 6 },
+		{ CHIP_FIJI, 6, 6, 7 },
+		{ CHIP_TONGA, 6, 6, 7 },
+		{ CHIP_CARRIZO, 3, 6, 9 },
+		{ CHIP_STONEY, 2, 6, 9 },
+		{ CHIP_POLARIS11, 5, 5, 5 },
+		{ CHIP_POLARIS12, 5, 5, 5 },
+		{ CHIP_POLARIS10, 6, 6, 6 },
+		{ CHIP_VEGAM, 6, 6, 6 },
+		{ CHIP_VEGA10, 6, 6, 6 },
+		{ CHIP_VEGA12, 6, 6, 6 },
+		{ CHIP_VEGA20, 6, 6, 6 },
+	};
+	struct amdgpu_device *adev = dm_test_early_init_adev(test);
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(cases); i++) {
+		adev->asic_type = cases[i].asic_type;
+
+		KUNIT_EXPECT_EQ_MSG(test, dm_test_run_early_init(adev), 0,
+				    "asic_type %d", cases[i].asic_type);
+		KUNIT_EXPECT_EQ_MSG(test, adev->mode_info.num_crtc, cases[i].num_crtc,
+				    "asic_type %d", cases[i].asic_type);
+		KUNIT_EXPECT_EQ_MSG(test, adev->mode_info.num_hpd, cases[i].num_hpd,
+				    "asic_type %d", cases[i].asic_type);
+		KUNIT_EXPECT_EQ_MSG(test, adev->mode_info.num_dig, cases[i].num_dig,
+				    "asic_type %d", cases[i].asic_type);
+	}
+
+	KUNIT_EXPECT_NOT_NULL(test, adev->mode_info.funcs);
+	KUNIT_EXPECT_TRUE(test, adev->dc_enabled);
+}
+
+/**
+ * dm_test_early_init_dcn_versions - Test the display counts of DCN IP versions
+ * @test: The KUnit test context
+ *
+ * Only IP versions without DMUB firmware are used, so dm_init_microcode() does
+ * not reach a firmware request.
+ */
+static void dm_test_early_init_dcn_versions(struct kunit *test)
+{
+	static const struct {
+		u32 ip_version;
+		u32 num_crtc;
+	} cases[] = {
+		{ IP_VERSION(2, 0, 2), 6 },
+		{ IP_VERSION(2, 0, 0), 5 },
+		{ IP_VERSION(2, 0, 3), 2 },
+		{ IP_VERSION(1, 0, 0), 4 },
+		{ IP_VERSION(1, 0, 1), 4 },
+	};
+	struct amdgpu_device *adev = dm_test_early_init_adev(test);
+	unsigned int i;
+
+	adev->asic_type = CHIP_IP_DISCOVERY;
+
+	for (i = 0; i < ARRAY_SIZE(cases); i++) {
+		adev->ip_versions[DCE_HWIP][0] = cases[i].ip_version;
+
+		KUNIT_EXPECT_EQ_MSG(test, dm_test_run_early_init(adev), 0,
+				    "ip_version 0x%x", cases[i].ip_version);
+		KUNIT_EXPECT_EQ_MSG(test, adev->mode_info.num_crtc, cases[i].num_crtc,
+				    "ip_version 0x%x", cases[i].ip_version);
+		/* Every DCN entry keeps hpd and dig in step with the CRTC count. */
+		KUNIT_EXPECT_EQ(test, adev->mode_info.num_hpd, cases[i].num_crtc);
+		KUNIT_EXPECT_EQ(test, adev->mode_info.num_dig, cases[i].num_crtc);
+	}
+}
+
+/**
+ * dm_test_early_init_unsupported_version - Test an unknown IP version is rejected
+ * @test: The KUnit test context
+ */
+static void dm_test_early_init_unsupported_version(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_test_early_init_adev(test);
+
+	adev->asic_type = CHIP_IP_DISCOVERY;
+	adev->ip_versions[DCE_HWIP][0] = IP_VERSION(9, 9, 9);
+
+	KUNIT_EXPECT_EQ(test, dm_test_run_early_init(adev), -EINVAL);
+	KUNIT_EXPECT_FALSE(test, adev->dc_enabled);
+}
+
 /* Tests for load_dmcu_fw() */
 
 /**
@@ -4091,6 +4254,11 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	/* amdgpu_dm_init_power_module */
 	KUNIT_CASE(dm_test_init_power_module_no_edp),
 	KUNIT_CASE(dm_test_init_power_module_alloc_failure),
+	/* dm_early_init */
+	KUNIT_CASE(dm_test_early_init_no_object_header),
+	KUNIT_CASE(dm_test_early_init_legacy_asics),
+	KUNIT_CASE(dm_test_early_init_dcn_versions),
+	KUNIT_CASE(dm_test_early_init_unsupported_version),
 	/* load_dmcu_fw */
 	KUNIT_CASE(dm_test_load_dmcu_fw_no_dmcu),
 	KUNIT_CASE(dm_test_load_dmcu_fw_dcn),
-- 
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.