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 <gerald.loacker@wolfvision.net>
Reviewed-by: Michael Riesch <michael.riesch@collabora.com>
Link: https://patch.msgid.link/20260725-feature-mipi-csi-dphy-4k60-v4-3-5b2c4626d31e@wolfvision.net
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Gerald Loacker
2026-07-25 18:56:05 +02:00
committed by Vinod Koul
parent f82ff8609f
commit 333c23c316

View File

@@ -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)) {