summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubhash Jadavani <subhashj@codeaurora.org>2014-09-21 00:00:27 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:57:29 -0700
commit9d89b6c4c80db9b7d62f40e5cca9b8730c828ada (patch)
treec4e1c9cb801f3ec48d23dc1c451e5f81ba85e927
parent8c17ea4d5b35ea2004ccea98ee8c8cdf308ba535 (diff)
scsi: ufs-qcom: enable host controller hardware clock gating
The UTP controller has a number of internal clock gating cells (CGCs). Internal hardware sub-modules within the UTP controller control the CGCs. Hardware CGCs disable the clock to inactivate UTP sub-modules not involved in a specific operation, UTP controller CGCs are by default disabled and this change enables them (after every UFS link startup) to save some power leakage. Change-Id: I47bba62436c5913eb6755e59c36a11fea2e9468f Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c19
-rw-r--r--include/linux/scsi/ufs/ufs-qcom.h15
2 files changed, 34 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index f6fe47ec2e99..036b0a7a3238 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -264,6 +264,24 @@ out:
return ret;
}
+/*
+ * The UTP controller has a number of internal clock gating cells (CGCs).
+ * Internal hardware sub-modules within the UTP controller control the CGCs.
+ * Hardware CGCs disable the clock to inactivate UTP sub-modules not involved
+ * in a specific operation, UTP controller CGCs are by default disabled and
+ * this function enables them (after every UFS link startup) to save some power
+ * leakage.
+ */
+static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
+{
+ ufshcd_writel(hba,
+ ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL,
+ REG_UFS_CFG2);
+
+ /* Ensure that HW clock gating is enabled before next operations */
+ mb();
+}
+
static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
{
struct ufs_qcom_host *host = hba->priv;
@@ -282,6 +300,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
case POST_CHANGE:
/* check if UFS PHY moved from DISABLED to HIBERN8 */
err = ufs_qcom_check_hibern8(hba);
+ ufs_qcom_enable_hw_clk_gating(hba);
break;
default:
dev_err(hba->dev, "%s: invalid status %d\n", __func__, status);
diff --git a/include/linux/scsi/ufs/ufs-qcom.h b/include/linux/scsi/ufs/ufs-qcom.h
index 2bcb1edd53fa..e3c7342a4772 100644
--- a/include/linux/scsi/ufs/ufs-qcom.h
+++ b/include/linux/scsi/ufs/ufs-qcom.h
@@ -60,6 +60,21 @@ enum {
REG_UFS_HW_VERSION = 0xE4,
};
+/* bit definitions for REG_UFS_CFG2 register */
+#define UAWM_HW_CGC_EN (1 << 0)
+#define UARM_HW_CGC_EN (1 << 1)
+#define TXUC_HW_CGC_EN (1 << 2)
+#define RXUC_HW_CGC_EN (1 << 3)
+#define DFC_HW_CGC_EN (1 << 4)
+#define TRLUT_HW_CGC_EN (1 << 5)
+#define TMRLUT_HW_CGC_EN (1 << 6)
+#define OCSC_HW_CGC_EN (1 << 7)
+
+#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
+ TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
+ DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
+ TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN)
+
/* bit offset */
enum {
OFFSET_UFS_PHY_SOFT_RESET = 1,