[PATCH] phy: qcom: edp: Fix missing lane drive level programming on Glymur
From: Gopikrishna Garmidi
Date: Mon Nov 09 2026 - 04:17:36 EST
Besides the per-TX TX_DRV_LVL, the Glymur eDP PHY has LN0_DRV_LVL and
LN1_DRV_LVL registers in its PCS block. The driver never programs them,
so they stay at their reset value of 0.
This goes unnoticed at HBR and below, but at HBR2 link training
completes and the sink then reports a high symbol error count on three
of the four lanes, leaving the panel blank.
Initialize both registers as documented in the programming guide and
update them together with TX_DRV_LVL whenever the voltage swing changes.
Tested on the Microsoft Surface Laptop 8th Edition 13.8" with 4-lane
HBR2.
Fixes: add66a6673bc ("phy: qcom: edp: Add Glymur platform support")
Assisted-by: LLM
Signed-off-by: Gopikrishna Garmidi <gopikrishna.garmidi@xxxxxxxxxxxxxxxx>
---
This depends on the Glymur eDP PHY programming sequence series:
https://lore.kernel.org/linux-arm-msm/20260622-glymur-edp-phy-v1-0-814b45089ac9@xxxxxxxxxxxxxxxx/
---
drivers/phy/qualcomm/phy-qcom-edp.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
index c5d1fa0ae6cb..ca17fd3b3c57 100644
--- a/drivers/phy/qualcomm/phy-qcom-edp.c
+++ b/drivers/phy/qualcomm/phy-qcom-edp.c
@@ -48,6 +48,8 @@
#define DP_PHY_LFPS_CYC 0x00d8
#define DP_PHY_AUXLESS_SETUP_CYC 0x00dc
#define DP_PHY_AUXLESS_SILENCE_CYC 0x00e0
+#define DP_PHY_LN0_DRV_LVL 0x00e4
+#define DP_PHY_LN1_DRV_LVL 0x00e8
#define DP_PHY_LDO_CFG 0x00f0
#define DP_PHY_STATUS 0x00e0
@@ -112,6 +114,7 @@ struct phy_ver_ops {
struct qcom_edp_phy_cfg {
bool is_edp;
+ bool has_ln_drv_lvl;
const u8 *aux_cfg;
const u8 *vco_div_cfg;
const struct qcom_edp_swing_pre_emph_cfg *dp_swing_pre_emph_cfg;
@@ -464,6 +467,11 @@ static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configur
writel(swing, edp->tx1 + TXn_TX_DRV_LVL);
writel(emph, edp->tx1 + TXn_TX_EMP_POST1_LVL);
+ if (edp->cfg->has_ln_drv_lvl) {
+ writel(swing, edp->edp + DP_PHY_LN0_DRV_LVL);
+ writel(swing, edp->edp + DP_PHY_LN1_DRV_LVL);
+ }
+
return 0;
}
@@ -620,6 +628,8 @@ static int qcom_edp_configure_pcs_v8(const struct qcom_edp *edp)
writel(edp->is_edp ? 0x03 : 0x00, edp->edp + DP_PHY_LDO_CFG);
writel(0x0f, edp->edp + DP_PHY_CFG_1);
+ writel(0x12, edp->edp + DP_PHY_LN0_DRV_LVL);
+ writel(0x12, edp->edp + DP_PHY_LN1_DRV_LVL);
writel(0x00, edp->edp + DP_PHY_AUXLESS_CFG1);
writel(auxless_setup_cyc, edp->edp + DP_PHY_AUXLESS_SETUP_CYC);
writel(auxless_silence_cyc, edp->edp + DP_PHY_AUXLESS_SILENCE_CYC);
@@ -1377,6 +1387,7 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v8 = {
};
static struct qcom_edp_phy_cfg glymur_phy_cfg = {
+ .has_ln_drv_lvl = true,
.aux_cfg = edp_phy_aux_cfg_v8,
.vco_div_cfg = edp_phy_vco_div_cfg_v8,
.dp_swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg_v8,
--
2.34.1