Skip to content

Commit

Permalink
cpufreq: airoha: Add EN7581 CPUFreq SMCCC driver
Browse files Browse the repository at this point in the history
Add simple CPU Freq driver for Airoha EN7581 SoC that control CPU
frequency scaling with SMC APIs and register a generic "cpufreq-dt"
device.

All CPU share the same frequency and can't be controlled independently.
CPU frequency is controlled by the attached PM domain.

Add SoC compatible to cpufreq-dt-plat block list as a dedicated cpufreq
driver is needed with OPP v2 nodes declared in DTS.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
  • Loading branch information
Christian Marangi authored and Viresh Kumar committed Jan 17, 2025
1 parent af6cc45 commit 84cf9e5
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
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");
2 changes: 2 additions & 0 deletions drivers/cpufreq/cpufreq-dt-platdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ static const struct of_device_id allowlist[] __initconst = {
* platforms using "operating-points-v2" property.
*/
static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "airoha,en7581", },

{ .compatible = "allwinner,sun50i-a100" },
{ .compatible = "allwinner,sun50i-h6", },
{ .compatible = "allwinner,sun50i-h616", },
Expand Down

0 comments on commit 84cf9e5

Please sign in to comment.