diff options
24 files changed, 442 insertions, 280 deletions
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt index 366690cb86a3..e41c98ffbccb 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt | |||
@@ -1,8 +1,8 @@ | |||
1 | Generic CPU0 cpufreq driver | 1 | Generic cpufreq driver |
2 | 2 | ||
3 | It is a generic cpufreq driver for CPU0 frequency management. It | 3 | It is a generic DT based cpufreq driver for frequency management. It supports |
4 | supports both uniprocessor (UP) and symmetric multiprocessor (SMP) | 4 | both uniprocessor (UP) and symmetric multiprocessor (SMP) systems which share |
5 | systems which share clock and voltage across all CPUs. | 5 | clock and voltage across all CPUs. |
6 | 6 | ||
7 | Both required and optional properties listed below must be defined | 7 | Both required and optional properties listed below must be defined |
8 | under node /cpus/cpu@0. | 8 | under node /cpus/cpu@0. |
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig index fdfda1fa9521..7309988b0f1f 100644 --- a/arch/arm/configs/mvebu_v7_defconfig +++ b/arch/arm/configs/mvebu_v7_defconfig | |||
@@ -32,7 +32,7 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y | |||
32 | CONFIG_CPU_IDLE=y | 32 | CONFIG_CPU_IDLE=y |
33 | CONFIG_ARM_MVEBU_V7_CPUIDLE=y | 33 | CONFIG_ARM_MVEBU_V7_CPUIDLE=y |
34 | CONFIG_CPU_FREQ=y | 34 | CONFIG_CPU_FREQ=y |
35 | CONFIG_CPUFREQ_GENERIC=y | 35 | CONFIG_CPUFREQ_DT=y |
36 | CONFIG_VFP=y | 36 | CONFIG_VFP=y |
37 | CONFIG_NET=y | 37 | CONFIG_NET=y |
38 | CONFIG_INET=y | 38 | CONFIG_INET=y |
diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c index 080e66c6a1d0..dc8f1a6f45f2 100644 --- a/arch/arm/mach-imx/imx27-dt.c +++ b/arch/arm/mach-imx/imx27-dt.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | static void __init imx27_dt_init(void) | 21 | static void __init imx27_dt_init(void) |
22 | { | 22 | { |
23 | struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; | 23 | struct platform_device_info devinfo = { .name = "cpufreq-dt", }; |
24 | 24 | ||
25 | mxc_arch_reset_init_dt(); | 25 | mxc_arch_reset_init_dt(); |
26 | 26 | ||
diff --git a/arch/arm/mach-imx/mach-imx51.c b/arch/arm/mach-imx/mach-imx51.c index c77deb3f0893..2c5fcaf8675b 100644 --- a/arch/arm/mach-imx/mach-imx51.c +++ b/arch/arm/mach-imx/mach-imx51.c | |||
@@ -51,7 +51,7 @@ static void __init imx51_ipu_mipi_setup(void) | |||
51 | 51 | ||
52 | static void __init imx51_dt_init(void) | 52 | static void __init imx51_dt_init(void) |
53 | { | 53 | { |
54 | struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; | 54 | struct platform_device_info devinfo = { .name = "cpufreq-dt", }; |
55 | 55 | ||
56 | mxc_arch_reset_init_dt(); | 56 | mxc_arch_reset_init_dt(); |
57 | imx51_ipu_mipi_setup(); | 57 | imx51_ipu_mipi_setup(); |
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 8a70a51533fd..bbd8664d1bac 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c | |||
@@ -644,7 +644,7 @@ static int __init armada_xp_pmsu_cpufreq_init(void) | |||
644 | } | 644 | } |
645 | } | 645 | } |
646 | 646 | ||
647 | platform_device_register_simple("cpufreq-generic", -1, NULL, 0); | 647 | platform_device_register_simple("cpufreq-dt", -1, NULL, 0); |
648 | return 0; | 648 | return 0; |
649 | } | 649 | } |
650 | 650 | ||
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 828aee9ea6a8..58920bc8807b 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -282,7 +282,7 @@ static inline void omap_init_cpufreq(void) | |||
282 | if (!of_have_populated_dt()) | 282 | if (!of_have_populated_dt()) |
283 | devinfo.name = "omap-cpufreq"; | 283 | devinfo.name = "omap-cpufreq"; |
284 | else | 284 | else |
285 | devinfo.name = "cpufreq-cpu0"; | 285 | devinfo.name = "cpufreq-dt"; |
286 | platform_device_register_full(&devinfo); | 286 | platform_device_register_full(&devinfo); |
287 | } | 287 | } |
288 | 288 | ||
diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c index 2f7723e5fe91..0110751da511 100644 --- a/arch/arm/mach-shmobile/board-ape6evm-reference.c +++ b/arch/arm/mach-shmobile/board-ape6evm-reference.c | |||
@@ -50,7 +50,7 @@ static void __init ape6evm_add_standard_devices(void) | |||
50 | 50 | ||
51 | r8a73a4_add_dt_devices(); | 51 | r8a73a4_add_dt_devices(); |
52 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 52 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
53 | platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0); | 53 | platform_device_register_simple("cpufreq-dt", -1, NULL, 0); |
54 | } | 54 | } |
55 | 55 | ||
56 | static const char *ape6evm_boards_compat_dt[] __initdata = { | 56 | static const char *ape6evm_boards_compat_dt[] __initdata = { |
diff --git a/arch/arm/mach-shmobile/cpufreq.c b/arch/arm/mach-shmobile/cpufreq.c index 8a24b2be46ae..57fbff024dcd 100644 --- a/arch/arm/mach-shmobile/cpufreq.c +++ b/arch/arm/mach-shmobile/cpufreq.c | |||
@@ -12,6 +12,6 @@ | |||
12 | 12 | ||
13 | int __init shmobile_cpufreq_init(void) | 13 | int __init shmobile_cpufreq_init(void) |
14 | { | 14 | { |
15 | platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0); | 15 | platform_device_register_simple("cpufreq-dt", -1, NULL, 0); |
16 | return 0; | 16 | return 0; |
17 | } | 17 | } |
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index 2c802ae9b241..15b990cd8c70 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c | |||
@@ -775,7 +775,7 @@ void __init sh73a0_add_early_devices(void) | |||
775 | 775 | ||
776 | void __init sh73a0_add_standard_devices_dt(void) | 776 | void __init sh73a0_add_standard_devices_dt(void) |
777 | { | 777 | { |
778 | struct platform_device_info devinfo = { .name = "cpufreq-cpu0", .id = -1, }; | 778 | struct platform_device_info devinfo = { .name = "cpufreq-dt", .id = -1, }; |
779 | 779 | ||
780 | /* clocks are setup late during boot in the case of DT */ | 780 | /* clocks are setup late during boot in the case of DT */ |
781 | sh73a0_clock_init(); | 781 | sh73a0_clock_init(); |
@@ -784,7 +784,7 @@ void __init sh73a0_add_standard_devices_dt(void) | |||
784 | ARRAY_SIZE(sh73a0_devices_dt)); | 784 | ARRAY_SIZE(sh73a0_devices_dt)); |
785 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 785 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
786 | 786 | ||
787 | /* Instantiate cpufreq-cpu0 */ | 787 | /* Instantiate cpufreq-dt */ |
788 | platform_device_register_full(&devinfo); | 788 | platform_device_register_full(&devinfo); |
789 | } | 789 | } |
790 | 790 | ||
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 31a6fa40ba37..ec03ec40e9c6 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c | |||
@@ -104,7 +104,7 @@ static int __init zynq_get_revision(void) | |||
104 | */ | 104 | */ |
105 | static void __init zynq_init_machine(void) | 105 | static void __init zynq_init_machine(void) |
106 | { | 106 | { |
107 | struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; | 107 | struct platform_device_info devinfo = { .name = "cpufreq-dt", }; |
108 | struct soc_device_attribute *soc_dev_attr; | 108 | struct soc_device_attribute *soc_dev_attr; |
109 | struct soc_device *soc_dev; | 109 | struct soc_device *soc_dev; |
110 | struct device *parent = NULL; | 110 | struct device *parent = NULL; |
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index ffe350f86bca..3489f8f5fada 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig | |||
@@ -183,14 +183,14 @@ config CPU_FREQ_GOV_CONSERVATIVE | |||
183 | 183 | ||
184 | If in doubt, say N. | 184 | If in doubt, say N. |
185 | 185 | ||
186 | config GENERIC_CPUFREQ_CPU0 | 186 | config CPUFREQ_DT |
187 | tristate "Generic CPU0 cpufreq driver" | 187 | tristate "Generic DT based cpufreq driver" |
188 | depends on HAVE_CLK && OF | 188 | depends on HAVE_CLK && OF |
189 | # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y: | 189 | # if CPU_THERMAL is on and THERMAL=m, CPUFREQ_DT cannot be =y: |
190 | depends on !CPU_THERMAL || THERMAL | 190 | depends on !CPU_THERMAL || THERMAL |
191 | select PM_OPP | 191 | select PM_OPP |
192 | help | 192 | help |
193 | This adds a generic cpufreq driver for CPU0 frequency management. | 193 | This adds a generic DT based cpufreq driver for frequency management. |
194 | It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) | 194 | It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) |
195 | systems which share clock and voltage across all CPUs. | 195 | systems which share clock and voltage across all CPUs. |
196 | 196 | ||
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 7364a538e056..48ed28b789f7 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm | |||
@@ -92,7 +92,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW | |||
92 | 92 | ||
93 | config ARM_HIGHBANK_CPUFREQ | 93 | config ARM_HIGHBANK_CPUFREQ |
94 | tristate "Calxeda Highbank-based" | 94 | tristate "Calxeda Highbank-based" |
95 | depends on ARCH_HIGHBANK && GENERIC_CPUFREQ_CPU0 && REGULATOR | 95 | depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR |
96 | default m | 96 | default m |
97 | help | 97 | help |
98 | This adds the CPUFreq driver for Calxeda Highbank SoC | 98 | This adds the CPUFreq driver for Calxeda Highbank SoC |
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index db6d9a2fea4d..40c53dc1937e 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
@@ -13,7 +13,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o | |||
13 | obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o | 13 | obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o |
14 | obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o | 14 | obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o |
15 | 15 | ||
16 | obj-$(CONFIG_GENERIC_CPUFREQ_CPU0) += cpufreq-cpu0.o | 16 | obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o |
17 | 17 | ||
18 | ################################################################################## | 18 | ################################################################################## |
19 | # x86 drivers. | 19 | # x86 drivers. |
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c deleted file mode 100644 index 0d2172b07765..000000000000 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ /dev/null | |||
@@ -1,248 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * The OPP code in function cpu0_set_target() is reused from | ||
5 | * drivers/cpufreq/omap-cpufreq.c | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/cpu.h> | ||
16 | #include <linux/cpu_cooling.h> | ||
17 | #include <linux/cpufreq.h> | ||
18 | #include <linux/cpumask.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/pm_opp.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/thermal.h> | ||
27 | |||
28 | static unsigned int transition_latency; | ||
29 | static unsigned int voltage_tolerance; /* in percentage */ | ||
30 | |||
31 | static struct device *cpu_dev; | ||
32 | static struct clk *cpu_clk; | ||
33 | static struct regulator *cpu_reg; | ||
34 | static struct cpufreq_frequency_table *freq_table; | ||
35 | static struct thermal_cooling_device *cdev; | ||
36 | |||
37 | static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) | ||
38 | { | ||
39 | struct dev_pm_opp *opp; | ||
40 | unsigned long volt = 0, volt_old = 0, tol = 0; | ||
41 | unsigned int old_freq, new_freq; | ||
42 | long freq_Hz, freq_exact; | ||
43 | int ret; | ||
44 | |||
45 | freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); | ||
46 | if (freq_Hz <= 0) | ||
47 | freq_Hz = freq_table[index].frequency * 1000; | ||
48 | |||
49 | freq_exact = freq_Hz; | ||
50 | new_freq = freq_Hz / 1000; | ||
51 | old_freq = clk_get_rate(cpu_clk) / 1000; | ||
52 | |||
53 | if (!IS_ERR(cpu_reg)) { | ||
54 | rcu_read_lock(); | ||
55 | opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); | ||
56 | if (IS_ERR(opp)) { | ||
57 | rcu_read_unlock(); | ||
58 | pr_err("failed to find OPP for %ld\n", freq_Hz); | ||
59 | return PTR_ERR(opp); | ||
60 | } | ||
61 | volt = dev_pm_opp_get_voltage(opp); | ||
62 | rcu_read_unlock(); | ||
63 | tol = volt * voltage_tolerance / 100; | ||
64 | volt_old = regulator_get_voltage(cpu_reg); | ||
65 | } | ||
66 | |||
67 | pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", | ||
68 | old_freq / 1000, volt_old ? volt_old / 1000 : -1, | ||
69 | new_freq / 1000, volt ? volt / 1000 : -1); | ||
70 | |||
71 | /* scaling up? scale voltage before frequency */ | ||
72 | if (!IS_ERR(cpu_reg) && new_freq > old_freq) { | ||
73 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | ||
74 | if (ret) { | ||
75 | pr_err("failed to scale voltage up: %d\n", ret); | ||
76 | return ret; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | ret = clk_set_rate(cpu_clk, freq_exact); | ||
81 | if (ret) { | ||
82 | pr_err("failed to set clock rate: %d\n", ret); | ||
83 | if (!IS_ERR(cpu_reg)) | ||
84 | regulator_set_voltage_tol(cpu_reg, volt_old, tol); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | /* scaling down? scale voltage after frequency */ | ||
89 | if (!IS_ERR(cpu_reg) && new_freq < old_freq) { | ||
90 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | ||
91 | if (ret) { | ||
92 | pr_err("failed to scale voltage down: %d\n", ret); | ||
93 | clk_set_rate(cpu_clk, old_freq * 1000); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | static int cpu0_cpufreq_init(struct cpufreq_policy *policy) | ||
101 | { | ||
102 | policy->clk = cpu_clk; | ||
103 | return cpufreq_generic_init(policy, freq_table, transition_latency); | ||
104 | } | ||
105 | |||
106 | static struct cpufreq_driver cpu0_cpufreq_driver = { | ||
107 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, | ||
108 | .verify = cpufreq_generic_frequency_table_verify, | ||
109 | .target_index = cpu0_set_target, | ||
110 | .get = cpufreq_generic_get, | ||
111 | .init = cpu0_cpufreq_init, | ||
112 | .name = "generic_cpu0", | ||
113 | .attr = cpufreq_generic_attr, | ||
114 | }; | ||
115 | |||
116 | static int cpu0_cpufreq_probe(struct platform_device *pdev) | ||
117 | { | ||
118 | struct device_node *np; | ||
119 | int ret; | ||
120 | |||
121 | cpu_dev = get_cpu_device(0); | ||
122 | if (!cpu_dev) { | ||
123 | pr_err("failed to get cpu0 device\n"); | ||
124 | return -ENODEV; | ||
125 | } | ||
126 | |||
127 | np = of_node_get(cpu_dev->of_node); | ||
128 | if (!np) { | ||
129 | pr_err("failed to find cpu0 node\n"); | ||
130 | return -ENOENT; | ||
131 | } | ||
132 | |||
133 | cpu_reg = regulator_get_optional(cpu_dev, "cpu0"); | ||
134 | if (IS_ERR(cpu_reg)) { | ||
135 | /* | ||
136 | * If cpu0 regulator supply node is present, but regulator is | ||
137 | * not yet registered, we should try defering probe. | ||
138 | */ | ||
139 | if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) { | ||
140 | dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n"); | ||
141 | ret = -EPROBE_DEFER; | ||
142 | goto out_put_node; | ||
143 | } | ||
144 | pr_warn("failed to get cpu0 regulator: %ld\n", | ||
145 | PTR_ERR(cpu_reg)); | ||
146 | } | ||
147 | |||
148 | cpu_clk = clk_get(cpu_dev, NULL); | ||
149 | if (IS_ERR(cpu_clk)) { | ||
150 | ret = PTR_ERR(cpu_clk); | ||
151 | pr_err("failed to get cpu0 clock: %d\n", ret); | ||
152 | goto out_put_reg; | ||
153 | } | ||
154 | |||
155 | /* OPPs might be populated at runtime, don't check for error here */ | ||
156 | of_init_opp_table(cpu_dev); | ||
157 | |||
158 | ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); | ||
159 | if (ret) { | ||
160 | pr_err("failed to init cpufreq table: %d\n", ret); | ||
161 | goto out_put_clk; | ||
162 | } | ||
163 | |||
164 | of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance); | ||
165 | |||
166 | if (of_property_read_u32(np, "clock-latency", &transition_latency)) | ||
167 | transition_latency = CPUFREQ_ETERNAL; | ||
168 | |||
169 | if (!IS_ERR(cpu_reg)) { | ||
170 | struct dev_pm_opp *opp; | ||
171 | unsigned long min_uV, max_uV; | ||
172 | int i; | ||
173 | |||
174 | /* | ||
175 | * OPP is maintained in order of increasing frequency, and | ||
176 | * freq_table initialised from OPP is therefore sorted in the | ||
177 | * same order. | ||
178 | */ | ||
179 | for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) | ||
180 | ; | ||
181 | rcu_read_lock(); | ||
182 | opp = dev_pm_opp_find_freq_exact(cpu_dev, | ||
183 | freq_table[0].frequency * 1000, true); | ||
184 | min_uV = dev_pm_opp_get_voltage(opp); | ||
185 | opp = dev_pm_opp_find_freq_exact(cpu_dev, | ||
186 | freq_table[i-1].frequency * 1000, true); | ||
187 | max_uV = dev_pm_opp_get_voltage(opp); | ||
188 | rcu_read_unlock(); | ||
189 | ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); | ||
190 | if (ret > 0) | ||
191 | transition_latency += ret * 1000; | ||
192 | } | ||
193 | |||
194 | ret = cpufreq_register_driver(&cpu0_cpufreq_driver); | ||
195 | if (ret) { | ||
196 | pr_err("failed register driver: %d\n", ret); | ||
197 | goto out_free_table; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * For now, just loading the cooling device; | ||
202 | * thermal DT code takes care of matching them. | ||
203 | */ | ||
204 | if (of_find_property(np, "#cooling-cells", NULL)) { | ||
205 | cdev = of_cpufreq_cooling_register(np, cpu_present_mask); | ||
206 | if (IS_ERR(cdev)) | ||
207 | pr_err("running cpufreq without cooling device: %ld\n", | ||
208 | PTR_ERR(cdev)); | ||
209 | } | ||
210 | |||
211 | of_node_put(np); | ||
212 | return 0; | ||
213 | |||
214 | out_free_table: | ||
215 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); | ||
216 | out_put_clk: | ||
217 | if (!IS_ERR(cpu_clk)) | ||
218 | clk_put(cpu_clk); | ||
219 | out_put_reg: | ||
220 | if (!IS_ERR(cpu_reg)) | ||
221 | regulator_put(cpu_reg); | ||
222 | out_put_node: | ||
223 | of_node_put(np); | ||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | static int cpu0_cpufreq_remove(struct platform_device *pdev) | ||
228 | { | ||
229 | cpufreq_cooling_unregister(cdev); | ||
230 | cpufreq_unregister_driver(&cpu0_cpufreq_driver); | ||
231 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static struct platform_driver cpu0_cpufreq_platdrv = { | ||
237 | .driver = { | ||
238 | .name = "cpufreq-cpu0", | ||
239 | .owner = THIS_MODULE, | ||
240 | }, | ||
241 | .probe = cpu0_cpufreq_probe, | ||
242 | .remove = cpu0_cpufreq_remove, | ||
243 | }; | ||
244 | module_platform_driver(cpu0_cpufreq_platdrv); | ||
245 | |||
246 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); | ||
247 | MODULE_DESCRIPTION("Generic CPU0 cpufreq driver"); | ||
248 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c new file mode 100644 index 000000000000..6bbb8b913446 --- /dev/null +++ b/drivers/cpufreq/cpufreq-dt.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * Copyright (C) 2014 Linaro. | ||
5 | * Viresh Kumar <viresh.kumar@linaro.org> | ||
6 | * | ||
7 | * The OPP code in function set_target() is reused from | ||
8 | * drivers/cpufreq/omap-cpufreq.c | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/cpu.h> | ||
19 | #include <linux/cpu_cooling.h> | ||
20 | #include <linux/cpufreq.h> | ||
21 | #include <linux/cpumask.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/pm_opp.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/regulator/consumer.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/thermal.h> | ||
30 | |||
31 | struct private_data { | ||
32 | struct device *cpu_dev; | ||
33 | struct regulator *cpu_reg; | ||
34 | struct thermal_cooling_device *cdev; | ||
35 | unsigned int voltage_tolerance; /* in percentage */ | ||
36 | }; | ||
37 | |||
38 | static int set_target(struct cpufreq_policy *policy, unsigned int index) | ||
39 | { | ||
40 | struct dev_pm_opp *opp; | ||
41 | struct cpufreq_frequency_table *freq_table = policy->freq_table; | ||
42 | struct clk *cpu_clk = policy->clk; | ||
43 | struct private_data *priv = policy->driver_data; | ||
44 | struct device *cpu_dev = priv->cpu_dev; | ||
45 | struct regulator *cpu_reg = priv->cpu_reg; | ||
46 | unsigned long volt = 0, volt_old = 0, tol = 0; | ||
47 | unsigned int old_freq, new_freq; | ||
48 | long freq_Hz, freq_exact; | ||
49 | int ret; | ||
50 | |||
51 | freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); | ||
52 | if (freq_Hz <= 0) | ||
53 | freq_Hz = freq_table[index].frequency * 1000; | ||
54 | |||
55 | freq_exact = freq_Hz; | ||
56 | new_freq = freq_Hz / 1000; | ||
57 | old_freq = clk_get_rate(cpu_clk) / 1000; | ||
58 | |||
59 | if (!IS_ERR(cpu_reg)) { | ||
60 | rcu_read_lock(); | ||
61 | opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); | ||
62 | if (IS_ERR(opp)) { | ||
63 | rcu_read_unlock(); | ||
64 | dev_err(cpu_dev, "failed to find OPP for %ld\n", | ||
65 | freq_Hz); | ||
66 | return PTR_ERR(opp); | ||
67 | } | ||
68 | volt = dev_pm_opp_get_voltage(opp); | ||
69 | rcu_read_unlock(); | ||
70 | tol = volt * priv->voltage_tolerance / 100; | ||
71 | volt_old = regulator_get_voltage(cpu_reg); | ||
72 | } | ||
73 | |||
74 | dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", | ||
75 | old_freq / 1000, volt_old ? volt_old / 1000 : -1, | ||
76 | new_freq / 1000, volt ? volt / 1000 : -1); | ||
77 | |||
78 | /* scaling up? scale voltage before frequency */ | ||
79 | if (!IS_ERR(cpu_reg) && new_freq > old_freq) { | ||
80 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | ||
81 | if (ret) { | ||
82 | dev_err(cpu_dev, "failed to scale voltage up: %d\n", | ||
83 | ret); | ||
84 | return ret; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | ret = clk_set_rate(cpu_clk, freq_exact); | ||
89 | if (ret) { | ||
90 | dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); | ||
91 | if (!IS_ERR(cpu_reg)) | ||
92 | regulator_set_voltage_tol(cpu_reg, volt_old, tol); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | /* scaling down? scale voltage after frequency */ | ||
97 | if (!IS_ERR(cpu_reg) && new_freq < old_freq) { | ||
98 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | ||
99 | if (ret) { | ||
100 | dev_err(cpu_dev, "failed to scale voltage down: %d\n", | ||
101 | ret); | ||
102 | clk_set_rate(cpu_clk, old_freq * 1000); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | static int allocate_resources(int cpu, struct device **cdev, | ||
110 | struct regulator **creg, struct clk **cclk) | ||
111 | { | ||
112 | struct device *cpu_dev; | ||
113 | struct regulator *cpu_reg; | ||
114 | struct clk *cpu_clk; | ||
115 | int ret = 0; | ||
116 | char *reg_cpu0 = "cpu0", *reg_cpu = "cpu", *reg; | ||
117 | |||
118 | cpu_dev = get_cpu_device(cpu); | ||
119 | if (!cpu_dev) { | ||
120 | pr_err("failed to get cpu%d device\n", cpu); | ||
121 | return -ENODEV; | ||
122 | } | ||
123 | |||
124 | /* Try "cpu0" for older DTs */ | ||
125 | if (!cpu) | ||
126 | reg = reg_cpu0; | ||
127 | else | ||
128 | reg = reg_cpu; | ||
129 | |||
130 | try_again: | ||
131 | cpu_reg = regulator_get_optional(cpu_dev, reg); | ||
132 | if (IS_ERR(cpu_reg)) { | ||
133 | /* | ||
134 | * If cpu's regulator supply node is present, but regulator is | ||
135 | * not yet registered, we should try defering probe. | ||
136 | */ | ||
137 | if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) { | ||
138 | dev_dbg(cpu_dev, "cpu%d regulator not ready, retry\n", | ||
139 | cpu); | ||
140 | return -EPROBE_DEFER; | ||
141 | } | ||
142 | |||
143 | /* Try with "cpu-supply" */ | ||
144 | if (reg == reg_cpu0) { | ||
145 | reg = reg_cpu; | ||
146 | goto try_again; | ||
147 | } | ||
148 | |||
149 | dev_warn(cpu_dev, "failed to get cpu%d regulator: %ld\n", | ||
150 | cpu, PTR_ERR(cpu_reg)); | ||
151 | } | ||
152 | |||
153 | cpu_clk = clk_get(cpu_dev, NULL); | ||
154 | if (IS_ERR(cpu_clk)) { | ||
155 | /* put regulator */ | ||
156 | if (!IS_ERR(cpu_reg)) | ||
157 | regulator_put(cpu_reg); | ||
158 | |||
159 | ret = PTR_ERR(cpu_clk); | ||
160 | |||
161 | /* | ||
162 | * If cpu's clk node is present, but clock is not yet | ||
163 | * registered, we should try defering probe. | ||
164 | */ | ||
165 | if (ret == -EPROBE_DEFER) | ||
166 | dev_dbg(cpu_dev, "cpu%d clock not ready, retry\n", cpu); | ||
167 | else | ||
168 | dev_err(cpu_dev, "failed to get cpu%d clock: %d\n", ret, | ||
169 | cpu); | ||
170 | } else { | ||
171 | *cdev = cpu_dev; | ||
172 | *creg = cpu_reg; | ||
173 | *cclk = cpu_clk; | ||
174 | } | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int cpufreq_init(struct cpufreq_policy *policy) | ||
180 | { | ||
181 | struct cpufreq_frequency_table *freq_table; | ||
182 | struct thermal_cooling_device *cdev; | ||
183 | struct device_node *np; | ||
184 | struct private_data *priv; | ||
185 | struct device *cpu_dev; | ||
186 | struct regulator *cpu_reg; | ||
187 | struct clk *cpu_clk; | ||
188 | unsigned int transition_latency; | ||
189 | int ret; | ||
190 | |||
191 | ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk); | ||
192 | if (ret) { | ||
193 | pr_err("%s: Failed to allocate resources\n: %d", __func__, ret); | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | np = of_node_get(cpu_dev->of_node); | ||
198 | if (!np) { | ||
199 | dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu); | ||
200 | ret = -ENOENT; | ||
201 | goto out_put_reg_clk; | ||
202 | } | ||
203 | |||
204 | /* OPPs might be populated at runtime, don't check for error here */ | ||
205 | of_init_opp_table(cpu_dev); | ||
206 | |||
207 | ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); | ||
208 | if (ret) { | ||
209 | dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); | ||
210 | goto out_put_node; | ||
211 | } | ||
212 | |||
213 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
214 | if (!priv) { | ||
215 | ret = -ENOMEM; | ||
216 | goto out_free_table; | ||
217 | } | ||
218 | |||
219 | of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance); | ||
220 | |||
221 | if (of_property_read_u32(np, "clock-latency", &transition_latency)) | ||
222 | transition_latency = CPUFREQ_ETERNAL; | ||
223 | |||
224 | if (!IS_ERR(cpu_reg)) { | ||
225 | struct dev_pm_opp *opp; | ||
226 | unsigned long min_uV, max_uV; | ||
227 | int i; | ||
228 | |||
229 | /* | ||
230 | * OPP is maintained in order of increasing frequency, and | ||
231 | * freq_table initialised from OPP is therefore sorted in the | ||
232 | * same order. | ||
233 | */ | ||
234 | for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) | ||
235 | ; | ||
236 | rcu_read_lock(); | ||
237 | opp = dev_pm_opp_find_freq_exact(cpu_dev, | ||
238 | freq_table[0].frequency * 1000, true); | ||
239 | min_uV = dev_pm_opp_get_voltage(opp); | ||
240 | opp = dev_pm_opp_find_freq_exact(cpu_dev, | ||
241 | freq_table[i-1].frequency * 1000, true); | ||
242 | max_uV = dev_pm_opp_get_voltage(opp); | ||
243 | rcu_read_unlock(); | ||
244 | ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); | ||
245 | if (ret > 0) | ||
246 | transition_latency += ret * 1000; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * For now, just loading the cooling device; | ||
251 | * thermal DT code takes care of matching them. | ||
252 | */ | ||
253 | if (of_find_property(np, "#cooling-cells", NULL)) { | ||
254 | cdev = of_cpufreq_cooling_register(np, cpu_present_mask); | ||
255 | if (IS_ERR(cdev)) | ||
256 | dev_err(cpu_dev, | ||
257 | "running cpufreq without cooling device: %ld\n", | ||
258 | PTR_ERR(cdev)); | ||
259 | else | ||
260 | priv->cdev = cdev; | ||
261 | } | ||
262 | |||
263 | priv->cpu_dev = cpu_dev; | ||
264 | priv->cpu_reg = cpu_reg; | ||
265 | policy->driver_data = priv; | ||
266 | |||
267 | policy->clk = cpu_clk; | ||
268 | ret = cpufreq_generic_init(policy, freq_table, transition_latency); | ||
269 | if (ret) | ||
270 | goto out_cooling_unregister; | ||
271 | |||
272 | of_node_put(np); | ||
273 | |||
274 | return 0; | ||
275 | |||
276 | out_cooling_unregister: | ||
277 | cpufreq_cooling_unregister(priv->cdev); | ||
278 | kfree(priv); | ||
279 | out_free_table: | ||
280 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); | ||
281 | out_put_node: | ||
282 | of_node_put(np); | ||
283 | out_put_reg_clk: | ||
284 | clk_put(cpu_clk); | ||
285 | if (!IS_ERR(cpu_reg)) | ||
286 | regulator_put(cpu_reg); | ||
287 | |||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static int cpufreq_exit(struct cpufreq_policy *policy) | ||
292 | { | ||
293 | struct private_data *priv = policy->driver_data; | ||
294 | |||
295 | cpufreq_cooling_unregister(priv->cdev); | ||
296 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); | ||
297 | clk_put(policy->clk); | ||
298 | if (!IS_ERR(priv->cpu_reg)) | ||
299 | regulator_put(priv->cpu_reg); | ||
300 | kfree(priv); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static struct cpufreq_driver dt_cpufreq_driver = { | ||
306 | .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, | ||
307 | .verify = cpufreq_generic_frequency_table_verify, | ||
308 | .target_index = set_target, | ||
309 | .get = cpufreq_generic_get, | ||
310 | .init = cpufreq_init, | ||
311 | .exit = cpufreq_exit, | ||
312 | .name = "cpufreq-dt", | ||
313 | .attr = cpufreq_generic_attr, | ||
314 | }; | ||
315 | |||
316 | static int dt_cpufreq_probe(struct platform_device *pdev) | ||
317 | { | ||
318 | struct device *cpu_dev; | ||
319 | struct regulator *cpu_reg; | ||
320 | struct clk *cpu_clk; | ||
321 | int ret; | ||
322 | |||
323 | /* | ||
324 | * All per-cluster (CPUs sharing clock/voltages) initialization is done | ||
325 | * from ->init(). In probe(), we just need to make sure that clk and | ||
326 | * regulators are available. Else defer probe and retry. | ||
327 | * | ||
328 | * FIXME: Is checking this only for CPU0 sufficient ? | ||
329 | */ | ||
330 | ret = allocate_resources(0, &cpu_dev, &cpu_reg, &cpu_clk); | ||
331 | if (ret) | ||
332 | return ret; | ||
333 | |||
334 | clk_put(cpu_clk); | ||
335 | if (!IS_ERR(cpu_reg)) | ||
336 | regulator_put(cpu_reg); | ||
337 | |||
338 | ret = cpufreq_register_driver(&dt_cpufreq_driver); | ||
339 | if (ret) | ||
340 | dev_err(cpu_dev, "failed register driver: %d\n", ret); | ||
341 | |||
342 | return ret; | ||
343 | } | ||
344 | |||
345 | static int dt_cpufreq_remove(struct platform_device *pdev) | ||
346 | { | ||
347 | cpufreq_unregister_driver(&dt_cpufreq_driver); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static struct platform_driver dt_cpufreq_platdrv = { | ||
352 | .driver = { | ||
353 | .name = "cpufreq-dt", | ||
354 | .owner = THIS_MODULE, | ||
355 | }, | ||
356 | .probe = dt_cpufreq_probe, | ||
357 | .remove = dt_cpufreq_remove, | ||
358 | }; | ||
359 | module_platform_driver(dt_cpufreq_platdrv); | ||
360 | |||
361 | MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); | ||
362 | MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); | ||
363 | MODULE_DESCRIPTION("Generic cpufreq driver"); | ||
364 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 61190f6b4829..24bf76fba141 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -437,7 +437,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor) | |||
437 | struct cpufreq_governor *t; | 437 | struct cpufreq_governor *t; |
438 | 438 | ||
439 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) | 439 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) |
440 | if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN)) | 440 | if (!strncasecmp(str_governor, t->name, CPUFREQ_NAME_LEN)) |
441 | return t; | 441 | return t; |
442 | 442 | ||
443 | return NULL; | 443 | return NULL; |
@@ -455,10 +455,10 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, | |||
455 | goto out; | 455 | goto out; |
456 | 456 | ||
457 | if (cpufreq_driver->setpolicy) { | 457 | if (cpufreq_driver->setpolicy) { |
458 | if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { | 458 | if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { |
459 | *policy = CPUFREQ_POLICY_PERFORMANCE; | 459 | *policy = CPUFREQ_POLICY_PERFORMANCE; |
460 | err = 0; | 460 | err = 0; |
461 | } else if (!strnicmp(str_governor, "powersave", | 461 | } else if (!strncasecmp(str_governor, "powersave", |
462 | CPUFREQ_NAME_LEN)) { | 462 | CPUFREQ_NAME_LEN)) { |
463 | *policy = CPUFREQ_POLICY_POWERSAVE; | 463 | *policy = CPUFREQ_POLICY_POWERSAVE; |
464 | err = 0; | 464 | err = 0; |
@@ -1382,7 +1382,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
1382 | if (!cpufreq_suspended) | 1382 | if (!cpufreq_suspended) |
1383 | pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", | 1383 | pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", |
1384 | __func__, new_cpu, cpu); | 1384 | __func__, new_cpu, cpu); |
1385 | } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) { | 1385 | } else if (cpufreq_driver->stop_cpu) { |
1386 | cpufreq_driver->stop_cpu(policy); | 1386 | cpufreq_driver->stop_cpu(policy); |
1387 | } | 1387 | } |
1388 | 1388 | ||
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c b/drivers/cpufreq/exynos4210-cpufreq.c index 61a54310a1b9..843ec824fd91 100644 --- a/drivers/cpufreq/exynos4210-cpufreq.c +++ b/drivers/cpufreq/exynos4210-cpufreq.c | |||
@@ -127,7 +127,7 @@ int exynos4210_cpufreq_init(struct exynos_dvfs_info *info) | |||
127 | * dependencies on platform headers. It is necessary to enable | 127 | * dependencies on platform headers. It is necessary to enable |
128 | * Exynos multi-platform support and will be removed together with | 128 | * Exynos multi-platform support and will be removed together with |
129 | * this whole driver as soon as Exynos gets migrated to use | 129 | * this whole driver as soon as Exynos gets migrated to use |
130 | * cpufreq-cpu0 driver. | 130 | * cpufreq-dt driver. |
131 | */ | 131 | */ |
132 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-clock"); | 132 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos4210-clock"); |
133 | if (!np) { | 133 | if (!np) { |
diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index 351a2074cfea..9e78a850e29f 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c | |||
@@ -174,7 +174,7 @@ int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info) | |||
174 | * dependencies on platform headers. It is necessary to enable | 174 | * dependencies on platform headers. It is necessary to enable |
175 | * Exynos multi-platform support and will be removed together with | 175 | * Exynos multi-platform support and will be removed together with |
176 | * this whole driver as soon as Exynos gets migrated to use | 176 | * this whole driver as soon as Exynos gets migrated to use |
177 | * cpufreq-cpu0 driver. | 177 | * cpufreq-dt driver. |
178 | */ | 178 | */ |
179 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos4412-clock"); | 179 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos4412-clock"); |
180 | if (!np) { | 180 | if (!np) { |
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c index c91ce69dc631..3eafdc7ba787 100644 --- a/drivers/cpufreq/exynos5250-cpufreq.c +++ b/drivers/cpufreq/exynos5250-cpufreq.c | |||
@@ -153,7 +153,7 @@ int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) | |||
153 | * dependencies on platform headers. It is necessary to enable | 153 | * dependencies on platform headers. It is necessary to enable |
154 | * Exynos multi-platform support and will be removed together with | 154 | * Exynos multi-platform support and will be removed together with |
155 | * this whole driver as soon as Exynos gets migrated to use | 155 | * this whole driver as soon as Exynos gets migrated to use |
156 | * cpufreq-cpu0 driver. | 156 | * cpufreq-dt driver. |
157 | */ | 157 | */ |
158 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock"); | 158 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock"); |
159 | if (!np) { | 159 | if (!np) { |
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c index bf8902a0866d..ec399ad2f059 100644 --- a/drivers/cpufreq/highbank-cpufreq.c +++ b/drivers/cpufreq/highbank-cpufreq.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * This driver provides the clk notifier callbacks that are used when | 8 | * This driver provides the clk notifier callbacks that are used when |
9 | * the cpufreq-cpu0 driver changes to frequency to alert the highbank | 9 | * the cpufreq-dt driver changes to frequency to alert the highbank |
10 | * EnergyCore Management Engine (ECME) about the need to change | 10 | * EnergyCore Management Engine (ECME) about the need to change |
11 | * voltage. The ECME interfaces with the actual voltage regulators. | 11 | * voltage. The ECME interfaces with the actual voltage regulators. |
12 | */ | 12 | */ |
@@ -60,7 +60,7 @@ static struct notifier_block hb_cpufreq_clk_nb = { | |||
60 | 60 | ||
61 | static int hb_cpufreq_driver_init(void) | 61 | static int hb_cpufreq_driver_init(void) |
62 | { | 62 | { |
63 | struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; | 63 | struct platform_device_info devinfo = { .name = "cpufreq-dt", }; |
64 | struct device *cpu_dev; | 64 | struct device *cpu_dev; |
65 | struct clk *cpu_clk; | 65 | struct clk *cpu_clk; |
66 | struct device_node *np; | 66 | struct device_node *np; |
@@ -95,7 +95,7 @@ static int hb_cpufreq_driver_init(void) | |||
95 | goto out_put_node; | 95 | goto out_put_node; |
96 | } | 96 | } |
97 | 97 | ||
98 | /* Instantiate cpufreq-cpu0 */ | 98 | /* Instantiate cpufreq-dt */ |
99 | platform_device_register_full(&devinfo); | 99 | platform_device_register_full(&devinfo); |
100 | 100 | ||
101 | out_put_node: | 101 | out_put_node: |
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 379c0837f5a9..2dfd4fdb5a52 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/cpufreq.h> | 26 | #include <linux/cpufreq.h> |
27 | #include <linux/smp.h> | 27 | #include <linux/smp.h> |
28 | #include <linux/of.h> | 28 | #include <linux/of.h> |
29 | #include <linux/reboot.h> | ||
29 | 30 | ||
30 | #include <asm/cputhreads.h> | 31 | #include <asm/cputhreads.h> |
31 | #include <asm/firmware.h> | 32 | #include <asm/firmware.h> |
@@ -35,6 +36,7 @@ | |||
35 | #define POWERNV_MAX_PSTATES 256 | 36 | #define POWERNV_MAX_PSTATES 256 |
36 | 37 | ||
37 | static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; | 38 | static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; |
39 | static bool rebooting; | ||
38 | 40 | ||
39 | /* | 41 | /* |
40 | * Note: The set of pstates consists of contiguous integers, the | 42 | * Note: The set of pstates consists of contiguous integers, the |
@@ -284,6 +286,15 @@ static void set_pstate(void *freq_data) | |||
284 | } | 286 | } |
285 | 287 | ||
286 | /* | 288 | /* |
289 | * get_nominal_index: Returns the index corresponding to the nominal | ||
290 | * pstate in the cpufreq table | ||
291 | */ | ||
292 | static inline unsigned int get_nominal_index(void) | ||
293 | { | ||
294 | return powernv_pstate_info.max - powernv_pstate_info.nominal; | ||
295 | } | ||
296 | |||
297 | /* | ||
287 | * powernv_cpufreq_target_index: Sets the frequency corresponding to | 298 | * powernv_cpufreq_target_index: Sets the frequency corresponding to |
288 | * the cpufreq table entry indexed by new_index on the cpus in the | 299 | * the cpufreq table entry indexed by new_index on the cpus in the |
289 | * mask policy->cpus | 300 | * mask policy->cpus |
@@ -293,6 +304,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, | |||
293 | { | 304 | { |
294 | struct powernv_smp_call_data freq_data; | 305 | struct powernv_smp_call_data freq_data; |
295 | 306 | ||
307 | if (unlikely(rebooting) && new_index != get_nominal_index()) | ||
308 | return 0; | ||
309 | |||
296 | freq_data.pstate_id = powernv_freqs[new_index].driver_data; | 310 | freq_data.pstate_id = powernv_freqs[new_index].driver_data; |
297 | 311 | ||
298 | /* | 312 | /* |
@@ -317,6 +331,33 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
317 | return cpufreq_table_validate_and_show(policy, powernv_freqs); | 331 | return cpufreq_table_validate_and_show(policy, powernv_freqs); |
318 | } | 332 | } |
319 | 333 | ||
334 | static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb, | ||
335 | unsigned long action, void *unused) | ||
336 | { | ||
337 | int cpu; | ||
338 | struct cpufreq_policy cpu_policy; | ||
339 | |||
340 | rebooting = true; | ||
341 | for_each_online_cpu(cpu) { | ||
342 | cpufreq_get_policy(&cpu_policy, cpu); | ||
343 | powernv_cpufreq_target_index(&cpu_policy, get_nominal_index()); | ||
344 | } | ||
345 | |||
346 | return NOTIFY_DONE; | ||
347 | } | ||
348 | |||
349 | static struct notifier_block powernv_cpufreq_reboot_nb = { | ||
350 | .notifier_call = powernv_cpufreq_reboot_notifier, | ||
351 | }; | ||
352 | |||
353 | static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy) | ||
354 | { | ||
355 | struct powernv_smp_call_data freq_data; | ||
356 | |||
357 | freq_data.pstate_id = powernv_pstate_info.min; | ||
358 | smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1); | ||
359 | } | ||
360 | |||
320 | static struct cpufreq_driver powernv_cpufreq_driver = { | 361 | static struct cpufreq_driver powernv_cpufreq_driver = { |
321 | .name = "powernv-cpufreq", | 362 | .name = "powernv-cpufreq", |
322 | .flags = CPUFREQ_CONST_LOOPS, | 363 | .flags = CPUFREQ_CONST_LOOPS, |
@@ -324,6 +365,7 @@ static struct cpufreq_driver powernv_cpufreq_driver = { | |||
324 | .verify = cpufreq_generic_frequency_table_verify, | 365 | .verify = cpufreq_generic_frequency_table_verify, |
325 | .target_index = powernv_cpufreq_target_index, | 366 | .target_index = powernv_cpufreq_target_index, |
326 | .get = powernv_cpufreq_get, | 367 | .get = powernv_cpufreq_get, |
368 | .stop_cpu = powernv_cpufreq_stop_cpu, | ||
327 | .attr = powernv_cpu_freq_attr, | 369 | .attr = powernv_cpu_freq_attr, |
328 | }; | 370 | }; |
329 | 371 | ||
@@ -342,12 +384,14 @@ static int __init powernv_cpufreq_init(void) | |||
342 | return rc; | 384 | return rc; |
343 | } | 385 | } |
344 | 386 | ||
387 | register_reboot_notifier(&powernv_cpufreq_reboot_nb); | ||
345 | return cpufreq_register_driver(&powernv_cpufreq_driver); | 388 | return cpufreq_register_driver(&powernv_cpufreq_driver); |
346 | } | 389 | } |
347 | module_init(powernv_cpufreq_init); | 390 | module_init(powernv_cpufreq_init); |
348 | 391 | ||
349 | static void __exit powernv_cpufreq_exit(void) | 392 | static void __exit powernv_cpufreq_exit(void) |
350 | { | 393 | { |
394 | unregister_reboot_notifier(&powernv_cpufreq_reboot_nb); | ||
351 | cpufreq_unregister_driver(&powernv_cpufreq_driver); | 395 | cpufreq_unregister_driver(&powernv_cpufreq_driver); |
352 | } | 396 | } |
353 | module_exit(powernv_cpufreq_exit); | 397 | module_exit(powernv_cpufreq_exit); |
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c index 3607070797af..bee5df7794d3 100644 --- a/drivers/cpufreq/ppc-corenet-cpufreq.c +++ b/drivers/cpufreq/ppc-corenet-cpufreq.c | |||
@@ -199,7 +199,6 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
199 | } | 199 | } |
200 | 200 | ||
201 | data->table = table; | 201 | data->table = table; |
202 | per_cpu(cpu_data, cpu) = data; | ||
203 | 202 | ||
204 | /* update ->cpus if we have cluster, no harm if not */ | 203 | /* update ->cpus if we have cluster, no harm if not */ |
205 | cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu)); | 204 | cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu)); |
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 3f9791f07b8e..567caa6313ff 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c | |||
@@ -597,7 +597,7 @@ static int s5pv210_cpufreq_probe(struct platform_device *pdev) | |||
597 | * and dependencies on platform headers. It is necessary to enable | 597 | * and dependencies on platform headers. It is necessary to enable |
598 | * S5PV210 multi-platform support and will be removed together with | 598 | * S5PV210 multi-platform support and will be removed together with |
599 | * this whole driver as soon as S5PV210 gets migrated to use | 599 | * this whole driver as soon as S5PV210 gets migrated to use |
600 | * cpufreq-cpu0 driver. | 600 | * cpufreq-dt driver. |
601 | */ | 601 | */ |
602 | np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); | 602 | np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock"); |
603 | if (!np) { | 603 | if (!np) { |
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 7d1955afa62c..138336b6bb04 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
@@ -112,6 +112,9 @@ struct cpufreq_policy { | |||
112 | spinlock_t transition_lock; | 112 | spinlock_t transition_lock; |
113 | wait_queue_head_t transition_wait; | 113 | wait_queue_head_t transition_wait; |
114 | struct task_struct *transition_task; /* Task which is doing the transition */ | 114 | struct task_struct *transition_task; /* Task which is doing the transition */ |
115 | |||
116 | /* For cpufreq driver's internal use */ | ||
117 | void *driver_data; | ||
115 | }; | 118 | }; |
116 | 119 | ||
117 | /* Only for ACPI */ | 120 | /* Only for ACPI */ |