2023-10-03 11:12:57

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 0/6] UFS: Add OPP support

Hi,

This series adds OPP (Operating Points) support to UFSHCD driver.

Motivation behind adding OPP support is to scale both clocks as well as
regulators/performance state dynamically. Currently, UFSHCD just scales
clock frequency during runtime with the help of "freq-table-hz" property
defined in devicetree. With the addition of OPP tables in devicetree (as
done for Qcom SDM845 and SM8250 SoCs in this series) UFSHCD can now scale
both clocks and performance state of power domain which helps in power
saving.

For the addition of OPP support to UFSHCD, there are changes required to
the OPP framework and devfreq drivers. The OPP framework changes are already
merged and the devfreq change is added in this series.

Credits
=======

This series is a continuation of previous work by Krzysztof Kozlowski [1].

Testing
=======

This series is tested on 96Boards RB3 (SDM845 SoC) and RB5 (SM8250 SoC)
development boards.

Merging Strategy
================

Since the devfreq patch got an Ack from the maintainer, either it can be merged
to scsi tree with rest of the patches or merged separately through devfreq tree.

Thanks,
Mani

[1] https://lore.kernel.org/all/[email protected]/

Changes in v4:

* Rebased on top of v6.6-rc3

Changes in v3:

* Rebased on top of linux-next/master tag: next-20230731
* Dropped the already applied patches (dts, opp binding and framework)
* Moved the interconnect patches to a separate series:
https://lore.kernel.org/linux-scsi/[email protected]/
* Moved ufshcd_opp_config_clks() API to ufshcd.c to fix the build failure
reported by Kbuild bot: https://lore.kernel.org/all/[email protected]/
* Collected Acks
* v2: https://lore.kernel.org/all/[email protected]/

Changes in v2:

* Added more description to the bindings patch 2/15
* Fixed dev_pm_opp_put() usage in patch 10/15
* Added a new patch for adding enums for UFS lanes 14/15
* Changed the icc variables to mem_bw and cfg_bw and used
the enums for gears and lanes in bw_table
* Collected review tags
* Added SCSI list and folks
* Removed duplicate patches

Krzysztof Kozlowski (2):
dt-bindings: ufs: common: add OPP table
arm64: dts: qcom: sdm845: Add OPP table support to UFSHC

Manivannan Sadhasivam (4):
PM / devfreq: Switch to dev_pm_opp_find_freq_{ceil/floor}_indexed()
APIs
scsi: ufs: core: Add OPP support for scaling clocks and regulators
scsi: ufs: host: Add support for parsing OPP
arm64: dts: qcom: sm8250: Add OPP table support to UFSHC

.../devicetree/bindings/ufs/ufs-common.yaml | 36 +++-
arch/arm64/boot/dts/qcom/sdm845.dtsi | 42 +++-
arch/arm64/boot/dts/qcom/sm8250.dtsi | 39 +++-
drivers/devfreq/devfreq.c | 14 +-
drivers/ufs/core/ufshcd.c | 179 ++++++++++++++----
drivers/ufs/host/ufshcd-pltfrm.c | 78 ++++++++
include/ufs/ufshcd.h | 7 +
7 files changed, 332 insertions(+), 63 deletions(-)

--
2.25.1


2023-10-03 11:13:36

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 3/6] scsi: ufs: core: Add OPP support for scaling clocks and regulators

UFS core is only scaling the clocks during devfreq scaling and
initialization. But for an optimum power saving, regulators should also
be scaled along with the clocks.

So let's use the OPP framework which supports scaling clocks, regulators,
and performance state using OPP table defined in devicetree. For
accomodating the OPP support, the existing APIs (ufshcd_scale_clks,
ufshcd_is_devfreq_scaling_required and ufshcd_devfreq_scale) are modified
to accept "freq" as an argument which in turn used by the OPP helpers.

The OPP support is added along with the old freq-table based clock scaling
so that the existing platforms work as expected.

Co-developed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/ufs/core/ufshcd.c | 144 +++++++++++++++++++++++++++++---------
include/ufs/ufshcd.h | 4 ++
2 files changed, 115 insertions(+), 33 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index c2df07545f96..55de0ff1f01f 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
#include <linux/sched/clock.h>
#include <linux/iopoll.h>
@@ -275,7 +276,8 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
static void ufshcd_resume_clkscaling(struct ufs_hba *hba);
static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
-static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
+static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq,
+ bool scale_up);
static irqreturn_t ufshcd_intr(int irq, void *__hba);
static int ufshcd_change_power_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *pwr_mode);
@@ -1062,14 +1064,32 @@ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up)
return ret;
}

