summaryrefslogtreecommitdiff
path: root/drivers/scsi/ufs/ufshcd.c
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2018-03-20 15:07:38 +0200
committerMartin K. Petersen <martin.petersen@oracle.com>2018-03-21 21:21:25 -0400
commitad448378825f5746c5fa37718724bc8f4e7b6945 (patch)
tree0ebb00a59acf4e870228d90900fe8c39b5dfbc30 /drivers/scsi/ufs/ufshcd.c
parent114c1aa210494a02c26aa33f793e5b641df01989 (diff)
scsi: ufs: Add support for Auto-Hibernate Idle Timer
UFS host controllers may support an autonomous power management feature called the Auto-Hibernate Idle Timer. The timer is set to the number of microseconds of idle time before the UFS host controller will autonomously put the link into Hibernate state. That will save power at the expense of increased latency. Any access to the host controller interface registers will automatically put the link out of Hibernate state. So once configured, the feature is transparent to the driver. Expose the Auto-Hibernate Idle Timer value via SysFS to allow users to choose between power efficiency or lower latency. Set a default value of 150 ms. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Stanislav Nijnikov <stanislav.nijnikov@wdc.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.c')
-rw-r--r--drivers/scsi/ufs/ufshcd.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3abcd31646eb..facee2b97926 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -41,6 +41,7 @@
#include <linux/devfreq.h>
#include <linux/nls.h>
#include <linux/of.h>
+#include <linux/bitfield.h>
#include "ufshcd.h"
#include "ufs_quirks.h"
#include "unipro.h"
@@ -3708,6 +3709,18 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
return ret;
}
+static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
+{
+ unsigned long flags;
+
+ if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit)
+ return;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+
/**
* ufshcd_init_pwr_info - setting the POR (power on reset)
* values in hba power info
@@ -6307,6 +6320,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
/* UniPro link is active now */
ufshcd_set_link_active(hba);
+ /* Enable Auto-Hibernate if configured */
+ ufshcd_auto_hibern8_enable(hba);
+
ret = ufshcd_verify_dev_init(hba);
if (ret)
goto out;
@@ -7391,6 +7407,10 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release(hba);
+
+ /* Enable Auto-Hibernate if configured */
+ ufshcd_auto_hibern8_enable(hba);
+
goto out;
set_old_link_state:
@@ -7834,6 +7854,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
UFS_SLEEP_PWR_MODE,
UIC_LINK_HIBERN8_STATE);
+ /* Set the default auto-hiberate idle timer value to 150 ms */
+ if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) {
+ hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) |
+ FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
+ }
+
/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);