Merge "scsi: ufs: Add workaround to bypass cfgready signal for UFS gear4"

This commit is contained in:
qctecmdr 2020-08-12 08:31:57 -07:00 • committed by Gerrit - the friendly Code Review server
commit 8a6bfe1047
2 changed files with 85 additions and 3 deletions

View file

@ -81,7 +81,7 @@ static int ufs_qcom_init_sysfs(struct ufs_hba *hba);
static int ufs_qcom_update_qos_constraints(struct qos_cpu_group *qcg,
enum constraint type);
static int ufs_qcom_unvote_qos_all(struct ufs_hba *hba);
static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host);
static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param,
struct ufs_pa_layer_attr *dev_max,
struct ufs_pa_layer_attr *agreed_pwr)
@ -813,6 +813,61 @@ static int ufs_qcom_set_dme_vs_core_clk_ctrl_max_freq_mode(struct ufs_hba *hba)
return err;
}
/**
* ufs_qcom_bypass_cfgready_signal - Tunes PA_VS_CONFIG_REG1 and
* PA_VS_CONFIG_REG2 vendor specific attributes of local unipro
* to bypass CFGREADY signal on Config interface between UFS
* controller and PHY.
*
* The issue is related to config signals sampling from PHY
* to controller. The PHY signals which are driven by 150MHz
* clock and sampled by 300MHz instead of 150MHZ.
*
* The issue will be seen when only one of tx_cfg_rdyn_0
* and tx_cfg_rdyn_1 is 0 around sampling clock edge and
* if timing is not met as timing margin for some devices is
* very less in one of the corner.
*
* To workaround this issue, controller should bypass the Cfgready
* signal(TX_CFGREADY and RX_CFGREDY) because controller still wait
* for another signal tx_savestatusn which will serve same purpose.
*
* The corresponding HW CR: 'QCTDD06985523' UFS HSG4 test fails
* in SDF MAX GLS is linked to this issue.
*/
static int ufs_qcom_bypass_cfgready_signal(struct ufs_hba *hba)
{
int err = 0;
u32 pa_vs_config_reg1;
u32 pa_vs_config_reg2;
u32 mask;
err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
&pa_vs_config_reg1);
if (err)
goto out;
err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1),
(pa_vs_config_reg1 | BIT_TX_EOB_COND));
if (err)
goto out;
err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG2),
&pa_vs_config_reg2);
if (err)
goto out;
mask = (BIT_RX_EOB_COND | BIT_LINKCFG_WAIT_LL1_RX_CFG_RDY |
H8_ENTER_COND_MASK);
pa_vs_config_reg2 = (pa_vs_config_reg2 & ~mask) |
(0x2 << H8_ENTER_COND_OFFSET);
err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG2),
(pa_vs_config_reg2));
out:
return err;
}
static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
@ -853,6 +908,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
err = ufshcd_disable_host_tx_lcc(hba);
if (err)
goto out;
if (host->bypass_g4_cfgready)
err = ufs_qcom_bypass_cfgready_signal(hba);
break;
case POST_CHANGE:
ufs_qcom_link_startup_post_change(hba);
@ -2602,6 +2660,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_parse_pm_level(hba);
ufs_qcom_parse_limits(host);
ufs_qcom_parse_g4_workaround_flag(host);
ufs_qcom_parse_lpm(host);
if (host->disable_lpm)
pm_runtime_forbid(host->hba->dev);
@ -3180,6 +3239,20 @@ static void ufs_qcom_parse_limits(struct ufs_qcom_host *host)
of_property_read_u32(np, "limit-phy-submode", &host->limit_phy_submode);
}
/*
* ufs_qcom_parse_g4_workaround_flag - read bypass-g4-cfgready entry from DT
*/
static void ufs_qcom_parse_g4_workaround_flag(struct ufs_qcom_host *host)
{
struct device_node *np = host->hba->dev->of_node;
const char *str = "bypass-g4-cfgready";
if (!np)
return;
host->bypass_g4_cfgready = of_property_read_bool(np, str);
}
/*
* ufs_qcom_parse_lpm - read from DTS whether LPM modes should be disabled.
*/

View file

@ -168,8 +168,16 @@ enum ufs_qcom_phy_init_type {
/* QUniPro Vendor specific attributes */
#define PA_VS_CONFIG_REG1 0x9000
#define SAVECONFIGTIME_MODE_MASK 0x6000
#define DME_VS_CORE_CLK_CTRL 0xD002
#define BIT_TX_EOB_COND BIT(23)
#define PA_VS_CONFIG_REG2 0x9005
#define H8_ENTER_COND_OFFSET 0x6
#define H8_ENTER_COND_MASK GENMASK(6, 7)
#define BIT_RX_EOB_COND BIT(5)
#define BIT_LINKCFG_WAIT_LL1_RX_CFG_RDY BIT(26)
#define SAVECONFIGTIME_MODE_MASK 0x6000
#define DME_VS_CORE_CLK_CTRL 0xD002
/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF
@ -367,6 +375,7 @@ struct ufs_qcom_host {
atomic_t scale_up;
atomic_t clks_on;
struct ufs_qcom_qos_req *ufs_qos;
bool bypass_g4_cfgready;
};
static inline u32