RE: [PATCH] drm/amd/display: Don't replace a sink mode that shares the native totals

From: Li, Roman

Date: Mon Oct 05 2026 - 12:02:21 EST


Public

Reviewed-by: Roman Li <roman.li@xxxxxxx>

> -----Original Message-----
> From: amd-gfx <amd-gfx-bounces@xxxxxxxxxxxxxxxxxxxxx> On Behalf Of Adrian
> Betschart
> Sent: Friday, September 25, 2026 3:48 AM
> To: amd-gfx@xxxxxxxxxxxxxxxxxxxxx
> Cc: Wentland, Harry <Harry.Wentland@xxxxxxx>; Li, Sun peng (Leo)
> <Sunpeng.Li@xxxxxxx>; Rodrigo Siqueira <siqueira@xxxxxxxxxx>; Deucher,
> Alexander <Alexander.Deucher@xxxxxxx>; Koenig, Christian
> <Christian.Koenig@xxxxxxx>; David Airlie <airlied@xxxxxxxxx>; Simona Vetter
> <simona@xxxxxxxx>; dri-devel@xxxxxxxxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx
> Subject: [PATCH] drm/amd/display: Don't replace a sink mode that shares the
> native totals
>
> decide_crtc_timing_for_drm_display_mode() copies the native mode's CRTC timing
> into the requested mode when clock, htotal and vtotal match.
> That is meant for the modes amdgpu inserts itself:
> amdgpu_dm_create_common_mode() duplicates the native mode and changes only
> hdisplay and vdisplay, so those are sent with the native timing and scaled.
>
> A sink can also offer a real mode with the same clock and totals as its native mode.
> CTA-861 VIC 102 (4096x2160@60) and VIC 97
> (3840x2160@60) both use 594 MHz and 4400x2250. With 3840x2160@60 as the
> preferred mode, a 4096x2160@60 request goes out with the 3840x2160 timing and
> the framebuffer scaled into it (dst 3840x2025 at y=67), while the AVI InfoFrame still
> carries VIC 102. A JVC projector then reports 3840x2160 and shows a corrupted
> right edge. 4096x2160@24, whose totals differ, is sent and displayed correctly.
>
> Inserted modes keep the native sync positions; a real mode with its own active
> width does not. Compare those too, so only inserted modes are patched.
>
> Fixes: 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)")
> Signed-off-by: Adrian Betschart <adrian.betschart@xxxxxxxxxxxx>
> Assisted-by: Claude Code:claude-opus-5-5
> ---
> Tested on an RX 7600 (7.2.4 backport) with a JVC projector behind an HDFury
> VRROOM: 4096x2160@60 now arrives as 4096x2160 with a clean right edge;
> 3840x2160@60 and 7680x4320@60 are unchanged. KUnit
> amdgpu_dm_connector*: 360/360.
>
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 7 +++-
> .../tests/amdgpu_dm_connector_test.c | 42 +++++++++++++++++++
> 2 files changed, 48 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index 7ebf7216b499..7db85bcebecd 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -996,10 +996,15 @@ decide_crtc_timing_for_drm_display_mode(struct
> drm_display_mode *drm_mode,
> const struct drm_display_mode *native_mode,
> bool scale_enabled)
> {
> + /* Inserted modes copy the native sync; a sink mode with equal totals
> +may not */
> if (scale_enabled || (
> native_mode->clock == drm_mode->clock &&
> native_mode->htotal == drm_mode->htotal &&
> - native_mode->vtotal == drm_mode->vtotal)) {
> + native_mode->vtotal == drm_mode->vtotal &&
> + native_mode->hsync_start == drm_mode->hsync_start &&
> + native_mode->hsync_end == drm_mode->hsync_end &&
> + native_mode->vsync_start == drm_mode->vsync_start &&
> + native_mode->vsync_end == drm_mode->vsync_end)) {
> if (native_mode->crtc_clock)
> copy_crtc_timing_for_drm_display_mode(native_mode,
> drm_mode);
> } else {
> diff --git
> a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
> b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
> index bd55d943e4e5..04e0afd7aa71 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_te
> +++ st.c
> @@ -1468,6 +1468,46 @@ static void
> dm_test_decide_crtc_timing_no_crtc_clock(struct kunit *test)
> KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 0); }
>
> +static void dm_test_decide_crtc_timing_sink_mode_same_totals(struct
> +kunit *test) {
> + struct drm_display_mode native_mode = {
> + DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000,
> 3840, 4016, 4104,
> + 4400, 0, 2160, 2168, 2178, 2250, 0,
> + DRM_MODE_FLAG_PHSYNC |
> DRM_MODE_FLAG_PVSYNC) };
> + struct drm_display_mode drm_mode = {
> + DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000,
> 4096, 4184, 4272,
> + 4400, 0, 2160, 2168, 2178, 2250, 0,
> + DRM_MODE_FLAG_PHSYNC |
> DRM_MODE_FLAG_PVSYNC) };
> +
> + drm_mode_set_crtcinfo(&native_mode, 0);
> + drm_mode_set_crtcinfo(&drm_mode, 0);
> +
> + decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode,
> +false);
> +
> + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 4096);
> + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hsync_start, 4184); }
> +
> +static void dm_test_decide_crtc_timing_inserted_mode(struct kunit
> +*test) {
> + struct drm_display_mode native_mode = {
> + DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000,
> 3840, 4016, 4104,
> + 4400, 0, 2160, 2168, 2178, 2250, 0,
> + DRM_MODE_FLAG_PHSYNC |
> DRM_MODE_FLAG_PVSYNC) };
> + struct drm_display_mode drm_mode;
> +
> + drm_mode_set_crtcinfo(&native_mode, 0);
> + drm_mode = native_mode;
> + drm_mode.hdisplay = 1920;
> + drm_mode.vdisplay = 1080;
> + drm_mode_set_crtcinfo(&drm_mode, 0);
> +
> + decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode,
> +false);
> +
> + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 3840);
> + KUNIT_EXPECT_EQ(test, drm_mode.crtc_vdisplay, 2160); }
> +
> /* Tests for amdgpu_dm_connector_funcs_reset() */
>
> static const struct drm_connector_funcs dm_test_connector_funcs = { @@ -
> 10342,6 +10382,8 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
> KUNIT_CASE(dm_test_decide_crtc_timing_matching_mode),
> KUNIT_CASE(dm_test_decide_crtc_timing_no_copy),
> KUNIT_CASE(dm_test_decide_crtc_timing_no_crtc_clock),
> + KUNIT_CASE(dm_test_decide_crtc_timing_sink_mode_same_totals),
> + KUNIT_CASE(dm_test_decide_crtc_timing_inserted_mode),
> /* amdgpu_dm_connector_funcs_reset */
> KUNIT_CASE(dm_test_funcs_reset_sets_defaults),
> KUNIT_CASE(dm_test_funcs_reset_edp_abm_level),
> --
> 2.55.0