scsi: ufs: adjusted UFS power management for exynos specific
authorhgchu <hg.chu@samsung.com>
Fri, 12 Jan 2018 01:32:29 +0000 (10:32 +0900)
committerJaeHun Jung <jh0801.jung@samsung.com>
Tue, 8 May 2018 08:20:14 +0000 (17:20 +0900)
Change-Id: I151e77eb1f5f2703e33cd4e9834204a9fa66f88c
Signed-off-by: hgchu <hg.chu@samsung.com>
drivers/scsi/ufs/ufshcd-pltfrm.c
drivers/scsi/ufs/ufshcd.c

index f33a3797ef7b392c645f7b7d0ff02a839fff61ad..713570e17b8478985b9e511b199bac2f79227e5f 100644 (file)
@@ -221,6 +221,34 @@ out:
        return err;
 }
 
+static int ufshcd_parse_pm_lvl_policy(struct ufs_hba *hba)
+{
+       struct device *dev = hba->dev;
+       struct device_node *np = dev->of_node;
+       u32 lvl_def[] = {UFS_PM_LVL_2, UFS_PM_LVL_5};
+       u32 lvl[2] = {0,}, i;
+
+       for (i = 0; i < ARRAY_SIZE(lvl); i++) {
+               if (of_property_read_u32_index(np, "pm_lvl_states", i, lvl +i)) {
+                       dev_info(hba->dev,
+                               "UFS power management: set default level%d index %d\n",
+                               lvl_def[i], i);
+                       lvl[i] = lvl_def[i];
+               }
+
+               if (lvl[i] < UFS_PM_LVL_0 || lvl[i] >= UFS_PM_LVL_MAX) {
+                       dev_warn(hba->dev,
+                               "UFS power management: out of range level%d index %d\n",
+                               lvl[i], i);
+                       lvl[i] =  lvl_def[i];
+               }
+       }
+
+       hba->rpm_lvl = lvl[0];
+       hba->spm_lvl = lvl[1];
+
+       return 0;
+}
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -340,6 +368,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
                goto dealloc_host;
        }
 
+       ufshcd_parse_pm_lvl_policy(hba);
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
index 28f3b8582eae2dd8cf5215da175c50687eaefcc9..193f67f5424ba01059805f68b382b3106458488b 100644 (file)
@@ -3969,8 +3969,10 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
                dev_err(hba->dev,
                        "%s: power mode change failed %d\n", __func__, ret);
        } else {
-               ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
+               ret = ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
                                                                pwr_mode);
+               if (ret)
+                       goto out;
 
                memcpy(&hba->pwr_info, pwr_mode,
                        sizeof(struct ufs_pa_layer_attr));
@@ -3993,13 +3995,17 @@ int ufshcd_config_pwr_mode(struct ufs_hba *hba,
        ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE,
                                        desired_pwr_mode, &final_params);
 
-       if (ret)
-               memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
+       if (ret) {
+               if (ret == -ENOTSUPP)
+                       memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
+               else
+                       goto out;
+       }
 
        ret = ufshcd_change_power_mode(hba, &final_params);
        if (!ret)
                ufshcd_print_pwr_info(hba);
-
+out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);
@@ -6899,6 +6905,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
        int ret = 0;
        struct ufs_clk_info *clki;
        struct list_head *head = &hba->clk_list_head;
+       const char *ref_clk = "ref_clk";
        unsigned long flags;
        ktime_t start = ktime_get();
        bool clk_state_changed = false;
@@ -6912,7 +6919,8 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
 
        list_for_each_entry(clki, head, list) {
                if (!IS_ERR_OR_NULL(clki->clk)) {
-                       if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
+                       if (skip_ref_clk &&
+                           !strncmp(clki->name, ref_clk, strlen(ref_clk)))
                                continue;
 
                        clk_state_changed = on ^ clki->enabled;
@@ -7426,17 +7434,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
        if (ret)
                goto set_dev_active;
 
-       ufshcd_vreg_set_lpm(hba);
-
 disable_clks:
        /*
-        * Call vendor specific suspend callback. As these callbacks may access
-        * vendor specific host controller register space call them before the
-        * host clocks are ON.
+        * Disable the host irq as host controller as there won't be any
+        * host controller trasanction expected till resume.
         */
-       ret = ufshcd_vops_suspend(hba, pm_op);
-       if (ret)
-               goto set_link_active;
+       ufshcd_disable_irq(hba);
+
 
        if (!ufshcd_is_link_active(hba))
                ufshcd_setup_clocks(hba, false);
@@ -7447,10 +7451,15 @@ disable_clks:
        hba->clk_gating.state = CLKS_OFF;
        trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
        /*
-        * Disable the host irq as host controller as there won't be any
-        * host controller transaction expected till resume.
+        * Call vendor specific suspend callback. As these callbacks may access
+        * vendor specific host controller register space call them before the
+        * host clocks are ON.
         */
-       ufshcd_disable_irq(hba);
+       ret = ufshcd_vops_suspend(hba, pm_op);
+       if (ret)
+               goto set_link_active;
+
+
        /* Put the host controller in low power mode if possible */
        ufshcd_hba_vreg_set_lpm(hba);
        goto out;