From: Bhawanpreet Lakha <[email protected]>

Add KUnit tests for amdgpu_dm_prune_primary_tile_modes() covering the
no-sink, no panel-patch and non-tiled early returns, a secondary tile,
and the primary-tile path that prunes per-tile modes.

Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <[email protected]>
Signed-off-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Ivan Lipski <[email protected]>
---
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |   3 +-
 .../display/amdgpu_dm/amdgpu_dm_connector.h   |   1 +
 .../tests/amdgpu_dm_connector_test.c          | 172 ++++++++++++++++++
 3 files changed, 175 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index ddefef1debf25..a473218f4d75c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -2853,7 +2853,7 @@ EXPORT_IF_KUNIT(amdgpu_set_panel_orientation);
  * per-tile timing from the primary connector so compositors only pick the full
  * 5K mode.
  */
-static void amdgpu_dm_prune_primary_tile_modes(struct drm_connector *connector)
+STATIC_IFN_KUNIT void amdgpu_dm_prune_primary_tile_modes(struct drm_connector 
*connector)
 {
        struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
        struct drm_display_mode *mode, *t;
@@ -2886,6 +2886,7 @@ static void amdgpu_dm_prune_primary_tile_modes(struct 
drm_connector *connector)
                aconnector->num_modes--;
        }
 }
+EXPORT_IF_KUNIT(amdgpu_dm_prune_primary_tile_modes);
 
 STATIC_IFN_KUNIT void amdgpu_dm_connector_ddc_get_modes(struct drm_connector 
*connector,
                                              const struct drm_edid *drm_edid)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index 91b8434ba591d..a86d5c879b646 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -169,6 +169,7 @@ void amdgpu_dm_connector_add_common_modes(struct 
drm_encoder *encoder,
 void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
                                       const struct drm_edid *drm_edid);
 int amdgpu_dm_connector_get_modes(struct drm_connector *connector);
+void amdgpu_dm_prune_primary_tile_modes(struct drm_connector *connector);
 uint add_fs_modes(struct amdgpu_dm_connector *aconnector);
 void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector,
                                            const struct drm_edid *drm_edid);
diff --git 
a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index e63202fc7ba9f..e022f93c36cf5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -7540,6 +7540,172 @@ static void 
dm_test_panel_orientation_applies_quirk(struct kunit *test)
                        DRM_MODE_PANEL_ORIENTATION_UNKNOWN);
 }
 
