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

Reply via email to