Skip to content

Commit 420f262

Browse files
committed
Merge tag 'tegra-for-4.3-cpufreq' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers
ARM: tegra: CPU frequency scaling for v4.3-rc1 This adds CPU frequency scaling support for Tegra124. * tag 'tegra-for-4.3-cpufreq' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: cpufreq: Add cpufreq driver for Tegra124 cpufreq: tegra: Rename tegra-cpufreq to tegra20-cpufreq cpufreq: tegra124: Add device tree bindings Signed-off-by: Olof Johansson <[email protected]>
2 parents 5378e46 + 9eb15db commit 420f262

File tree

5 files changed

+270
-4
lines changed

5 files changed

+270
-4
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Tegra124 CPU frequency scaling driver bindings
2+
----------------------------------------------
3+
4+
Both required and optional properties listed below must be defined
5+
under node /cpus/cpu@0.
6+
7+
Required properties:
8+
- clocks: Must contain an entry for each entry in clock-names.
9+
See ../clocks/clock-bindings.txt for details.
10+
- clock-names: Must include the following entries:
11+
- cpu_g: Clock mux for the fast CPU cluster.
12+
- cpu_lp: Clock mux for the low-power CPU cluster.
13+
- pll_x: Fast PLL clocksource.
14+
- pll_p: Auxiliary PLL used during fast PLL rate changes.
15+
- dfll: Fast DFLL clocksource that also automatically scales CPU voltage.
16+
- vdd-cpu-supply: Regulator for CPU voltage
17+
18+
Optional properties:
19+
- clock-latency: Specify the possible maximum transition latency for clock,
20+
in unit of nanoseconds.
21+
22+
Example:
23+
--------
24+
cpus {
25+
#address-cells = <1>;
26+
#size-cells = <0>;
27+
28+
cpu@0 {
29+
device_type = "cpu";
30+
compatible = "arm,cortex-a15";
31+
reg = <0>;
32+
33+
clocks = <&tegra_car TEGRA124_CLK_CCLK_G>,
34+
<&tegra_car TEGRA124_CLK_CCLK_LP>,
35+
<&tegra_car TEGRA124_CLK_PLL_X>,
36+
<&tegra_car TEGRA124_CLK_PLL_P>,
37+
<&dfll>;
38+
clock-names = "cpu_g", "cpu_lp", "pll_x", "pll_p", "dfll";
39+
clock-latency = <300000>;
40+
vdd-cpu-supply: <&vdd_cpu>;
41+
};
42+
43+
<...>
44+
};

drivers/cpufreq/Kconfig.arm

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,19 @@ config ARM_SPEAR_CPUFREQ
247247
help
248248
This adds the CPUFreq driver support for SPEAr SOCs.
249249

250-
config ARM_TEGRA_CPUFREQ
251-
bool "TEGRA CPUFreq support"
250+
config ARM_TEGRA20_CPUFREQ
251+
bool "Tegra20 CPUFreq support"
252252
depends on ARCH_TEGRA
253253
default y
254254
help
255-
This adds the CPUFreq driver support for TEGRA SOCs.
255+
This adds the CPUFreq driver support for Tegra20 SOCs.
256+
257+
config ARM_TEGRA124_CPUFREQ
258+
tristate "Tegra124 CPUFreq support"
259+
depends on ARCH_TEGRA && CPUFREQ_DT
260+
default y
261+
help
262+
This adds the CPUFreq driver support for Tegra124 SOCs.
256263

257264
config ARM_PXA2xx_CPUFREQ
258265
tristate "Intel PXA2xx CPUfreq driver"

drivers/cpufreq/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
7676
obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
7777
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
7878
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
79-
obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
79+
obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
80+
obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
8081
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
8182

8283
##################################################################################

