]> www.infradead.org Git - users/hch/misc.git/commitdiff
scsi: ufs: host: mediatek: Disable auto-hibern8 during power mode changes
authorPeter Wang <peter.wang@mediatek.com>
Wed, 3 Sep 2025 02:44:42 +0000 (10:44 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 10 Sep 2025 02:46:23 +0000 (22:46 -0400)
Disable auto-hibern8 during power mode transitions to prevent unintended
entry into auto-hibern8. Restore the original auto-hibern8 timer value
after completing the power mode change to maintain system stability and
prevent potential issues during power state transitions.

Signed-off-by: Peter Wang <peter.wang@mediatek.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/host/ufs-mediatek.c

index f79b488498462cd1f2c23ea09e4c30d7875fff08..63dd3087211a1d7d366038fef70341627b4fb87d 100644 (file)
@@ -1429,19 +1429,49 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
        return ret;
 }
 
+static int ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
+{
+       int ret;
+
+       /* disable auto-hibern8 */
+       ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
+
+       /* wait host return to idle state when auto-hibern8 off */
+       ufs_mtk_wait_idle_state(hba, 5);
+
+       ret = ufs_mtk_wait_link_state(hba, VS_LINK_UP, 100);
+       if (ret) {
+               dev_warn(hba->dev, "exit h8 state fail, ret=%d\n", ret);
+
+               ufshcd_force_error_recovery(hba);
+
+               /* trigger error handler and break suspend */
+               ret = -EBUSY;
+       }
+
+       return ret;
+}
+
 static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
                                enum ufs_notify_change_status stage,
                                const struct ufs_pa_layer_attr *dev_max_params,
                                struct ufs_pa_layer_attr *dev_req_params)
 {
        int ret = 0;
+       static u32 reg;
 
        switch (stage) {
        case PRE_CHANGE:
+               if (ufshcd_is_auto_hibern8_supported(hba)) {
+                       reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
+                       ufs_mtk_auto_hibern8_disable(hba);
+               }
                ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
                                             dev_req_params);
                break;
        case POST_CHANGE:
+               if (ufshcd_is_auto_hibern8_supported(hba))
+                       ufshcd_writel(hba, reg, REG_AUTO_HIBERNATE_IDLE_TIMER);
                break;
        default:
                ret = -EINVAL;
@@ -1686,29 +1716,6 @@ static void ufs_mtk_dev_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
        }
 }
 
-static int ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
-{
-       int ret;
-
-       /* disable auto-hibern8 */
-       ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
-
-       /* wait host return to idle state when auto-hibern8 off */
-       ufs_mtk_wait_idle_state(hba, 5);
-
-       ret = ufs_mtk_wait_link_state(hba, VS_LINK_UP, 100);
-       if (ret) {
-               dev_warn(hba->dev, "exit h8 state fail, ret=%d\n", ret);
-
-               ufshcd_force_error_recovery(hba);
-
-               /* trigger error handler and break suspend */
-               ret = -EBUSY;
-       }
-
-       return ret;
-}
-
 static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
        enum ufs_notify_change_status status)
 {