Merge tag 'lsk-v3.10-android-14.11'
[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 struct kobject *rk_gpu;
110
111 static u32 get_mali_dvfs_status(void)
112 {
113         return maliDvfsStatus.currentStep;
114 }
115 static void set_mali_dvfs_step(u32 value)
116 {
117         maliDvfsStatus.currentStep = value;
118 }
119
120 static void scale_enable_set(u32 value)
121 {
122         scale_enable = value;
123 }
124 static u32 mali_dvfs_search(u32 value)
125 {
126         u32 i;  
127         u32 clock = value;
128         for (i=0;i<num_clock;i++) {
129                 if (clock == mali_dvfs[i]) {
130                         _mali_osk_mutex_wait(clockSetlock);
131                         mali_clk_set_rate(mali_clock,clock);
132                         _mali_osk_mutex_signal(clockSetlock);
133                         set_mali_dvfs_step(i);
134                         scale_enable_set(0);
135                         return 0;
136                 }
137                 if(i>=7)
138                 MALI_DEBUG_PRINT(2,("USER set clock not in the mali_dvfs table\r\n"));
139         }
140         return 1;
141 }
142
143 static int mali400_utility_show(struct device *dev,struct device_attribute *attr, char *buf)
144 {
145         return sprintf(buf, "%d\n", utilization_global);
146 }
147 static int mali400_clock_set(struct device *dev,struct device_attribute *attr, const char *buf,u32 count)
148 {
149         u32 clock;
150         u32 currentStep;
151         u64 timeValue;
152         clock = simple_strtoul(buf, NULL, 10);
153         currentStep = get_mali_dvfs_status();
154         timeValue = _mali_osk_time_get_ns();
155         /*MALI_PRINT(("USER SET CLOCK,%d\r\n",clock));*/
156         if(!clock) {
157                 scale_enable_set(1);
158         } else {
159                 mali_dvfs_search(clock);
160         }
161         return count;
162 }
163 static int clock_show(struct device *dev,struct device_attribute *attr, char *buf)
164 {
165         u32 i;
166         char *pos = buf;
167         pos += snprintf(pos,PAGE_SIZE,"%d,",num_clock);
168         for(i=0;i<(num_clock-1);i++) {
169                 pos += snprintf(pos,PAGE_SIZE,"%d,",mali_dvfs[i]);
170         }
171         pos +=snprintf(pos,PAGE_SIZE,"%d\n",mali_dvfs[i]); 
172         return pos - buf;
173 }
174 static int sampling_timeout_show(struct device *dev,struct device_attribute *attr, char *buf)
175 {
176         return sprintf(buf, "mali_utilization_timeout = %d\n", mali_utilization_timeout);
177 }
178 static int sampling_timeout_set(struct device *dev,struct device_attribute *attr,
179                                 const char *buf,u32 count)
180 {
181         u32 sampling;
182         sampling = simple_strtoul(buf, NULL, 10);
183         
184         if (sampling == 0 ) {
185                 sampling_enable = 0;
186                 MALI_PRINT(("disable mali clock frequency scalling\r\n"));
187         } else {
188                 mali_utilization_timeout = sampling;
189                 sampling_enable = 1;
190                 MALI_PRINT(("enable mali clock frequency scalling ,mali_utilization_timeout : %dms\r\n",
191                             mali_utilization_timeout));
192         }
193         return count;
194 }
195 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
196 {
197         return sprintf(buf, "%d\n", mali_group_error);
198 }
199
200 static DEVICE_ATTR(utility, 0644, mali400_utility_show, mali400_clock_set);
201 static DEVICE_ATTR(param, 0644, clock_show, NULL);
202 static DEVICE_ATTR(sampling_timeout, 0644, sampling_timeout_show,sampling_timeout_set);
203 static DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
204
205
206 static mali_bool mali400_utility_sysfs_init(void)
207 {
208         u32 ret ;
209
210         mali400_utility_object = kobject_create_and_add("mali400_utility", NULL);
211         if (mali400_utility_object == NULL) {
212                 return -1;
213         }
214         rk_gpu = kobject_create_and_add("rk_gpu", NULL);
215         if (!rk_gpu)
216                 return -1;
217         ret = sysfs_create_file(mali400_utility_object, &dev_attr_utility.attr);
218         if (ret) {
219                 return -1;
220         }
221         ret = sysfs_create_file(mali400_utility_object, &dev_attr_param.attr);
222         if (ret) {
223                 return -1;
224         }
225         ret = sysfs_create_file(mali400_utility_object, &dev_attr_sampling_timeout.attr);
226         if(ret){
227                 return -1;
228         }
229         ret = sysfs_create_file(rk_gpu, &dev_attr_error_count.attr);
230         if(ret){
231                 return -1;
232         }
233         return 0 ;
234 }       
235 static unsigned int decideNextStatus(unsigned int utilization)
236 {
237     u32 level=0;
238
239     if(utilization > GPU_DVFS_UP_THRESHOLD &&
240              maliDvfsStatus.currentStep == 0 &&
241              maliDvfsStatus.currentStep < (num_clock-minuend))
242             level = 1;
243     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
244              maliDvfsStatus.currentStep == 1 &&
245              maliDvfsStatus.currentStep < (num_clock-minuend))
246             level = 2;
247     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
248              maliDvfsStatus.currentStep == 2 &&
249              maliDvfsStatus.currentStep < (num_clock-minuend))
250             level = 3;
251     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
252              maliDvfsStatus.currentStep == 3 &&
253              maliDvfsStatus.currentStep < (num_clock-minuend))
254             level = 4;
255     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
256              maliDvfsStatus.currentStep == 4 &&
257              maliDvfsStatus.currentStep < (num_clock-minuend))
258             level = 5;
259     else if (utilization > GPU_DVFS_UP_THRESHOLD &&
260              maliDvfsStatus.currentStep == 5 &&
261              maliDvfsStatus.currentStep < (num_clock-minuend))
262             level = 6;
263         /*
264         determined by minuend to up to level 6
265         */
266     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
267             maliDvfsStatus.currentStep == 6)
268             level = 5;
269     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
270             maliDvfsStatus.currentStep == 5)
271             level = 4;
272     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
273             maliDvfsStatus.currentStep == 4)
274             level = 3;
275     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
276             maliDvfsStatus.currentStep == 3)
277             level = 2;
278     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
279             maliDvfsStatus.currentStep == 2)
280             level = 1;
281     else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
282             maliDvfsStatus.currentStep == 1)
283             level = 0;
284     else
285             level = maliDvfsStatus.currentStep;
286     return level;
287 }
288
289 static mali_bool set_mali_dvfs_status(u32 step)
290 {
291         u32 validatedStep=step; 
292
293         _mali_osk_mutex_wait(clockSetlock);
294         mali_clk_set_rate(mali_clock, mali_dvfs[validatedStep]);
295         _mali_osk_mutex_signal(clockSetlock);
296         set_mali_dvfs_step(validatedStep);
297         
298         return MALI_TRUE;
299 }
300
301 static mali_bool change_mali_dvfs_status(u32 step)
302 {
303         if(!set_mali_dvfs_status(step)) {
304                 MALI_DEBUG_PRINT(2,("error on set_mali_dvfs_status: %d\n",step));
305                 return MALI_FALSE;
306         }
307
308         return MALI_TRUE;
309 }
310
311 static void  mali_freq_scale_work(struct work_struct *work)
312 {       
313
314         u32 nextStatus = 0;
315         u32 curStatus = 0;
316
317         curStatus = get_mali_dvfs_status();
318         nextStatus = decideNextStatus(utilization_global);
319         
320         if (curStatus!=nextStatus) {
321                 if (!change_mali_dvfs_status(nextStatus)) {
322                         MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
323                 }
324         }               
325 }
326 static mali_bool init_mali_clock(void)
327 {
328         mali_bool ret = MALI_TRUE;
329         int i;
330
331         if (mali_clock != 0 || mali_clock_pd != 0)
332                 return ret; 
333 #if 1
334         mali_clock_pd = clk_get(NULL,GPUCLK_PD_NAME);
335         if (IS_ERR(mali_clock_pd)) {
336                 MALI_PRINT( ("MALI Error : failed to get source mali pd\n"));
337                 ret = MALI_FALSE;
338                 goto err_gpu_clk;
339         }
340         clk_prepare_enable(mali_clock_pd);
341 #endif
342         mali_clock = clk_get_dvfs_node(GPUCLK_NAME);
343         if (IS_ERR(mali_clock)) {
344                 MALI_PRINT( ("MALI Error : failed to get source mali clock\n"));
345                 ret = MALI_FALSE;
346                 goto err_gpu_clk;
347         }
348         dvfs_clk_prepare_enable(mali_clock);
349         freq_table = dvfs_get_freq_volt_table(mali_clock);
350         if (!freq_table) {
351                 MALI_PRINT(("Stop,dvfs table should be set in dts\n"));
352                 return MALI_FALSE;
353         }
354         for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
355                 mali_dvfs[i] = freq_table[i].frequency/1000;
356         }
357         mali_init_clock = mali_dvfs[0];
358         num_clock = i;
359         minuend = 2;
360         MALI_PRINT(("Mali400 inside of rk3126\r\n"));
361
362         mali_clk_set_rate(mali_clock, mali_init_clock);
363         gpu_power_state = 1;
364
365         return MALI_TRUE;
366
367 err_gpu_clk:
368         MALI_PRINT(("::clk_put:: %s mali_clock\n", __FUNCTION__));
369         gpu_power_state = 0;
370 #if 1
371         clk_disable_unprepare(mali_clock_pd);
372 #endif
373         dvfs_clk_disable_unprepare(mali_clock);
374         mali_clock = 0;
375         mali_clock_pd = 0;
376
377         return ret;
378 }
379
380 static mali_bool deinit_mali_clock(void)
381 {
382         if (mali_clock == 0 && mali_clock_pd == 0)
383                 return MALI_TRUE;
384         dvfs_clk_disable_unprepare(mali_clock);
385 #if 1
386         clk_disable_unprepare(mali_clock_pd);
387 #endif
388         mali_clock = 0;
389         mali_clock_pd = 0;
390         if(gpu_power_state)
391                 gpu_power_state = 0;
392         return MALI_TRUE;
393 }
394
395 mali_bool init_mali_dvfs_status(int step)
396 {
397         set_mali_dvfs_step(step);
398     return MALI_TRUE;
399 }
400
401 #ifdef CONFIG_HAS_EARLYSUSPEND
402 static void mali_pm_early_suspend(struct early_suspend *mali_dev)
403 {
404         /*do nothing*/
405 }
406 static void mali_pm_late_resume(struct early_suspend *mali_dev)
407 {
408         /*do nothing*/
409 }
410 static struct early_suspend mali_dev_early_suspend = {
411         .suspend = mali_pm_early_suspend,
412         .resume = mali_pm_late_resume,
413         .level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
414 };
415 #endif /* CONFIG_HAS_EARLYSUSPEND */
416
417 _mali_osk_errcode_t mali_platform_init(void)
418 {
419         if (cpu_is_rk3036()) {
420                 audis_gpu_clk = clk_get(NULL,"clk_gpu");        
421
422                 if (IS_ERR(audis_gpu_clk)) {
423                          MALI_PRINT( ("MALI Error : failed to get audis mali clk\n"));
424                          return MALI_FALSE;
425                          
426                 }
427
428                 clk_prepare_enable(audis_gpu_clk);
429
430                 MALI_SUCCESS;
431         }
432         MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
433         
434         clockSetlock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,_MALI_OSK_LOCK_ORDER_UTILIZATION);
435         if(!init_mali_dvfs_status(MALI_DVFS_DEFAULT_STEP))
436                 MALI_DEBUG_PRINT(1, ("init_mali_dvfs_status failed\n"));
437         
438         if(mali400_utility_sysfs_init())
439                 MALI_PRINT(("mali400_utility_sysfs_init error\r\n"));
440         
441         mali_freq_data = kmalloc(sizeof(struct mali_freq_data), GFP_KERNEL);
442         if(!mali_freq_data) {
443                 MALI_PRINT(("kmalloc error\r\n"));
444                 MALI_ERROR(-1);
445         }
446         mali_freq_data->wq = create_workqueue(mali_freq_workqueue_name);
447         if(!mali_freq_data->wq)
448                 MALI_ERROR(-1);
449         INIT_WORK(&mali_freq_data->work,mali_freq_scale_work);
450         
451 #ifdef CONFIG_HAS_EARLYSUSPEND
452         register_early_suspend(&mali_dev_early_suspend);
453 #endif
454
455     MALI_SUCCESS;
456 }
457
458 _mali_osk_errcode_t mali_platform_deinit(void)
459 {
460         if (cpu_is_rk3036()) {
461                 clk_disable_unprepare(audis_gpu_clk);
462                 MALI_SUCCESS;
463         }
464
465         deinit_mali_clock();
466         _mali_osk_mutex_term(clockSetlock);
467
468     MALI_SUCCESS;
469 }
470 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
471 {
472         if (!bpower_off) {
473                 if (!gpu_power_state) {
474                         if (cpu_is_rk3036()) {
475                                 clk_prepare_enable(audis_gpu_clk);
476                         } else {
477                 #if 1
478                                 clk_prepare_enable(mali_clock_pd);
479                 #endif
480                                 dvfs_clk_prepare_enable(mali_clock);
481                         }
482                         gpu_power_state = 1 ;
483                 }               
484         } else if (bpower_off == 2) {
485                 ;
486         } else if (bpower_off == 1) {
487                 if(gpu_power_state) {
488                         if (cpu_is_rk3036()) {
489                                 clk_disable_unprepare(audis_gpu_clk);
490                         } else {
491                                 dvfs_clk_disable_unprepare(mali_clock);
492                 #if 1
493                                 clk_disable_unprepare(mali_clock_pd);   
494                 #endif
495                         }
496                         gpu_power_state = 0;
497                 }
498         }
499     MALI_SUCCESS;
500 }
501
502 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
503 {
504 #if 1
505         switch(power_mode) {
506                 case MALI_POWER_MODE_ON:
507                         MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_ON\r\n"));
508                         mali_power_domain_control(MALI_POWER_MODE_ON);
509                         break;
510                 case MALI_POWER_MODE_LIGHT_SLEEP:
511                         MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
512                         mali_power_domain_control(MALI_POWER_MODE_LIGHT_SLEEP);
513                         break;
514                 case MALI_POWER_MODE_DEEP_SLEEP:
515                         MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
516                         mali_power_domain_control(MALI_POWER_MODE_DEEP_SLEEP);
517                         break;
518                 default:
519                         MALI_DEBUG_PRINT(2,("mali_platform_power_mode_change:power_mode(%d) not support \r\n",power_mode));
520         }
521 #endif
522     MALI_SUCCESS;
523 }
524 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
525 {
526         if (cpu_is_rk3036())
527                 return;
528
529         if(data->utilization_pp > 256)
530                 return;
531         utilization_global = data->utilization_pp;
532         
533         //MALI_PRINT(("utilization_global = %d\r\n",utilization_global));
534
535         if(scale_enable && sampling_enable)
536                 queue_work(mali_freq_data->wq,&mali_freq_data->work);
537         
538         return ;
539 }