summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorWang Shuaiwei <wangshuaiwei1@xiaomi.com>2026-04-14 11:37:18 +0800
committerMartin K. Petersen <martin.petersen@oracle.com>2026-04-21 20:58:06 -0400
commitb06cf63d83d3b3744d3aefdd2f3ced25e99d7ec1 (patch)
tree6afcb57cb4c671cd78a5e559d2d099e5c650a158 /drivers
parent47e66bec3edaebd7c52d8ee981065a4c83b3072f (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ufs/core/ufshcd.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 4805e40ed4d7..c3f08957d179 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -9259,6 +9259,30 @@ static void ufshcd_config_mcq(struct ufs_hba *hba)
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)
{
int ret;
@@ -9281,11 +9305,13 @@ static int ufshcd_post_device_init(struct ufs_hba *hba)
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.
*/
- 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);
+
/* Gear up to HS gear. */
ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info,
UFSHCD_PMC_POLICY_DONT_FORCE);