scsi: ufs: Put HBA into LPM during clk gating
authorCan Guo <cang@codeaurora.org>
Tue, 27 Oct 2020 19:10:36 +0000 (12:10 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 30 Oct 2020 01:57:18 +0000 (21:57 -0400)
During clock gating, after clocks are disabled, put HBA into LPM to save
more power.

Link: https://lore.kernel.org/r/52198e70bff750632740d78678a815256d697e43.1603825776.git.asutoshd@codeaurora.org
Reviewed-by: Avri Altman <avri.altman@wdc.com>
Acked-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Can Guo <cang@codeaurora.org>
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index b8f573a..2309253 100644 (file)
@@ -245,6 +245,8 @@ static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba);
 static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable);
 static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set);
 static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
+static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
+static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
 
 static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
 {
@@ -1548,6 +1550,7 @@ static void ufshcd_ungate_work(struct work_struct *work)
        }
 
        spin_unlock_irqrestore(hba->host->host_lock, flags);
+       ufshcd_hba_vreg_set_hpm(hba);
        ufshcd_setup_clocks(hba, true);
 
        ufshcd_enable_irq(hba);
@@ -1713,6 +1716,8 @@ static void ufshcd_gate_work(struct work_struct *work)
                /* If link is active, device ref_clk can't be switched off */
                __ufshcd_setup_clocks(hba, false, true);
 
+       /* Put the host controller in low power mode if possible */
+       ufshcd_hba_vreg_set_lpm(hba);
        /*
         * In case you are here to cancel this work the gating state
         * would be marked as REQ_CLKS_ON. In this case keep the state
@@ -8405,13 +8410,13 @@ out:
 
 static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba)
 {
-       if (ufshcd_is_link_off(hba))
+       if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
                ufshcd_setup_hba_vreg(hba, false);
 }
 
 static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
 {
-       if (ufshcd_is_link_off(hba))
+       if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
                ufshcd_setup_hba_vreg(hba, true);
 }
 
index 47eb143..0fbb735 100644 (file)
@@ -592,6 +592,13 @@ enum ufshcd_caps {
         * inline crypto engine, if it is present
         */
        UFSHCD_CAP_CRYPTO                               = 1 << 8,
+
+       /*
+        * This capability allows the controller regulators to be put into
+        * lpm mode aggressively during clock gating.
+        * This would increase power savings.
+        */
+       UFSHCD_CAP_AGGR_POWER_COLLAPSE                  = 1 << 9,
 };
 
 struct ufs_hba_variant_params {
@@ -829,6 +836,12 @@ return true;
 #endif
 }
 
+static inline bool ufshcd_can_aggressive_pc(struct ufs_hba *hba)
+{
+       return !!(ufshcd_is_link_hibern8(hba) &&
+                 (hba->caps & UFSHCD_CAP_AGGR_POWER_COLLAPSE));
+}
+
 static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
 {
        return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) &&