diff options
author | Olof Johansson <olof@lixom.net> | 2015-08-20 21:47:04 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2015-08-20 21:47:04 -0400 |
commit | 420f2629fa041ed92f7e687b3bc8020d80b209bb (patch) | |
tree | 19d1075162d842a090fee278a1bad4a7fa2712fe | |
parent | 5378e4665f226e3b5b460793397eff32b4de9daa (diff) | |
parent | 9eb15dbbfa1a23b5e65efaf1d5d6c47798e7264b (diff) |
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 <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt | 44 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig.arm | 13 | ||||
-rw-r--r-- | drivers/cpufreq/Makefile | 3 | ||||
-rw-r--r-- | drivers/cpufreq/tegra124-cpufreq.c | 214 | ||||
-rw-r--r-- | drivers/cpufreq/tegra20-cpufreq.c (renamed from drivers/cpufreq/tegra-cpufreq.c) | 0 |
5 files changed, 270 insertions, 4 deletions
diff --git a/Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt new file mode 100644 index 000000000000..b1669fbfb740 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/tegra124-cpufreq.txt | |||
@@ -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 | }; | ||
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index cc8a71c267b8..24e5c664683f 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm | |||
@@ -247,12 +247,19 @@ config ARM_SPEAR_CPUFREQ | |||
247 | help | 247 | help |
248 | This adds the CPUFreq driver support for SPEAr SOCs. | 248 | This adds the CPUFreq driver support for SPEAr SOCs. |
249 | 249 | ||
250 | config ARM_TEGRA_CPUFREQ | 250 | config ARM_TEGRA20_CPUFREQ |
251 | bool "TEGRA CPUFreq support" | 251 | bool "Tegra20 CPUFreq support" |
252 | depends on ARCH_TEGRA | 252 | depends on ARCH_TEGRA |
253 | default y | 253 | default y |
254 | help | 254 | 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. | ||
256 | 263 | ||
257 | config ARM_PXA2xx_CPUFREQ | 264 | config ARM_PXA2xx_CPUFREQ |
258 | tristate "Intel PXA2xx CPUfreq driver" | 265 | tristate "Intel PXA2xx CPUfreq driver" |
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 2169bf792db7..032745de8fcc 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
@@ -76,7 +76,8 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o | |||
76 | obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o | 76 | obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o |
77 | obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o | 77 | obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o |
78 | obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o | 78 | 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 | ||
80 | obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o | 81 | obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o |
81 | 82 | ||
82 | ################################################################################## | 83 | ################################################################################## |
diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c new file mode 100644 index 000000000000..20bcceb58ccc --- /dev/null +++ b/drivers/cpufreq/tegra124-cpufreq.c | |||
@@ -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 <ttynkkynen@nvidia.com>"); | ||
213 | MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124"); | ||
214 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra20-cpufreq.c index 8084c7f7e206..8084c7f7e206 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra20-cpufreq.c | |||