]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
phy: rockchip: samsung-hdptx: Compute clk rate from PLL config
authorCristian Ciocaltea <cristian.ciocaltea@collabora.com>
Mon, 12 Jan 2026 23:20:54 +0000 (01:20 +0200)
committerVinod Koul <vkoul@kernel.org>
Wed, 21 Jan 2026 08:41:57 +0000 (14:11 +0530)
Improve ->recalc_rate() callback of hdptx_phy_clk_ops to calculate the
initial clock rate based on the actual PHY PLL configuration as
retrieved from the related hardware registers.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Link: https://patch.msgid.link/20260113-phy-hdptx-frl-v6-7-8d5f97419c0b@collabora.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c

index 0a0e38e95a37f21e40b164c55a9b6af584a8c05f..3cc8976e10e63f909d4a3e999d95ea4dc1bf3916 100644 (file)
@@ -1818,12 +1818,101 @@ static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
        rk_hdptx_phy_consumer_put(hdptx, true);
 }
 
+#define PLL_REF_CLK 24000000ULL
+
+static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
+{
+       struct ropll_config ropll_hw;
+       u64 fout, sdm;
+       u32 mode, val;
+       int ret;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode);
+       if (ret)
+               return 0;
+
+       if (mode & LCPLL_LCVCO_MODE_EN_MASK)
+               return 0;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0051), &val);
+       if (ret)
+               return 0;
+       ropll_hw.pms_mdiv = val;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(005E), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdm_en = val & ROPLL_SDM_EN_MASK;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0064), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdm_num_sign = val & ROPLL_SDM_NUM_SIGN_RBR_MASK;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0065), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdm_num = val;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0060), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdm_deno = val;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0069), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdc_n = (val & ROPLL_SDC_N_RBR_MASK) + 3;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(006c), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdc_num = val;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0070), &val);
+       if (ret)
+               return 0;
+       ropll_hw.sdc_deno = val;
+
+       ret = regmap_read(hdptx->regmap, CMN_REG(0086), &val);
+       if (ret)
+               return 0;
+       ropll_hw.pms_sdiv = ((val & PLL_PCG_POSTDIV_SEL_MASK) >> 4) + 1;
+
+       fout = PLL_REF_CLK * ropll_hw.pms_mdiv;
+       if (ropll_hw.sdm_en) {
+               sdm = div_u64(PLL_REF_CLK * ropll_hw.sdc_deno *
+                             ropll_hw.pms_mdiv * ropll_hw.sdm_num,
+                             16 * ropll_hw.sdm_deno *
+                             (ropll_hw.sdc_deno * ropll_hw.sdc_n - ropll_hw.sdc_num));
+
+               if (ropll_hw.sdm_num_sign)
+                       fout = fout - sdm;
+               else
+                       fout = fout + sdm;
+       }
+
+       return div_u64(fout * 2, ropll_hw.pms_sdiv * 10);
+}
+
 static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
                                                  unsigned long parent_rate)
 {
        struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
+       u32 status;
+       u64 rate;
+       int ret;
+
+       if (hdptx->hw_rate)
+               return hdptx->hw_rate;
+
+       ret = regmap_read(hdptx->grf, GRF_HDPTX_CON0, &status);
+       if (ret || !(status & HDPTX_I_PLL_EN))
+               return 0;
+
+       rate = rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx);
 
-       return hdptx->hw_rate;
+       return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc);
 }
 
 static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,