CPUFreq updates for 6.18

- Minor improvements to Rust Cpumask APIs (Alice Ryhl, Baptiste Lepers,
   and Shankari Anand).
 
 - Minor cleanups and optimizations to various cpufreq drivers (Akhilesh
   Patil, BowenYu, Dennis Beier, Liao Yuanhong, Zihuan Zhang, Florian
   Fainelli, Taniya Das, Md Sadre Alam, and Christian Marangi).
 
 - Enhancements for TI cpufreq driver (Judith Mendez, and Paresh Bhagat).
 
 - Enhancements for mediatek cpufreq driver (Nicolas Frattaroli).
 
 - Remove outdated cpufreq-dt.txt (Frank Li).
 
 - Update MAINTAINERS for virtual-cpufreq maintainer (Saravana Kannan).
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmi5KikACgkQ0rkcPK6B
 EhzEwg//X8dw5f9hEQmQqh1aT9tZ7BaJ98E+a0cpVb6zST6lAAtXBk4YUUjgAHm0
 cCcHON03rUfa8OQAvoVR5kJzjtzQpqIviyxujuZ+a30r+7WgF0FTg/Mp4t9zXWwR
 sqyGDQmX/snfe+jhdVVwO1a2elAvcNP2cF1nycPHbphzH9HdsqKpAT2LscOoIY2f
 VBZKKIqaNFXxb2U/kAUIkNRCWDHOMyrszgbGu6AsQDvoL9N7TyPxiNqdJTC5wcAW
 lPuWzUAkptWYWWiQ8d4oXlnQHcRFQF+w1woUXqCvkoDQxcuHTjKGtQYzZi+b21rk
 ROsMdz3H7UgiNmkrRZJPxTjSoExdSjQTWFrM19jKjh929R0AOej+Nd6TlAVqzA5H
 ImrTTSV0Kx7BeaHfsNqh5uTgUFMe9v54V1K79Xk4b4Lu4+A7JmfPa/IntGa0WbAO
 heW5Wtvhbv5wEfYbVJgPV/ztLWu7IxGctCZXTCdJi+C/hUjXZfGNpB9MIroQHVEu
 tm9WMkaPQ0N7ysEm3J1ZFtjBrAUKhg2QszuzUsNnn8iM1mV2PIC0HpfI6+MN0OKa
 +X3G+4STwla5Bpc4g9YbINDaSgJiPRDjpT9fWiY1YOG02wHee+KvUcTYz/yJz0GN
 mzutWMJqJNCMzpa+6CN7+a/mCorGCLZOV+GdjBetmmCXI7Ar8TI=
 =jRmJ
 -----END PGP SIGNATURE-----

Merge tag 'cpufreq-arm-updates-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm

Merge CPUFreq updates for 6.18 from Viresh Kumar:

"- Minor improvements to Rust Cpumask APIs (Alice Ryhl, Baptiste Lepers,
   and Shankari Anand).

 - Minor cleanups and optimizations to various cpufreq drivers (Akhilesh
   Patil, BowenYu, Dennis Beier, Liao Yuanhong, Zihuan Zhang, Florian
   Fainelli, Taniya Das, Md Sadre Alam, and Christian Marangi).

 - Enhancements for TI cpufreq driver (Judith Mendez, and Paresh Bhagat).

 - Enhancements for mediatek cpufreq driver (Nicolas Frattaroli).

 - Remove outdated cpufreq-dt.txt (Frank Li).

 - Update MAINTAINERS for virtual-cpufreq maintainer (Saravana Kannan)."