+static int ufshcd_opp_set_rate(struct ufs_hba *hba, unsigned long freq)
+{
+ struct dev_pm_opp *opp;
+ int ret;
+
+ opp = dev_pm_opp_find_freq_floor_indexed(hba->dev,
+ &freq, 0);
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
+
+ ret = dev_pm_opp_set_opp(hba->dev, opp);
+ dev_pm_opp_put(opp);
+
+ return ret;
+}
+
/**
* ufshcd_scale_clks - scale up or scale down UFS controller clocks
* @hba: per adapter instance
+ * @freq: frequency to scale
* @scale_up: True if scaling up and false if scaling down
*
* Return: 0 if successful; < 0 upon failure.
*/
-static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq,
+ bool scale_up)
{
int ret = 0;
ktime_t start = ktime_get();
@@ -1078,13 +1098,21 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
if (ret)
goto out;

- ret = ufshcd_set_clk_freq(hba, scale_up);
+ if (hba->use_pm_opp)
+ ret = ufshcd_opp_set_rate(hba, freq);
+ else
+ ret = ufshcd_set_clk_freq(hba, scale_up);
if (ret)
goto out;

ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
- if (ret)
- ufshcd_set_clk_freq(hba, !scale_up);
+ if (ret) {
+ if (hba->use_pm_opp)
+ ufshcd_opp_set_rate(hba,
+ hba->devfreq->previous_freq);
+ else
+ ufshcd_set_clk_freq(hba, !scale_up);
+ }

out:
trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
@@ -1096,12 +1124,13 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
/**
* ufshcd_is_devfreq_scaling_required - check if scaling is required or not
* @hba: per adapter instance
+ * @freq: frequency to scale
* @scale_up: True if scaling up and false if scaling down
*
* Return: true if scaling is required, false otherwise.
*/
static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
- bool scale_up)
+ unsigned long freq, bool scale_up)
{
struct ufs_clk_info *clki;
struct list_head *head = &hba->clk_list_head;
@@ -1109,6 +1138,9 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
if (list_empty(head))
return false;

+ if (hba->use_pm_opp)
+ return freq != hba->clk_scaling.target_freq;
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (scale_up && clki->max_freq) {
@@ -1304,12 +1336,14 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool sc
/**
* ufshcd_devfreq_scale - scale up/down UFS clocks and gear
* @hba: per adapter instance
+ * @freq: frequency to scale
* @scale_up: True for scaling up and false for scalin down
*
* Return: 0 for success; -EBUSY if scaling can't happen at this time; non-zero
* for any other errors.
*/
-static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
+static int ufshcd_devfreq_scale(struct ufs_hba *hba, unsigned long freq,
+ bool scale_up)
{
int ret = 0;

@@ -1324,7 +1358,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
goto out_unprepare;
}

- ret = ufshcd_scale_clks(hba, scale_up);
+ ret = ufshcd_scale_clks(hba, freq, scale_up);
if (ret) {
if (!scale_up)
ufshcd_scale_gear(hba, true);
@@ -1335,7 +1369,8 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
if (scale_up) {
ret = ufshcd_scale_gear(hba, true);
if (ret) {
- ufshcd_scale_clks(hba, false);
+ ufshcd_scale_clks(hba, hba->devfreq->previous_freq,
+ false);
goto out_unprepare;
}
}
@@ -1393,9 +1428,22 @@ static int ufshcd_devfreq_target(struct device *dev,
if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;

- clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info, list);
- /* Override with the closest supported frequency */
- *freq = (unsigned long) clk_round_rate(clki->clk, *freq);
+ if (hba->use_pm_opp) {
+ struct dev_pm_opp *opp;
+
+ /* Get the recommended frequency from OPP framework */
+ opp = devfreq_recommended_opp(dev, freq, flags);
+ if (IS_ERR(opp))
+ return PTR_ERR(opp);
+
+ dev_pm_opp_put(opp);
+ } else {
+ /* Override with the closest supported frequency */
+ clki = list_first_entry(&hba->clk_list_head, struct ufs_clk_info,
+ list);
+ *freq = (unsigned long) clk_round_rate(clki->clk, *freq);
+ }
+
spin_lock_irqsave(hba->host->host_lock, irq_flags);
if (ufshcd_eh_in_progress(hba)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
@@ -1410,12 +1458,17 @@ static int ufshcd_devfreq_target(struct device *dev,
goto out;
}

- /* Decide based on the rounded-off frequency and update */
- scale_up = *freq == clki->max_freq;
- if (!scale_up)
+ /* Decide based on the target or rounded-off frequency and update */
+ if (hba->use_pm_opp)
+ scale_up = *freq > hba->clk_scaling.target_freq;
+ else
+ scale_up = *freq == clki->max_freq;
+
+ if (!hba->use_pm_opp && !scale_up)
*freq = clki->min_freq;
+
/* Update the frequency */
- if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) {
+ if (!ufshcd_is_devfreq_scaling_required(hba, *freq, scale_up)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
ret = 0;
goto out; /* no state change required */
@@ -1423,7 +1476,9 @@ static int ufshcd_devfreq_target(struct device *dev,
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);

start = ktime_get();
- ret = ufshcd_devfreq_scale(hba, scale_up);
+ ret = ufshcd_devfreq_scale(hba, *freq, scale_up);
+ if (!ret)
+ hba->clk_scaling.target_freq = *freq;

trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
(scale_up ? "up" : "down"),
@@ -1443,8 +1498,6 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_clk_scaling *scaling = &hba->clk_scaling;
unsigned long flags;
- struct list_head *clk_list = &hba->clk_list_head;
- struct ufs_clk_info *clki;
ktime_t curr_t;

if (!ufshcd_is_clkscaling_supported(hba))
@@ -1457,17 +1510,24 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
if (!scaling->window_start_t)
goto start_window;

- clki = list_first_entry(clk_list, struct ufs_clk_info, list);
/*
* If current frequency is 0, then the ondemand governor considers
* there's no initial frequency set. And it always requests to set
* to max. frequency.
*/
- stat->current_frequency = clki->curr_freq;
+ if (hba->use_pm_opp) {
+ stat->current_frequency = hba->clk_scaling.target_freq;
+ } else {
+ struct list_head *clk_list = &hba->clk_list_head;
+ struct ufs_clk_info *clki;
+
+ clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+ stat->current_frequency = clki->curr_freq;
+ }
+
if (scaling->is_busy_started)
scaling->tot_busy_t += ktime_us_delta(curr_t,
scaling->busy_start_t);
-
stat->total_time = ktime_us_delta(curr_t, scaling->window_start_t);
stat->busy_time = scaling->tot_busy_t;
start_window:
@@ -1496,9 +1556,11 @@ static int ufshcd_devfreq_init(struct ufs_hba *hba)
if (list_empty(clk_list))
return 0;

- clki = list_first_entry(clk_list, struct ufs_clk_info, list);
- dev_pm_opp_add(hba->dev, clki->min_freq, 0);
- dev_pm_opp_add(hba->dev, clki->max_freq, 0);
+ if (!hba->use_pm_opp) {
+ clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+ dev_pm_opp_add(hba->dev, clki->min_freq, 0);
+ dev_pm_opp_add(hba->dev, clki->max_freq, 0);
+ }

ufshcd_vops_config_scaling_param(hba, &hba->vps->devfreq_profile,
&hba->vps->ondemand_data);
@@ -1510,8 +1572,10 @@ static int ufshcd_devfreq_init(struct ufs_hba *hba)
ret = PTR_ERR(devfreq);
dev_err(hba->dev, "Unable to register with devfreq %d\n", ret);

- dev_pm_opp_remove(hba->dev, clki->min_freq);
- dev_pm_opp_remove(hba->dev, clki->max_freq);
+ if (!hba->use_pm_opp) {
+ dev_pm_opp_remove(hba->dev, clki->min_freq);
+ dev_pm_opp_remove(hba->dev, clki->max_freq);
+ }
return ret;
}

@@ -1523,7 +1587,6 @@ static int ufshcd_devfreq_init(struct ufs_hba *hba)
static void ufshcd_devfreq_remove(struct ufs_hba *hba)
{
struct list_head *clk_list = &hba->clk_list_head;
- struct ufs_clk_info *clki;

if (!hba->devfreq)
return;
@@ -1531,9 +1594,13 @@ static void ufshcd_devfreq_remove(struct ufs_hba *hba)
devfreq_remove_device(hba->devfreq);
hba->devfreq = NULL;

- clki = list_first_entry(clk_list, struct ufs_clk_info, list);
- dev_pm_opp_remove(hba->dev, clki->min_freq);
- dev_pm_opp_remove(hba->dev, clki->max_freq);
+ if (!hba->use_pm_opp) {
+ struct ufs_clk_info *clki;
+
+ clki = list_first_entry(clk_list, struct ufs_clk_info, list);
+ dev_pm_opp_remove(hba->dev, clki->min_freq);
+ dev_pm_opp_remove(hba->dev, clki->max_freq);
+ }
}

static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba)
@@ -1618,7 +1685,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
ufshcd_resume_clkscaling(hba);
} else {
ufshcd_suspend_clkscaling(hba);
- err = ufshcd_devfreq_scale(hba, true);
+ err = ufshcd_devfreq_scale(hba, ULONG_MAX, true);
if (err)
dev_err(hba->dev, "%s: failed to scale clocks up %d\n",
__func__, err);
@@ -7627,7 +7694,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
hba->silence_err_logs = false;

/* scale up clocks to max frequency before full reinitialization */
- ufshcd_scale_clks(hba, true);
+ ufshcd_scale_clks(hba, ULONG_MAX, true);

err = ufshcd_hba_enable(hba);

@@ -9159,6 +9226,17 @@ static int ufshcd_init_clocks(struct ufs_hba *hba)
dev_dbg(dev, "%s: clk: %s, rate: %lu\n", __func__,
clki->name, clk_get_rate(clki->clk));
}
+
+ /* Set Max. frequency for all clocks */
+ if (hba->use_pm_opp) {
+ ret = ufshcd_opp_set_rate(hba, ULONG_MAX);
+ if (ret) {
+ dev_err(hba->dev, "%s: failed to set OPP: %d", __func__,
+ ret);
+ goto out;
+ }
+ }
+
out:
return ret;
}
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index 7d07b256e906..c181cc5c523b 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -427,6 +427,7 @@ struct ufs_clk_gating {
* @workq: workqueue to schedule devfreq suspend/resume work
* @suspend_work: worker to suspend devfreq
* @resume_work: worker to resume devfreq
+ * @target_freq: frequency requested by devfreq framework
* @min_gear: lowest HS gear to scale down to
* @is_enabled: tracks if scaling is currently enabled or not, controlled by
* clkscale_enable sysfs node
@@ -446,6 +447,7 @@ struct ufs_clk_scaling {
struct workqueue_struct *workq;
struct work_struct suspend_work;
struct work_struct resume_work;
+ unsigned long target_freq;
u32 min_gear;
bool is_enabled;
bool is_allowed;
@@ -865,6 +867,7 @@ enum ufshcd_mcq_opr {
* @auto_bkops_enabled: to track whether bkops is enabled in device
* @vreg_info: UFS device voltage regulator information
* @clk_list_head: UFS host controller clocks list node head
+ * @use_pm_opp: Indicates whether OPP based scaling is used or not
* @req_abort_count: number of times ufshcd_abort() has been called
* @lanes_per_direction: number of lanes per data direction between the UFS
* controller and the UFS device.
@@ -1015,6 +1018,7 @@ struct ufs_hba {
bool auto_bkops_enabled;
struct ufs_vreg_info vreg_info;
struct list_head clk_list_head;
+ bool use_pm_opp;

/* Number of requests aborts */
int req_abort_count;
--
2.25.1

2023-10-03 11:13:37

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 2/6] PM / devfreq: Switch to dev_pm_opp_find_freq_{ceil/floor}_indexed() APIs

Some devfreq consumers like UFS driver need to work with multiple clocks
through the OPP framework. For this reason, OPP framework exposes the
_indexed() APIs for finding the floor/ceil of the supplied frequency of
the indexed clock. So let's use them in the devfreq driver.

Currently, the clock index of 0 is used which works fine for multiple as
well as single clock.

Acked-by: Chanwoo Choi <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/devfreq/devfreq.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 474d81831ad3..b3a68d5833bd 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -88,7 +88,7 @@ static unsigned long find_available_min_freq(struct devfreq *devfreq)
struct dev_pm_opp *opp;
unsigned long min_freq = 0;

- opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &min_freq);
+ opp = dev_pm_opp_find_freq_ceil_indexed(devfreq->dev.parent, &min_freq, 0);
if (IS_ERR(opp))
min_freq = 0;
else
@@ -102,7 +102,7 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
struct dev_pm_opp *opp;
unsigned long max_freq = ULONG_MAX;

- opp = dev_pm_opp_find_freq_floor(devfreq->dev.parent, &max_freq);
+ opp = dev_pm_opp_find_freq_floor_indexed(devfreq->dev.parent, &max_freq, 0);
if (IS_ERR(opp))
max_freq = 0;
else
@@ -196,7 +196,7 @@ static int set_freq_table(struct devfreq *devfreq)
return -ENOMEM;

for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
- opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
+ opp = dev_pm_opp_find_freq_ceil_indexed(devfreq->dev.parent, &freq, 0);
if (IS_ERR(opp)) {
devm_kfree(devfreq->dev.parent, devfreq->freq_table);
return PTR_ERR(opp);
@@ -2036,18 +2036,18 @@ struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,

if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
/* The freq is an upper bound. opp should be lower */
- opp = dev_pm_opp_find_freq_floor(dev, freq);
+ opp = dev_pm_opp_find_freq_floor_indexed(dev, freq, 0);

/* If not available, use the closest opp */
if (opp == ERR_PTR(-ERANGE))
- opp = dev_pm_opp_find_freq_ceil(dev, freq);
+ opp = dev_pm_opp_find_freq_ceil_indexed(dev, freq, 0);
} else {
/* The freq is an lower bound. opp should be higher */
- opp = dev_pm_opp_find_freq_ceil(dev, freq);
+ opp = dev_pm_opp_find_freq_ceil_indexed(dev, freq, 0);

/* If not available, use the closest opp */
if (opp == ERR_PTR(-ERANGE))
- opp = dev_pm_opp_find_freq_floor(dev, freq);
+ opp = dev_pm_opp_find_freq_floor_indexed(dev, freq, 0);
}

return opp;
--
2.25.1

2023-10-03 11:13:53

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 4/6] scsi: ufs: host: Add support for parsing OPP

OPP framework can be used to scale the clocks along with other entities
such as regulators, performance state etc... So let's add support for
parsing OPP from devicetree. OPP support in devicetree is added through
the "operating-points-v2" property which accepts the OPP table defining
clock frequency, regulator voltage, power domain performance state etc...

Since the UFS controller requires multiple clocks to be controlled for
proper working, devm_pm_opp_set_config() has been used which supports
scaling multiple clocks through custom ufshcd_opp_config_clks() callback.

It should be noted that the OPP support is not compatible with the old
"freq-table-hz" property. So only one can be used at a time even though
the UFS core supports both.

Co-developed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
drivers/ufs/core/ufshcd.c | 35 ++++++++++++++
drivers/ufs/host/ufshcd-pltfrm.c | 78 ++++++++++++++++++++++++++++++++
include/ufs/ufshcd.h | 3 ++
3 files changed, 116 insertions(+)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 55de0ff1f01f..ccd7fcd18355 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1064,6 +1064,41 @@ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up)
return ret;
}

