.. | .. |
---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
---|
1 | 2 | /* |
---|
2 | 3 | * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework |
---|
3 | 4 | * for Non-CPU Devices. |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2011 Samsung Electronics |
---|
6 | 7 | * MyungJoo Ham <myungjoo.ham@samsung.com> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #ifndef __LINUX_DEVFREQ_H__ |
---|
.. | .. |
---|
16 | 13 | #include <linux/device.h> |
---|
17 | 14 | #include <linux/notifier.h> |
---|
18 | 15 | #include <linux/pm_opp.h> |
---|
| 16 | +#include <linux/pm_qos.h> |
---|
19 | 17 | |
---|
20 | 18 | #define DEVFREQ_NAME_LEN 16 |
---|
21 | 19 | |
---|
.. | .. |
---|
28 | 26 | |
---|
29 | 27 | /* DEVFREQ notifier interface */ |
---|
30 | 28 | #define DEVFREQ_TRANSITION_NOTIFIER (0) |
---|
31 | | -#define DEVFREQ_POLICY_NOTIFIER (1) |
---|
32 | 29 | |
---|
33 | 30 | /* Transition notifiers of DEVFREQ_TRANSITION_NOTIFIER */ |
---|
34 | 31 | #define DEVFREQ_PRECHANGE (0) |
---|
35 | 32 | #define DEVFREQ_POSTCHANGE (1) |
---|
36 | 33 | |
---|
37 | | -/* Policy Notifiers */ |
---|
38 | | -#define DEVFREQ_ADJUST (0) |
---|
| 34 | +/* DEVFREQ work timers */ |
---|
| 35 | +enum devfreq_timer { |
---|
| 36 | + DEVFREQ_TIMER_DEFERRABLE = 0, |
---|
| 37 | + DEVFREQ_TIMER_DELAYED, |
---|
| 38 | + DEVFREQ_TIMER_NUM, |
---|
| 39 | +}; |
---|
39 | 40 | |
---|
40 | 41 | struct devfreq; |
---|
41 | 42 | struct devfreq_governor; |
---|
.. | .. |
---|
49 | 50 | * @busy_time: The time that the device was working among the |
---|
50 | 51 | * total_time. |
---|
51 | 52 | * @current_frequency: The operating frequency. |
---|
52 | | - * @update: Whether need to update total_time and busy_time. |
---|
53 | 53 | * @private_data: An entry not specified by the devfreq framework. |
---|
54 | 54 | * A device and a specific governor may have their |
---|
55 | 55 | * own protocol with private_data. However, because |
---|
.. | .. |
---|
61 | 61 | unsigned long total_time; |
---|
62 | 62 | unsigned long busy_time; |
---|
63 | 63 | unsigned long current_frequency; |
---|
64 | | - bool update; |
---|
65 | 64 | void *private_data; |
---|
66 | 65 | }; |
---|
67 | 66 | |
---|
.. | .. |
---|
78 | 77 | * @initial_freq: The operating frequency when devfreq_add_device() is |
---|
79 | 78 | * called. |
---|
80 | 79 | * @polling_ms: The polling interval in ms. 0 disables polling. |
---|
| 80 | + * @timer: Timer type is either deferrable or delayed timer. |
---|
81 | 81 | * @target: The device should set its operating frequency at |
---|
82 | 82 | * freq or lowest-upper-than-freq value. If freq is |
---|
83 | 83 | * higher than any operable frequency, set maximum. |
---|
.. | .. |
---|
104 | 104 | struct devfreq_dev_profile { |
---|
105 | 105 | unsigned long initial_freq; |
---|
106 | 106 | unsigned int polling_ms; |
---|
| 107 | + enum devfreq_timer timer; |
---|
107 | 108 | |
---|
108 | 109 | int (*target)(struct device *dev, unsigned long *freq, u32 flags); |
---|
109 | 110 | int (*get_dev_status)(struct device *dev, |
---|
.. | .. |
---|
116 | 117 | }; |
---|
117 | 118 | |
---|
118 | 119 | /** |
---|
119 | | - * struct devfreq_policy - Devfreq frequency limits |
---|
120 | | - * @min_: minimum frequency (adjustable by policy notifiers) |
---|
121 | | - * @max: maximum frequency (adjustable by policy notifiers) |
---|
| 120 | + * struct devfreq_stats - Statistics of devfreq device behavior |
---|
| 121 | + * @total_trans: Number of devfreq transitions. |
---|
| 122 | + * @trans_table: Statistics of devfreq transitions. |
---|
| 123 | + * @time_in_state: Statistics of devfreq states. |
---|
| 124 | + * @last_update: The last time stats were updated. |
---|
122 | 125 | */ |
---|
123 | | -struct devfreq_policy { |
---|
124 | | - unsigned long min; |
---|
125 | | - unsigned long max; |
---|
| 126 | +struct devfreq_stats { |
---|
| 127 | + unsigned int total_trans; |
---|
| 128 | + unsigned int *trans_table; |
---|
| 129 | + u64 *time_in_state; |
---|
| 130 | + u64 last_update; |
---|
126 | 131 | }; |
---|
127 | 132 | |
---|
128 | 133 | /** |
---|
.. | .. |
---|
140 | 145 | * devfreq.nb to the corresponding register notifier call chain. |
---|
141 | 146 | * @work: delayed work for load monitoring. |
---|
142 | 147 | * @previous_freq: previously configured frequency value. |
---|
| 148 | + * @last_status: devfreq user device info, performance statistics |
---|
143 | 149 | * @data: Private data of the governor. The devfreq framework does not |
---|
144 | 150 | * touch this. |
---|
145 | | - * @policy: Frequency limits of the device |
---|
146 | | - * @min_freq: Limit minimum frequency requested by user (0: none) |
---|
147 | | - * @max_freq: Limit maximum frequency requested by user (0: none) |
---|
| 151 | + * @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs) |
---|
| 152 | + * @user_max_freq_req: PM QoS maximum frequency request from user (via sysfs) |
---|
148 | 153 | * @scaling_min_freq: Limit minimum frequency requested by OPP interface |
---|
149 | 154 | * @scaling_max_freq: Limit maximum frequency requested by OPP interface |
---|
150 | 155 | * @stop_polling: devfreq polling status of a device. |
---|
151 | | - * @total_trans: Number of devfreq transitions |
---|
152 | | - * @trans_table: Statistics of devfreq transitions |
---|
153 | | - * @time_in_state: Statistics of devfreq states |
---|
154 | | - * @last_stat_updated: The last time stat updated |
---|
| 156 | + * @suspend_freq: frequency of a device set during suspend phase. |
---|
| 157 | + * @resume_freq: frequency of a device set in resume phase. |
---|
| 158 | + * @suspend_count: suspend requests counter for a device. |
---|
| 159 | + * @stats: Statistics of devfreq device behavior |
---|
155 | 160 | * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier |
---|
156 | | - * @policy_notifier_list: list head of DEVFREQ_POLICY_NOTIFIER notifier |
---|
| 161 | + * @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY |
---|
| 162 | + * @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY |
---|
157 | 163 | * |
---|
158 | | - * This structure stores the devfreq information for a give device. |
---|
| 164 | + * This structure stores the devfreq information for a given device. |
---|
159 | 165 | * |
---|
160 | 166 | * Note that when a governor accesses entries in struct devfreq in its |
---|
161 | 167 | * functions except for the context of callbacks defined in struct |
---|
162 | 168 | * devfreq_governor, the governor should protect its access with the |
---|
163 | 169 | * struct mutex lock in struct devfreq. A governor may use this mutex |
---|
164 | | - * to protect its own private data in void *data as well. |
---|
| 170 | + * to protect its own private data in ``void *data`` as well. |
---|
165 | 171 | */ |
---|
166 | 172 | struct devfreq { |
---|
167 | 173 | struct list_head node; |
---|
168 | 174 | |
---|
169 | 175 | struct mutex lock; |
---|
170 | | - struct mutex event_lock; |
---|
171 | 176 | struct device dev; |
---|
172 | 177 | struct devfreq_dev_profile *profile; |
---|
173 | 178 | const struct devfreq_governor *governor; |
---|
.. | .. |
---|
180 | 185 | |
---|
181 | 186 | void *data; /* private data for governors */ |
---|
182 | 187 | |
---|
183 | | - struct devfreq_policy policy; |
---|
184 | | - |
---|
185 | | - unsigned long min_freq; |
---|
186 | | - unsigned long max_freq; |
---|
| 188 | + struct dev_pm_qos_request user_min_freq_req; |
---|
| 189 | + struct dev_pm_qos_request user_max_freq_req; |
---|
187 | 190 | unsigned long scaling_min_freq; |
---|
188 | 191 | unsigned long scaling_max_freq; |
---|
189 | 192 | bool stop_polling; |
---|
190 | 193 | |
---|
191 | | - /* information for device frequency transition */ |
---|
192 | | - unsigned int total_trans; |
---|
193 | | - unsigned int *trans_table; |
---|
194 | | - unsigned long *time_in_state; |
---|
195 | | - unsigned long last_stat_updated; |
---|
| 194 | + unsigned long suspend_freq; |
---|
| 195 | + unsigned long resume_freq; |
---|
| 196 | + atomic_t suspend_count; |
---|
| 197 | + |
---|
| 198 | + /* information for device frequency transitions */ |
---|
| 199 | + struct devfreq_stats stats; |
---|
196 | 200 | |
---|
197 | 201 | struct srcu_notifier_head transition_notifier_list; |
---|
198 | | - struct srcu_notifier_head policy_notifier_list; |
---|
| 202 | + |
---|
| 203 | + struct notifier_block nb_min; |
---|
| 204 | + struct notifier_block nb_max; |
---|
199 | 205 | }; |
---|
200 | 206 | |
---|
201 | 207 | struct devfreq_freqs { |
---|
.. | .. |
---|
204 | 210 | }; |
---|
205 | 211 | |
---|
206 | 212 | #if defined(CONFIG_PM_DEVFREQ) |
---|
207 | | -extern struct devfreq *devfreq_add_device(struct device *dev, |
---|
208 | | - struct devfreq_dev_profile *profile, |
---|
209 | | - const char *governor_name, |
---|
210 | | - void *data); |
---|
211 | | -extern int devfreq_remove_device(struct devfreq *devfreq); |
---|
212 | | -extern struct devfreq *devm_devfreq_add_device(struct device *dev, |
---|
213 | | - struct devfreq_dev_profile *profile, |
---|
214 | | - const char *governor_name, |
---|
215 | | - void *data); |
---|
216 | | -extern void devm_devfreq_remove_device(struct device *dev, |
---|
217 | | - struct devfreq *devfreq); |
---|
| 213 | +struct devfreq *devfreq_add_device(struct device *dev, |
---|
| 214 | + struct devfreq_dev_profile *profile, |
---|
| 215 | + const char *governor_name, |
---|
| 216 | + void *data); |
---|
| 217 | +int devfreq_remove_device(struct devfreq *devfreq); |
---|
| 218 | +struct devfreq *devm_devfreq_add_device(struct device *dev, |
---|
| 219 | + struct devfreq_dev_profile *profile, |
---|
| 220 | + const char *governor_name, |
---|
| 221 | + void *data); |
---|
| 222 | +void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq); |
---|
218 | 223 | |
---|
219 | 224 | /* Supposed to be called by PM callbacks */ |
---|
220 | | -extern int devfreq_suspend_device(struct devfreq *devfreq); |
---|
221 | | -extern int devfreq_resume_device(struct devfreq *devfreq); |
---|
| 225 | +int devfreq_suspend_device(struct devfreq *devfreq); |
---|
| 226 | +int devfreq_resume_device(struct devfreq *devfreq); |
---|
| 227 | + |
---|
| 228 | +void devfreq_suspend(void); |
---|
| 229 | +void devfreq_resume(void); |
---|
| 230 | + |
---|
| 231 | +/* update_devfreq() - Reevaluate the device and configure frequency */ |
---|
| 232 | +int update_devfreq(struct devfreq *devfreq); |
---|
222 | 233 | |
---|
223 | 234 | /* Helper functions for devfreq user device driver with OPP. */ |
---|
224 | | -extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, |
---|
225 | | - unsigned long *freq, u32 flags); |
---|
226 | | -extern int devfreq_register_opp_notifier(struct device *dev, |
---|
227 | | - struct devfreq *devfreq); |
---|
228 | | -extern int devfreq_unregister_opp_notifier(struct device *dev, |
---|
229 | | - struct devfreq *devfreq); |
---|
230 | | -extern int devm_devfreq_register_opp_notifier(struct device *dev, |
---|
231 | | - struct devfreq *devfreq); |
---|
232 | | -extern void devm_devfreq_unregister_opp_notifier(struct device *dev, |
---|
233 | | - struct devfreq *devfreq); |
---|
234 | | -extern int devfreq_register_notifier(struct devfreq *devfreq, |
---|
235 | | - struct notifier_block *nb, |
---|
236 | | - unsigned int list); |
---|
237 | | -extern int devfreq_unregister_notifier(struct devfreq *devfreq, |
---|
238 | | - struct notifier_block *nb, |
---|
239 | | - unsigned int list); |
---|
240 | | -extern int devm_devfreq_register_notifier(struct device *dev, |
---|
| 235 | +struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, |
---|
| 236 | + unsigned long *freq, u32 flags); |
---|
| 237 | +int devfreq_register_opp_notifier(struct device *dev, |
---|
| 238 | + struct devfreq *devfreq); |
---|
| 239 | +int devfreq_unregister_opp_notifier(struct device *dev, |
---|
| 240 | + struct devfreq *devfreq); |
---|
| 241 | +int devm_devfreq_register_opp_notifier(struct device *dev, |
---|
| 242 | + struct devfreq *devfreq); |
---|
| 243 | +void devm_devfreq_unregister_opp_notifier(struct device *dev, |
---|
| 244 | + struct devfreq *devfreq); |
---|
| 245 | +int devfreq_register_notifier(struct devfreq *devfreq, |
---|
| 246 | + struct notifier_block *nb, |
---|
| 247 | + unsigned int list); |
---|
| 248 | +int devfreq_unregister_notifier(struct devfreq *devfreq, |
---|
| 249 | + struct notifier_block *nb, |
---|
| 250 | + unsigned int list); |
---|
| 251 | +int devm_devfreq_register_notifier(struct device *dev, |
---|
241 | 252 | struct devfreq *devfreq, |
---|
242 | 253 | struct notifier_block *nb, |
---|
243 | 254 | unsigned int list); |
---|
244 | | -extern void devm_devfreq_unregister_notifier(struct device *dev, |
---|
| 255 | +void devm_devfreq_unregister_notifier(struct device *dev, |
---|
245 | 256 | struct devfreq *devfreq, |
---|
246 | 257 | struct notifier_block *nb, |
---|
247 | 258 | unsigned int list); |
---|
248 | | -extern struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, |
---|
249 | | - int index); |
---|
250 | | - |
---|
251 | | -/** |
---|
252 | | - * devfreq_verify_within_limits() - Adjust a devfreq policy if needed to make |
---|
253 | | - * sure its min/max values are within a |
---|
254 | | - * specified range. |
---|
255 | | - * @policy: the policy |
---|
256 | | - * @min: the minimum frequency |
---|
257 | | - * @max: the maximum frequency |
---|
258 | | - */ |
---|
259 | | -static inline void devfreq_verify_within_limits(struct devfreq_policy *policy, |
---|
260 | | - unsigned int min, unsigned int max) |
---|
261 | | -{ |
---|
262 | | - if (policy->min < min) |
---|
263 | | - policy->min = min; |
---|
264 | | - if (policy->max < min) |
---|
265 | | - policy->max = min; |
---|
266 | | - if (policy->min > max) |
---|
267 | | - policy->min = max; |
---|
268 | | - if (policy->max > max) |
---|
269 | | - policy->max = max; |
---|
270 | | - if (policy->min > policy->max) |
---|
271 | | - policy->min = policy->max; |
---|
272 | | -} |
---|
| 259 | +struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node); |
---|
| 260 | +struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, |
---|
| 261 | + const char *phandle_name, int index); |
---|
273 | 262 | |
---|
274 | 263 | #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) |
---|
275 | 264 | /** |
---|
276 | | - * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq |
---|
| 265 | + * struct devfreq_simple_ondemand_data - ``void *data`` fed to struct devfreq |
---|
277 | 266 | * and devfreq_add_device |
---|
278 | 267 | * @upthreshold: If the load is over this value, the frequency jumps. |
---|
279 | 268 | * Specify 0 to use the default. Valid value = 0 to 100. |
---|
.. | .. |
---|
281 | 270 | * the governor may consider slowing the frequency down. |
---|
282 | 271 | * Specify 0 to use the default. Valid value = 0 to 100. |
---|
283 | 272 | * downdifferential < upthreshold must hold. |
---|
284 | | - * @simple_scaling: Setting this flag will scale the clocks up only if the |
---|
285 | | - * load is above @upthreshold and will scale the clocks |
---|
286 | | - * down only if the load is below @downdifferential. |
---|
287 | 273 | * |
---|
288 | 274 | * If the fed devfreq_simple_ondemand_data pointer is NULL to the governor, |
---|
289 | 275 | * the governor uses the default values. |
---|
.. | .. |
---|
291 | 277 | struct devfreq_simple_ondemand_data { |
---|
292 | 278 | unsigned int upthreshold; |
---|
293 | 279 | unsigned int downdifferential; |
---|
294 | | - unsigned int simple_scaling; |
---|
295 | 280 | }; |
---|
296 | 281 | #endif |
---|
297 | 282 | |
---|
298 | 283 | #if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE) |
---|
299 | 284 | /** |
---|
300 | | - * struct devfreq_passive_data - void *data fed to struct devfreq |
---|
| 285 | + * struct devfreq_passive_data - ``void *data`` fed to struct devfreq |
---|
301 | 286 | * and devfreq_add_device |
---|
302 | 287 | * @parent: the devfreq instance of parent device. |
---|
303 | 288 | * @get_target_freq: Optional callback, Returns desired operating frequency |
---|
.. | .. |
---|
330 | 315 | |
---|
331 | 316 | #else /* !CONFIG_PM_DEVFREQ */ |
---|
332 | 317 | static inline struct devfreq *devfreq_add_device(struct device *dev, |
---|
333 | | - struct devfreq_dev_profile *profile, |
---|
334 | | - const char *governor_name, |
---|
335 | | - void *data) |
---|
| 318 | + struct devfreq_dev_profile *profile, |
---|
| 319 | + const char *governor_name, |
---|
| 320 | + void *data) |
---|
336 | 321 | { |
---|
337 | 322 | return ERR_PTR(-ENOSYS); |
---|
338 | 323 | } |
---|
.. | .. |
---|
365 | 350 | return 0; |
---|
366 | 351 | } |
---|
367 | 352 | |
---|
| 353 | +static inline void devfreq_suspend(void) {} |
---|
| 354 | +static inline void devfreq_resume(void) {} |
---|
| 355 | + |
---|
368 | 356 | static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, |
---|
369 | | - unsigned long *freq, u32 flags) |
---|
| 357 | + unsigned long *freq, u32 flags) |
---|
370 | 358 | { |
---|
371 | 359 | return ERR_PTR(-EINVAL); |
---|
372 | 360 | } |
---|
373 | 361 | |
---|
374 | 362 | static inline int devfreq_register_opp_notifier(struct device *dev, |
---|
375 | | - struct devfreq *devfreq) |
---|
| 363 | + struct devfreq *devfreq) |
---|
376 | 364 | { |
---|
377 | 365 | return -EINVAL; |
---|
378 | 366 | } |
---|
379 | 367 | |
---|
380 | 368 | static inline int devfreq_unregister_opp_notifier(struct device *dev, |
---|
381 | | - struct devfreq *devfreq) |
---|
| 369 | + struct devfreq *devfreq) |
---|
382 | 370 | { |
---|
383 | 371 | return -EINVAL; |
---|
384 | 372 | } |
---|
385 | 373 | |
---|
386 | 374 | static inline int devm_devfreq_register_opp_notifier(struct device *dev, |
---|
387 | | - struct devfreq *devfreq) |
---|
| 375 | + struct devfreq *devfreq) |
---|
388 | 376 | { |
---|
389 | 377 | return -EINVAL; |
---|
390 | 378 | } |
---|
391 | 379 | |
---|
392 | 380 | static inline void devm_devfreq_unregister_opp_notifier(struct device *dev, |
---|
393 | | - struct devfreq *devfreq) |
---|
| 381 | + struct devfreq *devfreq) |
---|
394 | 382 | { |
---|
395 | 383 | } |
---|
396 | 384 | |
---|
.. | .. |
---|
409 | 397 | } |
---|
410 | 398 | |
---|
411 | 399 | static inline int devm_devfreq_register_notifier(struct device *dev, |
---|
412 | | - struct devfreq *devfreq, |
---|
413 | | - struct notifier_block *nb, |
---|
414 | | - unsigned int list) |
---|
| 400 | + struct devfreq *devfreq, |
---|
| 401 | + struct notifier_block *nb, |
---|
| 402 | + unsigned int list) |
---|
415 | 403 | { |
---|
416 | 404 | return 0; |
---|
417 | 405 | } |
---|
418 | 406 | |
---|
419 | 407 | static inline void devm_devfreq_unregister_notifier(struct device *dev, |
---|
420 | | - struct devfreq *devfreq, |
---|
421 | | - struct notifier_block *nb, |
---|
422 | | - unsigned int list) |
---|
| 408 | + struct devfreq *devfreq, |
---|
| 409 | + struct notifier_block *nb, |
---|
| 410 | + unsigned int list) |
---|
423 | 411 | { |
---|
424 | 412 | } |
---|
425 | 413 | |
---|
426 | | -static inline struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, |
---|
427 | | - int index) |
---|
| 414 | +static inline struct devfreq *devfreq_get_devfreq_by_node(struct device_node *node) |
---|
428 | 415 | { |
---|
429 | 416 | return ERR_PTR(-ENODEV); |
---|
430 | 417 | } |
---|
431 | 418 | |
---|
432 | | -static inline void devfreq_verify_within_limits(struct devfreq_policy *policy, |
---|
433 | | - unsigned int min, unsigned int max) |
---|
| 419 | +static inline struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, |
---|
| 420 | + const char *phandle_name, int index) |
---|
434 | 421 | { |
---|
| 422 | + return ERR_PTR(-ENODEV); |
---|
435 | 423 | } |
---|
436 | 424 | |
---|
437 | 425 | static inline int devfreq_update_stats(struct devfreq *df) |
---|