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>
43 #include <linux/input.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 {
76 struct kbase_device *kbdev;
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
102 #ifdef CONFIG_MALI_MIDGARD_DVFS
103 static void gpufreq_input_event(struct input_handle *handle, unsigned int type,
104 unsigned int code, int value)
106 mali_dvfs_status *dvfs_status;
107 struct rk_context *platform;
113 dvfs_status = &mali_dvfs_status_current;
114 platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
116 spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
117 platform->gpu_in_touch = true;
118 spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
121 static int gpufreq_input_connect(struct input_handler *handler,
122 struct input_dev *dev, const struct input_device_id *id)
124 struct input_handle *handle;
127 handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
132 handle->handler = handler;
133 handle->name = "gpufreq";
135 error = input_register_handle(handle);
139 error = input_open_device(handle);
142 pr_info("%s\n",__func__);
145 input_unregister_handle(handle);
151 static void gpufreq_input_disconnect(struct input_handle *handle)
153 input_close_device(handle);
154 input_unregister_handle(handle);
156 pr_info("%s\n",__func__);
159 static const struct input_device_id gpufreq_ids[] = {
161 .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
162 INPUT_DEVICE_ID_MATCH_ABSBIT,
163 .evbit = { BIT_MASK(EV_ABS) },
164 .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
165 BIT_MASK(ABS_MT_POSITION_X) |
166 BIT_MASK(ABS_MT_POSITION_Y) },
169 .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
170 INPUT_DEVICE_ID_MATCH_ABSBIT,
171 .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
172 .absbit = { [BIT_WORD(ABS_X)] =
173 BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
178 static struct input_handler gpufreq_input_handler = {
179 .event = gpufreq_input_event,
180 .connect = gpufreq_input_connect,
181 .disconnect = gpufreq_input_disconnect,
183 .id_table = gpufreq_ids,
187 static void mali_dvfs_event_proc(struct work_struct *w)
190 mali_dvfs_status *dvfs_status;
191 static int level_down_time = 0;
192 static int level_up_time = 0;
194 struct rk_context *platform;
198 mutex_lock(&mali_enable_clock_lock);
199 dvfs_status = &mali_dvfs_status_current;
201 if (!kbase_platform_dvfs_get_enable_status()) {
202 mutex_unlock(&mali_enable_clock_lock);
205 platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
207 fps = rk_get_real_fps(0);
209 dvfs_status->temperature_time++;
211 temp_tmp += rockchip_tsadc_get_temp(1);
213 if(dvfs_status->temperature_time >= gpu_temp_statis_time) {
214 dvfs_status->temperature_time = 0;
215 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
219 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
221 policy = rockchip_pm_get_policy();
223 policy = ROCKCHIP_PM_POLICY_NORMAL;
225 if (ROCKCHIP_PM_POLICY_PERFORMANCE == policy) {
226 dvfs_status->step = MALI_DVFS_STEP - 1;
228 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
230 printk("policy : %d , fps_limit = %d\n",policy,fps_limit);
233 /*give priority to temperature unless in performance mode */
234 if (dvfs_status->temperature > gpu_temp_limit) {
235 if(dvfs_status->step > 0)
238 if(gpu_temp_statis_time > 1)
239 dvfs_status->temperature = 0;
241 pr_info("decrease step for temperature over %d,next clock = %d\n",
242 gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock);
244 } else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) &&
245 (dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit) {
247 if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL) {
249 printk("up,utilisation=%d,current clock=%d,fps = %d,temperature = %d",
250 dvfs_status->utilisation, mali_dvfs_infotbl[dvfs_status->step].clock,
251 fps,dvfs_status->temperature);
256 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
258 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP);
261 } else if ((dvfs_status->step > 0) &&
262 (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) {
264 if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL) {
266 printk("down,utilisation=%d,current clock=%d,fps = %d,temperature = %d",
267 dvfs_status->utilisation,
268 mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature);
270 BUG_ON(dvfs_status->step <= 0);
274 printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock);
282 printk("keep,utilisation=%d,current clock=%d,fps = %d,temperature = %d\n",
283 dvfs_status->utilisation,
284 mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature);
288 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
289 if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock))
290 dvfs_status->step = dvfs_status->upper_lock;
292 if (dvfs_status->under_lock > 0) {
293 if (dvfs_status->step < dvfs_status->under_lock)
294 dvfs_status->step = dvfs_status->under_lock;
297 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
298 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
300 mutex_unlock(&mali_enable_clock_lock);
303 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
305 int kbase_platform_dvfs_event(struct kbase_device *kbdev,
307 u32 util_gl_share_no_use,
308 u32 util_cl_share_no_use[2] )
311 struct rk_context *platform;
314 platform = (struct rk_context *)kbdev->platform_context;
316 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
317 if (platform->time_tick < MALI_DVFS_UP_TIME_INTERVAL) {
318 platform->time_tick++;
319 platform->time_busy += kbdev->pm.backend.metrics.time_busy;
321 platform->time_idle += kbdev->pm.backend.metrics.time_idle;
323 platform->time_busy = kbdev->pm.backend.metrics.time_busy;
324 platform->time_idle = kbdev->pm.backend.metrics.time_idle;
325 platform->time_tick = 0;
328 if ((platform->time_tick == MALI_DVFS_UP_TIME_INTERVAL) &&
329 (platform->time_idle + platform->time_busy > 0))
330 platform->utilisation = (100 * platform->time_busy) /
331 (platform->time_idle + platform->time_busy);
333 mali_dvfs_status_current.utilisation = utilisation;
334 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
336 queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
337 /*add error handle here */
341 int kbase_platform_dvfs_get_utilisation(void)
346 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
347 utilisation = mali_dvfs_status_current.utilisation;
348 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
353 int kbase_platform_dvfs_get_enable_status(void)
355 struct kbase_device *kbdev;
359 kbdev = mali_dvfs_status_current.kbdev;
360 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
361 enable = kbdev->pm.backend.metrics.timer_active;
362 spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
367 int kbase_platform_dvfs_enable(bool enable, int freq)
369 mali_dvfs_status *dvfs_status;
370 struct kbase_device *kbdev;
372 struct rk_context *platform;
374 dvfs_status = &mali_dvfs_status_current;
375 kbdev = mali_dvfs_status_current.kbdev;
377 BUG_ON(kbdev == NULL);
378 platform = (struct rk_context *)kbdev->platform_context;
380 mutex_lock(&mali_enable_clock_lock);
382 if (enable != kbdev->pm.backend.metrics.timer_active) {
384 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
385 kbdev->pm.backend.metrics.timer_active = MALI_TRUE;
386 spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
387 hrtimer_start(&kbdev->pm.backend.metrics.timer,
388 HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
391 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
392 kbdev->pm.backend.metrics.timer_active = MALI_FALSE;
393 spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
394 hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
398 if (freq != MALI_DVFS_CURRENT_FREQ) {
399 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
400 platform->time_tick = 0;
401 platform->time_busy = 0;
402 platform->time_idle = 0;
403 platform->utilisation = 0;
404 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
405 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
406 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
409 mutex_unlock(&mali_enable_clock_lock);
414 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
415 static bool calculate_dvfs_max_min_threshold(u32 level)
420 if ((MALI_DVFS_STEP-1) == level) {
421 mali_dvfs_infotbl[level].min_threshold = level0_min;
422 mali_dvfs_infotbl[level].max_threshold = levelf_max;
424 mali_dvfs_infotbl[level].min_threshold = level0_min;
425 mali_dvfs_infotbl[level].max_threshold = level0_max;
428 pre_level = level - 1;
429 if ((MALI_DVFS_STEP-1) == level) {
430 mali_dvfs_infotbl[level].max_threshold = levelf_max;
432 mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold +
435 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold *
436 (mali_dvfs_infotbl[pre_level].clock/1000)) /
437 (mali_dvfs_infotbl[level].clock/1000);
439 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
441 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
443 pr_info("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",
444 level,mali_dvfs_infotbl[level].clock, mali_dvfs_infotbl[level].min_threshold,
445 mali_dvfs_infotbl[level].max_threshold);
449 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
453 add here with the right function to get initilization value.
455 struct rk_context *platform;
459 platform = (struct rk_context *)kbdev->platform_context;
460 if (NULL == platform)
463 mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
465 if (mali_freq_table == NULL) {
466 printk("mali freq table not assigned yet,use default\n");
471 for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
472 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
475 if(MALI_DVFS_STEP > 1)
476 div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1);
477 printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs);
479 for(i=0;i<MALI_DVFS_STEP;i++)
480 calculate_dvfs_max_min_threshold(i);
481 p_mali_dvfs_infotbl = mali_dvfs_infotbl;
485 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
487 spin_lock_init(&mali_dvfs_spinlock);
488 mutex_init(&mali_set_clock_lock);
489 mutex_init(&mali_enable_clock_lock);
491 spin_lock_init(&platform->gpu_in_touch_lock);
492 rc = input_register_handler(&gpufreq_input_handler);
494 /*add a error handling here */
495 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
496 mali_dvfs_status_current.kbdev = kbdev;
497 mali_dvfs_status_current.utilisation = 0;
498 mali_dvfs_status_current.step = 0;
499 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
500 mali_dvfs_status_current.upper_lock = -1;
501 mali_dvfs_status_current.under_lock = -1;
504 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
509 void kbase_platform_dvfs_term(void)
512 destroy_workqueue(mali_dvfs_wq);
516 input_unregister_handler(&gpufreq_input_handler);
518 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
520 int mali_get_dvfs_upper_locked_freq(void)
523 int locked_level = -1;
525 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
526 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
527 if (mali_dvfs_status_current.upper_lock >= 0)
528 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
529 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
534 int mali_get_dvfs_under_locked_freq(void)
537 int locked_level = -1;
539 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
540 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
541 if (mali_dvfs_status_current.under_lock >= 0)
542 locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
543 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
548 int mali_get_dvfs_current_level(void)
551 int current_level = -1;
553 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
554 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
555 current_level = mali_dvfs_status_current.step;
556 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
558 return current_level;
561 int mali_dvfs_freq_lock(int level)
564 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
565 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
566 if (mali_dvfs_status_current.under_lock >= 0 &&
567 mali_dvfs_status_current.under_lock > level) {
568 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
569 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
572 mali_dvfs_status_current.upper_lock = level;
573 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
575 printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
580 void mali_dvfs_freq_unlock(void)
583 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
584 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
585 mali_dvfs_status_current.upper_lock = -1;
586 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
588 printk(KERN_DEBUG "mali Upper Lock Unset\n");
591 int mali_dvfs_freq_under_lock(int level)
594 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
595 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
596 if (mali_dvfs_status_current.upper_lock >= 0 &&
597 mali_dvfs_status_current.upper_lock < level) {
598 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
599 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
602 mali_dvfs_status_current.under_lock = level;
603 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
605 printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
610 void mali_dvfs_freq_under_unlock(void)
613 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
614 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
615 mali_dvfs_status_current.under_lock = -1;
616 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
618 printk(KERN_DEBUG " mali clock Under Lock Unset\n");
621 void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq)
623 struct rk_context *platform;
628 platform = (struct rk_context *)kbdev->platform_context;
629 if (NULL == platform)
632 if (!platform->mali_clk_node) {
633 printk("mali_clk_node not init\n");
636 mali_dvfs_clk_set(platform->mali_clk_node,freq);
642 int kbase_platform_dvfs_get_level(int freq)
645 for (i = 0; i < MALI_DVFS_STEP; i++) {
646 if (mali_dvfs_infotbl[i].clock == freq)
651 void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level)
653 static int prev_level = -1;
655 if (level == prev_level)
658 if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0))) {
659 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
662 /*panic("invalid level");*/
663 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
664 if (mali_dvfs_status_current.upper_lock >= 0 &&
665 level > mali_dvfs_status_current.upper_lock)
666 level = mali_dvfs_status_current.upper_lock;
667 if (mali_dvfs_status_current.under_lock >= 0 &&
668 level < mali_dvfs_status_current.under_lock)
669 level = mali_dvfs_status_current.under_lock;
671 #ifdef CONFIG_MALI_MIDGARD_DVFS
672 mutex_lock(&mali_set_clock_lock);
675 kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
676 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
677 update_time_in_state(prev_level);
680 #ifdef CONFIG_MALI_MIDGARD_DVFS
681 mutex_unlock(&mali_set_clock_lock);
685 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
686 #ifdef CONFIG_MALI_MIDGARD_DVFS
687 static void update_time_in_state(int level)
690 static u64 prev_time=0;
695 if (!kbase_platform_dvfs_get_enable_status())
699 prev_time=get_jiffies_64();
701 current_time = get_jiffies_64();
702 mali_dvfs_infotbl[level].time += current_time-prev_time;
704 prev_time = current_time;
708 ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr,
711 struct kbase_device *kbdev;
715 kbdev = dev_get_drvdata(dev);
717 #ifdef CONFIG_MALI_MIDGARD_DVFS
718 update_time_in_state(mali_dvfs_status_current.step);
723 for (i = 0; i < MALI_DVFS_STEP; i++)
724 ret += snprintf(buf + ret, PAGE_SIZE - ret,
726 mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time);
728 if (ret < PAGE_SIZE - 1)
729 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
731 buf[PAGE_SIZE - 2] = '\n';
732 buf[PAGE_SIZE - 1] = '\0';
739 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr,
740 const char *buf, size_t count)
744 for (i = 0; i < MALI_DVFS_STEP; i++)
745 mali_dvfs_infotbl[i].time = 0;
747 printk(KERN_DEBUG "time_in_state value is reset complete.\n");