Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/meson: fix more rounding issues with 59.94Hz modes

Commit 1017560164b6 ("drm/meson: use unsigned long long / Hz for
frequency types") attempts to resolve video playback using 59.94Hz.
using YUV420 by changing the clock calculation to use
Hz instead of kHz (thus yielding more precision).

The basic calculation itself is correct, however the comparisions in
meson_vclk_vic_supported_freq() and meson_vclk_setup() don't work
anymore for 59.94Hz modes (using the freq * 1000 / 1001 logic). For
example, drm/edid specifies a 593407kHz clock for 3840x2160@59.94Hz.
With the mentioend commit we convert this to Hz. Then meson_vclk
tries to find a matchig "params" entry (as the clock setup code
currently only supports specific frequencies) by taking the venc_freq
from the params and calculating the "alt frequency" (used for the
59.94Hz modes) from it, which is:
(594000000Hz * 1000) / 1001 = 593406593Hz

Similar calculation is applied to the phy_freq (TMDS clock), which is 10
times the pixel clock.

Implement a new meson_vclk_freqs_are_matching_param() function whose
purpose is to compare if the requested and calculated frequencies. They
may not match exactly (for the reasons mentioned above). Allow the
clocks to deviate slightly to make the 59.94Hz modes again.

Fixes: 1017560164b6 ("drm/meson: use unsigned long long / Hz for frequency types")
Reported-by: Christian Hewitt <christianshewitt@gmail.com>
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://lore.kernel.org/r/20250609202751.962208-1-martin.blumenstingl@googlemail.com

authored by

Martin Blumenstingl and committed by
Neil Armstrong
0cee6c4d faf2f838

+34 -21
+34 -21
drivers/gpu/drm/meson/meson_vclk.c
··· 110 110 #define HDMI_PLL_LOCK BIT(31) 111 111 #define HDMI_PLL_LOCK_G12A (3 << 30) 112 112 113 - #define PIXEL_FREQ_1000_1001(_freq) \ 114 - DIV_ROUND_CLOSEST_ULL((_freq) * 1000ULL, 1001ULL) 115 - #define PHY_FREQ_1000_1001(_freq) \ 116 - (PIXEL_FREQ_1000_1001(DIV_ROUND_DOWN_ULL(_freq, 10ULL)) * 10) 113 + #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST_ULL((_freq) * 1000ULL, 1001ULL) 117 114 118 115 /* VID PLL Dividers */ 119 116 enum { ··· 769 772 pll_freq); 770 773 } 771 774 775 + static bool meson_vclk_freqs_are_matching_param(unsigned int idx, 776 + unsigned long long phy_freq, 777 + unsigned long long vclk_freq) 778 + { 779 + DRM_DEBUG_DRIVER("i = %d vclk_freq = %lluHz alt = %lluHz\n", 780 + idx, params[idx].vclk_freq, 781 + FREQ_1000_1001(params[idx].vclk_freq)); 782 + DRM_DEBUG_DRIVER("i = %d phy_freq = %lluHz alt = %lluHz\n", 783 + idx, params[idx].phy_freq, 784 + FREQ_1000_1001(params[idx].phy_freq)); 785 + 786 + /* Match strict frequency */ 787 + if (phy_freq == params[idx].phy_freq && 788 + vclk_freq == params[idx].vclk_freq) 789 + return true; 790 + 791 + /* Match 1000/1001 variant: vclk deviation has to be less than 1kHz 792 + * (drm EDID is defined in 1kHz steps, so everything smaller must be 793 + * rounding error) and the PHY freq deviation has to be less than 794 + * 10kHz (as the TMDS clock is 10 times the pixel clock, so anything 795 + * smaller must be rounding error as well). 796 + */ 797 + if (abs(vclk_freq - FREQ_1000_1001(params[idx].vclk_freq)) < 1000 && 798 + abs(phy_freq - FREQ_1000_1001(params[idx].phy_freq)) < 10000) 799 + return true; 800 + 801 + /* no match */ 802 + return false; 803 + } 804 + 772 805 enum drm_mode_status 773 806 meson_vclk_vic_supported_freq(struct meson_drm *priv, 774 807 unsigned long long phy_freq, ··· 817 790 } 818 791 819 792 for (i = 0 ; params[i].pixel_freq ; ++i) { 820 - DRM_DEBUG_DRIVER("i = %d vclk_freq = %lluHz alt = %lluHz\n", 821 - i, params[i].vclk_freq, 822 - PIXEL_FREQ_1000_1001(params[i].vclk_freq)); 823 - DRM_DEBUG_DRIVER("i = %d phy_freq = %lluHz alt = %lluHz\n", 824 - i, params[i].phy_freq, 825 - PHY_FREQ_1000_1001(params[i].phy_freq)); 826 - /* Match strict frequency */ 827 - if (phy_freq == params[i].phy_freq && 828 - vclk_freq == params[i].vclk_freq) 829 - return MODE_OK; 830 - /* Match 1000/1001 variant */ 831 - if (phy_freq == PHY_FREQ_1000_1001(params[i].phy_freq) && 832 - vclk_freq == PIXEL_FREQ_1000_1001(params[i].vclk_freq)) 793 + if (meson_vclk_freqs_are_matching_param(i, phy_freq, vclk_freq)) 833 794 return MODE_OK; 834 795 } 835 796 ··· 1090 1075 } 1091 1076 1092 1077 for (freq = 0 ; params[freq].pixel_freq ; ++freq) { 1093 - if ((phy_freq == params[freq].phy_freq || 1094 - phy_freq == PHY_FREQ_1000_1001(params[freq].phy_freq)) && 1095 - (vclk_freq == params[freq].vclk_freq || 1096 - vclk_freq == PIXEL_FREQ_1000_1001(params[freq].vclk_freq))) { 1078 + if (meson_vclk_freqs_are_matching_param(freq, phy_freq, 1079 + vclk_freq)) { 1097 1080 if (vclk_freq != params[freq].vclk_freq) 1098 1081 vic_alternate_clock = true; 1099 1082 else