From 333c23c31696dbddd7dad28e82bd34e37a67d5ff Mon Sep 17 00:00:00 2001 From: Gerald Loacker Date: Sat, 25 Jul 2026 18:56:05 +0200 Subject: [PATCH] phy: rockchip: phy-rockchip-inno-csidphy: add clock lane phase tuning At high data rates like 4K60 (2500 Mbps), such as when using an LT6911GXD bridge chip on an RK3588 board, fixed default timing parameters can cause signal integrity issues and clock-data recovery failures. The driver currently lacks a mechanism to adjust the clock lane sampling phase to compensate for board-specific trace variations. Resolve this by parsing and applying the optional 'rockchip,clk-lane-phase' device tree property. This enables board-specific tuning of the clock lane sampling phase in ~40 ps steps (range 0-7) to optimize link stability. If the property is absent, the driver falls back to the hardware default. Signed-off-by: Gerald Loacker Reviewed-by: Michael Riesch Link: https://patch.msgid.link/20260725-feature-mipi-csi-dphy-4k60-v4-3-5b2c4626d31e@wolfvision.net Signed-off-by: Vinod Koul --- .../phy/rockchip/phy-rockchip-inno-csidphy.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index 5281f8dea0ad..d989f1649b0e 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -69,6 +69,10 @@ #define RK1808_CSIDPHY_CLK_CALIB_EN 0x168 #define RK3568_CSIDPHY_CLK_CALIB_EN 0x168 +#define CSIDPHY_LANE_CLK_3_PHASE 0x38 +#define CSIDPHY_CLK_PHASE_MASK GENMASK(6, 4) +#define CSIDPHY_CLK_PHASE_DEFAULT 3 + #define RESETS_MAX 2 /* @@ -151,6 +155,7 @@ struct rockchip_inno_csidphy { const struct dphy_drv_data *drv_data; struct phy_configure_opts_mipi_dphy config; u8 hsfreq; + int clk_phase; }; static inline void write_grf_reg(struct rockchip_inno_csidphy *priv, @@ -304,6 +309,13 @@ static int rockchip_inno_csidphy_power_on(struct phy *phy) rockchip_inno_csidphy_ths_settle(priv, priv->hsfreq, CSIDPHY_LANE_THS_SETTLE(i)); + if (priv->clk_phase >= 0) { + val = readl(priv->phy_base + CSIDPHY_LANE_CLK_3_PHASE); + val &= ~CSIDPHY_CLK_PHASE_MASK; + val |= FIELD_PREP(CSIDPHY_CLK_PHASE_MASK, priv->clk_phase); + writel(val, priv->phy_base + CSIDPHY_LANE_CLK_3_PHASE); + } + write_grf_reg(priv, GRF_DPHY_CSIPHY_CLKLANE_EN, 0x1); write_grf_reg(priv, GRF_DPHY_CSIPHY_DATALANE_EN, GENMASK(priv->config.lanes - 1, 0)); @@ -449,6 +461,7 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct phy_provider *phy_provider; struct phy *phy; + u32 phase; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -464,6 +477,18 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev) return -ENODEV; } + priv->clk_phase = -1; + if (device_property_read_u32(dev, "rockchip,clk-lane-phase", + &phase) == 0) { + if (phase > 7) { + dev_warn(dev, + "invalid rockchip,clk-lane-phase %u, using default %u\n", + phase, CSIDPHY_CLK_PHASE_DEFAULT); + phase = CSIDPHY_CLK_PHASE_DEFAULT; + } + priv->clk_phase = phase; + } + priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); if (IS_ERR(priv->grf)) {