291632e171a25a5aa0a845ddd8f47430f39ce413
[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 #include <mali_kbase.h>
17 #include <mali_kbase_uku.h>
18 #include <mali_kbase_mem.h>
19 #include <mali_midg_regmap.h>
20 #include <mali_kbase_mem_linux.h>
21
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/poll.h>
25 #include <linux/kernel.h>
26 #include <linux/errno.h>
27 #include <linux/platform_device.h>
28 #include <linux/pci.h>
29 #include <linux/miscdevice.h>
30 #include <linux/list.h>
31 #include <linux/semaphore.h>
32 #include <linux/fs.h>
33 #include <linux/uaccess.h>
34 #include <linux/interrupt.h>
35 #include <linux/io.h>
36 #include <linux/cpufreq.h>
37 #include <linux/fb.h>
38 #include <linux/clk.h>
39 #include <linux/delay.h>
40 #include <linux/regulator/consumer.h>
41 #include <linux/regulator/driver.h>
42 #include <linux/rk_fb.h>
43
44 #include <linux/rockchip/common.h>
45
46 #include <platform/rk/mali_kbase_platform.h>
47 #include <platform/rk/mali_kbase_dvfs.h>
48 #include <mali_kbase_gator.h>
49 #include <linux/rockchip/dvfs.h>
50 /***********************************************************/
51 /*  This table and variable are using the check time share of GPU Clock  */
52 /***********************************************************/
53 extern int rockchip_tsadc_get_temp(int chn);
54 #define gpu_temp_limit 110
55 #define gpu_temp_statis_time 1
56 #define level0_min 0
57 #define level0_max 70
58 #define levelf_max 100
59 static u32 div_dvfs = 0 ;
60
61 static mali_dvfs_info mali_dvfs_infotbl[] = {
62           {925000, 100000, 0, 70, 0},
63       {925000, 160000, 50, 65, 0},
64       {1025000, 266000, 60, 78, 0},
65       {1075000, 350000, 65, 75, 0},
66       {1125000, 400000, 70, 75, 0},
67       {1200000, 500000, 90, 100, 0},
68 };
69 mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
70
71 unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
72
73 static struct cpufreq_frequency_table *mali_freq_table = NULL;
74 #ifdef CONFIG_MALI_MIDGARD_DVFS
75 typedef struct _mali_dvfs_status_type {
76         kbase_device *kbdev;
77         int step;
78         int utilisation;
79         u32 temperature;
80         u32 temperature_time;
81 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
82         int upper_lock;
83         int under_lock;
84 #endif
85
86 } mali_dvfs_status;
87
88 static struct workqueue_struct *mali_dvfs_wq = 0;
89 spinlock_t mali_dvfs_spinlock;
90 struct mutex mali_set_clock_lock;
91 struct mutex mali_enable_clock_lock;
92
93 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
94 static void update_time_in_state(int level);
95 #endif
96 /*dvfs status*/
97 static mali_dvfs_status mali_dvfs_status_current;
98
99 #define LIMIT_FPS 60
100 #define LIMIT_FPS_POWER_SAVE 50
101 static void mali_dvfs_event_proc(struct work_struct *w)
102 {
103         unsigned long flags;
104         mali_dvfs_status *dvfs_status;
105         static int level_down_time = 0;
106         static int level_up_time = 0;
107         static u32 temp_tmp;
108         struct rk_context *platform;
109         u32 fps=0;
110         u32 fps_limit;
111         u32 policy;
112         mutex_lock(&mali_enable_clock_lock);
113         dvfs_status = &mali_dvfs_status_current;
114
115         if (!kbase_platform_dvfs_get_enable_status()) {
116                 mutex_unlock(&mali_enable_clock_lock);
117                 return;
118         }
119         platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
120         
121         fps = rk_get_real_fps(0);
122
123         dvfs_status->temperature_time++;
124         temp_tmp += rockchip_tsadc_get_temp(2);
125
126         if(dvfs_status->temperature_time >= gpu_temp_statis_time)
127         {
128                 dvfs_status->temperature_time = 0;
129                 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
130                 temp_tmp = 0;
131                 /*pr_info("dvfs_status->temperature = %d\n",dvfs_status->temperature);*/
132         }
133
134         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
135         /*
136         policy = rockchip_pm_get_policy();
137         */
138         policy = ROCKCHIP_PM_POLICY_NORMAL;
139         
140         if(ROCKCHIP_PM_POLICY_PERFORMANCE == policy)
141         {
142                 dvfs_status->step = MALI_DVFS_STEP - 1; /*Highest level when performance mode*/
143         }
144         else
145         {
146                 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
147                 /*
148                 printk("policy : %d , fps_limit = %d\n",policy,fps_limit);
149                 */
150                 
151                 /*give priority to temperature unless in performance mode */
152                 if(dvfs_status->temperature > gpu_temp_limit)
153                 {
154                         if(dvfs_status->step > 0)
155                                 dvfs_status->step--;
156                         
157                         if(gpu_temp_statis_time > 1)
158                                 dvfs_status->temperature = 0;
159                 }
160                 else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) && (dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit) 
161                 {
162                         level_up_time++;
163                         if(level_up_time == MALI_DVFS_TIME_INTERVAL)
164                         {
165                                 /*
166                                 printk("up,utilisation=%d,current clock=%d,fps = %d",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
167                                 */
168                                 dvfs_status->step++;
169                                 level_up_time = 0;
170                                 /*
171                                 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
172                                 */
173                                 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
174                         }
175                         level_down_time = 0;
176                 } 
177                 else if((dvfs_status->step > 0) && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) 
178                 /*else if((dvfs_status->step > 0) && (platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) */
179                 {
180                         level_down_time++;
181                         if(level_down_time==MALI_DVFS_TIME_INTERVAL)
182                         {
183                                 /*
184                                 printk("down,utilisation=%d,current clock=%d,fps = %d",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
185                                 */
186                                 BUG_ON(dvfs_status->step <= 0);
187                                 dvfs_status->step--;
188                                 level_down_time = 0;
189                                 /*
190                                 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
191                                 */
192                         }
193                         level_up_time = 0;
194                 }
195                 else
196                 {
197                         level_down_time = 0;
198                         level_up_time = 0;
199                         /*
200                         printk("keep,utilisation=%d,current clock=%d,fps = %d\n",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
201                         */              
202                 }
203         }
204 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
205         if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock)) 
206         {
207                 dvfs_status->step = dvfs_status->upper_lock;
208         }
209
210         if (dvfs_status->under_lock > 0) 
211         {
212                 if (dvfs_status->step < dvfs_status->under_lock)
213                         dvfs_status->step = dvfs_status->under_lock;
214         }
215 #endif
216         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
217         kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
218
219         mutex_unlock(&mali_enable_clock_lock);
220 }
221
222 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
223
224 int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation)
225 {
226         unsigned long flags;
227         struct rk_context *platform;
228
229         BUG_ON(!kbdev);
230         platform = (struct rk_context *)kbdev->platform_context;
231
232         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
233         if (platform->time_tick < MALI_DVFS_TIME_INTERVAL) {
234                 platform->time_tick++;
235                 platform->time_busy += kbdev->pm.metrics.time_busy;
236                 platform->time_idle += kbdev->pm.metrics.time_idle;
237         } else {
238                 platform->time_busy = kbdev->pm.metrics.time_busy;
239                 platform->time_idle = kbdev->pm.metrics.time_idle;
240                 platform->time_tick = 0;
241         }
242
243         if ((platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->time_idle + platform->time_busy > 0))
244                 platform->utilisation = (100 * platform->time_busy) / (platform->time_idle + platform->time_busy);
245
246         mali_dvfs_status_current.utilisation = utilisation;
247         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
248
249         queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
250         /*add error handle here */
251         return MALI_TRUE;
252 }
253
254 int kbase_platform_dvfs_get_utilisation(void)
255 {
256         unsigned long flags;
257         int utilisation = 0;
258
259         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
260         utilisation = mali_dvfs_status_current.utilisation;
261         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
262
263         return utilisation;
264 }
265
266 int kbase_platform_dvfs_get_enable_status(void)
267 {
268         struct kbase_device *kbdev;
269         unsigned long flags;
270         int enable;
271
272         kbdev = mali_dvfs_status_current.kbdev;
273         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
274         enable = kbdev->pm.metrics.timer_active;
275         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
276
277         return enable;
278 }
279
280 int kbase_platform_dvfs_enable(bool enable, int freq)
281 {
282         mali_dvfs_status *dvfs_status;
283         struct kbase_device *kbdev;
284         unsigned long flags;
285         struct rk_context *platform;
286
287         dvfs_status = &mali_dvfs_status_current;
288         kbdev = mali_dvfs_status_current.kbdev;
289
290         BUG_ON(kbdev == NULL);
291         platform = (struct rk_context *)kbdev->platform_context;
292
293         mutex_lock(&mali_enable_clock_lock);
294
295         if (enable != kbdev->pm.metrics.timer_active) {
296                 if (enable) {
297                         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
298                         kbdev->pm.metrics.timer_active = MALI_TRUE;
299                         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
300                         hrtimer_start(&kbdev->pm.metrics.timer,
301                                         HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
302                                         HRTIMER_MODE_REL);
303                 } else {
304                         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
305                         kbdev->pm.metrics.timer_active = MALI_FALSE;
306                         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
307                         hrtimer_cancel(&kbdev->pm.metrics.timer);
308                 }
309         }
310
311         if (freq != MALI_DVFS_CURRENT_FREQ) {
312                 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
313                 platform->time_tick = 0;
314                 platform->time_busy = 0;
315                 platform->time_idle = 0;
316                 platform->utilisation = 0;
317                 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
318                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
319                 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
320         }
321  
322         mutex_unlock(&mali_enable_clock_lock);
323
324         return MALI_TRUE;
325 }
326 #define dividend 7
327 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
328 static bool calculate_dvfs_max_min_threshold(u32 level)
329 {
330         u32 pre_level;
331         u32     tmp ;
332         if(0 == level)
333         {
334                 if((MALI_DVFS_STEP-1) == level)
335                 {
336                         mali_dvfs_infotbl[level].min_threshold = level0_min;
337                         mali_dvfs_infotbl[level].max_threshold = levelf_max;
338                 }
339                 else 
340                 {
341                         mali_dvfs_infotbl[level].min_threshold = level0_min;
342                         mali_dvfs_infotbl[level].max_threshold = level0_max;
343                 }
344         }
345         else
346         {
347                 pre_level = level - 1;
348                 if((MALI_DVFS_STEP-1) == level)
349                 {
350                         mali_dvfs_infotbl[level].max_threshold = levelf_max;
351                 }
352                 else
353                 {
354                         mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold + div_dvfs;
355                 }
356                 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold * (mali_dvfs_infotbl[pre_level].clock/1000)) 
357                                                                                                 / (mali_dvfs_infotbl[level].clock/1000); 
358                 
359                 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
360                 
361                 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
362         }
363         #if 1
364         printk("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",level,
365                                                                                                                                                                 mali_dvfs_infotbl[level].clock,
366                                                                                                                                                                 mali_dvfs_infotbl[level].min_threshold,
367                                                                                                                                                                 mali_dvfs_infotbl[level].max_threshold
368                                                                                                                                                                 );
369         #endif
370         return MALI_TRUE;
371 }
372
373 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
374 {
375         unsigned long flags;
376         /*default status
377            add here with the right function to get initilization value.
378          */
379         struct rk_context *platform;
380         int i;
381         
382         platform = (struct rk_context *)kbdev->platform_context;
383         if (NULL == platform)
384                 panic("oops");
385                     
386         mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
387         
388         if (mali_freq_table == NULL) 
389         {
390                 printk("mali freq table not assigned yet,use default\n");
391                 goto not_assigned ;
392         }
393         else 
394         {
395                 /*recalculte step*/
396                 MALI_DVFS_STEP = 0;
397                 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) 
398                 {
399                         mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
400                         MALI_DVFS_STEP++;
401                 }
402                 if(MALI_DVFS_STEP > 1)
403                         div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1);
404                 printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs);
405                 
406                 for(i=0;i<MALI_DVFS_STEP;i++)
407                 {
408                         calculate_dvfs_max_min_threshold(i);
409                 }
410                 p_mali_dvfs_infotbl = mali_dvfs_infotbl;                                
411         }
412 not_assigned :
413         if (!mali_dvfs_wq)
414                 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
415
416         spin_lock_init(&mali_dvfs_spinlock);
417         mutex_init(&mali_set_clock_lock);
418         mutex_init(&mali_enable_clock_lock);
419
420         /*add a error handling here */
421         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
422         mali_dvfs_status_current.kbdev = kbdev;
423         mali_dvfs_status_current.utilisation = 0;
424         mali_dvfs_status_current.step = 0;
425 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
426         mali_dvfs_status_current.upper_lock = -1;
427         mali_dvfs_status_current.under_lock = -1;
428 #endif
429
430         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
431
432         return MALI_TRUE;
433 }
434
435 void kbase_platform_dvfs_term(void)
436 {
437         if (mali_dvfs_wq)
438                 destroy_workqueue(mali_dvfs_wq);
439
440         mali_dvfs_wq = NULL;
441 }
442 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
443
444 int mali_get_dvfs_upper_locked_freq(void)
445 {
446         unsigned long flags;
447         int locked_level = -1;
448
449 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
450         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
451         if (mali_dvfs_status_current.upper_lock >= 0)
452                 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
453         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
454 #endif
455         return locked_level;
456 }
457
458 int mali_get_dvfs_under_locked_freq(void)
459 {
460         unsigned long flags;
461         int locked_level = -1;
462
463 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
464         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
465         if (mali_dvfs_status_current.under_lock >= 0)
466                 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
467         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
468 #endif
469         return locked_level;
470 }
471
472 int mali_get_dvfs_current_level(void)
473 {
474         unsigned long flags;
475         int current_level = -1;
476
477 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
478         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
479         current_level = mali_dvfs_status_current.step;
480         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
481 #endif
482         return current_level;
483 }
484
485 int mali_dvfs_freq_lock(int level)
486 {
487         unsigned long flags;
488 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
489         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
490         if (mali_dvfs_status_current.under_lock >= 0 && mali_dvfs_status_current.under_lock > level) {
491                 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
492                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
493                 return -1;
494         }
495         mali_dvfs_status_current.upper_lock = level;
496         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
497
498         printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
499 #endif
500         return 0;
501 }
502
503 void mali_dvfs_freq_unlock(void)
504 {
505         unsigned long flags;
506 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
507         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
508         mali_dvfs_status_current.upper_lock = -1;
509         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
510 #endif
511         printk(KERN_DEBUG "mali Upper Lock Unset\n");
512 }
513
514 int mali_dvfs_freq_under_lock(int level)
515 {
516         unsigned long flags;
517 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
518         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
519         if (mali_dvfs_status_current.upper_lock >= 0 && mali_dvfs_status_current.upper_lock < level) {
520                 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
521                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
522                 return -1;
523         }
524         mali_dvfs_status_current.under_lock = level;
525         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
526
527         printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
528 #endif
529         return 0;
530 }
531
532 void mali_dvfs_freq_under_unlock(void)
533 {
534         unsigned long flags;
535 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
536         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
537         mali_dvfs_status_current.under_lock = -1;
538         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
539 #endif
540         printk(KERN_DEBUG " mali clock Under Lock Unset\n");
541 }
542
543 void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq)
544 {
545         struct rk_context *platform;
546
547         if (!kbdev)
548                 panic("oops");
549
550         platform = (struct rk_context *)kbdev->platform_context;
551         if (NULL == platform)
552                 panic("oops");
553
554         if (!platform->mali_clk_node) 
555         {
556                 printk("mali_clk_node not init\n");
557                 return;
558         }
559         mali_dvfs_clk_set(platform->mali_clk_node,freq);
560         
561         return;
562 }
563
564
565 int kbase_platform_dvfs_get_level(int freq)
566 {
567         int i;
568         for (i = 0; i < MALI_DVFS_STEP; i++) {
569                 if (mali_dvfs_infotbl[i].clock == freq)
570                         return i;
571         }
572         return -1;
573 }
574 void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level)
575 {
576         static int prev_level = -1;
577
578         if (level == prev_level)
579                 return;
580
581         if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0)))
582         {
583                 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
584                 return  ;
585         }
586         /*panic("invalid level");*/
587 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
588         if (mali_dvfs_status_current.upper_lock >= 0 && level > mali_dvfs_status_current.upper_lock)
589                 level = mali_dvfs_status_current.upper_lock;
590         if (mali_dvfs_status_current.under_lock >= 0 && level < mali_dvfs_status_current.under_lock)
591                 level = mali_dvfs_status_current.under_lock;
592 #endif
593 #ifdef CONFIG_MALI_MIDGARD_DVFS
594         mutex_lock(&mali_set_clock_lock);
595 #endif
596
597         kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
598 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
599         update_time_in_state(prev_level);
600 #endif
601         prev_level = level;
602 #ifdef CONFIG_MALI_MIDGARD_DVFS
603         mutex_unlock(&mali_set_clock_lock);
604 #endif
605 }
606
607 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
608 #ifdef CONFIG_MALI_MIDGARD_DVFS
609 static void update_time_in_state(int level)
610 {
611         u64 current_time;
612         static u64 prev_time=0;
613
614         if (level < 0)
615                 return;
616
617         if (!kbase_platform_dvfs_get_enable_status())
618                 return;
619
620         if (prev_time ==0)
621                 prev_time=get_jiffies_64();
622
623         current_time = get_jiffies_64();
624         mali_dvfs_infotbl[level].time += current_time-prev_time;
625
626         prev_time = current_time;
627 }
628 #endif
629
630 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
631 {
632         struct kbase_device *kbdev;
633         ssize_t ret = 0;
634         int i;
635
636         kbdev = dev_get_drvdata(dev);
637
638 #ifdef CONFIG_MALI_MIDGARD_DVFS
639         update_time_in_state(mali_dvfs_status_current.step);
640 #endif
641         if (!kbdev)
642                 return -ENODEV;
643
644         for (i = 0; i < MALI_DVFS_STEP; i++)
645                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d %llu\n", mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
646
647         if (ret < PAGE_SIZE - 1)
648                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
649         else {
650                 buf[PAGE_SIZE - 2] = '\n';
651                 buf[PAGE_SIZE - 1] = '\0';
652                 ret = PAGE_SIZE - 1;
653         }
654
655         return ret;
656 }
657
658 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
659 {
660         int i;
661
662         for (i = 0; i < MALI_DVFS_STEP; i++)
663                 mali_dvfs_infotbl[i].time = 0;
664
665         printk(KERN_DEBUG "time_in_state value is reset complete.\n");
666         return count;
667 }
668 #endif