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"
18 #include <linux/workqueue.h>
19 #include <linux/kernel.h>
20 #include <linux/slab.h>
21 #include <linux/gfp.h>
23 #include <linux/clk.h>
24 #include <linux/device.h>
25 #ifdef CONFIG_HAS_EARLYSUSPEND
26 #include <linux/earlysuspend.h>
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>
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;
43 #define MALI_DVFS_DEFAULT_STEP 0 // 50Mhz default
45 u32 mali_dvfs[] = {50, 100, 133, 160, 200, 266, 400};
47 u32 mali_init_clock = 50;
48 static int minuend = 0;
50 static struct cpufreq_frequency_table *freq_table = NULL;
52 module_param_array(mali_dvfs, int, &num_clock,S_IRUGO | S_IWUSR);
53 MODULE_PARM_DESC(mali_dvfs,"mali clock table");
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;
59 u32 gpu_power_state = 0;
60 static u32 utilization_global = 0;
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;
72 typedef struct mali_dvfs_tableTag{
77 typedef struct mali_dvfs_statusTag{
79 mali_dvfs_table * pCurrentDvfs;
83 mali_dvfs_status maliDvfsStatus;
85 #define GPU_DVFS_UP_THRESHOLD ((int)((255*50)/100))
86 #define GPU_DVFS_DOWN_THRESHOLD ((int)((255*35)/100))
88 _mali_osk_mutex_t *clockSetlock;
90 struct clk* mali_clk_get(unsigned char *name)
93 clk = clk_get(NULL,name);
96 unsigned long mali_clk_get_rate(struct dvfs_node *clk)
98 return dvfs_clk_get_rate(clk);
101 void mali_clk_set_rate(struct dvfs_node *clk, u32 value)
103 unsigned long rate = (unsigned long)value * GPU_MHZ;
104 dvfs_clk_set_rate(clk, rate);
105 rate = mali_clk_get_rate(clk);
108 static struct kobject *mali400_utility_object;
109 static struct kobject *rk_gpu;
111 static u32 get_mali_dvfs_status(void)
113 return maliDvfsStatus.currentStep;
115 static void set_mali_dvfs_step(u32 value)
117 maliDvfsStatus.currentStep = value;
120 static void scale_enable_set(u32 value)
122 scale_enable = value;
124 static u32 mali_dvfs_search(u32 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);
138 MALI_DEBUG_PRINT(2,("USER set clock not in the mali_dvfs table\r\n"));
143 static int mali400_utility_show(struct device *dev,struct device_attribute *attr, char *buf)
145 return sprintf(buf, "%d\n", utilization_global);
147 static int mali400_clock_set(struct device *dev,struct device_attribute *attr, const char *buf,u32 count)
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));*/
159 mali_dvfs_search(clock);
163 static int clock_show(struct device *dev,struct device_attribute *attr, char *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]);
171 pos +=snprintf(pos,PAGE_SIZE,"%d\n",mali_dvfs[i]);
174 static int sampling_timeout_show(struct device *dev,struct device_attribute *attr, char *buf)
176 return sprintf(buf, "mali_utilization_timeout = %d\n", mali_utilization_timeout);
178 static int sampling_timeout_set(struct device *dev,struct device_attribute *attr,
179 const char *buf,u32 count)
182 sampling = simple_strtoul(buf, NULL, 10);
184 if (sampling == 0 ) {
186 MALI_PRINT(("disable mali clock frequency scalling\r\n"));
188 mali_utilization_timeout = sampling;
190 MALI_PRINT(("enable mali clock frequency scalling ,mali_utilization_timeout : %dms\r\n",
191 mali_utilization_timeout));
195 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
197 return sprintf(buf, "%d\n", mali_group_error);
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);
206 static mali_bool mali400_utility_sysfs_init(void)
210 mali400_utility_object = kobject_create_and_add("mali400_utility", NULL);
211 if (mali400_utility_object == NULL) {
214 rk_gpu = kobject_create_and_add("rk_gpu", NULL);
217 ret = sysfs_create_file(mali400_utility_object, &dev_attr_utility.attr);
221 ret = sysfs_create_file(mali400_utility_object, &dev_attr_param.attr);
225 ret = sysfs_create_file(mali400_utility_object, &dev_attr_sampling_timeout.attr);
229 ret = sysfs_create_file(rk_gpu, &dev_attr_error_count.attr);
235 static unsigned int decideNextStatus(unsigned int utilization)
239 if(utilization > GPU_DVFS_UP_THRESHOLD &&
240 maliDvfsStatus.currentStep == 0 &&
241 maliDvfsStatus.currentStep < (num_clock-minuend))
243 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
244 maliDvfsStatus.currentStep == 1 &&
245 maliDvfsStatus.currentStep < (num_clock-minuend))
247 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
248 maliDvfsStatus.currentStep == 2 &&
249 maliDvfsStatus.currentStep < (num_clock-minuend))
251 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
252 maliDvfsStatus.currentStep == 3 &&
253 maliDvfsStatus.currentStep < (num_clock-minuend))
255 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
256 maliDvfsStatus.currentStep == 4 &&
257 maliDvfsStatus.currentStep < (num_clock-minuend))
259 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
260 maliDvfsStatus.currentStep == 5 &&
261 maliDvfsStatus.currentStep < (num_clock-minuend))
264 determined by minuend to up to level 6
266 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
267 maliDvfsStatus.currentStep == 6)
269 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
270 maliDvfsStatus.currentStep == 5)
272 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
273 maliDvfsStatus.currentStep == 4)
275 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
276 maliDvfsStatus.currentStep == 3)
278 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
279 maliDvfsStatus.currentStep == 2)
281 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
282 maliDvfsStatus.currentStep == 1)
285 level = maliDvfsStatus.currentStep;
289 static mali_bool set_mali_dvfs_status(u32 step)
291 u32 validatedStep=step;
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);
301 static mali_bool change_mali_dvfs_status(u32 step)
303 if(!set_mali_dvfs_status(step)) {
304 MALI_DEBUG_PRINT(2,("error on set_mali_dvfs_status: %d\n",step));
311 static void mali_freq_scale_work(struct work_struct *work)
317 curStatus = get_mali_dvfs_status();
318 nextStatus = decideNextStatus(utilization_global);
320 if (curStatus!=nextStatus) {
321 if (!change_mali_dvfs_status(nextStatus)) {
322 MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
326 static mali_bool init_mali_clock(void)
328 mali_bool ret = MALI_TRUE;
331 if (mali_clock != 0 || mali_clock_pd != 0)
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"));
340 clk_prepare_enable(mali_clock_pd);
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"));
348 dvfs_clk_prepare_enable(mali_clock);
349 freq_table = dvfs_get_freq_volt_table(mali_clock);
351 MALI_PRINT(("Stop,dvfs table should be set in dts\n"));
354 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
355 mali_dvfs[i] = freq_table[i].frequency/1000;
357 mali_init_clock = mali_dvfs[0];
360 MALI_PRINT(("Mali400 inside of rk3126\r\n"));
362 mali_clk_set_rate(mali_clock, mali_init_clock);
368 MALI_PRINT(("::clk_put:: %s mali_clock\n", __FUNCTION__));
371 clk_disable_unprepare(mali_clock_pd);
373 dvfs_clk_disable_unprepare(mali_clock);
380 static mali_bool deinit_mali_clock(void)
382 if (mali_clock == 0 && mali_clock_pd == 0)
384 dvfs_clk_disable_unprepare(mali_clock);
386 clk_disable_unprepare(mali_clock_pd);
395 mali_bool init_mali_dvfs_status(int step)
397 set_mali_dvfs_step(step);
401 #ifdef CONFIG_HAS_EARLYSUSPEND
402 static void mali_pm_early_suspend(struct early_suspend *mali_dev)
406 static void mali_pm_late_resume(struct early_suspend *mali_dev)
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,
415 #endif /* CONFIG_HAS_EARLYSUSPEND */
417 _mali_osk_errcode_t mali_platform_init(void)
419 if (cpu_is_rk3036()) {
420 audis_gpu_clk = clk_get(NULL,"clk_gpu");
422 if (IS_ERR(audis_gpu_clk)) {
423 MALI_PRINT( ("MALI Error : failed to get audis mali clk\n"));
428 clk_prepare_enable(audis_gpu_clk);
432 MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
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"));
438 if(mali400_utility_sysfs_init())
439 MALI_PRINT(("mali400_utility_sysfs_init error\r\n"));
441 mali_freq_data = kmalloc(sizeof(struct mali_freq_data), GFP_KERNEL);
442 if(!mali_freq_data) {
443 MALI_PRINT(("kmalloc error\r\n"));
446 mali_freq_data->wq = create_workqueue(mali_freq_workqueue_name);
447 if(!mali_freq_data->wq)
449 INIT_WORK(&mali_freq_data->work,mali_freq_scale_work);
451 #ifdef CONFIG_HAS_EARLYSUSPEND
452 register_early_suspend(&mali_dev_early_suspend);
458 _mali_osk_errcode_t mali_platform_deinit(void)
460 if (cpu_is_rk3036()) {
461 clk_disable_unprepare(audis_gpu_clk);
466 _mali_osk_mutex_term(clockSetlock);
470 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
473 if (!gpu_power_state) {
474 if (cpu_is_rk3036()) {
475 clk_prepare_enable(audis_gpu_clk);
478 clk_prepare_enable(mali_clock_pd);
480 dvfs_clk_prepare_enable(mali_clock);
482 gpu_power_state = 1 ;
484 } else if (bpower_off == 2) {
486 } else if (bpower_off == 1) {
487 if(gpu_power_state) {
488 if (cpu_is_rk3036()) {
489 clk_disable_unprepare(audis_gpu_clk);
491 dvfs_clk_disable_unprepare(mali_clock);
493 clk_disable_unprepare(mali_clock_pd);
502 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode 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);
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);
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);
519 MALI_DEBUG_PRINT(2,("mali_platform_power_mode_change:power_mode(%d) not support \r\n",power_mode));
524 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
529 if(data->utilization_pp > 256)
531 utilization_global = data->utilization_pp;
533 //MALI_PRINT(("utilization_global = %d\r\n",utilization_global));
535 if(scale_enable && sampling_enable)
536 queue_work(mali_freq_data->wq,&mali_freq_data->work);