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.

phy: rockchip: samsung-hdptx: Restrict altering TMDS char rate via CCF

Although, in theory, the clock provider functionality could be enabled
as a standalone driver feature, in practice it is unlikely that it would
be ever needed separately from the common PHY related features, i.e.
making use of the PHY PLL as an alternative and more accurate clock
source for display modes handling. Which means the PLL will be always
programmed according to the TMDS char rate set via the HDMI PHY
configuration API.

Currently it's possible to freely adjust the rate via the clock API as
well, that is through clk_set_rate(). Making the clock read-only is not
feasible since we need to ensure any rate update done via the PHY
configuration API has been actually programmed into the hardware before
CCF accesses it. This would be normally done during phy_ops.power_on()
or clk_ops.prepare() callbacks, but it might happen that the former gets
fired too late and the latter only once, hence we need to keep handle it
via clk_ops.set_rate() as a fallback approach.

Prevent changing the TMDS character rate via CCF by letting
rk_hdptx_phy_clk_round_rate() always return the value set via
phy_configure(). To avoid breaking existing users, i.e. RK DW HDMI QP
bridge driver, until the switch to the HDMI PHY config based approach is
completed, introduce a temporary exception to the rule, toggled via the
new ->restrict_rate_change flag, which indicates whether phy_configure()
has been called or not.

Additionally, revert any unlikely rate change that might have occurred
between the calls to ->round_rate() and ->set_rate().

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-11-8cb1678e7663@collabora.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Cristian Ciocaltea and committed by
Vinod Koul
6efbd0f4 2392050a

+40 -12
+40 -12
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
··· 402 402 /* clk provider */ 403 403 struct clk_hw hw; 404 404 unsigned long rate; 405 + bool restrict_rate_change; 405 406 406 407 atomic_t usage_count; 407 408 ··· 1759 1758 1760 1759 if (mode != PHY_MODE_DP) { 1761 1760 ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi); 1762 - if (ret) 1761 + if (ret) { 1763 1762 dev_err(hdptx->dev, "invalid hdmi params for phy configure\n"); 1764 - else 1763 + } else { 1765 1764 hdptx->hdmi_cfg = opts->hdmi; 1765 + hdptx->restrict_rate_change = true; 1766 + } 1766 1767 return ret; 1767 1768 } 1768 1769 ··· 1851 1848 static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, 1852 1849 unsigned long *parent_rate) 1853 1850 { 1854 - int i; 1851 + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 1855 1852 1856 - if (rate > HDMI20_MAX_RATE) 1857 - return rate; 1853 + /* 1854 + * FIXME: Temporarily allow altering TMDS char rate via CCF. 1855 + * To be dropped as soon as the RK DW HDMI QP bridge driver 1856 + * switches to make use of phy_configure(). 1857 + */ 1858 + if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) { 1859 + struct phy_configure_opts_hdmi hdmi = { 1860 + .tmds_char_rate = rate, 1861 + }; 1862 + int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi); 1858 1863 1859 - for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) 1860 - if (rate == ropll_tmds_cfg[i].rate) 1861 - break; 1864 + if (ret) 1865 + return ret; 1862 1866 1863 - if (i == ARRAY_SIZE(ropll_tmds_cfg) && 1864 - !rk_hdptx_phy_clk_pll_calc(rate, NULL)) 1865 - return -EINVAL; 1867 + hdptx->hdmi_cfg = hdmi; 1868 + } 1866 1869 1867 - return rate; 1870 + /* 1871 + * The TMDS char rate shall be adjusted via phy_configure() only, 1872 + * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with 1873 + * a different rate argument. 1874 + */ 1875 + return hdptx->hdmi_cfg.tmds_char_rate; 1868 1876 } 1869 1877 1870 1878 static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, ··· 1883 1869 { 1884 1870 struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); 1885 1871 1872 + /* Revert any unlikely TMDS char rate change since round_rate() */ 1873 + if (hdptx->hdmi_cfg.tmds_char_rate != rate) { 1874 + dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n", 1875 + rate, hdptx->hdmi_cfg.tmds_char_rate); 1876 + hdptx->hdmi_cfg.tmds_char_rate = rate; 1877 + } 1878 + 1879 + /* 1880 + * The TMDS char rate would be normally programmed in HW during 1881 + * phy_ops.power_on() or clk_ops.prepare() callbacks, but it might 1882 + * happen that the former gets fired too late, i.e. after this call, 1883 + * while the latter being executed only once, i.e. when clock remains 1884 + * in the prepared state during rate changes. 1885 + */ 1886 1886 return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); 1887 1887 } 1888 1888