From: Relja Vojvodic rvojvodi@amd.com
[ Upstream commit 002a612023c8b105bd3829d81862dee04368d6de ]
[Why] -Pipe splitting allows for clocks to be reduced, but when using TMDS 420, reduced clocks lead to missed clocks cycles on clock resyncing
[How] -Impose a minimum clock when using TMDS 420
Reviewed-by: Chris Park chris.park@amd.com Signed-off-by: Relja Vojvodic rvojvodi@amd.com Signed-off-by: Alex Hung alex.hung@amd.com Tested-by: Dan Wheeler daniel.wheeler@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
- What it fixes - Prevents missed clock cycles during clock resync when using HDMI TMDS with YCbCr 4:2:0 and ODM pipe splitting (commit message explicitly cites user-visible failures). This is a correctness fix, not a feature.
- What changed (code-level) - `CalculateRequiredDispclk` now takes `isTMDS420` and clamps the required display clock to a minimum of `PixelClock / 2.0` when TMDS 4:2:0 is used: - Function signature adds the flag: drivers/gpu/drm/amd/display/dc/d ml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c:1239 - The ODM-scaling branches are unchanged (e.g., 4:1 → `PixelClock / 4.0` at 1247), but a new clamp is applied: - TMDS-420 check: 1256 - Clamp: `DispClk = math_max2(DispClk, PixelClock / 2.0);` at 1258 - `CalculateODMMode` detects TMDS 4:2:0 and passes the new flag to all `CalculateRequiredDispclk` calls: - TMDS-420 detection: `(OutFormat == dml2_420 && Output == dml2_hdmi)` at 4134 - Updated calls: 4136, 4137, 4138, 4139
- Why it’s needed - ODM combine modes lower pipe clocks (e.g., 3:1 → `PixelClock/3`, 4:1 → `PixelClock/4`). For HDMI TMDS 4:2:0 (two pixels per TMDS clock), letting DISPCLK drop below `PixelClock/2` can cause resync to miss clock cycles. The clamp ensures DISPCLK never falls below the effective minimum for TMDS 420, avoiding those failures.
- Scope and side effects - Scope is tightly limited to DML2.1 DCN4 calculations for AMD display, and only when: - Output is HDMI and the output format is 4:2:0 (line 4134). - ODM pipe splitting is being considered (the affected DISPCLK computations at 4136–4139). - No architectural changes; static function signature change is local to the file, with all callers updated. - Potential behavioral change: ODM 3:1 or 4:1 modes may no longer be selected if the clamped DISPCLK would exceed the device’s `MaxDispclk`. That trades an unstable configuration (missed clocks) for a safe one (bypass or 2:1), which is appropriate for stable.
- Risk assessment - Small, localized change; clearly guarded by `isTMDS420`. No API, ABI, or cross-subsystem impact. - Aligns with existing math for TMDS 4:2:0 behavior elsewhere (e.g., other code also treats 4:2:0 as 2 pixels per clock). - The worst case is a slightly higher required DISPCLK or a different ODM choice, which avoids the reported failure mode.
- Stable backport criteria - Fixes a real user-visible bug (missed clock cycles/resync issues). - Minimal and contained to one source file in AMD display’s DML2.1 path. - No new features or architectural changes. - Touches a GPU driver (not a core kernel subsystem), limiting regression blast radius. - Even without a Fixes: tag, the change is a clear bugfix with strong rationale.
Given the above, this is a good candidate for backporting to stable trees that include the DML2.1 DCN4 code path.
.../src/dml2_core/dml2_core_dcn4_calcs.c | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index b9cff21985110..bf62d42b3f78b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -1238,18 +1238,27 @@ static void CalculateDETBufferSize(
static double CalculateRequiredDispclk( enum dml2_odm_mode ODMMode, - double PixelClock) + double PixelClock, + bool isTMDS420) { + double DispClk;
if (ODMMode == dml2_odm_mode_combine_4to1) { - return PixelClock / 4.0; + DispClk = PixelClock / 4.0; } else if (ODMMode == dml2_odm_mode_combine_3to1) { - return PixelClock / 3.0; + DispClk = PixelClock / 3.0; } else if (ODMMode == dml2_odm_mode_combine_2to1) { - return PixelClock / 2.0; + DispClk = PixelClock / 2.0; } else { - return PixelClock; + DispClk = PixelClock; + } + + if (isTMDS420) { + double TMDS420MinPixClock = PixelClock / 2.0; + DispClk = math_max2(DispClk, TMDS420MinPixClock); } + + return DispClk; }
static double TruncToValidBPP( @@ -4122,11 +4131,12 @@ static noinline_for_stack void CalculateODMMode( bool success; bool UseDSC = DSCEnable && (NumberOfDSCSlices > 0); enum dml2_odm_mode DecidedODMMode; + bool isTMDS420 = (OutFormat == dml2_420 && Output == dml2_hdmi);
- SurfaceRequiredDISPCLKWithoutODMCombine = CalculateRequiredDispclk(dml2_odm_mode_bypass, PixelClock); - SurfaceRequiredDISPCLKWithODMCombineTwoToOne = CalculateRequiredDispclk(dml2_odm_mode_combine_2to1, PixelClock); - SurfaceRequiredDISPCLKWithODMCombineThreeToOne = CalculateRequiredDispclk(dml2_odm_mode_combine_3to1, PixelClock); - SurfaceRequiredDISPCLKWithODMCombineFourToOne = CalculateRequiredDispclk(dml2_odm_mode_combine_4to1, PixelClock); + SurfaceRequiredDISPCLKWithoutODMCombine = CalculateRequiredDispclk(dml2_odm_mode_bypass, PixelClock, isTMDS420); + SurfaceRequiredDISPCLKWithODMCombineTwoToOne = CalculateRequiredDispclk(dml2_odm_mode_combine_2to1, PixelClock, isTMDS420); + SurfaceRequiredDISPCLKWithODMCombineThreeToOne = CalculateRequiredDispclk(dml2_odm_mode_combine_3to1, PixelClock, isTMDS420); + SurfaceRequiredDISPCLKWithODMCombineFourToOne = CalculateRequiredDispclk(dml2_odm_mode_combine_4to1, PixelClock, isTMDS420); #ifdef __DML_VBA_DEBUG__ DML_LOG_VERBOSE("DML::%s: ODMUse = %d\n", __func__, ODMUse); DML_LOG_VERBOSE("DML::%s: Output = %d\n", __func__, Output);