diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2022-03-22 12:15:47 +0100 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2022-03-22 12:15:47 +0100 |
commit | 2353828f3695ecbbc3fb4b695fa6c77323db42d0 (patch) | |
tree | 6b499f0a770d4cd18a2d3217cf4f9d2cf84f43d5 /drivers/cpufreq | |
parent | 02b82b02c34321dde10d003aafcd831a769b2a8a (diff) | |
parent | b7f2b0d3511a6bbf9387f08f370f9125663e18d8 (diff) | |
download | linux-2353828f3695ecbbc3fb4b695fa6c77323db42d0.tar.bz2 |
Merge branch 'cpufreq/arm/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm
Pull ARM cpufreq updates for 5.18-rc1 fron Viresh Kumar:
"- Add per core DVFS support for QCom SoC (Bjorn Andersson), convert to yaml
binding (Manivannan Sadhasivam) and various other fixes to the QCom drivers
(Luca Weiss).
- Add OPP table for imx7s SoC (Denys Drozdov) and minor fixes (Stefan Agner).
- Fix CPPC driver's freq/performance conversions (Pierre Gondois).
- Minor generic cleanups (Yury Norov)."
* 'cpufreq/arm/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
dt-bindings: cpufreq: cpufreq-qcom-hw: Convert to YAML bindings
dt-bindings: dvfs: Use MediaTek CPUFREQ HW as an example
cpufreq: blocklist Qualcomm sc8280xp and sa8540p in cpufreq-dt-platdev
cpufreq: qcom-hw: Add support for per-core-dcvs
cpufreq: CPPC: Fix performance/frequency conversion
cpufreq: Add i.MX7S to cpufreq-dt-platdev blocklist
ARM: dts: imx7s: Define operating points table for cpufreq
cpufreq: qcom-cpufreq-nvmem: fix reading of PVS Valid fuse
cpufreq: replace cpumask_weight with cpumask_empty where appropriate
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/cppc_cpufreq.c | 43 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt-platdev.c | 3 | ||||
-rw-r--r-- | drivers/cpufreq/qcom-cpufreq-hw.c | 20 | ||||
-rw-r--r-- | drivers/cpufreq/qcom-cpufreq-nvmem.c | 2 | ||||
-rw-r--r-- | drivers/cpufreq/scmi-cpufreq.c | 2 |
5 files changed, 45 insertions, 25 deletions
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index db17196266e4..82d370ae6a4a 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -303,52 +303,48 @@ static u64 cppc_get_dmi_max_khz(void) /* * If CPPC lowest_freq and nominal_freq registers are exposed then we can - * use them to convert perf to freq and vice versa - * - * If the perf/freq point lies between Nominal and Lowest, we can treat - * (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line - * and extrapolate the rest - * For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion + * use them to convert perf to freq and vice versa. The conversion is + * extrapolated as an affine function passing by the 2 points: + * - (Low perf, Low freq) + * - (Nominal perf, Nominal perf) */ static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu_data, unsigned int perf) { struct cppc_perf_caps *caps = &cpu_data->perf_caps; + s64 retval, offset = 0; static u64 max_khz; u64 mul, div; if (caps->lowest_freq && caps->nominal_freq) { - if (perf >= caps->nominal_perf) { - mul = caps->nominal_freq; - div = caps->nominal_perf; - } else { - mul = caps->nominal_freq - caps->lowest_freq; - div = caps->nominal_perf - caps->lowest_perf; - } + mul = caps->nominal_freq - caps->lowest_freq; + div = caps->nominal_perf - caps->lowest_perf; + offset = caps->nominal_freq - div64_u64(caps->nominal_perf * mul, div); } else { if (!max_khz) max_khz = cppc_get_dmi_max_khz(); mul = max_khz; div = caps->highest_perf; } - return (u64)perf * mul / div; + + retval = offset + div64_u64(perf * mul, div); + if (retval >= 0) + return retval; + return 0; } static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data, unsigned int freq) { struct cppc_perf_caps *caps = &cpu_data->perf_caps; + s64 retval, offset = 0; static u64 max_khz; u64 mul, div; if (caps->lowest_freq && caps->nominal_freq) { - if (freq >= caps->nominal_freq) { - mul = caps->nominal_perf; - div = caps->nominal_freq; - } else { - mul = caps->lowest_perf; - div = caps->lowest_freq; - } + mul = caps->nominal_perf - caps->lowest_perf; + div = caps->nominal_freq - caps->lowest_freq; + offset = caps->nominal_perf - div64_u64(caps->nominal_freq * mul, div); } else { if (!max_khz) max_khz = cppc_get_dmi_max_khz(); @@ -356,7 +352,10 @@ static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data, div = max_khz; } - return (u64)freq * mul / div; + retval = offset + div64_u64(freq * mul, div); + if (retval >= 0) + return retval; + return 0; } static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index ca1d103ec449..96de1536e1cb 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -110,6 +110,7 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "fsl,imx7ulp", }, { .compatible = "fsl,imx7d", }, + { .compatible = "fsl,imx7s", }, { .compatible = "fsl,imx8mq", }, { .compatible = "fsl,imx8mm", }, { .compatible = "fsl,imx8mn", }, @@ -138,9 +139,11 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "qcom,msm8996", }, { .compatible = "qcom,qcs404", }, { .compatible = "qcom,sa8155p" }, + { .compatible = "qcom,sa8540p" }, { .compatible = "qcom,sc7180", }, { .compatible = "qcom,sc7280", }, { .compatible = "qcom,sc8180x", }, + { .compatible = "qcom,sc8280xp", }, { .compatible = "qcom,sdm845", }, { .compatible = "qcom,sm6350", }, { .compatible = "qcom,sm8150", }, diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index effbb680b453..f9d593ff4718 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -28,6 +28,7 @@ struct qcom_cpufreq_soc_data { u32 reg_enable; + u32 reg_dcvs_ctrl; u32 reg_freq_lut; u32 reg_volt_lut; u32 reg_current_vote; @@ -50,6 +51,8 @@ struct qcom_cpufreq_data { bool cancel_throttle; struct delayed_work throttle_work; struct cpufreq_policy *policy; + + bool per_core_dcvs; }; static unsigned long cpu_hw_rate, xo_rate; @@ -102,9 +105,14 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, struct qcom_cpufreq_data *data = policy->driver_data; const struct qcom_cpufreq_soc_data *soc_data = data->soc_data; unsigned long freq = policy->freq_table[index].frequency; + unsigned int i; writel_relaxed(index, data->base + soc_data->reg_perf_state); + if (data->per_core_dcvs) + for (i = 1; i < cpumask_weight(policy->related_cpus); i++) + writel_relaxed(index, data->base + soc_data->reg_perf_state + i * 4); + if (icc_scaling_enabled) qcom_cpufreq_set_bw(policy, freq); @@ -137,10 +145,15 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, struct qcom_cpufreq_data *data = policy->driver_data; const struct qcom_cpufreq_soc_data *soc_data = data->soc_data; unsigned int index; + unsigned int i; index = policy->cached_resolved_idx; writel_relaxed(index, data->base + soc_data->reg_perf_state); + if (data->per_core_dcvs) + for (i = 1; i < cpumask_weight(policy->related_cpus); i++) + writel_relaxed(index, data->base + soc_data->reg_perf_state + i * 4); + return policy->freq_table[index].frequency; } @@ -342,6 +355,7 @@ static irqreturn_t qcom_lmh_dcvs_handle_irq(int irq, void *data) static const struct qcom_cpufreq_soc_data qcom_soc_data = { .reg_enable = 0x0, + .reg_dcvs_ctrl = 0xbc, .reg_freq_lut = 0x110, .reg_volt_lut = 0x114, .reg_current_vote = 0x704, @@ -351,6 +365,7 @@ static const struct qcom_cpufreq_soc_data qcom_soc_data = { static const struct qcom_cpufreq_soc_data epss_soc_data = { .reg_enable = 0x0, + .reg_dcvs_ctrl = 0xb0, .reg_freq_lut = 0x100, .reg_volt_lut = 0x200, .reg_perf_state = 0x320, @@ -481,8 +496,11 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) goto error; } + if (readl_relaxed(base + data->soc_data->reg_dcvs_ctrl) & 0x1) + data->per_core_dcvs = true; + qcom_get_related_cpus(index, policy->cpus); - if (!cpumask_weight(policy->cpus)) { + if (cpumask_empty(policy->cpus)) { dev_err(dev, "Domain-%d failed to get related CPUs\n", index); ret = -ENOENT; goto error; diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index d1744b5d9619..6dfa86971a75 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -130,7 +130,7 @@ static void get_krait_bin_format_b(struct device *cpu_dev, } /* Check PVS_BLOW_STATUS */ - pte_efuse = *(((u32 *)buf) + 4); + pte_efuse = *(((u32 *)buf) + 1); pte_efuse &= BIT(21); if (pte_efuse) { dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 1e0cd4d165f0..919fa6e3f462 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -154,7 +154,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) * table and opp-shared. */ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->opp_shared_cpus); - if (ret || !cpumask_weight(priv->opp_shared_cpus)) { + if (ret || cpumask_empty(priv->opp_shared_cpus)) { /* * Either opp-table is not set or no opp-shared was found. * Use the CPU mask from SCMI to designate CPUs sharing an OPP |