mirror of
https://github.com/torvalds/linux.git
synced 2026-05-22 22:22:08 +02:00
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:
commit
c69d79c532
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
{},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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", },
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, },
|
||||
|
|
|
|||
|
|
@ -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`].
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user