phy: qcom-ufs-qmp-14nm: add svs mode workaround
UFS PHY power up calibration sequence on UFS controller revision 2.0.0 can't have SVS mode configuration otherwise calibration result cannot be used in HS-G3. So there are additional register writes must be done after the PHY is initialized but before the controller requests hibernate exit. Also as this issue is not present on UFS controller revision 2.1.0, SVS mode configuration registers are written as part of the power up calibration sequence itself. This change takes care of these issues related to SVS mode. Change-Id: Ib431d98345224db13f1d68197e948bb077c95080 Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> [venkatg@codeaurora.org: resolved trivial merge conflicts, drop include/linux/phy/phy-qcom-ufs.h] Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
parent
5283ec6226
commit
c852983434
2 changed files with 130 additions and 8 deletions
|
@ -21,13 +21,35 @@ static
|
|||
int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
|
||||
bool is_rate_B)
|
||||
{
|
||||
int tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
|
||||
int tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
|
||||
int err;
|
||||
int tbl_size_A, tbl_size_B;
|
||||
struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
|
||||
u8 major = ufs_qcom_phy->host_ctrl_rev_major;
|
||||
u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
|
||||
u16 step = ufs_qcom_phy->host_ctrl_rev_step;
|
||||
|
||||
err = ufs_qcom_phy_calibrate(ufs_qcom_phy, phy_cal_table_rate_A,
|
||||
tbl_size_A, phy_cal_table_rate_B, tbl_size_B, is_rate_B);
|
||||
tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
|
||||
tbl_B = phy_cal_table_rate_B;
|
||||
|
||||
if ((major == 0x2) && (minor == 0x000) && (step == 0x0000)) {
|
||||
tbl_A = phy_cal_table_rate_A_2_0_0;
|
||||
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_0_0);
|
||||
} else if ((major == 0x2) && (minor == 0x001) && (step == 0x0000)) {
|
||||
tbl_A = phy_cal_table_rate_A_2_1_0;
|
||||
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_2_1_0);
|
||||
} else {
|
||||
dev_err(ufs_qcom_phy->dev,
|
||||
"%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
|
||||
__func__, major, minor, step);
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
|
||||
tbl_A, tbl_size_A,
|
||||
tbl_B, tbl_size_B,
|
||||
rate);
|
||||
out:
|
||||
if (err)
|
||||
dev_err(ufs_qcom_phy->dev,
|
||||
"%s: ufs_qcom_phy_calibrate() failed %d\n",
|
||||
|
@ -38,8 +60,14 @@ int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
|
|||
static
|
||||
void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
|
||||
{
|
||||
phy_common->quirks =
|
||||
UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
|
||||
u8 major = phy_common->host_ctrl_rev_major;
|
||||
u16 minor = phy_common->host_ctrl_rev_minor;
|
||||
u16 step = phy_common->host_ctrl_rev_step;
|
||||
|
||||
if ((major == 0x2) && (minor == 0x000) && (step == 0x0000))
|
||||
phy_common->quirks =
|
||||
UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE |
|
||||
UFS_QCOM_PHY_QUIRK_SVS_MODE;
|
||||
}
|
||||
|
||||
static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
|
||||
|
@ -126,9 +154,24 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
|
|||
|
||||
err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
|
||||
val, (val & MASK_PCS_READY), 10, 1000000);
|
||||
if (err)
|
||||
if (err) {
|
||||
dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
|
||||
__func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (phy_common->quirks & UFS_QCOM_PHY_QUIRK_SVS_MODE) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(phy_svs_mode_config_2_0_0); i++)
|
||||
writel_relaxed(phy_svs_mode_config_2_0_0[i].cfg_value,
|
||||
(phy_common->mmio +
|
||||
phy_svs_mode_config_2_0_0[i].reg_offset));
|
||||
/* apply above configuration immediately */
|
||||
mb();
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ struct ufs_qcom_phy_qmp_14nm {
|
|||
struct ufs_qcom_phy common_cfg;
|
||||
};
|
||||
|
||||
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
|
||||
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_2_0_0[] = {
|
||||
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
|
||||
|
@ -174,8 +174,87 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
|
|||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
|
||||
};
|
||||
|
||||
/*
|
||||
* For 2.1.0 revision, SVS mode configuration can be part of PHY power
|
||||
* up sequence itself.
|
||||
*/
|
||||
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_2_1_0[] = {
|
||||
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_PWM_GEAR_BAND, 0x15),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x06),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x05),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x10),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x14),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
|
||||
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x02),
|
||||
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x02),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0F),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
|
||||
};
|
||||
|
||||
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x54),
|
||||
};
|
||||
|
||||
/*
|
||||
* For 2.0.0 revision, apply this SVS mode configuration after PHY power
|
||||
* up sequence is completed.
|
||||
*/
|
||||
static struct ufs_qcom_phy_calibration phy_svs_mode_config_2_0_0[] = {
|
||||
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
|
||||
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_PWM_GEAR_BAND, 0x15),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue