[PATCH v4 3/3] phy: rockchip: phy-rockchip-inno-csidphy: add clock lane phase tuning
Gerald Loacker <[email protected]>
| Newsgroups | org.infradead.lists.linux-rockchip,org.infradead.lists.linux-arm-kernel,org.infradead.lists.linux-phy,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260725-feature-mipi-csi-dphy-4k60-v4-3-5b2c4626d31e@wolfvision.net> |
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 <[email protected]> --- drivers/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 5281f8dea0ad3..d989f1649b0e4 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)) { -- 2.34.1 _______________________________________________ Linux-rockchip mailing list [email protected] http://lists.infradead.org/mailman/listinfo/linux-rockchip