+int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table,
+ struct dev_pm_opp *opp, void *data,
+ bool scaling_down)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct list_head *head = &hba->clk_list_head;
+ struct ufs_clk_info *clki;
+ unsigned long freq;
+ u8 idx = 0;
+ int ret;
+
+ list_for_each_entry(clki, head, list) {
+ if (!IS_ERR_OR_NULL(clki->clk)) {
+ freq = dev_pm_opp_get_freq_indexed(opp, idx++);
+
+ /* Do not set rate for clocks having frequency as 0 */
+ if (!freq)
+ continue;
+
+ ret = clk_set_rate(clki->clk, freq);
+ if (ret) {
+ dev_err(dev, "%s: %s clk set rate(%ldHz) failed, %d\n",
+ __func__, clki->name, freq, ret);
+ return ret;
+ }
+
+ trace_ufshcd_clk_scaling(dev_name(dev),
+ (scaling_down ? "scaled down" : "scaled up"),
+ clki->name, hba->clk_scaling.target_freq, freq);
+ }
+ }
+
+ return 0;
+}
+
static int ufshcd_opp_set_rate(struct ufs_hba *hba, unsigned long freq)
{
struct dev_pm_opp *opp;
diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c
index 797a4dfe45d9..ffd786991244 100644
--- a/drivers/ufs/host/ufshcd-pltfrm.c
+++ b/drivers/ufs/host/ufshcd-pltfrm.c
@@ -10,6 +10,7 @@

#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>

@@ -207,6 +208,77 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
}
}

