From: Alex Hung <[email protected]>

Add amdgpu_dm_helpers_test.c with 32 KUnit test cases covering the
following functions in amdgpu_dm_helpers.c:

- edid_extract_panel_id(): basic extraction with known mfg_id and
  prod_code; zero inputs produce zero output.
- dm_is_freesync_pcon_whitelist(): every entry in the whitelist
  table returns true; an unknown ID and a zero ID return false.
- populate_hdmi_info_from_connector(): scdc_present is copied from
  hdmi->scdc.supported for both true and false; FRL DSC fields map
  10bpc and 12bpc correctly and ignore unknown values.
- dm_get_adaptive_sync_support_type(): five cases covering the
  default non-converter path, HDMI converter without conditions,
  partial conditions, all conditions met with a whitelist device
  (FREESYNC_TYPE_PCON_IN_WHITELIST), and all conditions met with a
  non-whitelisted device.
- dm_helpers_is_fullscreen() / dm_helpers_is_hdr_on(): stubs always
  return false.
- get_max_frl_rate(): all six valid lane/rate combinations plus the
  unknown combination returning 0.
- dm_dtn_log_begin()/dm_dtn_log_append_v()/dm_dtn_log_end(): buffer
  accumulation and NULL-context handling without crashing.
- dm_helpers_dp_read_dpcd()/dm_helpers_dp_write_dpcd(): NULL link
  private data returns false.
- dm_helpers_dp_mst_start_top_mgr()/dm_helpers_dp_mst_stop_top_mgr():
  NULL link private data and the boot path.
- dm_helpers_dp_write_hblank_reduction(): stub returns false.

Assisted-by: Copilot:Claude-Opus-4.8

Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Chenyu Chen <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |  58 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.h |  20 +
 .../drm/amd/display/amdgpu_dm/tests/Makefile  |   1 +
 .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c  | 645 ++++++++++++++++++
 4 files changed, 707 insertions(+), 17 deletions(-)
 create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h
 create mode 100644 
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 6350212b9a66..9c4e0a4e251c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -48,6 +48,8 @@
 #include "dm_helpers.h"
 #include "ddc_service_types.h"
 #include "clk_mgr.h"
+#include "amdgpu_dm_kunit_helpers.h"
+#include "amdgpu_dm_helpers.h"
 
 #define MCCS_DEST_ADDR (0x6E >> 1)
 #define MCCS_SRC_ADDR  0x51
@@ -88,12 +90,13 @@ union vcp_reply {
        unsigned char raw[11];
 };
 
-static u32 edid_extract_panel_id(struct edid *edid)
+STATIC_IFN_KUNIT u32 edid_extract_panel_id(struct edid *edid)
 {
        return (u32)edid->mfg_id[0] << 24   |
               (u32)edid->mfg_id[1] << 16   |
               (u32)EDID_PRODUCT_ID(edid);
 }
+EXPORT_IF_KUNIT(edid_extract_panel_id);
 
 static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
                              struct dc_edid_caps *edid_caps)
@@ -495,6 +498,7 @@ void dm_dtn_log_begin(struct dc_context *ctx,
 
        dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
 }
