1 /* drivers/gpu/t6xx/kbase/src/platform/manta/mali_kbase_dvfs.c
4 * Rockchip SoC Mali-T764 DVFS driver
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software FoundatIon.
12 * @file mali_kbase_dvfs.c
16 #include <mali_kbase.h>
17 #include <mali_kbase_uku.h>
18 #include <mali_kbase_mem.h>
19 #include <mali_midg_regmap.h>
20 #include <mali_kbase_mem_linux.h>
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/poll.h>
25 #include <linux/kernel.h>
26 #include <linux/errno.h>
27 #include <linux/platform_device.h>
28 #include <linux/pci.h>
29 #include <linux/miscdevice.h>
30 #include <linux/list.h>
31 #include <linux/semaphore.h>
33 #include <linux/uaccess.h>
34 #include <linux/interrupt.h>
36 #include <linux/cpufreq.h>
38 #include <linux/clk.h>
39 #include <linux/delay.h>
40 #include <linux/regulator/consumer.h>
41 #include <linux/regulator/driver.h>
42 #include <linux/rk_fb.h>
44 #include <linux/rockchip/common.h>
46 #include <platform/rk/mali_kbase_platform.h>
47 #include <platform/rk/mali_kbase_dvfs.h>
48 #include <mali_kbase_gator.h>
49 #include <linux/rockchip/dvfs.h>
50 /***********************************************************/
51 /* This table and variable are using the check time share of GPU Clock */
52 /***********************************************************/
53 extern int rockchip_tsadc_get_temp(int chn);
54 #define gpu_temp_limit 110
55 #define gpu_temp_statis_time 1
58 #define levelf_max 100
59 static u32 div_dvfs = 0 ;
61 static mali_dvfs_info mali_dvfs_infotbl[] = {
62 {925000, 100000, 0, 70, 0},
63 {925000, 160000, 50, 65, 0},
64 {1025000, 266000, 60, 78, 0},
65 {1075000, 350000, 65, 75, 0},
66 {1125000, 400000, 70, 75, 0},
67 {1200000, 500000, 90, 100, 0},
69 mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
71 unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
73 static struct cpufreq_frequency_table *mali_freq_table = NULL;
74 #ifdef CONFIG_MALI_MIDGARD_DVFS
75 typedef struct _mali_dvfs_status_type {
81 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
88 static struct workqueue_struct *mali_dvfs_wq = 0;
89 spinlock_t mali_dvfs_spinlock;
90 struct mutex mali_set_clock_lock;
91 struct mutex mali_enable_clock_lock;
93 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
94 static void update_time_in_state(int level);
97 static mali_dvfs_status mali_dvfs_status_current;
100 #define LIMIT_FPS_POWER_SAVE 50
101 static void mali_dvfs_event_proc(struct work_struct *w)
104 mali_dvfs_status *dvfs_status;
105 static int level_down_time = 0;
106 static int level_up_time = 0;
108 struct rk_context *platform;
112 mutex_lock(&mali_enable_clock_lock);
113 dvfs_status = &mali_dvfs_status_current;
115 if (!kbase_platform_dvfs_get_enable_status()) {
116 mutex_unlock(&mali_enable_clock_lock);
119 platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
121 fps = rk_get_real_fps(0);
123 dvfs_status->temperature_time++;
125 temp_tmp += rockchip_tsadc_get_temp(2);
127 if(dvfs_status->temperature_time >= gpu_temp_statis_time)
129 dvfs_status->temperature_time = 0;
130 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
132 /*pr_info("dvfs_status->temperature = %d\n",dvfs_status->temperature);*/
135 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
137 policy = rockchip_pm_get_policy();
139 policy = ROCKCHIP_PM_POLICY_NORMAL;
141 if(ROCKCHIP_PM_POLICY_PERFORMANCE == policy)
143 dvfs_status->step = MALI_DVFS_STEP - 1; /*Highest level when performance mode*/
147 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
149 printk("policy : %d , fps_limit = %d\n",policy,fps_limit);
152 /*give priority to temperature unless in performance mode */
153 if(dvfs_status->temperature > gpu_temp_limit)
155 if(dvfs_status->step > 0)
158 if(gpu_temp_statis_time > 1)
159 dvfs_status->temperature = 0;
161 else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) && (dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit)
164 if(level_up_time == MALI_DVFS_TIME_INTERVAL)
167 printk("up,utilisation=%d,current clock=%d,fps = %d",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
172 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
174 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
178 else if((dvfs_status->step > 0) && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold))
179 /*else if((dvfs_status->step > 0) && (platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) */
182 if(level_down_time==MALI_DVFS_TIME_INTERVAL)
185 printk("down,utilisation=%d,current clock=%d,fps = %d",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
187 BUG_ON(dvfs_status->step <= 0);
191 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
201 printk("keep,utilisation=%d,current clock=%d,fps = %d\n",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
205 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
206 if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock))
208 dvfs_status->step = dvfs_status->upper_lock;
211 if (dvfs_status->under_lock > 0)
213 if (dvfs_status->step < dvfs_status->under_lock)
214 dvfs_status->step = dvfs_status->under_lock;
217 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
218 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
220 mutex_unlock(&mali_enable_clock_lock);
223 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
225 int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation)
228 struct rk_context *platform;
231 platform = (struct rk_context *)kbdev->platform_context;
233 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
234 if (platform->time_tick < MALI_DVFS_TIME_INTERVAL) {
235 platform->time_tick++;
236 platform->time_busy += kbdev->pm.metrics.time_busy;
237 platform->time_idle += kbdev->pm.metrics.time_idle;
239 platform->time_busy = kbdev->pm.metrics.time_busy;
240 platform->time_idle = kbdev->pm.metrics.time_idle;
241 platform->time_tick = 0;
244 if ((platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->time_idle + platform->time_busy > 0))
245 platform->utilisation = (100 * platform->time_busy) / (platform->time_idle + platform->time_busy);
247 mali_dvfs_status_current.utilisation = utilisation;
248 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
250 queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
251 /*add error handle here */
255 int kbase_platform_dvfs_get_utilisation(void)
260 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
261 utilisation = mali_dvfs_status_current.utilisation;
262 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
267 int kbase_platform_dvfs_get_enable_status(void)
269 struct kbase_device *kbdev;
273 kbdev = mali_dvfs_status_current.kbdev;
274 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
275 enable = kbdev->pm.metrics.timer_active;
276 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
281 int kbase_platform_dvfs_enable(bool enable, int freq)
283 mali_dvfs_status *dvfs_status;
284 struct kbase_device *kbdev;
286 struct rk_context *platform;
288 dvfs_status = &mali_dvfs_status_current;
289 kbdev = mali_dvfs_status_current.kbdev;
291 BUG_ON(kbdev == NULL);
292 platform = (struct rk_context *)kbdev->platform_context;
294 mutex_lock(&mali_enable_clock_lock);
296 if (enable != kbdev->pm.metrics.timer_active) {
298 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
299 kbdev->pm.metrics.timer_active = MALI_TRUE;
300 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
301 hrtimer_start(&kbdev->pm.metrics.timer,
302 HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
305 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
306 kbdev->pm.metrics.timer_active = MALI_FALSE;
307 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
308 hrtimer_cancel(&kbdev->pm.metrics.timer);
312 if (freq != MALI_DVFS_CURRENT_FREQ) {
313 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
314 platform->time_tick = 0;
315 platform->time_busy = 0;
316 platform->time_idle = 0;
317 platform->utilisation = 0;
318 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
319 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
320 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
323 mutex_unlock(&mali_enable_clock_lock);
328 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
329 static bool calculate_dvfs_max_min_threshold(u32 level)
335 if((MALI_DVFS_STEP-1) == level)
337 mali_dvfs_infotbl[level].min_threshold = level0_min;
338 mali_dvfs_infotbl[level].max_threshold = levelf_max;
342 mali_dvfs_infotbl[level].min_threshold = level0_min;
343 mali_dvfs_infotbl[level].max_threshold = level0_max;
348 pre_level = level - 1;
349 if((MALI_DVFS_STEP-1) == level)
351 mali_dvfs_infotbl[level].max_threshold = levelf_max;
355 mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold + div_dvfs;
357 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold * (mali_dvfs_infotbl[pre_level].clock/1000))
358 / (mali_dvfs_infotbl[level].clock/1000);
360 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
362 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
365 printk("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",level,
366 mali_dvfs_infotbl[level].clock,
367 mali_dvfs_infotbl[level].min_threshold,
368 mali_dvfs_infotbl[level].max_threshold
374 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
378 add here with the right function to get initilization value.
380 struct rk_context *platform;
383 platform = (struct rk_context *)kbdev->platform_context;
384 if (NULL == platform)
387 mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
389 if (mali_freq_table == NULL)
391 printk("mali freq table not assigned yet,use default\n");
398 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
400 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
403 if(MALI_DVFS_STEP > 1)
404 div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1);
405 printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs);
407 for(i=0;i<MALI_DVFS_STEP;i++)
409 calculate_dvfs_max_min_threshold(i);
411 p_mali_dvfs_infotbl = mali_dvfs_infotbl;
415 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
417 spin_lock_init(&mali_dvfs_spinlock);
418 mutex_init(&mali_set_clock_lock);
419 mutex_init(&mali_enable_clock_lock);
421 /*add a error handling here */
422 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
423 mali_dvfs_status_current.kbdev = kbdev;
424 mali_dvfs_status_current.utilisation = 0;
425 mali_dvfs_status_current.step = 0;
426 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
427 mali_dvfs_status_current.upper_lock = -1;
428 mali_dvfs_status_current.under_lock = -1;
431 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
436 void kbase_platform_dvfs_term(void)
439 destroy_workqueue(mali_dvfs_wq);
443 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
445 int mali_get_dvfs_upper_locked_freq(void)
448 int locked_level = -1;
450 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
451 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
452 if (mali_dvfs_status_current.upper_lock >= 0)
453 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
454 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
459 int mali_get_dvfs_under_locked_freq(void)
462 int locked_level = -1;
464 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
465 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
466 if (mali_dvfs_status_current.under_lock >= 0)
467 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
468 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
473 int mali_get_dvfs_current_level(void)
476 int current_level = -1;
478 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
479 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
480 current_level = mali_dvfs_status_current.step;
481 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
483 return current_level;
486 int mali_dvfs_freq_lock(int level)
489 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
490 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
491 if (mali_dvfs_status_current.under_lock >= 0 && mali_dvfs_status_current.under_lock > level) {
492 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
493 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
496 mali_dvfs_status_current.upper_lock = level;
497 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
499 printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
504 void mali_dvfs_freq_unlock(void)
507 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
508 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
509 mali_dvfs_status_current.upper_lock = -1;
510 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
512 printk(KERN_DEBUG "mali Upper Lock Unset\n");
515 int mali_dvfs_freq_under_lock(int level)
518 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
519 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
520 if (mali_dvfs_status_current.upper_lock >= 0 && mali_dvfs_status_current.upper_lock < level) {
521 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
522 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
525 mali_dvfs_status_current.under_lock = level;
526 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
528 printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
533 void mali_dvfs_freq_under_unlock(void)
536 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
537 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
538 mali_dvfs_status_current.under_lock = -1;
539 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
541 printk(KERN_DEBUG " mali clock Under Lock Unset\n");
544 void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq)
546 struct rk_context *platform;
551 platform = (struct rk_context *)kbdev->platform_context;
552 if (NULL == platform)
555 if (!platform->mali_clk_node)
557 printk("mali_clk_node not init\n");
560 mali_dvfs_clk_set(platform->mali_clk_node,freq);
566 int kbase_platform_dvfs_get_level(int freq)
569 for (i = 0; i < MALI_DVFS_STEP; i++) {
570 if (mali_dvfs_infotbl[i].clock == freq)
575 void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level)
577 static int prev_level = -1;
579 if (level == prev_level)
582 if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0)))
584 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
587 /*panic("invalid level");*/
588 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
589 if (mali_dvfs_status_current.upper_lock >= 0 && level > mali_dvfs_status_current.upper_lock)
590 level = mali_dvfs_status_current.upper_lock;
591 if (mali_dvfs_status_current.under_lock >= 0 && level < mali_dvfs_status_current.under_lock)
592 level = mali_dvfs_status_current.under_lock;
594 #ifdef CONFIG_MALI_MIDGARD_DVFS
595 mutex_lock(&mali_set_clock_lock);
598 kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
599 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
600 update_time_in_state(prev_level);
603 #ifdef CONFIG_MALI_MIDGARD_DVFS
604 mutex_unlock(&mali_set_clock_lock);
608 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
609 #ifdef CONFIG_MALI_MIDGARD_DVFS
610 static void update_time_in_state(int level)
613 static u64 prev_time=0;
618 if (!kbase_platform_dvfs_get_enable_status())
622 prev_time=get_jiffies_64();
624 current_time = get_jiffies_64();
625 mali_dvfs_infotbl[level].time += current_time-prev_time;
627 prev_time = current_time;
631 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
633 struct kbase_device *kbdev;
637 kbdev = dev_get_drvdata(dev);
639 #ifdef CONFIG_MALI_MIDGARD_DVFS
640 update_time_in_state(mali_dvfs_status_current.step);
645 for (i = 0; i < MALI_DVFS_STEP; i++)
646 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d %llu\n", mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
648 if (ret < PAGE_SIZE - 1)
649 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
651 buf[PAGE_SIZE - 2] = '\n';
652 buf[PAGE_SIZE - 1] = '\0';
659 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
663 for (i = 0; i < MALI_DVFS_STEP; i++)
664 mali_dvfs_infotbl[i].time = 0;
666 printk(KERN_DEBUG "time_in_state value is reset complete.\n");