]> www.infradead.org Git - users/hch/misc.git/commitdiff
scsi: ufs: host: mediatek: Fix auto-hibern8 timer configuration
authorPeter Wang <peter.wang@mediatek.com>
Mon, 11 Aug 2025 13:11:18 +0000 (21:11 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 15 Aug 2025 02:49:12 +0000 (22:49 -0400)
Move the configuration of the Auto-Hibern8 (AHIT) timer from the
post-link stage to the 'fixup_dev_quirks' function. This change allows
setting the AHIT based on the vendor requirements:

   (a) Samsung: 3.5 ms
   (b) Micron: 2 ms
   (c) Others: 1 ms

Additionally, the clock gating timer is adjusted based on the AHIT
scale, with a maximum setting of 10 ms. This ensures that the clock
gating delay is appropriately configured to match the AHIT settings.

Signed-off-by: Peter Wang <peter.wang@mediatek.com>
Link: https://lore.kernel.org/r/20250811131423.3444014-3-peter.wang@mediatek.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/host/ufs-mediatek.c

index 1d2df63457bf06c61f116ee951142067e87430c1..e1eac1b428f81e25566565dd0be3dd922cd9cc58 100644 (file)
@@ -1075,6 +1075,69 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
        }
 }
 
+static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
+{
+       unsigned long flags;
+       u32 ah_ms = 10;
+       u32 ah_scale, ah_timer;
+       u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
+
+       if (ufshcd_is_clkgating_allowed(hba)) {
+               if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) {
+                       ah_scale = FIELD_GET(UFSHCI_AHIBERN8_SCALE_MASK,
+                                         hba->ahit);
+                       ah_timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
+                                         hba->ahit);
+                       if (ah_scale <= 5)
+                               ah_ms = ah_timer * scale_us[ah_scale] / 1000;
+               }
+
+               spin_lock_irqsave(hba->host->host_lock, flags);
+               hba->clk_gating.delay_ms = max(ah_ms, 10U);
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+       }
+}
+
+/* Convert microseconds to Auto-Hibernate Idle Timer register value */
+static u32 ufs_mtk_us_to_ahit(unsigned int timer)
+{
+       unsigned int scale;
+
+       for (scale = 0; timer > UFSHCI_AHIBERN8_TIMER_MASK; ++scale)
+               timer /= UFSHCI_AHIBERN8_SCALE_FACTOR;
+
+       return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) |
+              FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale);
+}
+
+static void ufs_mtk_fix_ahit(struct ufs_hba *hba)
+{
+       unsigned int us;
+
+       if (ufshcd_is_auto_hibern8_supported(hba)) {
+               switch (hba->dev_info.wmanufacturerid) {
+               case UFS_VENDOR_SAMSUNG:
+                       /* configure auto-hibern8 timer to 3.5 ms */
+                       us = 3500;
+                       break;
+
+               case UFS_VENDOR_MICRON:
+                       /* configure auto-hibern8 timer to 2 ms */
+                       us = 2000;
+                       break;
+
+               default:
+                       /* configure auto-hibern8 timer to 1 ms */
+                       us = 1000;
+                       break;
+               }
+
+               hba->ahit = ufs_mtk_us_to_ahit(us);
+       }
+
+       ufs_mtk_setup_clk_gating(hba);
+}
+
 static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
 {
        struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -1369,32 +1432,10 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba)
 
        return ret;
 }
-
-static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
-{
-       u32 ah_ms;
-
-       if (ufshcd_is_clkgating_allowed(hba)) {
-               if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit)
-                       ah_ms = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
-                                         hba->ahit);
-               else
-                       ah_ms = 10;
-               ufshcd_clkgate_delay_set(hba->dev, ah_ms + 5);
-       }
-}
-
 static void ufs_mtk_post_link(struct ufs_hba *hba)
 {
        /* enable unipro clock gating feature */
        ufs_mtk_cfg_unipro_cg(hba, true);
-
-       /* will be configured during probe hba */
-       if (ufshcd_is_auto_hibern8_supported(hba))
-               hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) |
-                       FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
-
-       ufs_mtk_setup_clk_gating(hba);
 }
 
 static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
@@ -1726,6 +1767,7 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
 
        ufs_mtk_vreg_fix_vcc(hba);
        ufs_mtk_vreg_fix_vccqx(hba);
+       ufs_mtk_fix_ahit(hba);
 }
 
 static void ufs_mtk_event_notify(struct ufs_hba *hba,