+EXPORT_IF_KUNIT(dm_dtn_log_begin);
 
 __printf(3, 4)
 void dm_dtn_log_append_v(struct dc_context *ctx,
@@ -557,6 +561,7 @@ void dm_dtn_log_append_v(struct dc_context *ctx,
        if (n > 0)
                log_ctx->pos += n;
 }
+EXPORT_IF_KUNIT(dm_dtn_log_append_v);
 
 void dm_dtn_log_end(struct dc_context *ctx,
        struct dc_log_buffer_ctx *log_ctx)
@@ -570,6 +575,7 @@ void dm_dtn_log_end(struct dc_context *ctx,
 
        dm_dtn_log_append_v(ctx, log_ctx, "%s", msg);
 }
+EXPORT_IF_KUNIT(dm_dtn_log_end);
 
 bool dm_helpers_dp_mst_start_top_mgr(
                struct dc_context *ctx,
@@ -604,6 +610,7 @@ bool dm_helpers_dp_mst_start_top_mgr(
 
        return true;
 }
+EXPORT_IF_KUNIT(dm_helpers_dp_mst_start_top_mgr);
 
 bool dm_helpers_dp_mst_stop_top_mgr(
                struct dc_context *ctx,
@@ -626,6 +633,7 @@ bool dm_helpers_dp_mst_stop_top_mgr(
 
        return false;
 }
+EXPORT_IF_KUNIT(dm_helpers_dp_mst_stop_top_mgr);
 
 bool dm_helpers_dp_read_dpcd(
                struct dc_context *ctx,
@@ -643,6 +651,7 @@ bool dm_helpers_dp_read_dpcd(
        return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address, data,
                                size) == size;
 }
+EXPORT_IF_KUNIT(dm_helpers_dp_read_dpcd);
 
 bool dm_helpers_dp_write_dpcd(
                struct dc_context *ctx,
@@ -659,6 +668,7 @@ bool dm_helpers_dp_write_dpcd(
        return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux,
                        address, (uint8_t *)data, size) > 0;
 }
+EXPORT_IF_KUNIT(dm_helpers_dp_write_dpcd);
 
 bool dm_helpers_submit_i2c(
                struct dc_context *ctx,
@@ -974,6 +984,7 @@ bool dm_helpers_dp_write_hblank_reduction(struct dc_context 
*ctx, const struct d
        // TODO
        return false;
 }
+EXPORT_IF_KUNIT(dm_helpers_dp_write_hblank_reduction);
 
 bool dm_helpers_is_dp_sink_present(struct dc_link *link)
 {
@@ -1091,7 +1102,7 @@ dm_helpers_read_vbios_hardcoded_edid(struct dc_link 
*link, struct amdgpu_dm_conn
        return edid;
 }
 
-static uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane)
+STATIC_IFN_KUNIT uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t 
max_rate_per_lane)
 {
        uint8_t max_frl_rate;
 
@@ -1112,6 +1123,7 @@ static uint8_t get_max_frl_rate(uint8_t max_lanes, 
uint8_t max_rate_per_lane)
 
        return max_frl_rate;
 }
+EXPORT_IF_KUNIT(get_max_frl_rate);
 
 static uint8_t get_dsc_max_slices(uint8_t max_slices, int clk_per_slice)
 {
@@ -1156,6 +1168,7 @@ void populate_hdmi_info_from_connector(bool enable_frl, 
struct drm_hdmi_info *hd
                }
        }
 }
+EXPORT_IF_KUNIT(populate_hdmi_info_from_connector);
 
 enum dc_edid_status dm_helpers_read_local_edid(
                struct dc_context *ctx,
@@ -1556,24 +1569,32 @@ void dm_helpers_dp_mst_update_branch_bandwidth(
        // TODO
 }
 
-static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id)
+STATIC_IFN_KUNIT const uint32_t dm_freesync_pcon_whitelist[] = {
+       DP_BRANCH_DEVICE_ID_0060AD,
+       DP_BRANCH_DEVICE_ID_00E04C,
+       DP_BRANCH_DEVICE_ID_90CC24,
+       DP_BRANCH_DEVICE_ID_001CF8,
+       DP_BRANCH_DEVICE_ID_001FF2,
+};
+EXPORT_IF_KUNIT(dm_freesync_pcon_whitelist);
+
+STATIC_IFN_KUNIT uint32_t dm_freesync_pcon_whitelist_count(void)
 {
-       bool ret_val = false;
-
-       switch (branch_dev_id) {
-       case DP_BRANCH_DEVICE_ID_0060AD:
-       case DP_BRANCH_DEVICE_ID_00E04C:
-       case DP_BRANCH_DEVICE_ID_90CC24:
-       case DP_BRANCH_DEVICE_ID_001CF8:
-       case DP_BRANCH_DEVICE_ID_001FF2:
-               ret_val = true;
-               break;
-       default:
-               break;
-       }
+       return ARRAY_SIZE(dm_freesync_pcon_whitelist);
+}
+EXPORT_IF_KUNIT(dm_freesync_pcon_whitelist_count);
+
+STATIC_IFN_KUNIT bool dm_is_freesync_pcon_whitelist(const uint32_t 
branch_dev_id)
+{
+       u32 i;
 
-       return ret_val;
+       for (i = 0; i < dm_freesync_pcon_whitelist_count(); i++)
+               if (dm_freesync_pcon_whitelist[i] == branch_dev_id)
+                       return true;
+
+       return false;
 }
+EXPORT_IF_KUNIT(dm_is_freesync_pcon_whitelist);
 
 enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link)
 {
@@ -1593,18 +1614,21 @@ enum adaptive_sync_type 
dm_get_adaptive_sync_support_type(struct dc_link *link)
 
        return as_type;
 }
+EXPORT_IF_KUNIT(dm_get_adaptive_sync_support_type);
 
 bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state 
*stream)
 {
        // TODO
        return false;
 }
