[PATCH v3 3/3] phy: qcom: edp: Add support for X1E80100 PHY
Abel Vesa
abel.vesa at linaro.org
Thu Dec 7 02:52:50 PST 2023
The Qualcomm X1E80100 platform has a number of eDP/DP PHY instances. These
are based on QMP v6. So add support for v6 QMP COM registers by supporting
configuration-based register offsets. For legacy platforms, keep the eDP and DP
compatibles different, but for new platforms, use the phy-type DT property
instead. So add platform specific configs, specify the version and override
the PHY type where compatible dictates it.
Co-developed-by: Abhinav Kumar <quic_abhinavk at quicinc.com>
Signed-off-by: Abhinav Kumar <quic_abhinavk at quicinc.com>
Signed-off-by: Abel Vesa <abel.vesa at linaro.org>
---
drivers/phy/qualcomm/phy-qcom-edp.c | 583 ++++++++++++++++++++++++++++++------
1 file changed, 490 insertions(+), 93 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c
index 8e5078304646..6fc18bf80db1 100644
--- a/drivers/phy/qualcomm/phy-qcom-edp.c
+++ b/drivers/phy/qualcomm/phy-qcom-edp.c
@@ -68,10 +68,333 @@
#define TXn_TRAN_DRVR_EMP_EN 0x0078
-struct qcom_edp_cfg {
- bool is_dp;
+enum dp_qmp_com_version {
+ DP_QMP_VERSION_V4,
+ DP_QMP_VERSION_V6,
+};
+
+enum dp_link_rate {
+ DP_LINK_RATE_1_6_GHZ,
+ DP_LINK_RATE_2_7_GHZ,
+ DP_LINK_RATE_5_4_GHZ,
+ DP_LINK_RATE_8_1_GHZ,
+};
+
+struct qmp_com_regs_layout {
+ unsigned int cmn_status;
+ unsigned int ssc_en_center;
+ unsigned int resetsm_cntrl;
+ unsigned int c_ready_status;
+ unsigned int ssc_per1;
+ unsigned int ssc_per2;
+ unsigned int ssc_step_size1_mode0;
+ unsigned int ssc_step_size2_mode0;
+ unsigned int ssc_adj_per1;
+ unsigned int svs_mode_clk_sel;
+ unsigned int sysclk_en_sel;
+ unsigned int sys_clk_ctrl;
+ unsigned int clk_enable1;
+ unsigned int clk_select;
+ unsigned int sysclk_buf_enable;
+ unsigned int hsclk_sel;
+ unsigned int pll_ivco;
+ unsigned int lock_cmp_en;
+ unsigned int pll_cctrl_mode0;
+ unsigned int pll_rctrl_mode0;
+ unsigned int cp_ctrl_mode0;
+ unsigned int dec_start_mode0;
+ unsigned int div_frac_start1_mode0;
+ unsigned int div_frac_start2_mode0;
+ unsigned int div_frac_start3_mode0;
+ unsigned int cmn_config;
+ unsigned int integloop_gain0_mode0;
+ unsigned int integloop_gain1_mode0;
+ unsigned int vco_tune_map;
+ unsigned int lock_cmp1_mode0;
+ unsigned int lock_cmp2_mode0;
+ unsigned int bg_timer;
+ unsigned int pll_core_clk_div_mode0;
+ unsigned int vco_tune_ctrl;
+ unsigned int pll_bias_en_clk_buflr_en;
+ unsigned int core_clk_en;
+ unsigned int vco_tune1_mode0;
+ unsigned int vco_tune2_mode0;
+ unsigned int bin_vcocal_cmp_code1_mode0;
+ unsigned int bin_vcocal_cmp_code2_mode0;
+};
+
+static const struct qmp_com_regs_layout qmp_v4_com_regs = {
+ .cmn_status = QSERDES_V4_COM_CMN_STATUS,
+ .c_ready_status = QSERDES_V4_COM_C_READY_STATUS,
+ .resetsm_cntrl = QSERDES_V4_COM_RESETSM_CNTRL,
+ .ssc_en_center = QSERDES_V4_COM_SSC_EN_CENTER,
+ .ssc_per1 = QSERDES_V4_COM_SSC_PER1,
+ .ssc_per2 = QSERDES_V4_COM_SSC_PER2,
+ .ssc_step_size1_mode0 = QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0,
+ .ssc_step_size2_mode0 = QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0,
+ .ssc_adj_per1 = QSERDES_V4_COM_SSC_ADJ_PER1,
+ .svs_mode_clk_sel = QSERDES_V4_COM_SVS_MODE_CLK_SEL,
+ .sysclk_en_sel = QSERDES_V4_COM_SYSCLK_EN_SEL,
+ .sys_clk_ctrl = QSERDES_V4_COM_SYS_CLK_CTRL,
+ .sysclk_buf_enable = QSERDES_V4_COM_SYSCLK_BUF_ENABLE,
+ .clk_enable1 = QSERDES_V4_COM_CLK_ENABLE1,
+ .clk_select = QSERDES_V4_COM_CLK_SELECT,
+ .hsclk_sel = QSERDES_V4_COM_HSCLK_SEL,
+ .pll_ivco = QSERDES_V4_COM_PLL_IVCO,
+ .lock_cmp_en = QSERDES_V4_COM_LOCK_CMP_EN,
+ .pll_cctrl_mode0 = QSERDES_V4_COM_PLL_CCTRL_MODE0,
+ .pll_rctrl_mode0 = QSERDES_V4_COM_PLL_RCTRL_MODE0,
+ .cp_ctrl_mode0 = QSERDES_V4_COM_CP_CTRL_MODE0,
+ .dec_start_mode0 = QSERDES_V4_COM_DEC_START_MODE0,
+ .div_frac_start1_mode0 = QSERDES_V4_COM_DIV_FRAC_START1_MODE0,
+ .div_frac_start2_mode0 = QSERDES_V4_COM_DIV_FRAC_START2_MODE0,
+ .div_frac_start3_mode0 = QSERDES_V4_COM_DIV_FRAC_START3_MODE0,
+ .cmn_config = QSERDES_V4_COM_CMN_CONFIG,
+ .integloop_gain0_mode0 = QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0,
+ .integloop_gain1_mode0 = QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0,
+ .vco_tune_map = QSERDES_V4_COM_VCO_TUNE_MAP,
+ .lock_cmp1_mode0 = QSERDES_V4_COM_LOCK_CMP1_MODE0,
+ .lock_cmp2_mode0 = QSERDES_V4_COM_LOCK_CMP2_MODE0,
+ .bg_timer = QSERDES_V4_COM_BG_TIMER,
+ .pll_core_clk_div_mode0 = QSERDES_V4_COM_CORECLK_DIV_MODE0,
+ .vco_tune_ctrl = QSERDES_V4_COM_VCO_TUNE_CTRL,
+ .pll_bias_en_clk_buflr_en = QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN,
+ .core_clk_en = QSERDES_V4_COM_CORE_CLK_EN,
+ .vco_tune1_mode0 = QSERDES_V4_COM_VCO_TUNE1_MODE0,
+ .vco_tune2_mode0 = QSERDES_V4_COM_VCO_TUNE2_MODE0,
+};
+
+static const struct qmp_com_regs_layout qmp_v6_com_regs = {
+ .cmn_status = QSERDES_V6_COM_CMN_STATUS,
+ .c_ready_status = QSERDES_V6_COM_C_READY_STATUS,
+ .resetsm_cntrl = QSERDES_V6_COM_RESETSM_CNTRL,
+ .ssc_en_center = QSERDES_V6_COM_SSC_EN_CENTER,
+ .ssc_per1 = QSERDES_V6_COM_SSC_PER1,
+ .ssc_per2 = QSERDES_V6_COM_SSC_PER2,
+ .ssc_step_size1_mode0 = QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0,
+ .ssc_step_size2_mode0 = QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0,
+ .ssc_adj_per1 = QSERDES_V6_COM_SSC_ADJ_PER1,
+ .svs_mode_clk_sel = QSERDES_V6_COM_SVS_MODE_CLK_SEL,
+ .sysclk_en_sel = QSERDES_V6_COM_SYSCLK_EN_SEL,
+ .sys_clk_ctrl = QSERDES_V6_COM_SYS_CLK_CTRL,
+ .sysclk_buf_enable = QSERDES_V6_COM_SYSCLK_BUF_ENABLE,
+ .clk_enable1 = QSERDES_V6_COM_CLK_ENABLE1,
+ .clk_select = QSERDES_V6_COM_CLK_SELECT,
+ .hsclk_sel = QSERDES_V6_COM_HSCLK_SEL_1,
+ .pll_ivco = QSERDES_V6_COM_PLL_IVCO,
+ .lock_cmp_en = QSERDES_V6_COM_LOCK_CMP_EN,
+ .pll_cctrl_mode0 = QSERDES_V6_COM_PLL_CCTRL_MODE0,
+ .pll_rctrl_mode0 = QSERDES_V6_COM_PLL_RCTRL_MODE0,
+ .cp_ctrl_mode0 = QSERDES_V6_COM_CP_CTRL_MODE0,
+ .dec_start_mode0 = QSERDES_V6_COM_DEC_START_MODE0,
+ .div_frac_start1_mode0 = QSERDES_V6_COM_DIV_FRAC_START1_MODE0,
+ .div_frac_start2_mode0 = QSERDES_V6_COM_DIV_FRAC_START2_MODE0,
+ .div_frac_start3_mode0 = QSERDES_V6_COM_DIV_FRAC_START3_MODE0,
+ .cmn_config = QSERDES_V6_COM_CMN_CONFIG_1,
+ .integloop_gain0_mode0 = QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0,
+ .integloop_gain1_mode0 = QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0,
+ .vco_tune_map = QSERDES_V6_COM_VCO_TUNE_MAP,
+ .lock_cmp1_mode0 = QSERDES_V6_COM_LOCK_CMP1_MODE0,
+ .lock_cmp2_mode0 = QSERDES_V6_COM_LOCK_CMP2_MODE0,
+ .bg_timer = QSERDES_V6_COM_BG_TIMER,
+ .pll_core_clk_div_mode0 = QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0,
+ .vco_tune_ctrl = QSERDES_V6_COM_VCO_TUNE_CTRL,
+ .pll_bias_en_clk_buflr_en = QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN,
+ .core_clk_en = QSERDES_V6_COM_CORE_CLK_EN,
+ .bin_vcocal_cmp_code1_mode0 = QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0,
+ .bin_vcocal_cmp_code2_mode0 = QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0,
+};
+
+struct qmp_com_init {
+ const u8 ssc_per1;
+ const u8 ssc_per2;
+ const u8 pll_ivco;
+ const u8 cmn_config;
+ const u8 vco_tune1_mode0;
+ const u8 vco_tune2_mode0;
+ const u8 pll_bias_en_clk_buflr_en;
+
+ const u8 *ssc_step1;
+ const u8 *ssc_step2;
+ const u8 *hsclk_sel;
+ const u8 *dec_start_mode0;
+ const u8 *div_frac_start2_mode0;
+ const u8 *div_frac_start3_mode0;
+ const u8 *lock_cmp1_mode0;
+ const u8 *lock_cmp2_mode0;
+ const u8 *code1_mode0;
+ const u8 *code2_mode0;
+};
+
+static const u8 qmp_v4_com_ssc_step1[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x45,
+ [DP_LINK_RATE_2_7_GHZ] = 0x45,
+ [DP_LINK_RATE_5_4_GHZ] = 0x5c,
+ [DP_LINK_RATE_8_1_GHZ] = 0x45,
+};
+
+static const u8 qmp_v4_com_ssc_step2[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x06,
+ [DP_LINK_RATE_2_7_GHZ] = 0x06,
+ [DP_LINK_RATE_5_4_GHZ] = 0x08,
+ [DP_LINK_RATE_8_1_GHZ] = 0x06,
+};
+
+static const u8 qmp_v4_com_hsclk_sel[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x05,
+ [DP_LINK_RATE_2_7_GHZ] = 0x03,
+ [DP_LINK_RATE_5_4_GHZ] = 0x01,
+ [DP_LINK_RATE_8_1_GHZ] = 0x00,
+};
+
+static const u8 qmp_v4_com_dec_start_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x69,
+ [DP_LINK_RATE_2_7_GHZ] = 0x69,
+ [DP_LINK_RATE_5_4_GHZ] = 0x8c,
+ [DP_LINK_RATE_8_1_GHZ] = 0x69,
+};
+
+static const u8 qmp_v4_com_div_frac_start2_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x80,
+ [DP_LINK_RATE_2_7_GHZ] = 0x80,
+ [DP_LINK_RATE_5_4_GHZ] = 0x00,
+ [DP_LINK_RATE_8_1_GHZ] = 0x80,
+};
+
+static const u8 qmp_v4_com_div_frac_start3_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x07,
+ [DP_LINK_RATE_2_7_GHZ] = 0x07,
+ [DP_LINK_RATE_5_4_GHZ] = 0x0a,
+ [DP_LINK_RATE_8_1_GHZ] = 0x07,
+};
+
+static const u8 qmp_v4_com_lock_cmp1_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x6f,
+ [DP_LINK_RATE_2_7_GHZ] = 0x0f,
+ [DP_LINK_RATE_5_4_GHZ] = 0x1f,
+ [DP_LINK_RATE_8_1_GHZ] = 0x2f,
+};
+
+static const u8 qmp_v4_com_lock_cmp2_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x08,
+ [DP_LINK_RATE_2_7_GHZ] = 0x0e,
+ [DP_LINK_RATE_5_4_GHZ] = 0x1c,
+ [DP_LINK_RATE_8_1_GHZ] = 0x2a,
+};
+
+static const struct qmp_com_init qmp_v4_com_init = {
+ .ssc_per1 = 0x36,
+ .ssc_per2 = 0x01,
+ .pll_ivco = 0x0f,
+ .cmn_config = 0x02,
+ .pll_bias_en_clk_buflr_en = 0x17,
+ .ssc_step1 = qmp_v4_com_ssc_step1,
+ .ssc_step2 = qmp_v4_com_ssc_step2,
+ .hsclk_sel = qmp_v4_com_hsclk_sel,
+ .dec_start_mode0 = qmp_v4_com_dec_start_mode0,
+ .div_frac_start2_mode0 = qmp_v4_com_div_frac_start2_mode0,
+ .div_frac_start3_mode0 = qmp_v4_com_div_frac_start3_mode0,
+ .lock_cmp1_mode0 = qmp_v4_com_lock_cmp1_mode0,
+ .lock_cmp2_mode0 = qmp_v4_com_lock_cmp2_mode0,
+ .vco_tune1_mode0 = 0xa0,
+ .vco_tune2_mode0 = 0x03,
+};
+
+static const u8 qmp_v6_com_ssc_step1[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x92,
+ [DP_LINK_RATE_2_7_GHZ] = 0x92,
+ [DP_LINK_RATE_5_4_GHZ] = 0x18,
+ [DP_LINK_RATE_8_1_GHZ] = 0x92,
+};
+
+static const u8 qmp_v6_com_ssc_step2[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x01,
+ [DP_LINK_RATE_2_7_GHZ] = 0x01,
+ [DP_LINK_RATE_5_4_GHZ] = 0x02,
+ [DP_LINK_RATE_8_1_GHZ] = 0x01,
+};
+
+static const u8 qmp_v6_com_hsclk_sel[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x05,
+ [DP_LINK_RATE_2_7_GHZ] = 0x03,
+ [DP_LINK_RATE_5_4_GHZ] = 0x01,
+ [DP_LINK_RATE_8_1_GHZ] = 0x00,
+};
+
+static const u8 qmp_v6_com_dec_start_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x34,
+ [DP_LINK_RATE_2_7_GHZ] = 0x34,
+ [DP_LINK_RATE_5_4_GHZ] = 0x46,
+ [DP_LINK_RATE_8_1_GHZ] = 0x34,
+};
+
+static const u8 qmp_v6_com_div_frac_start2_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0xc0,
+ [DP_LINK_RATE_2_7_GHZ] = 0xc0,
+ [DP_LINK_RATE_5_4_GHZ] = 0x00,
+ [DP_LINK_RATE_8_1_GHZ] = 0xc0,
+};
+
+static const u8 qmp_v6_com_div_frac_start3_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x0b,
+ [DP_LINK_RATE_2_7_GHZ] = 0x0b,
+ [DP_LINK_RATE_5_4_GHZ] = 0x05,
+ [DP_LINK_RATE_8_1_GHZ] = 0x0b,
+};
+
+static const u8 qmp_v6_com_lock_cmp1_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x37,
+ [DP_LINK_RATE_2_7_GHZ] = 0x07,
+ [DP_LINK_RATE_5_4_GHZ] = 0x0f,
+ [DP_LINK_RATE_8_1_GHZ] = 0x17,
+};
- /* DP PHY swing and pre_emphasis tables */
+static const u8 qmp_v6_com_lock_cmp2_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x04,
+ [DP_LINK_RATE_2_7_GHZ] = 0x07,
+ [DP_LINK_RATE_5_4_GHZ] = 0x0e,
+ [DP_LINK_RATE_8_1_GHZ] = 0x15,
+};
+
+static const u8 qmp_v6_com_code1_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x71,
+ [DP_LINK_RATE_2_7_GHZ] = 0x71,
+ [DP_LINK_RATE_5_4_GHZ] = 0x97,
+ [DP_LINK_RATE_8_1_GHZ] = 0x71,
+};
+
+static const u8 qmp_v6_com_code2_mode0[] = {
+ [DP_LINK_RATE_1_6_GHZ] = 0x0c,
+ [DP_LINK_RATE_2_7_GHZ] = 0x0c,
+ [DP_LINK_RATE_5_4_GHZ] = 0x10,
+ [DP_LINK_RATE_8_1_GHZ] = 0x0c,
+};
+
+static const struct qmp_com_init qmp_v6_com_init = {
+ .ssc_per1 = 0x6b,
+ .ssc_per2 = 0x02,
+ .pll_ivco = 0x07,
+ .cmn_config = 0x12,
+ .pll_bias_en_clk_buflr_en = 0x1f,
+ .ssc_step1 = qmp_v6_com_ssc_step1,
+ .ssc_step2 = qmp_v6_com_ssc_step2,
+ .hsclk_sel = qmp_v6_com_hsclk_sel,
+ .dec_start_mode0 = qmp_v6_com_dec_start_mode0,
+ .div_frac_start2_mode0 = qmp_v6_com_div_frac_start2_mode0,
+ .div_frac_start3_mode0 = qmp_v6_com_div_frac_start3_mode0,
+ .lock_cmp1_mode0 = qmp_v6_com_lock_cmp1_mode0,
+ .lock_cmp2_mode0 = qmp_v6_com_lock_cmp2_mode0,
+ .code1_mode0 = qmp_v6_com_code1_mode0,
+ .code2_mode0 = qmp_v6_com_code2_mode0,
+};
+
+struct qmp_phy_cfg {
+ int type;
+ enum dp_qmp_com_version version;
+ bool needs_swing_pre_emph_cfg;
+};
+
+struct qcom_dp_swing_pre_emph_cfg {
const u8 (*swing_hbr_rbr)[4][4];
const u8 (*swing_hbr3_hbr2)[4][4];
const u8 (*pre_emphasis_hbr_rbr)[4][4];
@@ -80,7 +403,9 @@ struct qcom_edp_cfg {
struct qcom_edp {
struct device *dev;
- const struct qcom_edp_cfg *cfg;
+ const struct qcom_dp_swing_pre_emph_cfg *swing_pre_emph_cfg;
+ const struct qmp_com_regs_layout *com_regs;
+ const struct qmp_com_init *init_values;
struct phy *phy;
@@ -96,6 +421,8 @@ struct qcom_edp {
struct clk_bulk_data clks[2];
struct regulator_bulk_data supplies[2];
+
+ bool is_dp;
};
static const u8 dp_swing_hbr_rbr[4][4] = {
@@ -126,8 +453,7 @@ static const u8 dp_pre_emp_hbr2_hbr3[4][4] = {
{ 0x04, 0xff, 0xff, 0xff }
};
-static const struct qcom_edp_cfg dp_phy_cfg = {
- .is_dp = true,
+static const struct qcom_dp_swing_pre_emph_cfg dp_phy_swing_pre_emph_cfg = {
.swing_hbr_rbr = &dp_swing_hbr_rbr,
.swing_hbr3_hbr2 = &dp_swing_hbr2_hbr3,
.pre_emphasis_hbr_rbr = &dp_pre_emp_hbr_rbr,
@@ -162,18 +488,40 @@ static const u8 edp_pre_emp_hbr2_hbr3[4][4] = {
{ 0x00, 0xff, 0xff, 0xff }
};
-static const struct qcom_edp_cfg edp_phy_cfg = {
- .is_dp = false,
+static const struct qcom_dp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = {
.swing_hbr_rbr = &edp_swing_hbr_rbr,
.swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3,
.pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr,
.pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3,
};
+static struct qmp_phy_cfg sc7280_dp_phy_cfg = {
+ .type = PHY_TYPE_DP,
+ .version = DP_QMP_VERSION_V4,
+};
+
+static struct qmp_phy_cfg sc8280xp_dp_phy_cfg = {
+ .type = PHY_TYPE_DP,
+ .version = DP_QMP_VERSION_V4,
+ .needs_swing_pre_emph_cfg = true,
+};
+
+static struct qmp_phy_cfg sc8280xp_edp_phy_cfg = {
+ .type = PHY_TYPE_EDP,
+ .version = DP_QMP_VERSION_V4,
+ .needs_swing_pre_emph_cfg = true,
+};
+
+static struct qmp_phy_cfg x1e80100_phy_cfg = {
+ .version = DP_QMP_VERSION_V6,
+ .needs_swing_pre_emph_cfg = true,
+};
+
static int qcom_edp_phy_init(struct phy *phy)
{
struct qcom_edp *edp = phy_get_drvdata(phy);
- const struct qcom_edp_cfg *cfg = edp->cfg;
+ const struct qmp_com_init *init = edp->init_values;
+ const struct qmp_com_regs_layout *regs = edp->com_regs;
int ret;
u8 cfg8;
@@ -190,7 +538,8 @@ static int qcom_edp_phy_init(struct phy *phy)
edp->edp + DP_PHY_PD_CTL);
/* Turn on BIAS current for PHY/PLL */
- writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
+ writel(init->pll_bias_en_clk_buflr_en,
+ edp->pll + regs->pll_bias_en_clk_buflr_en);
writel(DP_PHY_PD_CTL_PSR_PWRDN, edp->edp + DP_PHY_PD_CTL);
msleep(20);
@@ -200,7 +549,7 @@ static int qcom_edp_phy_init(struct phy *phy)
DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
edp->edp + DP_PHY_PD_CTL);
- if (cfg && cfg->is_dp)
+ if (edp->is_dp)
cfg8 = 0xb7;
else
cfg8 = 0x37;
@@ -234,7 +583,7 @@ static int qcom_edp_phy_init(struct phy *phy)
static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts)
{
- const struct qcom_edp_cfg *cfg = edp->cfg;
+ const struct qcom_dp_swing_pre_emph_cfg *cfg = edp->swing_pre_emph_cfg;
unsigned int v_level = 0;
unsigned int p_level = 0;
u8 ldo_config;
@@ -261,7 +610,7 @@ static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configur
if (swing == 0xff || emph == 0xff)
return -EINVAL;
- ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0;
+ ldo_config = edp->is_dp ? 0x1 : 0x0;
writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
writel(swing, edp->tx0 + TXn_TX_DRV_LVL);
@@ -291,20 +640,21 @@ static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opt
static int qcom_edp_configure_ssc(const struct qcom_edp *edp)
{
const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
- u32 step1;
- u32 step2;
+ const struct qmp_com_regs_layout *regs = edp->com_regs;
+ const struct qmp_com_init *init = edp->init_values;
+ int link_rate;
+ u8 step1, step2;
+ u8 per1, per2;
switch (dp_opts->link_rate) {
case 1620:
case 2700:
case 8100:
- step1 = 0x45;
- step2 = 0x06;
+ link_rate = DP_LINK_RATE_1_6_GHZ;
break;
case 5400:
- step1 = 0x5c;
- step2 = 0x08;
+ link_rate = DP_LINK_RATE_5_4_GHZ;
break;
default:
@@ -312,12 +662,18 @@ static int qcom_edp_configure_ssc(const struct qcom_edp *edp)
return -EINVAL;
}
- writel(0x01, edp->pll + QSERDES_V4_COM_SSC_EN_CENTER);
- writel(0x00, edp->pll + QSERDES_V4_COM_SSC_ADJ_PER1);
- writel(0x36, edp->pll + QSERDES_V4_COM_SSC_PER1);
- writel(0x01, edp->pll + QSERDES_V4_COM_SSC_PER2);
- writel(step1, edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0);
- writel(step2, edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0);
+ step1 = init->ssc_step1[link_rate];
+ step2 = init->ssc_step2[link_rate];
+
+ per1 = init->ssc_per1;
+ per2 = init->ssc_per2;
+
+ writel(0x01, edp->pll + regs->ssc_en_center);
+ writel(0x00, edp->pll + regs->ssc_adj_per1);
+ writel(per1, edp->pll + regs->ssc_per1);
+ writel(per2, edp->pll + regs->ssc_per2);
+ writel(step1, edp->pll + regs->ssc_step_size1_mode0);
+ writel(step2, edp->pll + regs->ssc_step_size2_mode0);
return 0;
}
@@ -325,48 +681,30 @@ static int qcom_edp_configure_ssc(const struct qcom_edp *edp)
static int qcom_edp_configure_pll(const struct qcom_edp *edp)
{
const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
+ const struct qmp_com_regs_layout *regs = edp->com_regs;
+ const struct qmp_com_init *init = edp->init_values;
u32 div_frac_start2_mode0;
u32 div_frac_start3_mode0;
u32 dec_start_mode0;
u32 lock_cmp1_mode0;
u32 lock_cmp2_mode0;
+ u32 code1_mode0;
+ u32 code2_mode0;
u32 hsclk_sel;
+ int link_rate;
switch (dp_opts->link_rate) {
case 1620:
- hsclk_sel = 0x5;
- dec_start_mode0 = 0x69;
- div_frac_start2_mode0 = 0x80;
- div_frac_start3_mode0 = 0x07;
- lock_cmp1_mode0 = 0x6f;
- lock_cmp2_mode0 = 0x08;
+ link_rate = DP_LINK_RATE_1_6_GHZ;
break;
-
case 2700:
- hsclk_sel = 0x3;
- dec_start_mode0 = 0x69;
- div_frac_start2_mode0 = 0x80;
- div_frac_start3_mode0 = 0x07;
- lock_cmp1_mode0 = 0x0f;
- lock_cmp2_mode0 = 0x0e;
+ link_rate = DP_LINK_RATE_2_7_GHZ;
break;
-
case 5400:
- hsclk_sel = 0x1;
- dec_start_mode0 = 0x8c;
- div_frac_start2_mode0 = 0x00;
- div_frac_start3_mode0 = 0x0a;
- lock_cmp1_mode0 = 0x1f;
- lock_cmp2_mode0 = 0x1c;
+ link_rate = DP_LINK_RATE_5_4_GHZ;
break;
-
case 8100:
- hsclk_sel = 0x0;
- dec_start_mode0 = 0x69;
- div_frac_start2_mode0 = 0x80;
- div_frac_start3_mode0 = 0x07;
- lock_cmp1_mode0 = 0x2f;
- lock_cmp2_mode0 = 0x2a;
+ link_rate = DP_LINK_RATE_8_1_GHZ;
break;
default:
@@ -374,36 +712,59 @@ static int qcom_edp_configure_pll(const struct qcom_edp *edp)
return -EINVAL;
}
- writel(0x01, edp->pll + QSERDES_V4_COM_SVS_MODE_CLK_SEL);
- writel(0x0b, edp->pll + QSERDES_V4_COM_SYSCLK_EN_SEL);
- writel(0x02, edp->pll + QSERDES_V4_COM_SYS_CLK_CTRL);
- writel(0x0c, edp->pll + QSERDES_V4_COM_CLK_ENABLE1);
- writel(0x06, edp->pll + QSERDES_V4_COM_SYSCLK_BUF_ENABLE);
- writel(0x30, edp->pll + QSERDES_V4_COM_CLK_SELECT);
- writel(hsclk_sel, edp->pll + QSERDES_V4_COM_HSCLK_SEL);
- writel(0x0f, edp->pll + QSERDES_V4_COM_PLL_IVCO);
- writel(0x08, edp->pll + QSERDES_V4_COM_LOCK_CMP_EN);
- writel(0x36, edp->pll + QSERDES_V4_COM_PLL_CCTRL_MODE0);
- writel(0x16, edp->pll + QSERDES_V4_COM_PLL_RCTRL_MODE0);
- writel(0x06, edp->pll + QSERDES_V4_COM_CP_CTRL_MODE0);
- writel(dec_start_mode0, edp->pll + QSERDES_V4_COM_DEC_START_MODE0);
- writel(0x00, edp->pll + QSERDES_V4_COM_DIV_FRAC_START1_MODE0);
- writel(div_frac_start2_mode0, edp->pll + QSERDES_V4_COM_DIV_FRAC_START2_MODE0);
- writel(div_frac_start3_mode0, edp->pll + QSERDES_V4_COM_DIV_FRAC_START3_MODE0);
- writel(0x02, edp->pll + QSERDES_V4_COM_CMN_CONFIG);
- writel(0x3f, edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0);
- writel(0x00, edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0);
- writel(0x00, edp->pll + QSERDES_V4_COM_VCO_TUNE_MAP);
- writel(lock_cmp1_mode0, edp->pll + QSERDES_V4_COM_LOCK_CMP1_MODE0);
- writel(lock_cmp2_mode0, edp->pll + QSERDES_V4_COM_LOCK_CMP2_MODE0);
-
- writel(0x0a, edp->pll + QSERDES_V4_COM_BG_TIMER);
- writel(0x14, edp->pll + QSERDES_V4_COM_CORECLK_DIV_MODE0);
- writel(0x00, edp->pll + QSERDES_V4_COM_VCO_TUNE_CTRL);
- writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
- writel(0x0f, edp->pll + QSERDES_V4_COM_CORE_CLK_EN);
- writel(0xa0, edp->pll + QSERDES_V4_COM_VCO_TUNE1_MODE0);
- writel(0x03, edp->pll + QSERDES_V4_COM_VCO_TUNE2_MODE0);
+ hsclk_sel = init->hsclk_sel[link_rate];
+ dec_start_mode0 = init->dec_start_mode0[link_rate];
+ div_frac_start2_mode0 = init->div_frac_start2_mode0[link_rate];
+ div_frac_start3_mode0 = init->div_frac_start3_mode0[link_rate];
+ lock_cmp1_mode0 = init->lock_cmp1_mode0[link_rate];
+ lock_cmp2_mode0 = init->lock_cmp2_mode0[link_rate];
+
+ if (init->code1_mode0)
+ code1_mode0 = init->code1_mode0[link_rate];
+
+ if (init->code2_mode0)
+ code2_mode0 = init->code2_mode0[link_rate];
+
+ writel(0x01, edp->pll + regs->svs_mode_clk_sel);
+ writel(0x0b, edp->pll + regs->sysclk_en_sel);
+ writel(0x02, edp->pll + regs->sys_clk_ctrl);
+ writel(0x0c, edp->pll + regs->clk_enable1);
+ writel(0x06, edp->pll + regs->sysclk_buf_enable);
+ writel(0x30, edp->pll + regs->clk_select);
+ writel(hsclk_sel, edp->pll + regs->hsclk_sel);
+ writel(init->pll_ivco, edp->pll + regs->pll_ivco);
+ writel(0x08, edp->pll + regs->lock_cmp_en);
+ writel(0x36, edp->pll + regs->pll_cctrl_mode0);
+ writel(0x16, edp->pll + regs->pll_rctrl_mode0);
+ writel(0x06, edp->pll + regs->cp_ctrl_mode0);
+ writel(dec_start_mode0, edp->pll + regs->dec_start_mode0);
+ writel(0x00, edp->pll + regs->div_frac_start1_mode0);
+ writel(div_frac_start2_mode0, edp->pll + regs->div_frac_start2_mode0);
+ writel(div_frac_start3_mode0, edp->pll + regs->div_frac_start3_mode0);
+ writel(init->cmn_config, edp->pll + regs->cmn_config);
+ writel(0x3f, edp->pll + regs->integloop_gain0_mode0);
+ writel(0x00, edp->pll + regs->integloop_gain1_mode0);
+ writel(0x00, edp->pll + regs->vco_tune_map);
+ writel(lock_cmp1_mode0, edp->pll + regs->lock_cmp1_mode0);
+ writel(lock_cmp2_mode0, edp->pll + regs->lock_cmp2_mode0);
+
+ writel(0x0a, edp->pll + regs->bg_timer);
+ writel(0x14, edp->pll + regs->pll_core_clk_div_mode0);
+ writel(0x00, edp->pll + regs->vco_tune_ctrl);
+ writel(0x17, edp->pll + regs->pll_bias_en_clk_buflr_en);
+ writel(0x0f, edp->pll + regs->core_clk_en);
+
+ if (regs->vco_tune1_mode0)
+ writel(init->vco_tune1_mode0, edp->pll + regs->vco_tune1_mode0);
+
+ if (regs->vco_tune2_mode0)
+ writel(init->vco_tune2_mode0, edp->pll + regs->vco_tune2_mode0);
+
+ if (regs->bin_vcocal_cmp_code1_mode0)
+ writel(code1_mode0, edp->pll + regs->bin_vcocal_cmp_code1_mode0);
+
+ if (regs->bin_vcocal_cmp_code2_mode0)
+ writel(code2_mode0, edp->pll + regs->bin_vcocal_cmp_code2_mode0);
return 0;
}
@@ -447,10 +808,10 @@ static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel
static int qcom_edp_phy_power_on(struct phy *phy)
{
const struct qcom_edp *edp = phy_get_drvdata(phy);
- const struct qcom_edp_cfg *cfg = edp->cfg;
+ const struct qmp_com_regs_layout *regs = edp->com_regs;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
unsigned long pixel_freq;
- u8 ldo_config;
+ u8 ldo_config = 0x0;
int timeout;
int ret;
u32 val;
@@ -462,13 +823,14 @@ static int qcom_edp_phy_power_on(struct phy *phy)
edp->edp + DP_PHY_PD_CTL);
writel(0xfc, edp->edp + DP_PHY_MODE);
- timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS,
+ timeout = readl_poll_timeout(edp->pll + regs->cmn_status,
val, val & BIT(7), 5, 200);
if (timeout)
return timeout;
- ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0;
+ if (edp->swing_pre_emph_cfg && edp->is_dp)
+ ldo_config = 0x1;
writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG);
@@ -512,9 +874,9 @@ static int qcom_edp_phy_power_on(struct phy *phy)
writel(0x01, edp->edp + DP_PHY_CFG);
writel(0x09, edp->edp + DP_PHY_CFG);
- writel(0x20, edp->pll + QSERDES_V4_COM_RESETSM_CNTRL);
+ writel(0x20, edp->pll + regs->resetsm_cntrl);
- timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS,
+ timeout = readl_poll_timeout(edp->pll + regs->c_ready_status,
val, val & BIT(0), 500, 10000);
if (timeout)
return timeout;
@@ -768,6 +1130,37 @@ static int qcom_edp_clks_register(struct qcom_edp *edp, struct device_node *np)
return devm_of_clk_add_hw_provider(edp->dev, of_clk_hw_onecell_get, data);
}
+static int qcom_edp_setup_phy(struct platform_device *pdev, struct qcom_edp *edp)
+{
+ struct device *dev = &pdev->dev;
+ const struct qmp_phy_cfg *cfg = of_device_get_match_data(dev);
+ enum dp_qmp_com_version version = cfg->version;
+ struct device_node *node = dev->of_node;
+ int type = cfg->type;
+
+ of_property_read_u32(node, "phy-type", &type);
+
+ if (type != PHY_TYPE_DP && type != PHY_TYPE_EDP)
+ return -EINVAL;
+
+ edp->is_dp = (type == PHY_TYPE_DP) ? true : false;
+
+ if (cfg->needs_swing_pre_emph_cfg)
+ edp->swing_pre_emph_cfg = edp->is_dp ?
+ &dp_phy_swing_pre_emph_cfg:
+ &edp_phy_swing_pre_emph_cfg;
+
+ if (version == DP_QMP_VERSION_V6) {
+ edp->com_regs = &qmp_v6_com_regs;
+ edp->init_values = &qmp_v6_com_init;
+ } else {
+ edp->com_regs = &qmp_v4_com_regs;
+ edp->init_values = &qmp_v4_com_init;
+ }
+
+ return 0;
+}
+
static int qcom_edp_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
@@ -780,7 +1173,10 @@ static int qcom_edp_phy_probe(struct platform_device *pdev)
return -ENOMEM;
edp->dev = dev;
- edp->cfg = of_device_get_match_data(&pdev->dev);
+
+ ret = qcom_edp_setup_phy(pdev, edp);
+ if (ret)
+ return ret;
edp->edp = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(edp->edp))
@@ -839,10 +1235,11 @@ static int qcom_edp_phy_probe(struct platform_device *pdev)
}
static const struct of_device_id qcom_edp_phy_match_table[] = {
- { .compatible = "qcom,sc7280-edp-phy" },
- { .compatible = "qcom,sc8180x-edp-phy" },
- { .compatible = "qcom,sc8280xp-dp-phy", .data = &dp_phy_cfg },
- { .compatible = "qcom,sc8280xp-edp-phy", .data = &edp_phy_cfg },
+ { .compatible = "qcom,sc7280-edp-phy" , .data = &sc7280_dp_phy_cfg, },
+ { .compatible = "qcom,sc8180x-edp-phy", .data = &sc7280_dp_phy_cfg, },
+ { .compatible = "qcom,sc8280xp-dp-phy", .data = &sc8280xp_dp_phy_cfg, },
+ { .compatible = "qcom,sc8280xp-edp-phy", .data = &sc8280xp_edp_phy_cfg, },
+ { .compatible = "qcom,x1e80100-dp-phy" , .data = &x1e80100_phy_cfg, },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table);
--
2.34.1
More information about the linux-phy
mailing list