* [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