Add some KUnit tests to verify that the HDMI state helper's mode_valid
implementation does not improperly reject chroma subsampled modes on the
basis of their clock rate not being satisfiable in RGB.

Signed-off-by: Nicolas Frattaroli <[email protected]>
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 109 +++++++++++++++++++++
 1 file changed, 109 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 f9648f9de46b..b2c421d7e986 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -77,6 +77,23 @@ static struct drm_display_mode *find_420_only_mode(struct 
drm_connector *connect
        return NULL;
 }
 
+static struct drm_display_mode *find_420_also_mode(struct drm_connector 
*connector)
+{
+       struct drm_device *drm = connector->dev;
+       struct drm_display_mode *mode;
+
+       mutex_lock(&drm->mode_config.mutex);
+       list_for_each_entry(mode, &connector->modes, head) {
+               if (drm_mode_is_420_also(&connector->display_info, mode)) {
+                       mutex_unlock(&drm->mode_config.mutex);
+                       return mode;
+               }
+       }
+       mutex_unlock(&drm->mode_config.mutex);
+
+       return NULL;
+}
+
 static int set_connector_edid(struct kunit *test, struct drm_connector 
*connector,
                              const void *edid, size_t edid_len)
 {
@@ -2700,11 +2717,103 @@ static void 
drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
        KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
 }
 
+/*
+ * 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
+ * constraints if it used RGB 4:4:4.
+ */
+static void drm_test_check_mode_valid_yuv420_only_max_clock(struct kunit *test)
+{
+       struct drm_atomic_helper_connector_hdmi_priv *priv;
+       struct drm_display_mode *dank;
+       struct drm_connector *conn;
+
+       priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+                               BIT(HDMI_COLORSPACE_RGB) |
+                               BIT(HDMI_COLORSPACE_YUV420),
+                               8,
+                               &dummy_connector_hdmi_funcs,
+                               
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+       KUNIT_ASSERT_NOT_NULL(test, priv);
+
+       conn = &priv->connector;
+       KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 200 * 1000);
+
+       dank = find_420_only_mode(conn);
+       KUNIT_ASSERT_NOT_NULL(test, dank);
+       KUNIT_EXPECT_EQ(test, dank->hdisplay, 3840);
+       KUNIT_EXPECT_EQ(test, dank->vdisplay, 2160);
+
+       /*
+        * Note: The mode's "clock" here is not accurate to the actual TMDS
+        * clock that HDMI will use for a subsampled mode. Hence, why the mode's
+        * clock is above the .max_tmds_clock of 200MHz.
+        */
+       KUNIT_EXPECT_EQ(test, dank->clock, 297000);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() will reject modes that require
+ * 4:2:0 chroma subsampling, if the connector does not support 4:2:0.
+ */
+static void
+drm_test_check_mode_valid_reject_yuv420_only_connector(struct kunit *test)
+{
+       struct drm_atomic_helper_connector_hdmi_priv *priv;
+       struct drm_display_mode *dank;
+       struct drm_connector *conn;
+
+       priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+                               BIT(HDMI_COLORSPACE_RGB),
+                               8,
+                               &dummy_connector_hdmi_funcs,
+                               
test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+       KUNIT_ASSERT_NOT_NULL(test, priv);
+
+       conn = &priv->connector;
+       KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 200 * 1000);
+
+       dank = find_420_only_mode(conn);
+       KUNIT_EXPECT_NULL(test, dank);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() will accept modes that allow 
(among
+ * other color formats) 4:2:0 chroma subsampling, even if the connector does 
not
+ * support 4:2:0, but the mode's clock works for RGB 4:4:4.
+ */
+static void
+drm_test_check_mode_valid_accept_yuv420_also_connector_rgb(struct kunit *test)
+{
+       struct drm_atomic_helper_connector_hdmi_priv *priv;
+       struct drm_display_mode *mode;
+       struct drm_connector *conn;
+
+       priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+                               BIT(HDMI_COLORSPACE_RGB),
+                               8,
+                               &dummy_connector_hdmi_funcs,
+                               test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+       KUNIT_ASSERT_NOT_NULL(test, priv);
+
+       conn = &priv->connector;
+       KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 340 * 1000);
+
+       mode = find_420_also_mode(conn);
+       KUNIT_ASSERT_NOT_NULL(test, mode);
+       KUNIT_EXPECT_EQ(test, mode->hdisplay, 3840);
+       KUNIT_EXPECT_EQ(test, mode->vdisplay, 2160);
+       KUNIT_EXPECT_EQ(test, mode->clock, 297000);
+}
+
 static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = 
{
        KUNIT_CASE(drm_test_check_mode_valid),
        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_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.52.0

Reply via email to