[PATCH v3 16/19] phy: rockchip: inno-hdmi: Use the common Innosilicon PHY helpers
From: Michal Wilczynski <m.wilczynski@samsung.com>
Date: 2026-09-04 13:27:44
Also in:
dri-devel, linux-arm-kernel, linux-clk, linux-phy, linux-riscv, linux-rockchip, lkml
Subsystem:
arm/rockchip soc support, generic phy framework, the rest · Maintainers:
Heiko Stuebner, Vinod Koul, Linus Torvalds
The RK3328 pre-PLL programming, its table lookup and its recalc_rate and determine_rate implementations are the generic Innosilicon ones, so drop the local copies and use the shared helpers instead. The RK3228 pre-PLL sits at different register addresses, so it keeps its own register level code and only shares the table lookup. The now unused RK3328 pre-PLL register macros go with it, as does the local pre-PLL config lookup wrapper; both call sites already have the TMDS clock to hand and call inno_hdmi_phy_pre_pll_lookup() directly. The RK3328 recalc_rate used to log the pre-PLL output as "vco". The shared helper logs it too, and reports the actual VCO frequency alongside the rate, which is the value with the 1.4-3.2 GHz constraint. The register writes, their order and the values written are unchanged. No functional change intended. Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com> --- drivers/phy/rockchip/Kconfig | 1 + drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 165 ++++---------------------- 2 files changed, 26 insertions(+), 140 deletions(-)
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 14698571b607590dc0e7a29f3b39eb9a5d4e3d25..9732c5be87717dc3ddbea1c60080952336a07af9 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig@@ -34,6 +34,7 @@ config PHY_ROCKCHIP_INNO_HDMI depends on COMMON_CLK depends on HAS_IOMEM select GENERIC_PHY + select PHY_INNO_HDMI help Enable this to support the Rockchip Innosilicon HDMI PHY.
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index c3d257a0f4a65b4c475ed7246568dd463b46ed86..17229d039132e90d46097d875531eb70385b6687 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c@@ -17,6 +17,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/phy/inno-hdmi-phy.h> #include <linux/phy/phy.h> #include <linux/slab.h>
@@ -130,42 +131,17 @@ #define RK3328_INT_VSS_AGND_ESD_DET BIT(1) #define RK3328_INT_AGND_VSS_ESD_DET BIT(0) /* REG: 0xa0 */ -#define RK3328_PCLK_VCO_DIV_5_MASK BIT(1) -#define RK3328_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1) #define RK3328_PRE_PLL_POWER_DOWN BIT(0) /* REG: 0xa1 */ -#define RK3328_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0) -#define RK3328_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0) /* REG: 0xa2 */ /* unset means center spread */ #define RK3328_SPREAD_SPECTRUM_MOD_DOWN BIT(7) #define RK3328_SPREAD_SPECTRUM_MOD_DISABLE BIT(6) -#define RK3328_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4) -#define RK3328_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) -#define RK3328_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0) /* REG: 0xa3 */ -#define RK3328_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) /* REG: 0xa4*/ -#define RK3328_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0) -#define RK3328_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0) -#define RK3328_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2) -#define RK3328_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2) -#define RK3328_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4) -#define RK3328_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4) /* REG: 0xa5 */ -#define RK3328_PRE_PLL_PCLK_DIV_B_SHIFT 5 -#define RK3328_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) -#define RK3328_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) -#define RK3328_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) -#define RK3328_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) /* REG: 0xa6 */ -#define RK3328_PRE_PLL_PCLK_DIV_C_SHIFT 5 -#define RK3328_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) -#define RK3328_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) -#define RK3328_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) -#define RK3328_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) /* REG: 0xa9 */ -#define RK3328_PRE_PLL_LOCK_STATUS BIT(0) /* REG: 0xaa */ #define RK3328_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2) #define RK3328_POST_PLL_REFCLK_SEL_TMDS BIT(1)
@@ -218,11 +194,8 @@ #define RK3328_TMDS_TERM_RESIST_1000 BIT(1) #define RK3328_TMDS_TERM_RESIST_2000 BIT(0) /* REG: 0xd1 */ -#define RK3328_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0) /* REG: 0xd2 */ -#define RK3328_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0) /* REG: 0xd3 */ -#define RK3328_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0) struct inno_hdmi_phy_drv_data;
@@ -240,6 +213,8 @@ struct inno_hdmi_phy { const struct inno_hdmi_phy_drv_data *plat_data; int chip_version; + struct inno_hdmi_phy_pre_pll pre_pll; + /* clk provider */ struct clk_hw hw; struct clk *phyclk;
@@ -248,21 +223,6 @@ struct inno_hdmi_phy { unsigned long opts_tmds_char_rate; }; -struct pre_pll_config { - unsigned long pixclock; - unsigned long tmdsclock; - u8 prediv; - u16 fbdiv; - u8 tmds_div_a; - u8 tmds_div_b; - u8 tmds_div_c; - u8 pclk_div_a; - u8 pclk_div_b; - u8 pclk_div_c; - u8 pclk_div_d; - u8 vco_div_5_en; - u32 fracdiv; -}; struct post_pll_config { unsigned long tmdsclock;
@@ -291,7 +251,7 @@ struct inno_hdmi_phy_drv_data { const struct phy_config *phy_cfg_table; }; -static const struct pre_pll_config pre_pll_cfg_table[] = { +static const struct inno_hdmi_phy_pre_pll_config pre_pll_cfg_table[] = { { 25175000, 25175000, 3, 125, 3, 1, 1, 1, 3, 3, 4, 0, 0xe00000}, { 25175000, 31468750, 1, 41, 0, 3, 3, 1, 3, 3, 4, 0, 0xf5554f}, { 27000000, 27000000, 1, 36, 0, 3, 3, 1, 2, 3, 4, 0, 0x0},
@@ -603,7 +563,7 @@ static irqreturn_t inno_hdmi_phy_rk3328_irq(int irq, void *dev_id) static int inno_hdmi_phy_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts) { - const struct pre_pll_config *cfg = pre_pll_cfg_table; + const struct inno_hdmi_phy_pre_pll_config *cfg = pre_pll_cfg_table; unsigned long tmdsclock; if (!(mode == PHY_MODE_HDMI && submode == PHY_HDMI_MODE_TMDS))
@@ -717,23 +677,6 @@ static const struct phy_ops inno_hdmi_phy_ops = { .validate = inno_hdmi_phy_validate, }; -static const -struct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi_phy *inno, - unsigned long rate) -{ - const struct pre_pll_config *cfg = pre_pll_cfg_table; - unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); - - for (; cfg->pixclock != 0; cfg++) - if (cfg->pixclock == rate && cfg->tmdsclock == tmdsclock) - break; - - if (cfg->pixclock == 0) - return ERR_PTR(-EINVAL); - - return cfg; -} - static int inno_hdmi_phy_rk3228_clk_is_prepared(struct clk_hw *hw) { struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
@@ -797,7 +740,7 @@ unsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw, static int inno_hdmi_phy_rk3228_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - const struct pre_pll_config *cfg = pre_pll_cfg_table; + const struct inno_hdmi_phy_pre_pll_config *cfg = pre_pll_cfg_table; req->rate = (req->rate / 1000) * 1000;
@@ -818,7 +761,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, unsigned long parent_rate) { struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); - const struct pre_pll_config *cfg; + const struct inno_hdmi_phy_pre_pll_config *cfg; unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); u32 v; int ret;
@@ -829,7 +772,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) return 0; - cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + cfg = inno_hdmi_phy_pre_pll_lookup(&inno->pre_pll, rate, tmdsclock); if (IS_ERR(cfg)) return PTR_ERR(cfg);
@@ -915,39 +858,11 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); - unsigned long frac; - u8 nd, no_a, no_b, no_d; - u64 vco; - u16 nf; - - nd = inno_read(inno, 0xa1) & RK3328_PRE_PLL_PRE_DIV_MASK; - nf = ((inno_read(inno, 0xa2) & RK3328_PRE_PLL_FB_DIV_11_8_MASK) << 8); - nf |= inno_read(inno, 0xa3); - vco = parent_rate * nf; - - if (!(inno_read(inno, 0xa2) & RK3328_PRE_PLL_FRAC_DIV_DISABLE)) { - frac = inno_read(inno, 0xd3) | - (inno_read(inno, 0xd2) << 8) | - (inno_read(inno, 0xd1) << 16); - vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24)); - } - - if (inno_read(inno, 0xa0) & RK3328_PCLK_VCO_DIV_5_MASK) { - do_div(vco, nd * 5); - } else { - no_a = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_A_MASK; - no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; - no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; - no_b += 2; - no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; - - do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); - } - inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; + inno->pixclock = inno_hdmi_phy_pre_pll_recalc_rate(&inno->pre_pll, + parent_rate); - dev_dbg(inno->dev, "%s rate %lu vco %llu\n", - __func__, inno->pixclock, vco); + dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); return inno->pixclock; }
@@ -955,20 +870,9 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, static int inno_hdmi_phy_rk3328_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - const struct pre_pll_config *cfg = pre_pll_cfg_table; - - req->rate = (req->rate / 1000) * 1000; - - for (; cfg->pixclock != 0; cfg++) - if (cfg->pixclock == req->rate) - break; - - if (cfg->pixclock == 0) - return -EINVAL; - - req->rate = cfg->pixclock; + struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); - return 0; + return inno_hdmi_phy_pre_pll_determine_rate(&inno->pre_pll, req); } static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
@@ -976,9 +880,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, unsigned long parent_rate) { struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); - const struct pre_pll_config *cfg; + const struct inno_hdmi_phy_pre_pll_config *cfg; unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); - u32 val; int ret; dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
@@ -987,39 +890,15 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) return 0; - cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); + cfg = inno_hdmi_phy_pre_pll_lookup(&inno->pre_pll, rate, tmdsclock); if (IS_ERR(cfg)) return PTR_ERR(cfg); - inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, - RK3328_PRE_PLL_POWER_DOWN); + inno_hdmi_phy_pre_pll_power_down(&inno->pre_pll, true); + inno_hdmi_phy_pre_pll_configure(&inno->pre_pll, cfg); + inno_hdmi_phy_pre_pll_power_down(&inno->pre_pll, false); - /* Configure pre-pll */ - inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, - RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); - inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); - - val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; - if (!cfg->fracdiv) - val |= RK3328_PRE_PLL_FRAC_DIV_DISABLE; - inno_write(inno, 0xa2, RK3328_PRE_PLL_FB_DIV_11_8(cfg->fbdiv) | val); - inno_write(inno, 0xa3, RK3328_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); - inno_write(inno, 0xa5, RK3328_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a) | - RK3328_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b)); - inno_write(inno, 0xa6, RK3328_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | - RK3328_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); - inno_write(inno, 0xa4, RK3328_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | - RK3328_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | - RK3328_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); - inno_write(inno, 0xd3, RK3328_PRE_PLL_FRAC_DIV_7_0(cfg->fracdiv)); - inno_write(inno, 0xd2, RK3328_PRE_PLL_FRAC_DIV_15_8(cfg->fracdiv)); - inno_write(inno, 0xd1, RK3328_PRE_PLL_FRAC_DIV_23_16(cfg->fracdiv)); - - inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); - - /* Wait for Pre-PLL lock */ - ret = inno_poll(inno, 0xa9, val, val & RK3328_PRE_PLL_LOCK_STATUS, - 1000, 10000); + ret = inno_hdmi_phy_pre_pll_wait_locked(&inno->pre_pll, 10000); if (ret) { dev_err(inno->dev, "Pre-PLL locking failed\n"); return ret;
@@ -1418,6 +1297,12 @@ static int inno_hdmi_phy_probe(struct platform_device *pdev) if (IS_ERR(inno->regmap)) return PTR_ERR(inno->regmap); + /* The PHY block starts the register space on these SoCs. */ + inno->pre_pll.dev = inno->dev; + inno->pre_pll.regmap = inno->regmap; + inno->pre_pll.offset = 0; + inno->pre_pll.table = pre_pll_cfg_table; + /* only the newer rk3328 hdmiphy has an interrupt */ inno->irq = platform_get_irq(pdev, 0); if (inno->irq > 0) {
--
2.34.1