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 <[email protected]> --- 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
