rk3288 midgard:optimize gpu frequency scaling
[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 <platform/rk/mali_kbase_platform.h>
43 #include <platform/rk/mali_kbase_dvfs.h>
44 #include <mali_kbase_gator.h>
45 #include <linux/rockchip/dvfs.h>
46 /***********************************************************/
47 /*  This table and variable are using the check time share of GPU Clock  */
48 /***********************************************************/
49
50 static mali_dvfs_info mali_dvfs_infotbl[] = {
51           {925000, 100000, 0, 70, 0},
52       {925000, 160000, 50, 65, 0},
53       {1025000, 266000, 60, 78, 0},
54       {1075000, 350000, 65, 75, 0},
55       {1125000, 400000, 70, 75, 0},
56       {1200000, 500000, 90, 100, 0},
57 };
58 mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
59
60 unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
61
62 static struct cpufreq_frequency_table *mali_freq_table = NULL;
63 #ifdef CONFIG_MALI_MIDGARD_DVFS
64 typedef struct _mali_dvfs_status_type {
65         kbase_device *kbdev;
66         int step;
67         int utilisation;
68 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
69         int upper_lock;
70         int under_lock;
71 #endif
72
73 } mali_dvfs_status;
74
75 static struct workqueue_struct *mali_dvfs_wq = 0;
76 spinlock_t mali_dvfs_spinlock;
77 struct mutex mali_set_clock_lock;
78 struct mutex mali_enable_clock_lock;
79
80 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
81 static void update_time_in_state(int level);
82 #endif
83
84 /*dvfs status*/
85 static mali_dvfs_status mali_dvfs_status_current;
86
87 static void mali_dvfs_event_proc(struct work_struct *w)
88 {
89         unsigned long flags;
90         mali_dvfs_status *dvfs_status;
91         struct rk_context *platform;
92
93         mutex_lock(&mali_enable_clock_lock);
94         dvfs_status = &mali_dvfs_status_current;
95
96         if (!kbase_platform_dvfs_get_enable_status()) {
97                 mutex_unlock(&mali_enable_clock_lock);
98                 return;
99         }
100
101         platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
102         
103         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
104         if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) && (dvfs_status->step < MALI_DVFS_STEP-1)) 
105         {
106         #if 0
107                 if (dvfs_status->step==kbase_platform_dvfs_get_level(450)) 
108                 {
109                         if (platform->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold)
110                                 dvfs_status->step++;
111                         BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
112                 } 
113                 else 
114                 {
115                         dvfs_status->step++;
116                         BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
117                 }
118         #endif
119                 dvfs_status->step++;
120                 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
121
122         } 
123         //else if((dvfs_status->step > 0) && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) 
124         else if((dvfs_status->step > 0) && (platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) 
125         {
126                 BUG_ON(dvfs_status->step <= 0);
127                 dvfs_status->step--;
128         }
129 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
130         if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock)) 
131         {
132                 dvfs_status->step = dvfs_status->upper_lock;
133         }
134
135         if (dvfs_status->under_lock > 0) 
136         {
137                 if (dvfs_status->step < dvfs_status->under_lock)
138                         dvfs_status->step = dvfs_status->under_lock;
139         }
140 #endif
141         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
142         //printk("%n",__func__);
143         kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
144
145         mutex_unlock(&mali_enable_clock_lock);
146 }
147
148 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
149
150 int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation)
151 {
152         unsigned long flags;
153         struct rk_context *platform;
154
155         BUG_ON(!kbdev);
156         platform = (struct rk_context *)kbdev->platform_context;
157
158         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
159         if (platform->time_tick < MALI_DVFS_TIME_INTERVAL) {
160                 platform->time_tick++;
161                 platform->time_busy += kbdev->pm.metrics.time_busy;
162                 platform->time_idle += kbdev->pm.metrics.time_idle;
163         } else {
164                 platform->time_busy = kbdev->pm.metrics.time_busy;
165                 platform->time_idle = kbdev->pm.metrics.time_idle;
166                 platform->time_tick = 0;
167         }
168
169         if ((platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->time_idle + platform->time_busy > 0))
170                 platform->utilisation = (100 * platform->time_busy) / (platform->time_idle + platform->time_busy);
171
172         mali_dvfs_status_current.utilisation = utilisation;
173         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
174
175         queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
176         /*add error handle here */
177         return MALI_TRUE;
178 }
179
180 int kbase_platform_dvfs_get_utilisation(void)
181 {
182         unsigned long flags;
183         int utilisation = 0;
184
185         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
186         utilisation = mali_dvfs_status_current.utilisation;
187         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
188
189         return utilisation;
190 }
191
192 int kbase_platform_dvfs_get_enable_status(void)
193 {
194         struct kbase_device *kbdev;
195         unsigned long flags;
196         int enable;
197
198         kbdev = mali_dvfs_status_current.kbdev;
199         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
200         enable = kbdev->pm.metrics.timer_active;
201         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
202
203         return enable;
204 }
205
206 int kbase_platform_dvfs_enable(bool enable, int freq)
207 {
208         mali_dvfs_status *dvfs_status;
209         struct kbase_device *kbdev;
210         unsigned long flags;
211         struct rk_context *platform;
212
213         dvfs_status = &mali_dvfs_status_current;
214         kbdev = mali_dvfs_status_current.kbdev;
215
216         BUG_ON(kbdev == NULL);
217         platform = (struct rk_context *)kbdev->platform_context;
218
219         mutex_lock(&mali_enable_clock_lock);
220
221         if (enable != kbdev->pm.metrics.timer_active) {
222                 if (enable) {
223                         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
224                         kbdev->pm.metrics.timer_active = MALI_TRUE;
225                         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
226                         hrtimer_start(&kbdev->pm.metrics.timer,
227                                         HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
228                                         HRTIMER_MODE_REL);
229                 } else {
230                         spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
231                         kbdev->pm.metrics.timer_active = MALI_FALSE;
232                         spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
233                         hrtimer_cancel(&kbdev->pm.metrics.timer);
234                 }
235         }
236
237         if (freq != MALI_DVFS_CURRENT_FREQ) {
238                 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
239                 platform->time_tick = 0;
240                 platform->time_busy = 0;
241                 platform->time_idle = 0;
242                 platform->utilisation = 0;
243                 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
244                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
245                 //printk("%s,freq = %d\n",__func__,freq);
246                 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
247         }
248  
249         mutex_unlock(&mali_enable_clock_lock);
250
251         return MALI_TRUE;
252 }
253
254 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
255 {
256         unsigned long flags;
257         /*default status
258            add here with the right function to get initilization value.
259          */
260         struct rk_context *platform;
261         int i;
262         
263         platform = (struct rk_context *)kbdev->platform_context;
264         if (NULL == platform)
265                 panic("oops");
266                     
267         mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
268         
269         if (mali_freq_table == NULL) 
270         {
271                 printk("mali freq table not assigned yet,use default\n");
272                 goto not_assigned ;
273         }
274         else 
275         {
276                 /*recalculte step*/
277                 MALI_DVFS_STEP = 0;
278                 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) 
279                 {
280                         if((mali_freq_table[i].frequency > 0) && (mali_freq_table[i].frequency <= 100000))
281                         {
282                                 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
283                                 mali_dvfs_infotbl[i].min_threshold = 0;
284                                 mali_dvfs_infotbl[i].max_threshold = 70;
285                                 MALI_DVFS_STEP++;
286                         }
287                         else if ((mali_freq_table[i].frequency > 100000) && (mali_freq_table[i].frequency <= 200000))
288                         {
289                                 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
290                                 mali_dvfs_infotbl[i].min_threshold = 50;
291                                 mali_dvfs_infotbl[i].max_threshold = 65;
292                                 MALI_DVFS_STEP++;
293                         }
294                         else if ((mali_freq_table[i].frequency > 200000) && (mali_freq_table[i].frequency <= 300000))
295                         {
296                                 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
297                                 mali_dvfs_infotbl[i].min_threshold = 60;
298                                 mali_dvfs_infotbl[i].max_threshold = 78;
299                                 MALI_DVFS_STEP++;
300                         }
301                         else if ((mali_freq_table[i].frequency > 300000) && (mali_freq_table[i].frequency <= 400000))
302                         {
303                                 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
304                                 mali_dvfs_infotbl[i].min_threshold = 65;
305                                 mali_dvfs_infotbl[i].max_threshold = 75;                
306                                 MALI_DVFS_STEP++;
307                         }
308                         else if ((mali_freq_table[i].frequency > 400000) && (mali_freq_table[i].frequency <= 500000))
309                         {
310                                 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
311                                 mali_dvfs_infotbl[i].min_threshold = 90;
312                                 mali_dvfs_infotbl[i].max_threshold = 100;
313                                 MALI_DVFS_STEP++;
314                         }                       
315                 }
316                 p_mali_dvfs_infotbl = mali_dvfs_infotbl;                                
317         }
318 not_assigned :
319         if (!mali_dvfs_wq)
320                 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
321
322         spin_lock_init(&mali_dvfs_spinlock);
323         mutex_init(&mali_set_clock_lock);
324         mutex_init(&mali_enable_clock_lock);
325
326         /*add a error handling here */
327         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
328         mali_dvfs_status_current.kbdev = kbdev;
329         mali_dvfs_status_current.utilisation = 0;
330         mali_dvfs_status_current.step = 0;
331 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
332         mali_dvfs_status_current.upper_lock = -1;
333         mali_dvfs_status_current.under_lock = -1;
334 #endif
335
336         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
337
338         return MALI_TRUE;
339 }
340
341 void kbase_platform_dvfs_term(void)
342 {
343         if (mali_dvfs_wq)
344                 destroy_workqueue(mali_dvfs_wq);
345
346         mali_dvfs_wq = NULL;
347 }
348 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
349
350 int mali_get_dvfs_upper_locked_freq(void)
351 {
352         unsigned long flags;
353         int locked_level = -1;
354
355 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
356         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
357         if (mali_dvfs_status_current.upper_lock >= 0)
358                 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
359         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
360 #endif
361         return locked_level;
362 }
363
364 int mali_get_dvfs_under_locked_freq(void)
365 {
366         unsigned long flags;
367         int locked_level = -1;
368
369 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
370         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
371         if (mali_dvfs_status_current.under_lock >= 0)
372                 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
373         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
374 #endif
375         return locked_level;
376 }
377
378 int mali_get_dvfs_current_level(void)
379 {
380         unsigned long flags;
381         int current_level = -1;
382
383 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
384         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
385         current_level = mali_dvfs_status_current.step;
386         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
387 #endif
388         return current_level;
389 }
390
391 int mali_dvfs_freq_lock(int level)
392 {
393         unsigned long flags;
394 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
395         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
396         if (mali_dvfs_status_current.under_lock >= 0 && mali_dvfs_status_current.under_lock > level) {
397                 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
398                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
399                 return -1;
400         }
401         mali_dvfs_status_current.upper_lock = level;
402         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
403
404         printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
405 #endif
406         return 0;
407 }
408
409 void mali_dvfs_freq_unlock(void)
410 {
411         unsigned long flags;
412 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
413         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
414         mali_dvfs_status_current.upper_lock = -1;
415         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
416 #endif
417         printk(KERN_DEBUG "mali Upper Lock Unset\n");
418 }
419
420 int mali_dvfs_freq_under_lock(int level)
421 {
422         unsigned long flags;
423 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
424         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
425         if (mali_dvfs_status_current.upper_lock >= 0 && mali_dvfs_status_current.upper_lock < level) {
426                 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
427                 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
428                 return -1;
429         }
430         mali_dvfs_status_current.under_lock = level;
431         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
432
433         printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
434 #endif
435         return 0;
436 }
437
438 void mali_dvfs_freq_under_unlock(void)
439 {
440         unsigned long flags;
441 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
442         spin_lock_irqsave(&mali_dvfs_spinlock, flags);
443         mali_dvfs_status_current.under_lock = -1;
444         spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
445 #endif
446         printk(KERN_DEBUG " mali clock Under Lock Unset\n");
447 }
448
449 void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq)
450 {
451         struct rk_context *platform;
452
453         if (!kbdev)
454                 panic("oops");
455
456         platform = (struct rk_context *)kbdev->platform_context;
457         if (NULL == platform)
458                 panic("oops");
459
460         if (!platform->mali_clk_node) 
461         {
462                 printk("mali_clk_node not init\n");
463                 return;
464         }
465         mali_dvfs_clk_set(platform->mali_clk_node,freq);
466         
467         return;
468 }
469
470
471 int kbase_platform_dvfs_get_level(int freq)
472 {
473         int i;
474         for (i = 0; i < MALI_DVFS_STEP; i++) {
475                 if (mali_dvfs_infotbl[i].clock == freq)
476                         return i;
477         }
478         return -1;
479 }
480 void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level)
481 {
482         static int prev_level = -1;
483
484         if (level == prev_level)
485                 return;
486
487         if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0)))
488         {
489                 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
490                 return  ;
491         }
492         //panic("invalid level");
493 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
494         if (mali_dvfs_status_current.upper_lock >= 0 && level > mali_dvfs_status_current.upper_lock)
495                 level = mali_dvfs_status_current.upper_lock;
496         if (mali_dvfs_status_current.under_lock >= 0 && level < mali_dvfs_status_current.under_lock)
497                 level = mali_dvfs_status_current.under_lock;
498 #endif
499 #ifdef CONFIG_MALI_MIDGARD_DVFS
500         mutex_lock(&mali_set_clock_lock);
501 #endif
502         kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
503 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
504         update_time_in_state(prev_level);
505 #endif
506         prev_level = level;
507 #ifdef CONFIG_MALI_MIDGARD_DVFS
508         mutex_unlock(&mali_set_clock_lock);
509 #endif
510 }
511
512 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
513 #ifdef CONFIG_MALI_MIDGARD_DVFS
514 static void update_time_in_state(int level)
515 {
516         u64 current_time;
517         static u64 prev_time=0;
518
519         if (level < 0)
520                 return;
521
522         if (!kbase_platform_dvfs_get_enable_status())
523                 return;
524
525         if (prev_time ==0)
526                 prev_time=get_jiffies_64();
527
528         current_time = get_jiffies_64();
529         mali_dvfs_infotbl[level].time += current_time-prev_time;
530
531         prev_time = current_time;
532 }
533 #endif
534
535 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
536 {
537         struct kbase_device *kbdev;
538         ssize_t ret = 0;
539         int i;
540
541         kbdev = dev_get_drvdata(dev);
542
543 #ifdef CONFIG_MALI_MIDGARD_DVFS
544         update_time_in_state(mali_dvfs_status_current.step);
545 #endif
546         if (!kbdev)
547                 return -ENODEV;
548
549         for (i = 0; i < MALI_DVFS_STEP; i++)
550                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d %llu\n", mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
551
552         if (ret < PAGE_SIZE - 1)
553                 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
554         else {
555                 buf[PAGE_SIZE - 2] = '\n';
556                 buf[PAGE_SIZE - 1] = '\0';
557                 ret = PAGE_SIZE - 1;
558         }
559
560         return ret;
561 }
562
563 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
564 {
565         int i;
566
567         for (i = 0; i < MALI_DVFS_STEP; i++)
568                 mali_dvfs_infotbl[i].time = 0;
569
570         printk(KERN_DEBUG "time_in_state value is reset complete.\n");
571         return count;
572 }
573 #endif