+static int ufshcd_parse_operating_points(struct ufs_hba *hba)
+{
+ struct device *dev = hba->dev;
+ struct device_node *np = dev->of_node;
+ struct dev_pm_opp_config config = {};
+ struct ufs_clk_info *clki;
+ const char **clk_names;
+ int cnt, i, ret;
+
+ if (!of_find_property(np, "operating-points-v2", NULL))
+ return 0;
+
+ if (of_find_property(np, "freq-table-hz", NULL)) {
+ dev_err(dev, "%s: operating-points and freq-table-hz are incompatible\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ cnt = of_property_count_strings(np, "clock-names");
+ if (cnt <= 0) {
+ dev_err(dev, "%s: Missing clock-names\n", __func__);
+ return -ENODEV;
+ }
+
+ /* OPP expects clk_names to be NULL terminated */
+ clk_names = devm_kcalloc(dev, cnt + 1, sizeof(*clk_names), GFP_KERNEL);
+ if (!clk_names)
+ return -ENOMEM;
+
+ /*
+ * We still need to get reference to all clocks as the UFS core uses
+ * them separately.
+ */
+ for (i = 0; i < cnt; i++) {
+ ret = of_property_read_string_index(np, "clock-names", i,
+ &clk_names[i]);
+ if (ret)
+ return ret;
+
+ clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
+ if (!clki)
+ return -ENOMEM;
+
+ clki->name = devm_kstrdup(dev, clk_names[i], GFP_KERNEL);
+ if (!clki->name)
+ return -ENOMEM;
+
+ if (!strcmp(clk_names[i], "ref_clk"))
+ clki->keep_link_active = true;
+
+ list_add_tail(&clki->list, &hba->clk_list_head);
+ }
+
+ config.clk_names = clk_names,
+ config.config_clks = ufshcd_opp_config_clks;
+
+ ret = devm_pm_opp_set_config(dev, &config);
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_of_add_table(dev);
+ if (ret) {
+ dev_err(dev, "Failed to add OPP table: %d\n", ret);
+ return ret;
+ }
+
+ hba->use_pm_opp = true;
+
+ return 0;
+}
+
/**
* ufshcd_get_pwr_dev_param - get finally agreed attributes for
* power mode change
@@ -373,6 +445,12 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,

ufshcd_init_lanes_per_dir(hba);

+ err = ufshcd_parse_operating_points(hba);
+ if (err) {
+ dev_err(dev, "%s: OPP parse failed %d\n", __func__, err);
+ goto dealloc_host;
+ }
+
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
dev_err_probe(dev, err, "Initialization failed with error %d\n",
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index c181cc5c523b..8491b690e3ef 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -1257,6 +1257,9 @@ void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba);
void ufshcd_mcq_enable_esi(struct ufs_hba *hba);
void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg);

+int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table,
+ struct dev_pm_opp *opp, void *data,
+ bool scaling_down);
/**
* ufshcd_set_variant - set variant specific data to the hba
* @hba: per adapter instance
--
2.25.1

2023-10-03 11:14:00

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 1/6] dt-bindings: ufs: common: add OPP table

From: Krzysztof Kozlowski <[email protected]>

Except scaling UFS and bus clocks, it's necessary to scale also the
voltages of regulators or power domain performance state levels. Adding
Operating Performance Points table allows to adjust power domain
performance state, depending on the UFS clock speed.

OPPv2 deprecates previous property limited to clock scaling:
freq-table-hz.

Signed-off-by: Krzysztof Kozlowski <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
.../devicetree/bindings/ufs/ufs-common.yaml | 36 ++++++++++++++++---
1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/ufs/ufs-common.yaml b/Documentation/devicetree/bindings/ufs/ufs-common.yaml
index bbaee4f5f7b2..d7d2c8a136bb 100644
--- a/Documentation/devicetree/bindings/ufs/ufs-common.yaml
+++ b/Documentation/devicetree/bindings/ufs/ufs-common.yaml
@@ -20,11 +20,24 @@ properties:
items:
- description: Minimum frequency for given clock in Hz
- description: Maximum frequency for given clock in Hz
+ deprecated: true
description: |
+ Preferred is operating-points-v2.
+
Array of <min max> operating frequencies in Hz stored in the same order
- as the clocks property. If this property is not 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.
+ as the clocks property. If either this property or operating-points-v2 is
+ not 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.
+
+ operating-points-v2:
+ description:
+ Preferred over freq-table-hz.
+ If present, each OPP must contain array of frequencies stored in the same
+ order for each clock. If clock frequency in the array is "0" then it is
+ assumed that the frequency is set by the parent clock or a fixed rate
+ clock source.
+
+ opp-table: true

interrupts:
maxItems: 1
@@ -74,9 +87,24 @@ properties:
Specifies max. load that can be drawn from VCCQ2 supply.

dependencies:
- freq-table-hz: [ clocks ]
+ freq-table-hz: [ 'clocks' ]
+ operating-points-v2: [ 'clocks', 'clock-names' ]

required:
- interrupts

+allOf:
+ - if:
+ required:
+ - freq-table-hz
+ then:
+ properties:
+ operating-points-v2: false
+ - if:
+ required:
+ - operating-points-v2
+ then:
+ properties:
+ freq-table-hz: false
+
additionalProperties: true
--
2.25.1

2023-10-03 11:14:20

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 5/6] arm64: dts: qcom: sdm845: Add OPP table support to UFSHC

From: Krzysztof Kozlowski <[email protected]>

UFS host controller, when scaling gears, should choose appropriate
performance state of RPMh power domain controller along with clock
frequency. So let's add the OPP table support to specify both clock
frequency and RPMh performance states replacing the old "freq-table-hz"
property.

Signed-off-by: Krzysztof Kozlowski <[email protected]>
[mani: Splitted pd change and used rpmhpd_opp_low_svs]
Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
arch/arm64/boot/dts/qcom/sdm845.dtsi | 42 +++++++++++++++++++++-------
1 file changed, 32 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 055ca80c0075..2ea6eb44953e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -2605,22 +2605,44 @@ ufs_mem_hc: ufshc@1d84000 {
<&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>,
<&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
- freq-table-hz =
- <50000000 200000000>,
- <0 0>,
- <0 0>,
- <37500000 150000000>,
- <0 0>,
- <0 0>,
- <0 0>,
- <0 0>,
- <75000000 300000000>;
+
+ operating-points-v2 = <&ufs_opp_table>;

interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mem_noc SLAVE_EBI1 0>,
<&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
interconnect-names = "ufs-ddr", "cpu-ufs";

status = "disabled";
+
+ ufs_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-50000000 {
+ opp-hz = /bits/ 64 <50000000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <37500000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <75000000>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <150000000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <300000000>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
};

ufs_mem_phy: phy@1d87000 {
--
2.25.1

2023-10-03 11:15:07

by Manivannan Sadhasivam

[permalink] [raw]
Subject: [PATCH v4 6/6] arm64: dts: qcom: sm8250: Add OPP table support to UFSHC

UFS host controller, when scaling gears, should choose appropriate
performance state of RPMh power domain controller along with clock
frequency. So let's add the OPP table support to specify both clock
frequency and RPMh performance states replacing the old "freq-table-hz"
property.

Signed-off-by: Manivannan Sadhasivam <[email protected]>
---
arch/arm64/boot/dts/qcom/sm8250.dtsi | 39 +++++++++++++++++++++-------
1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
index a4e58ad731c3..33abd84aae53 100644
--- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
+++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
@@ -2198,21 +2198,42 @@ ufs_mem_hc: ufshc@1d84000 {
<&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
<&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
- freq-table-hz =
- <37500000 300000000>,
- <0 0>,
- <0 0>,
- <37500000 300000000>,
- <0 0>,
- <0 0>,
- <0 0>,
- <0 0>;
+
+ operating-points-v2 = <&ufs_opp_table>;

interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI_CH0 0>,
<&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
interconnect-names = "ufs-ddr", "cpu-ufs";

status = "disabled";
+
+ ufs_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-37500000 {
+ opp-hz = /bits/ 64 <37500000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <37500000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>;
+ required-opps = <&rpmhpd_opp_low_svs>;
+ };
+
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <300000000>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>,
+ /bits/ 64 <0>;
+ required-opps = <&rpmhpd_opp_nom>;
+ };
+ };
};

ufs_mem_phy: phy@1d87000 {
--
2.25.1

2023-10-03 12:16:50

by Rob Herring

[permalink] [raw]
Subject: Re: [PATCH v4 1/6] dt-bindings: ufs: common: add OPP table


On Tue, 03 Oct 2023 16:42:27 +0530, Manivannan Sadhasivam wrote:
> From: Krzysztof Kozlowski <[email protected]>
>
> Except scaling UFS and bus clocks, it's necessary to scale also the
> voltages of regulators or power domain performance state levels. Adding
> Operating Performance Points table allows to adjust power domain
> performance state, depending on the UFS clock speed.
>
> OPPv2 deprecates previous property limited to clock scaling:
> freq-table-hz.
>
> Signed-off-by: Krzysztof Kozlowski <[email protected]>
> Reviewed-by: Rob Herring <[email protected]>
> Signed-off-by: Manivannan Sadhasivam <[email protected]>
> ---
> .../devicetree/bindings/ufs/ufs-common.yaml | 36 ++++++++++++++++---
> 1 file changed, 32 insertions(+), 4 deletions(-)
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/ufs/ufs-common.yaml:90:20: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/ufs/ufs-common.yaml:91:26: [error] string value is redundantly quoted with any quotes (quoted-strings)
./Documentation/devicetree/bindings/ufs/ufs-common.yaml:91:36: [error] string value is redundantly quoted with any quotes (quoted-strings)

dtschema/dtc warnings/errors:

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.

2023-10-03 12:45:36

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v4 1/6] dt-bindings: ufs: common: add OPP table

On Tue, Oct 03, 2023 at 07:16:35AM -0500, Rob Herring wrote:
>
> On Tue, 03 Oct 2023 16:42:27 +0530, Manivannan Sadhasivam wrote:
> > From: Krzysztof Kozlowski <[email protected]>
> >
> > Except scaling UFS and bus clocks, it's necessary to scale also the
> > voltages of regulators or power domain performance state levels. Adding
> > Operating Performance Points table allows to adjust power domain
> > performance state, depending on the UFS clock speed.
> >
> > OPPv2 deprecates previous property limited to clock scaling:
> > freq-table-hz.
> >
> > Signed-off-by: Krzysztof Kozlowski <[email protected]>
> > Reviewed-by: Rob Herring <[email protected]>
> > Signed-off-by: Manivannan Sadhasivam <[email protected]>
> > ---
> > .../devicetree/bindings/ufs/ufs-common.yaml | 36 ++++++++++++++++---
> > 1 file changed, 32 insertions(+), 4 deletions(-)
> >
>
> My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
> on your patch (DT_CHECKER_FLAGS is new in v5.13):
>
> yamllint warnings/errors:
> ./Documentation/devicetree/bindings/ufs/ufs-common.yaml:90:20: [error] string value is redundantly quoted with any quotes (quoted-strings)
> ./Documentation/devicetree/bindings/ufs/ufs-common.yaml:91:26: [error] string value is redundantly quoted with any quotes (quoted-strings)
> ./Documentation/devicetree/bindings/ufs/ufs-common.yaml:91:36: [error] string value is redundantly quoted with any quotes (quoted-strings)
>

Oops! I ran the check on wrong binding file :/ Will fix it in next version.

- Mani

> dtschema/dtc warnings/errors:
>
> doc reference errors (make refcheckdocs):
>
> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]
>
> The base for the series is generally the latest rc1. A different dependency
> should be noted in *this* patch.
>
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
>
> pip3 install dtschema --upgrade
>
> Please check and re-submit after running the above command yourself. Note
> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> your schema. However, it must be unset to test all examples with your schema.
>

--
மணிவண்ணன் சதாசிவம்

2023-10-03 15:26:36

by Dmitry Baryshkov

[permalink] [raw]
Subject: Re: [PATCH v4 6/6] arm64: dts: qcom: sm8250: Add OPP table support to UFSHC

On Tue, 3 Oct 2023 at 14:16, Manivannan Sadhasivam
<[email protected]> wrote:
>
> UFS host controller, when scaling gears, should choose appropriate
> performance state of RPMh power domain controller along with clock
> frequency. So let's add the OPP table support to specify both clock
> frequency and RPMh performance states replacing the old "freq-table-hz"
> property.
>
> Signed-off-by: Manivannan Sadhasivam <[email protected]>
> ---
> arch/arm64/boot/dts/qcom/sm8250.dtsi | 39 +++++++++++++++++++++-------
> 1 file changed, 30 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
> index a4e58ad731c3..33abd84aae53 100644
> --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
> @@ -2198,21 +2198,42 @@ ufs_mem_hc: ufshc@1d84000 {
> <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
> <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
> <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
> - freq-table-hz =
> - <37500000 300000000>,
> - <0 0>,
> - <0 0>,
> - <37500000 300000000>,
> - <0 0>,
> - <0 0>,
> - <0 0>,
> - <0 0>;
> +
> + operating-points-v2 = <&ufs_opp_table>;
>
> interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI_CH0 0>,
> <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
> interconnect-names = "ufs-ddr", "cpu-ufs";
>
> status = "disabled";
> +
> + ufs_opp_table: opp-table {
> + compatible = "operating-points-v2";
> +
> + opp-37500000 {
> + opp-hz = /bits/ 64 <37500000>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>,
> + /bits/ 64 <37500000>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>;

I must say I still consider this to be uglier than hard coding clock
names in the driver.

> + required-opps = <&rpmhpd_opp_low_svs>;
> + };
> +
> + opp-300000000 {
> + opp-hz = /bits/ 64 <300000000>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>,
> + /bits/ 64 <300000000>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>,
> + /bits/ 64 <0>;
> + required-opps = <&rpmhpd_opp_nom>;
> + };
> + };
> };
>
> ufs_mem_phy: phy@1d87000 {
> --
> 2.25.1
>


--
With best wishes
Dmitry

2023-10-04 06:26:28

by Manivannan Sadhasivam

[permalink] [raw]
Subject: Re: [PATCH v4 6/6] arm64: dts: qcom: sm8250: Add OPP table support to UFSHC

On Tue, Oct 03, 2023 at 06:25:22PM +0300, Dmitry Baryshkov wrote:
> On Tue, 3 Oct 2023 at 14:16, Manivannan Sadhasivam
> <[email protected]> wrote:
> >
> > UFS host controller, when scaling gears, should choose appropriate
> > performance state of RPMh power domain controller along with clock
> > frequency. So let's add the OPP table support to specify both clock
> > frequency and RPMh performance states replacing the old "freq-table-hz"
> > property.
> >
> > Signed-off-by: Manivannan Sadhasivam <[email protected]>
> > ---
> > arch/arm64/boot/dts/qcom/sm8250.dtsi | 39 +++++++++++++++++++++-------
> > 1 file changed, 30 insertions(+), 9 deletions(-)
> >
> > diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi
> > index a4e58ad731c3..33abd84aae53 100644
> > --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi
> > @@ -2198,21 +2198,42 @@ ufs_mem_hc: ufshc@1d84000 {
> > <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
> > <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
> > <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
> > - freq-table-hz =
> > - <37500000 300000000>,
> > - <0 0>,
> > - <0 0>,
> > - <37500000 300000000>,
> > - <0 0>,
> > - <0 0>,
> > - <0 0>,
> > - <0 0>;
> > +
> > + operating-points-v2 = <&ufs_opp_table>;
> >
> > interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI_CH0 0>,
> > <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
> > interconnect-names = "ufs-ddr", "cpu-ufs";
> >
> > status = "disabled";
> > +
> > + ufs_opp_table: opp-table {
> > + compatible = "operating-points-v2";
> > +
> > + opp-37500000 {
> > + opp-hz = /bits/ 64 <37500000>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <37500000>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>;
>
> I must say I still consider this to be uglier than hard coding clock
> names in the driver.
>

It is all about choosing the less uglier one... First of all, it is not a good
practice to hardcode clk names in the driver as the driver has to trust what is
being supplied from DT. Also, the OPP support is added in the generic
"ufshcd-platfrm" driver. Now for getting the clk names, I need to introduce a
method to pass the names from the vendor drivers. There are already many such
methods going between these two drivers making it messy and adding one more
would only add up the worse.

So I'd like to stick to this approach.

- Mani

> > + required-opps = <&rpmhpd_opp_low_svs>;
> > + };
> > +
> > + opp-300000000 {
> > + opp-hz = /bits/ 64 <300000000>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <300000000>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>,
> > + /bits/ 64 <0>;
> > + required-opps = <&rpmhpd_opp_nom>;
> > + };
> > + };
> > };
> >
> > ufs_mem_phy: phy@1d87000 {
> > --
> > 2.25.1
> >
>
>
> --
> With best wishes
> Dmitry

--
மணிவண்ணன் சதாசிவம்

2023-10-06 15:25:15

by Chanwoo Choi

[permalink] [raw]
Subject: Re: [PATCH v4 2/6] PM / devfreq: Switch to dev_pm_opp_find_freq_{ceil/floor}_indexed() APIs

On 23. 10. 3. 20:12, Manivannan Sadhasivam wrote:
> Some devfreq consumers like UFS driver need to work with multiple clocks
> through the OPP framework. For this reason, OPP framework exposes the
> _indexed() APIs for finding the floor/ceil of the supplied frequency of
> the indexed clock. So let's use them in the devfreq driver.
>
> Currently, the clock index of 0 is used which works fine for multiple as
> well as single clock.
>
> Acked-by: Chanwoo Choi <[email protected]>
> Signed-off-by: Manivannan Sadhasivam <[email protected]>
> ---
> drivers/devfreq/devfreq.c | 14 +++++++-------
> 1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 474d81831ad3..b3a68d5833bd 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -88,7 +88,7 @@ static unsigned long find_available_min_freq(struct devfreq *devfreq)
> struct dev_pm_opp *opp;
> unsigned long min_freq = 0;
>
> - opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &min_freq);
> + opp = dev_pm_opp_find_freq_ceil_indexed(devfreq->dev.parent, &min_freq, 0);
> if (IS_ERR(opp))
> min_freq = 0;
> else
> @@ -102,7 +102,7 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
> struct dev_pm_opp *opp;
> unsigned long max_freq = ULONG_MAX;
>
> - opp = dev_pm_opp_find_freq_floor(devfreq->dev.parent, &max_freq);
> + opp = dev_pm_opp_find_freq_floor_indexed(devfreq->dev.parent, &max_freq, 0);
> if (IS_ERR(opp))
> max_freq = 0;
> else
> @@ -196,7 +196,7 @@ static int set_freq_table(struct devfreq *devfreq)
> return -ENOMEM;
>
> for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
> - opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
> + opp = dev_pm_opp_find_freq_ceil_indexed(devfreq->dev.parent, &freq, 0);
> if (IS_ERR(opp)) {
> devm_kfree(devfreq->dev.parent, devfreq->freq_table);
> return PTR_ERR(opp);
> @@ -2036,18 +2036,18 @@ struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
>
> if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
> /* The freq is an upper bound. opp should be lower */
> - opp = dev_pm_opp_find_freq_floor(dev, freq);
> + opp = dev_pm_opp_find_freq_floor_indexed(dev, freq, 0);
>
> /* If not available, use the closest opp */
> if (opp == ERR_PTR(-ERANGE))
> - opp = dev_pm_opp_find_freq_ceil(dev, freq);
> + opp = dev_pm_opp_find_freq_ceil_indexed(dev, freq, 0);
> } else {
> /* The freq is an lower bound. opp should be higher */
> - opp = dev_pm_opp_find_freq_ceil(dev, freq);
> + opp = dev_pm_opp_find_freq_ceil_indexed(dev, freq, 0);
>
> /* If not available, use the closest opp */
> if (opp == ERR_PTR(-ERANGE))
> - opp = dev_pm_opp_find_freq_floor(dev, freq);
> + opp = dev_pm_opp_find_freq_floor_indexed(dev, freq, 0);
> }
>
> return opp;

The related OPP patch was already merge. So that applied it. Thanks.

--
Best Regards,
Samsung Electronics
Chanwoo Choi