Add two atomic-check cases that initialise an HDMI 2.0 connector via drm_connector_hdmi_caps (so the core infers scrambler_supported and the 600 MHz TMDS limit) and assert that conn_state->hdmi.scrambler_needed stays clear for a 1080p@60 CEA mode (~148.5 MHz TMDS) and is set for the 4K@60 RGB preferred mode (~594 MHz TMDS), straddling the 340 MHz threshold.
Signed-off-by: Cristian Ciocaltea <[email protected]> --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 160 +++++++++++++++++++++ 1 file changed, 160 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 b8ae5fad2794..7cd6bd422b0b 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -20,6 +20,8 @@ #include <drm/display/drm_hdmi_helper.h> #include <drm/display/drm_hdmi_state_helper.h> +#include <linux/hdmi.h> + #include "../drm_crtc_internal.h" #include <kunit/test.h> @@ -194,6 +196,29 @@ static const struct drm_connector_hdmi_funcs accept_connector_hdmi_funcs = { }, }; +static int accept_scrambler_enable(struct drm_connector *connector) +{ + return 0; +} + +static int accept_scrambler_disable(struct drm_connector *connector) +{ + return 0; +} + +static const struct drm_connector_hdmi_funcs scrambler_connector_hdmi_funcs = { + .scrambler_enable = accept_scrambler_enable, + .scrambler_disable = accept_scrambler_disable, + .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 = @@ -2265,6 +2290,139 @@ static void drm_test_check_disable_connector(struct kunit *test) drm_modeset_acquire_fini(&ctx); } +/* + * Test that on an HDMI connector with source+sink scrambling support, driving + * a sub-340 MHz CEA mode, we end up with scrambler_needed cleared. + */ +static void drm_test_check_scrambler_needed_low_rate(struct kunit *test) +{ + struct drm_connector_hdmi_caps caps = { + .supported_hdmi_ver = HDMI_VERSION_2_0, + .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + .max_bpc = 8, + }; + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *low_rate_mode; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + unsigned long long rate; + int ret; + + priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test, + &caps, + &scrambler_connector_hdmi_funcs, + test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; + crtc = priv->crtc; + conn = &priv->connector; + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported); + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported); + KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported); + + low_rate_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16); + KUNIT_ASSERT_NOT_NULL(test, low_rate_mode); + + rate = drm_hdmi_compute_mode_clock(low_rate_mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); + KUNIT_ASSERT_LT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ); + + drm_modeset_acquire_init(&ctx, 0); + +retry_conn_enable: + ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn, + low_rate_mode, &ctx); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry_conn_enable; + } + KUNIT_ASSERT_EQ(test, ret, 0); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_LE(test, conn_state->hdmi.tmds_char_rate, + HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ); + KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +/* + * Test that on an HDMI connector with source+sink scrambling support, driving + * the 4K@60 RGB preferred mode (~594 MHz TMDS, above the 340 MHz threshold), + * we end up with scrambler_needed set. + */ +static void drm_test_check_scrambler_needed_high_rate(struct kunit *test) +{ + struct drm_connector_hdmi_caps caps = { + .supported_hdmi_ver = HDMI_VERSION_2_0, + .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444), + .max_bpc = 8, + }; + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_modeset_acquire_ctx ctx; + struct drm_connector_state *conn_state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + struct drm_connector *conn; + struct drm_device *drm; + struct drm_crtc *crtc; + unsigned long long rate; + int ret; + + priv = drm_kunit_helper_connector_hdmi_init_with_caps_edid_funcs(test, + &caps, + &scrambler_connector_hdmi_funcs, + test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; + crtc = priv->crtc; + conn = &priv->connector; + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported); + KUNIT_ASSERT_TRUE(test, info->is_hdmi); + KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported); + KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported); + + preferred = find_preferred_mode(conn); + KUNIT_ASSERT_NOT_NULL(test, preferred); + + rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444); + KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ); + + 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); + + conn_state = conn->state; + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate, + HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ); + KUNIT_EXPECT_TRUE(test, conn_state->hdmi.scrambler_needed); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + struct color_format_test_param { enum drm_connector_color_format fmt; enum drm_output_color_format expected; @@ -2505,6 +2663,8 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc), KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc), + KUNIT_CASE(drm_test_check_scrambler_needed_low_rate), + KUNIT_CASE(drm_test_check_scrambler_needed_high_rate), KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format, check_hdmi_color_format_gen_params), KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only, -- 2.54.0
