Skip to content

Commit

Permalink
Merge branch 'pm-cpufreq'
Browse files Browse the repository at this point in the history
Merge cpufreq updates for 6.14:

 - Use str_enable_disable()-like helpers in cpufreq (Krzysztof
   Kozlowski).

 - Extend the Apple cpufreq driver to support more SoCs (Hector Martin,
   Nick Chan).

 - Add new cpufreq driver for Airoha SoCs (Christian Marangi).

 - Fix using cpufreq-dt as module (Andreas Kemnade).

 - Minor fixes for Sparc, SCMI, and Qcom cpufreq drivers (Ethan Carter
   Edwards, Sibi Sankar, Manivannan Sadhasivam).

 - Fix the maximum supported frequency computation in the ACPI cpufreq
   driver to avoid relying on unfounded assumptions (Gautham Shenoy).

 - Fix an amd-pstate driver regression with preferred core rankings not
   being used (Mario Limonciello).

 - Fix a precision issue with frequency calculation in the amd-pstate
   driver (Naresh Solanki).

 - Add ftrace event to the amd-pstate driver for active mode (Mario
   Limonciello).

 - Set default EPP policy on Ryzen processors in amd-pstate (Mario
   Limonciello).

 - Clean up the amd-pstate cpufreq driver and optimize it to increase
   code reuse (Mario Limonciello, Dhananjay Ugwekar).

 - Use CPPC to get scaling factors between HWP performance levels and
   frequency in the intel_pstate driver and make it stop using a built
   -in scaling factor for the Arrow Lake processor (Rafael Wysocki).

 - Make intel_pstate initialize epp_policy to CPUFREQ_POLICY_UNKNOWN for
   consistency with CPU offline (Christian Loehle).

 - Fix superfluous updates caused by need_freq_update in the schedutil
   cpufreq governor (Sultan Alsawaf).

* pm-cpufreq: (40 commits)
  cpufreq: Use str_enable_disable()-like helpers
  cpufreq: airoha: Add EN7581 CPUFreq SMCCC driver
  cpufreq: ACPI: Fix max-frequency computation
  cpufreq/amd-pstate: Refactor max frequency calculation
  cpufreq/amd-pstate: Fix prefcore rankings
  cpufreq: sparc: change kzalloc to kcalloc
  cpufreq: qcom: Implement clk_ops::determine_rate() for qcom_cpufreq* clocks
  cpufreq: qcom: Fix qcom_cpufreq_hw_recalc_rate() to query LUT if LMh IRQ is not available
  cpufreq: apple-soc: Add Apple A7-A8X SoC cpufreq support
  cpufreq: apple-soc: Set fallback transition latency to APPLE_DVFS_TRANSITION_TIMEOUT
  cpufreq: apple-soc: Increase cluster switch timeout to 400us
  cpufreq: apple-soc: Use 32-bit read for status register
  cpufreq: apple-soc: Allow per-SoC configuration of APPLE_DVFS_CMD_PS1
  cpufreq: apple-soc: Drop setting the PS2 field on M2+
  dt-bindings: cpufreq: apple,cluster-cpufreq: Add A7-A11, T2 compatibles
  dt-bindings: cpufreq: Document support for Airoha EN7581 CPUFreq
  cpufreq: fix using cpufreq-dt as module
  cpufreq: scmi: Register for limit change notifications
  cpufreq: schedutil: Fix superfluous updates caused by need_freq_update
  cpufreq: intel_pstate: Use CPUFREQ_POLICY_UNKNOWN
  ...
  • Loading branch information
Rafael J. Wysocki committed Jan 20, 2025
2 parents 1225bb4 + 251be0b commit a5c16f2
Show file tree
Hide file tree
Showing 21 changed files with 691 additions and 340 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/cpufreq/airoha,en7581-cpufreq.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Airoha EN7581 CPUFreq

maintainers:
- Christian Marangi <ansuelsmth@gmail.com>

description: |
On newer Airoha SoC, CPU Frequency is scaled indirectly with SMC commands
to ATF.
A virtual clock is exposed. This virtual clock is a get-only clock and
is used to expose the current global CPU clock. The frequency info comes
by the output of the SMC command that reports the clock in MHz.
The SMC sets the CPU clock by providing an index, this is modelled as
performance states in a power domain.
CPUs can't be individually scaled as the CPU frequency is shared across
all CPUs and is global.
properties:
compatible:
const: airoha,en7581-cpufreq

'#clock-cells':
const: 0

'#power-domain-cells':
const: 0

operating-points-v2: true

required:
- compatible
- '#clock-cells'
- '#power-domain-cells'
- operating-points-v2

additionalProperties: false

