From: Matthias Kaehlcke <mka@chromium.org>
To: Taniya Das <tdas@codeaurora.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>,
Viresh Kumar <viresh.kumar@linaro.org>,
linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org,
Stephen Boyd <sboyd@kernel.org>,
Rajendra Nayak <rnayak@codeaurora.org>,
devicetree@vger.kernel.org, robh@kernel.org,
skannan@codeaurora.org, linux-arm-msm@vger.kernel.org,
amit.kucheria@linaro.org, evgreen@google.com
Subject: Re: [PATCH v1] cpufreq: qcom: Read voltage LUT and populate OPP
Date: Fri, 21 Dec 2018 12:57:52 -0800 [thread overview]
Message-ID: <20181221205752.GD261387@google.com> (raw)
In-Reply-To: <1545415608-15163-1-git-send-email-tdas@codeaurora.org>
Hi Taniya,
On Fri, Dec 21, 2018 at 11:36:48PM +0530, Taniya Das wrote:
> Add support to read the voltage look up table and populate OPP for all
> corresponding CPUS.
>
> Signed-off-by: Taniya Das <tdas@codeaurora.org>
> ---
> drivers/cpufreq/qcom-cpufreq-hw.c | 32 ++++++++++++++++++++++++++++++--
> 1 file changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
> index d83939a..7559b87 100644
> --- a/drivers/cpufreq/qcom-cpufreq-hw.c
> +++ b/drivers/cpufreq/qcom-cpufreq-hw.c
> @@ -10,18 +10,21 @@
> #include <linux/module.h>
> #include <linux/of_address.h>
> #include <linux/of_platform.h>
> +#include <linux/pm_opp.h>
> #include <linux/slab.h>
>
> #define LUT_MAX_ENTRIES 40U
> #define LUT_SRC GENMASK(31, 30)
> #define LUT_L_VAL GENMASK(7, 0)
> #define LUT_CORE_COUNT GENMASK(18, 16)
> +#define LUT_VOLT GENMASK(11, 0)
> #define LUT_ROW_SIZE 32
> #define CLK_HW_DIV 2
>
> /* Register offsets */
> #define REG_ENABLE 0x0
> -#define REG_LUT_TABLE 0x110
> +#define REG_FREQ_LUT_TABLE 0x110
> +#define REG_VOLT_LUT_TABLE 0x114
The new names suggest that there is a LUT for frequencies and another
one for voltages. I don't have access to hardware documentation, but
from the code and offsets in this driver it seems there is a single
table at offset 0x110, with a 'row' of 32 bytes per OPP. Within this
row the frequency (and other values) is located at offset 0, the
voltage at offset 4.
I'd suggest to keep REG_LUT_TABLE, add a define LUT_OFFSET_VOLTAGE/MV
(or similar) and adjust the math in qcom_cpufreq_hw_read_lut() to use
REG_LUT_TABLE as base offset.
> #define REG_PERF_STATE 0x920
>
> static unsigned long cpu_hw_rate, xo_rate;
> @@ -75,19 +78,26 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
> void __iomem *base)
> {
> u32 data, src, lval, i, core_count, prev_cc = 0, prev_freq = 0, freq;
> + u32 volt;
> unsigned int max_cores = cpumask_weight(policy->cpus);
> struct cpufreq_frequency_table *table;
> + unsigned long cpu_r;
nit: why 'cpu_r' and not just 'cpu'?
(if it is needed at all, see my comment below)
>
> table = kcalloc(LUT_MAX_ENTRIES + 1, sizeof(*table), GFP_KERNEL);
> if (!table)
> return -ENOMEM;
>
> for (i = 0; i < LUT_MAX_ENTRIES; i++) {
> - data = readl_relaxed(base + REG_LUT_TABLE + i * LUT_ROW_SIZE);
> + data = readl_relaxed(base + REG_FREQ_LUT_TABLE +
> + i * LUT_ROW_SIZE);
> src = FIELD_GET(LUT_SRC, data);
> lval = FIELD_GET(LUT_L_VAL, data);
> core_count = FIELD_GET(LUT_CORE_COUNT, data);
>
> + data = readl_relaxed(base + REG_VOLT_LUT_TABLE +
> + i * LUT_ROW_SIZE);
> + volt = FIELD_GET(LUT_VOLT, data) * 1000;
> +
> if (src)
> freq = xo_rate * lval / 1000;
> else
> @@ -123,6 +133,10 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev,
>
> prev_cc = core_count;
> prev_freq = freq;
> +
> + freq *= 1000;
> + for_each_cpu(cpu_r, policy->cpus)
> + dev_pm_opp_add(get_cpu_device(cpu_r), freq, volt);
Are you sure we want to duplicate the OPP entries for all CPUs in the
cluster? IIUC the frequencies of the cores in a cluster can't be
changed individually, hence the cores should have a shared table. I
think dev_pm_opp_get_sharing_cpus() does what you need.
You currently also add OPPs for invalid frequencies. From my SDM845
device:
cat /sys/devices/system/cpu/cpufreq/policy4/scaling_available_freq
=> 825600 902400 979200 1056000 1209600 1286400 1363200 1459200
1536000 1612800 1689600 1766400 1843200 1920000 1996800 2092800
2169600 2246400 2323200 2400000 2476800 2553600 2649600
cat /sys/devices/system/cpu/cpufreq/policy4/scaling_boost_frequencies
2803200
ls /sys/kernel/debug/opp/cpu4/
opp:1056000000 opp:1612800000 opp:2092800000 opp:2553600000 opp:825600000
opp:1209600000 opp:1689600000 opp:2169600000 opp:2649600000 opp:902400000
opp:1286400000 opp:1766400000 opp:2246400000 opp:2707200000 opp:979200000
opp:1363200000 opp:1843200000 opp:2323200000 opp:2764800000
opp:1459200000 opp:1920000000 opp:2400000000 opp:2784000000
opp:1536000000 opp:1996800000 opp:2476800000 opp:2803200000
There are OPP entries for 2707200000, 2764800000 and 2784000000 Hz,
however these frequencies appear neither in available_frequencies nor
boost_frequencies.
> }
>
> table[i].frequency = CPUFREQ_TABLE_END;
> @@ -159,10 +173,18 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
> struct device *dev = &global_pdev->dev;
> struct of_phandle_args args;
> struct device_node *cpu_np;
> + struct device *cpu_dev;
> struct resource *res;
> void __iomem *base;
> int ret, index;
>
> + cpu_dev = get_cpu_device(policy->cpu);
> + if (!cpu_dev) {
> + pr_err("%s: failed to get cpu%d device\n", __func__,
> + policy->cpu);
> + return -ENODEV;
> + }
> +
> cpu_np = of_cpu_device_node_get(policy->cpu);
> if (!cpu_np)
> return -EINVAL;
> @@ -205,6 +227,12 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
> goto error;
> }
>
> + ret = dev_pm_opp_get_opp_count(cpu_dev);
> + if (ret <= 0) {
> + dev_err(cpu_dev, "OPP table is not ready\n");
> + goto error;
> + }
> +
> policy->fast_switch_possible = true;
>
> return 0;
I suppose we want to remove the OPPs when the cpufreq driver is
unloaded, looks like dev_pm_opp_cpumask_remove_table() should do the
trick.
Cheers
Matthias
next prev parent reply other threads:[~2018-12-21 20:57 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-21 18:06 [PATCH v1] cpufreq: qcom: Read voltage LUT and populate OPP Taniya Das
2018-12-21 20:57 ` Matthias Kaehlcke [this message]
2018-12-23 18:59 ` Taniya Das
2018-12-26 19:32 ` Matthias Kaehlcke
2019-01-07 7:18 ` Taniya Das
2019-01-08 0:02 ` Matthias Kaehlcke
2019-01-09 8:08 ` Taniya Das
2018-12-21 21:45 ` Stephen Boyd
2019-01-07 7:37 ` Taniya Das
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=20181221205752.GD261387@google.com \
--to=mka@chromium.org \
--cc=amit.kucheria@linaro.org \
--cc=devicetree@vger.kernel.org \
--cc=evgreen@google.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=rjw@rjwysocki.net \
--cc=rnayak@codeaurora.org \
--cc=robh@kernel.org \
--cc=sboyd@kernel.org \
--cc=skannan@codeaurora.org \
--cc=tdas@codeaurora.org \
--cc=viresh.kumar@linaro.org \
/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
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.