[PATCH v8 35/39] drm/tests: hdmi_state_helper: Add max_tmds_char_rate fallback tests
Cristian Ciocaltea
cristian.ciocaltea at collabora.com
Thu Jul 2 07:46:48 PDT 2026
Cover the fallback in hdmi_clock_valid() that rejects modes whose TMDS
character rate exceeds connector->hdmi.max_tmds_char_rate when the
driver provides no .tmds_char_rate_valid() callback. Exercise both an
explicit limit set through drm_connector_hdmi_caps and the limit
inferred from caps.supported_hdmi_ver, and confirm that a driver hook
takes precedence over the connector limit.
The connector limit is installed via the new
drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs() helper so it
is in place before mode probing runs.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 120 +++++++++++++++++++++
1 file changed, 120 insertions(+)
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 6a7dd2de002a..b8ae5fad2794 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -174,6 +174,26 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
},
};
+static enum drm_mode_status
+accept_connector_tmds_char_rate_valid(const struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ unsigned long long tmds_rate)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_hdmi_funcs accept_connector_hdmi_funcs = {
+ .tmds_char_rate_valid = accept_connector_tmds_char_rate_valid,
+ .avi = {
+ .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,
+ },
+};
+
static int dummy_connector_get_modes(struct drm_connector *connector)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
@@ -2771,6 +2791,103 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
}
+/*
+ * Test that a driver-provided .tmds_char_rate_valid() hook takes precedence
+ * over the connector->hdmi.max_tmds_char_rate fallback: the fallback must
+ * not be consulted when the hook is present.
+ */
+static void
+drm_test_check_mode_valid_driver_hook_overrides_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = 100ULL * 1000 * 1000,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &accept_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1920);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1080);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 148500);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() falls back to
+ * connector->hdmi.max_tmds_char_rate when the driver provides no
+ * .tmds_char_rate_valid() hook, rejecting modes whose computed TMDS character
+ * rate exceeds the connector limit.
+ */
+static void
+drm_test_check_mode_valid_reject_connector_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ .max_tmds_char_rate = 100ULL * 1000 * 1000,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_1080p_rgb_max_200mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640);
+ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480);
+ KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
+}
+
+/*
+ * Test that the max_tmds_char_rate inferred from caps.supported_hdmi_ver
+ * is applied as a mode-filtering limit: with an HDMI 1.3 connector
+ * (340 MHz inferred cap) and no driver hook, modes whose RGB444/8bpc TMDS
+ * rate exceeds 340 MHz must be filtered out even though the sink itself
+ * advertises a higher limit.
+ */
+static void
+drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate(struct kunit *test)
+{
+ struct drm_connector_hdmi_caps caps = {
+ .supported_hdmi_ver = HDMI_VERSION_1_3,
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+ .max_bpc = 8,
+ };
+ struct drm_atomic_helper_connector_hdmi_priv *priv;
+ struct drm_display_mode *preferred;
+ unsigned long long rate;
+
+ priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test,
+ &caps,
+ &dummy_connector_hdmi_funcs,
+ test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+
+ KUNIT_ASSERT_EQ(test, priv->connector.hdmi.max_tmds_char_rate,
+ HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+ preferred = find_preferred_mode(&priv->connector);
+ KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+ rate = drm_hdmi_compute_mode_clock(preferred, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444);
+ KUNIT_EXPECT_LE(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+}
+
/*
* Test that drm_hdmi_connector_mode_valid() will accept modes that require a
* 4:2:0 chroma subsampling, even if said mode would violate maximum clock
@@ -2865,6 +2982,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
KUNIT_CASE(drm_test_check_mode_valid_reject),
KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
+ KUNIT_CASE(drm_test_check_mode_valid_driver_hook_overrides_max_tmds_char_rate),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_connector_max_tmds_char_rate),
+ KUNIT_CASE(drm_test_check_mode_valid_reject_inferred_max_tmds_char_rate),
KUNIT_CASE(drm_test_check_mode_valid_yuv420_only_max_clock),
KUNIT_CASE(drm_test_check_mode_valid_reject_yuv420_only_connector),
KUNIT_CASE(drm_test_check_mode_valid_accept_yuv420_also_connector_rgb),
--
2.54.0
More information about the linux-arm-kernel
mailing list