Linux-PHY Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] phy: qcom: edp: Update v8 programming sequence
@ 2026-06-22 23:29 Bjorn Andersson
  2026-06-22 23:29 ` [PATCH 1/2] phy: qcom: edp: split power-on sequencing by PHY version Bjorn Andersson
  2026-06-22 23:29 ` [PATCH 2/2] phy: qcom: edp: update v8 power-on programming sequence Bjorn Andersson
  0 siblings, 2 replies; 4+ messages in thread
From: Bjorn Andersson @ 2026-06-22 23:29 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong
  Cc: linux-arm-msm, linux-phy, linux-kernel, Bjorn Andersson

The programming sequences introduced for v8 doesn't work other than for
4-lane 8.1Gbps. For 2-lane 5.4Gbps link training fails and for 2.7 and
1.62Gbps PLL lock isn't reached.

Update the driver to match the documentation (and Windows driver for the
1.62Gbps PLL settings), to get past the link training on lower
resolution monitors.

Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
---
Bjorn Andersson (2):
      phy: qcom: edp: split power-on sequencing by PHY version
      phy: qcom: edp: update v8 power-on programming sequence

 drivers/phy/qualcomm/phy-qcom-edp.c | 575 +++++++++++++++++++++++++++++++-----
 1 file changed, 507 insertions(+), 68 deletions(-)
---
base-commit: 948efecf22e49aa4bf55bb73ec79a0ddcfd38571
change-id: 20260622-glymur-edp-phy-4f75f5897b0b

Best regards,
--  
Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] phy: qcom: edp: split power-on sequencing by PHY version
  2026-06-22 23:29 [PATCH 0/2] phy: qcom: edp: Update v8 programming sequence Bjorn Andersson
@ 2026-06-22 23:29 ` Bjorn Andersson
  2026-06-22 23:29 ` [PATCH 2/2] phy: qcom: edp: update v8 power-on programming sequence Bjorn Andersson
  1 sibling, 0 replies; 4+ messages in thread
From: Bjorn Andersson @ 2026-06-22 23:29 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong
  Cc: linux-arm-msm, linux-phy, linux-kernel, Bjorn Andersson

The eDP PHY power-on sequence has grown version-specific differences,
but qcom_edp_phy_power_on() still contains the sequence as one shared
flow. This makes it difficult to add newer PHY programming without
interleaving it with the v4/v6 sequence.

Split the power-on sequence into version callbacks for the parts that
differ between PHY revisions:

  - pre-power-on preparation
  - TX programming before PLL enable
  - rate/PCS programming
  - lane programming after PLL enable
  - final status polling

Keep the existing v4/v6 sequence as the v46 implementation, and wire v8
to the same callbacks for now. This keeps the programming unchanged
while making the next patch a v8-only programming update.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-edp.c | 175 +++++++++++++++++++++++++-----------
 1 file changed, 125 insertions(+), 50 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
index a3c893f72908..6588419d4860 100644
--- a/drivers/phy/qualcomm/phy-qcom-edp.c
+++ b/drivers/phy/qualcomm/phy-qcom-edp.c
@@ -48,13 +48,10 @@
 /* LANE_TXn registers */
 #define TXn_CLKBUF_ENABLE                       0x0000
 #define TXn_TX_EMP_POST1_LVL                    0x0004
-
 #define TXn_TX_DRV_LVL                          0x0014
 #define TXn_TX_DRV_LVL_OFFSET                   0x0018
 #define TXn_RESET_TSYNC_EN                      0x001c
-#define TXn_LDO_CONFIG                          0x0084
 #define TXn_TX_BAND                             0x0028
-
 #define TXn_RES_CODE_LANE_OFFSET_TX0            0x0044
 #define TXn_RES_CODE_LANE_OFFSET_TX1            0x0048
 
@@ -64,6 +61,7 @@
 #define TXn_LANE_MODE_1                         0x0064
 
 #define TXn_TRAN_DRVR_EMP_EN                    0x0078
