summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt10
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c14
-rw-r--r--drivers/scsi/ufs/ufshcd.c23
-rw-r--r--include/linux/scsi/ufs/ufshcd.h4
4 files changed, 44 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index c9cd219c4a3c..72b2aa03321e 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -38,6 +38,14 @@ Optional properties:
defined or a value in the array is "0" then it is assumed
that the frequency is set by the parent clock or a
fixed rate clock source.
+- rpm-level : UFS Runtime power management level. Following PM levels are suppported:
+ 0 - Both UFS device and Link in active state (Highest power consumption)
+ 1 - UFS device in active state but Link in Hibern8 state
+ 2 - UFS device in Sleep state but Link in active state
+ 3 - UFS device in Sleep state and Link in hibern8 state (default PM level)
+ 4 - UFS device in Power-down state and Link in Hibern8 state
+ 5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption)
+- spm-level : UFS System power management level. Allowed PM levels are same as rpm-level.
Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on.
@@ -63,6 +71,8 @@ Example:
freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
phys = <&ufsphy1>;
phy-names = "ufsphy";
+ rpm-level = <3>;
+ spm-level = <5>;
};
==== MSM UFS platform driver properties =====
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 967a78470f73..31fe2e5797c8 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -222,6 +222,19 @@ out:
return err;
}
+static void ufshcd_parse_pm_levels(struct ufs_hba *hba)
+{
+ struct device *dev = hba->dev;
+ struct device_node *np = dev->of_node;
+
+ if (np) {
+ if (of_property_read_u32(np, "rpm-level", &hba->rpm_lvl))
+ hba->rpm_lvl = -1;
+ if (of_property_read_u32(np, "spm-level", &hba->spm_lvl))
+ hba->spm_lvl = -1;
+ }
+}
+
#ifdef CONFIG_PM
/**
* ufshcd_pltfrm_suspend - suspend power management function
@@ -326,6 +339,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
goto dealloc_host;
}
+ ufshcd_parse_pm_levels(hba);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7fb477d4f97e..ce37b0e0a1eb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -266,6 +266,14 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
return UFS_PM_LVL_0;
}
+static inline bool ufshcd_is_valid_pm_lvl(int lvl)
+{
+ if (lvl >= 0 && lvl < ARRAY_SIZE(ufs_pm_lvl_states))
+ return true;
+ else
+ return false;
+}
+
static void ufshcd_tmc_handler(struct ufs_hba *hba);
static void ufshcd_async_scan(void *data, async_cookie_t cookie);
static int ufshcd_reset_and_restore(struct ufs_hba *hba);
@@ -6836,14 +6844,19 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
}
/*
- * Set the default power management level for UFS runtime and system
+ * If rpm_lvl and and spm_lvl are not already set to valid levels,
+ * set the default power management level for UFS runtime and system
* suspend. Default power saving mode selected is keeping UFS link in
* Hibern8 state and UFS device in sleep.
*/
- hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
- UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE);
- hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
- UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE);
+ if (!ufshcd_is_valid_pm_lvl(hba->rpm_lvl))
+ hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+ UFS_SLEEP_PWR_MODE,
+ UIC_LINK_HIBERN8_STATE);
+ if (!ufshcd_is_valid_pm_lvl(hba->spm_lvl))
+ hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+ UFS_SLEEP_PWR_MODE,
+ UIC_LINK_HIBERN8_STATE);
/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);
diff --git a/include/linux/scsi/ufs/ufshcd.h b/include/linux/scsi/ufs/ufshcd.h
index 7b96bbcc70b3..c706837cac76 100644
--- a/include/linux/scsi/ufs/ufshcd.h
+++ b/include/linux/scsi/ufs/ufshcd.h
@@ -473,9 +473,9 @@ struct ufs_hba {
enum ufs_dev_pwr_mode curr_dev_pwr_mode;
enum uic_link_state uic_link_state;
/* Desired UFS power management level during runtime PM */
- enum ufs_pm_level rpm_lvl;
+ int rpm_lvl;
/* Desired UFS power management level during system PM */
- enum ufs_pm_level spm_lvl;
+ int spm_lvl;
struct device_attribute rpm_lvl_attr;
struct device_attribute spm_lvl_attr;
int pm_op_in_progress;