+EXPORT_IF_KUNIT(dm_helpers_is_fullscreen);
 
 bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state 
*stream)
 {
        // TODO
        return false;
 }
+EXPORT_IF_KUNIT(dm_helpers_is_hdr_on);
 
 static int mccs_operation_vcp_request(unsigned int vcp_code, struct dc_link 
*link,
                                union vcp_reply *reply)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h
new file mode 100644
index 000000000000..2ac9762895ec
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef __AMDGPU_DM_HELPERS_H__
+#define __AMDGPU_DM_HELPERS_H__
+
+#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+#include <drm/drm_edid.h>
+
+/* Exported for KUnit testing */
+u32 edid_extract_panel_id(struct edid *edid);
+uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane);
+bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id);
+extern const uint32_t dm_freesync_pcon_whitelist[];
+uint32_t dm_freesync_pcon_whitelist_count(void);
+#endif /* CONFIG_DRM_AMD_DC_KUNIT_TEST */
+
+#endif /* __AMDGPU_DM_HELPERS_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
index 364b4f3c783f..a067332f9f41 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_pp_smu_test.o
 obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_test.o
 obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crtc_test.o
 obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_services_test.o
+obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_helpers_test.o
diff --git 
a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
new file mode 100644
index 000000000000..14004ff87c9b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * KUnit tests for amdgpu_dm_helpers.c
+ *
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <kunit/test.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_kunit_helpers.h>
+
+#include "dc.h"
+#include "amdgpu.h"
+#include "amdgpu_mode.h"
+#include "amdgpu_dm.h"
+#include "dm_helpers.h"
+#include "ddc_service_types.h"
+#include "amdgpu_dm_helpers.h"
+
+/* Tests for edid_extract_panel_id() */
+
+/**
+ * dm_test_edid_extract_panel_id_basic - Test Edid extract panel id basic
+ * @test: The KUnit test context
+ */
+static void dm_test_edid_extract_panel_id_basic(struct kunit *test)
+{
+       struct edid *edid;
+       u32 panel_id;
+
+       edid = kunit_kzalloc(test, sizeof(*edid), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, edid);
+
+       edid->mfg_id[0] = 0x12;
+       edid->mfg_id[1] = 0x34;
+       edid->prod_code[0] = 0xAB;
+       edid->prod_code[1] = 0xCD;
+
+       panel_id = edid_extract_panel_id(edid);
+
+       /*
+        * Expected: (0x12 << 24) | (0x34 << 16) | EDID_PRODUCT_ID(edid)
+        * EDID_PRODUCT_ID = prod_code[0] | (prod_code[1] << 8) = 0xAB | 0xCD00 
= 0xCDAB
+        * Result: 0x12340000 | 0x0000CDAB = 0x1234CDAB
+        */
+       KUNIT_EXPECT_EQ(test, panel_id, (u32)0x1234CDAB);
+}
+
+/**
+ * dm_test_edid_extract_panel_id_zeros - Test Edid extract panel id zeros
+ * @test: The KUnit test context
+ */
+static void dm_test_edid_extract_panel_id_zeros(struct kunit *test)
+{
+       struct edid *edid;
+
+       edid = kunit_kzalloc(test, sizeof(*edid), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, edid);
+
+       KUNIT_EXPECT_EQ(test, edid_extract_panel_id(edid), 0U);
+}
+
+/* Tests for dm_is_freesync_pcon_whitelist() */
+
+/**
+ * dm_test_freesync_pcon_whitelist_all_known - Test all known Freesync Pcon 
whitelist entries
+ * @test: The KUnit test context
+ *
+ * Iterates over the driver's whitelist table directly so that any ID added
+ * to dm_freesync_pcon_whitelist[] is automatically covered by this test.
+ */
+static void dm_test_freesync_pcon_whitelist_all_known(struct kunit *test)
+{
+       u32 i;
+
+       for (i = 0; i < dm_freesync_pcon_whitelist_count(); i++)
+               KUNIT_EXPECT_TRUE(test,
+                                 
dm_is_freesync_pcon_whitelist(dm_freesync_pcon_whitelist[i]));
+}
+
+/**
+ * dm_test_freesync_pcon_whitelist_not_in_list - Test Freesync pcon whitelist 
not in list
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_pcon_whitelist_not_in_list(struct kunit *test)
+{
+       /* 0xFFFFFF is not a known whitelist device */
+       KUNIT_EXPECT_FALSE(test, dm_is_freesync_pcon_whitelist(0xFFFFFF));
+}
+
+/**
+ * dm_test_freesync_pcon_whitelist_zero - Test Freesync pcon whitelist zero
+ * @test: The KUnit test context
+ */
+static void dm_test_freesync_pcon_whitelist_zero(struct kunit *test)
+{
+       KUNIT_EXPECT_FALSE(test, dm_is_freesync_pcon_whitelist(0));
+}
+
+/* Tests for populate_hdmi_info_from_connector() */
+
+/**
+ * dm_test_populate_hdmi_scdc_present_true - Test Populate hdmi scdc present 
true
+ * @test: The KUnit test context
+ */
+static void dm_test_populate_hdmi_scdc_present_true(struct kunit *test)
+{
+       struct drm_hdmi_info *hdmi;
+       struct dc_edid_caps *caps;
+
+       hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, hdmi);
+       caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, caps);
+
+       hdmi->scdc.supported = true;
+
+       populate_hdmi_info_from_connector(true, hdmi, caps);
+
+       KUNIT_EXPECT_TRUE(test, caps->scdc_present);
+}
+
+/**
+ * dm_test_populate_hdmi_scdc_present_false - Test Populate hdmi scdc present 
false
+ * @test: The KUnit test context
+ */
+static void dm_test_populate_hdmi_scdc_present_false(struct kunit *test)
+{
+       struct drm_hdmi_info *hdmi;
+       struct dc_edid_caps *caps;
+
+       hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, hdmi);
+       caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, caps);
+
+       hdmi->scdc.supported = false;
+       caps->scdc_present = true; /* pre-set to confirm it gets cleared */
+
+       populate_hdmi_info_from_connector(true, hdmi, caps);
+
+       KUNIT_EXPECT_FALSE(test, caps->scdc_present);
+}
+
+/**
+ * dm_test_populate_hdmi_frl_dsc_10bpc - Test HDMI FRL DSC 10 bpc caps
+ * @test: The KUnit test context
+ */
+static void dm_test_populate_hdmi_frl_dsc_10bpc(struct kunit *test)
+{
+       struct drm_hdmi_info *hdmi;
+       struct dc_edid_caps *caps;
+
+       hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, hdmi);
+       caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, caps);
+
+       hdmi->max_lanes = 4;
+       hdmi->max_frl_rate_per_lane = 12;
+       hdmi->dsc_cap.v_1p2 = true;
+       hdmi->dsc_cap.bpc_supported = 10;
+       hdmi->dsc_cap.all_bpp = true;
+       hdmi->dsc_cap.native_420 = true;
+       hdmi->dsc_cap.max_slices = 8;
+       hdmi->dsc_cap.clk_per_slice = 400;
+       hdmi->dsc_cap.max_lanes = 4;
+       hdmi->dsc_cap.max_frl_rate_per_lane = 10;
+       hdmi->dsc_cap.total_chunk_kbytes = 7;
+
+       populate_hdmi_info_from_connector(true, hdmi, caps);
+
+       KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 6);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_10bpc);
+       KUNIT_EXPECT_FALSE(test, caps->frl_dsc_12bpc);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_all_bpp);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_native_420);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 5);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 5);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_total_chunk_kbytes, 7);
+}
+
+/**
+ * dm_test_populate_hdmi_frl_dsc_12bpc - Test HDMI FRL DSC 12 bpc caps
+ * @test: The KUnit test context
+ */
+static void dm_test_populate_hdmi_frl_dsc_12bpc(struct kunit *test)
+{
+       struct drm_hdmi_info *hdmi;
+       struct dc_edid_caps *caps;
+
+       hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, hdmi);
+       caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, caps);
+
+       hdmi->max_lanes = 3;
+       hdmi->max_frl_rate_per_lane = 6;
+       hdmi->dsc_cap.v_1p2 = true;
+       hdmi->dsc_cap.bpc_supported = 12;
+       hdmi->dsc_cap.max_slices = 16;
+       hdmi->dsc_cap.clk_per_slice = 400;
+       hdmi->dsc_cap.max_lanes = 3;
+       hdmi->dsc_cap.max_frl_rate_per_lane = 3;
+
+       populate_hdmi_info_from_connector(true, hdmi, caps);
+
+       KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 2);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support);
+       KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_12bpc);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 7);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 1);
+}
+
+/**
+ * dm_test_populate_hdmi_frl_dsc_unknown_values - Test HDMI FRL DSC unknown 
values
+ * @test: The KUnit test context
+ */
+static void dm_test_populate_hdmi_frl_dsc_unknown_values(struct kunit *test)
+{
+       struct drm_hdmi_info *hdmi;
+       struct dc_edid_caps *caps;
+
+       hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, hdmi);
+       caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, caps);
+
+       hdmi->max_lanes = 2;
+       hdmi->max_frl_rate_per_lane = 3;
+       hdmi->dsc_cap.v_1p2 = true;
+       hdmi->dsc_cap.bpc_supported = 8;
+       hdmi->dsc_cap.max_slices = 3;
+       hdmi->dsc_cap.clk_per_slice = 340;
+       hdmi->dsc_cap.max_lanes = 2;
+       hdmi->dsc_cap.max_frl_rate_per_lane = 12;
+
+       populate_hdmi_info_from_connector(true, hdmi, caps);
+
+       KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 0);
+       KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support);
+       KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc);
+       KUNIT_EXPECT_FALSE(test, caps->frl_dsc_12bpc);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 0);
+       KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 0);
+}
+
+/* Tests for dm_get_adaptive_sync_support_type() */
+
+/**
+ * dm_test_adaptive_sync_type_none_default - Test Adaptive sync type none 
default
+ * @test: The KUnit test context
+ */
+static void dm_test_adaptive_sync_type_none_default(struct kunit *test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* dongle_type = 0 (DISPLAY_DONGLE_NONE) → default case → TYPE_NONE */
+       KUNIT_EXPECT_EQ(test,
+                       (int)dm_get_adaptive_sync_support_type(link),
+                       (int)ADAPTIVE_SYNC_TYPE_NONE);
+}
+
+/**
+ * dm_test_adaptive_sync_type_converter_no_conditions - Converter without caps
+ * @test: The KUnit test context
+ */
+static void dm_test_adaptive_sync_type_converter_no_conditions(struct kunit 
*test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* HDMI converter but no adaptive sync cap → still NONE */
+       link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+
+       KUNIT_EXPECT_EQ(test,
+                       (int)dm_get_adaptive_sync_support_type(link),
+                       (int)ADAPTIVE_SYNC_TYPE_NONE);
+}
+
+/**
+ * dm_test_adaptive_sync_type_converter_partial_conditions - Partial caps
+ * @test: The KUnit test context
+ */
+static void dm_test_adaptive_sync_type_converter_partial_conditions(struct 
kunit *test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* Cap set and whitelist ID, but allow_invalid_MSA_timing_param = false 
*/
+       link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+       
link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT
 = 1;
+       link->dpcd_caps.allow_invalid_MSA_timing_param = false;
+       link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_0060AD;
+
+       KUNIT_EXPECT_EQ(test,
+                       (int)dm_get_adaptive_sync_support_type(link),
+                       (int)ADAPTIVE_SYNC_TYPE_NONE);
+}
+
+/**
+ * dm_test_adaptive_sync_type_pcon_whitelist - Test Adaptive sync type pcon 
whitelist
+ * @test: The KUnit test context
+ */
+static void dm_test_adaptive_sync_type_pcon_whitelist(struct kunit *test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* All conditions met → FREESYNC_TYPE_PCON_IN_WHITELIST */
+       link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+       
link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT
 = 1;
+       link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+       link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_0060AD;
+
+       KUNIT_EXPECT_EQ(test,
+                       (int)dm_get_adaptive_sync_support_type(link),
+                       (int)FREESYNC_TYPE_PCON_IN_WHITELIST);
+}
+
+/**
+ * dm_test_adaptive_sync_type_converter_nonwhitelist - Converter not 
whitelisted
+ * @test: The KUnit test context
+ */
+static void dm_test_adaptive_sync_type_converter_nonwhitelist(struct kunit 
*test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* All conditions met but branch_dev_id not in whitelist → NONE */
+       link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+       
link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT
 = 1;
+       link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+       link->dpcd_caps.branch_dev_id = 0xFFFFFF;
+
+       KUNIT_EXPECT_EQ(test,
+                       (int)dm_get_adaptive_sync_support_type(link),
+                       (int)ADAPTIVE_SYNC_TYPE_NONE);
+}
+
+/* Tests for dm_helpers_is_fullscreen() and dm_helpers_is_hdr_on() */
+
+/**
+ * dm_test_helpers_is_fullscreen_returns_false - Test Helpers is fullscreen 
returns false
+ * @test: The KUnit test context
+ */
+static void dm_test_helpers_is_fullscreen_returns_false(struct kunit *test)
+{
+       /* Stub — always returns false */
+       KUNIT_EXPECT_FALSE(test, dm_helpers_is_fullscreen(NULL, NULL));
+}
+
+/**
+ * dm_test_helpers_is_hdr_on_returns_false - Test Helpers is hdr on returns 
false
+ * @test: The KUnit test context
+ */
+static void dm_test_helpers_is_hdr_on_returns_false(struct kunit *test)
+{
+       /* Stub — always returns false */
+       KUNIT_EXPECT_FALSE(test, dm_helpers_is_hdr_on(NULL, NULL));
+}
+
+/* Tests for get_max_frl_rate() */
+
+/**
+ * dm_test_get_max_frl_rate_3lanes_3gbps - Test Get max frl rate 3lanes 3gbps
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_3lanes_3gbps(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(3, 3), 1);
+}
+
+/**
+ * dm_test_get_max_frl_rate_3lanes_6gbps - Test Get max frl rate 3lanes 6gbps
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_3lanes_6gbps(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(3, 6), 2);
+}
+
+/**
+ * dm_test_get_max_frl_rate_4lanes_6gbps - Test Get max frl rate 4lanes 6gbps
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_4lanes_6gbps(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 6), 3);
+}
+
+/**
+ * dm_test_get_max_frl_rate_4lanes_8gbps - Test Get max frl rate 4lanes 8gbps
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_4lanes_8gbps(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 8), 4);
+}
+
+/**
+ * dm_test_get_max_frl_rate_4lanes_10gbps - Test Get max frl rate 4lanes 10gbps
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_4lanes_10gbps(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 10), 5);
+}
+
+/**
+ * dm_test_get_max_frl_rate_4lanes_12gbps - Test Get max frl rate 4lanes 12gbps
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_4lanes_12gbps(struct kunit *test)
+{
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 12), 6);
+}
+
+/**
+ * dm_test_get_max_frl_rate_unknown - Test Get max frl rate unknown
+ * @test: The KUnit test context
+ */
+static void dm_test_get_max_frl_rate_unknown(struct kunit *test)
+{
+       /* Unknown lane/rate combination → 0 */
+       KUNIT_EXPECT_EQ(test, get_max_frl_rate(2, 3), 0);
+}
+
+/* Tests for dm_dtn_log_begin() / dm_dtn_log_append_v() / dm_dtn_log_end() */
+
+/**
+ * dm_test_dtn_log_buffer_accumulates - Test DTN log buffer accumulation
+ * @test: The KUnit test context
+ */
+static void dm_test_dtn_log_buffer_accumulates(struct kunit *test)
+{
+       struct dc_log_buffer_ctx log_ctx = {0};
+
+       dm_dtn_log_begin(NULL, &log_ctx);
+       dm_dtn_log_append_v(NULL, &log_ctx, "x=%d\n", 7);
+       dm_dtn_log_end(NULL, &log_ctx);
+
+       KUNIT_ASSERT_NOT_NULL(test, log_ctx.buf);
+       KUNIT_EXPECT_STREQ(test, log_ctx.buf, "[dtn begin]\nx=7\n[dtn end]\n");
+       KUNIT_EXPECT_EQ(test, log_ctx.pos, strlen("[dtn begin]\nx=7\n[dtn 
end]\n"));
+
+       kvfree(log_ctx.buf);
+}
+
+/**
+ * dm_test_dtn_log_null_ctx_no_crash - Test DTN log helpers with NULL log 
buffer
+ * @test: The KUnit test context
+ */
+static void dm_test_dtn_log_null_ctx_no_crash(struct kunit *test)
+{
+       /* NULL log_ctx redirects to dmesg and must not dereference a buffer */
+       dm_dtn_log_begin(NULL, NULL);
+       dm_dtn_log_append_v(NULL, NULL, "value %d\n", 1);
+       dm_dtn_log_end(NULL, NULL);
+
+       KUNIT_EXPECT_TRUE(test, true);
+}
+
+/* Tests for dm_helpers_dp_read_dpcd() / dm_helpers_dp_write_dpcd() */
+
+/**
+ * dm_test_dp_read_dpcd_null_priv - Test DPCD read returns false without 
connector
+ * @test: The KUnit test context
+ */
+static void dm_test_dp_read_dpcd_null_priv(struct kunit *test)
+{
+       struct dc_link *link;
+       uint8_t data = 0;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* link->priv (aconnector) is NULL → early return false */
+       KUNIT_EXPECT_FALSE(test,
+                          dm_helpers_dp_read_dpcd(NULL, link, 0, &data, 
sizeof(data)));
+}
+
+/**
+ * dm_test_dp_write_dpcd_null_priv - Test DPCD write returns false without 
connector
+ * @test: The KUnit test context
+ */
+static void dm_test_dp_write_dpcd_null_priv(struct kunit *test)
+{
+       struct dc_link *link;
+       uint8_t data = 0;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       /* link->priv (aconnector) is NULL → early return false */
+       KUNIT_EXPECT_FALSE(test,
+                          dm_helpers_dp_write_dpcd(NULL, link, 0, &data, 
sizeof(data)));
+}
+
+/* Tests for dm_helpers_dp_mst_start_top_mgr() / 
dm_helpers_dp_mst_stop_top_mgr() */
+
+/**
+ * dm_test_mst_start_top_mgr_null_priv - Test MST start returns false without 
connector
+ * @test: The KUnit test context
+ */
+static void dm_test_mst_start_top_mgr_null_priv(struct kunit *test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       KUNIT_EXPECT_FALSE(test, dm_helpers_dp_mst_start_top_mgr(NULL, link, 
false));
+}
+
+/**
+ * dm_test_mst_stop_top_mgr_null_priv - Test MST stop returns false without 
connector
+ * @test: The KUnit test context
+ */
+static void dm_test_mst_stop_top_mgr_null_priv(struct kunit *test)
+{
+       struct dc_link *link;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+
+       KUNIT_EXPECT_FALSE(test, dm_helpers_dp_mst_stop_top_mgr(NULL, link));
+}
+
+/**
+ * dm_test_mst_start_top_mgr_boot - Test MST start boot path on a 
connector-backed link
+ * @test: The KUnit test context
+ *
+ * Uses the DRM KUnit mock device to back the connector so the link is a
+ * realistic connector-backed link. The boot path short-circuits and returns
+ * true without touching the MST topology manager.
+ */
+static void dm_test_mst_start_top_mgr_boot(struct kunit *test)
+{
+       struct amdgpu_dm_connector *aconnector;
+       struct amdgpu_device *adev;
+       struct drm_device *drm;
+       struct device *dev;
+       struct dc_link *link;
+
+       dev = drm_kunit_helper_alloc_device(test);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+       drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+                                                 sizeof(*adev),
+                                                 offsetof(struct 
amdgpu_device, ddev),
+                                                 DRIVER_MODESET);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
+       adev = drm_to_adev(drm);
+
+       aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, aconnector);
+       aconnector->base.dev = drm;
+
+       link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, link);
+       link->priv = aconnector;
+
+       KUNIT_EXPECT_TRUE(test, dm_helpers_dp_mst_start_top_mgr(NULL, link, 
true));
+}
+
+/* Tests for dm_helpers_dp_write_hblank_reduction() */
+
+/**
+ * dm_test_dp_write_hblank_reduction_false - Test hblank reduction stub 
returns false
+ * @test: The KUnit test context
+ */
+static void dm_test_dp_write_hblank_reduction_false(struct kunit *test)
+{
+       KUNIT_EXPECT_FALSE(test, dm_helpers_dp_write_hblank_reduction(NULL, 
NULL));
+}
+
+static struct kunit_case amdgpu_dm_helpers_test_cases[] = {
+       /* edid_extract_panel_id */
+       KUNIT_CASE(dm_test_edid_extract_panel_id_basic),
+       KUNIT_CASE(dm_test_edid_extract_panel_id_zeros),
+       /* dm_is_freesync_pcon_whitelist */
+       KUNIT_CASE(dm_test_freesync_pcon_whitelist_all_known),
+       KUNIT_CASE(dm_test_freesync_pcon_whitelist_not_in_list),
+       KUNIT_CASE(dm_test_freesync_pcon_whitelist_zero),
+       /* populate_hdmi_info_from_connector */
+       KUNIT_CASE(dm_test_populate_hdmi_scdc_present_true),
+       KUNIT_CASE(dm_test_populate_hdmi_scdc_present_false),
+       KUNIT_CASE(dm_test_populate_hdmi_frl_dsc_10bpc),
+       KUNIT_CASE(dm_test_populate_hdmi_frl_dsc_12bpc),
+       KUNIT_CASE(dm_test_populate_hdmi_frl_dsc_unknown_values),
+       /* dm_get_adaptive_sync_support_type */
+       KUNIT_CASE(dm_test_adaptive_sync_type_none_default),
+       KUNIT_CASE(dm_test_adaptive_sync_type_converter_no_conditions),
+       KUNIT_CASE(dm_test_adaptive_sync_type_converter_partial_conditions),
+       KUNIT_CASE(dm_test_adaptive_sync_type_pcon_whitelist),
+       KUNIT_CASE(dm_test_adaptive_sync_type_converter_nonwhitelist),
+       /* dm_helpers_is_fullscreen / dm_helpers_is_hdr_on */
+       KUNIT_CASE(dm_test_helpers_is_fullscreen_returns_false),
+       KUNIT_CASE(dm_test_helpers_is_hdr_on_returns_false),
+       /* get_max_frl_rate */
+       KUNIT_CASE(dm_test_get_max_frl_rate_3lanes_3gbps),
+       KUNIT_CASE(dm_test_get_max_frl_rate_3lanes_6gbps),
+       KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_6gbps),
+       KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_8gbps),
+       KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_10gbps),
+       KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_12gbps),
+       KUNIT_CASE(dm_test_get_max_frl_rate_unknown),
+       /* dm_dtn_log_begin / dm_dtn_log_append_v / dm_dtn_log_end */
+       KUNIT_CASE(dm_test_dtn_log_buffer_accumulates),
+       KUNIT_CASE(dm_test_dtn_log_null_ctx_no_crash),
+       /* dm_helpers_dp_read_dpcd / dm_helpers_dp_write_dpcd */
+       KUNIT_CASE(dm_test_dp_read_dpcd_null_priv),
+       KUNIT_CASE(dm_test_dp_write_dpcd_null_priv),
+       /* dm_helpers_dp_mst_start_top_mgr / dm_helpers_dp_mst_stop_top_mgr */
+       KUNIT_CASE(dm_test_mst_start_top_mgr_null_priv),
+       KUNIT_CASE(dm_test_mst_stop_top_mgr_null_priv),
+       KUNIT_CASE(dm_test_mst_start_top_mgr_boot),
+       /* dm_helpers_dp_write_hblank_reduction */
+       KUNIT_CASE(dm_test_dp_write_hblank_reduction_false),
+       {}
+};
+
+static struct kunit_suite amdgpu_dm_helpers_test_suite = {
+       .name = "amdgpu_dm_helpers",
+       .test_cases = amdgpu_dm_helpers_test_cases,
+};
+
+kunit_test_suite(amdgpu_dm_helpers_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_helpers");
+MODULE_LICENSE("Dual MIT/GPL");
-- 
2.43.0


Reply via email to