* tag 'cpufreq-arm-updates-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: (28 commits)
  cpufreq: mediatek: avoid redundant conditions
  cpufreq/longhaul: handle NULL policy in longhaul_exit
  cpufreq: tegra186: Use scope-based cleanup helper
  cpufreq: mediatek: Use scope-based cleanup helper
  cpufreq: s5pv210: Use scope-based cleanup helper
  cpufreq: CPPC: Use scope-based cleanup helper
  cpufreq: brcmstb-avs: Use scope-based cleanup helper
  dt-bindings: Remove outdated cpufreq-dt.txt
  arm64: dts: ti: k3-am62p: Fix supported hardware for 1GHz OPP
  cpufreq: ti: Allow all silicon revisions to support OPPs
  cpufreq: ti: Support more speed grades on AM62Px SoC
  cpufreq: ti: Add support for AM62D2
  cpufreq: dt-platdev: Blacklist ti,am62d2 SoC
  rust: opp: update ARef and AlwaysRefCounted imports from sync::aref
  cpufreq: mediatek-hw: don't use error path on NULL fdvfs
  cpufreq: scmi: Account for malformed DT in scmi_dev_used_by_cpus()
  rust: cpumask: Mark CpumaskVar as transparent
  rust: cpumask: rename CpumaskVar::as[_mut]_ref to from_raw[_mut]
  dt-bindings: cpufreq: cpufreq-qcom-hw: Add QCS615 compatible
  MAINTAINERS: Add myself as virtual-cpufreq maintainer
  ...
This commit is contained in:
Rafael J. Wysocki 2025-09-04 20:36:55 +02:00
commit c69d79c532
21 changed files with 257 additions and 125 deletions

View File

@ -1,61 +0,0 @@
Generic cpufreq driver
It is a generic DT based cpufreq driver for frequency management. It supports
both uniprocessor (UP) and symmetric multiprocessor (SMP) systems which share
clock and voltage across all CPUs.
Both required and optional properties listed below must be defined
under node /cpus/cpu@0.
Required properties:
- None
Optional properties:
- operating-points: Refer to Documentation/devicetree/bindings/opp/opp-v1.yaml for
details. OPPs *must* be supplied either via DT, i.e. this property, or
populated at runtime.
- clock-latency: Specify the possible maximum transition latency for clock,
in unit of nanoseconds.
- voltage-tolerance: Specify the CPU voltage tolerance in percentage.
- #cooling-cells:
Please refer to
Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml.
Examples:
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
next-level-cache = <&L2>;
operating-points = <
/* kHz uV */
792000 1100000
396000 950000
198000 850000
>;
clock-latency = <61036>; /* two CLK32 periods */
#cooling-cells = <2>;
};
cpu@1 {
compatible = "arm,cortex-a9";
reg = <1>;
next-level-cache = <&L2>;
};
cpu@2 {
compatible = "arm,cortex-a9";
reg = <2>;
next-level-cache = <&L2>;
};
cpu@3 {
compatible = "arm,cortex-a9";
reg = <3>;
next-level-cache = <&L2>;
};
};

View File

@ -22,6 +22,7 @@ properties:
items:
- enum:
- qcom,qcm2290-cpufreq-hw
- qcom,qcs615-cpufreq-hw
- qcom,sc7180-cpufreq-hw
- qcom,sc8180x-cpufreq-hw
- qcom,sdm670-cpufreq-hw
@ -132,6 +133,7 @@ allOf:
compatible:
contains:
enum:
- qcom,qcs615-cpufreq-hw
- qcom,qdu1000-cpufreq-epss
- qcom,sa8255p-cpufreq-epss
- qcom,sa8775p-cpufreq-epss

View File

@ -0,0 +1,82 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/cpufreq/mediatek,mt8196-cpufreq-hw.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Hybrid CPUFreq for MT8196/MT6991 series SoCs
maintainers:
- Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
description:
MT8196 uses CPUFreq management hardware that supports dynamic voltage
frequency scaling (dvfs), and can support several performance domains.
properties:
compatible:
const: mediatek,mt8196-cpufreq-hw
reg:
items:
- description: FDVFS control register region
- description: OPP tables and control for performance domain 0
- description: OPP tables and control for performance domain 1
- description: OPP tables and control for performance domain 2
"#performance-domain-cells":
const: 1
required:
- compatible
- reg
- "#performance-domain-cells"
additionalProperties: false
examples:
- |
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a720";
enable-method = "psci";
performance-domains = <&performance 0>;
reg = <0x000>;
};
/* ... */
cpu6: cpu@600 {
device_type = "cpu";
compatible = "arm,cortex-x4";
enable-method = "psci";
performance-domains = <&performance 1>;
reg = <0x600>;
};
cpu7: cpu@700 {
device_type = "cpu";
compatible = "arm,cortex-x925";
enable-method = "psci";
performance-domains = <&performance 2>;
reg = <0x700>;
};
};
/* ... */
soc {
#address-cells = <2>;
#size-cells = <2>;
performance: performance-controller@c2c2034 {
compatible = "mediatek,mt8196-cpufreq-hw";
reg = <0 0xc220400 0 0x20>, <0 0xc2c0f20 0 0x120>,
<0 0xc2c1040 0 0x120>, <0 0xc2c1160 0 0x120>;
#performance-domain-cells = <1>;
};
};

