From f8c15594b092513e0e0bdba8a58ef5e81125085e Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Wed, 19 Feb 2020 15:35:03 -0800 Subject: [PATCH 1/3] scsi: ufs-qcom: Get low power levels from devicetree Parse runtime-pm and system-pm levels from devicetree. If unspecified, assign invalid levels so that default values of 3 are used. Change-Id: I74a7f35c40299207b13221d87d3fbc3ffad4fe10 Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufs-qcom.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index b7cac5384c67..b06b89d44b5e 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1979,6 +1979,21 @@ ufs_qcom_ioctl(struct scsi_device *dev, unsigned int cmd, void __user *buffer) return err; } +static void ufs_qcom_parse_pm_level(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; + } +} + /** * ufs_qcom_init - bind phy with controller * @hba: host controller instance @@ -2132,6 +2147,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) if (err) goto out_set_load_vccq_parent; + ufs_qcom_parse_pm_level(hba); ufs_qcom_parse_limits(host); ufs_qcom_parse_lpm(host); if (host->disable_lpm) From 3595f454918c10aea1c9aea0a81d78a860000533 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Wed, 19 Feb 2020 13:47:57 -0800 Subject: [PATCH 2/3] scsi: ufshcd-qti: Always allow vendor to configure clocks Allow vendor configuration on prechange and post-change change while setting up clocks. Change-Id: I90c7657f1ccfd1beed97779d2c7a3a85173fd176 Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd-qti.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd-qti.c b/drivers/scsi/ufs/ufshcd-qti.c index 2405844354d7..f50ed83ff723 100644 --- a/drivers/scsi/ufs/ufshcd-qti.c +++ b/drivers/scsi/ufs/ufshcd-qti.c @@ -8703,11 +8703,9 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, * this standard driver hence call the vendor specific setup_clocks * before disabling the clocks managed here. */ - if (!on) { - ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE); - if (ret) - goto out_unlock; - } + ret = ufshcd_vops_setup_clocks(hba, on, PRE_CHANGE); + if (ret) + return ret; list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk)) { @@ -8742,11 +8740,7 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, * this standard driver hence call the vendor specific setup_clocks * after enabling the clocks managed here. */ - if (on) { - ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE); - if (ret) - goto out; - } + ret = ufshcd_vops_setup_clocks(hba, on, POST_CHANGE); out: if (ret) { @@ -8766,7 +8760,6 @@ out: trace_ufshcd_profile_clk_gating(dev_name(hba->dev), (on ? "on" : "off"), ktime_to_us(ktime_sub(ktime_get(), start)), ret); -out_unlock: return ret; } From 55af5bb593c50970b9390199bdef4965d12bfd0e Mon Sep 17 00:00:00 2001 From: Can Guo Date: Wed, 30 Oct 2019 02:01:15 -0700 Subject: [PATCH 3/3] scsi: ufs-qcom: Adjust the order of bus bandwidth voting and unvoting The bus bandwidth voting is required to be done before the bus clocks are enabled, and the unvoting is required to be done only after the bus clocks are disabled. Change-Id: Ie231d9c373c0d8c8f3dd90b8322ff24fabdfae26 Signed-off-by: Can Guo --- drivers/scsi/ufs/ufs-qcom.c | 82 ++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index b06b89d44b5e..ebd370933f6b 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -64,7 +64,6 @@ struct ufs_qcom_dev_params { static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, u32 clk_1us_cycles, @@ -1053,7 +1052,7 @@ static int ufs_qcom_get_ib_ab(struct ufs_qcom_host *host, int index, return 0; } -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +static int __ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) { int err = 0; struct qcom_bus_scale_data *d = host->qbsd; @@ -1100,7 +1099,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) vote = ufs_qcom_get_bus_vote(host, mode); if (vote >= 0) - err = ufs_qcom_set_bus_vote(host, vote); + err = __ufs_qcom_set_bus_vote(host, vote); else err = vote; @@ -1111,6 +1110,35 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return err; } +static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int vote, err; + + /* + * In case ufs_qcom_init() is not yet done, simply ignore. + * This ufs_qcom_set_bus_vote() shall be called from + * ufs_qcom_init() after init is done. + */ + if (!host) + return 0; + + if (on) { + vote = host->bus_vote.saved_vote; + if (vote == host->bus_vote.min_bw_vote) + ufs_qcom_update_bus_bw_vote(host); + } else { + vote = host->bus_vote.min_bw_vote; + } + + err = __ufs_qcom_set_bus_vote(host, vote); + if (err) + dev_err(hba->dev, "%s: set bus vote failed %d\n", + __func__, err); + + return err; +} + static ssize_t show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, char *buf) @@ -1271,7 +1299,7 @@ static int ufs_qcom_bus_register(struct ufs_qcom_host *host) err); /* Full throttle */ - err = ufs_qcom_set_bus_vote(host, host->bus_vote.max_bw_vote); + err = __ufs_qcom_set_bus_vote(host, host->bus_vote.max_bw_vote); if (err) dev_err(dev, "Error: (%d) Failed to set max bus vote\n", err); @@ -1550,8 +1578,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err; - int vote = 0; + int err = 0; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -1561,32 +1588,28 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, if (!host) return 0; - if (on && (status == POST_CHANGE)) { - /* enable the device ref clock for HS mode*/ - if (ufshcd_is_hs_mode(&hba->pwr_info)) - ufs_qcom_dev_ref_clk_ctrl(host, true); - vote = host->bus_vote.saved_vote; - if (vote == host->bus_vote.min_bw_vote) - ufs_qcom_update_bus_bw_vote(host); - - } else if (!on && (status == PRE_CHANGE)) { - if ((ufshcd_is_auto_hibern8_supported(hba) && - !!hba->ahit) || - !ufs_qcom_is_link_active(hba)) { - /* disable device ref_clk */ - ufs_qcom_dev_ref_clk_ctrl(host, false); - /* powering off PHY during aggressive clk gating */ + switch (status) { + case PRE_CHANGE: + if (on) { + err = ufs_qcom_set_bus_vote(hba, true); + } else { + if (!ufs_qcom_is_link_active(hba)) { + /* disable device ref_clk */ + ufs_qcom_dev_ref_clk_ctrl(host, false); + } } - - - vote = host->bus_vote.min_bw_vote; + break; + case POST_CHANGE: + if (on) { + /* enable the device ref clock for HS mode*/ + if (ufshcd_is_hs_mode(&hba->pwr_info)) + ufs_qcom_dev_ref_clk_ctrl(host, true); + } else { + err = ufs_qcom_set_bus_vote(hba, false); + } + break; } - err = ufs_qcom_set_bus_vote(host, vote); - if (err) - dev_err(hba->dev, "%s: set bus vote failed %d\n", - __func__, err); - return err; } @@ -2156,6 +2179,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_bus_vote(hba, true); ufs_qcom_setup_clocks(hba, true, POST_CHANGE); if (hba->dev->id < MAX_UFS_QCOM_HOSTS)