+#define TXn_LDO_CONFIG                          0x0084
 
 struct qcom_edp_swing_pre_emph_cfg {
 	const u8 (*swing_hbr_rbr)[4][4];
@@ -82,6 +80,12 @@ struct phy_ver_ops {
 	int (*com_configure_pll)(const struct qcom_edp *edp);
 	int (*com_configure_ssc)(const struct qcom_edp *edp);
 	int (*com_ldo_config)(const struct qcom_edp *edp);
+	int (*prepare_power_on)(const struct qcom_edp *edp);
+	int (*configure_tx_pre_pll)(const struct qcom_edp *edp);
+	int (*configure_rate_pcs)(const struct qcom_edp *edp,
+				  unsigned long *pixel_freq);
+	void (*configure_lanes_after_pll)(const struct qcom_edp *edp);
+	int (*finish_power_on)(const struct qcom_edp *edp);
 };
 
 struct qcom_edp_phy_cfg {
@@ -117,6 +121,13 @@ struct qcom_edp {
 	bool is_edp;
 };
 
+static int qcom_edp_prepare_power_on_v46(const struct qcom_edp *edp);
+static int qcom_edp_configure_tx_pre_pll_v46(const struct qcom_edp *edp);
+static int qcom_edp_configure_rate_pcs_v46(const struct qcom_edp *edp,
+					   unsigned long *pixel_freq);
+static void qcom_edp_configure_lanes_after_pll_v46(const struct qcom_edp *edp);
+static int qcom_edp_finish_power_on_v46(const struct qcom_edp *edp);
+
 static const u8 dp_swing_hbr_rbr[4][4] = {
 	{ 0x07, 0x0f, 0x16, 0x1f },
 	{ 0x11, 0x1e, 0x1f, 0xff },
@@ -653,6 +664,11 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v3 = {
 	.com_configure_pll	= qcom_edp_com_configure_pll_v4,
 	.com_configure_ssc	= qcom_edp_com_configure_ssc_v4,
 	.com_ldo_config		= qcom_edp_ldo_config_v3,
+	.prepare_power_on	= qcom_edp_prepare_power_on_v46,
+	.configure_tx_pre_pll	= qcom_edp_configure_tx_pre_pll_v46,
+	.configure_rate_pcs	= qcom_edp_configure_rate_pcs_v46,
+	.configure_lanes_after_pll = qcom_edp_configure_lanes_after_pll_v46,
+	.finish_power_on	= qcom_edp_finish_power_on_v46,
 };
 
 static const struct phy_ver_ops qcom_edp_phy_ops_v4 = {
@@ -663,6 +679,11 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v4 = {
 	.com_configure_pll	= qcom_edp_com_configure_pll_v4,
 	.com_configure_ssc	= qcom_edp_com_configure_ssc_v4,
 	.com_ldo_config		= qcom_edp_ldo_config_v4,
+	.prepare_power_on	= qcom_edp_prepare_power_on_v46,
+	.configure_tx_pre_pll	= qcom_edp_configure_tx_pre_pll_v46,
+	.configure_rate_pcs	= qcom_edp_configure_rate_pcs_v46,
+	.configure_lanes_after_pll = qcom_edp_configure_lanes_after_pll_v46,
+	.finish_power_on	= qcom_edp_finish_power_on_v46,
 };
 
 static const struct qcom_edp_phy_cfg sa8775p_dp_phy_cfg = {
@@ -898,6 +919,11 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v6 = {
 	.com_configure_pll	= qcom_edp_com_configure_pll_v6,
 	.com_configure_ssc	= qcom_edp_com_configure_ssc_v6,
 	.com_ldo_config		= qcom_edp_ldo_config_v6,
+	.prepare_power_on	= qcom_edp_prepare_power_on_v46,
+	.configure_tx_pre_pll	= qcom_edp_configure_tx_pre_pll_v46,
+	.configure_rate_pcs	= qcom_edp_configure_rate_pcs_v46,
+	.configure_lanes_after_pll = qcom_edp_configure_lanes_after_pll_v46,
+	.finish_power_on	= qcom_edp_finish_power_on_v46,
 };
 
 static struct qcom_edp_phy_cfg x1e80100_phy_cfg = {
@@ -1079,6 +1105,11 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v8 = {
 	.com_configure_pll	= qcom_edp_com_configure_pll_v8,
 	.com_configure_ssc	= qcom_edp_com_configure_ssc_v8,
 	.com_ldo_config		= qcom_edp_ldo_config_v6,
+	.prepare_power_on	= qcom_edp_prepare_power_on_v46,
+	.configure_tx_pre_pll	= qcom_edp_configure_tx_pre_pll_v46,
+	.configure_rate_pcs	= qcom_edp_configure_rate_pcs_v46,
+	.configure_lanes_after_pll = qcom_edp_configure_lanes_after_pll_v46,
+	.finish_power_on	= qcom_edp_finish_power_on_v46,
 };
 
 static struct qcom_edp_phy_cfg glymur_phy_cfg = {
@@ -1089,81 +1120,49 @@ static struct qcom_edp_phy_cfg glymur_phy_cfg = {
 	.ver_ops = &qcom_edp_phy_ops_v8,
 };
 
-static int qcom_edp_phy_power_on(struct phy *phy)
+static int qcom_edp_prepare_power_on_v46(const struct qcom_edp *edp)
 {
-	const struct qcom_edp *edp = phy_get_drvdata(phy);
-	u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
-	unsigned long pixel_freq;
-	int ret;
-	u32 val;
-	u8 cfg1;
-
-	ret = edp->cfg->ver_ops->com_power_on(edp);
-	if (ret)
-		return ret;
-
-	ret = edp->cfg->ver_ops->com_ldo_config(edp);
-	if (ret)
-		return ret;
-
-	writel(0x00, edp->tx0 + TXn_LANE_MODE_1);
-	writel(0x00, edp->tx1 + TXn_LANE_MODE_1);
-
-	if (edp->dp_opts.ssc) {
-		ret = qcom_edp_configure_ssc(edp);
-		if (ret)
-			return ret;
-	}
-
-	ret = qcom_edp_configure_pll(edp);
-	if (ret)
-		return ret;
+	return 0;
+}
 
-	/* TX Lane configuration */
+static int qcom_edp_configure_tx_pre_pll_v46(const struct qcom_edp *edp)
+{
 	writel(0x05, edp->edp + DP_PHY_TX0_TX1_LANE_CTL);
 	writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL);
 
-	/* TX-0 register configuration */
 	writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
 	writel(0x0f, edp->tx0 + TXn_CLKBUF_ENABLE);
 	writel(0x03, edp->tx0 + TXn_RESET_TSYNC_EN);
 	writel(0x01, edp->tx0 + TXn_TRAN_DRVR_EMP_EN);
 	writel(0x04, edp->tx0 + TXn_TX_BAND);
 
-	/* TX-1 register configuration */
 	writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
 	writel(0x0f, edp->tx1 + TXn_CLKBUF_ENABLE);
 	writel(0x03, edp->tx1 + TXn_RESET_TSYNC_EN);
 	writel(0x01, edp->tx1 + TXn_TRAN_DRVR_EMP_EN);
 	writel(0x04, edp->tx1 + TXn_TX_BAND);
 
-	ret = qcom_edp_set_vco_div(edp, &pixel_freq);
-	if (ret)
-		return ret;
-
-	writel(0x01, edp->edp + DP_PHY_CFG);
-	writel(0x05, edp->edp + DP_PHY_CFG);
-	writel(0x01, edp->edp + DP_PHY_CFG);
-	writel(0x09, edp->edp + DP_PHY_CFG);
+	return 0;
+}
 
-	ret = edp->cfg->ver_ops->com_resetsm_cntrl(edp);
-	if (ret)
-		return ret;
+static void qcom_edp_configure_lanes_after_pll_v46(const struct qcom_edp *edp)
+{
+	u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
+	u8 cfg1;
 
-	writel(0x19, edp->edp + DP_PHY_CFG);
 	writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN);
 	writel(0x04, edp->tx0 + TXn_HIGHZ_DRVR_EN);
 	writel(0x00, edp->tx0 + TXn_TX_POL_INV);
 	writel(0x1f, edp->tx1 + TXn_HIGHZ_DRVR_EN);
 	writel(0x04, edp->tx1 + TXn_HIGHZ_DRVR_EN);
 	writel(0x00, edp->tx1 + TXn_TX_POL_INV);
+
 	writel(0x10, edp->tx0 + TXn_TX_DRV_LVL_OFFSET);
 	writel(0x10, edp->tx1 + TXn_TX_DRV_LVL_OFFSET);
 	writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0);
 	writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1);
 	writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0);
 	writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1);
-
 	writel(0x10, edp->tx0 + TXn_TX_EMP_POST1_LVL);
 	writel(0x10, edp->tx1 + TXn_TX_EMP_POST1_LVL);
 	writel(0x1f, edp->tx0 + TXn_TX_DRV_LVL);
@@ -1194,14 +1193,90 @@ static int qcom_edp_phy_power_on(struct phy *phy)
 	writel(drvr1_en, edp->tx1 + TXn_HIGHZ_DRVR_EN);
 	writel(bias1_en, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
 	writel(cfg1, edp->edp + DP_PHY_CFG_1);
+}
+
+static int qcom_edp_configure_rate_pcs_v46(const struct qcom_edp *edp,
+					   unsigned long *pixel_freq)
+{
+	return qcom_edp_set_vco_div(edp, pixel_freq);
+}
+
+static int qcom_edp_start_pll(const struct qcom_edp *edp)
+{
+	int ret;
+
+	writel(0x01, edp->edp + DP_PHY_CFG);
+	writel(0x05, edp->edp + DP_PHY_CFG);
+	writel(0x01, edp->edp + DP_PHY_CFG);
+	writel(0x09, edp->edp + DP_PHY_CFG);
+
+	ret = edp->cfg->ver_ops->com_resetsm_cntrl(edp);
+	if (ret)
+		return ret;
+
+	writel(0x19, edp->edp + DP_PHY_CFG);
+
+	return 0;
+}
+
+static int qcom_edp_finish_power_on_v46(const struct qcom_edp *edp)
+{
+	u32 val;
 
 	writel(0x18, edp->edp + DP_PHY_CFG);
 	usleep_range(100, 1000);
-
 	writel(0x19, edp->edp + DP_PHY_CFG);
 
-	ret = readl_poll_timeout(edp->edp + DP_PHY_STATUS,
-				 val, val & BIT(1), 500, 10000);
+	return readl_poll_timeout(edp->edp + DP_PHY_STATUS, val, val & BIT(1),
+				  500, 10000);
+}
+
+static int qcom_edp_phy_power_on(struct phy *phy)
+{
+	const struct qcom_edp *edp = phy_get_drvdata(phy);
+	unsigned long pixel_freq;
+	int ret;
+
+	ret = edp->cfg->ver_ops->com_power_on(edp);
+	if (ret)
+		return ret;
+
+	ret = edp->cfg->ver_ops->prepare_power_on(edp);
+	if (ret)
+		return ret;
+
+	ret = edp->cfg->ver_ops->com_ldo_config(edp);
+	if (ret)
+		return ret;
+
+	writel(0x00, edp->tx0 + TXn_LANE_MODE_1);
+	writel(0x00, edp->tx1 + TXn_LANE_MODE_1);
+
+	if (edp->dp_opts.ssc) {
+		ret = qcom_edp_configure_ssc(edp);
+		if (ret)
+			return ret;
+	}
+
+	ret = qcom_edp_configure_pll(edp);
+	if (ret)
+		return ret;
+
+	ret = edp->cfg->ver_ops->configure_tx_pre_pll(edp);
+	if (ret)
+		return ret;
+
+	ret = edp->cfg->ver_ops->configure_rate_pcs(edp, &pixel_freq);
+	if (ret)
+		return ret;
+
+	ret = qcom_edp_start_pll(edp);
+	if (ret)
+		return ret;
+
+	edp->cfg->ver_ops->configure_lanes_after_pll(edp);
+
+	ret = edp->cfg->ver_ops->finish_power_on(edp);
 	if (ret)
 		return ret;
 

-- 
2.53.0


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] phy: qcom: edp: update v8 power-on programming sequence
  2026-06-22 23:29 [PATCH 0/2] phy: qcom: edp: Update v8 programming sequence Bjorn Andersson
  2026-06-22 23:29 ` [PATCH 1/2] phy: qcom: edp: split power-on sequencing by PHY version Bjorn Andersson
@ 2026-06-22 23:29 ` Bjorn Andersson
  2026-06-22 23:41   ` sashiko-bot
  1 sibling, 1 reply; 4+ messages in thread
From: Bjorn Andersson @ 2026-06-22 23:29 UTC (permalink / raw)
  To: Vinod Koul, Neil Armstrong
  Cc: linux-arm-msm, linux-phy, linux-kernel, Bjorn Andersson

While the introduction of the v8 programming sequence brought functional
eDP support for the 4-lane 8.1Gbps case, it doesn't entirely match the
documented sequences from the programming guide. Further 5.4Gbps,
2.7Gbps and 1.62Gbps, and 2-lane support are both incorrect and
non-functional.

Update the v8 eDP PHY programming sequence to match the programming
sequence validated on Glymur.

This changes the v8-specific parts of the power-on flow:

  - AUX configuration:
    - update the default v8 AUX config
    - program AUX_CFG2 based on link rate

  - TX lane configuration:
    - add v8 TX lane register programming before PLL enable
    - program interface select based on link rate
    - use separate 2-lane and 4-lane post-PLL lane enable programming

  - PCS configuration:
    - add v8 PCS/LDO/AUX-less timing programming
    - program LFPS/AUX-less timing based on link rate

  - PLL and SSC programming:
    - update v8 SSC step values per link rate
    - make LOCK_CMP_EN, CMN_CONFIG_1, CORECLK_DIV_MODE0, CORE_CLK_EN and
      VCO tune values link-rate specific

  - DCC and TSYNC:
    - disable DCC before the v8 power-on sequence
    - run the v8 TSYNC sequence
    - run DCC calibration after PLL lock

  - Status polling:
    - poll the v8 PHY status register instead of the older status offset

  - LDO config:
    - use the correct LDO configuration parameters for v8

With these changes the v8 PHY has been validated to lock at 1.62, 2.7,
5.4 and 8.1 Gbps, using both 2 and 4 lanes. Link training now suceeds on
4-lane 8.1Gbps and 2-lane 5.4Gbps.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
---
 drivers/phy/qualcomm/phy-qcom-edp.c | 426 +++++++++++++++++++++++++++++++++---
 1 file changed, 395 insertions(+), 31 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
index 6588419d4860..c5d1fa0ae6cb 100644
--- a/drivers/phy/qualcomm/phy-qcom-edp.c
+++ b/drivers/phy/qualcomm/phy-qcom-edp.c
@@ -40,28 +40,50 @@
 #define DP_PHY_AUX_INTERRUPT_MASK		0x0058
 
 #define DP_PHY_VCO_DIV                          0x0074
+#define DP_PHY_TSYNC_OVRD                       0x0078
 #define DP_PHY_TX0_TX1_LANE_CTL                 0x007c
 #define DP_PHY_TX2_TX3_LANE_CTL                 0x00a0
+#define DP_PHY_AUXLESS_CFG1                     0x00cc
+#define DP_PHY_LFPS_PERIOD                      0x00d4
+#define DP_PHY_LFPS_CYC                         0x00d8
+#define DP_PHY_AUXLESS_SETUP_CYC                0x00dc
+#define DP_PHY_AUXLESS_SILENCE_CYC              0x00e0
+#define DP_PHY_LDO_CFG                          0x00f0
 
 #define DP_PHY_STATUS                           0x00e0
+#define DP_PHY_STATUS_V8                        0x0110
 
 /* LANE_TXn registers */
 #define TXn_CLKBUF_ENABLE                       0x0000
 #define TXn_TX_EMP_POST1_LVL                    0x0004
+#define TXn_TX_IDLE_LVL_LARGE_AMP               0x0010
 #define TXn_TX_DRV_LVL                          0x0014
 #define TXn_TX_DRV_LVL_OFFSET                   0x0018
 #define TXn_RESET_TSYNC_EN                      0x001c
+#define TXn_PRE_EMPH                            0x0020
+#define TXn_INTERFACE_SELECT                    0x0024
 #define TXn_TX_BAND                             0x0028
+#define TXn_SLEW_CNTL                           0x002c
+#define TXn_LPB_CFG1                            0x0034
+#define TXn_RES_CODE_LANE_TX                    0x003c
+#define TXn_RES_CODE_LANE_TX1                   0x0040
 #define TXn_RES_CODE_LANE_OFFSET_TX0            0x0044
 #define TXn_RES_CODE_LANE_OFFSET_TX1            0x0048
+#define TXn_SERDES_BYP_EN_OUT                   0x004c
 
 #define TXn_TRANSCEIVER_BIAS_EN                 0x0054
 #define TXn_HIGHZ_DRVR_EN                       0x0058
 #define TXn_TX_POL_INV                          0x005c
+#define TXn_PARRATE_REC_DETECT_IDLE_EN          0x0060
 #define TXn_LANE_MODE_1                         0x0064
+#define TXn_LANE_MODE_2                         0x0068
 
 #define TXn_TRAN_DRVR_EMP_EN                    0x0078
+#define TXn_VMODE_CTRL1                         0x007c
 #define TXn_LDO_CONFIG                          0x0084
+#define TXn_DCC0_CTRL                           0x00c8
+#define TXn_DCC1_CTRL                           0x00d0
+#define TXn_DCC_DONE                            0x00e0
 
 struct qcom_edp_swing_pre_emph_cfg {
 	const u8 (*swing_hbr_rbr)[4][4];
@@ -122,11 +144,18 @@ struct qcom_edp {
 };
 
 static int qcom_edp_prepare_power_on_v46(const struct qcom_edp *edp);
+static int qcom_edp_prepare_power_on_v8(const struct qcom_edp *edp);
 static int qcom_edp_configure_tx_pre_pll_v46(const struct qcom_edp *edp);
+static int qcom_edp_configure_tx_pre_pll_v8(const struct qcom_edp *edp);
 static int qcom_edp_configure_rate_pcs_v46(const struct qcom_edp *edp,
 					   unsigned long *pixel_freq);
+static int qcom_edp_configure_rate_pcs_v8(const struct qcom_edp *edp,
+					  unsigned long *pixel_freq);
 static void qcom_edp_configure_lanes_after_pll_v46(const struct qcom_edp *edp);
+static void qcom_edp_configure_lanes_after_pll_v8(const struct qcom_edp *edp);
 static int qcom_edp_finish_power_on_v46(const struct qcom_edp *edp);
+static int qcom_edp_finish_power_on_v8(const struct qcom_edp *edp);
+
 
 static const u8 dp_swing_hbr_rbr[4][4] = {
 	{ 0x07, 0x0f, 0x16, 0x1f },
@@ -239,6 +268,41 @@ static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = {
 	.pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3,
 };
 
+static const u8 edp_swing_hbr_rbr_v8[4][4] = {
+	{ 0x07, 0x0f, 0x16, 0x1f },
+	{ 0x0d, 0x16, 0x1e, 0xff },
+	{ 0x11, 0x1b, 0xff, 0xff },
+	{ 0x16, 0xff, 0xff, 0xff }
+};
+
+static const u8 edp_pre_emp_hbr_rbr_v8[4][4] = {
+	{ 0x05, 0x11, 0x17, 0x1d },
+	{ 0x05, 0x11, 0x18, 0xff },
+	{ 0x06, 0x11, 0xff, 0xff },
+	{ 0x00, 0xff, 0xff, 0xff }
+};
+
+static const u8 edp_swing_hbr2_hbr3_v8[4][4] = {
+	{ 0x0b, 0x11, 0x17, 0x1c },
+	{ 0x10, 0x19, 0x1f, 0xff },
+	{ 0x19, 0x1f, 0xff, 0xff },
+	{ 0x1f, 0xff, 0xff, 0xff }
+};
+
+static const u8 edp_pre_emp_hbr2_hbr3_v8[4][4] = {
+	{ 0x0c, 0x15, 0x19, 0x1e },
+	{ 0x0b, 0x15, 0x19, 0xff },
+	{ 0x0e, 0x14, 0xff, 0xff },
+	{ 0x0d, 0xff, 0xff, 0xff }
+};
+
+static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg_v8 = {
+	.swing_hbr_rbr = &edp_swing_hbr_rbr_v8,
+	.swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3_v8,
+	.pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr_v8,
+	.pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3_v8,
+};
+
 static const u8 edp_phy_aux_cfg_v4[DP_AUX_CFG_SIZE] = {
 	0x00, 0x13, 0x24, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x00,
 };
@@ -294,7 +358,7 @@ static const u8 edp_phy_aux_cfg_v5[DP_AUX_CFG_SIZE] = {
 };
 
 static const u8 edp_phy_aux_cfg_v8[DP_AUX_CFG_SIZE] = {
-	0x00, 0x00, 0xa0, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x04,
+	0x00, 0x13, 0xa4, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03, 0x02, 0x02, 0x04,
 };
 
 static const u8 edp_phy_vco_div_cfg_v8[4] = {
@@ -427,6 +491,145 @@ static int qcom_edp_configure_pll(const struct qcom_edp *edp)
 	return edp->cfg->ver_ops->com_configure_pll(edp);
 }
 
+static int qcom_edp_set_link_rate_aux_cfg2(const struct qcom_edp *edp)
+{
+	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
+	u32 aux_cfg2;
+
+	switch (dp_opts->link_rate) {
+	case 1620:
+	case 2700:
+	case 5400:
+		aux_cfg2 = 0xa4;
+		break;
+	case 8100:
+		aux_cfg2 = 0xa0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(aux_cfg2, edp->edp + DP_PHY_AUX_CFG(2));
+
+	return 0;
+}
+
+static void qcom_edp_configure_tx_pre_pll_v8_lane(void __iomem *tx, u32 interface_select)
+{
+	writel(0x0f, tx + TXn_CLKBUF_ENABLE);
+	writel(0x00, tx + TXn_PRE_EMPH);
+	writel(0x00, tx + TXn_VMODE_CTRL1);
+	writel(0x00, tx + TXn_SERDES_BYP_EN_OUT);
+	writel(0x03, tx + TXn_LPB_CFG1);
+	writel(0x10, tx + TXn_TX_DRV_LVL_OFFSET);
+	writel(interface_select, tx + TXn_INTERFACE_SELECT);
+	writel(0x01, tx + TXn_TRAN_DRVR_EMP_EN);
+	writel(0x06, tx + TXn_TX_EMP_POST1_LVL);
+	writel(0x00, tx + TXn_LANE_MODE_1);
+	writel(0x00, tx + TXn_LANE_MODE_2);
+	writel(0x12, tx + TXn_TX_DRV_LVL);
+	writel(0x00, tx + TXn_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, tx + TXn_TX_IDLE_LVL_LARGE_AMP);
+	writel(0x03, tx + TXn_RESET_TSYNC_EN);
+	writel(0x04, tx + TXn_TX_BAND);
+	writel(0x00, tx + TXn_SLEW_CNTL);
+	writel(0x60, tx + TXn_RES_CODE_LANE_TX);
+	writel(0x60, tx + TXn_RES_CODE_LANE_TX1);
+}
+
+static void qcom_edp_configure_lanes_after_pll_v8(const struct qcom_edp *edp)
+{
+	if (edp->dp_opts.lanes == 2) {
+		writel(0x1b, edp->tx0 + TXn_HIGHZ_DRVR_EN);
+		writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
+		writel(0x04, edp->tx0 + TXn_HIGHZ_DRVR_EN);
+		writel(0x00, edp->tx0 + TXn_TX_POL_INV);
+
+		writel(0x1b, edp->tx1 + TXn_HIGHZ_DRVR_EN);
+		writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
+		writel(0x04, edp->tx1 + TXn_HIGHZ_DRVR_EN);
+		writel(0x50, edp->tx1 + TXn_TX_IDLE_LVL_LARGE_AMP);
+		writel(0x00, edp->tx1 + TXn_TX_POL_INV);
+	} else {
+		writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN);
+		writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
+		writel(0x04, edp->tx0 + TXn_HIGHZ_DRVR_EN);
+		writel(0x00, edp->tx0 + TXn_TX_POL_INV);
+
+		writel(0x1f, edp->tx1 + TXn_HIGHZ_DRVR_EN);
+		writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
+		writel(0x04, edp->tx1 + TXn_HIGHZ_DRVR_EN);
+		writel(0x00, edp->tx1 + TXn_TX_POL_INV);
+	}
+}
+
+static int qcom_edp_configure_tx_pre_pll_v8_lanes(const struct qcom_edp *edp)
+{
+	u32 interface_select;
+
+	switch (edp->dp_opts.link_rate) {
+	case 1620:
+	case 2700:
+	case 5400:
+		interface_select = 0x05;
+		break;
+	case 8100:
+		interface_select = 0x07;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	qcom_edp_configure_tx_pre_pll_v8_lane(edp->tx0, interface_select);
+	qcom_edp_configure_tx_pre_pll_v8_lane(edp->tx1, interface_select);
+
+	return 0;
+}
+
+static int qcom_edp_configure_pcs_v8(const struct qcom_edp *edp)
+{
+	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
+	u32 auxless_setup_cyc;
+	u32 auxless_silence_cyc;
+	u32 lfps_period;
+
+	switch (dp_opts->link_rate) {
+	case 1620:
+		auxless_setup_cyc = 0x03;
+		auxless_silence_cyc = 0x06;
+		lfps_period = 0x00;
+		break;
+	case 2700:
+		auxless_setup_cyc = 0x04;
+		auxless_silence_cyc = 0x08;
+		lfps_period = 0x11;
+		break;
+	case 5400:
+		auxless_setup_cyc = 0x09;
+		auxless_silence_cyc = 0x11;
+		lfps_period = 0x33;
+		break;
+	case 8100:
+		auxless_setup_cyc = 0x0f;
+		auxless_silence_cyc = 0x1a;
+		lfps_period = 0x55;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(edp->is_edp ? 0x03 : 0x00, edp->edp + DP_PHY_LDO_CFG);
+	writel(0x0f, edp->edp + DP_PHY_CFG_1);
+	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);
+	writel(0x08, edp->edp + DP_PHY_LFPS_CYC);
+	writel(lfps_period, edp->edp + DP_PHY_LFPS_PERIOD);
+	writel(0x2f, edp->edp + DP_PHY_CFG_1);
+
+	return 0;
+}
+
 static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq)
 {
 	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
@@ -911,6 +1114,22 @@ static int qcom_edp_ldo_config_v6(const struct qcom_edp *edp)
 	return 0;
 }
 
+static int qcom_edp_ldo_config_v8(const struct qcom_edp *edp)
+{
+	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
+	u32 ldo_config;
+
+	if (edp->is_edp)
+		ldo_config = 0xd0;
+	else
+		ldo_config = 0x00;
+
+	writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
+	writel(dp_opts->lanes > 2 ? ldo_config : 0x00, edp->tx1 + TXn_LDO_CONFIG);
+
+	return 0;
+}
+
 static const struct phy_ver_ops qcom_edp_phy_ops_v6 = {
 	.com_power_on		= qcom_edp_phy_power_on_v6,
 	.com_resetsm_cntrl	= qcom_edp_phy_com_resetsm_cntrl_v6,
@@ -942,13 +1161,18 @@ static int qcom_edp_com_configure_ssc_v8(const struct qcom_edp *edp)
 
 	switch (dp_opts->link_rate) {
 	case 1620:
+		step1 = 0x83;
+		step2 = 0x02;
+		break;
 	case 2700:
-	case 8100:
-		step1 = 0x5b;
+		step1 = 0x18;
 		step2 = 0x02;
 		break;
-
 	case 5400:
+		step1 = 0x18;
+		step2 = 0x02;
+		break;
+	case 8100:
 		step1 = 0x5b;
 		step2 = 0x02;
 		break;
@@ -976,34 +1200,68 @@ static int qcom_edp_com_configure_pll_v8(const struct qcom_edp *edp)
 	u32 dec_start_mode0;
 	u32 lock_cmp1_mode0;
 	u32 lock_cmp2_mode0;
+	u32 lock_cmp_en;
 	u32 code1_mode0;
 	u32 code2_mode0;
+	u32 coreclk_div_mode0;
+	u32 vco_tune1_mode0;
+	u32 vco_tune2_mode0;
 	u32 hsclk_sel;
+	u32 core_clk_en;
+	u32 cmn_config_1;
 
 	switch (dp_opts->link_rate) {
 	case 1620:
-		hsclk_sel = 0x5;
-		dec_start_mode0 = 0x34;
-		div_frac_start2_mode0 = 0xc0;
-		div_frac_start3_mode0 = 0x0b;
-		lock_cmp1_mode0 = 0x37;
-		lock_cmp2_mode0 = 0x04;
-		code1_mode0 = 0x71;
-		code2_mode0 = 0x0c;
+		hsclk_sel = 0x4;
+		dec_start_mode0 = 0x54;
+		div_frac_start2_mode0 = 0x00;
+		div_frac_start3_mode0 = 0x06;
+		lock_cmp1_mode0 = 0x1c;
+		lock_cmp2_mode0 = 0x02;
+		lock_cmp_en = 0x04;
+		coreclk_div_mode0 = 0x14;
+		vco_tune1_mode0 = 0xfe;
+		vco_tune2_mode0 = 0x00;
+		code1_mode0 = 0x8d;
+		code2_mode0 = 0x27;
+		core_clk_en = 0x60;
+		cmn_config_1 = 0x76;
 		break;
 
 	case 2700:
 		hsclk_sel = 0x3;
-		dec_start_mode0 = 0x34;
-		div_frac_start2_mode0 = 0xc0;
-		div_frac_start3_mode0 = 0x0b;
-		lock_cmp1_mode0 = 0x07;
+		dec_start_mode0 = 0x46;
+		div_frac_start2_mode0 = 0x00;
+		div_frac_start3_mode0 = 0x05;
+		lock_cmp1_mode0 = 0x08;
 		lock_cmp2_mode0 = 0x07;
-		code1_mode0 = 0x71;
-		code2_mode0 = 0x0c;
+		lock_cmp_en = 0x08;
+		coreclk_div_mode0 = 0x14;
+		vco_tune1_mode0 = 0xae;
+		vco_tune2_mode0 = 0x02;
+		code1_mode0 = 0xf6;
+		code2_mode0 = 0x20;
+		core_clk_en = 0x00;
+		cmn_config_1 = 0x96;
 		break;
 
 	case 5400:
+		hsclk_sel = 0x1;
+		dec_start_mode0 = 0x46;
+		div_frac_start2_mode0 = 0x00;
+		div_frac_start3_mode0 = 0x05;
+		lock_cmp1_mode0 = 0x10;
+		lock_cmp2_mode0 = 0x0e;
+		lock_cmp_en = 0x08;
+		coreclk_div_mode0 = 0x14;
+		vco_tune1_mode0 = 0xae;
+		vco_tune2_mode0 = 0x02;
+		code1_mode0 = 0xf6;
+		code2_mode0 = 0x20;
+		core_clk_en = 0x00;
+		cmn_config_1 = 0x56;
+		break;
+
 	case 8100:
 		hsclk_sel = 0x2;
 		dec_start_mode0 = 0x4f;
@@ -1011,8 +1269,14 @@ static int qcom_edp_com_configure_pll_v8(const struct qcom_edp *edp)
 		div_frac_start3_mode0 = 0x01;
 		lock_cmp1_mode0 = 0x18;
 		lock_cmp2_mode0 = 0x15;
+		lock_cmp_en = 0x08;
+		coreclk_div_mode0 = 0x0a;
+		vco_tune1_mode0 = 0xa0;
+		vco_tune2_mode0 = 0x01;
 		code1_mode0 = 0x14;
 		code2_mode0 = 0x25;
+		core_clk_en = 0x00;
+		cmn_config_1 = 0x96;
 		break;
 
 	default:
@@ -1028,7 +1292,7 @@ static int qcom_edp_com_configure_pll_v8(const struct qcom_edp *edp)
 	writel(0x30, edp->pll + DP_QSERDES_V8_COM_CLK_SELECT);
 	writel(hsclk_sel, edp->pll + DP_QSERDES_V8_COM_HSCLK_SEL_1);
 	writel(0x07, edp->pll + DP_QSERDES_V8_COM_PLL_IVCO);
-	writel(0x00, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP_EN);
+	writel(lock_cmp_en, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP_EN);
 	writel(0x36, edp->pll + DP_QSERDES_V8_COM_PLL_CCTRL_MODE0);
 	writel(0x16, edp->pll + DP_QSERDES_V8_COM_PLL_RCTRL_MODE0);
 	writel(0x06, edp->pll + DP_QSERDES_V8_COM_CP_CTRL_MODE0);
@@ -1036,7 +1300,7 @@ static int qcom_edp_com_configure_pll_v8(const struct qcom_edp *edp)
 	writel(0x00, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START1_MODE0);
 	writel(div_frac_start2_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START2_MODE0);
 	writel(div_frac_start3_mode0, edp->pll + DP_QSERDES_V8_COM_DIV_FRAC_START3_MODE0);
-	writel(0x96, edp->pll + DP_QSERDES_V8_COM_CMN_CONFIG_1);
+	writel(cmn_config_1, edp->pll + DP_QSERDES_V8_COM_CMN_CONFIG_1);
 	writel(0x3f, edp->pll + DP_QSERDES_V8_COM_INTEGLOOP_GAIN0_MODE0);
 	writel(0x00, edp->pll + DP_QSERDES_V8_COM_INTEGLOOP_GAIN1_MODE0);
 	writel(0x00, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE_MAP);
@@ -1044,12 +1308,12 @@ static int qcom_edp_com_configure_pll_v8(const struct qcom_edp *edp)
 	writel(lock_cmp2_mode0, edp->pll + DP_QSERDES_V8_COM_LOCK_CMP2_MODE0);
 
 	writel(0x0a, edp->pll + DP_QSERDES_V8_COM_BG_TIMER);
-	writel(0x0a, edp->pll + DP_QSERDES_V8_COM_CORECLK_DIV_MODE0);
+	writel(coreclk_div_mode0, edp->pll + DP_QSERDES_V8_COM_CORECLK_DIV_MODE0);
 	writel(0x00, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE_CTRL);
 	writel(0x1f, edp->pll + DP_QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN);
-	writel(0x00, edp->pll + DP_QSERDES_V8_COM_CORE_CLK_EN);
-	writel(0xa0, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE1_MODE0);
-	writel(0x01, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE2_MODE0);
+	writel(core_clk_en, edp->pll + DP_QSERDES_V8_COM_CORE_CLK_EN);
+	writel(vco_tune1_mode0, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE1_MODE0);
+	writel(vco_tune2_mode0, edp->pll + DP_QSERDES_V8_COM_VCO_TUNE2_MODE0);
 
 	writel(code1_mode0, edp->pll + DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0);
 	writel(code2_mode0, edp->pll + DP_QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0);
@@ -1104,27 +1368,85 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v8 = {
 	.com_clk_fwd_cfg	= qcom_edp_com_clk_fwd_cfg_v8,
 	.com_configure_pll	= qcom_edp_com_configure_pll_v8,
 	.com_configure_ssc	= qcom_edp_com_configure_ssc_v8,
-	.com_ldo_config		= qcom_edp_ldo_config_v6,
-	.prepare_power_on	= qcom_edp_prepare_power_on_v46,
-	.configure_tx_pre_pll	= qcom_edp_configure_tx_pre_pll_v46,
-	.configure_rate_pcs	= qcom_edp_configure_rate_pcs_v46,
-	.configure_lanes_after_pll = qcom_edp_configure_lanes_after_pll_v46,
-	.finish_power_on	= qcom_edp_finish_power_on_v46,
+	.com_ldo_config		= qcom_edp_ldo_config_v8,
+	.prepare_power_on	= qcom_edp_prepare_power_on_v8,
+	.configure_tx_pre_pll	= qcom_edp_configure_tx_pre_pll_v8,
+	.configure_rate_pcs	= qcom_edp_configure_rate_pcs_v8,
+	.configure_lanes_after_pll = qcom_edp_configure_lanes_after_pll_v8,
+	.finish_power_on	= qcom_edp_finish_power_on_v8,
 };
 
 static struct qcom_edp_phy_cfg glymur_phy_cfg = {
 	.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,
-	.edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg,
+	.edp_swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v8,
 	.ver_ops = &qcom_edp_phy_ops_v8,
 };
 
+static void qcom_edp_disable_dcc(const struct qcom_edp *edp)
+{
+	writel(0x06, edp->tx0 + TXn_DCC0_CTRL);
+	writel(0x06, edp->tx0 + TXn_DCC1_CTRL);
+	writel(0x06, edp->tx1 + TXn_DCC0_CTRL);
+	writel(0x06, edp->tx1 + TXn_DCC1_CTRL);
+}
+
+static int qcom_edp_run_dcc_calibration(const struct qcom_edp *edp)
+{
+	u32 val;
+	int ret;
+
+	writel(0x07, edp->tx0 + TXn_DCC0_CTRL);
+	writel(0x07, edp->tx0 + TXn_DCC1_CTRL);
+
+	if (edp->dp_opts.lanes > 2) {
+		writel(0x07, edp->tx1 + TXn_DCC0_CTRL);
+		writel(0x07, edp->tx1 + TXn_DCC1_CTRL);
+	}
+
+	ret = readl_poll_timeout(edp->tx0 + TXn_DCC_DONE,
+				 val, (val & GENMASK(1, 0)) == GENMASK(1, 0),
+				 500, 10000);
+	if (ret)
+		goto out_disable_dcc;
+
+	if (edp->dp_opts.lanes > 2) {
+		ret = readl_poll_timeout(edp->tx1 + TXn_DCC_DONE,
+					 val, (val & GENMASK(1, 0)) == GENMASK(1, 0),
+					 500, 10000);
+	}
+
+out_disable_dcc:
+	qcom_edp_disable_dcc(edp);
+
+	return ret;
+}
+
+static void qcom_edp_run_tsync(const struct qcom_edp *edp)
+{
+	writel(0x0f, edp->tx0 + TXn_RESET_TSYNC_EN);
+	writel(0x0f, edp->tx1 + TXn_RESET_TSYNC_EN);
+	writel(0x03, edp->edp + DP_PHY_TSYNC_OVRD);
+	writel(0x23, edp->edp + DP_PHY_TSYNC_OVRD);
+	writel(0x22, edp->edp + DP_PHY_TSYNC_OVRD);
+	writel(0x0a, edp->tx0 + TXn_RESET_TSYNC_EN);
+	writel(0x0a, edp->tx1 + TXn_RESET_TSYNC_EN);
+	writel(0x3e, edp->edp + DP_PHY_TSYNC_OVRD);
+}
+
 static int qcom_edp_prepare_power_on_v46(const struct qcom_edp *edp)
 {
 	return 0;
 }
 
+static int qcom_edp_prepare_power_on_v8(const struct qcom_edp *edp)
+{
+	qcom_edp_disable_dcc(edp);
+
+	return 0;
+}
+
 static int qcom_edp_configure_tx_pre_pll_v46(const struct qcom_edp *edp)
 {
 	writel(0x05, edp->edp + DP_PHY_TX0_TX1_LANE_CTL);
@@ -1145,6 +1467,14 @@ static int qcom_edp_configure_tx_pre_pll_v46(const struct qcom_edp *edp)
 	return 0;
 }
 
+static int qcom_edp_configure_tx_pre_pll_v8(const struct qcom_edp *edp)
+{
+	writel(0x05, edp->edp + DP_PHY_TX0_TX1_LANE_CTL);
+	writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL);
+
+	return qcom_edp_configure_tx_pre_pll_v8_lanes(edp);
+}
+
 static void qcom_edp_configure_lanes_after_pll_v46(const struct qcom_edp *edp)
 {
 	u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
@@ -1201,6 +1531,22 @@ static int qcom_edp_configure_rate_pcs_v46(const struct qcom_edp *edp,
 	return qcom_edp_set_vco_div(edp, pixel_freq);
 }
 
+static int qcom_edp_configure_rate_pcs_v8(const struct qcom_edp *edp,
+					  unsigned long *pixel_freq)
+{
+	int ret;
+
+	ret = qcom_edp_set_vco_div(edp, pixel_freq);
+	if (ret)
+		return ret;
+
+	ret = qcom_edp_set_link_rate_aux_cfg2(edp);
+	if (ret)
+		return ret;
+
+	return qcom_edp_configure_pcs_v8(edp);
+}
+
 static int qcom_edp_start_pll(const struct qcom_edp *edp)
 {
 	int ret;
@@ -1231,6 +1577,24 @@ static int qcom_edp_finish_power_on_v46(const struct qcom_edp *edp)
 				  500, 10000);
 }
 
+static int qcom_edp_finish_power_on_v8(const struct qcom_edp *edp)
+{
+	u32 val;
+	int ret;
+
+	qcom_edp_run_tsync(edp);
+	writel(0x08, edp->edp + DP_PHY_CFG);
+	usleep_range(100, 1000);
+	writel(0x09, edp->edp + DP_PHY_CFG);
+
+	ret = readl_poll_timeout(edp->edp + DP_PHY_STATUS_V8, val, val & BIT(1),
+				 500, 10000);
+	if (ret)
+		return ret;
+
+	return qcom_edp_run_dcc_calibration(edp);
+}
+
 static int qcom_edp_phy_power_on(struct phy *phy)
 {
 	const struct qcom_edp *edp = phy_get_drvdata(phy);

-- 
2.53.0


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 2/2] phy: qcom: edp: update v8 power-on programming sequence
  2026-06-22 23:29 ` [PATCH 2/2] phy: qcom: edp: update v8 power-on programming sequence Bjorn Andersson
@ 2026-06-22 23:41   ` sashiko-bot
  0 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-06-22 23:41 UTC (permalink / raw)
  To: Bjorn Andersson; +Cc: neil.armstrong, olteanv, vkoul, linux-phy

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing handling for 1-lane eDP/DP configuration in the v8 PHY sequence, resulting in an inconsistent fallback to 4-lane configuration for tx1.
--

commit 86692efb0406428e7857a2fe90f5797a7385d5e6
Author: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>

phy: qcom: edp: update v8 power-on programming sequence

This commit updates the v8 eDP PHY programming sequence to match documented 
hardware requirements. It adjusts settings across several configuration stages
including AUX, TX lanes, PCS, PLL, and DCC to improve support for various link
rates and lane configurations.

> diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
> index 6588419d4860b..c5d1fa0ae6cb7 100644
> --- a/drivers/phy/qualcomm/phy-qcom-edp.c
> +++ b/drivers/phy/qualcomm/phy-qcom-edp.c
[ ... ]
> @@ -427,6 +491,145 @@ static int qcom_edp_configure_pll(const struct qcom_edp *edp)
[ ... ]
> +static void qcom_edp_configure_lanes_after_pll_v8(const struct qcom_edp *edp)
> +{
> +	if (edp->dp_opts.lanes == 2) {
> +		writel(0x1b, edp->tx0 + TXn_HIGHZ_DRVR_EN);
[ ... ]
> +	} else {
> +		writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN);
> +		writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
> +		writel(0x04, edp->tx0 + TXn_HIGHZ_DRVR_EN);
> +		writel(0x00, edp->tx0 + TXn_TX_POL_INV);
> +
> +		writel(0x1f, edp->tx1 + TXn_HIGHZ_DRVR_EN);
> +		writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);

[Severity: Medium]
What happens if the DP framework requests a 1-lane configuration, such as
during a link training fallback?

Since there is no explicit check for edp->dp_opts.lanes == 1, a 1-lane
configuration will fall into this else block, which configures tx1 as if it
were in a 4-lane setup by enabling its transceiver driver and bias.

However, as seen in qcom_edp_ldo_config_v8() below, the tx1 LDO is correctly
kept unpowered (0x00) for lanes <= 2. Could this create an electrical conflict
or cause link training to fail, because the tx1 transceivers are enabled while
the LDO remains unpowered?

Should 1-lane mode be explicitly handled here or rejected with -EINVAL early
in the power-on sequence?

> +		writel(0x04, edp->tx1 + TXn_HIGHZ_DRVR_EN);
> +		writel(0x00, edp->tx1 + TXn_TX_POL_INV);
> +	}
> +}
[ ... ]
> @@ -911,6 +1114,22 @@ static int qcom_edp_ldo_config_v6(const struct qcom_edp *edp)
[ ... ]
> +static int qcom_edp_ldo_config_v8(const struct qcom_edp *edp)
> +{
> +	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
> +	u32 ldo_config;
> +
> +	if (edp->is_edp)
> +		ldo_config = 0xd0;
> +	else
> +		ldo_config = 0x00;
> +
> +	writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
> +	writel(dp_opts->lanes > 2 ? ldo_config : 0x00, edp->tx1 + TXn_LDO_CONFIG);
> +
> +	return 0;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-glymur-edp-phy-v1-0-814b45089ac9@oss.qualcomm.com?part=2

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-22 23:41 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 23:29 [PATCH 0/2] phy: qcom: edp: Update v8 programming sequence Bjorn Andersson
2026-06-22 23:29 ` [PATCH 1/2] phy: qcom: edp: split power-on sequencing by PHY version Bjorn Andersson
2026-06-22 23:29 ` [PATCH 2/2] phy: qcom: edp: update v8 power-on programming sequence Bjorn Andersson
2026-06-22 23:41   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox