diff options
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra.c | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index fea5719c7072..ad26a9f3a134 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/err.h> | 28 | #include <linux/err.h> |
29 | #include <linux/clk.h> | 29 | #include <linux/clk.h> |
30 | #include <linux/io.h> | 30 | #include <linux/io.h> |
31 | #include <linux/suspend.h> | ||
31 | 32 | ||
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
33 | 34 | ||
@@ -36,14 +37,15 @@ | |||
36 | 37 | ||
37 | /* Frequency table index must be sequential starting at 0 */ | 38 | /* Frequency table index must be sequential starting at 0 */ |
38 | static struct cpufreq_frequency_table freq_table[] = { | 39 | static struct cpufreq_frequency_table freq_table[] = { |
39 | { 0, 312000 }, | 40 | { 0, 216000 }, |
40 | { 1, 456000 }, | 41 | { 1, 312000 }, |
41 | { 2, 608000 }, | 42 | { 2, 456000 }, |
42 | { 3, 760000 }, | 43 | { 3, 608000 }, |
43 | { 4, 816000 }, | 44 | { 4, 760000 }, |
44 | { 5, 912000 }, | 45 | { 5, 816000 }, |
45 | { 6, 1000000 }, | 46 | { 6, 912000 }, |
46 | { 7, CPUFREQ_TABLE_END }, | 47 | { 7, 1000000 }, |
48 | { 8, CPUFREQ_TABLE_END }, | ||
47 | }; | 49 | }; |
48 | 50 | ||
49 | #define NUM_CPUS 2 | 51 | #define NUM_CPUS 2 |
@@ -51,6 +53,8 @@ static struct cpufreq_frequency_table freq_table[] = { | |||
51 | static struct clk *cpu_clk; | 53 | static struct clk *cpu_clk; |
52 | 54 | ||
53 | static unsigned long target_cpu_speed[NUM_CPUS]; | 55 | static unsigned long target_cpu_speed[NUM_CPUS]; |
56 | static DEFINE_MUTEX(tegra_cpu_lock); | ||
57 | static bool is_suspended; | ||
54 | 58 | ||
55 | int tegra_verify_speed(struct cpufreq_policy *policy) | 59 | int tegra_verify_speed(struct cpufreq_policy *policy) |
56 | { | 60 | { |
@@ -68,16 +72,11 @@ unsigned int tegra_getspeed(unsigned int cpu) | |||
68 | return rate; | 72 | return rate; |
69 | } | 73 | } |
70 | 74 | ||
71 | static int tegra_update_cpu_speed(void) | 75 | static int tegra_update_cpu_speed(unsigned long rate) |
72 | { | 76 | { |
73 | int i; | ||
74 | unsigned long rate = 0; | ||
75 | int ret = 0; | 77 | int ret = 0; |
76 | struct cpufreq_freqs freqs; | 78 | struct cpufreq_freqs freqs; |
77 | 79 | ||
78 | for_each_online_cpu(i) | ||
79 | rate = max(rate, target_cpu_speed[i]); | ||
80 | |||
81 | freqs.old = tegra_getspeed(0); | 80 | freqs.old = tegra_getspeed(0); |
82 | freqs.new = rate; | 81 | freqs.new = rate; |
83 | 82 | ||
@@ -105,12 +104,30 @@ static int tegra_update_cpu_speed(void) | |||
105 | return 0; | 104 | return 0; |
106 | } | 105 | } |
107 | 106 | ||
107 | static unsigned long tegra_cpu_highest_speed(void) | ||
108 | { | ||
109 | unsigned long rate = 0; | ||
110 | int i; | ||
111 | |||
112 | for_each_online_cpu(i) | ||
113 | rate = max(rate, target_cpu_speed[i]); | ||
114 | return rate; | ||
115 | } | ||
116 | |||
108 | static int tegra_target(struct cpufreq_policy *policy, | 117 | static int tegra_target(struct cpufreq_policy *policy, |
109 | unsigned int target_freq, | 118 | unsigned int target_freq, |
110 | unsigned int relation) | 119 | unsigned int relation) |
111 | { | 120 | { |
112 | int idx; | 121 | int idx; |
113 | unsigned int freq; | 122 | unsigned int freq; |
123 | int ret = 0; | ||
124 | |||
125 | mutex_lock(&tegra_cpu_lock); | ||
126 | |||
127 | if (is_suspended) { | ||
128 | ret = -EBUSY; | ||
129 | goto out; | ||
130 | } | ||
114 | 131 | ||
115 | cpufreq_frequency_table_target(policy, freq_table, target_freq, | 132 | cpufreq_frequency_table_target(policy, freq_table, target_freq, |
116 | relation, &idx); | 133 | relation, &idx); |
@@ -119,9 +136,34 @@ static int tegra_target(struct cpufreq_policy *policy, | |||
119 | 136 | ||
120 | target_cpu_speed[policy->cpu] = freq; | 137 | target_cpu_speed[policy->cpu] = freq; |
121 | 138 | ||
122 | return tegra_update_cpu_speed(); | 139 | ret = tegra_update_cpu_speed(tegra_cpu_highest_speed()); |
140 | |||
141 | out: | ||
142 | mutex_unlock(&tegra_cpu_lock); | ||
143 | return ret; | ||
123 | } | 144 | } |
124 | 145 | ||
146 | static int tegra_pm_notify(struct notifier_block *nb, unsigned long event, | ||
147 | void *dummy) | ||
148 | { | ||
149 | mutex_lock(&tegra_cpu_lock); | ||
150 | if (event == PM_SUSPEND_PREPARE) { | ||
151 | is_suspended = true; | ||
152 | pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n", | ||
153 | freq_table[0].frequency); | ||
154 | tegra_update_cpu_speed(freq_table[0].frequency); | ||
155 | } else if (event == PM_POST_SUSPEND) { | ||
156 | is_suspended = false; | ||
157 | } | ||
158 | mutex_unlock(&tegra_cpu_lock); | ||
159 | |||
160 | return NOTIFY_OK; | ||
161 | } | ||
162 | |||
163 | static struct notifier_block tegra_cpu_pm_notifier = { | ||
164 | .notifier_call = tegra_pm_notify, | ||
165 | }; | ||
166 | |||
125 | static int tegra_cpu_init(struct cpufreq_policy *policy) | 167 | static int tegra_cpu_init(struct cpufreq_policy *policy) |
126 | { | 168 | { |
127 | if (policy->cpu >= NUM_CPUS) | 169 | if (policy->cpu >= NUM_CPUS) |
@@ -142,6 +184,9 @@ static int tegra_cpu_init(struct cpufreq_policy *policy) | |||
142 | policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; | 184 | policy->shared_type = CPUFREQ_SHARED_TYPE_ALL; |
143 | cpumask_copy(policy->related_cpus, cpu_possible_mask); | 185 | cpumask_copy(policy->related_cpus, cpu_possible_mask); |
144 | 186 | ||
187 | if (policy->cpu == 0) | ||
188 | register_pm_notifier(&tegra_cpu_pm_notifier); | ||
189 | |||
145 | return 0; | 190 | return 0; |
146 | } | 191 | } |
147 | 192 | ||