Skip to content

Commit 6efbd0f

Browse files
cristiccvinodkoul
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 2392050 commit 6efbd0f

File tree

1 file changed

+40
-12
lines changed

1 file changed

+40
-12
lines changed

drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ struct rk_hdptx_phy {
402402
/* clk provider */
403403
struct clk_hw hw;
404404
unsigned long rate;
405+
bool restrict_rate_change;
405406

406407
atomic_t usage_count;
407408

@@ -1758,10 +1759,12 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
17581759

17591760
if (mode != PHY_MODE_DP) {
17601761
ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
1761-
if (ret)
1762+
if (ret) {
17621763
dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
1763-
else
1764+
} else {
17641765
hdptx->hdmi_cfg = opts->hdmi;
1766+
hdptx->restrict_rate_change = true;
1767+
}
17651768
return ret;
17661769
}
17671770

@@ -1848,27 +1851,52 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
18481851
static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
18491852
unsigned long *parent_rate)
18501853
{
1851-
int i;
1854+
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
18521855

1853-
if (rate > HDMI20_MAX_RATE)
1854-
return rate;
1856+
/*
1857+
* FIXME: Temporarily allow altering TMDS char rate via CCF.
1858+
* To be dropped as soon as the RK DW HDMI QP bridge driver
1859+
* switches to make use of phy_configure().
1860+
*/
1861+
if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) {
1862+
struct phy_configure_opts_hdmi hdmi = {
1863+
.tmds_char_rate = rate,
1864+
};
1865+
int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi);
18551866

1856-
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
1857-
if (rate == ropll_tmds_cfg[i].rate)
1858-
break;
1867+
if (ret)
1868+
return ret;
18591869

1860-
if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
1861-
!rk_hdptx_phy_clk_pll_calc(rate, NULL))
1862-
return -EINVAL;
1870+
hdptx->hdmi_cfg = hdmi;
1871+
}
18631872

1864-
return rate;
1873+
/*
1874+
* The TMDS char rate shall be adjusted via phy_configure() only,
1875+
* hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
1876+
* a different rate argument.
1877+
*/
1878+
return hdptx->hdmi_cfg.tmds_char_rate;
18651879
}
18661880

18671881
static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
18681882
unsigned long parent_rate)
18691883
{
18701884
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
18711885

1886+
/* Revert any unlikely TMDS char rate change since round_rate() */
1887+
if (hdptx->hdmi_cfg.tmds_char_rate != rate) {
1888+
dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n",
1889+
rate, hdptx->hdmi_cfg.tmds_char_rate);
1890+
hdptx->hdmi_cfg.tmds_char_rate = rate;
1891+
}
1892+
1893+
/*
1894+
* The TMDS char rate would be normally programmed in HW during
1895+
* phy_ops.power_on() or clk_ops.prepare() callbacks, but it might
1896+
* happen that the former gets fired too late, i.e. after this call,
1897+
* while the latter being executed only once, i.e. when clock remains
1898+
* in the prepared state during rate changes.
1899+
*/
18721900
return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
18731901
}
18741902

0 commit comments

Comments
 (0)