examples:
- |
performance-domain {
compatible = "airoha,en7581-cpufreq";
operating-points-v2 = <&cpu_smcc_opp_table>;
#power-domain-cells = <0>;
#clock-cells = <0>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@ properties:
- apple,t8112-cluster-cpufreq
- const: apple,cluster-cpufreq
- items:
- const: apple,t6000-cluster-cpufreq
- enum:
- apple,s8000-cluster-cpufreq
- apple,t8010-cluster-cpufreq
- apple,t8015-cluster-cpufreq
- apple,t6000-cluster-cpufreq
- const: apple,t8103-cluster-cpufreq
- const: apple,cluster-cpufreq
- items:
- const: apple,t7000-cluster-cpufreq
- const: apple,s5l8960x-cluster-cpufreq
- const: apple,s5l8960x-cluster-cpufreq

reg:
maxItems: 1
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ config CPUFREQ_VIRT
If in doubt, say N.

config CPUFREQ_DT_PLATDEV
tristate "Generic DT based cpufreq platdev driver"
bool "Generic DT based cpufreq platdev driver"
depends on OF
help
This adds a generic DT based cpufreq platdev driver for frequency
Expand Down
8 changes: 8 additions & 0 deletions drivers/cpufreq/Kconfig.arm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
To compile this driver as a module, choose M here: the
module will be called sun50i-cpufreq-nvmem.

config ARM_AIROHA_SOC_CPUFREQ
tristate "Airoha EN7581 SoC CPUFreq support"
depends on ARCH_AIROHA || COMPILE_TEST
select PM_OPP
default ARCH_AIROHA
help
This adds the CPUFreq driver for Airoha EN7581 SoCs.

config ARM_APPLE_SOC_CPUFREQ
tristate "Apple Silicon SoC CPUFreq support"
depends on ARCH_APPLE || (COMPILE_TEST && 64BIT)
Expand Down
1 change: 1 addition & 0 deletions drivers/cpufreq/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o

##################################################################################
# ARM SoC drivers
obj-$(CONFIG_ARM_AIROHA_SOC_CPUFREQ) += airoha-cpufreq.o
obj-$(CONFIG_ARM_APPLE_SOC_CPUFREQ) += apple-soc-cpufreq.o
obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_ARMADA_8K_CPUFREQ) += armada-8k-cpufreq.o
Expand Down
36 changes: 27 additions & 9 deletions drivers/cpufreq/acpi-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,14 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c)
#endif

#ifdef CONFIG_ACPI_CPPC_LIB
static u64 get_max_boost_ratio(unsigned int cpu)
/*
* get_max_boost_ratio: Computes the max_boost_ratio as the ratio
* between the highest_perf and the nominal_perf.
*
* Returns the max_boost_ratio for @cpu. Returns the CPPC nominal
* frequency via @nominal_freq if it is non-NULL pointer.
*/
static u64 get_max_boost_ratio(unsigned int cpu, u64 *nominal_freq)
{
struct cppc_perf_caps perf_caps;
u64 highest_perf, nominal_perf;
Expand Down Expand Up @@ -652,6 +659,9 @@ static u64 get_max_boost_ratio(unsigned int cpu)

nominal_perf = perf_caps.nominal_perf;

if (nominal_freq)
*nominal_freq = perf_caps.nominal_freq;

if (!highest_perf || !nominal_perf) {
pr_debug("CPU%d: highest or nominal performance missing\n", cpu);
return 0;
Expand All @@ -664,8 +674,12 @@ static u64 get_max_boost_ratio(unsigned int cpu)

return div_u64(highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf);
}

#else
static inline u64 get_max_boost_ratio(unsigned int cpu) { return 0; }
static inline u64 get_max_boost_ratio(unsigned int cpu, u64 *nominal_freq)
{
return 0;
}
#endif

static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
Expand All @@ -675,9 +689,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
struct acpi_cpufreq_data *data;
unsigned int cpu = policy->cpu;
struct cpuinfo_x86 *c = &cpu_data(cpu);
u64 max_boost_ratio, nominal_freq = 0;
unsigned int valid_states = 0;
unsigned int result = 0;
u64 max_boost_ratio;
unsigned int i;
#ifdef CONFIG_SMP
static int blacklisted;
Expand Down Expand Up @@ -827,16 +841,20 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
}
freq_table[valid_states].frequency = CPUFREQ_TABLE_END;

