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