[PATCH v3 14/15] drm/tests: hdmi: Add max TMDS rate fallback tests for YUV420 mode
Maxime Ripard
mripard at kernel.org
Thu Apr 10 08:35:06 UTC 2025
On Wed, Mar 26, 2025 at 12:20:03PM +0200, Cristian Ciocaltea wrote:
> Provide tests to verify drm_atomic_helper_connector_hdmi_check() helper
> fallback behavior when using YUV420 output.
>
> Also rename drm_test_check_max_tmds_rate_{bpc|format}_fallback() to
> better differentiate from the newly introduced *_yuv420() variants.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
> drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 152 ++++++++++++++++++++-
> drivers/gpu/drm/tests/drm_kunit_edid.h | 110 +++++++++++++++
> 2 files changed, 258 insertions(+), 4 deletions(-)
>
> 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 3fae7ccf65309a1d8a4acf12de961713b9163096..99bedb2d6f555b3b140256000dfa7491d2a8f515 100644
> --- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
> +++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
> @@ -1224,7 +1224,7 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
> * Then we will pick the latter, and the computed TMDS character rate
> * will be equal to 1.25 times the mode pixel clock.
> */
> -static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test)
> +static void drm_test_check_max_tmds_rate_bpc_fallback_rgb(struct kunit *test)
> {
> struct drm_atomic_helper_connector_hdmi_priv *priv;
> struct drm_modeset_acquire_ctx ctx;
> @@ -1279,6 +1279,75 @@ static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test)
> drm_modeset_acquire_fini(&ctx);
> }
>
> +/*
> + * Test that if:
> + * - We have an HDMI connector supporting both RGB and YUV420
I assume the monitor also supports both?
> + * - The chosen mode can be supported in YUV420 output format only
> + * - The chosen mode has a TMDS character rate higher than the display
> + * supports in YUV420/12bpc
> + * - The chosen mode has a TMDS character rate lower than the display
> + * supports in YUV420/10bpc.
> + *
> + * Then we will pick the latter, and the computed TMDS character rate
> + * will be equal to 1.25 * 0.5 times the mode pixel clock.
> + */
> +static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
> +{
> + 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 *yuv420_only_mode;
> + unsigned long long rate;
> + struct drm_connector *conn;
> + struct drm_device *drm;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + priv = drm_kunit_helper_connector_hdmi_init_with_edid(test,
> + BIT(HDMI_COLORSPACE_RGB) |
> + BIT(HDMI_COLORSPACE_YUV420),
> + 12,
> + test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
> + KUNIT_ASSERT_NOT_NULL(test, priv);
> +
> + drm = &priv->drm;
> + crtc = priv->crtc;
> + conn = &priv->connector;
> + info = &conn->display_info;
> + KUNIT_ASSERT_TRUE(test, info->is_hdmi);
> + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
> + KUNIT_ASSERT_TRUE(test, conn->ycbcr_420_allowed);
> +
> + yuv420_only_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 95);
> + KUNIT_ASSERT_NOT_NULL(test, yuv420_only_mode);
> + KUNIT_ASSERT_TRUE(test, drm_mode_is_420_only(info, yuv420_only_mode));
> +
> + rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 12, HDMI_COLORSPACE_YUV420);
> + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
> +
> + rate = drm_hdmi_compute_mode_clock(yuv420_only_mode, 10, HDMI_COLORSPACE_YUV420);
> + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + ret = drm_kunit_helper_enable_crtc_connector(test, drm,
> + crtc, conn,
> + yuv420_only_mode,
> + &ctx);
> + KUNIT_EXPECT_EQ(test, ret, 0);
We need to handle EDEADLK
> +
> + conn_state = conn->state;
> + KUNIT_ASSERT_NOT_NULL(test, conn_state);
> +
> + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
> + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_YUV420);
> + KUNIT_EXPECT_EQ(test, conn_state->hdmi.tmds_char_rate, yuv420_only_mode->clock * 625);
> +
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> +}
> +
> /*
> * Test that if:
> * - We have an HDMI connector supporting both RGB and YUV422 and up to
> @@ -1292,7 +1361,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test)
> * Then we will prefer to keep the RGB format with a lower bpc over
> * picking YUV422.
> */
> -static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test)
> +static void drm_test_check_max_tmds_rate_format_fallback_yuv422(struct kunit *test)
> {
> struct drm_atomic_helper_connector_hdmi_priv *priv;
> struct drm_modeset_acquire_ctx ctx;
> @@ -1351,6 +1420,79 @@ static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test)
> drm_modeset_acquire_fini(&ctx);
> }
>
> +/*
> + * Test that if:
> + * - We have an HDMI connector supporting both RGB and YUV420 and up to
> + * 12 bpc
> + * - The chosen mode has a TMDS character rate higher than the display
> + * supports in RGB/10bpc but lower than the display supports in
> + * RGB/8bpc
> + * - The chosen mode has a TMDS character rate lower than the display
> + * supports in YUV420/12bpc.
> + *
> + * Then we will prefer to keep the RGB format with a lower bpc over
> + * picking YUV420.
> + */
> +static void drm_test_check_max_tmds_rate_format_fallback_yuv420(struct kunit *test)
Are you sure about the name here? It looks like we're not testing the
YUV420 fallback at all?
> +{
> + 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;
> + unsigned long long rate;
> + struct drm_connector *conn;
> + struct drm_device *drm;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + priv = drm_kunit_helper_connector_hdmi_init_with_edid(test,
> + BIT(HDMI_COLORSPACE_RGB) |
> + BIT(HDMI_COLORSPACE_YUV420),
> + 12,
> + test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
> + KUNIT_ASSERT_NOT_NULL(test, priv);
> +
> + drm = &priv->drm;
> + crtc = priv->crtc;
> + conn = &priv->connector;
> + info = &conn->display_info;
> + KUNIT_ASSERT_TRUE(test, info->is_hdmi);
> + KUNIT_ASSERT_GT(test, info->max_tmds_clock, 0);
> + KUNIT_ASSERT_TRUE(test, conn->ycbcr_420_allowed);
> +
> + preferred = find_preferred_mode(conn);
> + KUNIT_ASSERT_NOT_NULL(test, preferred);
> + KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
> + KUNIT_ASSERT_TRUE(test, drm_mode_is_420_also(info, preferred));
> +
> + rate = drm_hdmi_compute_mode_clock(preferred, 8, HDMI_COLORSPACE_RGB);
> + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
> +
> + rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
> + KUNIT_ASSERT_GT(test, rate, info->max_tmds_clock * 1000);
> +
> + rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV420);
> + KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + ret = drm_kunit_helper_enable_crtc_connector(test, drm,
> + crtc, conn,
> + preferred,
> + &ctx);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + conn_state = conn->state;
> + KUNIT_ASSERT_NOT_NULL(test, conn_state);
> +
> + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
> + KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, HDMI_COLORSPACE_RGB);
> +
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> +}
> /*
> * Test that if a driver and screen supports RGB and YUV formats, and we
> * try to set the VIC 1 mode, we end up with 8bpc RGB even if we could
> @@ -1738,8 +1880,10 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
> KUNIT_CASE(drm_test_check_broadcast_rgb_crtc_mode_not_changed),
> KUNIT_CASE(drm_test_check_disable_connector),
> 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),
These name changes belong in a separate patch
> + KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_rgb),
> + KUNIT_CASE(drm_test_check_max_tmds_rate_bpc_fallback_yuv420),
> + KUNIT_CASE(drm_test_check_max_tmds_rate_format_fallback_yuv422),
> + KUNIT_CASE(drm_test_check_max_tmds_rate_format_fallback_yuv420),
We should also test what happens when the monitor or connector doesn't
support YUV420, and we'd still need to fallback. In such a case, we
should return an error.
> KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_changed),
> KUNIT_CASE(drm_test_check_output_bpc_crtc_mode_not_changed),
> KUNIT_CASE(drm_test_check_output_bpc_dvi),
> diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
> index ff316e6114d65c96b1338cd83bc0d8d9e6e143e9..8e9086df20c690f34623d7858c716032d77d0c26 100644
> --- a/drivers/gpu/drm/tests/drm_kunit_edid.h
> +++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
> @@ -695,4 +695,114 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
> 0x00, 0x00, 0x00, 0xca
> };
>
> +/*
> + * edid-decode (hex):
> + *
> + * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
> + * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
> + * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
> + * 01 01 01 01 01 01 04 74 00 30 f2 70 5a 80 b0 58
> + * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
> + * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 18
> + * 55 18 5e 22 00 0a 20 20 20 20 20 20 00 00 00 10
> + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ce
> + *
> + * 02 03 27 31 41 5f 6c 03 0c 00 10 00 78 44 20 00
> + * 00 01 03 6d d8 5d c4 01 44 80 07 00 00 00 00 00
> + * 00 e3 0f 01 00 e1 0e 00 00 00 00 00 00 00 00 00
> + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84
> + *
> + * ----------------
> + *
> + * Block 0, Base EDID:
> + * EDID Structure Version & Revision: 1.3
> + * Vendor & Product Identification:
> + * Manufacturer: LNX
> + * Model: 52
> + * Model year: 2025
> + * Basic Display Parameters & Features:
> + * Digital display
> + * Maximum image size: 96 cm x 54 cm
> + * Gamma: 2.20
> + * RGB color display
> + * Default (sRGB) color space is primary color space
> + * First detailed timing is the preferred timing
> + * Supports GTF timings within operating range
> + * Color Characteristics:
> + * Red : 0.6396, 0.3300
> + * Green: 0.2998, 0.5996
> + * Blue : 0.1503, 0.0595
> + * White: 0.3125, 0.3291
> + * Established Timings I & II:
> + * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz
> + * Standard Timings: none
> + * Detailed Timing Descriptors:
> + * DTD 1: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz (1600 mm x 900 mm)
> + * Hfront 176 Hsync 88 Hback 296 Hpol P
> + * Vfront 8 Vsync 10 Vback 72 Vpol P
> + * Display Product Name: 'Test EDID'
> + * Display Range Limits:
> + * Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 340 MHz
> + * Dummy Descriptor:
> + * Extension blocks: 1
> + * Checksum: 0xce
> + *
> + * ----------------
> + *
> + * Block 1, CTA-861 Extension Block:
> + * Revision: 3
> + * Supports YCbCr 4:4:4
> + * Supports YCbCr 4:2:2
> + * Native detailed modes: 1
> + * Video Data Block:
> + * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
> + * Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
> + * Source physical address: 1.0.0.0
> + * DC_48bit
> + * DC_36bit
> + * DC_30bit
> + * DC_Y444
> + * Maximum TMDS clock: 340 MHz
> + * Extended HDMI video details:
> + * Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
> + * Version: 1
> + * Maximum TMDS Character Rate: 340 MHz
> + * SCDC Present
> + * Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
> + * Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
> + * Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
> + * YCbCr 4:2:0 Capability Map Data Block:
> + * VIC 95: 3840x2160 30.000000 Hz 16:9 67.500 kHz 297.000000 MHz
> + * YCbCr 4:2:0 Video Data Block:
> + * Checksum: 0x84
> + */
> +static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
> + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
> + 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
> + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
> + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70,
> + 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
> + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44,
> + 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
> + 0x55, 0x18, 0x5e, 0x22, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
> + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xce, 0x02, 0x03, 0x27, 0x31,
> + 0x41, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00,
> + 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x44, 0x80, 0x07, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x01, 0x00, 0xe1, 0x0e, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x84
> +};
This should be a separate patch as well, but most importantly it's
pretty hard to know the difference with the one you introduced in a
previous patch. We should document it better than just with edid-decode.
Also, how did you generate it?
Maxime
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20250410/4e4e83e6/attachment-0001.sig>
More information about the dri-devel
mailing list