Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: qcom: edp: Introduce support for DisplayPort

The eDP phy can be used to drive either eDP or DP output, with some
minor variations in some of the configuration and seemingly a need for
implementing swing and pre_emphasis calibration.

Introduce a config object, indicating if the phy is operating in eDP or
DP mode and swing/pre-emphasis calibration to support this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Link: https://lore.kernel.org/r/20220810040745.3582985-5-bjorn.andersson@linaro.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Bjorn Andersson and committed by
Vinod Koul
2300d1cb 5894ff12

+76 -4
+76 -4
drivers/phy/qualcomm/phy-qcom-edp.c
··· 70 70 71 71 #define TXn_TRAN_DRVR_EMP_EN 0x0078 72 72 73 + struct qcom_edp_cfg { 74 + bool is_dp; 75 + 76 + /* DP PHY swing and pre_emphasis tables */ 77 + const u8 (*swing_hbr_rbr)[4][4]; 78 + const u8 (*swing_hbr3_hbr2)[4][4]; 79 + const u8 (*pre_emphasis_hbr_rbr)[4][4]; 80 + const u8 (*pre_emphasis_hbr3_hbr2)[4][4]; 81 + }; 82 + 73 83 struct qcom_edp { 74 84 struct device *dev; 85 + const struct qcom_edp_cfg *cfg; 75 86 76 87 struct phy *phy; 77 88 ··· 103 92 static int qcom_edp_phy_init(struct phy *phy) 104 93 { 105 94 struct qcom_edp *edp = phy_get_drvdata(phy); 95 + const struct qcom_edp_cfg *cfg = edp->cfg; 106 96 int ret; 97 + u8 cfg8; 107 98 108 99 ret = regulator_bulk_enable(ARRAY_SIZE(edp->supplies), edp->supplies); 109 100 if (ret) ··· 130 117 DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, 131 118 edp->edp + DP_PHY_PD_CTL); 132 119 120 + if (cfg && cfg->is_dp) 121 + cfg8 = 0xb7; 122 + else 123 + cfg8 = 0x37; 124 + 125 + writel(0xfc, edp->edp + DP_PHY_MODE); 126 + 133 127 writel(0x00, edp->edp + DP_PHY_AUX_CFG0); 134 128 writel(0x13, edp->edp + DP_PHY_AUX_CFG1); 135 129 writel(0x24, edp->edp + DP_PHY_AUX_CFG2); ··· 145 125 writel(0x26, edp->edp + DP_PHY_AUX_CFG5); 146 126 writel(0x0a, edp->edp + DP_PHY_AUX_CFG6); 147 127 writel(0x03, edp->edp + DP_PHY_AUX_CFG7); 148 - writel(0x37, edp->edp + DP_PHY_AUX_CFG8); 128 + writel(cfg8, edp->edp + DP_PHY_AUX_CFG8); 149 129 writel(0x03, edp->edp + DP_PHY_AUX_CFG9); 150 130 151 131 writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | ··· 162 142 return ret; 163 143 } 164 144 145 + static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts) 146 + { 147 + const struct qcom_edp_cfg *cfg = edp->cfg; 148 + unsigned int v_level = 0; 149 + unsigned int p_level = 0; 150 + u8 ldo_config; 151 + u8 swing; 152 + u8 emph; 153 + int i; 154 + 155 + if (!cfg) 156 + return 0; 157 + 158 + for (i = 0; i < dp_opts->lanes; i++) { 159 + v_level = max(v_level, dp_opts->voltage[i]); 160 + p_level = max(p_level, dp_opts->pre[i]); 161 + } 162 + 163 + if (dp_opts->link_rate <= 2700) { 164 + swing = (*cfg->swing_hbr_rbr)[v_level][p_level]; 165 + emph = (*cfg->pre_emphasis_hbr_rbr)[v_level][p_level]; 166 + } else { 167 + swing = (*cfg->swing_hbr3_hbr2)[v_level][p_level]; 168 + emph = (*cfg->pre_emphasis_hbr3_hbr2)[v_level][p_level]; 169 + } 170 + 171 + if (swing == 0xff || emph == 0xff) 172 + return -EINVAL; 173 + 174 + ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0; 175 + 176 + writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); 177 + writel(swing, edp->tx0 + TXn_TX_DRV_LVL); 178 + writel(emph, edp->tx0 + TXn_TX_EMP_POST1_LVL); 179 + 180 + writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG); 181 + writel(swing, edp->tx1 + TXn_TX_DRV_LVL); 182 + writel(emph, edp->tx1 + TXn_TX_EMP_POST1_LVL); 183 + 184 + return 0; 185 + } 186 + 165 187 static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opts) 166 188 { 167 189 const struct phy_configure_opts_dp *dp_opts = &opts->dp; 168 190 struct qcom_edp *edp = phy_get_drvdata(phy); 191 + int ret = 0; 169 192 170 193 memcpy(&edp->dp_opts, dp_opts, sizeof(*dp_opts)); 171 194 172 - return 0; 195 + if (dp_opts->set_voltages) 196 + ret = qcom_edp_set_voltages(edp, dp_opts); 197 + 198 + return ret; 173 199 } 174 200 175 201 static int qcom_edp_configure_ssc(const struct qcom_edp *edp) ··· 381 315 static int qcom_edp_phy_power_on(struct phy *phy) 382 316 { 383 317 const struct qcom_edp *edp = phy_get_drvdata(phy); 318 + const struct qcom_edp_cfg *cfg = edp->cfg; 384 319 u32 bias0_en, drvr0_en, bias1_en, drvr1_en; 320 + u8 ldo_config; 385 321 int timeout; 386 322 int ret; 387 323 u32 val; ··· 400 332 if (timeout) 401 333 return timeout; 402 334 403 - writel(0x01, edp->tx0 + TXn_LDO_CONFIG); 404 - writel(0x01, edp->tx1 + TXn_LDO_CONFIG); 335 + 336 + ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0; 337 + 338 + writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); 339 + writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG); 405 340 writel(0x00, edp->tx0 + TXn_LANE_MODE_1); 406 341 writel(0x00, edp->tx1 + TXn_LANE_MODE_1); 407 342 ··· 706 635 return -ENOMEM; 707 636 708 637 edp->dev = dev; 638 + edp->cfg = of_device_get_match_data(&pdev->dev); 709 639 710 640 edp->edp = devm_platform_ioremap_resource(pdev, 0); 711 641 if (IS_ERR(edp->edp))