max_boost_ratio = get_max_boost_ratio(cpu);
max_boost_ratio = get_max_boost_ratio(cpu, &nominal_freq);
if (max_boost_ratio) {
unsigned int freq = freq_table[0].frequency;
unsigned int freq = nominal_freq;

/*
* Because the loop above sorts the freq_table entries in the
* descending order, freq is the maximum frequency in the table.
* Assume that it corresponds to the CPPC nominal frequency and
* use it to set cpuinfo.max_freq.
* The loop above sorts the freq_table entries in the
* descending order. If ACPI CPPC has not advertised
* the nominal frequency (this is possible in CPPC
* revisions prior to 3), then use the first entry in
* the pstate table as a proxy for nominal frequency.
*/
if (!freq)
freq = freq_table[0].frequency;

policy->cpuinfo.max_freq = freq * max_boost_ratio >> SCHED_CAPACITY_SHIFT;
} else {
/*
Expand Down
152 changes: 152 additions & 0 deletions drivers/cpufreq/airoha-cpufreq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: GPL-2.0

#include <linux/bitfield.h>
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>

#include "cpufreq-dt.h"

struct airoha_cpufreq_priv {
int opp_token;
struct dev_pm_domain_list *pd_list;
struct platform_device *cpufreq_dt;
};

static struct platform_device *cpufreq_pdev;

/* NOP function to disable OPP from setting clock */
static int airoha_cpufreq_config_clks_nop(struct device *dev,
struct opp_table *opp_table,
struct dev_pm_opp *opp,
void *data, bool scaling_down)
{
return 0;
}

static const char * const airoha_cpufreq_clk_names[] = { "cpu", NULL };
static const char * const airoha_cpufreq_pd_names[] = { "perf" };

static int airoha_cpufreq_probe(struct platform_device *pdev)
{
const struct dev_pm_domain_attach_data attach_data = {
.pd_names = airoha_cpufreq_pd_names,
.num_pd_names = ARRAY_SIZE(airoha_cpufreq_pd_names),
.pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP,
};
struct dev_pm_opp_config config = {
.clk_names = airoha_cpufreq_clk_names,
.config_clks = airoha_cpufreq_config_clks_nop,
};
struct platform_device *cpufreq_dt;
struct airoha_cpufreq_priv *priv;
struct device *dev = &pdev->dev;
struct device *cpu_dev;
int ret;

/* CPUs refer to the same OPP table */
cpu_dev = get_cpu_device(0);
if (!cpu_dev)
return -ENODEV;

priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

/* Set OPP table conf with NOP config_clks */
priv->opp_token = dev_pm_opp_set_config(cpu_dev, &config);
if (priv->opp_token < 0)
return dev_err_probe(dev, priv->opp_token, "Failed to set OPP config\n");

/* Attach PM for OPP */
ret = dev_pm_domain_attach_list(cpu_dev, &attach_data,
&priv->pd_list);
if (ret)
goto clear_opp_config;

cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
ret = PTR_ERR_OR_ZERO(cpufreq_dt);
if (ret) {
dev_err(dev, "failed to create cpufreq-dt device: %d\n", ret);
goto detach_pm;
}

priv->cpufreq_dt = cpufreq_dt;
platform_set_drvdata(pdev, priv);

return 0;

detach_pm:
dev_pm_domain_detach_list(priv->pd_list);
clear_opp_config:
dev_pm_opp_clear_config(priv->opp_token);

return ret;
}

static void airoha_cpufreq_remove(struct platform_device *pdev)
{
struct airoha_cpufreq_priv *priv = platform_get_drvdata(pdev);

platform_device_unregister(priv->cpufreq_dt);

dev_pm_domain_detach_list(priv->pd_list);

dev_pm_opp_clear_config(priv->opp_token);
}

static struct platform_driver airoha_cpufreq_driver = {
.probe = airoha_cpufreq_probe,
.remove = airoha_cpufreq_remove,
.driver = {
.name = "airoha-cpufreq",
},
};

static const struct of_device_id airoha_cpufreq_match_list[] __initconst = {
{ .compatible = "airoha,en7581" },
{},
};
MODULE_DEVICE_TABLE(of, airoha_cpufreq_match_list);

static int __init airoha_cpufreq_init(void)
{
struct device_node *np = of_find_node_by_path("/");
const struct of_device_id *match;
int ret;

if (!np)
return -ENODEV;

match = of_match_node(airoha_cpufreq_match_list, np);
of_node_put(np);
if (!match)
return -ENODEV;

ret = platform_driver_register(&airoha_cpufreq_driver);
if (unlikely(ret < 0))
return ret;

cpufreq_pdev = platform_device_register_data(NULL, "airoha-cpufreq",
-1, match, sizeof(*match));
ret = PTR_ERR_OR_ZERO(cpufreq_pdev);
if (ret)
platform_driver_unregister(&airoha_cpufreq_driver);

return ret;
}
module_init(airoha_cpufreq_init);

static void __exit airoha_cpufreq_exit(void)
{
platform_device_unregister(cpufreq_pdev);
platform_driver_unregister(&airoha_cpufreq_driver);
}
module_exit(airoha_cpufreq_exit);

MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
MODULE_DESCRIPTION("CPUfreq driver for Airoha SoCs");
MODULE_LICENSE("GPL");
Loading

0 comments on commit a5c16f2

Please sign in to comment.