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 u32 get_mali_dvfs_status(void)
111 return maliDvfsStatus.currentStep;
113 static void set_mali_dvfs_step(u32 value)
115 maliDvfsStatus.currentStep = value;
118 static void scale_enable_set(u32 value)
120 scale_enable = value;
122 static u32 mali_dvfs_search(u32 value)
126 for (i=0;i<num_clock;i++) {
127 if (clock == mali_dvfs[i]) {
128 _mali_osk_mutex_wait(clockSetlock);
129 mali_clk_set_rate(mali_clock,clock);
130 _mali_osk_mutex_signal(clockSetlock);
131 set_mali_dvfs_step(i);
136 MALI_DEBUG_PRINT(2,("USER set clock not in the mali_dvfs table\r\n"));
141 static int mali400_utility_show(struct device *dev,struct device_attribute *attr, char *buf)
143 return sprintf(buf, "%d\n", utilization_global);
145 static int mali400_clock_set(struct device *dev,struct device_attribute *attr, const char *buf,u32 count)
150 clock = simple_strtoul(buf, NULL, 10);
151 currentStep = get_mali_dvfs_status();
152 timeValue = _mali_osk_time_get_ns();
153 /*MALI_PRINT(("USER SET CLOCK,%d\r\n",clock));*/
157 mali_dvfs_search(clock);
161 static int clock_show(struct device *dev,struct device_attribute *attr, char *buf)
165 pos += snprintf(pos,PAGE_SIZE,"%d,",num_clock);
166 for(i=0;i<(num_clock-1);i++) {
167 pos += snprintf(pos,PAGE_SIZE,"%d,",mali_dvfs[i]);
169 pos +=snprintf(pos,PAGE_SIZE,"%d\n",mali_dvfs[i]);
172 static int sampling_timeout_show(struct device *dev,struct device_attribute *attr, char *buf)
174 return sprintf(buf, "mali_utilization_timeout = %d\n", mali_utilization_timeout);
176 static int sampling_timeout_set(struct device *dev,struct device_attribute *attr,
177 const char *buf,u32 count)
180 sampling = simple_strtoul(buf, NULL, 10);
182 if (sampling == 0 ) {
184 MALI_PRINT(("disable mali clock frequency scalling\r\n"));
186 mali_utilization_timeout = sampling;
188 MALI_PRINT(("enable mali clock frequency scalling ,mali_utilization_timeout : %dms\r\n",
189 mali_utilization_timeout));
193 static int error_count_show(struct device *dev,struct device_attribute *attr, char *buf)
195 return sprintf(buf, "%d\n", mali_group_error);
198 static DEVICE_ATTR(utility, 0644, mali400_utility_show, mali400_clock_set);
199 static DEVICE_ATTR(param, 0644, clock_show, NULL);
200 static DEVICE_ATTR(sampling_timeout, 0644, sampling_timeout_show,sampling_timeout_set);
201 static DEVICE_ATTR(error_count, 0644, error_count_show, NULL);
204 static mali_bool mali400_utility_sysfs_init(void)
208 mali400_utility_object = kobject_create_and_add("mali400_utility", NULL);
209 if (mali400_utility_object == NULL) {
212 ret = sysfs_create_file(mali400_utility_object, &dev_attr_utility.attr);
216 ret = sysfs_create_file(mali400_utility_object, &dev_attr_param.attr);
220 ret = sysfs_create_file(mali400_utility_object, &dev_attr_sampling_timeout.attr);
224 ret = sysfs_create_file(mali400_utility_object, &dev_attr_error_count.attr);
230 static unsigned int decideNextStatus(unsigned int utilization)
234 if(utilization > GPU_DVFS_UP_THRESHOLD &&
235 maliDvfsStatus.currentStep == 0 &&
236 maliDvfsStatus.currentStep < (num_clock-minuend))
238 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
239 maliDvfsStatus.currentStep == 1 &&
240 maliDvfsStatus.currentStep < (num_clock-minuend))
242 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
243 maliDvfsStatus.currentStep == 2 &&
244 maliDvfsStatus.currentStep < (num_clock-minuend))
246 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
247 maliDvfsStatus.currentStep == 3 &&
248 maliDvfsStatus.currentStep < (num_clock-minuend))
250 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
251 maliDvfsStatus.currentStep == 4 &&
252 maliDvfsStatus.currentStep < (num_clock-minuend))
254 else if (utilization > GPU_DVFS_UP_THRESHOLD &&
255 maliDvfsStatus.currentStep == 5 &&
256 maliDvfsStatus.currentStep < (num_clock-minuend))
259 determined by minuend to up to level 6
261 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
262 maliDvfsStatus.currentStep == 6)
264 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
265 maliDvfsStatus.currentStep == 5)
267 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
268 maliDvfsStatus.currentStep == 4)
270 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
271 maliDvfsStatus.currentStep == 3)
273 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
274 maliDvfsStatus.currentStep == 2)
276 else if(utilization < GPU_DVFS_DOWN_THRESHOLD &&
277 maliDvfsStatus.currentStep == 1)
280 level = maliDvfsStatus.currentStep;
284 static mali_bool set_mali_dvfs_status(u32 step)
286 u32 validatedStep=step;
288 _mali_osk_mutex_wait(clockSetlock);
289 mali_clk_set_rate(mali_clock, mali_dvfs[validatedStep]);
290 _mali_osk_mutex_signal(clockSetlock);
291 set_mali_dvfs_step(validatedStep);
296 static mali_bool change_mali_dvfs_status(u32 step)
298 if(!set_mali_dvfs_status(step)) {
299 MALI_DEBUG_PRINT(2,("error on set_mali_dvfs_status: %d\n",step));
306 static void mali_freq_scale_work(struct work_struct *work)
312 curStatus = get_mali_dvfs_status();
313 nextStatus = decideNextStatus(utilization_global);
315 if (curStatus!=nextStatus) {
316 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;
326 if (mali_clock != 0 || mali_clock_pd != 0)
329 mali_clock_pd = clk_get(NULL,GPUCLK_PD_NAME);
330 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)) {
339 MALI_PRINT( ("MALI Error : failed to get source mali clock\n"));
343 dvfs_clk_prepare_enable(mali_clock);
344 freq_table = dvfs_get_freq_volt_table(mali_clock);
346 MALI_PRINT(("Stop,dvfs table should be set in dts\n"));
349 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
350 mali_dvfs[i] = freq_table[i].frequency/1000;
352 mali_init_clock = mali_dvfs[0];
355 MALI_PRINT(("Mali400 inside of rk3126\r\n"));
357 mali_clk_set_rate(mali_clock, mali_init_clock);
363 MALI_PRINT(("::clk_put:: %s mali_clock\n", __FUNCTION__));
366 clk_disable_unprepare(mali_clock_pd);
368 dvfs_clk_disable_unprepare(mali_clock);
375 static mali_bool deinit_mali_clock(void)
377 if (mali_clock == 0 && mali_clock_pd == 0)
379 dvfs_clk_disable_unprepare(mali_clock);
381 clk_disable_unprepare(mali_clock_pd);
390 mali_bool init_mali_dvfs_status(int step)
392 set_mali_dvfs_step(step);
396 #ifdef CONFIG_HAS_EARLYSUSPEND
397 static void mali_pm_early_suspend(struct early_suspend *mali_dev)
401 static void mali_pm_late_resume(struct early_suspend *mali_dev)
405 static struct early_suspend mali_dev_early_suspend = {
406 .suspend = mali_pm_early_suspend,
407 .resume = mali_pm_late_resume,
408 .level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
410 #endif /* CONFIG_HAS_EARLYSUSPEND */
412 _mali_osk_errcode_t mali_platform_init(void)
414 if (cpu_is_rk3036()) {
415 audis_gpu_clk = clk_get(NULL,"clk_gpu");
417 if (IS_ERR(audis_gpu_clk)) {
418 MALI_PRINT( ("MALI Error : failed to get audis mali clk\n"));
423 clk_prepare_enable(audis_gpu_clk);
427 MALI_CHECK(init_mali_clock(), _MALI_OSK_ERR_FAULT);
429 clockSetlock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED,_MALI_OSK_LOCK_ORDER_UTILIZATION);
430 if(!init_mali_dvfs_status(MALI_DVFS_DEFAULT_STEP))
431 MALI_DEBUG_PRINT(1, ("init_mali_dvfs_status failed\n"));
433 if(mali400_utility_sysfs_init())
434 MALI_PRINT(("mali400_utility_sysfs_init error\r\n"));
436 mali_freq_data = kmalloc(sizeof(struct mali_freq_data), GFP_KERNEL);
437 if(!mali_freq_data) {
438 MALI_PRINT(("kmalloc error\r\n"));
441 mali_freq_data->wq = create_workqueue(mali_freq_workqueue_name);
442 if(!mali_freq_data->wq)
444 INIT_WORK(&mali_freq_data->work,mali_freq_scale_work);
446 #ifdef CONFIG_HAS_EARLYSUSPEND
447 register_early_suspend(&mali_dev_early_suspend);
453 _mali_osk_errcode_t mali_platform_deinit(void)
455 if (cpu_is_rk3036()) {
456 clk_disable_unprepare(audis_gpu_clk);
461 _mali_osk_mutex_term(clockSetlock);
465 _mali_osk_errcode_t mali_power_domain_control(u32 bpower_off)
468 if (!gpu_power_state) {
469 if (cpu_is_rk3036()) {
470 clk_prepare_enable(audis_gpu_clk);
473 clk_prepare_enable(mali_clock_pd);
475 dvfs_clk_prepare_enable(mali_clock);
477 gpu_power_state = 1 ;
479 } else if (bpower_off == 2) {
481 } else if (bpower_off == 1) {
482 if(gpu_power_state) {
483 if (cpu_is_rk3036()) {
484 clk_disable_unprepare(audis_gpu_clk);
486 dvfs_clk_disable_unprepare(mali_clock);
488 clk_disable_unprepare(mali_clock_pd);
497 _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode)
501 case MALI_POWER_MODE_ON:
502 MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_ON\r\n"));
503 mali_power_domain_control(MALI_POWER_MODE_ON);
505 case MALI_POWER_MODE_LIGHT_SLEEP:
506 MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_LIGHT_SLEEP\r\n"));
507 mali_power_domain_control(MALI_POWER_MODE_LIGHT_SLEEP);
509 case MALI_POWER_MODE_DEEP_SLEEP:
510 MALI_DEBUG_PRINT(2,("MALI_POWER_MODE_DEEP_SLEEP\r\n"));
511 mali_power_domain_control(MALI_POWER_MODE_DEEP_SLEEP);
514 MALI_DEBUG_PRINT(2,("mali_platform_power_mode_change:power_mode(%d) not support \r\n",power_mode));
519 void mali_gpu_utilization_handler(struct mali_gpu_utilization_data *data)
524 if(data->utilization_pp > 256)
526 utilization_global = data->utilization_pp;
528 //MALI_PRINT(("utilization_global = %d\r\n",utilization_global));
530 if(scale_enable && sampling_enable)
531 queue_work(mali_freq_data->wq,&mali_freq_data->work);