rk312x: gpu: disable the highest freq except benchmark,version to 0x03
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / platform / rk30 / mali_platform.c
1 /*
2  * This confidential and proprietary software may be used only as
3  * authorised by a licensing agreement from ARM Limited
4  * (C) COPYRIGHT 2009-2012 ARM Limited
5  * ALL RIGHTS RESERVED
6  * The entire notice above must be reproduced on all authorised
7  * copies and copies may only be made to the extent permitted
8  * by a licensing agreement from ARM Limited.
9  */
10
11 /**
12  * @file mali_platform.c
13  * Platform specific Mali driver functions for a default platform
14  */
15 #include "mali_kernel_common.h"
16 #include "mali_osk.h"
17 #include "mali_platform.h"
18 #include <linux/workqueue.h>
19 #include <linux/kernel.h>
20 #include <linux/slab.h>
21 #include <linux/gfp.h>
22 #include <linux/fs.h>
23 #include <linux/clk.h>
24 #include <linux/device.h>
25 #ifdef CONFIG_HAS_EARLYSUSPEND
26 #include <linux/earlysuspend.h>
27 #endif 
28
29 #include <linux/miscdevice.h>
30 #include <asm/uaccess.h>
31 #include <linux/module.h>
32 #include <linux/cpufreq.h>
33
34 #include <linux/rockchip/cpu.h>
35 #include <linux/rockchip/dvfs.h>
36 #define GPUCLK_NAME     "clk_gpu"
37 #define GPUCLK_PD_NAME                           "pd_gpu"
38 #define GPU_MHZ                                          1000000
39 static struct dvfs_node *mali_clock = 0;
40 static struct clk *mali_clock_pd = 0;
41 static struct clk *audis_gpu_clk = 0;
42
43 #define MALI_DVFS_DEFAULT_STEP 0 // 50Mhz default
44
45 u32 mali_dvfs[] = {50, 100, 133, 160, 200, 266, 400};
46 int num_clock;
47 u32 mali_init_clock = 50;
48 static int minuend = 0;
49
50 static struct cpufreq_frequency_table *freq_table = NULL; 
51
52 module_param_array(mali_dvfs, int, &num_clock,S_IRUGO | S_IWUSR);
53 MODULE_PARM_DESC(mali_dvfs,"mali clock table");
54
55 module_param(mali_init_clock, int,S_IRUGO | S_IWUSR);
56 MODULE_PARM_DESC(mali_init_clock,"mali init clock value");
57 u32 mali_group_error = 0;
58 u32 scale_enable = 1;
59 u32 gpu_power_state = 0;
60 static u32 utilization_global = 0;
61
62 u32 mali_utilization_timeout = 10;
63 u32 sampling_enable = 1;
64 #define mali_freq_workqueue_name         "mali_freq_workqueue"
65 #define mali_freq_work_name              "mali_freq_work"
66 struct mali_freq_data {
67         struct workqueue_struct *wq;
68         struct work_struct work;
69         u32 freq;
70 }*mali_freq_data;
71
72 typedef struct mali_dvfs_tableTag{
73         u32 clock;
74         u32 vol;
75 }mali_dvfs_table;
76
77 typedef struct mali_dvfs_statusTag{
78     int currentStep;
79     mali_dvfs_table * pCurrentDvfs;
80
81 }mali_dvfs_status;
82
83 mali_dvfs_status maliDvfsStatus;
84
85 #define GPU_DVFS_UP_THRESHOLD   ((int)((255*50)/100))   
86 #define GPU_DVFS_DOWN_THRESHOLD ((int)((255*35)/100))   
87
88 _mali_osk_mutex_t *clockSetlock;
89
90 struct clk* mali_clk_get(unsigned char *name)
91 {
92         struct clk *clk;
93         clk = clk_get(NULL,name);
94         return clk;
95 }
96 unsigned long mali_clk_get_rate(struct dvfs_node *clk)
97 {
98         return dvfs_clk_get_rate(clk);
99 }
100
101 void mali_clk_set_rate(struct dvfs_node *clk, u32 value)
102 {
103         unsigned long rate = (unsigned long)value * GPU_MHZ;
104         dvfs_clk_set_rate(clk, rate);
105         rate = mali_clk_get_rate(clk);
106 }
107
108 static struct kobject *mali400_utility_object;
109 static u32 get_mali_dvfs_status(void)
110 {
111         return maliDvfsStatus.currentStep;
112 }
113 static void set_mali_dvfs_step(u32 value)
114 {
115         maliDvfsStatus.currentStep = value;
116 }
117
118 static void scale_enable_set(u32 value)
119 {
120         scale_enable = value;
121 }
122 static u32 mali_dvfs_search(u32 value)
123 {
124         u32 i;  
125         u32 clock = value;
126         for (i=0;i<num_clock;i++) {
127                 if (clock == mali_dvfs[i]) {
128                         _mali_osk_mutex_wait(clockSetlock);
129                         mali_clk_set_rate(mali_clock,clock);
130                         _mali_osk_mutex_signal(clockSetlock);
131                         set_mali_dvfs_step(i);
132                         scale_enable_set(0);
133                         return 0;
134                 }
135                 if(i>=7)
136                 MALI_DEBUG_PRINT(2,("USER set clock not in the mali_dvfs table\r\n"));
137         }
138         return 1;
139 }
140
141 static int mali400_utility_show(struct device *dev,struct device_attribute *attr, char *buf)
142 {
143         return sprintf(buf, "%d\n", utilization_global);
144 }
145 static int mali400_clock_set(struct device *dev,struct device_attribute *attr, const char *buf,u32 count)
146 {
147         u32 clock;
148         u32 currentStep;
149         u64 timeValue;
150         clock = simple_strtoul(buf, NULL, 10);
151         currentStep = get_mali_dvfs_status();
152         timeValue = _mali_osk_time_get_ns();
153         /*MALI_PRINT(("USER SET CLOCK,%d\r\n",clock));*/
154         if(!clock) {
155                 scale_enable_set(1);
156         } else {
157                 mali_dvfs_search(clock);
158         }
159         return count;
160 }
161 static int clock_show(struct device *dev,struct device_attribute *attr, char *buf)
162 {
163         u32 i;
164         char *pos = buf;
165         pos += snprintf(pos,PAGE_SIZE,"%d,",num_clock);
166         for(i=0;i<(num_clock-1);i++) {
167                 pos += snprintf(pos,PAGE_SIZE,"%d,",mali_dvfs[i]);
168         }
169         pos +=snprintf(pos,PAGE_SIZE,"%d\n",mali_dvfs[i]); 
170         return pos - buf;
171 }
172 static int sampling_timeout_show(struct device *dev,struct device_attribute *attr, char *buf)
173 {
174         return sprintf(buf, "mali_utilization_timeout = %d\n", mali_utilization_timeout);
175 }
176 static int sampling_timeout_set(struct device *dev,struct device_attribute *attr,
177                                 const char *buf,u32 count)
178 {
179         u32 sampling;
180         sampling = simple_strtoul(buf, NULL, 10);
181         
182         if (sampling == 0 ) {
183                 sampling_enable = 0;
184                 MALI_PRINT(("disable mali clock frequency scalling\r\n"));
185         } else {
186                 mali_utilization_timeout = sampling;
187                 sampling_enable = 1;
188                 MALI_PRINT(("enable mali clock frequency scalling ,mali_utilization_timeout : %dms\r\n",
189                             mali_utilization_timeout));
190         }
191         return count;
192 }
193 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
194 {
195         return sprintf(buf, "%d\n", mali_group_error);
196 }
197
198 static DEVICE_ATTR(utility, 0644, mali400_utility_show, mali400_clock_set);
199 static DEVICE_ATTR(param, 0644, clock_show, NULL);
200 static DEVICE_ATTR(sampling_timeout, 0644, sampling_timeout_show,sampling_timeout_set);
201 static DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
202
203
204 static mali_bool mali400_utility_sysfs_init(void)
205 {
206         u32 ret ;
207
208         mali400_utility_object = kobject_create_and_add("mali400_utility", NULL);
209         if (mali400_utility_object == NULL) {
210                 return -1;
211         }
212         ret = sysfs_create_file(mali400_utility_object, &dev_attr_utility.attr);
213         if (ret) {
214                 return -1;
215         }
216         ret = sysfs_create_file(mali400_utility_object, &dev_attr_param.attr);
217         if (ret) {
218                 return -1;
219         }
220         ret = sysfs_create_file(mali400_utility_object, &dev_attr_sampling_timeout.attr);
221         if(ret){
222                 return -1;      
223         }
224         ret = sysfs_create_file(mali400_utility_object, &dev_attr_error_count.attr);
225         if(ret){
226                 return -1;
227         }
228         return 0 ;
229 }       
230 static unsigned int decideNextStatus(unsigned int utilization)
231 {
232     u32 level=0;
233
234     if(utilization > GPU_DVFS_UP_THRESHOLD &&
235              maliDvfsStatus.currentStep == 0 &&
236              maliDvfsStatus.currentStep < (num_clock-minuend))
237             level = 1;
238     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
239              maliDvfsStatus.currentStep == 1 &&
240              maliDvfsStatus.currentStep < (num_clock-minuend))
241             level = 2;
242     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
243              maliDvfsStatus.currentStep == 2 &&
244              maliDvfsStatus.currentStep < (num_clock-minuend))
245             level = 3;
246     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
247              maliDvfsStatus.currentStep == 3 &&
248              maliDvfsStatus.currentStep < (num_clock-minuend))
249             level = 4;
250     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
251              maliDvfsStatus.currentStep == 4 &&
252              maliDvfsStatus.currentStep < (num_clock-minuend))
253             level = 5;
254     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
255              maliDvfsStatus.currentStep == 5 &&
256              maliDvfsStatus.currentStep < (num_clock-minuend))
257             level = 6;
258         /*
259         determined by minuend to up to level 6
260         */
261     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
262             maliDvfsStatus.currentStep == 6)
263             level = 5;
264     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
265             maliDvfsStatus.currentStep == 5)
266             level = 4;
267     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
268             maliDvfsStatus.currentStep == 4)
269             level = 3;
270     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
271             maliDvfsStatus.currentStep == 3)
272             level = 2;
273     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
274             maliDvfsStatus.currentStep == 2)
275             level = 1;
276     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
277             maliDvfsStatus.currentStep == 1)
278             level = 0;
279     else
280             level = maliDvfsStatus.currentStep;
281     return level;
282 }
283
284 static mali_bool set_mali_dvfs_status(u32 step)
285 {
286         u32 validatedStep=step; 
287
288         _mali_osk_mutex_wait(clockSetlock);
289         mali_clk_set_rate(mali_clock, mali_dvfs[validatedStep]);
290         _mali_osk_mutex_signal(clockSetlock);
291         set_mali_dvfs_step(validatedStep);
292         
293         return MALI_TRUE;
294 }
295
296 static mali_bool change_mali_dvfs_status(u32 step)
297 {
298         if(!set_mali_dvfs_status(step)) {
299                 MALI_DEBUG_PRINT(2,("error on set_mali_dvfs_status: %d\n",step));
300                 return MALI_FALSE;
301         }
302
303         return MALI_TRUE;
304 }
305
306 static void  mali_freq_scale_work(struct work_struct *work)
307 {       
308
309         u32 nextStatus = 0;
310         u32 curStatus = 0;
311
312         curStatus = get_mali_dvfs_status();
313         nextStatus = decideNextStatus(utilization_global);
314         
315         if (curStatus!=nextStatus) {
316                 if (!change_mali_dvfs_status(nextStatus)) {
317                         MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
318                 }
319         }               
320 }
321 static mali_bool init_mali_clock(void)
322 {
323         mali_bool ret = MALI_TRUE;
324         int i;
325
326         if (mali_clock != 0 || mali_clock_pd != 0)
327                 return ret; 
328 #if 1
329         mali_clock_pd = clk_get(NULL,GPUCLK_PD_NAME);
330         if (IS_ERR(mali_clock_pd)) {
331                 MALI_PRINT( ("MALI Error : failed to get source mali pd\n"));
332                 ret = MALI_FALSE;
333                 goto err_gpu_clk;
334         }
335         clk_prepare_enable(mali_clock_pd);
336 #endif
337         mali_clock = clk_get_dvfs_node(GPUCLK_NAME);
338         if (IS_ERR(mali_clock)) {
339                 MALI_PRINT( ("MALI Error : failed to get source mali clock\n"));
340                 ret = MALI_FALSE;
341                 goto err_gpu_clk;
342         }
343         dvfs_clk_prepare_enable(mali_clock);
344         freq_table = dvfs_get_freq_volt_table(mali_clock);
345         if (!freq_table) {
346                 MALI_PRINT(("Stop,dvfs table should be set in dts\n"));
347                 return MALI_FALSE;
348         }
349         for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
350                 mali_dvfs[i] = freq_table[i].frequency/1000;
351         }
352         mali_init_clock = mali_dvfs[0];
353         num_clock = i;
354         minuend = 2;
355         MALI_PRINT(("Mali400 inside of rk3126\r\n"));
356
357         mali_clk_set_rate(mali_clock, mali_init_clock);
358         gpu_power_state = 1;
359
360         return MALI_TRUE;
361
362 err_gpu_clk:
363         MALI_PRINT(("::clk_put:: %s mali_clock\n", __FUNCTION__));
364         gpu_power_state = 0;
365 #if 1
366         clk_disable_unprepare(mali_clock_pd);
367 #endif
368         dvfs_clk_disable_unprepare(mali_clock);
369         mali_clock = 0;
370         mali_clock_pd = 0;
371
372         return ret;
373 }
374
375 static mali_bool deinit_mali_clock(void)
376 {
377         if (mali_clock == 0 && mali_clock_pd == 0)
378                 return MALI_TRUE;
379         dvfs_clk_disable_unprepare(mali_clock);
380 #if 1
381         clk_disable_unprepare(mali_clock_pd);
382 #endif
383         mali_clock = 0;
384         mali_clock_pd = 0;
385         if(gpu_power_state)
386                 gpu_power_state = 0;
387         return MALI_TRUE;
388 }
389
390 mali_bool init_mali_dvfs_status(int step)
391 {
392         set_mali_dvfs_step(step);
393     return MALI_TRUE;
394 }
395
396 #ifdef CONFIG_HAS_EARLYSUSPEND
397 static void mali_pm_early_suspend(struct early_suspend *mali_dev)
398 {
399         /*do nothing*/
400 }
401 static void mali_pm_late_resume(struct early_suspend *mali_dev)
402 {
403         /*do nothing*/
404 }
405 static struct early_suspend mali_dev_early_suspend = {
406         .suspend = mali_pm_early_suspend,
407         .resume = mali_pm_late_resume,
408         .level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
409 };
410 #endif /* CONFIG_HAS_EARLYSUSPEND */
411
412 _mali_osk_errcode_t mali_platform_init(void)
413 {
414         if (cpu_is_rk3036()) {
415                 audis_gpu_clk = clk_get(NULL,"clk_gpu");        
416
417                 if (IS_ERR(audis_gpu_clk)) {
418                          MALI_PRINT( ("MALI Error : failed to get audis mali clk\n"));
419                          return MALI_FALSE;
420                          
421                 }
422
423                 clk_prepare_enable(audis_gpu_clk);
424
425                 MALI_SUCCESS;
426         }
427         MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
428         
429         clockSetlock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,_MALI_OSK_LOCK_ORDER_UTILIZATION);
430         if(!init_mali_dvfs_status(MALI_DVFS_DEFAULT_STEP))
431                 MALI_DEBUG_PRINT(1, ("init_mali_dvfs_status failed\n"));
432         
433         if(mali400_utility_sysfs_init())
434                 MALI_PRINT(("mali400_utility_sysfs_init error\r\n"));
435         
436         mali_freq_data = kmalloc(sizeof(struct mali_freq_data), GFP_KERNEL);
437         if(!mali_freq_data) {
438                 MALI_PRINT(("kmalloc error\r\n"));
439                 MALI_ERROR(-1);
440         }
441         mali_freq_data->wq = create_workqueue(mali_freq_workqueue_name);
442         if(!mali_freq_data->wq)
443                 MALI_ERROR(-1);
444         INIT_WORK(&mali_freq_data->work,mali_freq_scale_work);
445         
446 #ifdef CONFIG_HAS_EARLYSUSPEND
447         register_early_suspend(&mali_dev_early_suspend);
448 #endif
449
450     MALI_SUCCESS;
451 }
452
453 _mali_osk_errcode_t mali_platform_deinit(void)
454 {
455         if (cpu_is_rk3036()) {
456                 clk_disable_unprepare(audis_gpu_clk);
457                 MALI_SUCCESS;
458         }
459
460         deinit_mali_clock();
461         _mali_osk_mutex_term(clockSetlock);
462
463     MALI_SUCCESS;
464 }
465 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
466 {
467         if (!bpower_off) {
468                 if (!gpu_power_state) {
469                         if (cpu_is_rk3036()) {
470                                 clk_prepare_enable(audis_gpu_clk);
471                         } else {
472                 #if 1
473                                 clk_prepare_enable(mali_clock_pd);
474                 #endif
475                                 dvfs_clk_prepare_enable(mali_clock);
476                         }
477                         gpu_power_state = 1 ;
478                 }               
479         } else if (bpower_off == 2) {
480                 ;
481         } else if (bpower_off == 1) {
482                 if(gpu_power_state) {
483                         if (cpu_is_rk3036()) {
484                                 clk_disable_unprepare(audis_gpu_clk);
485                         } else {
486                                 dvfs_clk_disable_unprepare(mali_clock);
487                 #if 1
488                                 clk_disable_unprepare(mali_clock_pd);   
489                 #endif
490                         }
491                         gpu_power_state = 0;
492                 }
493         }
494     MALI_SUCCESS;
495 }
496
497 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
498 {
499 #if 1
500         switch(power_mode) {
501                 case MALI_POWER_MODE_ON:
502                         MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_ON\r\n"));
503                         mali_power_domain_control(MALI_POWER_MODE_ON);
504                         break;
505                 case MALI_POWER_MODE_LIGHT_SLEEP:
506                         MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
507                         mali_power_domain_control(MALI_POWER_MODE_LIGHT_SLEEP);
508                         break;
509                 case MALI_POWER_MODE_DEEP_SLEEP:
510                         MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
511                         mali_power_domain_control(MALI_POWER_MODE_DEEP_SLEEP);
512                         break;
513                 default:
514                         MALI_DEBUG_PRINT(2,("mali_platform_power_mode_change:power_mode(%d) not support \r\n",power_mode));
515         }
516 #endif
517     MALI_SUCCESS;
518 }
519 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
520 {
521         if (cpu_is_rk3036())
522                 return;
523
524         if(data->utilization_pp > 256)
525                 return;
526         utilization_global = data->utilization_pp;
527         
528         //MALI_PRINT(("utilization_global = %d\r\n",utilization_global));
529
530         if(scale_enable && sampling_enable)
531                 queue_work(mali_freq_data->wq,&mali_freq_data->work);
532         
533         return ;
534 }