Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 977028c7 authored by Nitin Rawat's avatar Nitin Rawat
Browse files

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



The tx_cfg_rdy signal from PHY to Controller to indicate
EOB(END OF BURST) runs using TX CFG clock which is half the Uniproclk
freq. But it is observed that tx_cfg_rdyn signal is getting sampled in
controller using Uniproclk (300 MHz) instead of TX CFG clock (150 MHz)
and hence FSM in controller is going into unwanted state when only
one of tx_cfg_rdyn_0 and tx_cfg_rdyn_1 is 0 around sampling clock edge.

To workaround this issue, control should bypass the Cfgready
signal(TX_CFGREADY and RX_CFGREDY) because controller stills wait
for another signal tx_savestatusn which will serve same purpose.

Change-Id: I2f32542682571ba6e7b1266393dfb1168dc68658
Signed-off-by: default avatarNitin Rawat <nitirawa@codeaurora.org>
parent d8534164
Loading
Loading
Loading
Loading
+74 −1
Original line number Diff line number Diff line
@@ -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.
 */
+11 −2
Original line number Diff line number Diff line
@@ -168,8 +168,16 @@ enum ufs_qcom_phy_init_type {

/* QUniPro Vendor specific attributes */
#define PA_VS_CONFIG_REG1	0x9000
#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