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