Merge tag 'v4.4-rc5'
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / midgard / platform / rk / mali_kbase_dvfs.c
1 /* drivers/gpu/t6xx/kbase/src/platform/manta/mali_kbase_dvfs.c
2  * 
3  *
4  * Rockchip SoC Mali-T764 DVFS driver
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  * @file mali_kbase_dvfs.c
13  * DVFS
14  */
15
16 // #define ENABLE_DEBUG_LOG
17 #include "custom_log.h"
18
19 #include <mali_kbase.h>
20 #include <mali_kbase_uku.h>
21 #include <mali_kbase_mem.h>
22 #include <mali_midg_regmap.h>
23 #include <mali_kbase_mem_linux.h>
24
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/poll.h>
28 #include <linux/kernel.h>
29 #include <linux/errno.h>
30 #include <linux/platform_device.h>
31 #include <linux/pci.h>
32 #include <linux/miscdevice.h>
33 #include <linux/list.h>
34 #include <linux/semaphore.h>
35 #include <linux/fs.h>
36 #include <linux/uaccess.h>
37 #include <linux/interrupt.h>
38 #include <linux/io.h>
39 #include <linux/cpufreq.h>
40 #include <linux/fb.h>
41 #include <linux/clk.h>
42 #include <linux/delay.h>
43 #include <linux/regulator/consumer.h>
44 #include <linux/regulator/driver.h>
45 #include <linux/rk_fb.h>
46 #include <linux/input.h>
47 #include <linux/rockchip/common.h>
48
49 #include <platform/rk/mali_kbase_platform.h>
50 #include <platform/rk/mali_kbase_dvfs.h>
51 #include <mali_kbase_gator.h>
52 #include <linux/rockchip/dvfs.h>
53 /***********************************************************/
54 /*  This table and variable are using the check time share of GPU Clock  */
55 /***********************************************************/
56 extern int rockchip_tsadc_get_temp(int chn);
57 /** gpu 温度上限. */
58 #define gpu_temp_limit 110
59 /** 经过 gpu_temp_statis_time 次测量记录之后, 对温度数据取平均. */
60 #define gpu_temp_statis_time 1
61
62 #define level0_min 0
63 #define level0_max 70
64 #define levelf_max 100
65
66 static u32 div_dvfs = 0 ;
67
68 /**
69  * .DP : mali_dvfs_level_table.
70  * 其中的 level_items 的 gpu_clk_freq 从低到高.
71  *
72  * 运行时初始化阶段, 将从 'mali_freq_table' 进行运行时初始化,
73  * 若获取 'mali_freq_table' 失败, 则使用这里的 缺省配置.
74  * 参见 kbase_platform_dvfs_init.
75  */
76 static mali_dvfs_info mali_dvfs_infotbl[] = {
77         {925000, 100000, 0, 70, 0},
78         {925000, 160000, 50, 65, 0},
79         {1025000, 266000, 60, 78, 0},
80         {1075000, 350000, 65, 75, 0},
81         {1125000, 400000, 70, 75, 0},
82         {1200000, 500000, 90, 100, 0},
83 };
84 /**
85  * pointer_to_mali_dvfs_level_table.
86  */
87 mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
88
89 /**
90  * num_of_mali_dvfs_levels : mali_dvfs_level_table 中有效的 level_item 的数量.
91  */
92 unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
93
94 /**
95  * mali_dvfs_level_table 中可以容纳的 level_items 的最大数量.
96  */
97 const unsigned int MAX_NUM_OF_MALI_DVFS_LEVELS = ARRAY_SIZE(mali_dvfs_infotbl);
98
99 /**
100  * gpu_clk_freq_table_from_system_dvfs_module, 从 system_dvfs_module 得到的 gpu_clk 的 频点表.
101  * 原始的 频点配置信息在 .dts 文件中.
102  */
103 static struct cpufreq_frequency_table *mali_freq_table = NULL;
104 #ifdef CONFIG_MALI_MIDGARD_DVFS
105
106 /** mali_dvfs_status_t. */
107 typedef struct _mali_dvfs_status_type {
108         struct kbase_device *kbdev;
109         /** 
110          * .DP : current_dvfs_level : 当前使用的 mali_dvfs_level 在 mali_dvfs_level_table 中的 index.
111          * 参见 mali_dvfs_infotbl. 
112          */
113         int step;
114         /** 最新的 由 metrics_system 报告的 current_calculated_utilisation. */
115         int utilisation;
116         /** 最近一次完成的 temperature_record_section 记录得到的温度数据. */
117         u32 temperature;
118         /** 当前 temperature_record_section 中, 已经记录温度的次数. */
119         u32 temperature_time;
120 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
121         /** 
122          * gpu_freq_upper_limit, 即 dvfs_level_upper_limit.
123          * 量纲是 index of mali_dvfs_level_table.
124          * 若是 -1, 则表示当前未设置 dvfs_level_upper_limit.
125          */
126         int upper_lock;
127         /** 
128          * gpu_freq_lower_limit, 即 dvfs_level_lower_limit.
129          * 量纲是 index of mali_dvfs_level_table.
130          * 若是 -1, 则表示当前未设置 dvfs_level_lower_limit.
131          */
132         int under_lock;
133 #endif
134
135 } mali_dvfs_status;
136
137 static struct workqueue_struct *mali_dvfs_wq = 0;
138
139 /**
140  * 用来在并发环境下, 保护 mali_dvfs_status_current 等数据.
141  */
142 spinlock_t mali_dvfs_spinlock;
143 struct mutex mali_set_clock_lock;
144 struct mutex mali_enable_clock_lock;
145
146 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
147 static void update_time_in_state(int level);
148 #endif
149 /* .DP : current_mali_dvfs_status. */
150 static mali_dvfs_status mali_dvfs_status_current;
151
152 #define LIMIT_FPS 60
153 #define LIMIT_FPS_POWER_SAVE 50
154
155 /*---------------------------------------------------------------------------*/
156 #ifdef CONFIG_MALI_MIDGARD_DVFS
157 static void gpufreq_input_event(struct input_handle *handle, unsigned int type,
158                                                                                 unsigned int code, int value)
159 {
160         mali_dvfs_status *dvfs_status;
161         struct rk_context *platform;
162         unsigned long flags;
163         
164         if (type != EV_ABS)
165                 return;
166         
167         dvfs_status = &mali_dvfs_status_current;
168         platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
169         
170         spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
171         /* 有 input_event 到来, 设置对应标识. */
172         platform->gpu_in_touch = true;
173         spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
174 }
175
176 static int gpufreq_input_connect(struct input_handler *handler,
177                 struct input_dev *dev, const struct input_device_id *id)
178 {
179         struct input_handle *handle;    // 用于关联 'dev' 和 'handler'.
180         int error;
181
182         handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
183         if (!handle)
184                 return -ENOMEM;
185
186         handle->dev = dev;              // 'handle' 关联的 input_dev.
187         handle->handler = handler;
188         handle->name = "gpufreq";
189
190         error = input_register_handle(handle);
191         if (error)
192                 goto err2;
193
194         error = input_open_device(handle);
195         if (error)
196                 goto err1;
197         pr_info("%s\n",__func__);
198         return 0;
199
200 err1:
201         input_unregister_handle(handle);
202 err2:
203         kfree(handle);
204         return error;
205 }
206
207 static void gpufreq_input_disconnect(struct input_handle *handle)
208 {
209         input_close_device(handle);
210         input_unregister_handle(handle);
211         kfree(handle);
212         pr_info("%s\n",__func__);
213 }
214
215 /**
216  * 待处理(关联) 的 input_device_ids_table.
217  */
218 static const struct input_device_id gpufreq_ids[] = {
219         {
220                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
221                         INPUT_DEVICE_ID_MATCH_ABSBIT,
222                 .evbit = { BIT_MASK(EV_ABS) },
223                 .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
224                         BIT_MASK(ABS_MT_POSITION_X) |
225                         BIT_MASK(ABS_MT_POSITION_Y) },
226         },
227         {
228                 .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
229                         INPUT_DEVICE_ID_MATCH_ABSBIT,
230                 .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
231                 .absbit = { [BIT_WORD(ABS_X)] =
232                         BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
233         },
234         { },
235 };
236
237 static struct input_handler gpufreq_input_handler = {
238         .event          = gpufreq_input_event,
239         .connect        = gpufreq_input_connect,
240         .disconnect     = gpufreq_input_disconnect,
241         .name           = "gpufreq",
242         .id_table       = gpufreq_ids,
243 };
244 #endif
245 /*---------------------------------------------------------------------------*/
246
247 /**
248  * mali_dvfs_work 的实现主体, 即对 dvfs_event 的处理流程的主体函数. 
249  */
250 static void mali_dvfs_event_proc(struct work_struct *w)
251 {
252         unsigned long flags;
253         mali_dvfs_status *dvfs_status;
254
255         static int level_down_time = 0; // counter_of_requests_to_jump_down_in_dvfs_level_table : 
256                                         //      对 mali_dvfs_level 下跳 请求 发生的次数的静态计数. 
257         static int level_up_time = 0;   // counter_of_requests_to_jump_up_in_dvfs_level_table : 
258                                         //      对 mali_dvfs_level 上跳 请求发生的次数的静态计数. 
259         static u32 temp_tmp;
260         struct rk_context *platform;
261         u32 fps = 0;            // real_fps.
262         u32 fps_limit;
263         u32 policy;
264         mutex_lock(&mali_enable_clock_lock);
265         dvfs_status = &mali_dvfs_status_current;
266
267         if (!kbase_platform_dvfs_get_enable_status()) {
268                 mutex_unlock(&mali_enable_clock_lock);
269                 return;
270         }
271         platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
272         
273         fps = rk_get_real_fps(0);
274
275         dvfs_status->temperature_time++;
276
277         temp_tmp += rockchip_tsadc_get_temp(1);         // .Q : 获取当前温度? "1" : 意义? 指定特定的测试通道? 
278
279         if(dvfs_status->temperature_time >= gpu_temp_statis_time) {
280                 dvfs_status->temperature_time = 0;
281                 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
282                 temp_tmp = 0;
283         }
284
285         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
286         /*
287         policy = rockchip_pm_get_policy();
288         */
289         policy = ROCKCHIP_PM_POLICY_NORMAL;
290         
291         if (ROCKCHIP_PM_POLICY_PERFORMANCE == policy) {
292                 dvfs_status->step = MALI_DVFS_STEP - 1;
293         } else {
294                 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
295                 V("policy : %d , fps_limit = %d", policy, fps_limit);
296
297                 /*give priority to temperature unless in performance mode */
298                 if (dvfs_status->temperature > gpu_temp_limit)  // 若记录的 gpu 温度 超过了 上限, 则 ...
299                 {
300                         if(dvfs_status->step > 0)
301                                 dvfs_status->step--;
302                         
303                         if(gpu_temp_statis_time > 1)
304                                 dvfs_status->temperature = 0;
305                         /*
306                            pr_info("decrease step for temperature over %d,next clock = %d\n",
307                            gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock);
308                          */
309                         V("jump down in dvfs_level_table to level '%d', for temperature over %d, next clock = %d",
310                                         dvfs_status->step,
311                                         gpu_temp_limit,
312                                         mali_dvfs_infotbl[dvfs_status->step].clock);
313                 } 
314                 // 若 current_calculated_utilisation 要求 上调 mali_dvfs_level, 
315                 //      且 current_dvfs_level 还可能被上调, 
316                 //      且 real_fps "小于" fps_limit, 
317                 // 则 .... 
318                 else if ( (dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) 
319                                 && (dvfs_status->step < MALI_DVFS_STEP - 1) 
320                                 && fps < fps_limit ) 
321                 {
322                         // 至此, 可认为一次请求 mali_dvfs_level 上跳 发生.
323
324                         level_up_time++;
325
326                         /* 若 上跳请求的次数 达到 执行具体上跳 要求, 则... */
327                         if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL) 
328                         {
329                                 V("to jump up in dvfs_level_table, utilisation=%d, current clock=%d, fps = %d, temperature = %d",
330                                                 dvfs_status->utilisation,
331                                                 mali_dvfs_infotbl[dvfs_status->step].clock,
332                                                 fps,
333                                                 dvfs_status->temperature);
334                                 /* 预置 current_dvfs_level 上跳. */      // 具体生效将在最后.
335                                 dvfs_status->step++;
336                                 /* 清 上跳请求计数. */
337                                 level_up_time = 0;
338
339                                 V(" next clock=%d.", mali_dvfs_infotbl[dvfs_status->step].clock);
340                                 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);    // 数组中元素的 index 总是比 size 小. 
341                         }
342
343                         /* 清 下跳请求计数. */
344                         level_down_time = 0;
345                 } 
346                 /* 否则, 若 current_calculated_utilisation 要求 current_dvfs_level 下跳, 且 还可以下跳, 则... */
347                 else if ((dvfs_status->step > 0) 
348                                 && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) 
349                 {
350                         level_down_time++;
351
352                         if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL) 
353                         {
354                                 V("to jump down in dvfs_level_table ,utilisation=%d, current clock=%d, fps = %d, temperature = %d",
355                                                 dvfs_status->utilisation,
356                                                 mali_dvfs_infotbl[dvfs_status->step].clock,
357                                                 fps,
358                                                 dvfs_status->temperature);
359
360                                 BUG_ON(dvfs_status->step <= 0);
361                                 dvfs_status->step--;
362                                 level_down_time = 0;
363
364                                 V(" next clock=%d",mali_dvfs_infotbl[dvfs_status->step].clock);
365                         }
366
367                         level_up_time = 0;
368                 } 
369                 /* 否则, ... */
370                 else 
371                 {
372                         level_down_time = 0;
373                         level_up_time = 0;
374
375                         V("keep current_dvfs_level, utilisation=%d,current clock=%d,fps = %d,temperature = %d\n",
376                                         dvfs_status->utilisation,
377                                         mali_dvfs_infotbl[dvfs_status->step].clock,
378                                         fps,
379                                         dvfs_status->temperature);                      
380                 }
381         }
382 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
383         // #error               // 目前配置下, 本段代码有效. 
384
385         // 若 指定了 dvfs_level_upper_limit, 
386         //      且 预置的 current_dvfs_level "大于" dvfs_level_upper_limit,
387         // 则...
388         if ((dvfs_status->upper_lock >= 0) 
389                         && (dvfs_status->step > dvfs_status->upper_lock))
390         {
391                 /* 将 预置的 current_dvfs_level 调整到 dvfs_level_upper_limit. */
392                 dvfs_status->step = dvfs_status->upper_lock;
393         }
394
395         if (dvfs_status->under_lock > 0) {
396                 if (dvfs_status->step < dvfs_status->under_lock)
397                         dvfs_status->step = dvfs_status->under_lock;
398         }
399 #endif
400         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
401         /* 将命令 dvfs_module 让 current_dvfs_level 具体生效. */
402         kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
403
404         mutex_unlock(&mali_enable_clock_lock);
405 }
406
407 /**
408  * mali_dvfs_work : 处理来自 kbase_platform_dvfs_event 的 dvfs_event 的 work.
409  */
410 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
411
412
413 /* ############################################################################################# */
414 // callback_interface_to_common_parts_in_mdd
415
416 /**
417  * 由 common_parts_in_mdd 调用的, 将 dvfs_event (utilisation_report_event) 通知回调到 platform_dependent_part_in_mdd.
418  */
419 int kbase_platform_dvfs_event(struct kbase_device *kbdev,
420                                 u32 utilisation,          // current_calculated_utilisation 
421                                 u32 util_gl_share_no_use,
422                                 u32 util_cl_share_no_use[2] )
423 {
424         unsigned long flags;
425         struct rk_context *platform;
426
427         BUG_ON(!kbdev);
428         platform = (struct rk_context *)kbdev->platform_context;
429
430         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
431         if (platform->time_tick < MALI_DVFS_UP_TIME_INTERVAL) {
432                 platform->time_tick++;
433                 platform->time_busy += kbdev->pm.backend.metrics.time_busy;
434                 
435                 platform->time_idle += kbdev->pm.backend.metrics.time_idle;
436         } else {
437                 platform->time_busy = kbdev->pm.backend.metrics.time_busy;
438                 platform->time_idle = kbdev->pm.backend.metrics.time_idle;
439                 platform->time_tick = 0;
440         }
441
442         if ((platform->time_tick == MALI_DVFS_UP_TIME_INTERVAL) &&
443                 (platform->time_idle + platform->time_busy > 0))
444                 platform->utilisation = (100 * platform->time_busy) /
445                                                                 (platform->time_idle + platform->time_busy);
446
447         /* 记录 current_calculated_utilisation. */
448         mali_dvfs_status_current.utilisation = utilisation;
449         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
450
451         /* 要求在 cpu_0 上, 使用 workqueue mali_dvfs_wq, 执行 mali_dvfs_work. */
452         queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
453         /*add error handle here */
454         return MALI_TRUE;
455 }
456 /* ############################################################################################# */
457
458 int kbase_platform_dvfs_get_utilisation(void)
459 {
460         unsigned long flags;
461         int utilisation = 0;
462
463         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
464         utilisation = mali_dvfs_status_current.utilisation;
465         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
466
467         return utilisation;
468 }
469
470 int kbase_platform_dvfs_get_enable_status(void)
471 {
472         struct kbase_device *kbdev;
473         unsigned long flags;
474         int enable;
475
476         kbdev = mali_dvfs_status_current.kbdev;
477         spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
478         enable = kbdev->pm.backend.metrics.timer_active;
479         spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
480
481         return enable;
482 }
483
484 int kbase_platform_dvfs_enable(bool enable, int freq)
485 {
486         mali_dvfs_status *dvfs_status;
487         struct kbase_device *kbdev;
488         unsigned long flags;
489         struct rk_context *platform;
490
491         dvfs_status = &mali_dvfs_status_current;
492         kbdev = mali_dvfs_status_current.kbdev;
493
494         BUG_ON(kbdev == NULL);
495         platform = (struct rk_context *)kbdev->platform_context;
496
497         mutex_lock(&mali_enable_clock_lock);
498
499         if (enable != kbdev->pm.backend.metrics.timer_active) {
500                 /* 若要 使能 dvfs, 则... */
501                 if (enable) {
502                         spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
503                         kbdev->pm.backend.metrics.timer_active = MALI_TRUE;
504                         spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
505                         hrtimer_start(&kbdev->pm.backend.metrics.timer,
506                                         HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
507                                         HRTIMER_MODE_REL);
508                 }
509                 /* 否则, 即要 disable dvfs, 则 ... */
510                 else {
511                         spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
512                         kbdev->pm.backend.metrics.timer_active = MALI_FALSE;
513                         spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
514                         hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
515                 }
516         }
517
518         if (freq != MALI_DVFS_CURRENT_FREQ) {
519                 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
520                 platform->time_tick = 0;
521                 platform->time_busy = 0;
522                 platform->time_idle = 0;
523                 platform->utilisation = 0;
524                 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
525                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
526                 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
527         }
528  
529         mutex_unlock(&mali_enable_clock_lock);
530
531         return MALI_TRUE;
532 }
533
534 #define dividend 7
535 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
536 /**
537  * 为 'mali_dvfs_info' 中 index 是 'level' 的 level_item, 计算 min_threshold 和 max_threshold.
538  */
539 static bool calculate_dvfs_max_min_threshold(u32 level)
540 {
541         u32 pre_level;
542         u32     tmp ;
543         if (0 == level) {
544                 if ((MALI_DVFS_STEP-1) == level) {
545                         mali_dvfs_infotbl[level].min_threshold = level0_min;
546                         mali_dvfs_infotbl[level].max_threshold = levelf_max;
547                 } else {
548                         mali_dvfs_infotbl[level].min_threshold = level0_min;
549                         mali_dvfs_infotbl[level].max_threshold = level0_max;
550                 }
551         } else {
552                 pre_level = level - 1;
553                 if ((MALI_DVFS_STEP-1) == level) {
554                         mali_dvfs_infotbl[level].max_threshold = levelf_max;
555                 } else {
556                         mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold +
557                                                                                                          div_dvfs;
558                 }
559                 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold *
560                                                                                                   (mali_dvfs_infotbl[pre_level].clock/1000)) /
561                                                                                                   (mali_dvfs_infotbl[level].clock/1000); 
562                 
563                 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
564                 
565                 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
566         }
567
568         pr_info("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",
569                         level,mali_dvfs_infotbl[level].clock, mali_dvfs_infotbl[level].min_threshold,
570                         mali_dvfs_infotbl[level].max_threshold);
571
572         return MALI_TRUE;
573 }
574
575 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
576 {
577         unsigned long flags;
578         /*default status
579            add here with the right function to get initilization value.
580          */
581         struct rk_context *platform;
582         int i;
583         int rc;
584         
585         platform = (struct rk_context *)kbdev->platform_context;
586         if (NULL == platform)
587                 panic("oops");
588                     
589         D("to get gpu_clk_freq_table from system_dvfs_module.");
590         mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
591         if (mali_freq_table == NULL) {
592                 printk("mali freq table not assigned yet,use default\n");
593                 goto not_assigned ;
594         } else {
595                 D("we got valid gpu_clk_freq_table, to init mali_dvfs_level_table with it.");
596
597                 /*recalculte step*/
598                 MALI_DVFS_STEP = 0;
599
600                 for ( i = 0; 
601                       mali_freq_table[i].frequency != CPUFREQ_TABLE_END 
602                         && i < MAX_NUM_OF_MALI_DVFS_LEVELS;
603                       i++ ) 
604                 {
605                         mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
606                         MALI_DVFS_STEP++;
607                 }
608
609                 if(MALI_DVFS_STEP > 1)
610                         div_dvfs = round_up( ( (levelf_max - level0_max) / (MALI_DVFS_STEP - 1) ), 1);
611
612                 printk("MALI_DVFS_STEP = %d, div_dvfs = %d \n",MALI_DVFS_STEP, div_dvfs);
613                 
614                 for(i=0;i<MALI_DVFS_STEP;i++)
615                         calculate_dvfs_max_min_threshold(i);
616
617                 p_mali_dvfs_infotbl = mali_dvfs_infotbl;                                
618         }
619
620 not_assigned :
621         if (!mali_dvfs_wq)
622                 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
623
624         spin_lock_init(&mali_dvfs_spinlock);
625         mutex_init(&mali_set_clock_lock);
626         mutex_init(&mali_enable_clock_lock);
627
628         /*add a error handling here */
629         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
630         mali_dvfs_status_current.kbdev = kbdev;
631         mali_dvfs_status_current.utilisation = 0;
632         mali_dvfs_status_current.step = 0;
633 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
634         mali_dvfs_status_current.upper_lock = -1;       // 初始时, 未设置. 
635         mali_dvfs_status_current.under_lock = -1;
636 #endif
637         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
638
639         spin_lock_init(&platform->gpu_in_touch_lock);
640         rc = input_register_handler(&gpufreq_input_handler);
641         if ( 0 != rc )
642         {
643                 E("fail to register gpufreq_input_handler.");
644         }
645
646         return MALI_TRUE;
647 }
648
649 void kbase_platform_dvfs_term(void)
650 {
651         if (mali_dvfs_wq)
652                 destroy_workqueue(mali_dvfs_wq);
653
654         mali_dvfs_wq = NULL;
655         
656         input_unregister_handler(&gpufreq_input_handler);
657 }
658 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
659
660 int mali_get_dvfs_upper_locked_freq(void)
661 {
662         unsigned long flags;
663         int  gpu_clk_freq = -1; // gpu_clk_freq_of_upper_limit
664
665 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
666         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
667         if (mali_dvfs_status_current.upper_lock >= 0)
668         {
669                 gpu_clk_freq = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
670         }
671         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
672 #endif
673         return gpu_clk_freq;
674 }
675
676 int mali_get_dvfs_under_locked_freq(void)
677 {
678         unsigned long flags;
679         int  gpu_clk_freq = -1; // gpu_clk_freq_of_upper_limit
680
681 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
682         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
683         if (mali_dvfs_status_current.under_lock >= 0)
684         {
685                 gpu_clk_freq = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
686         }
687         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
688 #endif
689         return gpu_clk_freq;
690 }
691
692 int mali_get_dvfs_current_level(void)
693 {
694         unsigned long flags;
695         int current_level = -1;
696
697 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
698         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
699         current_level = mali_dvfs_status_current.step;
700         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
701 #endif
702         return current_level;
703 }
704
705 int mali_dvfs_freq_lock(int level)
706 {
707         unsigned long flags;
708 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
709         /*-----------------------------------*/
710         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
711
712         if (mali_dvfs_status_current.under_lock >= 0 
713                 && mali_dvfs_status_current.under_lock > level) 
714         {
715                 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
716                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
717                 return -1;
718         }
719
720         V("to set current dvfs_upper_lock to level '%d'.", level);
721         mali_dvfs_status_current.upper_lock = level;
722
723         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
724         /*-----------------------------------*/
725
726         printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
727 #endif
728         return 0;
729 }
730
731 void mali_dvfs_freq_unlock(void)
732 {
733         unsigned long flags;
734 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
735         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
736         mali_dvfs_status_current.upper_lock = -1;
737         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
738 #endif
739         printk(KERN_DEBUG "mali Upper Lock Unset\n");
740 }
741
742 int mali_dvfs_freq_under_lock(int level)
743 {
744         unsigned long flags;
745 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
746         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
747         if (mali_dvfs_status_current.upper_lock >= 0 &&
748                 mali_dvfs_status_current.upper_lock < level) {
749                 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
750                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
751                 return -1;
752         }
753         mali_dvfs_status_current.under_lock = level;
754         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
755
756         printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
757 #endif
758         return 0;
759 }
760
761 void mali_dvfs_freq_under_unlock(void)
762 {
763         unsigned long flags;
764 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
765         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
766         mali_dvfs_status_current.under_lock = -1;
767         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
768 #endif
769         printk(KERN_DEBUG " mali clock Under Lock Unset\n");
770 }
771
772 void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq)
773 {
774         struct rk_context *platform;
775
776         if (!kbdev)
777                 panic("oops");
778
779         platform = (struct rk_context *)kbdev->platform_context;
780         if (NULL == platform)
781                 panic("oops");
782
783         if (!platform->mali_clk_node) {
784                 printk("mali_clk_node not init\n");
785                 return;
786         }
787         /* .KP : 将调用平台特定接口, 设置 gpu_clk. */
788         mali_dvfs_clk_set(platform->mali_clk_node,freq);
789         
790         return;
791 }
792
793 int kbase_platform_dvfs_get_level(int freq)
794 {
795         int i;
796         for (i = 0; i < MALI_DVFS_STEP; i++) {
797                 if (mali_dvfs_infotbl[i].clock == freq)
798                         return i;
799         }
800         return -1;
801 }
802
803 void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level)
804 {
805         static int prev_level = -1;
806
807         if (level == prev_level)
808                 return;
809
810         if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0))) {
811                 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
812                 return  ;
813         }
814         /*panic("invalid level");*/
815 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
816         if (mali_dvfs_status_current.upper_lock >= 0 &&
817                 level > mali_dvfs_status_current.upper_lock)
818                 level = mali_dvfs_status_current.upper_lock;
819         if (mali_dvfs_status_current.under_lock >= 0 &&
820                 level < mali_dvfs_status_current.under_lock)
821                 level = mali_dvfs_status_current.under_lock;
822 #endif
823 #ifdef CONFIG_MALI_MIDGARD_DVFS
824         mutex_lock(&mali_set_clock_lock);
825 #endif
826
827         /* 令 mali_dvfs_status_current 的 current_dvfs_level 的具体时钟配置生效. */
828         kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
829 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
830         // 将实际退出 prev_level, update mali_dvfs_level_table 中 prev_level 的 total_time_in_this_level.
831         update_time_in_state(prev_level);
832 #endif
833         prev_level = level;
834 #ifdef CONFIG_MALI_MIDGARD_DVFS
835         mutex_unlock(&mali_set_clock_lock);
836 #endif
837 }
838
839 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
840 #ifdef CONFIG_MALI_MIDGARD_DVFS
841 static u64 prev_time = 0;
842 /**
843  * update mali_dvfs_level_table 中当前 dvfs_level 'level' 的 total_time_in_this_level.
844  */
845 static void update_time_in_state(int level)
846 {
847         u64 current_time;
848
849         if (level < 0)
850                 return;
851
852 #if 0
853         /* 若当前 mali_dvfs "未开启", 则... */
854         if (!kbase_platform_dvfs_get_enable_status())
855         {
856                 return;
857         }
858 #endif
859
860         if (prev_time ==0)
861                 prev_time=get_jiffies_64();
862
863         current_time = get_jiffies_64();
864         mali_dvfs_infotbl[level].time += current_time - prev_time;
865
866         prev_time = current_time;
867 }
868 #endif
869
870 ssize_t show_time_in_state(struct device *dev,
871                            struct device_attribute *attr,
872                            char *buf)
873 {
874         struct kbase_device *kbdev;
875         ssize_t ret = 0;
876         int i;
877
878         kbdev = dev_get_drvdata(dev);
879
880 #ifdef CONFIG_MALI_MIDGARD_DVFS
881         update_time_in_state(mali_dvfs_status_current.step);
882 #endif
883         if (!kbdev)
884         {
885                 return -ENODEV;
886         }
887
888         ret += snprintf(buf + ret, 
889                         PAGE_SIZE - ret,
890                         "------------------------------------------------------------------------------");
891         ret += snprintf(buf + ret, 
892                         PAGE_SIZE - ret,
893                         "\n%-16s\t%-24s\t%-24s",
894                         "index_of_level",
895                         "gpu_clk_freq (KHz)",
896                         "time_in_this_level (s)");
897         ret += snprintf(buf + ret, 
898                         PAGE_SIZE - ret,
899                         "\n------------------------------------------------------------------------------");
900
901         for ( i = 0; i < MALI_DVFS_STEP; i++ )
902         {
903                 ret += snprintf(buf + ret, 
904                                 PAGE_SIZE - ret,
905                                 "\n%-16d\t%-24u\t%-24u",
906                                 i,
907                                 mali_dvfs_infotbl[i].clock / 1000,
908                                 jiffies_to_msecs(mali_dvfs_infotbl[i].time) / 1000);
909         }
910         ret += snprintf(buf + ret, 
911                         PAGE_SIZE - ret,
912                         "\n------------------------------------------------------------------------------");
913
914         if (ret < PAGE_SIZE - 1)
915                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
916         else {
917                 buf[PAGE_SIZE - 2] = '\n';
918                 buf[PAGE_SIZE - 1] = '\0';
919                 ret = PAGE_SIZE - 1;
920         }
921
922         return ret;
923 }
924
925 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr,
926                                                                 const char *buf, size_t count)
927 {
928         int i;
929
930         /* reset 所有 level 的 total_time_in_this_level. */
931         for (i = 0; i < MALI_DVFS_STEP; i++)
932         {
933                 mali_dvfs_infotbl[i].time = 0;
934         }
935
936         prev_time = 0;
937
938         printk(KERN_DEBUG "time_in_state value is reset complete.\n");
939         return count;
940 }
941 #endif