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
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.
12 * @file mali_platform.c
13 * Platform specific Mali driver functions for a default platform
15 #include "mali_kernel_common.h"
17 #include "mali_platform.h"
19 #include <linux/workqueue.h>
20 #include <linux/kernel.h>
21 #include <linux/slab.h>
22 #include <linux/gfp.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>
34 #include <linux/rockchip/cpu.h>
35 #include <linux/rockchip/dvfs.h>
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;
45 #define MALI_DVFS_DEFAULT_STEP 0 // 50Mhz default
47 u32 mali_dvfs[] = {50,100,133,160,200,266,400};
50 u32 mali_init_clock = 50;
51 static int minuend = 0;
53 static struct cpufreq_frequency_table *freq_table = NULL;
55 module_param_array(mali_dvfs, int, &num_clock,S_IRUGO | S_IWUSR);
56 MODULE_PARM_DESC(mali_dvfs,"mali clock table");
58 module_param(mali_init_clock, int,S_IRUGO | S_IWUSR);
59 MODULE_PARM_DESC(mali_init_clock,"mali init clock value");
61 u32 mali_group_error = 0;
63 u32 gpu_power_state = 0;
64 static u32 utilization_global = 0;
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;
76 typedef struct mali_dvfs_tableTag{
81 typedef struct mali_dvfs_statusTag{
83 mali_dvfs_table * pCurrentDvfs;
87 mali_dvfs_status maliDvfsStatus;
89 #define GPU_DVFS_UP_THRESHOLD ((int)((255*50)/100))
90 #define GPU_DVFS_DOWN_THRESHOLD ((int)((255*35)/100))
92 _mali_osk_mutex_t *clockSetlock;
94 struct clk* mali_clk_get(unsigned char *name)
97 clk = clk_get(NULL,name);
100 unsigned long mali_clk_get_rate(struct dvfs_node *clk)
102 return dvfs_clk_get_rate(clk);
105 void mali_clk_set_rate(struct dvfs_node *clk,u32 value)
107 unsigned long rate = (unsigned long)value * GPU_MHZ;
108 dvfs_clk_set_rate(clk, rate);
109 rate = mali_clk_get_rate(clk);
112 static struct kobject *mali400_utility_object;
114 static u32 get_mali_dvfs_status(void)
116 return maliDvfsStatus.currentStep;
118 static void set_mali_dvfs_step(u32 value)
120 maliDvfsStatus.currentStep = value;
123 static void scale_enable_set(u32 value)
125 scale_enable = value;
127 static u32 mali_dvfs_search(u32 value)
131 for(i=0;i<num_clock;i++)
133 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);
143 MALI_DEBUG_PRINT(2,("USER set clock not in the mali_dvfs table\r\n"));
148 static int mali400_utility_show(struct device *dev,struct device_attribute *attr, char *buf)
150 return sprintf(buf, "%d\n", utilization_global);
152 static int mali400_clock_set(struct device *dev,struct device_attribute *attr, const char *buf,u32 count)
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));*/
167 mali_dvfs_search(clock);
171 static int clock_show(struct device *dev,struct device_attribute *attr, char *buf)
175 pos += snprintf(pos,PAGE_SIZE,"%d,",num_clock);
176 for(i=0;i<(num_clock-1);i++)
178 pos += snprintf(pos,PAGE_SIZE,"%d,",mali_dvfs[i]);
180 pos +=snprintf(pos,PAGE_SIZE,"%d\n",mali_dvfs[i]);
183 static int sampling_timeout_show(struct device *dev,struct device_attribute *attr, char *buf)
185 return sprintf(buf, "mali_utilization_timeout = %d\n", mali_utilization_timeout);
187 static int sampling_timeout_set(struct device *dev,struct device_attribute *attr, const char *buf,u32 count)
190 sampling = simple_strtoul(buf, NULL, 10);
195 MALI_PRINT(("disable mali clock frequency scalling\r\n"));
199 mali_utilization_timeout = sampling;
201 MALI_PRINT(("enable mali clock frequency scalling ,mali_utilization_timeout : %dms\r\n",mali_utilization_timeout));
205 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
207 return sprintf(buf, "%d\n", mali_group_error);
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);
216 static mali_bool mali400_utility_sysfs_init(void)
220 mali400_utility_object = kobject_create_and_add("mali400_utility", NULL);
221 if (mali400_utility_object == NULL) {
224 ret = sysfs_create_file(mali400_utility_object, &dev_attr_utility.attr);
228 ret = sysfs_create_file(mali400_utility_object, &dev_attr_param.attr);
232 ret = sysfs_create_file(mali400_utility_object, &dev_attr_sampling_timeout.attr);
236 ret = sysfs_create_file(mali400_utility_object, &dev_attr_error_count.attr);
242 static unsigned int decideNextStatus(unsigned int utilization)
247 if(utilization>GPU_DVFS_UP_THRESHOLD && maliDvfsStatus.currentStep==0 && maliDvfsStatus.currentStep<(num_clock-minuend))
249 else if(utilization>GPU_DVFS_UP_THRESHOLD && maliDvfsStatus.currentStep==1 && maliDvfsStatus.currentStep<(num_clock-minuend))
251 else if(utilization>GPU_DVFS_UP_THRESHOLD && maliDvfsStatus.currentStep==2 && maliDvfsStatus.currentStep<(num_clock-minuend))
253 else if(utilization>GPU_DVFS_UP_THRESHOLD && maliDvfsStatus.currentStep==3 && maliDvfsStatus.currentStep<(num_clock-minuend))
255 else if(utilization>GPU_DVFS_UP_THRESHOLD && maliDvfsStatus.currentStep==4 && maliDvfsStatus.currentStep<(num_clock-minuend))
257 else if(utilization>GPU_DVFS_UP_THRESHOLD && maliDvfsStatus.currentStep==5 && maliDvfsStatus.currentStep<(num_clock-minuend))
260 determined by minuend to up to level 6
262 else if(utilization<GPU_DVFS_DOWN_THRESHOLD && maliDvfsStatus.currentStep==6 /*&& maliDvfsStatus.currentStep<num_clock*/)
264 else if(utilization<GPU_DVFS_DOWN_THRESHOLD && maliDvfsStatus.currentStep==5 /*&& maliDvfsStatus.currentStep<num_clock*/)
266 else if(utilization<GPU_DVFS_DOWN_THRESHOLD && maliDvfsStatus.currentStep==4 /*&& maliDvfsStatus.currentStep<num_clock*/)
268 else if(utilization<GPU_DVFS_DOWN_THRESHOLD && maliDvfsStatus.currentStep==3 /*&& maliDvfsStatus.currentStep<num_clock*/)
270 else if(utilization<GPU_DVFS_DOWN_THRESHOLD && maliDvfsStatus.currentStep==2 /*&& maliDvfsStatus.currentStep<num_clock*/)
272 else if(utilization<GPU_DVFS_DOWN_THRESHOLD && maliDvfsStatus.currentStep==1 /*&& maliDvfsStatus.currentStep<num_clock*/)
275 level = maliDvfsStatus.currentStep;
281 static mali_bool set_mali_dvfs_status(u32 step)
283 u32 validatedStep=step;
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);
294 static mali_bool change_mali_dvfs_status(u32 step)
296 if(!set_mali_dvfs_status(step))
298 MALI_DEBUG_PRINT(2,("error on set_mali_dvfs_status: %d\n",step));
304 static void mali_freq_scale_work(struct work_struct *work)
310 curStatus = get_mali_dvfs_status();
311 nextStatus = decideNextStatus(utilization_global);
313 if(curStatus!=nextStatus)
315 if(!change_mali_dvfs_status(nextStatus))
317 MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
321 static mali_bool init_mali_clock(void)
323 mali_bool ret = MALI_TRUE;
325 if (mali_clock != 0 || mali_clock_pd != 0)
328 mali_clock_pd = clk_get(NULL,GPUCLK_PD_NAME);
329 if (IS_ERR(mali_clock_pd))
331 MALI_PRINT( ("MALI Error : failed to get source mali pd\n"));
335 clk_prepare_enable(mali_clock_pd);
337 mali_clock = clk_get_dvfs_node(GPUCLK_NAME);
338 if (IS_ERR(mali_clock))
340 MALI_PRINT( ("MALI Error : failed to get source mali clock\n"));
344 dvfs_clk_prepare_enable(mali_clock);
345 freq_table = dvfs_get_freq_volt_table(mali_clock);
348 MALI_PRINT(("Stop,dvfs table should be set in dts\n"));
351 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
353 mali_dvfs[i] = freq_table[i].frequency/1000;
355 mali_init_clock = mali_dvfs[0];
358 MALI_PRINT(("Mali400 inside of rk3036\r\n"));
360 mali_clk_set_rate(mali_clock, mali_init_clock);
366 MALI_PRINT(("::clk_put:: %s mali_clock\n", __FUNCTION__));
368 clk_disable_unprepare(mali_clock_pd);
369 dvfs_clk_disable_unprepare(mali_clock);
376 static mali_bool deinit_mali_clock(void)
378 if (mali_clock == 0 && mali_clock_pd == 0)
380 dvfs_clk_disable_unprepare(mali_clock);
381 clk_disable_unprepare(mali_clock_pd);
389 mali_bool init_mali_dvfs_status(int step)
391 set_mali_dvfs_step(step);
395 #ifdef CONFIG_HAS_EARLYSUSPEND
396 static void mali_pm_early_suspend(struct early_suspend *mali_dev)
400 static void mali_pm_late_resume(struct early_suspend *mali_dev)
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,
409 #endif /* CONFIG_HAS_EARLYSUSPEND */
411 _mali_osk_errcode_t mali_platform_init(void)
416 MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
418 clockSetlock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,_MALI_OSK_LOCK_ORDER_UTILIZATION);
420 if(!init_mali_dvfs_status(MALI_DVFS_DEFAULT_STEP))
421 MALI_DEBUG_PRINT(1, ("init_mali_dvfs_status failed\n"));
423 if(mali400_utility_sysfs_init())
424 MALI_PRINT(("mali400_utility_sysfs_init error\r\n"));
426 mali_freq_data = kmalloc(sizeof(struct mali_freq_data), GFP_KERNEL);
429 MALI_PRINT(("kmalloc error\r\n"));
432 mali_freq_data->wq = create_workqueue(mali_freq_workqueue_name);
433 if(!mali_freq_data->wq)
435 INIT_WORK(&mali_freq_data->work,mali_freq_scale_work);
437 #ifdef CONFIG_HAS_EARLYSUSPEND
438 register_early_suspend(&mali_dev_early_suspend);
444 _mali_osk_errcode_t mali_platform_deinit(void)
450 _mali_osk_mutex_term(clockSetlock);
454 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
463 clk_prepare_enable(mali_clock_pd);
464 dvfs_clk_prepare_enable(mali_clock);
465 gpu_power_state = 1 ;
468 else if (bpower_off == 2)
472 else if (bpower_off == 1)
476 dvfs_clk_disable_unprepare(mali_clock);
477 clk_disable_unprepare(mali_clock_pd);
484 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
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);
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);
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);
502 MALI_DEBUG_PRINT(2,("mali_platform_power_mode_change:power_mode(%d) not support \r\n",power_mode));
508 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
513 if(data->utilization_pp > 256)
515 utilization_global = data->utilization_pp;
517 MALI_PRINT(("utilization_global = %d\r\n",utilization_global));
519 if(scale_enable && sampling_enable)
520 queue_work(mali_freq_data->wq,&mali_freq_data->work);
525 void set_mali_parent_power_domain(void* dev)