Add QCS615-specific configuration for USB/DP PHY, including DP init
routines, voltage swing tables, and platform data. Add compatible
"qcs615-qmp-usb3-dp-phy".
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++
1 file changed, 395 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 8030422d64382aa231d69dec9788778cdb0f218e..cc49310a23ca6aaea8fd3baab797633842953895 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -30,6 +30,7 @@
#include "phy-qcom-qmp-pcs-misc-v3.h"
#include "phy-qcom-qmp-dp-phy.h"
+#include "phy-qcom-qmp-dp-phy-v2.h"
#define PHY_INIT_COMPLETE_TIMEOUT 10000
#define SW_PORTSELECT_VAL BIT(0)
@@ -289,6 +290,86 @@ static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),
};
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_CTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x02),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_rbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x2c),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x21),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE_1, 0xc6),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x69),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE_1, 0xc4),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_serdes_tbl_hbr2[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x8c),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x70),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_LANE_MODE_1, 0xc4),
+};
+
+static const struct qmp_phy_init_tbl qmp_v2_dp_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRANSCEIVER_BIAS_EN, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_VMODE_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_PRE_STALL_LDO_BOOST_EN, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_INTERFACE_SELECT, 0x3d),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_CLKBUF_ENABLE, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RESET_TSYNC_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TRAN_DRVR_EMP_EN, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_INTERFACE_MODE, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_EMP_POST1_LVL, 0x2b),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_DRV_LVL, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_TX_BAND, 0x4),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_TX, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V2_TX_RES_CODE_LANE_OFFSET_RX, 0x12),
+};
+
struct qmp_usbc_offsets {
u16 serdes;
u16 pcs;
@@ -463,6 +544,34 @@ static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {
.rx2 = 0x800,
};
+static const struct qmp_usbc_offsets qmp_usbc_usb3dp_offsets_qcs615 = {
+ .serdes = 0x0,
+ .pcs = 0xc00,
+ .pcs_misc = 0xa00,
+ .tx = 0x200,
+ .rx = 0x400,
+ .tx2 = 0x600,
+ .rx2 = 0x800,
+ .dp_serdes = 0x1c00,
+ .dp_txa = 0x1400,
+ .dp_txb = 0x1800,
+ .dp_dp_phy = 0x1000,
+};
+
+static const u8 qmp_v2_dp_pre_emphasis_hbr2_rbr[4][4] = {
+ {0x00, 0x0b, 0x12, 0xff},
+ {0x00, 0x0a, 0x12, 0xff},
+ {0x00, 0x0c, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff}
+};
+
+static const u8 qmp_v2_dp_voltage_swing_hbr2_rbr[4][4] = {
+ {0x07, 0x0f, 0x14, 0xff},
+ {0x11, 0x1d, 0x1f, 0xff},
+ {0x18, 0x1f, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff}
+};
+
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
.offsets = &qmp_usbc_offsets_v3_qcm2290,
@@ -535,6 +644,51 @@ static const struct qmp_phy_cfg qcs615_usb3phy_cfg = {
.regs = qmp_v3_usb3phy_regs_layout_qcm2290,
};
+static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp);
+static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp);
+static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp);
+static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp);
+
+static const struct qmp_phy_cfg qcs615_usb3dp_phy_cfg = {
+ .offsets = &qmp_usbc_usb3dp_offsets_qcs615,
+
+ .serdes_tbl = qcm2290_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl),
+ .tx_tbl = qcm2290_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl),
+ .rx_tbl = qcm2290_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl),
+ .pcs_tbl = qcm2290_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl),
+
+ .regs = qmp_v3_usb3phy_regs_layout_qcm2290,
+
+ .dp_serdes_tbl = qmp_v2_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v2_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v2_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v2_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v2_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v2_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v2_dp_serdes_tbl_hbr2),
+
+ .swing_tbl = &qmp_v2_dp_voltage_swing_hbr2_rbr,
+ .pre_emphasis_tbl = &qmp_v2_dp_pre_emphasis_hbr2_rbr,
+
+ .dp_aux_init = qmp_v2_dp_aux_init,
+ .configure_dp_tx = qmp_v2_configure_dp_tx,
+ .configure_dp_phy = qmp_v2_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v2_calibrate_dp_phy,
+
+ .reset_list = usb3dpphy_reset_l,
+ .num_resets = ARRAY_SIZE(usb3dpphy_reset_l),
+ .vreg_list = qmp_phy_qcs615_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_qcs615_vreg_l),
+};
+
static void qmp_usbc_set_phy_mode(struct qmp_usbc *qmp, bool is_dp)
{
if (qmp->tcsr_map && qmp->dp_phy_mode_reg)
@@ -593,6 +747,244 @@ static int qmp_usbc_com_exit(struct phy *phy)
return 0;
}
+static void qmp_v2_dp_aux_init(struct qmp_usbc *qmp)
+{
+ writel(DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN,
+ qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0);
+ writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2);
+ writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG3);
+ writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG4);
+ writel(0x26, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG5);
+ writel(0x0a, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG6);
+ writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG7);
+ writel(0xbb, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG8);
+ writel(0x03, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG9);
+ qmp->dp_aux_cfg = 0;
+
+ writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
+ PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
+ PHY_AUX_REQ_ERR_MASK,
+ qmp->dp_dp_phy + QSERDES_V2_DP_PHY_AUX_INTERRUPT_MASK);
+}
+
+static int qmp_v2_configure_dp_swing(struct qmp_usbc *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+ unsigned int v_level = 0, p_level = 0;
+ u8 voltage_swing_cfg, pre_emphasis_cfg;
+ int i;
+
+ if (dp_opts->lanes > 4) {
+ dev_err(qmp->dev, "Invalid lane_num(%d)\n", dp_opts->lanes);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dp_opts->lanes; i++) {
+ v_level = max(v_level, dp_opts->voltage[i]);
+ p_level = max(p_level, dp_opts->pre[i]);
+ }
+
+ if (v_level > 4 || p_level > 4) {
+ dev_err(qmp->dev, "Invalid v(%d) | p(%d) level)\n",
+ v_level, p_level);
+ return -EINVAL;
+ }
+
+ voltage_swing_cfg = (*cfg->swing_tbl)[v_level][p_level];
+ pre_emphasis_cfg = (*cfg->pre_emphasis_tbl)[v_level][p_level];
+
+ voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN;
+ pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN;
+
+ if (voltage_swing_cfg == 0xff && pre_emphasis_cfg == 0xff)
+ return -EINVAL;
+
+ writel(voltage_swing_cfg, tx + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(pre_emphasis_cfg, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+ writel(voltage_swing_cfg, tx2 + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(pre_emphasis_cfg, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+
+ return 0;
+}
+
+static void qmp_usbc_configure_dp_mode(struct qmp_usbc *qmp)
+{
+ bool reverse = (qmp->orientation == TYPEC_ORIENTATION_REVERSE);
+ u32 val;
+
+ val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
+ DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN;
+
+ writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ if (reverse)
+ writel(0xc9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+ else
+ writel(0xd9, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+}
+
+static int qmp_usbc_configure_dp_clocks(struct qmp_usbc *qmp)
+{
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+ u32 phy_vco_div;
+ unsigned long pixel_freq;
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ phy_vco_div = 0x1;
+ pixel_freq = 1620000000UL / 2;
+ break;
+ case 2700:
+ phy_vco_div = 0x1;
+ pixel_freq = 2700000000UL / 2;
+ break;
+ case 5400:
+ phy_vco_div = 0x2;
+ pixel_freq = 5400000000UL / 4;
+ break;
+ default:
+ dev_err(qmp->dev, "link rate:%d not supported\n", dp_opts->link_rate);
+ return -EINVAL;
+ }
+ writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_VCO_DIV);
+
+ clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000);
+ clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq);
+
+ return 0;
+}
+
+static void qmp_v2_configure_dp_tx(struct qmp_usbc *qmp)
+{
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+
+ /* program default setting first */
+ writel(0x2a, tx + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(0x20, tx + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+ writel(0x2a, tx2 + QSERDES_V2_TX_TX_DRV_LVL);
+ writel(0x20, tx2 + QSERDES_V2_TX_TX_EMP_POST1_LVL);
+
+ qmp_v2_configure_dp_swing(qmp);
+}
+
+static int qmp_v2_configure_dp_phy(struct qmp_usbc *qmp)
+{
+ u32 status;
+ int ret;
+
+ qmp_usbc_configure_dp_mode(qmp);
+
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX0_TX1_LANE_CTL);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_V2_DP_PHY_TX2_TX3_LANE_CTL);
+
+ ret = qmp_usbc_configure_dp_clocks(qmp);
+ if (ret)
+ return ret;
+
+ writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ writel(0x20, qmp->dp_serdes + QSERDES_COM_RESETSM_CNTRL);
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_C_READY_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)) {
+ dev_err(qmp->dev, "C_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "FREQ_DONE not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_serdes + QSERDES_COM_CMN_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PLL_LOCKED not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(0)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "TSYNC_DONE not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PHY_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN);
+ writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN);
+ writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV);
+ writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN);
+ writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN);
+ writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV);
+
+ writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+ writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG);
+
+ if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS,
+ status,
+ ((status & BIT(1)) > 0),
+ 500,
+ 10000)){
+ dev_err(qmp->dev, "PHY_READY not ready\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int qmp_v2_calibrate_dp_phy(struct qmp_usbc *qmp)
+{
+ static const u8 cfg1_settings[] = {0x13, 0x23, 0x1d};
+ u8 val;
+
+ qmp->dp_aux_cfg++;
+ qmp->dp_aux_cfg %= ARRAY_SIZE(cfg1_settings);
+ val = cfg1_settings[qmp->dp_aux_cfg];
+
+ writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1);
+
+ return 0;
+}
+
static int qmp_usbc_usb_power_on(struct phy *phy)
{
struct qmp_usbc *qmp = phy_get_drvdata(phy);
@@ -1605,6 +1997,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = {
}, {
.compatible = "qcom,qcm2290-qmp-usb3-phy",
.data = &qcm2290_usb3phy_cfg,
+ }, {
+ .compatible = "qcom,qcs615-qmp-usb3-dp-phy",
+ .data = &qcs615_usb3dp_phy_cfg,
}, {
.compatible = "qcom,qcs615-qmp-usb3-phy",
.data = &qcs615_usb3phy_cfg,
--
2.34.1
On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: > Add QCS615-specific configuration for USB/DP PHY, including DP init > routines, voltage swing tables, and platform data. Add compatible > "qcs615-qmp-usb3-dp-phy". > > Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> > --- > drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ > 1 file changed, 395 insertions(+) > > + > + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); > + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); > + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); > + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); > + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); > + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); Are you sure that these don't need to be adjusted based on qmp->orientation or selected lanes count? In fact... I don't see orientation handling for DP at all. Don't we need it? > + > + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); > + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); > + > + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, > + status, > + ((status & BIT(1)) > 0), > + 500, > + 10000)){ > + dev_err(qmp->dev, "PHY_READY not ready\n"); > + return -ETIMEDOUT; > + } > + > + return 0; > +} > + -- With best wishes Dmitry
On 9/20/2025 2:41 AM, Dmitry Baryshkov wrote: > On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: >> Add QCS615-specific configuration for USB/DP PHY, including DP init >> routines, voltage swing tables, and platform data. Add compatible >> "qcs615-qmp-usb3-dp-phy". >> >> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> >> --- >> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ >> 1 file changed, 395 insertions(+) >> >> + >> + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >> + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); >> + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); >> + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >> + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); >> + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); > Are you sure that these don't need to be adjusted based on > qmp->orientation or selected lanes count? > > In fact... I don't see orientation handling for DP at all. Don't we need > it? Thanks for the review. I agree with your reasoning and compared talos 14nm HPG with hana/kona 7nm PHY HPG; the 7nm COMBO PHY series has orientation/lane-count dependent configs, but the 14nm PHY series does not. On QCS615 (talos), the TX_* registers you pointed to are programmed with constant values regardless of orientation or lane count. This has been confirmed from both the HPG and the downstream reference driver. For orientation, from reference the only difference is DP_PHY_MODE, which is set by qmp_usbc_configure_dp_mode(). The DP PHY does have an SW_PORTSELECT-related register, but due to talos lane mapping from the DP controller to the PHY not being the standard <0 1 2 3> sequence, it cannot reliably handle orientation flip. Also, QCS615 is a fixed- orientation platform (not DP-over-TypeC), so there is no validated hardware path for orientation flip on this platform. > >> + >> + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); >> + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); >> + >> + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, >> + status, >> + ((status & BIT(1)) > 0), >> + 500, >> + 10000)){ >> + dev_err(qmp->dev, "PHY_READY not ready\n"); >> + return -ETIMEDOUT; >> + } >> + >> + return 0; >> +} >> +
On Mon, Sep 22, 2025 at 02:58:17PM +0800, Xiangxu Yin wrote: > > On 9/20/2025 2:41 AM, Dmitry Baryshkov wrote: > > On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: > >> Add QCS615-specific configuration for USB/DP PHY, including DP init > >> routines, voltage swing tables, and platform data. Add compatible > >> "qcs615-qmp-usb3-dp-phy". > >> > >> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> > >> --- > >> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ > >> 1 file changed, 395 insertions(+) > >> > >> + > >> + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); > >> + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); > >> + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); > >> + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); > >> + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); > >> + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); > > Are you sure that these don't need to be adjusted based on > > qmp->orientation or selected lanes count? > > > > In fact... I don't see orientation handling for DP at all. Don't we need > > it? > > > Thanks for the review. > > I agree with your reasoning and compared talos 14nm HPG with hana/kona > 7nm PHY HPG; the 7nm COMBO PHY series has orientation/lane-count dependent > configs, but the 14nm PHY series does not. On QCS615 (talos), the TX_* > registers you pointed to are programmed with constant values regardless > of orientation or lane count. This has been confirmed from both the HPG > and the downstream reference driver. Thanks for the confirmation. > > For orientation, from reference the only difference is DP_PHY_MODE, which > is set by qmp_usbc_configure_dp_mode(). The DP PHY does have an > SW_PORTSELECT-related register, but due to talos lane mapping from the > DP controller to the PHY not being the standard <0 1 2 3> sequence, it > cannot reliably handle orientation flip. Also, QCS615 is a fixed- > orientation platform (not DP-over-TypeC), so there is no validated hardware > path for orientation flip on this platform. Wait... I thought that the the non-standard lane order is handled by the DP driver, then we should be able to handle the orientation inside PHY driver as usual. Anyway, please add a FIXME comment into the source file and a note to the commit message that SW_PORTSELECT should be handled, but it's not a part of this patch for the stated reasons. > > > > > >> + > >> + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); > >> + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); > >> + > >> + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, > >> + status, > >> + ((status & BIT(1)) > 0), > >> + 500, > >> + 10000)){ > >> + dev_err(qmp->dev, "PHY_READY not ready\n"); > >> + return -ETIMEDOUT; > >> + } > >> + > >> + return 0; > >> +} > >> + -- With best wishes Dmitry
On 9/22/2025 5:45 PM, Dmitry Baryshkov wrote: > On Mon, Sep 22, 2025 at 02:58:17PM +0800, Xiangxu Yin wrote: >> On 9/20/2025 2:41 AM, Dmitry Baryshkov wrote: >>> On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: >>>> Add QCS615-specific configuration for USB/DP PHY, including DP init >>>> routines, voltage swing tables, and platform data. Add compatible >>>> "qcs615-qmp-usb3-dp-phy". >>>> >>>> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> >>>> --- >>>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ >>>> 1 file changed, 395 insertions(+) >>>> >>>> + >>>> + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >>>> + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); >>>> + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); >>>> + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >>>> + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); >>>> + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); >>> Are you sure that these don't need to be adjusted based on >>> qmp->orientation or selected lanes count? >>> >>> In fact... I don't see orientation handling for DP at all. Don't we need >>> it? >> >> Thanks for the review. >> >> I agree with your reasoning and compared talos 14nm HPG with hana/kona >> 7nm PHY HPG; the 7nm COMBO PHY series has orientation/lane-count dependent >> configs, but the 14nm PHY series does not. On QCS615 (talos), the TX_* >> registers you pointed to are programmed with constant values regardless >> of orientation or lane count. This has been confirmed from both the HPG >> and the downstream reference driver. > Thanks for the confirmation. > >> For orientation, from reference the only difference is DP_PHY_MODE, which >> is set by qmp_usbc_configure_dp_mode(). The DP PHY does have an >> SW_PORTSELECT-related register, but due to talos lane mapping from the >> DP controller to the PHY not being the standard <0 1 2 3> sequence, it >> cannot reliably handle orientation flip. Also, QCS615 is a fixed- >> orientation platform (not DP-over-TypeC), so there is no validated hardware >> path for orientation flip on this platform. > Wait... I thought that the the non-standard lane order is handled by the > DP driver, then we should be able to handle the orientation inside PHY > driver as usual. Yes, I have confirmed this with our verification team. For the non-standard lane order, handling flip requires swapping mapped lane 0 ↔ lane 3 and lane 1 ↔ lane 2 in the logical2physical mapping. This is a hardware limitation, and with the current PHY driver we cannot propagate orientation status to dp_ctrl for processing. > Anyway, please add a FIXME comment into the source file and a note to > the commit message that SW_PORTSELECT should be handled, but it's not a > part of this patch for the stated reasons. OK, I will add a |FIXME| comment in |qmp_usbc_dp_power_on| and update the related commit message. >> >>>> + >>>> + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); >>>> + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); >>>> + >>>> + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, >>>> + status, >>>> + ((status & BIT(1)) > 0), >>>> + 500, >>>> + 10000)){ >>>> + dev_err(qmp->dev, "PHY_READY not ready\n"); >>>> + return -ETIMEDOUT; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> +
On Mon, Sep 22, 2025 at 07:28:17PM +0800, Xiangxu Yin wrote: > > On 9/22/2025 5:45 PM, Dmitry Baryshkov wrote: > > On Mon, Sep 22, 2025 at 02:58:17PM +0800, Xiangxu Yin wrote: > >> On 9/20/2025 2:41 AM, Dmitry Baryshkov wrote: > >>> On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: > >>>> Add QCS615-specific configuration for USB/DP PHY, including DP init > >>>> routines, voltage swing tables, and platform data. Add compatible > >>>> "qcs615-qmp-usb3-dp-phy". > >>>> > >>>> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> > >>>> --- > >>>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ > >>>> 1 file changed, 395 insertions(+) > >>>> > >>>> + > >>>> + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); > >>>> + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); > >>>> + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); > >>>> + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); > >>>> + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); > >>>> + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); > >>> Are you sure that these don't need to be adjusted based on > >>> qmp->orientation or selected lanes count? > >>> > >>> In fact... I don't see orientation handling for DP at all. Don't we need > >>> it? > >> > >> Thanks for the review. > >> > >> I agree with your reasoning and compared talos 14nm HPG with hana/kona > >> 7nm PHY HPG; the 7nm COMBO PHY series has orientation/lane-count dependent > >> configs, but the 14nm PHY series does not. On QCS615 (talos), the TX_* > >> registers you pointed to are programmed with constant values regardless > >> of orientation or lane count. This has been confirmed from both the HPG > >> and the downstream reference driver. > > Thanks for the confirmation. > > > >> For orientation, from reference the only difference is DP_PHY_MODE, which > >> is set by qmp_usbc_configure_dp_mode(). The DP PHY does have an > >> SW_PORTSELECT-related register, but due to talos lane mapping from the > >> DP controller to the PHY not being the standard <0 1 2 3> sequence, it > >> cannot reliably handle orientation flip. Also, QCS615 is a fixed- > >> orientation platform (not DP-over-TypeC), so there is no validated hardware > >> path for orientation flip on this platform. > > Wait... I thought that the the non-standard lane order is handled by the > > DP driver, then we should be able to handle the orientation inside PHY > > driver as usual. > > > Yes, I have confirmed this with our verification team. > > For the non-standard lane order, handling flip requires swapping mapped > lane 0 ↔ lane 3 and lane 1 ↔ lane 2 in the logical2physical mapping. > This is a hardware limitation, and with the current PHY driver we cannot > propagate orientation status to dp_ctrl for processing. This might mean that we might need to make DP host receive mux messages... > > > > Anyway, please add a FIXME comment into the source file and a note to > > the commit message that SW_PORTSELECT should be handled, but it's not a > > part of this patch for the stated reasons. > > > OK, I will add a |FIXME| comment in |qmp_usbc_dp_power_on| and update the > related commit message. Thanks! -- With best wishes Dmitry
On 9/23/2025 7:38 AM, Dmitry Baryshkov wrote: > On Mon, Sep 22, 2025 at 07:28:17PM +0800, Xiangxu Yin wrote: >> On 9/22/2025 5:45 PM, Dmitry Baryshkov wrote: >>> On Mon, Sep 22, 2025 at 02:58:17PM +0800, Xiangxu Yin wrote: >>>> On 9/20/2025 2:41 AM, Dmitry Baryshkov wrote: >>>>> On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: >>>>>> Add QCS615-specific configuration for USB/DP PHY, including DP init >>>>>> routines, voltage swing tables, and platform data. Add compatible >>>>>> "qcs615-qmp-usb3-dp-phy". >>>>>> >>>>>> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> >>>>>> --- >>>>>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ >>>>>> 1 file changed, 395 insertions(+) >>>>>> >>>>>> + >>>>>> + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >>>>>> + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); >>>>>> + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); >>>>>> + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >>>>>> + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); >>>>>> + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); >>>>> Are you sure that these don't need to be adjusted based on >>>>> qmp->orientation or selected lanes count? >>>>> >>>>> In fact... I don't see orientation handling for DP at all. Don't we need >>>>> it? >>>> Thanks for the review. >>>> >>>> I agree with your reasoning and compared talos 14nm HPG with hana/kona >>>> 7nm PHY HPG; the 7nm COMBO PHY series has orientation/lane-count dependent >>>> configs, but the 14nm PHY series does not. On QCS615 (talos), the TX_* >>>> registers you pointed to are programmed with constant values regardless >>>> of orientation or lane count. This has been confirmed from both the HPG >>>> and the downstream reference driver. >>> Thanks for the confirmation. >>> >>>> For orientation, from reference the only difference is DP_PHY_MODE, which >>>> is set by qmp_usbc_configure_dp_mode(). The DP PHY does have an >>>> SW_PORTSELECT-related register, but due to talos lane mapping from the >>>> DP controller to the PHY not being the standard <0 1 2 3> sequence, it >>>> cannot reliably handle orientation flip. Also, QCS615 is a fixed- >>>> orientation platform (not DP-over-TypeC), so there is no validated hardware >>>> path for orientation flip on this platform. >>> Wait... I thought that the the non-standard lane order is handled by the >>> DP driver, then we should be able to handle the orientation inside PHY >>> driver as usual. >> >> Yes, I have confirmed this with our verification team. >> >> For the non-standard lane order, handling flip requires swapping mapped >> lane 0 ↔ lane 3 and lane 1 ↔ lane 2 in the logical2physical mapping. >> This is a hardware limitation, and with the current PHY driver we cannot >> propagate orientation status to dp_ctrl for processing. > This might mean that we might need to make DP host receive mux > messages... Yeah, downstream handles this by passing orientation and lane_cnt info via the DP_PHY_SPARE0 PHY register. But even with that approach, dp_ctrl would still need access PHY address area. Let's see if there’s any follow-up on extending this in the future. >> >>> Anyway, please add a FIXME comment into the source file and a note to >>> the commit message that SW_PORTSELECT should be handled, but it's not a >>> part of this patch for the stated reasons. >> >> OK, I will add a |FIXME| comment in |qmp_usbc_dp_power_on| and update the >> related commit message. > Thanks! >
On 9/22/2025 5:45 PM, Dmitry Baryshkov wrote: > On Mon, Sep 22, 2025 at 02:58:17PM +0800, Xiangxu Yin wrote: >> On 9/20/2025 2:41 AM, Dmitry Baryshkov wrote: >>> On Fri, Sep 19, 2025 at 10:24:29PM +0800, Xiangxu Yin wrote: >>>> Add QCS615-specific configuration for USB/DP PHY, including DP init >>>> routines, voltage swing tables, and platform data. Add compatible >>>> "qcs615-qmp-usb3-dp-phy". >>>> >>>> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> >>>> --- >>>> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 395 +++++++++++++++++++++++++++++++ >>>> 1 file changed, 395 insertions(+) >>>> >>>> + >>>> + writel(0x3f, qmp->dp_tx + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >>>> + writel(0x10, qmp->dp_tx + QSERDES_V2_TX_HIGHZ_DRVR_EN); >>>> + writel(0x0a, qmp->dp_tx + QSERDES_V2_TX_TX_POL_INV); >>>> + writel(0x3f, qmp->dp_tx2 + QSERDES_V2_TX_TRANSCEIVER_BIAS_EN); >>>> + writel(0x10, qmp->dp_tx2 + QSERDES_V2_TX_HIGHZ_DRVR_EN); >>>> + writel(0x0a, qmp->dp_tx2 + QSERDES_V2_TX_TX_POL_INV); >>> Are you sure that these don't need to be adjusted based on >>> qmp->orientation or selected lanes count? >>> >>> In fact... I don't see orientation handling for DP at all. Don't we need >>> it? >> >> Thanks for the review. >> >> I agree with your reasoning and compared talos 14nm HPG with hana/kona >> 7nm PHY HPG; the 7nm COMBO PHY series has orientation/lane-count dependent >> configs, but the 14nm PHY series does not. On QCS615 (talos), the TX_* >> registers you pointed to are programmed with constant values regardless >> of orientation or lane count. This has been confirmed from both the HPG >> and the downstream reference driver. > Thanks for the confirmation. > >> For orientation, from reference the only difference is DP_PHY_MODE, which >> is set by qmp_usbc_configure_dp_mode(). The DP PHY does have an >> SW_PORTSELECT-related register, but due to talos lane mapping from the >> DP controller to the PHY not being the standard <0 1 2 3> sequence, it >> cannot reliably handle orientation flip. Also, QCS615 is a fixed- >> orientation platform (not DP-over-TypeC), so there is no validated hardware >> path for orientation flip on this platform. > Wait... I thought that the the non-standard lane order is handled by the > DP driver, then we should be able to handle the orientation inside PHY > driver as usual. Yes, I have confirmed this with our verification team. For the non-standard lane order, handling flip requires swapping mapped lane 0 ↔ lane 3 and lane 1 ↔ lane 2 in the logical2physical mapping. This is a hardware limitation, and with the current PHY driver we cannot propagate orientation status to dp_ctrl for processing. > Anyway, please add a FIXME comment into the source file and a note to > the commit message that SW_PORTSELECT should be handled, but it's not a > part of this patch for the stated reasons. OK, I will add a |FIXME| comment in |qmp_usbc_dp_power_on| and update the related commit message. >> >>>> + >>>> + writel(0x18, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); >>>> + writel(0x19, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); >>>> + >>>> + if (readl_poll_timeout(qmp->dp_dp_phy + QSERDES_V2_DP_PHY_STATUS, >>>> + status, >>>> + ((status & BIT(1)) > 0), >>>> + 500, >>>> + 10000)){ >>>> + dev_err(qmp->dev, "PHY_READY not ready\n"); >>>> + return -ETIMEDOUT; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> +
© 2016 - 2025 Red Hat, Inc.