MALI: utgard: upgrade DDK to r7p0-00rel0
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / platform / rk30 / mali_dvfs.c
1 /**
2  * Rockchip SoC Mali-450 DVFS driver
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software FoundatIon.
7  */
8
9
10 /* #define ENABLE_DEBUG_LOG */
11 #include "custom_log.h"
12
13 #include "mali_platform.h"
14 #include "mali_dvfs.h"
15
16 /*---------------------------------------------------------------------------*/
17
18 /**
19  * 若 count_of_continuous_requests_to_jump_up_in_dvfs_level_table 达到 value,
20  * 将触发一次 current_dvfs_level jump_up.
21  */
22 #define NUM_OF_CONTINUOUS_REQUESTS_TO_TRIGGER_REAL_JUMPING_UP           (1)
23 /**
24  * 若 count_of_continuous_requests_to_jump_down_in_dvfs_level_table 达到 value,
25  * 将触发一次 current_dvfs_level jump_down.
26  */
27 #define NUM_OF_CONTINUOUS_REQUESTS_TO_TRIGGER_REAL_JUMPING_DOWN         (30)
28
29 #define level0_min 0
30 #define level0_max 70
31 #define levelf_max 100
32
33 #define mali_dividend 7
34 #define mali_fix_float(a) \
35         ((((a) * mali_dividend) % 10) \
36                 ? ((((a) * mali_dividend) / 10) + 1) \
37                 : (((a) * mali_dividend) / 10))
38
39 #define work_to_dvfs(w) container_of(w, struct mali_dvfs, work)
40 #define dvfs_to_drv_data(dvfs) \
41         container_of(dvfs, struct mali_platform_drv_data, dvfs)
42
43 /*---------------------------------------------------------------------------*/
44 #if 0
45 static bool mali_dvfs_should_jump_up(const struct mali_dvfs *p_dvfs)
46 {
47         return (p_dvfs->m_count_of_requests_to_jump_up
48                 >= NUM_OF_CONTINUOUS_REQUESTS_TO_TRIGGER_REAL_JUMPING_UP);
49 }
50
51 static bool mali_dvfs_should_jump_down(const struct mali_dvfs *p_dvfs)
52 {
53         return (p_dvfs->m_count_of_requests_to_jump_down
54                 >= NUM_OF_CONTINUOUS_REQUESTS_TO_TRIGGER_REAL_JUMPING_DOWN);
55 }
56 #endif
57 /**
58  * .KP :
59  * work_to_handle_mali_utilization_event 的实现主体,
60  * 将根据 current_mali_utilization_data, 改变 current_dvfs_level.
61  */
62  #if 0
63 static void mali_dvfs_event_proc(struct work_struct *w)
64 {
65         struct mali_dvfs *dvfs = work_to_dvfs(w);/* mali_dvfs_context. */
66         struct mali_platform_drv_data *drv_data = dvfs_to_drv_data(dvfs);
67         unsigned int utilisation = dvfs->utilisation;
68         int ret = 0;
69         /* index_of_current_dvfs_level. */
70         unsigned int level = dvfs->current_level;
71         /* current_dvfs_level. */
72         const struct mali_fv_info *threshold = &drv_data->fv_info[level];
73         /* utilization_in_percentage. */
74         utilisation = utilisation * 100 / 256;
75
76         V("mali_utilization_in_percentage : %d; index_of_current_level : %d;"
77                         "min: %d, max : %d",
78           utilisation,
79           level,
80           threshold->min,
81           threshold->max);
82         V("num_of_requests_to_jump_up : %d; num_of_requests_to_jump_down : %d",
83           dvfs->m_count_of_requests_to_jump_up,
84           dvfs->m_count_of_requests_to_jump_down);
85
86         if (utilisation > threshold->max) {
87                 dvfs->m_count_of_requests_to_jump_down = 0;
88
89                 /* 若 current_dvfs_level 还 "有" 上跳的空间, 则... */
90                 if (level < (drv_data->fv_info_length - 1)) {
91                         V("to count one request_to_jump_up.");
92                         dvfs->m_count_of_requests_to_jump_up++;
93
94                         /* 若足够触发一次 real_jump_up, 则... */
95                         if (mali_dvfs_should_jump_up(dvfs)) {
96                                 V("to preset real_jump_up.");
97                                 level += 1;
98
99                                 dvfs->m_count_of_requests_to_jump_up = 0;
100
101                                 goto MAKE_DVFS_LEVEL_UPDATE_EFFECTIVE;
102                         }
103                         /* 否则, 即还 "不" 足以 real_jump_up, 则... */
104                         else
105                                 return;
106                 }
107                 /* 否则, 即 "没有" 上跳的空间了, 则... */
108                 else
109                         return;
110         } else if (utilisation < (threshold->min)) {
111                 dvfs->m_count_of_requests_to_jump_up = 0;
112
113                 /* 若 current_dvfs_level 还有 下跳的空间, 则... */
114                 if (level > 0) {
115                         V("to count one request_to_jump_down.");
116                         dvfs->m_count_of_requests_to_jump_down++;
117
118                         /* 若足够触发一次 real_jump_down, 则... */
119                         if (mali_dvfs_should_jump_down(dvfs)) {
120                                 V("to preset real_jump_down.");
121                                 level -= 1;
122
123                                 dvfs->m_count_of_requests_to_jump_down = 0;
124
125                                 goto MAKE_DVFS_LEVEL_UPDATE_EFFECTIVE;
126                         } else {
127                                 return;
128                         }
129                 }
130                 /* 否则, 即 "没有" 下跳的空间了, 则... */
131                 else
132                         return;
133         }
134         /* 否则,
135          * 即 mali_utilization 在 'min' 和 'max' 之间,
136          * 即 current_dvfs_level 合适, 则 ... */
137         else {
138                 dvfs->m_count_of_requests_to_jump_up = 0;
139                 dvfs->m_count_of_requests_to_jump_down = 0;
140                 return;
141         }
142
143         /*
144         dev_dbg(drv_data->dev, "Setting dvfs level %u: freq = %lu Hz\n",
145                 level, drv_data->fv_info[level].freq);
146         */
147
148 MAKE_DVFS_LEVEL_UPDATE_EFFECTIVE:
149         ret = mali_set_level(drv_data->dev, level);
150         if (ret) {
151                 dev_err(drv_data->dev, "set freq error, %d", ret);
152                 return;
153         }
154 }
155 #endif
156 /**
157  * 返回 mali_dvfs_facility 当前是否被使能.
158  */
159 bool mali_dvfs_is_enabled(struct device *dev)
160 {
161         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
162         struct mali_dvfs *dvfs = &drv_data->dvfs;
163
164         return dvfs->enabled;
165 }
166
167 /**
168  * 使能 mali_dvfs_facility.
169  */
170 void mali_dvfs_enable(struct device *dev)
171 {
172         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
173         struct mali_dvfs *dvfs = &drv_data->dvfs;
174
175         dvfs->enabled = true;
176 }
177
178 /**
179  * 禁用 mali_dvfs_facility.
180  */
181 void mali_dvfs_disable(struct device *dev)
182 {
183         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
184         struct mali_dvfs *dvfs = &drv_data->dvfs;
185
186         dvfs->enabled = false;
187         cancel_work_sync(&dvfs->work);
188
189         /* 使用 lowest_dvfs_level. */
190         if (0 != mali_set_level(dev, 0))
191                 W("fail to set current_dvfs_level to index 0.");
192 }
193
194 /**
195  * 返回当前 mali_dvfs_context 中最后记录的 mali_utilization.
196  */
197 unsigned int mali_dvfs_utilisation(struct device *dev)
198 {
199         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
200         struct mali_dvfs *dvfs = &drv_data->dvfs;
201
202         return dvfs->utilisation;
203 }
204
205 /**
206  * 根据当前的 mali_utilization_event, 对应调整 mali_dvfs_facility.
207  * 运行在 context_of_common_part_calling_back_mali_utilization_event 中.
208  */
209 int mali_dvfs_event(struct device *dev, u32 utilisation)
210 {
211         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
212         struct mali_dvfs *dvfs = &drv_data->dvfs;
213
214         dvfs->utilisation = utilisation;
215         V("mali_utilization_in_percentage : %d", utilisation * 100 / 256);
216
217 #if 0
218         if (dvfs->enabled) {
219                 /* 将 work_to_handle_mali_utilization_event,
220                  * 放置到 kernel_global_workqueue, 待执行. */
221                 schedule_work(&dvfs->work);
222         }
223 #endif
224
225         return MALI_TRUE;
226 }
227 #if 0
228 static void mali_dvfs_threshold(u32 div,
229                                 struct mali_platform_drv_data *drv_data)
230 {
231         int length = drv_data->fv_info_length;
232         u32 pre_level;
233         u32 tmp;
234         int level;
235
236         for (level = 0; level < length; level++) {
237                 if (level == 0) {
238                         drv_data->fv_info[level].min = level0_min;
239                         if (length == 1)
240                                 drv_data->fv_info[level].max = levelf_max;
241                         else
242                                 drv_data->fv_info[level].max = level0_max;
243                 } else {
244                         pre_level = level - 1;
245                         if (level == length - 1)
246                                 drv_data->fv_info[level].max = levelf_max;
247                         else
248                                 drv_data->fv_info[level].max
249                                 = drv_data->fv_info[pre_level].max + div;
250
251                         drv_data->fv_info[level].min
252                         = drv_data->fv_info[pre_level].max
253                                 * drv_data->fv_info[pre_level].freq
254                                 / drv_data->fv_info[level].freq;
255
256                         tmp
257                         = drv_data->fv_info[level].max
258                                 - drv_data->fv_info[level].min;
259                         drv_data->fv_info[level].min += mali_fix_float(tmp);
260                 }
261
262                 dev_info(drv_data->dev, "freq: %lu, min_threshold: %d, max_threshold: %d\n",
263                          drv_data->fv_info[level].freq,
264                          drv_data->fv_info[level].min,
265                          drv_data->fv_info[level].max);
266         }
267 }
268 #endif
269 /*---------------------------------------------------------------------------*/
270
271 int mali_dvfs_init(struct device *dev)
272 {
273 #if 0
274         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
275         /*mali_dvfs_context. */
276         struct mali_dvfs *dvfs = &drv_data->dvfs;
277         /* gpu_clk_freq_table. */
278         struct cpufreq_frequency_table *freq_table;
279         int i = 0;
280         int div_dvfs;
281         int ret;
282
283         freq_table = dvfs_get_freq_volt_table(drv_data->clk);
284         if (!freq_table) {
285                 dev_err(dev, "Can't find dvfs table in dts\n");
286                 return -1;
287         }
288
289         /* 确定 len_of_avaialble_dvfs_level_list. */
290         while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
291                 drv_data->fv_info_length++;
292                 i++;
293         }
294
295         drv_data->fv_info = devm_kcalloc(dev, drv_data->fv_info_length,
296                                          sizeof(*drv_data->fv_info),
297                                          GFP_KERNEL);
298         if (!drv_data->fv_info)
299                 return -ENOMEM;
300
301         for (i = 0; i < drv_data->fv_info_length; i++)
302                 drv_data->fv_info[i].freq = freq_table[i].frequency * 1000;
303
304         if (drv_data->fv_info_length > 1)
305                 div_dvfs
306                 = round_up(((levelf_max - level0_max)
307                                 / (drv_data->fv_info_length - 1)),
308                            1);
309
310         mali_dvfs_threshold(div_dvfs, drv_data);
311
312         ret = dvfs_clk_set_rate(drv_data->clk, drv_data->fv_info[0].freq);
313         if (ret)
314                 return ret;
315
316         drv_data->dvfs.current_level = 0;
317
318         dev_info(dev, "initial freq = %lu\n",
319                  dvfs_clk_get_rate(drv_data->clk));
320
321         INIT_WORK(&dvfs->work, mali_dvfs_event_proc);
322         dvfs->enabled = true;
323
324         dvfs->m_count_of_requests_to_jump_up = 0;
325         dvfs->m_count_of_requests_to_jump_down = 0;
326
327 #endif
328         return 0;
329 }
330
331 void mali_dvfs_term(struct device *dev)
332 {
333 #if 0
334         struct mali_platform_drv_data *drv_data = dev_get_drvdata(dev);
335         struct mali_dvfs *dvfs = &drv_data->dvfs;
336
337         dvfs->m_count_of_requests_to_jump_up = 0;
338         dvfs->m_count_of_requests_to_jump_down = 0;
339
340         dvfs->enabled = false;
341         cancel_work_sync(&dvfs->work);
342 #endif
343 }
344