View File

@ -6350,6 +6350,12 @@ F: kernel/sched/cpufreq*.c
F: rust/kernel/cpufreq.rs
F: tools/testing/selftests/cpufreq/
CPU FREQUENCY DRIVERS - VIRTUAL MACHINE CPUFREQ
M: Saravana Kannan <saravanak@google.com>
L: linux-pm@vger.kernel.org
S: Maintained
F: drivers/cpufreq/virtual-cpufreq.c
CPU HOTPLUG
M: Thomas Gleixner <tglx@linutronix.de>
M: Peter Zijlstra <peterz@infradead.org>

View File

@ -135,7 +135,7 @@ opp-800000000 {
opp-1000000000 {
opp-hz = /bits/ 64 <1000000000>;
opp-supported-hw = <0x01 0x0006>;
opp-supported-hw = <0x01 0x0007>;
clock-latency-ns = <6000000>;
};

View File

@ -107,6 +107,7 @@ static struct platform_driver airoha_cpufreq_driver = {
};
static const struct of_device_id airoha_cpufreq_match_list[] __initconst = {
{ .compatible = "airoha,an7583" },
{ .compatible = "airoha,en7581" },
{},
};

View File

@ -265,7 +265,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
*/
target_vm = avs_map[l0_vdd_min] - 100;
target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV;
target_vm = max(target_vm, MIN_VOLT_MV);
dvfs->avs[1] = armada_37xx_avs_val_match(target_vm);
/*
@ -273,7 +273,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
* be larger than 1000mv
*/
target_vm = avs_map[l0_vdd_min] - 150;
target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV;
target_vm = max(target_vm, MIN_VOLT_MV);
dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm);
/*

View File

@ -480,7 +480,7 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
struct private_data *priv;
if (!policy)
@ -488,8 +488,6 @@ static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
priv = policy->driver_data;
cpufreq_cpu_put(policy);
return brcm_avs_get_frequency(priv->base);
}

View File

@ -50,8 +50,7 @@ struct cppc_freq_invariance {
static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv);
static struct kthread_worker *kworker_fie;
static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
struct cppc_perf_fb_ctrs *fb_ctrs_t0,
static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
struct cppc_perf_fb_ctrs *fb_ctrs_t1);
/**
@ -87,8 +86,7 @@ static void cppc_scale_freq_workfn(struct kthread_work *work)
return;
}
perf = cppc_perf_from_fbctrs(cpu_data, &cppc_fi->prev_perf_fb_ctrs,
&fb_ctrs);
perf = cppc_perf_from_fbctrs(&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs);
if (!perf)
return;
@ -684,8 +682,7 @@ static inline u64 get_delta(u64 t1, u64 t0)
return (u32)t1 - (u32)t0;
}
static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
struct cppc_perf_fb_ctrs *fb_ctrs_t0,
static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
struct cppc_perf_fb_ctrs *fb_ctrs_t1)
{
u64 delta_reference, delta_delivered;
@ -725,8 +722,8 @@ static int cppc_get_perf_ctrs_sample(int cpu,
static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
{
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0};
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct cppc_cpudata *cpu_data;
u64 delivered_perf;
int ret;
@ -736,8 +733,6 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
cpu_data = policy->driver_data;
cpufreq_cpu_put(policy);
ret = cppc_get_perf_ctrs_sample(cpu, &fb_ctrs_t0, &fb_ctrs_t1);
if (ret) {
if (ret == -EFAULT)
@ -747,8 +742,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
return 0;
}
delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0,
&fb_ctrs_t1);
delivered_perf = cppc_perf_from_fbctrs(&fb_ctrs_t0, &fb_ctrs_t1);
if (!delivered_perf)
goto out_invalid_counters;

View File

@ -103,6 +103,7 @@ static const struct of_device_id allowlist[] __initconst = {
* platforms using "operating-points-v2" property.
*/
static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "airoha,an7583", },
{ .compatible = "airoha,en7581", },
{ .compatible = "allwinner,sun50i-a100" },
@ -188,9 +189,11 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "ti,omap3", },
{ .compatible = "ti,am625", },
{ .compatible = "ti,am62a7", },
{ .compatible = "ti,am62d2", },
{ .compatible = "ti,am62p5", },
{ .compatible = "qcom,ipq5332", },
{ .compatible = "qcom,ipq5424", },
{ .compatible = "qcom,ipq6018", },
{ .compatible = "qcom,ipq8064", },
{ .compatible = "qcom,ipq8074", },

