Merge remote-tracking branches 'regulator/fix/88pm800', 'regulator/fix/max8973',...
[linux-drm-fsl-dcu.git] / drivers / cpufreq / freq_table.c
1 /*
2  * linux/drivers/cpufreq/freq_table.c
3  *
4  * Copyright (C) 2002 - 2003 Dominik Brodowski
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14 #include <linux/cpufreq.h>
15 #include <linux/module.h>
16
17 /*********************************************************************
18  *                     FREQUENCY TABLE HELPERS                       *
19  *********************************************************************/
20
21 int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
22                                     struct cpufreq_frequency_table *table)
23 {
24         struct cpufreq_frequency_table *pos;
25         unsigned int min_freq = ~0;
26         unsigned int max_freq = 0;
27         unsigned int freq;
28
29         cpufreq_for_each_valid_entry(pos, table) {
30                 freq = pos->frequency;
31
32                 if (!cpufreq_boost_enabled()
33                     && (pos->flags & CPUFREQ_BOOST_FREQ))
34                         continue;
35
36                 pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
37                 if (freq < min_freq)
38                         min_freq = freq;
39                 if (freq > max_freq)
40                         max_freq = freq;
41         }
42
43         policy->min = policy->cpuinfo.min_freq = min_freq;
44         policy->max = policy->cpuinfo.max_freq = max_freq;
45
46         if (policy->min == ~0)
47                 return -EINVAL;
48         else
49                 return 0;
50 }
51 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
52
53
54 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
55                                    struct cpufreq_frequency_table *table)
56 {
57         struct cpufreq_frequency_table *pos;
58         unsigned int freq, next_larger = ~0;
59         bool found = false;
60
61         pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
62                                         policy->min, policy->max, policy->cpu);
63
64         cpufreq_verify_within_cpu_limits(policy);
65
66         cpufreq_for_each_valid_entry(pos, table) {
67                 freq = pos->frequency;
68
69                 if ((freq >= policy->min) && (freq <= policy->max)) {
70                         found = true;
71                         break;
72                 }
73
74                 if ((next_larger > freq) && (freq > policy->max))
75                         next_larger = freq;
76         }
77
78         if (!found) {
79                 policy->max = next_larger;
80                 cpufreq_verify_within_cpu_limits(policy);
81         }
82
83         pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
84                                 policy->min, policy->max, policy->cpu);
85
86         return 0;
87 }
88 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
89
90 /*
91  * Generic routine to verify policy & frequency table, requires driver to set
92  * policy->freq_table prior to it.
93  */
94 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
95 {
96         struct cpufreq_frequency_table *table =
97                 cpufreq_frequency_get_table(policy->cpu);
98         if (!table)
99                 return -ENODEV;
100
101         return cpufreq_frequency_table_verify(policy, table);
102 }
103 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
104
105 int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
106                                    struct cpufreq_frequency_table *table,
107                                    unsigned int target_freq,
108                                    unsigned int relation,
109                                    unsigned int *index)
110 {
111         struct cpufreq_frequency_table optimal = {
112                 .driver_data = ~0,
113                 .frequency = 0,
114         };
115         struct cpufreq_frequency_table suboptimal = {
116                 .driver_data = ~0,
117                 .frequency = 0,
118         };
119         struct cpufreq_frequency_table *pos;
120         unsigned int freq, diff, i = 0;
121
122         pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
123                                         target_freq, relation, policy->cpu);
124
125         switch (relation) {
126         case CPUFREQ_RELATION_H:
127                 suboptimal.frequency = ~0;
128                 break;
129         case CPUFREQ_RELATION_L:
130         case CPUFREQ_RELATION_C:
131                 optimal.frequency = ~0;
132                 break;
133         }
134
135         cpufreq_for_each_valid_entry(pos, table) {
136                 freq = pos->frequency;
137
138                 i = pos - table;
139                 if ((freq < policy->min) || (freq > policy->max))
140                         continue;
141                 if (freq == target_freq) {
142                         optimal.driver_data = i;
143                         break;
144                 }
145                 switch (relation) {
146                 case CPUFREQ_RELATION_H:
147                         if (freq < target_freq) {
148                                 if (freq >= optimal.frequency) {
149                                         optimal.frequency = freq;
150                                         optimal.driver_data = i;
151                                 }
152                         } else {
153                                 if (freq <= suboptimal.frequency) {
154                                         suboptimal.frequency = freq;
155                                         suboptimal.driver_data = i;
156                                 }
157                         }
158                         break;
159                 case CPUFREQ_RELATION_L:
160                         if (freq > target_freq) {
161                                 if (freq <= optimal.frequency) {
162                                         optimal.frequency = freq;
163                                         optimal.driver_data = i;
164                                 }
165                         } else {
166                                 if (freq >= suboptimal.frequency) {
167                                         suboptimal.frequency = freq;
168                                         suboptimal.driver_data = i;
169                                 }
170                         }
171                         break;
172                 case CPUFREQ_RELATION_C:
173                         diff = abs(freq - target_freq);
174                         if (diff < optimal.frequency ||
175                             (diff == optimal.frequency &&
176                              freq > table[optimal.driver_data].frequency)) {
177                                 optimal.frequency = diff;
178                                 optimal.driver_data = i;
179                         }
180                         break;
181                 }
182         }
183         if (optimal.driver_data > i) {
184                 if (suboptimal.driver_data > i)
185                         return -EINVAL;
186                 *index = suboptimal.driver_data;
187         } else
188                 *index = optimal.driver_data;
189
190         pr_debug("target index is %u, freq is:%u kHz\n", *index,
191                  table[*index].frequency);
192
193         return 0;
194 }
195 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
196
197 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
198                 unsigned int freq)
199 {
200         struct cpufreq_frequency_table *pos, *table;
201
202         table = cpufreq_frequency_get_table(policy->cpu);
203         if (unlikely(!table)) {
204                 pr_debug("%s: Unable to find frequency table\n", __func__);
205                 return -ENOENT;
206         }
207
208         cpufreq_for_each_valid_entry(pos, table)
209                 if (pos->frequency == freq)
210                         return pos - table;
211
212         return -EINVAL;
213 }
214 EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
215
216 /**
217  * show_available_freqs - show available frequencies for the specified CPU
218  */
219 static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
220                                     bool show_boost)
221 {
222         ssize_t count = 0;
223         struct cpufreq_frequency_table *pos, *table = policy->freq_table;
224
225         if (!table)
226                 return -ENODEV;
227
228         cpufreq_for_each_valid_entry(pos, table) {
229                 /*
230                  * show_boost = true and driver_data = BOOST freq
231                  * display BOOST freqs
232                  *
233                  * show_boost = false and driver_data = BOOST freq
234                  * show_boost = true and driver_data != BOOST freq
235                  * continue - do not display anything
236                  *
237                  * show_boost = false and driver_data != BOOST freq
238                  * display NON BOOST freqs
239                  */
240                 if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
241                         continue;
242
243                 count += sprintf(&buf[count], "%d ", pos->frequency);
244         }
245         count += sprintf(&buf[count], "\n");
246
247         return count;
248
249 }
250
251 #define cpufreq_attr_available_freq(_name)        \
252 struct freq_attr cpufreq_freq_attr_##_name##_freqs =     \
253 __ATTR_RO(_name##_frequencies)
254
255 /**
256  * show_scaling_available_frequencies - show available normal frequencies for
257  * the specified CPU
258  */
259 static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
260                                                   char *buf)
261 {
262         return show_available_freqs(policy, buf, false);
263 }
264 cpufreq_attr_available_freq(scaling_available);
265 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
266
267 /**
268  * show_available_boost_freqs - show available boost frequencies for
269  * the specified CPU
270  */
271 static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
272                                               char *buf)
273 {
274         return show_available_freqs(policy, buf, true);
275 }
276 cpufreq_attr_available_freq(scaling_boost);
277 EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
278
279 struct freq_attr *cpufreq_generic_attr[] = {
280         &cpufreq_freq_attr_scaling_available_freqs,
281 #ifdef CONFIG_CPU_FREQ_BOOST_SW
282         &cpufreq_freq_attr_scaling_boost_freqs,
283 #endif
284         NULL,
285 };
286 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
287
288 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
289                                       struct cpufreq_frequency_table *table)
290 {
291         int ret = cpufreq_frequency_table_cpuinfo(policy, table);
292
293         if (!ret)
294                 policy->freq_table = table;
295
296         return ret;
297 }
298 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
299
300 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
301 MODULE_DESCRIPTION("CPUfreq frequency table helpers");
302 MODULE_LICENSE("GPL");