From c01ccf91b257741e9edc374a465126bae9ae4711 Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Thu, 3 Sep 2026 05:47:58 +0000 Subject: [PATCH] phy: freescale: fsl-samsung-hdmi: initialize default rate The HDMI PHY clock reports 74.25 MHz when cur_cfg is unset, but does not establish that rate in hardware. The common clock framework caches the reported rate when registering the clock and skips a first clk_set_rate(74250000) request because the rate appears unchanged. Consequently, a display whose initial mode uses a 74.25 MHz pixel clock can leave the PHY with its bootloader register state and receive no TMDS signal. Requesting another rate first avoids the issue because the set_rate callback configures the PHY. Program the 74.25 MHz table entry with the reference clock enabled before registering the clock provider. recalc_rate can then report the configured rate, and a skipped first rate change is safe. Also enable the reference clock when restoring that configuration on resume. Fixes: 6ad082bee902 ("phy: freescale: add Samsung HDMI PHY") Signed-off-by: Aristo Chen Link: https://patch.msgid.link/20260903054811.9720-1-aristo.chen@canonical.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 59 +++++++++++++++----- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c index ded142020e72..02539ad0b0fe 100644 --- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c @@ -44,6 +44,8 @@ #define MHZ (1000UL * 1000UL) #endif +#define PHY_DEFAULT_RATE 74250000 + #define PHY_PLL_DIV_REGS_NUM 7 struct phy_config { @@ -489,17 +491,6 @@ static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, return ret; } -static unsigned long phy_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); - - if (!phy->cur_cfg) - return 74250000; - - return phy->cur_cfg->pixclk; -} - /* Helper function to lookup the available fractional-divider rate */ static const struct phy_config *fsl_samsung_hdmi_phy_lookup_rate(unsigned long rate) { @@ -520,6 +511,14 @@ static const struct phy_config *fsl_samsung_hdmi_phy_lookup_rate(unsigned long r &phy_pll_cfg[i] : &phy_pll_cfg[i+1]); } +static unsigned long phy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + + return phy->cur_cfg->pixclk; +} + static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned long rate, u8 p, u16 m, u8 s) { @@ -640,6 +639,7 @@ static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy) static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev) { + const struct phy_config *default_cfg; struct fsl_samsung_hdmi_phy *phy; int ret; @@ -664,6 +664,23 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev) return dev_err_probe(phy->dev, PTR_ERR(phy->refclk), "failed to get ref clk\n"); + /* + * Establish the rate reported by recalc_rate() before registering the + * clock. Otherwise CCF may skip the first set_rate() when it requests + * the assumed default rate, leaving the PHY unconfigured. + */ + ret = clk_prepare_enable(phy->refclk); + if (ret) + return dev_err_probe(phy->dev, ret, + "failed to enable ref clk\n"); + + default_cfg = fsl_samsung_hdmi_phy_lookup_rate(PHY_DEFAULT_RATE); + ret = fsl_samsung_hdmi_phy_configure(phy, default_cfg); + clk_disable_unprepare(phy->refclk); + if (ret) + return dev_err_probe(phy->dev, ret, + "failed to configure default rate\n"); + pm_runtime_get_noresume(phy->dev); pm_runtime_set_active(phy->dev); pm_runtime_enable(phy->dev); @@ -702,7 +719,7 @@ static int __maybe_unused fsl_samsung_hdmi_phy_suspend(struct device *dev) static int __maybe_unused fsl_samsung_hdmi_phy_resume(struct device *dev) { struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); - int ret = 0; + int ret; ret = clk_prepare_enable(phy->apbclk); if (ret) { @@ -710,11 +727,23 @@ static int __maybe_unused fsl_samsung_hdmi_phy_resume(struct device *dev) return ret; } - if (phy->cur_cfg) - ret = fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); + if (!phy->cur_cfg) + return 0; + ret = clk_prepare_enable(phy->refclk); + if (ret) { + dev_err(phy->dev, "failed to enable ref clk\n"); + goto disable_apbclk; + } + + ret = fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); + clk_disable_unprepare(phy->refclk); + if (!ret) + return 0; + +disable_apbclk: + clk_disable_unprepare(phy->apbclk); return ret; - } static DEFINE_RUNTIME_DEV_PM_OPS(fsl_samsung_hdmi_phy_pm_ops,