This had a bunch of kunit tests to make sure our code to handle the
Broadcast RGB property behaves properly.

This requires bringing a bit of infrastructure to create mock HDMI
connectors, with custom EDIDs.

Reviewed-by: Dave Stevenson <dave.steven...@raspberrypi.com>
Signed-off-by: Maxime Ripard <mrip...@kernel.org>
---
 .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 151 +++++++++++++++++++++
 drivers/gpu/drm/tests/drm_connector_test.c         | 116 ++++++++++++++++
 2 files changed, 267 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c 
b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
index c0f26422e925..3de15cec2f5f 100644
--- a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
@@ -224,6 +224,134 @@ drm_atomic_helper_connector_hdmi_init(struct kunit *test,
        return priv;
 }
 
+/*
+ * Test that if we change the RGB quantization property to a different
+ * value, we trigger a mode change on the connector's CRTC, which will
+ * in turn disable/enable the connector.
+ */
+static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
+{
+       struct drm_atomic_helper_connector_hdmi_priv *priv;
+       struct drm_modeset_acquire_ctx *ctx;
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector_state *new_conn_state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_atomic_state *state;
+       struct drm_display_mode *preferred;
+       struct drm_connector *conn;
+       struct drm_device *drm;
+       struct drm_crtc *crtc;
+       int ret;
+
+       priv = drm_atomic_helper_connector_hdmi_init(test,
+                                                    BIT(HDMI_COLORSPACE_RGB),
+                                                    8);
+       KUNIT_ASSERT_NOT_NULL(test, priv);
+
+       ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+       conn = &priv->connector;
+       preferred = find_preferred_mode(conn);
+       KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+       drm = &priv->drm;
+       crtc = priv->crtc;
+       ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+       new_conn_state = drm_atomic_get_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+       old_conn_state = drm_atomic_get_old_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
+
+       new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_FULL;
+
+       KUNIT_ASSERT_NE(test,
+                       old_conn_state->hdmi.broadcast_rgb,
+                       new_conn_state->hdmi.broadcast_rgb);
+
+       ret = drm_atomic_check_only(state);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       new_conn_state = drm_atomic_get_new_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+       KUNIT_EXPECT_EQ(test, new_conn_state->hdmi.broadcast_rgb, 
DRM_HDMI_BROADCAST_RGB_FULL);
+
+       crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+       KUNIT_EXPECT_TRUE(test, crtc_state->mode_changed);
+}
+
+/*
+ * Test that if we set the RGB quantization property to the same value,
+ * we don't trigger a mode change on the connector's CRTC and leave the
+ * connector unaffected.
+ */
+static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit 
*test)
+{
+       struct drm_atomic_helper_connector_hdmi_priv *priv;
+       struct drm_modeset_acquire_ctx *ctx;
+       struct drm_connector_state *old_conn_state;
+       struct drm_connector_state *new_conn_state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_atomic_state *state;
+       struct drm_display_mode *preferred;
+       struct drm_connector *conn;
+       struct drm_device *drm;
+       struct drm_crtc *crtc;
+       int ret;
+
+       priv = drm_atomic_helper_connector_hdmi_init(test,
+                                                    BIT(HDMI_COLORSPACE_RGB),
+                                                    8);
+       KUNIT_ASSERT_NOT_NULL(test, priv);
+
+       ctx = drm_kunit_helper_acquire_ctx_alloc(test);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+
+       conn = &priv->connector;
+       preferred = find_preferred_mode(conn);
+       KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+       drm = &priv->drm;
+       crtc = priv->crtc;
+       ret = light_up_connector(test, drm, crtc, conn, preferred, ctx);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+       new_conn_state = drm_atomic_get_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+       old_conn_state = drm_atomic_get_old_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
+
+       new_conn_state->hdmi.broadcast_rgb = old_conn_state->hdmi.broadcast_rgb;
+
+       ret = drm_atomic_check_only(state);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       old_conn_state = drm_atomic_get_old_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_conn_state);
+
+       new_conn_state = drm_atomic_get_new_connector_state(state, conn);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_conn_state);
+
+       KUNIT_EXPECT_EQ(test,
+                       old_conn_state->hdmi.broadcast_rgb,
+                       new_conn_state->hdmi.broadcast_rgb);
+
+       crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+       KUNIT_EXPECT_FALSE(test, crtc_state->mode_changed);
+}
+
 /*
  * Test that if we change the maximum bpc property to a different value,
  * we trigger a mode change on the connector's CRTC, which will in turn
@@ -1059,6 +1187,8 @@ static void 
drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes
 }
 
 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
+       KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_changed),
+       KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_not_changed),
        KUNIT_CASE(drm_test_check_hdmi_funcs_reject_rate),
        KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback),
        KUNIT_CASE(drm_test_check_max_tmds_rate_format_fallback),
@@ -1090,6 +1220,26 @@ static struct kunit_suite 
drm_atomic_helper_connector_hdmi_check_test_suite = {
        .test_cases     = drm_atomic_helper_connector_hdmi_check_tests,
 };
 
+/*
+ * Test that the value of the Broadcast RGB property out of reset is set
+ * to auto.
+ */
+static void drm_test_check_broadcast_rgb_value(struct kunit *test)
+{
+       struct drm_atomic_helper_connector_hdmi_priv *priv;
+       struct drm_connector_state *conn_state;
+       struct drm_connector *conn;
+
+       priv = drm_atomic_helper_connector_hdmi_init(test,
+                                                    BIT(HDMI_COLORSPACE_RGB),
+                                                    8);
+       KUNIT_ASSERT_NOT_NULL(test, priv);
+
+       conn = &priv->connector;
+       conn_state = conn->state;
+       KUNIT_EXPECT_EQ(test, conn_state->hdmi.broadcast_rgb, 
DRM_HDMI_BROADCAST_RGB_AUTO);
+}
+
 /*
  * Test that if the connector was initialised with a maximum bpc of 8,
  * the value of the max_bpc and max_requested_bpc properties out of
@@ -1207,6 +1357,7 @@ static void drm_test_check_tmds_char_value(struct kunit 
*test)
 }
 
 static struct kunit_case drm_atomic_helper_connector_hdmi_reset_tests[] = {
+       KUNIT_CASE(drm_test_check_broadcast_rgb_value),
        KUNIT_CASE(drm_test_check_bpc_8_value),
        KUNIT_CASE(drm_test_check_bpc_10_value),
        KUNIT_CASE(drm_test_check_bpc_12_value),
diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
b/drivers/gpu/drm/tests/drm_connector_test.c
index 732c59a1d4d5..6a3651b08c81 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -564,6 +564,63 @@ static struct kunit_suite 
drm_get_tv_mode_from_name_test_suite = {
        .test_cases = drm_get_tv_mode_from_name_tests,
 };
 
+struct drm_hdmi_connector_get_broadcast_rgb_name_test {
+       unsigned int kind;
+       const char *expected_name;
+};
+
+#define BROADCAST_RGB_TEST(_kind, _name)       \
+       {                                       \
+               .kind = _kind,                  \
+               .expected_name = _name,         \
+       }
+
+static void drm_test_drm_hdmi_connector_get_broadcast_rgb_name(struct kunit 
*test)
+{
+       const struct drm_hdmi_connector_get_broadcast_rgb_name_test *params =
+               test->param_value;
+
+       KUNIT_EXPECT_STREQ(test,
+                          
drm_hdmi_connector_get_broadcast_rgb_name(params->kind),
+                          params->expected_name);
+}
+
+static const
+struct drm_hdmi_connector_get_broadcast_rgb_name_test
+drm_hdmi_connector_get_broadcast_rgb_name_valid_tests[] = {
+       BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_AUTO, "Automatic"),
+       BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_FULL, "Full"),
+       BROADCAST_RGB_TEST(DRM_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235"),
+};
+
+static void
+drm_hdmi_connector_get_broadcast_rgb_name_valid_desc(const struct 
drm_hdmi_connector_get_broadcast_rgb_name_test *t,
+                                                    char *desc)
+{
+       sprintf(desc, "%s", t->expected_name);
+}
+
+KUNIT_ARRAY_PARAM(drm_hdmi_connector_get_broadcast_rgb_name_valid,
+                 drm_hdmi_connector_get_broadcast_rgb_name_valid_tests,
+                 drm_hdmi_connector_get_broadcast_rgb_name_valid_desc);
+
+static void drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid(struct 
kunit *test)
+{
+       KUNIT_EXPECT_NULL(test, drm_hdmi_connector_get_broadcast_rgb_name(3));
+};
+
+static struct kunit_case drm_hdmi_connector_get_broadcast_rgb_name_tests[] = {
+       KUNIT_CASE_PARAM(drm_test_drm_hdmi_connector_get_broadcast_rgb_name,
+                        
drm_hdmi_connector_get_broadcast_rgb_name_valid_gen_params),
+       KUNIT_CASE(drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid),
+       { }
+};
+
+static struct kunit_suite drm_hdmi_connector_get_broadcast_rgb_name_test_suite 
= {
+       .name = "drm_hdmi_connector_get_broadcast_rgb_name",
+       .test_cases = drm_hdmi_connector_get_broadcast_rgb_name_tests,
+};
+
 struct drm_hdmi_connector_get_output_format_name_test {
        unsigned int kind;
        const char *expected_name;
@@ -622,6 +679,63 @@ static struct kunit_suite 
drm_hdmi_connector_get_output_format_name_test_suite =
        .test_cases = drm_hdmi_connector_get_output_format_name_tests,
 };
 
+static void drm_test_drm_connector_attach_broadcast_rgb_property(struct kunit 
*test)
+{
+       struct drm_connector_init_priv *priv = test->priv;
+       struct drm_connector *connector = &priv->connector;
+       struct drm_property *prop;
+       int ret;
+
+       ret = drmm_connector_init(&priv->drm, connector,
+                                 &dummy_funcs,
+                                 DRM_MODE_CONNECTOR_HDMIA,
+                                 &priv->ddc);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       ret = drm_connector_attach_broadcast_rgb_property(connector);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       prop = connector->broadcast_rgb_property;
+       KUNIT_ASSERT_NOT_NULL(test, prop);
+       KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, 
prop->base.id));
+}
+
+static void 
drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector(struct 
kunit *test)
+{
+       struct drm_connector_init_priv *priv = test->priv;
+       struct drm_connector *connector = &priv->connector;
+       struct drm_property *prop;
+       int ret;
+
+       ret = drmm_connector_hdmi_init(&priv->drm, connector,
+                                      &dummy_funcs,
+                                      &dummy_hdmi_funcs,
+                                      DRM_MODE_CONNECTOR_HDMIA,
+                                      &priv->ddc,
+                                      BIT(HDMI_COLORSPACE_RGB),
+                                      8);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+
+       ret = drm_connector_attach_broadcast_rgb_property(connector);
+       KUNIT_ASSERT_EQ(test, ret, 0);
+
+       prop = connector->broadcast_rgb_property;
+       KUNIT_ASSERT_NOT_NULL(test, prop);
+       KUNIT_EXPECT_NOT_NULL(test, drm_mode_obj_find_prop_id(&connector->base, 
prop->base.id));
+}
+
+static struct kunit_case drm_connector_attach_broadcast_rgb_property_tests[] = 
{
+       KUNIT_CASE(drm_test_drm_connector_attach_broadcast_rgb_property),
+       
KUNIT_CASE(drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector),
+       { }
+};
+
+static struct kunit_suite 
drm_connector_attach_broadcast_rgb_property_test_suite = {
+       .name = "drm_connector_attach_broadcast_rgb_property",
+       .init = drm_test_connector_init,
+       .test_cases = drm_connector_attach_broadcast_rgb_property_tests,
+};
+
 /*
  * Test that for a given mode, with 8bpc and an RGB output the TMDS
  * character rate is equal to the mode pixel clock.
@@ -945,8 +1059,10 @@ static struct kunit_suite 
drm_connector_hdmi_compute_mode_clock_test_suite = {
 kunit_test_suites(
        &drmm_connector_hdmi_init_test_suite,
        &drmm_connector_init_test_suite,
+       &drm_connector_attach_broadcast_rgb_property_test_suite,
        &drm_connector_hdmi_compute_mode_clock_test_suite,
        &drm_get_tv_mode_from_name_test_suite,
+       &drm_hdmi_connector_get_broadcast_rgb_name_test_suite,
        &drm_hdmi_connector_get_output_format_name_test_suite
 );
 

-- 
2.43.2

Reply via email to