Skip to content

Commit 82e703d

Browse files
Ansuelstorulf
authored andcommitted
pmdomain: airoha: Add Airoha CPU PM Domain support
Add Airoha CPU PM Domain support to control frequency and power of CPU present on Airoha EN7581 SoC. Frequency and power can be controlled with the use of the SMC command by passing the performance state. The driver also expose a read-only clock that expose the current CPU frequency with SMC command. Signed-off-by: Christian Marangi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent 094041b commit 82e703d

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-0
lines changed

drivers/pmdomain/mediatek/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,16 @@ config MTK_SCPSYS_PM_DOMAINS
2626
Control Processor System (SCPSYS) has several power management related
2727
tasks in the system.
2828

29+
config AIROHA_CPU_PM_DOMAIN
30+
tristate "Airoha CPU power domain"
31+
default ARCH_AIROHA
32+
depends on HAVE_ARM_SMCCC
33+
depends on PM
34+
select PM_GENERIC_DOMAINS
35+
help
36+
Say y here to enable CPU power domain support for Airoha SoC.
37+
38+
CPU frequency and power is controlled by ATF with SMC command to
39+
set performance states.
40+
2941
endmenu

drivers/pmdomain/mediatek/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
33
obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
4+
obj-$(CONFIG_AIROHA_CPU_PM_DOMAIN) += airoha-cpu-pmdomain.o
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/arm-smccc.h>
4+
#include <linux/bitfield.h>
5+
#include <linux/clk-provider.h>
6+
#include <linux/module.h>
7+
#include <linux/platform_device.h>
8+
#include <linux/pm_domain.h>
9+
#include <linux/slab.h>
10+
11+
#define AIROHA_SIP_AVS_HANDLE 0x82000301
12+
#define AIROHA_AVS_OP_BASE 0xddddddd0
13+
#define AIROHA_AVS_OP_MASK GENMASK(1, 0)
14+
#define AIROHA_AVS_OP_FREQ_DYN_ADJ (AIROHA_AVS_OP_BASE | \
15+
FIELD_PREP(AIROHA_AVS_OP_MASK, 0x1))
16+
#define AIROHA_AVS_OP_GET_FREQ (AIROHA_AVS_OP_BASE | \
17+
FIELD_PREP(AIROHA_AVS_OP_MASK, 0x2))
18+
19+
struct airoha_cpu_pmdomain_priv {
20+
struct clk_hw hw;
21+
struct generic_pm_domain pd;
22+
};
23+
24+
static long airoha_cpu_pmdomain_clk_round(struct clk_hw *hw, unsigned long rate,
25+
unsigned long *parent_rate)
26+
{
27+
return rate;
28+
}
29+
30+
static unsigned long airoha_cpu_pmdomain_clk_get(struct clk_hw *hw,
31+
unsigned long parent_rate)
32+
{
33+
struct arm_smccc_res res;
34+
35+
arm_smccc_1_1_invoke(AIROHA_SIP_AVS_HANDLE, AIROHA_AVS_OP_GET_FREQ,
36+
0, 0, 0, 0, 0, 0, &res);
37+
38+
/* SMCCC returns freq in MHz */
39+
return (int)(res.a0 * 1000 * 1000);
40+
}
41+
42+
/* Airoha CPU clk SMCC is always enabled */
43+
static int airoha_cpu_pmdomain_clk_is_enabled(struct clk_hw *hw)
44+
{
45+
return true;
46+
}
47+
48+
static const struct clk_ops airoha_cpu_pmdomain_clk_ops = {
49+
.recalc_rate = airoha_cpu_pmdomain_clk_get,
50+
.is_enabled = airoha_cpu_pmdomain_clk_is_enabled,
51+
.round_rate = airoha_cpu_pmdomain_clk_round,
52+
};
53+
54+
static int airoha_cpu_pmdomain_set_performance_state(struct generic_pm_domain *domain,
55+
unsigned int state)
56+
{
57+
struct arm_smccc_res res;
58+
59+
arm_smccc_1_1_invoke(AIROHA_SIP_AVS_HANDLE, AIROHA_AVS_OP_FREQ_DYN_ADJ,
60+
0, state, 0, 0, 0, 0, &res);
61+
62+
/* SMC signal correct apply by unsetting BIT 0 */
63+
return res.a0 & BIT(0) ? -EINVAL : 0;
64+
}
65+
66+
static int airoha_cpu_pmdomain_probe(struct platform_device *pdev)
67+
{
68+
struct airoha_cpu_pmdomain_priv *priv;
69+
struct device *dev = &pdev->dev;
70+
const struct clk_init_data init = {
71+
.name = "cpu",
72+
.ops = &airoha_cpu_pmdomain_clk_ops,
73+
/* Clock with no set_rate, can't cache */
74+
.flags = CLK_GET_RATE_NOCACHE,
75+
};
76+
struct generic_pm_domain *pd;
77+
int ret;
78+
79+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
80+
if (!priv)
81+
return -ENOMEM;
82+
83+
/* Init and register a get-only clk for Cpufreq */
84+
priv->hw.init = &init;
85+
ret = devm_clk_hw_register(dev, &priv->hw);
86+
if (ret)
87+
return ret;
88+
89+
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
90+
&priv->hw);
91+
if (ret)
92+
return ret;
93+
94+
/* Init and register a PD for CPU */
95+
pd = &priv->pd;
96+
pd->name = "cpu_pd";
97+
pd->flags = GENPD_FLAG_ALWAYS_ON;
98+
pd->set_performance_state = airoha_cpu_pmdomain_set_performance_state;
99+
100+
ret = pm_genpd_init(pd, NULL, false);
101+
if (ret)
102+
return ret;
103+
104+
ret = of_genpd_add_provider_simple(dev->of_node, pd);
105+
if (ret)
106+
goto err_add_provider;
107+
108+
platform_set_drvdata(pdev, priv);
109+
110+
return 0;
111+
112+
err_add_provider:
113+
pm_genpd_remove(pd);
114+
115+
return ret;
116+
}
117+
118+
static void airoha_cpu_pmdomain_remove(struct platform_device *pdev)
119+
{
120+
struct airoha_cpu_pmdomain_priv *priv = platform_get_drvdata(pdev);
121+
122+
of_genpd_del_provider(pdev->dev.of_node);
123+
pm_genpd_remove(&priv->pd);
124+
}
125+
126+
static const struct of_device_id airoha_cpu_pmdomain_of_match[] = {
127+
{ .compatible = "airoha,en7581-cpufreq" },
128+
{ },
129+
};
130+
MODULE_DEVICE_TABLE(of, airoha_cpu_pmdomain_of_match);
131+
132+
static struct platform_driver airoha_cpu_pmdomain_driver = {
133+
.probe = airoha_cpu_pmdomain_probe,
134+
.remove = airoha_cpu_pmdomain_remove,
135+
.driver = {
136+
.name = "airoha-cpu-pmdomain",
137+
.of_match_table = airoha_cpu_pmdomain_of_match,
138+
},
139+
};
140+
module_platform_driver(airoha_cpu_pmdomain_driver);
141+
142+
MODULE_AUTHOR("Christian Marangi <[email protected]>");
143+
MODULE_DESCRIPTION("CPU PM domain driver for Airoha SoCs");
144+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)