Skip to content

Commit

Permalink
Merge tag 'cpufreq-arm-updates-6.14' of ssh://gitolite.kernel.org/pub…
Browse files Browse the repository at this point in the history
…/scm/linux/kernel/git/vireshk/pm

Merge ARM cpufreq updates for 6.14 from Viresh Kumar:

"- Extended support for more SoCs in apple cpufreq driver (Hector Martin
   and 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 drivers (Ethan Carter Edwards,
   Sibi Sankar and Manivannan Sadhasivam)."

* tag 'cpufreq-arm-updates-6.14' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
  cpufreq: airoha: Add EN7581 CPUFreq SMCCC driver
  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
  • Loading branch information
Rafael J. Wysocki committed Jan 20, 2025
2 parents f994c1c + 84cf9e5 commit 251be0b
Show file tree
Hide file tree
Showing 12 changed files with 344 additions and 27 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
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");
56 changes: 45 additions & 11 deletions drivers/cpufreq/apple-soc-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
#include <linux/pm_opp.h>
#include <linux/slab.h>

#define APPLE_DVFS_CMD 0x20
#define APPLE_DVFS_CMD_BUSY BIT(31)
#define APPLE_DVFS_CMD_SET BIT(25)
#define APPLE_DVFS_CMD_PS2 GENMASK(16, 12)
#define APPLE_DVFS_CMD_PS1 GENMASK(4, 0)
#define APPLE_DVFS_CMD 0x20
#define APPLE_DVFS_CMD_BUSY BIT(31)
#define APPLE_DVFS_CMD_SET BIT(25)
#define APPLE_DVFS_CMD_PS1_S5L8960X GENMASK(24, 22)
#define APPLE_DVFS_CMD_PS1_S5L8960X_SHIFT 22
#define APPLE_DVFS_CMD_PS2 GENMASK(15, 12)
#define APPLE_DVFS_CMD_PS1 GENMASK(4, 0)
#define APPLE_DVFS_CMD_PS1_SHIFT 0

/* Same timebase as CPU counter (24MHz) */
#define APPLE_DVFS_LAST_CHG_TIME 0x38
Expand All @@ -35,6 +38,9 @@
* Apple ran out of bits and had to shift this in T8112...
*/
#define APPLE_DVFS_STATUS 0x50
#define APPLE_DVFS_STATUS_CUR_PS_S5L8960X GENMASK(5, 3)
#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_S5L8960X 3
#define APPLE_DVFS_STATUS_TGT_PS_S5L8960X GENMASK(2, 0)
#define APPLE_DVFS_STATUS_CUR_PS_T8103 GENMASK(7, 4)
#define APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103 4
#define APPLE_DVFS_STATUS_TGT_PS_T8103 GENMASK(3, 0)
Expand All @@ -52,12 +58,15 @@
#define APPLE_DVFS_PLL_FACTOR_MULT GENMASK(31, 16)
#define APPLE_DVFS_PLL_FACTOR_DIV GENMASK(15, 0)

#define APPLE_DVFS_TRANSITION_TIMEOUT 100
#define APPLE_DVFS_TRANSITION_TIMEOUT 400

struct apple_soc_cpufreq_info {
bool has_ps2;
u64 max_pstate;
u64 cur_pstate_mask;
u64 cur_pstate_shift;
u64 ps1_mask;
u64 ps1_shift;
};

struct apple_cpu_priv {
Expand All @@ -68,24 +77,46 @@ struct apple_cpu_priv {

static struct cpufreq_driver apple_soc_cpufreq_driver;

static const struct apple_soc_cpufreq_info soc_s5l8960x_info = {
.has_ps2 = false,
.max_pstate = 7,
.cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_S5L8960X,
.cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_S5L8960X,
.ps1_mask = APPLE_DVFS_CMD_PS1_S5L8960X,
.ps1_shift = APPLE_DVFS_CMD_PS1_S5L8960X_SHIFT,
};

static const struct apple_soc_cpufreq_info soc_t8103_info = {
.has_ps2 = true,
.max_pstate = 15,
.cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8103,
.cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8103,
.ps1_mask = APPLE_DVFS_CMD_PS1,
.ps1_shift = APPLE_DVFS_CMD_PS1_SHIFT,
};

static const struct apple_soc_cpufreq_info soc_t8112_info = {
.has_ps2 = false,
.max_pstate = 31,
.cur_pstate_mask = APPLE_DVFS_STATUS_CUR_PS_T8112,
.cur_pstate_shift = APPLE_DVFS_STATUS_CUR_PS_SHIFT_T8112,
.ps1_mask = APPLE_DVFS_CMD_PS1,
.ps1_shift = APPLE_DVFS_CMD_PS1_SHIFT,
};

static const struct apple_soc_cpufreq_info soc_default_info = {
.has_ps2 = false,
.max_pstate = 15,
.cur_pstate_mask = 0, /* fallback */
.ps1_mask = APPLE_DVFS_CMD_PS1,
.ps1_shift = APPLE_DVFS_CMD_PS1_SHIFT,
};

static const struct of_device_id apple_soc_cpufreq_of_match[] __maybe_unused = {
{
.compatible = "apple,s5l8960x-cluster-cpufreq",
.data = &soc_s5l8960x_info,
},
{
.compatible = "apple,t8103-cluster-cpufreq",
.data = &soc_t8103_info,
Expand All @@ -109,7 +140,7 @@ static unsigned int apple_soc_cpufreq_get_rate(unsigned int cpu)
unsigned int pstate;

if (priv->info->cur_pstate_mask) {
u64 reg = readq_relaxed(priv->reg_base + APPLE_DVFS_STATUS);
u32 reg = readl_relaxed(priv->reg_base + APPLE_DVFS_STATUS);

pstate = (reg & priv->info->cur_pstate_mask) >> priv->info->cur_pstate_shift;
} else {
Expand Down Expand Up @@ -148,9 +179,12 @@ static int apple_soc_cpufreq_set_target(struct cpufreq_policy *policy,
return -EIO;
}

reg &= ~(APPLE_DVFS_CMD_PS1 | APPLE_DVFS_CMD_PS2);
reg |= FIELD_PREP(APPLE_DVFS_CMD_PS1, pstate);
reg |= FIELD_PREP(APPLE_DVFS_CMD_PS2, pstate);
reg &= ~priv->info->ps1_mask;
reg |= pstate << priv->info->ps1_shift;
if (priv->info->has_ps2) {
reg &= ~APPLE_DVFS_CMD_PS2;
reg |= FIELD_PREP(APPLE_DVFS_CMD_PS2, pstate);
}
reg |= APPLE_DVFS_CMD_SET;

writeq_relaxed(reg, priv->reg_base + APPLE_DVFS_CMD);
Expand Down Expand Up @@ -275,7 +309,7 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy)

transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
if (!transition_latency)
transition_latency = CPUFREQ_ETERNAL;
transition_latency = APPLE_DVFS_TRANSITION_TIMEOUT * NSEC_PER_USEC;

policy->cpuinfo.transition_latency = transition_latency;
policy->dvfs_possible_from_any_cpu = true;
Expand Down
Loading

0 comments on commit 251be0b

Please sign in to comment.