From: Bhawanpreet Lakha <[email protected]>
Add KUnit tests driving create_eml_sink() through the valid-EDID
branch: reading the EDID over DDC, and the forced-on paths using an
emulated sink and a cached local sink.
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]>
---
.../tests/amdgpu_dm_connector_test.c | 135 ++++++++++++++++++
1 file changed, 135 insertions(+)
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 fc6b6013d1188..120d0e27f5eed 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
@@ -7171,6 +7171,138 @@ static void dm_test_funcs_force_reads_edid(struct kunit *test)
ctx->aconnector->drm_edid = NULL;
}
+/* Tests for create_eml_sink() with a valid EDID */
+
+/*
+ * create_eml_sink() reads the EDID off the connector DDC and, on success,
+ * installs an emulated sink from link_srv->add_remote_sink(). A non-AUX link
+ * selects the connector i2c adapter (serving dm_test_uad_edid) and a fake
+ * add_remote_sink() returns dm_test_ces_remote_sink, so the full EDID path
+ * runs without real hardware or DC.
+ */
+static struct dc_sink *dm_test_ces_remote_sink;
+
+static struct dc_sink *
+dm_test_ces_add_remote_sink(struct dc_link *link, const uint8_t *edid,
+ unsigned int len, struct dc_sink_init_data *init_data)
+{
+ return dm_test_ces_remote_sink;
+}
+
+static void dm_test_ces_setup(struct kunit *test, struct dm_test_edid_ctx *ctx,
+ struct dc_sink *em_sink)
+{
+ struct amdgpu_i2c_adapter *i2c;
+ struct link_service *link_srv;
+ struct dc *dc;
+
+ i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, i2c);
+ i2c->base.algo = &dm_test_force_edid_i2c_algo;
+ i2c->base.lock_ops = &dm_test_force_edid_lock_ops;
+ ctx->aconnector->i2c = i2c;
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ link_srv->add_remote_sink = dm_test_ces_add_remote_sink;
+ dc->link_srv = link_srv;
+
+ ctx->link->dc = dc;
+ ctx->link->aux_mode = false;
+ dm_test_ces_remote_sink = em_sink;
+}
+
+/**
+ * dm_test_create_eml_sink_reads_edid - Test the valid-EDID path builds a sink
+ * @test: The KUnit test context
+ *
+ * With a readable EDID and force unspecified, create_eml_sink() caches the EDID
+ * in drm_edid and installs the emulated sink while leaving dc_sink untouched.
+ */
+static void dm_test_create_eml_sink_reads_edid(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct dc_sink *em_sink;
+
+ em_sink = kunit_kzalloc(test, sizeof(*em_sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, em_sink);
+ dm_test_ces_setup(test, ctx, em_sink);
+ ctx->aconnector->base.force = DRM_FORCE_UNSPECIFIED;
+
+ create_eml_sink(ctx->aconnector);
+
+ KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->drm_edid);
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_em_sink, em_sink);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->dc_sink);
+
+ drm_edid_free(ctx->aconnector->drm_edid);
+ ctx->aconnector->drm_edid = NULL;
+}
+
+/**
+ * dm_test_create_eml_sink_force_on_em - Test force-on adopts the emulated sink
+ * @test: The KUnit test context
+ *
+ * With DRM_FORCE_ON and no local sink, create_eml_sink() adopts the emulated
+ * sink as dc_sink and retains it.
+ */
+static void dm_test_create_eml_sink_force_on_em(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct dc_sink *em_sink;
+
+ em_sink = kunit_kzalloc(test, sizeof(*em_sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, em_sink);
+ kref_init(&em_sink->refcount);
+ dm_test_ces_setup(test, ctx, em_sink);
+ ctx->link->local_sink = NULL;
+ ctx->aconnector->base.force = DRM_FORCE_ON;
+
+ create_eml_sink(ctx->aconnector);
+
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_sink, em_sink);
+ KUNIT_EXPECT_EQ(test, kref_read(&em_sink->refcount), 2);
+
+ drm_edid_free(ctx->aconnector->drm_edid);
+ ctx->aconnector->drm_edid = NULL;
+}
+
+/**
+ * dm_test_create_eml_sink_force_on_local - Test force-on prefers the local sink
+ * @test: The KUnit test context
+ *
+ * With DRM_FORCE_ON and a local sink present, create_eml_sink() adopts the
+ * local sink as dc_sink instead of the emulated one and retains it.
+ */
+static void dm_test_create_eml_sink_force_on_local(struct kunit *test)
+{
+ struct dm_test_edid_ctx *ctx =
+ dm_test_edid_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct dc_sink *em_sink;
+ struct dc_sink *local_sink;
+
+ em_sink = kunit_kzalloc(test, sizeof(*em_sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, em_sink);
+ local_sink = kunit_kzalloc(test, sizeof(*local_sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, local_sink);
+ kref_init(&local_sink->refcount);
+ dm_test_ces_setup(test, ctx, em_sink);
+ ctx->link->local_sink = local_sink;
+ ctx->aconnector->base.force = DRM_FORCE_ON;
+
+ create_eml_sink(ctx->aconnector);
+
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_sink, local_sink);
+ KUNIT_EXPECT_EQ(test, kref_read(&local_sink->refcount), 2);
+
+ drm_edid_free(ctx->aconnector->drm_edid);
+ ctx->aconnector->drm_edid = NULL;
+}
+
/* Tests for amdgpu_dm_connector_get_modes() */
static enum dp_link_encoding dm_test_gm_enc_8b10b(const struct dc_link_settings *s)
@@ -7801,6 +7933,9 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_hdmi_cec_unset_edid_no_notifier),
/* create_eml_sink */
KUNIT_CASE(dm_test_create_eml_sink_no_edid),
+ KUNIT_CASE(dm_test_create_eml_sink_reads_edid),
+ KUNIT_CASE(dm_test_create_eml_sink_force_on_em),
+ KUNIT_CASE(dm_test_create_eml_sink_force_on_local),
/* handle_edid_mgmt */
KUNIT_CASE(dm_test_handle_edid_mgmt_dp_sets_link_caps),
KUNIT_CASE(dm_test_handle_edid_mgmt_non_dp_leaves_caps),
--
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.