scsi: ufs: core: Fix bRefClkFreq write failure in HS-LSS mode
According to the UFS spec, the bRefClkFreq attribute can only be written when both sub-links are in LS-MODE. However, in HS LSS mode with resetmode = HS_MODE, if the UFS device's default bRefClkFreq value differs from the host controller's dev_ref_clk_freq setting, the write operation will fail. To fix this issue, introduce ufshcd_get_op_mode() function to detect the current link operational mode. Call ufshcd_set_dev_ref_clk() only when both sub-links are in LS-MODE to ensure the attribute can be written successfully. Signed-off-by: Wang Shuaiwei <wangshuaiwei1@xiaomi.com> Link: https://patch.msgid.link/20260414033718.1459540-1-wangshuaiwei1@xiaomi.com Reviewed-by: Peter Wang <peter.wang@mediatek.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>master
parent
47e66bec3e
commit
b06cf63d83
|
|
@ -9259,6 +9259,30 @@ static void ufshcd_config_mcq(struct ufs_hba *hba)
|
||||||
hba->nutrs);
|
hba->nutrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ufshcd_get_op_mode - get UFS operating mode.
|
||||||
|
* @hba: per-adapter instance
|
||||||
|
*
|
||||||
|
* Use the PA_PWRMODE value to represent the operating mode of UFS.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static enum ufs_op_mode ufshcd_get_op_mode(struct ufs_hba *hba)
|
||||||
|
{
|
||||||
|
u32 mode;
|
||||||
|
u8 rx_mode;
|
||||||
|
u8 tx_mode;
|
||||||
|
|
||||||
|
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode);
|
||||||
|
rx_mode = (mode >> PWRMODE_RX_OFFSET) & PWRMODE_MASK;
|
||||||
|
tx_mode = mode & PWRMODE_MASK;
|
||||||
|
|
||||||
|
if ((rx_mode == SLOW_MODE || rx_mode == SLOWAUTO_MODE) &&
|
||||||
|
(tx_mode == SLOW_MODE || tx_mode == SLOWAUTO_MODE))
|
||||||
|
return LS_MODE;
|
||||||
|
|
||||||
|
return HS_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
static int ufshcd_post_device_init(struct ufs_hba *hba)
|
static int ufshcd_post_device_init(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -9281,11 +9305,13 @@ static int ufshcd_post_device_init(struct ufs_hba *hba)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the right value to bRefClkFreq before attempting to
|
* Set the right value to bRefClkFreq in LS_MODE before attempting to
|
||||||
* switch to HS gears.
|
* switch to HS gears.
|
||||||
*/
|
*/
|
||||||
if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL)
|
if (ufshcd_get_op_mode(hba) == LS_MODE &&
|
||||||
|
hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL)
|
||||||
ufshcd_set_dev_ref_clk(hba);
|
ufshcd_set_dev_ref_clk(hba);
|
||||||
|
|
||||||
/* Gear up to HS gear. */
|
/* Gear up to HS gear. */
|
||||||
ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info,
|
ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info,
|
||||||
UFSHCD_PMC_POLICY_DONT_FORCE);
|
UFSHCD_PMC_POLICY_DONT_FORCE);
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,11 @@ enum ufs_eom_eye_mask {
|
||||||
#define DME_LocalTC0ReplayTimeOutVal 0xD042
|
#define DME_LocalTC0ReplayTimeOutVal 0xD042
|
||||||
#define DME_LocalAFC0ReqTimeOutVal 0xD043
|
#define DME_LocalAFC0ReqTimeOutVal 0xD043
|
||||||
|
|
||||||
|
enum ufs_op_mode {
|
||||||
|
LS_MODE = 1,
|
||||||
|
HS_MODE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/* PA power modes */
|
/* PA power modes */
|
||||||
enum ufs_pa_pwr_mode {
|
enum ufs_pa_pwr_mode {
|
||||||
FAST_MODE = 1,
|
FAST_MODE = 1,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue