[PATCH v3 16/19] phy: rockchip: inno-hdmi: Use the common Innosilicon PHY helpers

From: Michal Wilczynski

Date: Fri Sep 04 2026 - 09:43:05 EST


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@xxxxxxxxxxx>
---
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