diff options
| -rw-r--r-- | Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | 10 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshcd-pltfrm.c | 14 | ||||
| -rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 23 | ||||
| -rw-r--r-- | include/linux/scsi/ufs/ufshcd.h | 4 |
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; |