+/* Tests for amdgpu_dm_prune_primary_tile_modes() */
+
+struct dm_test_prune_ctx {
+       struct drm_device *drm;
+       struct amdgpu_dm_connector *aconnector;
+       struct dc_sink *sink;
+};
+
+/*
+ * Build a connector configured as the primary tile of an Apple Studio Display:
+ * a dc_sink requesting the second-tile patch, has_tile set, tile location 
(0,0)
+ * and a per-tile timing of tile_h_size x tile_v_size. Individual tests relax a
+ * single precondition to exercise the early-return guards.
+ */
+static struct dm_test_prune_ctx *
+dm_test_prune_ctx_alloc(struct kunit *test)
+{
+       struct dm_test_prune_ctx *ctx;
+
+       ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+       ctx->drm = dm_test_alloc_drm(test);
+       ctx->aconnector = dm_test_add_connector(test, ctx->drm,
+                                               DRM_MODE_CONNECTOR_DisplayPort);
+
+       ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+       ctx->sink->edid_caps.panel_patch.disable_second_tile = true;
+       ctx->aconnector->dc_sink = ctx->sink;
+
+       ctx->aconnector->base.has_tile = true;
+       ctx->aconnector->base.tile_h_size = 2560;
+       ctx->aconnector->base.tile_v_size = 2880;
+
+       return ctx;
+}
+
+static struct drm_display_mode *
+dm_test_prune_add_mode(struct kunit *test, struct drm_connector *connector,
+                      int hdisplay, int vdisplay)
+{
+       struct drm_display_mode *mode = drm_mode_create(connector->dev);
+
+       KUNIT_ASSERT_NOT_NULL(test, mode);
+       mode->hdisplay = hdisplay;
+       mode->vdisplay = vdisplay;
+       list_add_tail(&mode->head, &connector->probed_modes);
+
+       return mode;
+}
+
+static int dm_test_prune_count(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode;
+       int n = 0;
+
+       list_for_each_entry(mode, &connector->probed_modes, head)
+               n++;
+
+       return n;
+}
+
+/**
+ * dm_test_prune_no_sink - Test a connector without a sink is left untouched
+ * @test: The KUnit test context
+ */
+static void dm_test_prune_no_sink(struct kunit *test)
+{
+       struct dm_test_prune_ctx *ctx = dm_test_prune_ctx_alloc(test);
+
+       ctx->aconnector->dc_sink = NULL;
+       dm_test_prune_add_mode(test, &ctx->aconnector->base, 2560, 2880);
+       ctx->aconnector->num_modes = 1;
+
+       amdgpu_dm_prune_primary_tile_modes(&ctx->aconnector->base);
+
+       KUNIT_EXPECT_EQ(test, dm_test_prune_count(&ctx->aconnector->base), 1);
+       KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 1);
+}
+
+/**
+ * dm_test_prune_no_patch - Test the patch flag being unset skips pruning
+ * @test: The KUnit test context
+ */
+static void dm_test_prune_no_patch(struct kunit *test)
+{
+       struct dm_test_prune_ctx *ctx = dm_test_prune_ctx_alloc(test);
+
+       ctx->sink->edid_caps.panel_patch.disable_second_tile = false;
+       dm_test_prune_add_mode(test, &ctx->aconnector->base, 2560, 2880);
+       ctx->aconnector->num_modes = 1;
+
+       amdgpu_dm_prune_primary_tile_modes(&ctx->aconnector->base);
+
+       KUNIT_EXPECT_EQ(test, dm_test_prune_count(&ctx->aconnector->base), 1);
+       KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 1);
+}
+
+/**
+ * dm_test_prune_no_tile - Test a non-tiled connector skips pruning
+ * @test: The KUnit test context
+ */
+static void dm_test_prune_no_tile(struct kunit *test)
+{
+       struct dm_test_prune_ctx *ctx = dm_test_prune_ctx_alloc(test);
+
+       ctx->aconnector->base.has_tile = false;
+       dm_test_prune_add_mode(test, &ctx->aconnector->base, 2560, 2880);
+       ctx->aconnector->num_modes = 1;
+
+       amdgpu_dm_prune_primary_tile_modes(&ctx->aconnector->base);
+
+       KUNIT_EXPECT_EQ(test, dm_test_prune_count(&ctx->aconnector->base), 1);
+       KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 1);
+}
+
+/**
+ * dm_test_prune_secondary_tile - Test a secondary tile is left untouched
+ * @test: The KUnit test context
+ *
+ * Only the primary tile (location 0,0) is pruned; a secondary tile keeps its
+ * per-tile timing.
+ */
+static void dm_test_prune_secondary_tile(struct kunit *test)
+{
+       struct dm_test_prune_ctx *ctx = dm_test_prune_ctx_alloc(test);
+
+       ctx->aconnector->base.tile_h_loc = 1;
+       dm_test_prune_add_mode(test, &ctx->aconnector->base, 2560, 2880);
+       ctx->aconnector->num_modes = 1;
+
+       amdgpu_dm_prune_primary_tile_modes(&ctx->aconnector->base);
+
+       KUNIT_EXPECT_EQ(test, dm_test_prune_count(&ctx->aconnector->base), 1);
+       KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 1);
+}
+
+/**
+ * dm_test_prune_removes_per_tile - Test the per-tile timing is pruned
+ * @test: The KUnit test context
+ *
+ * On the primary tile the per-tile (tile_h_size x tile_v_size) timing is
+ * dropped while the full-resolution mode is kept and num_modes is decremented.
+ */
+static void dm_test_prune_removes_per_tile(struct kunit *test)
+{
+       struct dm_test_prune_ctx *ctx = dm_test_prune_ctx_alloc(test);
+       struct drm_display_mode *mode;
+       bool has_tile_mode = false;
+
+       dm_test_prune_add_mode(test, &ctx->aconnector->base, 2560, 2880);
+       dm_test_prune_add_mode(test, &ctx->aconnector->base, 5120, 2880);
+       ctx->aconnector->num_modes = 2;
+
+       amdgpu_dm_prune_primary_tile_modes(&ctx->aconnector->base);
+
+       KUNIT_EXPECT_EQ(test, dm_test_prune_count(&ctx->aconnector->base), 1);
+       KUNIT_EXPECT_EQ(test, ctx->aconnector->num_modes, 1);
+
+       list_for_each_entry(mode, &ctx->aconnector->base.probed_modes, head)
+               if (mode->hdisplay == 2560 && mode->vdisplay == 2880)
+                       has_tile_mode = true;
+       KUNIT_EXPECT_FALSE(test, has_tile_mode);
+}
+
 /* Tests for amdgpu_dm_update_stream_scaling_settings() */
 
 /**
@@ -8015,6 +8181,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
        KUNIT_CASE(dm_test_panel_orientation_non_edp),
        KUNIT_CASE(dm_test_panel_orientation_no_native_mode),
        KUNIT_CASE(dm_test_panel_orientation_applies_quirk),
+       /* amdgpu_dm_prune_primary_tile_modes */
+       KUNIT_CASE(dm_test_prune_no_sink),
+       KUNIT_CASE(dm_test_prune_no_patch),
+       KUNIT_CASE(dm_test_prune_no_tile),
+       KUNIT_CASE(dm_test_prune_secondary_tile),
+       KUNIT_CASE(dm_test_prune_removes_per_tile),
        /* dm_validate_stream_and_context */
        KUNIT_CASE(dm_test_validate_stream_null_stream),
        KUNIT_CASE(dm_test_validate_stream_dc_ok_no_pipe),
-- 
2.43.0

Reply via email to