drivers/cpufreq/tegra124-cpufreq.c

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*
2+
* Tegra 124 cpufreq driver
3+
*
4+
* This software is licensed under the terms of the GNU General Public
5+
* License version 2, as published by the Free Software Foundation, and
6+
* may be copied, distributed, and modified under those terms.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*/
13+
14+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15+
16+
#include <linux/clk.h>
17+
#include <linux/cpufreq-dt.h>
18+
#include <linux/err.h>
19+
#include <linux/init.h>
20+
#include <linux/kernel.h>
21+
#include <linux/module.h>
22+
#include <linux/of_device.h>
23+
#include <linux/of.h>
24+
#include <linux/platform_device.h>
25+
#include <linux/pm_opp.h>
26+
#include <linux/regulator/consumer.h>
27+
#include <linux/types.h>
28+
29+
struct tegra124_cpufreq_priv {
30+
struct regulator *vdd_cpu_reg;
31+
struct clk *cpu_clk;
32+
struct clk *pllp_clk;
33+
struct clk *pllx_clk;
34+
struct clk *dfll_clk;
35+
struct platform_device *cpufreq_dt_pdev;
36+
};
37+
38+
static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv)
39+
{
40+
struct clk *orig_parent;
41+
int ret;
42+
43+
ret = clk_set_rate(priv->dfll_clk, clk_get_rate(priv->cpu_clk));
44+
if (ret)
45+
return ret;
46+
47+
orig_parent = clk_get_parent(priv->cpu_clk);
48+
clk_set_parent(priv->cpu_clk, priv->pllp_clk);
49+
50+
ret = clk_prepare_enable(priv->dfll_clk);
51+
if (ret)
52+
goto out;
53+
54+
clk_set_parent(priv->cpu_clk, priv->dfll_clk);
55+
56+
return 0;
57+
58+
out:
59+
clk_set_parent(priv->cpu_clk, orig_parent);
60+
61+
return ret;
62+
}
63+
64+
static void tegra124_cpu_switch_to_pllx(struct tegra124_cpufreq_priv *priv)
65+
{
66+
clk_set_parent(priv->cpu_clk, priv->pllp_clk);
67+
clk_disable_unprepare(priv->dfll_clk);
68+
regulator_sync_voltage(priv->vdd_cpu_reg);
69+
clk_set_parent(priv->cpu_clk, priv->pllx_clk);
70+
}
71+
72+
static struct cpufreq_dt_platform_data cpufreq_dt_pd = {
73+
.independent_clocks = false,
74+
};
75+
76+
static int tegra124_cpufreq_probe(struct platform_device *pdev)
77+
{
78+
struct tegra124_cpufreq_priv *priv;
79+
struct device_node *np;
80+
struct device *cpu_dev;
81+
struct platform_device_info cpufreq_dt_devinfo = {};
82+
int ret;
83+
84+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
85+
if (!priv)
86+
return -ENOMEM;
87+
88+
cpu_dev = get_cpu_device(0);
89+
if (!cpu_dev)
90+
return -ENODEV;
91+
92+
np = of_cpu_device_node_get(0);
93+
if (!np)
94+
return -ENODEV;
95+
96+
priv->vdd_cpu_reg = regulator_get(cpu_dev, "vdd-cpu");
97+
if (IS_ERR(priv->vdd_cpu_reg)) {
98+
ret = PTR_ERR(priv->vdd_cpu_reg);
99+
goto out_put_np;
100+
}
101+
102+
priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
103+
if (IS_ERR(priv->cpu_clk)) {
104+
ret = PTR_ERR(priv->cpu_clk);
105+
goto out_put_vdd_cpu_reg;
106+
}
107+
108+
priv->dfll_clk = of_clk_get_by_name(np, "dfll");
109+
if (IS_ERR(priv->dfll_clk)) {
110+
ret = PTR_ERR(priv->dfll_clk);
111+
goto out_put_cpu_clk;
112+
}
113+
114+
priv->pllx_clk = of_clk_get_by_name(np, "pll_x");
115+
if (IS_ERR(priv->pllx_clk)) {
116+
ret = PTR_ERR(priv->pllx_clk);
117+
goto out_put_dfll_clk;
118+
}
119+
120+
priv->pllp_clk = of_clk_get_by_name(np, "pll_p");
121+
if (IS_ERR(priv->pllp_clk)) {
122+
ret = PTR_ERR(priv->pllp_clk);
123+
goto out_put_pllx_clk;
124+
}
125+
126+
ret = tegra124_cpu_switch_to_dfll(priv);
127+
if (ret)
128+
goto out_put_pllp_clk;
129+
130+
cpufreq_dt_devinfo.name = "cpufreq-dt";
131+
cpufreq_dt_devinfo.parent = &pdev->dev;
132+
cpufreq_dt_devinfo.data = &cpufreq_dt_pd;
133+
cpufreq_dt_devinfo.size_data = sizeof(cpufreq_dt_pd);
134+
135+
priv->cpufreq_dt_pdev =
136+
platform_device_register_full(&cpufreq_dt_devinfo);
137+
if (IS_ERR(priv->cpufreq_dt_pdev)) {
138+
ret = PTR_ERR(priv->cpufreq_dt_pdev);
139+
goto out_switch_to_pllx;
140+
}
141+
142+
platform_set_drvdata(pdev, priv);
143+
144+
return 0;
145+
146+
out_switch_to_pllx:
147+
tegra124_cpu_switch_to_pllx(priv);
148+
out_put_pllp_clk:
149+
clk_put(priv->pllp_clk);
150+
out_put_pllx_clk:
151+
clk_put(priv->pllx_clk);
152+
out_put_dfll_clk:
153+
clk_put(priv->dfll_clk);
154+
out_put_cpu_clk:
155+
clk_put(priv->cpu_clk);
156+
out_put_vdd_cpu_reg:
157+
regulator_put(priv->vdd_cpu_reg);
158+
out_put_np:
159+
of_node_put(np);
160+
161+
return ret;
162+
}
163+
164+
static int tegra124_cpufreq_remove(struct platform_device *pdev)
165+
{
166+
struct tegra124_cpufreq_priv *priv = platform_get_drvdata(pdev);
167+
168+
platform_device_unregister(priv->cpufreq_dt_pdev);
169+
tegra124_cpu_switch_to_pllx(priv);
170+
171+
clk_put(priv->pllp_clk);
172+
clk_put(priv->pllx_clk);
173+
clk_put(priv->dfll_clk);
174+
clk_put(priv->cpu_clk);
175+
regulator_put(priv->vdd_cpu_reg);
176+
177+
return 0;
178+
}
179+
180+
static struct platform_driver tegra124_cpufreq_platdrv = {
181+
.driver.name = "cpufreq-tegra124",
182+
.probe = tegra124_cpufreq_probe,
183+
.remove = tegra124_cpufreq_remove,
184+
};
185+
186+
static int __init tegra_cpufreq_init(void)
187+
{
188+
int ret;
189+
struct platform_device *pdev;
190+
191+
if (!of_machine_is_compatible("nvidia,tegra124"))
192+
return -ENODEV;
193+
194+
/*
195+
* Platform driver+device required for handling EPROBE_DEFER with
196+
* the regulator and the DFLL clock
197+
*/
198+
ret = platform_driver_register(&tegra124_cpufreq_platdrv);
199+
if (ret)
200+
return ret;
201+
202+
pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
203+
if (IS_ERR(pdev)) {
204+
platform_driver_unregister(&tegra124_cpufreq_platdrv);
205+
return PTR_ERR(pdev);
206+
}
207+
208+
return 0;
209+
}
210+
module_init(tegra_cpufreq_init);
211+
212+
MODULE_AUTHOR("Tuomas Tynkkynen <[email protected]>");
213+
MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124");
214+
MODULE_LICENSE("GPL v2");
File renamed without changes.

0 commit comments

Comments
 (0)