Add some KUnit tests to check the color_format property is working as expected with the HDMI state helper.
Existing tests are extended to also test the DRM_COLOR_FORMAT_AUTO case, in order to avoid duplicating test cases. For the explicitly selected color format cases, parameterized tests are added. Signed-off-by: Nicolas Frattaroli <[email protected]> --- drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 191 +++++++++++++++++++++ 1 file changed, 191 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 4bdcea3c7435..f9648f9de46b 100644 --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c @@ -60,6 +60,23 @@ static struct drm_display_mode *find_preferred_mode(struct drm_connector *connec return preferred; } +static struct drm_display_mode *find_420_only_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_only(&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) { @@ -1547,6 +1564,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test) * RGB/10bpc * - The chosen mode has a TMDS character rate lower than the display * supports in YUV422/12bpc. + * - The HDMI connector state's color format property is unset (i.e. AUTO) * * Then we will prefer to keep the RGB format with a lower bpc over * picking YUV422. @@ -1609,6 +1627,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit conn_state = conn->state; KUNIT_ASSERT_NOT_NULL(test, conn_state); + KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_COLOR_FORMAT_AUTO); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); @@ -1626,6 +1645,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit * RGB/8bpc * - The chosen mode has a TMDS character rate lower than the display * supports in YUV420/12bpc. + * - The HDMI connector state's color format property is unset (i.e. AUTO) * * Then we will prefer to keep the RGB format with a lower bpc over * picking YUV420. @@ -1687,6 +1707,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit conn_state = conn->state; KUNIT_ASSERT_NOT_NULL(test, conn_state); + KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_COLOR_FORMAT_AUTO); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8); KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB); @@ -2198,6 +2219,172 @@ static void drm_test_check_disable_connector(struct kunit *test) drm_modeset_acquire_fini(&ctx); } +struct color_format_test_param { + enum drm_color_format fmt; + enum hdmi_colorspace expected; + int expected_ret; + const char *desc; +}; + +/* Test that if: + * - an HDMI connector supports RGB, YUV444, YUV422, and YUV420 + * - the display supports RGB, YUV444, YUV422, and YUV420 + * - the "color format" property is set + * then, for the preferred mode, for a given "color format" option: + * - DRM_COLOR_FORMAT_AUTO results in an HDMI output format of RGB + * - DRM_COLOR_FORMAT_YCBCR422 results in an HDMI output format of YUV422 + * - DRM_COLOR_FORMAT_YCBCR420 results in an HDMI output format of YUV420 + * - DRM_COLOR_FORMAT_YCBCR444 results in an HDMI output format of YUV444 + * - DRM_COLOR_FORMAT_RGB results in an HDMI output format of RGB + */ +static void drm_test_check_hdmi_color_format(struct kunit *test) +{ + const struct color_format_test_param *param = test->param_value; + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_crtc_state *crtc_state; + struct drm_atomic_state *state; + struct drm_display_info *info; + struct drm_display_mode *preferred; + int ret; + + priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV420) | + BIT(HDMI_COLORSPACE_YUV444), + 12, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm_modeset_acquire_init(&ctx, 0); + + KUNIT_ASSERT_TRUE(test, priv->connector.ycbcr_420_allowed); + + info = &priv->connector.display_info; + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info); + preferred = find_preferred_mode(&priv->connector); + KUNIT_ASSERT_TRUE(test, drm_mode_is_420(info, preferred)); + + state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + conn_state = drm_atomic_get_connector_state(state, &priv->connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->color_format = param->fmt; + + ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc); + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state = drm_atomic_get_crtc_state(state, priv->crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + ret = drm_atomic_set_mode_for_crtc(crtc_state, preferred); + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state->enable = true; + crtc_state->active = true; + + ret = drm_atomic_check_only(state); + KUNIT_EXPECT_EQ(test, ret, param->expected_ret); + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +static const struct color_format_test_param hdmi_color_format_params[] = { + { DRM_COLOR_FORMAT_AUTO, HDMI_COLORSPACE_RGB, 0, "AUTO -> RGB" }, + { DRM_COLOR_FORMAT_YCBCR422, HDMI_COLORSPACE_YUV422, 0, "YCBCR422 -> YUV422" }, + { DRM_COLOR_FORMAT_YCBCR420, HDMI_COLORSPACE_YUV420, 0, "YCBCR420 -> YUV420" }, + { DRM_COLOR_FORMAT_YCBCR444, HDMI_COLORSPACE_YUV444, 0, "YCBCR444 -> YUV444" }, + { DRM_COLOR_FORMAT_RGB444, HDMI_COLORSPACE_RGB, 0, "RGB -> RGB" }, +}; + +KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format, hdmi_color_format_params, desc); + +/* Test that if: + * - the HDMI connector supports RGB, YUV422, YUV420, and YUV444 + * - the display has a YUV420-only mode + * - the "color format" property is explicitly set (i.e. !AUTO) + * then: + * - color format DRM_COLOR_FORMAT_RGB will fail drm_atomic_check_only for the + * YUV420-only mode with -EINVAL + * - color format DRM_COLOR_FORMAT_YCBCR444 will fail drm_atomic_check_only for + * the YUV420-only mode with -EINVAL + * - color format DRM_COLOR_FORMAT_YCBCR422 will fail drm_atomic_check_only for + * the YUV420-only mode with -EINVAL + * - color format DRM_COLOR_FORMAT_YCBCR420 passes drm_atomic_check_only for + * the YUV420-only mode + */ +static void drm_test_check_hdmi_color_format_420_only(struct kunit *test) +{ + const struct color_format_test_param *param = test->param_value; + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector_state *conn_state; + struct drm_modeset_acquire_ctx ctx; + struct drm_crtc_state *crtc_state; + struct drm_atomic_state *state; + struct drm_display_mode *dank; + int ret; + + priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test, + BIT(HDMI_COLORSPACE_RGB) | + BIT(HDMI_COLORSPACE_YUV422) | + BIT(HDMI_COLORSPACE_YUV420) | + BIT(HDMI_COLORSPACE_YUV444), + 12, + &dummy_connector_hdmi_funcs, + test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm_modeset_acquire_init(&ctx, 0); + + dank = find_420_only_mode(&priv->connector); + KUNIT_ASSERT_NOT_NULL(test, dank); + + state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + conn_state = drm_atomic_get_connector_state(state, &priv->connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); + + conn_state->color_format = param->fmt; + + ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc); + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state = drm_atomic_get_crtc_state(state, priv->crtc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state); + + ret = drm_atomic_set_mode_for_crtc(crtc_state, dank); + KUNIT_ASSERT_EQ(test, ret, 0); + + crtc_state->enable = true; + crtc_state->active = true; + + ret = drm_atomic_check_only(state); + KUNIT_EXPECT_EQ(test, ret, param->expected_ret); + if (!param->expected_ret) + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +}; + +static const struct color_format_test_param hdmi_color_format_420_only_params[] = { + { DRM_COLOR_FORMAT_RGB444, HDMI_COLORSPACE_RGB, -EINVAL, "RGB should fail" }, + { DRM_COLOR_FORMAT_YCBCR444, HDMI_COLORSPACE_YUV444, -EINVAL, "YUV444 should fail" }, + { DRM_COLOR_FORMAT_YCBCR422, HDMI_COLORSPACE_YUV422, -EINVAL, "YUV422 should fail" }, + { DRM_COLOR_FORMAT_YCBCR420, HDMI_COLORSPACE_YUV420, 0, "YUV420 should work" }, +}; + +KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format_420_only, + hdmi_color_format_420_only_params, desc); + static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = { KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode), KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1), @@ -2227,6 +2414,10 @@ 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_PARAM(drm_test_check_hdmi_color_format, + check_hdmi_color_format_gen_params), + KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only, + check_hdmi_color_format_420_only_gen_params), /* * TODO: We should have tests to check that a change in the * format triggers a CRTC mode change just like we do for the -- 2.52.0