View File

@ -953,6 +953,9 @@ static void __exit longhaul_exit(void)
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
int i;
if (unlikely(!policy))
return;
for (i = 0; i < numscales; i++) {
if (mults[i] == maxmult) {
struct cpufreq_freqs freqs;

View File

@ -24,6 +24,8 @@
#define POLL_USEC 1000
#define TIMEOUT_USEC 300000
#define FDVFS_FDIV_HZ (26 * 1000)
enum {
REG_FREQ_LUT_TABLE,
REG_FREQ_ENABLE,
@ -35,7 +37,14 @@ enum {
REG_ARRAY_SIZE,
};
struct mtk_cpufreq_data {
struct mtk_cpufreq_priv {
struct device *dev;
const struct mtk_cpufreq_variant *variant;
void __iomem *fdvfs;
};
struct mtk_cpufreq_domain {
struct mtk_cpufreq_priv *parent;
struct cpufreq_frequency_table *table;
void __iomem *reg_bases[REG_ARRAY_SIZE];
struct resource *res;
@ -43,20 +52,51 @@ struct mtk_cpufreq_data {
int nr_opp;
};
static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = {
[REG_FREQ_LUT_TABLE] = 0x0,
[REG_FREQ_ENABLE] = 0x84,
[REG_FREQ_PERF_STATE] = 0x88,
[REG_FREQ_HW_STATE] = 0x8c,
[REG_EM_POWER_TBL] = 0x90,
[REG_FREQ_LATENCY] = 0x110,
struct mtk_cpufreq_variant {
int (*init)(struct mtk_cpufreq_priv *priv);
const u16 reg_offsets[REG_ARRAY_SIZE];
const bool is_hybrid_dvfs;
};
static const struct mtk_cpufreq_variant cpufreq_mtk_base_variant = {
.reg_offsets = {
[REG_FREQ_LUT_TABLE] = 0x0,
[REG_FREQ_ENABLE] = 0x84,
[REG_FREQ_PERF_STATE] = 0x88,
[REG_FREQ_HW_STATE] = 0x8c,
[REG_EM_POWER_TBL] = 0x90,
[REG_FREQ_LATENCY] = 0x110,
},
};
static int mtk_cpufreq_hw_mt8196_init(struct mtk_cpufreq_priv *priv)
{
priv->fdvfs = devm_of_iomap(priv->dev, priv->dev->of_node, 0, NULL);
if (IS_ERR(priv->fdvfs))
return dev_err_probe(priv->dev, PTR_ERR(priv->fdvfs),
"failed to get fdvfs iomem\n");
return 0;
}
static const struct mtk_cpufreq_variant cpufreq_mtk_mt8196_variant = {
.init = mtk_cpufreq_hw_mt8196_init,
.reg_offsets = {
[REG_FREQ_LUT_TABLE] = 0x0,
[REG_FREQ_ENABLE] = 0x84,
[REG_FREQ_PERF_STATE] = 0x88,
[REG_FREQ_HW_STATE] = 0x8c,
[REG_EM_POWER_TBL] = 0x90,
[REG_FREQ_LATENCY] = 0x114,
},
.is_hybrid_dvfs = true,
};
static int __maybe_unused
mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW,
unsigned long *KHz)
{
struct mtk_cpufreq_data *data;
struct mtk_cpufreq_domain *data;
struct cpufreq_policy *policy;
int i;
@ -80,19 +120,38 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW,
return 0;
}
static void mtk_cpufreq_hw_fdvfs_switch(unsigned int target_freq,
struct cpufreq_policy *policy)
{
struct mtk_cpufreq_domain *data = policy->driver_data;
struct mtk_cpufreq_priv *priv = data->parent;
unsigned int cpu;
target_freq = DIV_ROUND_UP(target_freq, FDVFS_FDIV_HZ);
for_each_cpu(cpu, policy->real_cpus) {
writel_relaxed(target_freq, priv->fdvfs + cpu * 4);
}
}
static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy,
unsigned int index)
{
struct mtk_cpufreq_data *data = policy->driver_data;
struct mtk_cpufreq_domain *data = policy->driver_data;
unsigned int target_freq;
writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]);
if (data->parent->fdvfs) {
target_freq = policy->freq_table[index].frequency;
mtk_cpufreq_hw_fdvfs_switch(target_freq, policy);
} else {
writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]);
}
return 0;
}
static unsigned int mtk_cpufreq_hw_get(unsigned int cpu)
{
struct mtk_cpufreq_data *data;
struct mtk_cpufreq_domain *data;
struct cpufreq_policy *policy;
unsigned int index;
@ -111,18 +170,21 @@ static unsigned int mtk_cpufreq_hw_get(unsigned int cpu)
static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
unsigned int target_freq)
{
struct mtk_cpufreq_data *data = policy->driver_data;
struct mtk_cpufreq_domain *data = policy->driver_data;
unsigned int index;
index = cpufreq_table_find_index_dl(policy, target_freq, false);
writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]);
if (data->parent->fdvfs)
mtk_cpufreq_hw_fdvfs_switch(target_freq, policy);
else
writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]);
return policy->freq_table[index].frequency;
}
static int mtk_cpu_create_freq_table(struct platform_device *pdev,
struct mtk_cpufreq_data *data)
struct mtk_cpufreq_domain *data)
{
struct device *dev = &pdev->dev;
u32 temp, i, freq, prev_freq = 0;
@ -157,9 +219,9 @@ static int mtk_cpu_create_freq_table(struct platform_device *pdev,
static int mtk_cpu_resources_init(struct platform_device *pdev,
struct cpufreq_policy *policy,
const u16 *offsets)
struct mtk_cpufreq_priv *priv)
{
struct mtk_cpufreq_data *data;
struct mtk_cpufreq_domain *data;
struct device *dev = &pdev->dev;
struct resource *res;
struct of_phandle_args args;
@ -180,6 +242,15 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
index = args.args[0];
of_node_put(args.np);
/*
* In a cpufreq with hybrid DVFS, such as the MT8196, the first declared
* register range is for FDVFS, followed by the frequency domain MMIOs.
*/
if (priv->variant->is_hybrid_dvfs)
index++;
data->parent = priv;
res = platform_get_resource(pdev, IORESOURCE_MEM, index);
if (!res) {
dev_err(dev, "failed to get mem resource %d\n", index);
@ -202,7 +273,7 @@ static int mtk_cpu_resources_init(struct platform_device *pdev,
data->res = res;
for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++)
data->reg_bases[i] = base + offsets[i];
data->reg_bases[i] = base + priv->variant->reg_offsets[i];
ret = mtk_cpu_create_freq_table(pdev, data);
if (ret) {
@ -223,7 +294,7 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
{
struct platform_device *pdev = cpufreq_get_driver_data();
int sig, pwr_hw = CPUFREQ_HW_STATUS | SVS_HW_STATUS;
struct mtk_cpufreq_data *data;
struct mtk_cpufreq_domain *data;
unsigned int latency;
int ret;
@ -262,7 +333,7 @@ static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
static void mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
{
struct mtk_cpufreq_data *data = policy->driver_data;
struct mtk_cpufreq_domain *data = policy->driver_data;
struct resource *res = data->res;
void __iomem *base = data->base;
@ -275,7 +346,7 @@ static void mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
static void mtk_cpufreq_register_em(struct cpufreq_policy *policy)
{
struct em_data_callback em_cb = EM_DATA_CB(mtk_cpufreq_get_cpu_power);
struct mtk_cpufreq_data *data = policy->driver_data;
struct mtk_cpufreq_domain *data = policy->driver_data;
em_dev_register_perf_domain(get_cpu_device(policy->cpu), data->nr_opp,
&em_cb, policy->cpus, true);
@ -297,6 +368,7 @@ static struct cpufreq_driver cpufreq_mtk_hw_driver = {
static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
{
struct mtk_cpufreq_priv *priv;
const void *data;
int ret, cpu;
struct device *cpu_dev;
@ -320,7 +392,20 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
if (!data)
return -EINVAL;
platform_set_drvdata(pdev, (void *) data);
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->variant = data;
priv->dev = &pdev->dev;
if (priv->variant->init) {
ret = priv->variant->init(priv);
if (ret)
return ret;
}
platform_set_drvdata(pdev, priv);
cpufreq_mtk_hw_driver.driver_data = pdev;
ret = cpufreq_register_driver(&cpufreq_mtk_hw_driver);
@ -336,7 +421,8 @@ static void mtk_cpufreq_hw_driver_remove(struct platform_device *pdev)
}
static const struct of_device_id mtk_cpufreq_hw_match[] = {
{ .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_offsets },
{ .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_base_variant },
{ .compatible = "mediatek,mt8196-cpufreq-hw", .data = &cpufreq_mtk_mt8196_variant },
{}
};
MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match);

View File

@ -123,7 +123,7 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
soc_data->sram_max_volt);
return ret;
}
} else if (pre_vproc > new_vproc) {
} else {
vproc = max(new_vproc,
pre_vsram - soc_data->max_volt_shift);
ret = regulator_set_voltage(proc_reg, vproc,
@ -320,7 +320,6 @@ static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
struct dev_pm_opp *new_opp;
struct mtk_cpu_dvfs_info *info;
unsigned long freq, volt;
struct cpufreq_policy *policy;
int ret = 0;
info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb);
@ -353,12 +352,12 @@ static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
}
dev_pm_opp_put(new_opp);
policy = cpufreq_cpu_get(info->opp_cpu);
if (policy) {
struct cpufreq_policy *policy __free(put_cpufreq_policy)
= cpufreq_cpu_get(info->opp_cpu);
if (policy)
cpufreq_driver_target(policy, freq / 1000,
CPUFREQ_RELATION_L);
cpufreq_cpu_put(policy);
}
}
}

View File

@ -200,6 +200,10 @@ static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
case QCOM_ID_IPQ9574:
drv->versions = 1 << (unsigned int)(*speedbin);
break;
case QCOM_ID_IPQ5424:
case QCOM_ID_IPQ5404:
drv->versions = (*speedbin == 0x3b) ? BIT(1) : BIT(0);
break;
case QCOM_ID_MSM8996SG:
case QCOM_ID_APQ8096SG:
drv->versions = 1 << ((unsigned int)(*speedbin) + 4);
@ -591,6 +595,7 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst __maybe_u
{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
{ .compatible = "qcom,ipq5332", .data = &match_data_kryo },
{ .compatible = "qcom,ipq5424", .data = &match_data_kryo },
{ .compatible = "qcom,ipq6018", .data = &match_data_ipq6018 },
{ .compatible = "qcom,ipq8064", .data = &match_data_ipq8064 },
{ .compatible = "qcom,ipq8074", .data = &match_data_ipq8074 },

View File

@ -554,17 +554,15 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(0);
int ret;
struct cpufreq_policy *policy;
policy = cpufreq_cpu_get(0);
if (!policy) {
pr_debug("cpufreq: get no policy for cpu0\n");
return NOTIFY_BAD;
}
ret = cpufreq_driver_target(policy, SLEEP_FREQ, 0);
cpufreq_cpu_put(policy);
if (ret < 0)
return NOTIFY_BAD;

View File

@ -15,6 +15,7 @@
#include <linux/energy_model.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
@ -424,6 +425,15 @@ static bool scmi_dev_used_by_cpus(struct device *scmi_dev)
return true;
}
/*
* Older Broadcom STB chips had a "clocks" property for CPU node(s)
* that did not match the SCMI performance protocol node, if we got
* there, it means we had such an older Device Tree, therefore return
* true to preserve backwards compatibility.
*/
if (of_machine_is_compatible("brcm,brcmstb"))
return true;
return false;
}

View File

@ -103,13 +103,12 @@ static int tegra186_cpufreq_set_target(struct cpufreq_policy *policy,
static unsigned int tegra186_cpufreq_get(unsigned int cpu)
{
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
struct tegra186_cpufreq_data *data = cpufreq_get_driver_data();
struct tegra186_cpufreq_cluster *cluster;
struct cpufreq_policy *policy;
unsigned int edvd_offset, cluster_id;
u32 ndiv;
policy = cpufreq_cpu_get(cpu);
if (!policy)
return 0;
@ -117,7 +116,6 @@ static unsigned int tegra186_cpufreq_get(unsigned int cpu)
ndiv = readl(data->regs + edvd_offset) & EDVD_CORE_VOLT_FREQ_F_MASK;
cluster_id = data->cpus[policy->cpu].bpmp_cluster_id;
cluster = &data->clusters[cluster_id];
cpufreq_cpu_put(policy);
return (cluster->ref_clk_khz * ndiv) / cluster->div;
}

View File

@ -72,7 +72,9 @@ enum {
#define AM62P5_EFUSE_O_MPU_OPP 15
#define AM62P5_EFUSE_S_MPU_OPP 19
#define AM62P5_EFUSE_T_MPU_OPP 20
#define AM62P5_EFUSE_U_MPU_OPP 21
#define AM62P5_EFUSE_V_MPU_OPP 22
#define AM62P5_SUPPORT_O_MPU_OPP BIT(0)
#define AM62P5_SUPPORT_U_MPU_OPP BIT(2)
@ -153,7 +155,9 @@ static unsigned long am62p5_efuse_xlate(struct ti_cpufreq_data *opp_data,
unsigned long calculated_efuse = AM62P5_SUPPORT_O_MPU_OPP;
switch (efuse) {
case AM62P5_EFUSE_V_MPU_OPP:
case AM62P5_EFUSE_U_MPU_OPP:
case AM62P5_EFUSE_T_MPU_OPP:
case AM62P5_EFUSE_S_MPU_OPP:
calculated_efuse |= AM62P5_SUPPORT_U_MPU_OPP;
fallthrough;
@ -307,9 +311,10 @@ static struct ti_cpufreq_soc_data am3517_soc_data = {
};
static const struct soc_device_attribute k3_cpufreq_soc[] = {
{ .family = "AM62X", .revision = "SR1.0" },
{ .family = "AM62AX", .revision = "SR1.0" },
{ .family = "AM62PX", .revision = "SR1.0" },
{ .family = "AM62X", },
{ .family = "AM62AX", },
{ .family = "AM62PX", },
{ .family = "AM62DX", },
{ /* sentinel */ }
};
@ -457,6 +462,7 @@ static const struct of_device_id ti_cpufreq_of_match[] __maybe_unused = {
{ .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, },
{ .compatible = "ti,am625", .data = &am625_soc_data, },
{ .compatible = "ti,am62a7", .data = &am62a7_soc_data, },
{ .compatible = "ti,am62d2", .data = &am62a7_soc_data, },
{ .compatible = "ti,am62p5", .data = &am62p5_soc_data, },
/* legacy */
{ .compatible = "ti,omap3430", .data = &omap34xx_soc_data, },

View File

@ -543,7 +543,7 @@ pub fn register_em_opp(&mut self) {
pub fn cpus(&mut self) -> &mut cpumask::Cpumask {
// SAFETY: The pointer to `cpus` is valid for writing and remains valid for the lifetime of
// the returned reference.
unsafe { cpumask::CpumaskVar::as_mut_ref(&mut self.as_mut_ref().cpus) }
unsafe { cpumask::CpumaskVar::from_raw_mut(&mut self.as_mut_ref().cpus) }
}
/// Sets clock for the [`Policy`].

View File

@ -212,6 +212,7 @@ pub fn copy(&self, dstp: &mut Self) {
/// }
/// assert_eq!(mask2.weight(), count);
/// ```
#[repr(transparent)]
pub struct CpumaskVar {
#[cfg(CONFIG_CPUMASK_OFFSTACK)]
ptr: NonNull<Cpumask>,
@ -270,7 +271,7 @@ pub unsafe fn new(_flags: Flags) -> Result<Self, AllocError> {
///
/// The caller must ensure that `ptr` is valid for writing and remains valid for the lifetime
/// of the returned reference.
pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self {
pub unsafe fn from_raw_mut<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self {
// SAFETY: Guaranteed by the safety requirements of the function.
//
// INVARIANT: The caller ensures that `ptr` is valid for writing and remains valid for the
@ -284,7 +285,7 @@ pub unsafe fn as_mut_ref<'a>(ptr: *mut bindings::cpumask_var_t) -> &'a mut Self
///
/// The caller must ensure that `ptr` is valid for reading and remains valid for the lifetime
/// of the returned reference.
pub unsafe fn as_ref<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self {
pub unsafe fn from_raw<'a>(ptr: *const bindings::cpumask_var_t) -> &'a Self {
// SAFETY: Guaranteed by the safety requirements of the function.
//
// INVARIANT: The caller ensures that `ptr` is valid for reading and remains valid for the

View File

@ -16,7 +16,8 @@
ffi::c_ulong,
prelude::*,
str::CString,
types::{ARef, AlwaysRefCounted, Opaque},
sync::aref::{ARef, AlwaysRefCounted},
types::Opaque,
};
#[cfg(CONFIG_CPU_FREQ)]
@ -162,7 +163,7 @@ fn from(power: MicroWatt) -> Self {
/// use kernel::device::Device;
/// use kernel::error::Result;
/// use kernel::opp::{Data, MicroVolt, Token};
/// use kernel::types::ARef;
/// use kernel::sync::aref::ARef;
///
/// fn create_opp(dev: &ARef<Device>, freq: Hertz, volt: MicroVolt, level: u32) -> Result<Token> {
/// let data = Data::new(freq, volt, level, false);
@ -211,7 +212,7 @@ fn drop(&mut self) {
/// use kernel::device::Device;
/// use kernel::error::Result;
/// use kernel::opp::{Data, MicroVolt, Token};
/// use kernel::types::ARef;
/// use kernel::sync::aref::ARef;
///
/// fn create_opp(dev: &ARef<Device>, freq: Hertz, volt: MicroVolt, level: u32) -> Result<Token> {
/// let data = Data::new(freq, volt, level, false);
@ -262,7 +263,7 @@ fn freq(&self) -> Hertz {
/// use kernel::clk::Hertz;
/// use kernel::error::Result;
/// use kernel::opp::{OPP, SearchType, Table};
/// use kernel::types::ARef;
/// use kernel::sync::aref::ARef;
///
/// fn find_opp(table: &Table, freq: Hertz) -> Result<ARef<OPP>> {
/// let opp = table.opp_from_freq(freq, Some(true), None, SearchType::Exact)?;
@ -335,7 +336,7 @@ fn drop(&mut self) {
/// use kernel::error::Result;
/// use kernel::opp::{Config, ConfigOps, ConfigToken};
/// use kernel::str::CString;
/// use kernel::types::ARef;
/// use kernel::sync::aref::ARef;
/// use kernel::macros::vtable;
///
/// #[derive(Default)]
@ -581,7 +582,7 @@ extern "C" fn config_regulators(
/// use kernel::device::Device;
/// use kernel::error::Result;
/// use kernel::opp::Table;
/// use kernel::types::ARef;
/// use kernel::sync::aref::ARef;
///
/// fn get_table(dev: &ARef<Device>, mask: &mut Cpumask, freq: Hertz) -> Result<Table> {
/// let mut opp_table = Table::from_of_cpumask(dev, mask)?;