[PATCH v11 74/74] drm/tests: hdmi: Add SPD InfoFrame vendor/product coverage

From: Cristian Ciocaltea

Date: Tue Sep 01 2026 - 15:01:09 EST


The vendor and product strings provided through struct
drm_connector_hdmi_funcs end up in the SPD InfoFrame, whose fields are
defined by the HDMI specification as fixed-size: 8 bytes for the vendor
name and 16 bytes for the product description, padded with zeros and
left without any trailing NUL when a name spans the whole field.

Nothing exercises that so far, since the SPD InfoFrame is only generated
for connectors implementing the related hooks, which none of the
existing test funcs provides.

Add a connector variant supplying those hooks, along with parametrized
tests covering both the padded and the exact length cases.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@xxxxxxxxxxxxx>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 164 ++++++++++++++++++++-
1 file changed, 163 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index 68b442c32a2a..415d82e75eaa 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -3205,6 +3205,167 @@ static void drm_test_check_infoframes(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}

+struct drm_hdmi_spd_infoframe_test {
+ const char *name;
+ const char *vendor;
+ const char *product;
+ unsigned char expected_vendor[HDMI_SPD_INFOFRAME_VENDOR_LEN];
+ unsigned char expected_product[HDMI_SPD_INFOFRAME_PRODUCT_LEN];
+};
+
+static const struct drm_hdmi_spd_infoframe_test drm_hdmi_spd_infoframe_tests[] = {
+ {
+ .name = "shorter-than-field",
+ .vendor = "Vend",
+ .product = "Prod",
+ .expected_vendor = { 'V', 'e', 'n', 'd' },
+ .expected_product = { 'P', 'r', 'o', 'd' },
+ },
+ {
+ .name = "whole-field",
+ .vendor = "VendorVe",
+ .product = "ProductProductPr",
+ .expected_vendor = {
+ 'V', 'e', 'n', 'd', 'o', 'r', 'V', 'e',
+ },
+ .expected_product = {
+ 'P', 'r', 'o', 'd', 'u', 'c', 't',
+ 'P', 'r', 'o', 'd', 'u', 'c', 't',
+ 'P', 'r',
+ },
+ },
+};
+
+static void drm_hdmi_spd_infoframe_desc(const struct drm_hdmi_spd_infoframe_test *t,
+ char *desc)
+{
+ strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+KUNIT_ARRAY_PARAM(drm_hdmi_spd_infoframe, drm_hdmi_spd_infoframe_tests,
+ drm_hdmi_spd_infoframe_desc);
+
+/*
+ * The SPD InfoFrame is only generated for connectors implementing the
+ * related hooks, hence the SPD tests cannot rely on the plain dummy funcs.
+ */
+static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_spd_funcs = {
+ .vendor = "Vendor",
+ .product = "Product",
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .avi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .spd = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = accept_infoframe_clear_infoframe,
+ .write_infoframe = accept_infoframe_write_infoframe,
+ },
+};
+
+/*
+ * Test that the vendor and product names end up in the SPD InfoFrame padded
+ * with zeros, and without any trailing NUL when spanning the whole field.
+ */
+static void drm_test_check_spd_infoframe(struct kunit *test)
+{
+ const struct drm_hdmi_spd_infoframe_test *param = test->param_value;
+ struct drm_connector_hdmi_funcs hdmi_funcs = dummy_connector_hdmi_spd_funcs;
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_atomic_commit *state;
+ struct drm_display_mode *preferred;
+ struct hdmi_spd_infoframe *frame;
+ struct drm_connector *conn;
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ int ret;
+
+ hdmi_funcs.vendor = param->vendor;
+ hdmi_funcs.product = param->product;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+ &hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ drm = &priv->drm;
+ crtc = priv->crtc;
+ conn = &priv->connector;
+
+ preferred = find_preferred_mode(conn);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
+ if (ret == -EDEADLK) {
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_conn_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_crtc_state:
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (PTR_ERR(crtc_state) == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_crtc_state;
+ }
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ crtc_state->mode_changed = true;
+
+ ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_crtc_state;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_crtc_state;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ conn_state = conn->state;
+ KUNIT_ASSERT_NOT_NULL(test, conn_state);
+ KUNIT_ASSERT_TRUE(test, conn_state->hdmi.infoframes.spd.set);
+
+ frame = &conn_state->hdmi.infoframes.spd.data.spd;
+
+ KUNIT_EXPECT_MEMEQ(test, frame->vendor, param->expected_vendor,
+ sizeof(frame->vendor));
+ KUNIT_EXPECT_MEMEQ(test, frame->product, param->expected_product,
+ sizeof(frame->product));
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
static int reject_infoframe_write_infoframe(struct drm_connector *connector,
const u8 *buffer, size_t len)
{
@@ -3723,9 +3884,10 @@ static void drm_test_check_reject_audio_infoframe(struct kunit *test)
drm_modeset_acquire_fini(&ctx);
}

-
static struct kunit_case drm_atomic_helper_connector_hdmi_infoframes_tests[] = {
KUNIT_CASE(drm_test_check_infoframes),
+ KUNIT_CASE_PARAM(drm_test_check_spd_infoframe,
+ drm_hdmi_spd_infoframe_gen_params),
KUNIT_CASE(drm_test_check_reject_avi_infoframe),
KUNIT_CASE(drm_test_check_reject_hdr_infoframe_bpc_8),
KUNIT_CASE(drm_test_check_reject_hdr_infoframe_bpc_10),

--
2.55.0