c2f0522c7c88b4c984546b2622a61a5655559e8a
[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 #include <linux/input.h>
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         struct 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
102 #ifdef CONFIG_MALI_MIDGARD_DVFS
103 static void gpufreq_input_event(struct input_handle *handle, unsigned int type,
104                                                                                 unsigned int code, int value)
105 {
106         mali_dvfs_status *dvfs_status;
107         struct rk_context *platform;
108         unsigned long flags;
109         
110         if (type != EV_ABS)
111                 return;
112         
113         dvfs_status = &mali_dvfs_status_current;
114         platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
115         
116         spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
117         platform->gpu_in_touch = true;
118         spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
119 }
120
121 static int gpufreq_input_connect(struct input_handler *handler,
122                 struct input_dev *dev, const struct input_device_id *id)
123 {
124         struct input_handle *handle;
125         int error;
126
127         handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
128         if (!handle)
129                 return -ENOMEM;
130
131         handle->dev = dev;
132         handle->handler = handler;
133         handle->name = "gpufreq";
134
135         error = input_register_handle(handle);
136         if (error)
137                 goto err2;
138
139         error = input_open_device(handle);
140         if (error)
141                 goto err1;
142         pr_info("%s\n",__func__);
143         return 0;
144 err1:
145         input_unregister_handle(handle);
146 err2:
147         kfree(handle);
148         return error;
149 }
150
151 static void gpufreq_input_disconnect(struct input_handle *handle)
152 {
153         input_close_device(handle);
154         input_unregister_handle(handle);
155         kfree(handle);
156         pr_info("%s\n",__func__);
157 }
158
159 static const struct input_device_id gpufreq_ids[] = {
160         {
161                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
162                         INPUT_DEVICE_ID_MATCH_ABSBIT,
163                 .evbit = { BIT_MASK(EV_ABS) },
164                 .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
165                         BIT_MASK(ABS_MT_POSITION_X) |
166                         BIT_MASK(ABS_MT_POSITION_Y) },
167         },
168         {
169                 .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
170                         INPUT_DEVICE_ID_MATCH_ABSBIT,
171                 .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
172                 .absbit = { [BIT_WORD(ABS_X)] =
173                         BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
174         },
175         { },
176 };
177
178 static struct input_handler gpufreq_input_handler = {
179         .event          = gpufreq_input_event,
180         .connect        = gpufreq_input_connect,
181         .disconnect     = gpufreq_input_disconnect,
182         .name           = "gpufreq",
183         .id_table       = gpufreq_ids,
184 };
185 #endif
186
187 static void mali_dvfs_event_proc(struct work_struct *w)
188 {
189         unsigned long flags;
190         mali_dvfs_status *dvfs_status;
191         static int level_down_time = 0;
192         static int level_up_time = 0;
193         static u32 temp_tmp;
194         struct rk_context *platform;
195         u32 fps=0;
196         u32 fps_limit;
197         u32 policy;
198         mutex_lock(&mali_enable_clock_lock);
199         dvfs_status = &mali_dvfs_status_current;
200
201         if (!kbase_platform_dvfs_get_enable_status()) {
202                 mutex_unlock(&mali_enable_clock_lock);
203                 return;
204         }
205         platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
206         
207         fps = rk_get_real_fps(0);
208
209         dvfs_status->temperature_time++;
210         
211         temp_tmp += rockchip_tsadc_get_temp(1);
212         
213         if(dvfs_status->temperature_time >= gpu_temp_statis_time) {
214                 dvfs_status->temperature_time = 0;
215                 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
216                 temp_tmp = 0;
217         }
218
219         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
220         /*
221         policy = rockchip_pm_get_policy();
222         */
223         policy = ROCKCHIP_PM_POLICY_NORMAL;
224         
225         if (ROCKCHIP_PM_POLICY_PERFORMANCE == policy) {
226                 dvfs_status->step = MALI_DVFS_STEP - 1;
227         } else {
228                 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
229                 /*
230                 printk("policy : %d , fps_limit = %d\n",policy,fps_limit);
231                 */
232                 
233                 /*give priority to temperature unless in performance mode */
234                 if (dvfs_status->temperature > gpu_temp_limit) {
235                         if(dvfs_status->step > 0)
236                                 dvfs_status->step--;
237                         
238                         if(gpu_temp_statis_time > 1)
239                                 dvfs_status->temperature = 0;
240                         /*
241                         pr_info("decrease step for temperature over %d,next clock = %d\n",
242                                         gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock);
243                         */
244                 } else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) &&
245                                    (dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit) {
246                         level_up_time++;
247                         if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL) {
248                                 /*
249                                 printk("up,utilisation=%d,current clock=%d,fps = %d,temperature = %d",
250                                                 dvfs_status->utilisation, mali_dvfs_infotbl[dvfs_status->step].clock,
251                                                 fps,dvfs_status->temperature);
252                                 */
253                                 dvfs_status->step++;
254                                 level_up_time = 0;
255                                 /*
256                                 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
257                                 */
258                                 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
259                         }
260                         level_down_time = 0;
261                 } else if ((dvfs_status->step > 0) &&
262                                         (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) {
263                         level_down_time++;
264                         if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL) {
265                                 /*
266                                 printk("down,utilisation=%d,current clock=%d,fps = %d,temperature = %d",
267                                                 dvfs_status->utilisation,
268                                                 mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature);
269                                 */
270                                 BUG_ON(dvfs_status->step <= 0);
271                                 dvfs_status->step--;
272                                 level_down_time = 0;
273                                 /*
274                                 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
275                                 */
276                         }
277                         level_up_time = 0;
278                 } else {
279                         level_down_time = 0;
280                         level_up_time = 0;
281                         /*
282                         printk("keep,utilisation=%d,current clock=%d,fps = %d,temperature = %d\n",
283                                         dvfs_status->utilisation,
284                                         mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature);                       
285                         */
286                 }
287         }
288 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
289         if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock))
290                 dvfs_status->step = dvfs_status->upper_lock;
291
292         if (dvfs_status->under_lock > 0) {
293                 if (dvfs_status->step < dvfs_status->under_lock)
294                         dvfs_status->step = dvfs_status->under_lock;
295         }
296 #endif
297         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
298         kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
299
300         mutex_unlock(&mali_enable_clock_lock);
301 }
302
303 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
304
305 int kbase_platform_dvfs_event(struct kbase_device *kbdev,
306                                 u32 utilisation,
307                                 u32 util_gl_share_no_use,
308                                 u32 util_cl_share_no_use[2] )
309 {
310         unsigned long flags;
311         struct rk_context *platform;
312
313         BUG_ON(!kbdev);
314         platform = (struct rk_context *)kbdev->platform_context;
315
316         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
317         if (platform->time_tick < MALI_DVFS_UP_TIME_INTERVAL) {
318                 platform->time_tick++;
319                 platform->time_busy += kbdev->pm.backend.metrics.time_busy;
320                 
321                 platform->time_idle += kbdev->pm.backend.metrics.time_idle;
322         } else {
323                 platform->time_busy = kbdev->pm.backend.metrics.time_busy;
324                 platform->time_idle = kbdev->pm.backend.metrics.time_idle;
325                 platform->time_tick = 0;
326         }
327
328         if ((platform->time_tick == MALI_DVFS_UP_TIME_INTERVAL) &&
329                 (platform->time_idle + platform->time_busy > 0))
330                 platform->utilisation = (100 * platform->time_busy) /
331                                                                 (platform->time_idle + platform->time_busy);
332
333         mali_dvfs_status_current.utilisation = utilisation;
334         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
335
336         queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
337         /*add error handle here */
338         return MALI_TRUE;
339 }
340
341 int kbase_platform_dvfs_get_utilisation(void)
342 {
343         unsigned long flags;
344         int utilisation = 0;
345
346         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
347         utilisation = mali_dvfs_status_current.utilisation;
348         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
349
350         return utilisation;
351 }
352
353 int kbase_platform_dvfs_get_enable_status(void)
354 {
355         struct kbase_device *kbdev;
356         unsigned long flags;
357         int enable;
358
359         kbdev = mali_dvfs_status_current.kbdev;
360         spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
361         enable = kbdev->pm.backend.metrics.timer_active;
362         spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
363
364         return enable;
365 }
366
367 int kbase_platform_dvfs_enable(bool enable, int freq)
368 {
369         mali_dvfs_status *dvfs_status;
370         struct kbase_device *kbdev;
371         unsigned long flags;
372         struct rk_context *platform;
373
374         dvfs_status = &mali_dvfs_status_current;
375         kbdev = mali_dvfs_status_current.kbdev;
376
377         BUG_ON(kbdev == NULL);
378         platform = (struct rk_context *)kbdev->platform_context;
379
380         mutex_lock(&mali_enable_clock_lock);
381
382         if (enable != kbdev->pm.backend.metrics.timer_active) {
383                 if (enable) {
384                         spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
385                         kbdev->pm.backend.metrics.timer_active = MALI_TRUE;
386                         spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
387                         hrtimer_start(&kbdev->pm.backend.metrics.timer,
388                                         HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
389                                         HRTIMER_MODE_REL);
390                 } else {
391                         spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
392                         kbdev->pm.backend.metrics.timer_active = MALI_FALSE;
393                         spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
394                         hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
395                 }
396         }
397
398         if (freq != MALI_DVFS_CURRENT_FREQ) {
399                 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
400                 platform->time_tick = 0;
401                 platform->time_busy = 0;
402                 platform->time_idle = 0;
403                 platform->utilisation = 0;
404                 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
405                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
406                 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
407         }
408  
409         mutex_unlock(&mali_enable_clock_lock);
410
411         return MALI_TRUE;
412 }
413 #define dividend 7
414 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
415 static bool calculate_dvfs_max_min_threshold(u32 level)
416 {
417         u32 pre_level;
418         u32     tmp ;
419         if (0 == level) {
420                 if ((MALI_DVFS_STEP-1) == level) {
421                         mali_dvfs_infotbl[level].min_threshold = level0_min;
422                         mali_dvfs_infotbl[level].max_threshold = levelf_max;
423                 } else {
424                         mali_dvfs_infotbl[level].min_threshold = level0_min;
425                         mali_dvfs_infotbl[level].max_threshold = level0_max;
426                 }
427         } else {
428                 pre_level = level - 1;
429                 if ((MALI_DVFS_STEP-1) == level) {
430                         mali_dvfs_infotbl[level].max_threshold = levelf_max;
431                 } else {
432                         mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold +
433                                                                                                          div_dvfs;
434                 }
435                 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold *
436                                                                                                   (mali_dvfs_infotbl[pre_level].clock/1000)) /
437                                                                                                   (mali_dvfs_infotbl[level].clock/1000); 
438                 
439                 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
440                 
441                 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
442         }
443         pr_info("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",
444                         level,mali_dvfs_infotbl[level].clock, mali_dvfs_infotbl[level].min_threshold,
445                         mali_dvfs_infotbl[level].max_threshold);
446         return MALI_TRUE;
447 }
448
449 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
450 {
451         unsigned long flags;
452         /*default status
453            add here with the right function to get initilization value.
454          */
455         struct rk_context *platform;
456         int i;
457         int rc;
458         
459         platform = (struct rk_context *)kbdev->platform_context;
460         if (NULL == platform)
461                 panic("oops");
462                     
463         mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
464         
465         if (mali_freq_table == NULL) {
466                 printk("mali freq table not assigned yet,use default\n");
467                 goto not_assigned ;
468         } else {
469                 /*recalculte step*/
470                 MALI_DVFS_STEP = 0;
471                 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
472                         mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
473                         MALI_DVFS_STEP++;
474                 }
475                 if(MALI_DVFS_STEP > 1)
476                         div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1);
477                 printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs);
478                 
479                 for(i=0;i<MALI_DVFS_STEP;i++)
480                         calculate_dvfs_max_min_threshold(i);
481                 p_mali_dvfs_infotbl = mali_dvfs_infotbl;                                
482         }
483 not_assigned :
484         if (!mali_dvfs_wq)
485                 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
486
487         spin_lock_init(&mali_dvfs_spinlock);
488         mutex_init(&mali_set_clock_lock);
489         mutex_init(&mali_enable_clock_lock);
490
491         spin_lock_init(&platform->gpu_in_touch_lock);
492         rc = input_register_handler(&gpufreq_input_handler);
493
494         /*add a error handling here */
495         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
496         mali_dvfs_status_current.kbdev = kbdev;
497         mali_dvfs_status_current.utilisation = 0;
498         mali_dvfs_status_current.step = 0;
499 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
500         mali_dvfs_status_current.upper_lock = -1;
501         mali_dvfs_status_current.under_lock = -1;
502 #endif
503
504         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
505
506         return MALI_TRUE;
507 }
508
509 void kbase_platform_dvfs_term(void)
510 {
511         if (mali_dvfs_wq)
512                 destroy_workqueue(mali_dvfs_wq);
513
514         mali_dvfs_wq = NULL;
515         
516         input_unregister_handler(&gpufreq_input_handler);
517 }
518 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
519
520 int mali_get_dvfs_upper_locked_freq(void)
521 {
522         unsigned long flags;
523         int locked_level = -1;
524
525 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
526         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
527         if (mali_dvfs_status_current.upper_lock >= 0)
528                 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
529         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
530 #endif
531         return locked_level;
532 }
533
534 int mali_get_dvfs_under_locked_freq(void)
535 {
536         unsigned long flags;
537         int locked_level = -1;
538
539 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
540         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
541         if (mali_dvfs_status_current.under_lock >= 0)
542                 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
543         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
544 #endif
545         return locked_level;
546 }
547
548 int mali_get_dvfs_current_level(void)
549 {
550         unsigned long flags;
551         int current_level = -1;
552
553 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
554         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
555         current_level = mali_dvfs_status_current.step;
556         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
557 #endif
558         return current_level;
559 }
560
561 int mali_dvfs_freq_lock(int level)
562 {
563         unsigned long flags;
564 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
565         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
566         if (mali_dvfs_status_current.under_lock >= 0 &&
567                 mali_dvfs_status_current.under_lock > level) {
568                 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
569                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
570                 return -1;
571         }
572         mali_dvfs_status_current.upper_lock = level;
573         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
574
575         printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
576 #endif
577         return 0;
578 }
579
580 void mali_dvfs_freq_unlock(void)
581 {
582         unsigned long flags;
583 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
584         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
585         mali_dvfs_status_current.upper_lock = -1;
586         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
587 #endif
588         printk(KERN_DEBUG "mali Upper Lock Unset\n");
589 }
590
591 int mali_dvfs_freq_under_lock(int level)
592 {
593         unsigned long flags;
594 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
595         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
596         if (mali_dvfs_status_current.upper_lock >= 0 &&
597                 mali_dvfs_status_current.upper_lock < level) {
598                 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
599                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
600                 return -1;
601         }
602         mali_dvfs_status_current.under_lock = level;
603         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
604
605         printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
606 #endif
607         return 0;
608 }
609
610 void mali_dvfs_freq_under_unlock(void)
611 {
612         unsigned long flags;
613 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
614         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
615         mali_dvfs_status_current.under_lock = -1;
616         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
617 #endif
618         printk(KERN_DEBUG " mali clock Under Lock Unset\n");
619 }
620
621 void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq)
622 {
623         struct rk_context *platform;
624
625         if (!kbdev)
626                 panic("oops");
627
628         platform = (struct rk_context *)kbdev->platform_context;
629         if (NULL == platform)
630                 panic("oops");
631
632         if (!platform->mali_clk_node) {
633                 printk("mali_clk_node not init\n");
634                 return;
635         }
636         mali_dvfs_clk_set(platform->mali_clk_node,freq);
637         
638         return;
639 }
640
641
642 int kbase_platform_dvfs_get_level(int freq)
643 {
644         int i;
645         for (i = 0; i < MALI_DVFS_STEP; i++) {
646                 if (mali_dvfs_infotbl[i].clock == freq)
647                         return i;
648         }
649         return -1;
650 }
651 void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level)
652 {
653         static int prev_level = -1;
654
655         if (level == prev_level)
656                 return;
657
658         if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0))) {
659                 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
660                 return  ;
661         }
662         /*panic("invalid level");*/
663 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
664         if (mali_dvfs_status_current.upper_lock >= 0 &&
665                 level > mali_dvfs_status_current.upper_lock)
666                 level = mali_dvfs_status_current.upper_lock;
667         if (mali_dvfs_status_current.under_lock >= 0 &&
668                 level < mali_dvfs_status_current.under_lock)
669                 level = mali_dvfs_status_current.under_lock;
670 #endif
671 #ifdef CONFIG_MALI_MIDGARD_DVFS
672         mutex_lock(&mali_set_clock_lock);
673 #endif
674
675         kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
676 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
677         update_time_in_state(prev_level);
678 #endif
679         prev_level = level;
680 #ifdef CONFIG_MALI_MIDGARD_DVFS
681         mutex_unlock(&mali_set_clock_lock);
682 #endif
683 }
684
685 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
686 #ifdef CONFIG_MALI_MIDGARD_DVFS
687 static void update_time_in_state(int level)
688 {
689         u64 current_time;
690         static u64 prev_time=0;
691
692         if (level < 0)
693                 return;
694
695         if (!kbase_platform_dvfs_get_enable_status())
696                 return;
697
698         if (prev_time ==0)
699                 prev_time=get_jiffies_64();
700
701         current_time = get_jiffies_64();
702         mali_dvfs_infotbl[level].time += current_time-prev_time;
703
704         prev_time = current_time;
705 }
706 #endif
707
708 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr,
709                                                                         char *buf)
710 {
711         struct kbase_device *kbdev;
712         ssize_t ret = 0;
713         int i;
714
715         kbdev = dev_get_drvdata(dev);
716
717 #ifdef CONFIG_MALI_MIDGARD_DVFS
718         update_time_in_state(mali_dvfs_status_current.step);
719 #endif
720         if (!kbdev)
721                 return -ENODEV;
722
723         for (i = 0; i < MALI_DVFS_STEP; i++)
724                 ret += snprintf(buf + ret, PAGE_SIZE - ret,
725                                                 "%d %llu\n",
726                                                 mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
727
728         if (ret < PAGE_SIZE - 1)
729                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
730         else {
731                 buf[PAGE_SIZE - 2] = '\n';
732                 buf[PAGE_SIZE - 1] = '\0';
733                 ret = PAGE_SIZE - 1;
734         }
735
736         return ret;
737 }
738
739 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr,
740                                                                 const char *buf, size_t count)
741 {
742         int i;
743
744         for (i = 0; i < MALI_DVFS_STEP; i++)
745                 mali_dvfs_infotbl[i].time = 0;
746
747         printk(KERN_DEBUG "time_in_state value is reset complete.\n");
748         return count;
749 }
750 #endif