From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> To: Andy Gross <agross@kernel.org>, Bjorn Andersson <bjorn.andersson@linaro.org>, Michael Turquette <mturquette@baylibre.com>, Stephen Boyd <sboyd@kernel.org>, Rob Herring <robh+dt@kernel.org>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Viresh Kumar <vireshk@kernel.org>, Nishanth Menon <nm@ti.com>, Alim Akhtar <alim.akhtar@samsung.com>, Avri Altman <avri.altman@wdc.com>, "James E.J. Bottomley" <jejb@linux.ibm.com>, "Martin K. Petersen" <martin.petersen@oracle.com>, "Rafael J. Wysocki" <rafael@kernel.org>, Taniya Das <tdas@codeaurora.org>, linux-arm-msm@vger.kernel.org, linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, linux-scsi@vger.kernel.org Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Subject: [PATCH v3 6/7] PM: opp: parse multiple frequencies in each OPP Date: Fri, 13 May 2022 08:13:46 +0200 [thread overview] Message-ID: <20220513061347.46480-7-krzysztof.kozlowski@linaro.org> (raw) In-Reply-To: <20220513061347.46480-1-krzysztof.kozlowski@linaro.org> Devices might need to control several clocks when scaling the frequency and voltage, with each clock having different frequency. Parse the 'opp-hz' Devicetree property as an array and store all frequencies for the custom set_opp in a new field 'rates'. Since the PM OPP framework operates on only one clock (multiple clocks are for custom set_opp helpers), these frequencies are actually not used internally and still the core relies on the original field 'rate'. All other PM OPP functions, like finding floor/ceil PM OPPs, operate still on first rate given in the 'opp-hz' frequency. Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> --- Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> --- drivers/opp/core.c | 20 +++++++++++++++--- drivers/opp/of.c | 47 ++++++++++++++++++++++++++++++++++++++++++ drivers/opp/opp.h | 2 ++ include/linux/pm_opp.h | 3 +++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index aac3c6d89ae0..563e962c3411 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1033,7 +1033,9 @@ static int _set_opp_custom(const struct opp_table *opp_table, data->clks = opp_table->clks; data->dev = dev; data->old_opp.rate = old_opp->rate; + data->old_opp.rates = old_opp->rates; data->new_opp.rate = freq; + data->new_opp.rates = opp->rates; return opp_table->set_opp(data); } @@ -1307,6 +1309,11 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) __func__, freq, ret); goto put_opp_table; } + /* + * opp->rates are used for scaling clocks, so be sure accurate + * 'freq' is used, instead what was defined via e.g. Devicetree. + */ + opp->rates[0] = freq; } ret = _set_opp(dev, opp_table, opp, freq); @@ -1761,23 +1768,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic); struct dev_pm_opp *_opp_allocate(struct opp_table *table) { struct dev_pm_opp *opp; - int supply_count, supply_size, icc_size; + int rate_count, rate_size, supply_count, supply_size, icc_size; /* Allocate space for at least one supply */ supply_count = table->regulator_count > 0 ? table->regulator_count : 1; supply_size = sizeof(*opp->supplies) * supply_count; + /* Allocate space for at least one rate */ + rate_count = table->clk_count > 0 ? table->clk_count : 1; + rate_size = sizeof(*opp->rates) * rate_count; icc_size = sizeof(*opp->bandwidth) * table->path_count; /* allocate new OPP node and supplies structures */ - opp = kzalloc(sizeof(*opp) + supply_size + icc_size, GFP_KERNEL); + opp = kzalloc(sizeof(*opp) + rate_size + supply_size + icc_size, + GFP_KERNEL); if (!opp) return NULL; /* Put the supplies at the end of the OPP structure as an empty array */ opp->supplies = (struct dev_pm_opp_supply *)(opp + 1); + opp->rates = (unsigned long *)(opp->supplies + supply_count); if (icc_size) - opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->supplies + supply_count); + opp->bandwidth = (struct dev_pm_opp_icc_bw *)(opp->rates + rate_count); + INIT_LIST_HEAD(&opp->node); return opp; @@ -1957,6 +1970,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev, /* populate the opp table */ new_opp->rate = freq; + new_opp->rates[0] = freq; tol = u_volt * opp_table->voltage_tolerance_v1 / 100; new_opp->supplies[0].u_volt = u_volt; new_opp->supplies[0].u_volt_min = u_volt - tol; diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 30394929d700..b226d2c7a84b 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -767,6 +767,46 @@ void dev_pm_opp_of_remove_table(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); +static int _read_clocks(struct dev_pm_opp *opp, struct opp_table *opp_table, + struct device_node *np) +{ + int i, count, ret; + u64 *freq; + + count = of_property_count_u64_elems(np, "opp-hz"); + if (count < 0) { + pr_err("%s: Invalid %s property (%d)\n", + __func__, of_node_full_name(np), count); + return count; + } + + if (count != opp_table->clk_count) { + pr_err("%s: number of rates %d does not match number of clocks %d in %pOF\n", + __func__, count, opp_table->clk_count, np); + return -EINVAL; + } + + freq = kmalloc_array(count, sizeof(*freq), GFP_KERNEL); + if (!freq) + return -ENOMEM; + + ret = of_property_read_u64_array(np, "opp-hz", freq, count); + if (ret) { + pr_err("%s: error parsing %s: %d\n", __func__, + of_node_full_name(np), ret); + ret = -EINVAL; + goto free_freq; + } + + for (i = 0; i < count; i++) + opp->rates[i] = freq[i]; + +free_freq: + kfree(freq); + + return ret; +} + static int _read_bw(struct dev_pm_opp *new_opp, struct opp_table *table, struct device_node *np, bool peak) { @@ -827,6 +867,13 @@ static int _read_opp_key(struct dev_pm_opp *new_opp, struct opp_table *table, } *rate_not_available = !!ret; + if (!ret) { + ret = _read_clocks(new_opp, table, np); + /* The properties were found but we failed to parse them */ + if (ret && ret != -ENODEV) + return ret; + } + /* * Bandwidth consists of peak and average (optional) values: * opp-peak-kBps = <path1_value path2_value>; diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 59aac08baf82..217d4376af9b 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -61,6 +61,7 @@ extern struct list_head opp_tables, lazy_opp_tables; * @rate: Frequency in hertz * @level: Performance level * @supplies: Power supplies voltage/current values + * @rates: Frequency rates for the clocks (equal to @rate for one clock) * @bandwidth: Interconnect bandwidth values * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's * frequency from any other OPP's frequency. @@ -85,6 +86,7 @@ struct dev_pm_opp { unsigned int level; struct dev_pm_opp_supply *supplies; + unsigned long *rates; struct dev_pm_opp_icc_bw *bandwidth; unsigned long clock_latency_ns; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 5f17f10fcc3f..5fd3895af605 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -60,12 +60,15 @@ struct dev_pm_opp_icc_bw { /** * struct dev_pm_opp_info - OPP freq/voltage/current values * @rate: Target clk rate in hz + * @rates: Array of clock frequencies for all clocks (equal to @rate for + * one clock) * @supplies: Array of voltage/current values for all power supplies * * This structure stores the freq/voltage/current values for a single OPP. */ struct dev_pm_opp_info { unsigned long rate; + unsigned long *rates; struct dev_pm_opp_supply *supplies; }; -- 2.32.0
next prev parent reply other threads:[~2022-05-13 6:15 UTC|newest] Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-05-13 6:13 [PATCH v3 0/7] ufs: set power domain performance state when scaling gears Krzysztof Kozlowski 2022-05-13 6:13 ` [PATCH v3 1/7] dt-bindings: clock: qcom,gcc-sdm845: add parent power domain Krzysztof Kozlowski 2022-05-13 15:51 ` Manivannan Sadhasivam 2022-06-28 20:19 ` (subset) " Bjorn Andersson 2022-05-13 6:13 ` [PATCH v3 2/7] dt-bindings: opp: accept array of frequencies Krzysztof Kozlowski 2022-05-13 17:22 ` Manivannan Sadhasivam 2022-06-30 9:55 ` Viresh Kumar 2022-05-13 6:13 ` [PATCH v3 3/7] dt-bindings: ufs: common: add OPP table Krzysztof Kozlowski 2022-05-13 17:40 ` Manivannan Sadhasivam 2022-05-13 18:32 ` Manivannan Sadhasivam 2022-05-13 6:13 ` [PATCH v3 4/7] arm64: dts: qcom: sdm845: control RPMHPD performance states with UFS Krzysztof Kozlowski 2022-05-25 7:16 ` Viresh Kumar 2022-05-30 7:42 ` Krzysztof Kozlowski 2022-05-13 6:13 ` [PATCH v3 5/7] PM: opp: allow control of multiple clocks Krzysztof Kozlowski 2022-05-13 6:13 ` Krzysztof Kozlowski [this message] 2022-05-13 6:13 ` [PATCH v3 7/7] ufs: use PM OPP when scaling gears Krzysztof Kozlowski 2022-05-13 18:25 ` Manivannan Sadhasivam 2022-05-16 6:10 ` Krzysztof Kozlowski
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220513061347.46480-7-krzysztof.kozlowski@linaro.org \ --to=krzysztof.kozlowski@linaro.org \ --cc=agross@kernel.org \ --cc=alim.akhtar@samsung.com \ --cc=avri.altman@wdc.com \ --cc=bjorn.andersson@linaro.org \ --cc=devicetree@vger.kernel.org \ --cc=jejb@linux.ibm.com \ --cc=krzysztof.kozlowski+dt@linaro.org \ --cc=linux-arm-msm@vger.kernel.org \ --cc=linux-clk@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-pm@vger.kernel.org \ --cc=linux-scsi@vger.kernel.org \ --cc=manivannan.sadhasivam@linaro.org \ --cc=martin.petersen@oracle.com \ --cc=mturquette@baylibre.com \ --cc=nm@ti.com \ --cc=rafael@kernel.org \ --cc=robh+dt@kernel.org \ --cc=sboyd@kernel.org \ --cc=tdas@codeaurora.org \ --cc=vireshk@kernel.org \ --subject='Re: [PATCH v3 6/7] PM: opp: parse multiple frequencies in each OPP' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.