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++;
124 temp_tmp += rockchip_tsadc_get_temp(2);
126 if(dvfs_status->temperature_time >= gpu_temp_statis_time)
128 dvfs_status->temperature_time = 0;
129 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
131 /*pr_info("dvfs_status->temperature = %d\n",dvfs_status->temperature);*/
134 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
136 policy = rockchip_pm_get_policy();
138 policy = ROCKCHIP_PM_POLICY_NORMAL;
140 if(ROCKCHIP_PM_POLICY_PERFORMANCE == policy)
142 dvfs_status->step = MALI_DVFS_STEP - 1; /*Highest level when performance mode*/
146 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
148 printk("policy : %d , fps_limit = %d\n",policy,fps_limit);
151 /*give priority to temperature unless in performance mode */
152 if(dvfs_status->temperature > gpu_temp_limit)
154 if(dvfs_status->step > 0)
157 if(gpu_temp_statis_time > 1)
158 dvfs_status->temperature = 0;
160 else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) && (dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit)
163 if(level_up_time == MALI_DVFS_TIME_INTERVAL)
166 printk("up,utilisation=%d,current clock=%d,fps = %d",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
171 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
173 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
177 else if((dvfs_status->step > 0) && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold))
178 /*else if((dvfs_status->step > 0) && (platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) */
181 if(level_down_time==MALI_DVFS_TIME_INTERVAL)
184 printk("down,utilisation=%d,current clock=%d,fps = %d",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
186 BUG_ON(dvfs_status->step <= 0);
190 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
200 printk("keep,utilisation=%d,current clock=%d,fps = %d\n",dvfs_status->utilisation,mali_dvfs_infotbl[dvfs_status->step].clock,fps);
204 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
205 if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock))
207 dvfs_status->step = dvfs_status->upper_lock;
210 if (dvfs_status->under_lock > 0)
212 if (dvfs_status->step < dvfs_status->under_lock)
213 dvfs_status->step = dvfs_status->under_lock;
216 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
217 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
219 mutex_unlock(&mali_enable_clock_lock);
222 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
224 int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation)
227 struct rk_context *platform;
230 platform = (struct rk_context *)kbdev->platform_context;
232 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
233 if (platform->time_tick < MALI_DVFS_TIME_INTERVAL) {
234 platform->time_tick++;
235 platform->time_busy += kbdev->pm.metrics.time_busy;
236 platform->time_idle += kbdev->pm.metrics.time_idle;
238 platform->time_busy = kbdev->pm.metrics.time_busy;
239 platform->time_idle = kbdev->pm.metrics.time_idle;
240 platform->time_tick = 0;
243 if ((platform->time_tick == MALI_DVFS_TIME_INTERVAL) && (platform->time_idle + platform->time_busy > 0))
244 platform->utilisation = (100 * platform->time_busy) / (platform->time_idle + platform->time_busy);
246 mali_dvfs_status_current.utilisation = utilisation;
247 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
249 queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
250 /*add error handle here */
254 int kbase_platform_dvfs_get_utilisation(void)
259 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
260 utilisation = mali_dvfs_status_current.utilisation;
261 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
266 int kbase_platform_dvfs_get_enable_status(void)
268 struct kbase_device *kbdev;
272 kbdev = mali_dvfs_status_current.kbdev;
273 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
274 enable = kbdev->pm.metrics.timer_active;
275 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
280 int kbase_platform_dvfs_enable(bool enable, int freq)
282 mali_dvfs_status *dvfs_status;
283 struct kbase_device *kbdev;
285 struct rk_context *platform;
287 dvfs_status = &mali_dvfs_status_current;
288 kbdev = mali_dvfs_status_current.kbdev;
290 BUG_ON(kbdev == NULL);
291 platform = (struct rk_context *)kbdev->platform_context;
293 mutex_lock(&mali_enable_clock_lock);
295 if (enable != kbdev->pm.metrics.timer_active) {
297 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
298 kbdev->pm.metrics.timer_active = MALI_TRUE;
299 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
300 hrtimer_start(&kbdev->pm.metrics.timer,
301 HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
304 spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
305 kbdev->pm.metrics.timer_active = MALI_FALSE;
306 spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
307 hrtimer_cancel(&kbdev->pm.metrics.timer);
311 if (freq != MALI_DVFS_CURRENT_FREQ) {
312 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
313 platform->time_tick = 0;
314 platform->time_busy = 0;
315 platform->time_idle = 0;
316 platform->utilisation = 0;
317 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
318 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
319 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
322 mutex_unlock(&mali_enable_clock_lock);
327 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
328 static bool calculate_dvfs_max_min_threshold(u32 level)
334 if((MALI_DVFS_STEP-1) == level)
336 mali_dvfs_infotbl[level].min_threshold = level0_min;
337 mali_dvfs_infotbl[level].max_threshold = levelf_max;
341 mali_dvfs_infotbl[level].min_threshold = level0_min;
342 mali_dvfs_infotbl[level].max_threshold = level0_max;
347 pre_level = level - 1;
348 if((MALI_DVFS_STEP-1) == level)
350 mali_dvfs_infotbl[level].max_threshold = levelf_max;
354 mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold + div_dvfs;
356 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold * (mali_dvfs_infotbl[pre_level].clock/1000))
357 / (mali_dvfs_infotbl[level].clock/1000);
359 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
361 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
364 printk("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",level,
365 mali_dvfs_infotbl[level].clock,
366 mali_dvfs_infotbl[level].min_threshold,
367 mali_dvfs_infotbl[level].max_threshold
373 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
377 add here with the right function to get initilization value.
379 struct rk_context *platform;
382 platform = (struct rk_context *)kbdev->platform_context;
383 if (NULL == platform)
386 mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
388 if (mali_freq_table == NULL)
390 printk("mali freq table not assigned yet,use default\n");
397 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
399 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
402 if(MALI_DVFS_STEP > 1)
403 div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1);
404 printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs);
406 for(i=0;i<MALI_DVFS_STEP;i++)
408 calculate_dvfs_max_min_threshold(i);
410 p_mali_dvfs_infotbl = mali_dvfs_infotbl;
414 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
416 spin_lock_init(&mali_dvfs_spinlock);
417 mutex_init(&mali_set_clock_lock);
418 mutex_init(&mali_enable_clock_lock);
420 /*add a error handling here */
421 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
422 mali_dvfs_status_current.kbdev = kbdev;
423 mali_dvfs_status_current.utilisation = 0;
424 mali_dvfs_status_current.step = 0;
425 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
426 mali_dvfs_status_current.upper_lock = -1;
427 mali_dvfs_status_current.under_lock = -1;
430 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
435 void kbase_platform_dvfs_term(void)
438 destroy_workqueue(mali_dvfs_wq);
442 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
444 int mali_get_dvfs_upper_locked_freq(void)
447 int locked_level = -1;
449 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
450 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
451 if (mali_dvfs_status_current.upper_lock >= 0)
452 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
453 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
458 int mali_get_dvfs_under_locked_freq(void)
461 int locked_level = -1;
463 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
464 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
465 if (mali_dvfs_status_current.under_lock >= 0)
466 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
467 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
472 int mali_get_dvfs_current_level(void)
475 int current_level = -1;
477 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
478 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
479 current_level = mali_dvfs_status_current.step;
480 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
482 return current_level;
485 int mali_dvfs_freq_lock(int level)
488 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
489 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
490 if (mali_dvfs_status_current.under_lock >= 0 && mali_dvfs_status_current.under_lock > level) {
491 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
492 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
495 mali_dvfs_status_current.upper_lock = level;
496 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
498 printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
503 void mali_dvfs_freq_unlock(void)
506 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
507 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
508 mali_dvfs_status_current.upper_lock = -1;
509 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
511 printk(KERN_DEBUG "mali Upper Lock Unset\n");
514 int mali_dvfs_freq_under_lock(int level)
517 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
518 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
519 if (mali_dvfs_status_current.upper_lock >= 0 && mali_dvfs_status_current.upper_lock < level) {
520 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
521 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
524 mali_dvfs_status_current.under_lock = level;
525 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
527 printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
532 void mali_dvfs_freq_under_unlock(void)
535 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
536 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
537 mali_dvfs_status_current.under_lock = -1;
538 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
540 printk(KERN_DEBUG " mali clock Under Lock Unset\n");
543 void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq)
545 struct rk_context *platform;
550 platform = (struct rk_context *)kbdev->platform_context;
551 if (NULL == platform)
554 if (!platform->mali_clk_node)
556 printk("mali_clk_node not init\n");
559 mali_dvfs_clk_set(platform->mali_clk_node,freq);
565 int kbase_platform_dvfs_get_level(int freq)
568 for (i = 0; i < MALI_DVFS_STEP; i++) {
569 if (mali_dvfs_infotbl[i].clock == freq)
574 void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level)
576 static int prev_level = -1;
578 if (level == prev_level)
581 if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0)))
583 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
586 /*panic("invalid level");*/
587 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
588 if (mali_dvfs_status_current.upper_lock >= 0 && level > mali_dvfs_status_current.upper_lock)
589 level = mali_dvfs_status_current.upper_lock;
590 if (mali_dvfs_status_current.under_lock >= 0 && level < mali_dvfs_status_current.under_lock)
591 level = mali_dvfs_status_current.under_lock;
593 #ifdef CONFIG_MALI_MIDGARD_DVFS
594 mutex_lock(&mali_set_clock_lock);
597 kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
598 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
599 update_time_in_state(prev_level);
602 #ifdef CONFIG_MALI_MIDGARD_DVFS
603 mutex_unlock(&mali_set_clock_lock);
607 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
608 #ifdef CONFIG_MALI_MIDGARD_DVFS
609 static void update_time_in_state(int level)
612 static u64 prev_time=0;
617 if (!kbase_platform_dvfs_get_enable_status())
621 prev_time=get_jiffies_64();
623 current_time = get_jiffies_64();
624 mali_dvfs_infotbl[level].time += current_time-prev_time;
626 prev_time = current_time;
630 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
632 struct kbase_device *kbdev;
636 kbdev = dev_get_drvdata(dev);
638 #ifdef CONFIG_MALI_MIDGARD_DVFS
639 update_time_in_state(mali_dvfs_status_current.step);
644 for (i = 0; i < MALI_DVFS_STEP; i++)
645 ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d %llu\n", mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
647 if (ret < PAGE_SIZE - 1)
648 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
650 buf[PAGE_SIZE - 2] = '\n';
651 buf[PAGE_SIZE - 1] = '\0';
658 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
662 for (i = 0; i < MALI_DVFS_STEP; i++)
663 mali_dvfs_infotbl[i].time = 0;
665 printk(KERN_DEBUG "time_in_state value is reset complete.\n");