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 // #define ENABLE_DEBUG_LOG
17 #include "custom_log.h"
19 #include <mali_kbase.h>
20 #include <mali_kbase_uku.h>
21 #include <mali_kbase_mem.h>
22 #include <mali_midg_regmap.h>
23 #include <mali_kbase_mem_linux.h>
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/poll.h>
28 #include <linux/kernel.h>
29 #include <linux/errno.h>
30 #include <linux/platform_device.h>
31 #include <linux/pci.h>
32 #include <linux/miscdevice.h>
33 #include <linux/list.h>
34 #include <linux/semaphore.h>
36 #include <linux/uaccess.h>
37 #include <linux/interrupt.h>
39 #include <linux/cpufreq.h>
41 #include <linux/clk.h>
42 #include <linux/delay.h>
43 #include <linux/regulator/consumer.h>
44 #include <linux/regulator/driver.h>
45 #include <linux/rk_fb.h>
46 #include <linux/input.h>
47 #include <linux/rockchip/common.h>
49 #include <platform/rk/mali_kbase_platform.h>
50 #include <platform/rk/mali_kbase_dvfs.h>
51 #include <mali_kbase_gator.h>
52 #include <linux/rockchip/dvfs.h>
53 /***********************************************************/
54 /* This table and variable are using the check time share of GPU Clock */
55 /***********************************************************/
56 extern int rockchip_tsadc_get_temp(int chn);
58 #define gpu_temp_limit 110
59 /** 经过 gpu_temp_statis_time 次测量记录之后, 对温度数据取平均. */
60 #define gpu_temp_statis_time 1
64 #define levelf_max 100
66 static u32 div_dvfs = 0 ;
69 * .DP : mali_dvfs_level_table.
70 * 其中的 level_items 的 gpu_clk_freq 从低到高.
72 * 运行时初始化阶段, 将从 'mali_freq_table' 进行运行时初始化,
73 * 若获取 'mali_freq_table' 失败, 则使用这里的 缺省配置.
74 * 参见 kbase_platform_dvfs_init.
76 static mali_dvfs_info mali_dvfs_infotbl[] = {
77 {925000, 100000, 0, 70, 0},
78 {925000, 160000, 50, 65, 0},
79 {1025000, 266000, 60, 78, 0},
80 {1075000, 350000, 65, 75, 0},
81 {1125000, 400000, 70, 75, 0},
82 {1200000, 500000, 90, 100, 0},
85 * pointer_to_mali_dvfs_level_table.
87 mali_dvfs_info *p_mali_dvfs_infotbl = NULL;
90 * num_of_mali_dvfs_levels : mali_dvfs_level_table 中有效的 level_item 的数量.
92 unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl);
95 * mali_dvfs_level_table 中可以容纳的 level_items 的最大数量.
97 const unsigned int MAX_NUM_OF_MALI_DVFS_LEVELS = ARRAY_SIZE(mali_dvfs_infotbl);
100 * gpu_clk_freq_table_from_system_dvfs_module, 从 system_dvfs_module 得到的 gpu_clk 的 频点表.
101 * 原始的 频点配置信息在 .dts 文件中.
103 static struct cpufreq_frequency_table *mali_freq_table = NULL;
104 #ifdef CONFIG_MALI_MIDGARD_DVFS
106 /** mali_dvfs_status_t. */
107 typedef struct _mali_dvfs_status_type {
108 struct kbase_device *kbdev;
110 * .DP : current_dvfs_level : 当前使用的 mali_dvfs_level 在 mali_dvfs_level_table 中的 index.
111 * 参见 mali_dvfs_infotbl.
114 /** 最新的 由 metrics_system 报告的 current_calculated_utilisation. */
116 /** 最近一次完成的 temperature_record_section 记录得到的温度数据. */
118 /** 当前 temperature_record_section 中, 已经记录温度的次数. */
119 u32 temperature_time;
120 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
122 * gpu_freq_upper_limit, 即 dvfs_level_upper_limit.
123 * 量纲是 index of mali_dvfs_level_table.
124 * 若是 -1, 则表示当前未设置 dvfs_level_upper_limit.
128 * gpu_freq_lower_limit, 即 dvfs_level_lower_limit.
129 * 量纲是 index of mali_dvfs_level_table.
130 * 若是 -1, 则表示当前未设置 dvfs_level_lower_limit.
137 static struct workqueue_struct *mali_dvfs_wq = 0;
140 * 用来在并发环境下, 保护 mali_dvfs_status_current 等数据.
142 spinlock_t mali_dvfs_spinlock;
143 struct mutex mali_set_clock_lock;
144 struct mutex mali_enable_clock_lock;
146 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
147 static void update_time_in_state(int level);
149 /* .DP : current_mali_dvfs_status. */
150 static mali_dvfs_status mali_dvfs_status_current;
153 #define LIMIT_FPS_POWER_SAVE 50
155 /*---------------------------------------------------------------------------*/
156 #ifdef CONFIG_MALI_MIDGARD_DVFS
157 static void gpufreq_input_event(struct input_handle *handle, unsigned int type,
158 unsigned int code, int value)
160 mali_dvfs_status *dvfs_status;
161 struct rk_context *platform;
167 dvfs_status = &mali_dvfs_status_current;
168 platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
170 spin_lock_irqsave(&platform->gpu_in_touch_lock, flags);
171 /* 有 input_event 到来, 设置对应标识. */
172 platform->gpu_in_touch = true;
173 spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags);
176 static int gpufreq_input_connect(struct input_handler *handler,
177 struct input_dev *dev, const struct input_device_id *id)
179 struct input_handle *handle; // 用于关联 'dev' 和 'handler'.
182 handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
186 handle->dev = dev; // 'handle' 关联的 input_dev.
187 handle->handler = handler;
188 handle->name = "gpufreq";
190 error = input_register_handle(handle);
194 error = input_open_device(handle);
197 pr_info("%s\n",__func__);
201 input_unregister_handle(handle);
207 static void gpufreq_input_disconnect(struct input_handle *handle)
209 input_close_device(handle);
210 input_unregister_handle(handle);
212 pr_info("%s\n",__func__);
216 * 待处理(关联) 的 input_device_ids_table.
218 static const struct input_device_id gpufreq_ids[] = {
220 .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
221 INPUT_DEVICE_ID_MATCH_ABSBIT,
222 .evbit = { BIT_MASK(EV_ABS) },
223 .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] =
224 BIT_MASK(ABS_MT_POSITION_X) |
225 BIT_MASK(ABS_MT_POSITION_Y) },
228 .flags = INPUT_DEVICE_ID_MATCH_KEYBIT |
229 INPUT_DEVICE_ID_MATCH_ABSBIT,
230 .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
231 .absbit = { [BIT_WORD(ABS_X)] =
232 BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
237 static struct input_handler gpufreq_input_handler = {
238 .event = gpufreq_input_event,
239 .connect = gpufreq_input_connect,
240 .disconnect = gpufreq_input_disconnect,
242 .id_table = gpufreq_ids,
245 /*---------------------------------------------------------------------------*/
248 * mali_dvfs_work 的实现主体, 即对 dvfs_event 的处理流程的主体函数.
250 static void mali_dvfs_event_proc(struct work_struct *w)
253 mali_dvfs_status *dvfs_status;
255 static int level_down_time = 0; // counter_of_requests_to_jump_down_in_dvfs_level_table :
256 // 对 mali_dvfs_level 下跳 请求 发生的次数的静态计数.
257 static int level_up_time = 0; // counter_of_requests_to_jump_up_in_dvfs_level_table :
258 // 对 mali_dvfs_level 上跳 请求发生的次数的静态计数.
260 struct rk_context *platform;
261 u32 fps = 0; // real_fps.
264 mutex_lock(&mali_enable_clock_lock);
265 dvfs_status = &mali_dvfs_status_current;
267 if (!kbase_platform_dvfs_get_enable_status()) {
268 mutex_unlock(&mali_enable_clock_lock);
271 platform = (struct rk_context *)dvfs_status->kbdev->platform_context;
273 fps = rk_get_real_fps(0);
275 dvfs_status->temperature_time++;
277 temp_tmp += rockchip_tsadc_get_temp(1); // .Q : 获取当前温度? "1" : 意义? 指定特定的测试通道?
279 if(dvfs_status->temperature_time >= gpu_temp_statis_time) {
280 dvfs_status->temperature_time = 0;
281 dvfs_status->temperature = temp_tmp / gpu_temp_statis_time;
285 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
287 policy = rockchip_pm_get_policy();
289 policy = ROCKCHIP_PM_POLICY_NORMAL;
291 if (ROCKCHIP_PM_POLICY_PERFORMANCE == policy) {
292 dvfs_status->step = MALI_DVFS_STEP - 1;
294 fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE;
295 V("policy : %d , fps_limit = %d", policy, fps_limit);
297 /*give priority to temperature unless in performance mode */
298 if (dvfs_status->temperature > gpu_temp_limit) // 若记录的 gpu 温度 超过了 上限, 则 ...
300 if(dvfs_status->step > 0)
303 if(gpu_temp_statis_time > 1)
304 dvfs_status->temperature = 0;
306 pr_info("decrease step for temperature over %d,next clock = %d\n",
307 gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock);
309 V("jump down in dvfs_level_table to level '%d', for temperature over %d, next clock = %d",
312 mali_dvfs_infotbl[dvfs_status->step].clock);
314 // 若 current_calculated_utilisation 要求 上调 mali_dvfs_level,
315 // 且 current_dvfs_level 还可能被上调,
316 // 且 real_fps "小于" fps_limit,
318 else if ( (dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold)
319 && (dvfs_status->step < MALI_DVFS_STEP - 1)
322 // 至此, 可认为一次请求 mali_dvfs_level 上跳 发生.
326 /* 若 上跳请求的次数 达到 执行具体上跳 要求, 则... */
327 if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL)
329 V("to jump up in dvfs_level_table, utilisation=%d, current clock=%d, fps = %d, temperature = %d",
330 dvfs_status->utilisation,
331 mali_dvfs_infotbl[dvfs_status->step].clock,
333 dvfs_status->temperature);
334 /* 预置 current_dvfs_level 上跳. */ // 具体生效将在最后.
339 V(" next clock=%d.", mali_dvfs_infotbl[dvfs_status->step].clock);
340 BUG_ON(dvfs_status->step >= MALI_DVFS_STEP); // 数组中元素的 index 总是比 size 小.
346 /* 否则, 若 current_calculated_utilisation 要求 current_dvfs_level 下跳, 且 还可以下跳, 则... */
347 else if ((dvfs_status->step > 0)
348 && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold))
352 if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL)
354 V("to jump down in dvfs_level_table ,utilisation=%d, current clock=%d, fps = %d, temperature = %d",
355 dvfs_status->utilisation,
356 mali_dvfs_infotbl[dvfs_status->step].clock,
358 dvfs_status->temperature);
360 BUG_ON(dvfs_status->step <= 0);
364 V(" next clock=%d",mali_dvfs_infotbl[dvfs_status->step].clock);
375 V("keep current_dvfs_level, utilisation=%d,current clock=%d,fps = %d,temperature = %d\n",
376 dvfs_status->utilisation,
377 mali_dvfs_infotbl[dvfs_status->step].clock,
379 dvfs_status->temperature);
382 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
383 // #error // 目前配置下, 本段代码有效.
385 // 若 指定了 dvfs_level_upper_limit,
386 // 且 预置的 current_dvfs_level "大于" dvfs_level_upper_limit,
388 if ((dvfs_status->upper_lock >= 0)
389 && (dvfs_status->step > dvfs_status->upper_lock))
391 /* 将 预置的 current_dvfs_level 调整到 dvfs_level_upper_limit. */
392 dvfs_status->step = dvfs_status->upper_lock;
395 if (dvfs_status->under_lock > 0) {
396 if (dvfs_status->step < dvfs_status->under_lock)
397 dvfs_status->step = dvfs_status->under_lock;
400 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
401 /* 将命令 dvfs_module 让 current_dvfs_level 具体生效. */
402 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
404 mutex_unlock(&mali_enable_clock_lock);
408 * mali_dvfs_work : 处理来自 kbase_platform_dvfs_event 的 dvfs_event 的 work.
410 static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
413 /* ############################################################################################# */
414 // callback_interface_to_common_parts_in_mdd
417 * 由 common_parts_in_mdd 调用的, 将 dvfs_event (utilisation_report_event) 通知回调到 platform_dependent_part_in_mdd.
419 int kbase_platform_dvfs_event(struct kbase_device *kbdev,
420 u32 utilisation, // current_calculated_utilisation
421 u32 util_gl_share_no_use,
422 u32 util_cl_share_no_use[2] )
425 struct rk_context *platform;
428 platform = (struct rk_context *)kbdev->platform_context;
430 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
431 if (platform->time_tick < MALI_DVFS_UP_TIME_INTERVAL) {
432 platform->time_tick++;
433 platform->time_busy += kbdev->pm.backend.metrics.time_busy;
435 platform->time_idle += kbdev->pm.backend.metrics.time_idle;
437 platform->time_busy = kbdev->pm.backend.metrics.time_busy;
438 platform->time_idle = kbdev->pm.backend.metrics.time_idle;
439 platform->time_tick = 0;
442 if ((platform->time_tick == MALI_DVFS_UP_TIME_INTERVAL) &&
443 (platform->time_idle + platform->time_busy > 0))
444 platform->utilisation = (100 * platform->time_busy) /
445 (platform->time_idle + platform->time_busy);
447 /* 记录 current_calculated_utilisation. */
448 mali_dvfs_status_current.utilisation = utilisation;
449 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
451 /* 要求在 cpu_0 上, 使用 workqueue mali_dvfs_wq, 执行 mali_dvfs_work. */
452 queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
453 /*add error handle here */
456 /* ############################################################################################# */
458 int kbase_platform_dvfs_get_utilisation(void)
463 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
464 utilisation = mali_dvfs_status_current.utilisation;
465 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
470 int kbase_platform_dvfs_get_enable_status(void)
472 struct kbase_device *kbdev;
476 kbdev = mali_dvfs_status_current.kbdev;
477 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
478 enable = kbdev->pm.backend.metrics.timer_active;
479 spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
484 int kbase_platform_dvfs_enable(bool enable, int freq)
486 mali_dvfs_status *dvfs_status;
487 struct kbase_device *kbdev;
489 struct rk_context *platform;
491 dvfs_status = &mali_dvfs_status_current;
492 kbdev = mali_dvfs_status_current.kbdev;
494 BUG_ON(kbdev == NULL);
495 platform = (struct rk_context *)kbdev->platform_context;
497 mutex_lock(&mali_enable_clock_lock);
499 if (enable != kbdev->pm.backend.metrics.timer_active) {
500 /* 若要 使能 dvfs, 则... */
502 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
503 kbdev->pm.backend.metrics.timer_active = MALI_TRUE;
504 spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
505 hrtimer_start(&kbdev->pm.backend.metrics.timer,
506 HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
509 /* 否则, 即要 disable dvfs, 则 ... */
511 spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
512 kbdev->pm.backend.metrics.timer_active = MALI_FALSE;
513 spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
514 hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
518 if (freq != MALI_DVFS_CURRENT_FREQ) {
519 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
520 platform->time_tick = 0;
521 platform->time_busy = 0;
522 platform->time_idle = 0;
523 platform->utilisation = 0;
524 dvfs_status->step = kbase_platform_dvfs_get_level(freq);
525 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
526 kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
529 mutex_unlock(&mali_enable_clock_lock);
535 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10))
537 * 为 'mali_dvfs_info' 中 index 是 'level' 的 level_item, 计算 min_threshold 和 max_threshold.
539 static bool calculate_dvfs_max_min_threshold(u32 level)
544 if ((MALI_DVFS_STEP-1) == level) {
545 mali_dvfs_infotbl[level].min_threshold = level0_min;
546 mali_dvfs_infotbl[level].max_threshold = levelf_max;
548 mali_dvfs_infotbl[level].min_threshold = level0_min;
549 mali_dvfs_infotbl[level].max_threshold = level0_max;
552 pre_level = level - 1;
553 if ((MALI_DVFS_STEP-1) == level) {
554 mali_dvfs_infotbl[level].max_threshold = levelf_max;
556 mali_dvfs_infotbl[level].max_threshold = mali_dvfs_infotbl[pre_level].max_threshold +
559 mali_dvfs_infotbl[level].min_threshold = (mali_dvfs_infotbl[pre_level].max_threshold *
560 (mali_dvfs_infotbl[pre_level].clock/1000)) /
561 (mali_dvfs_infotbl[level].clock/1000);
563 tmp = mali_dvfs_infotbl[level].max_threshold - mali_dvfs_infotbl[level].min_threshold;
565 mali_dvfs_infotbl[level].min_threshold += fix_float(tmp);
568 pr_info("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n",
569 level,mali_dvfs_infotbl[level].clock, mali_dvfs_infotbl[level].min_threshold,
570 mali_dvfs_infotbl[level].max_threshold);
575 int kbase_platform_dvfs_init(struct kbase_device *kbdev)
579 add here with the right function to get initilization value.
581 struct rk_context *platform;
585 platform = (struct rk_context *)kbdev->platform_context;
586 if (NULL == platform)
589 D("to get gpu_clk_freq_table from system_dvfs_module.");
590 mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node);
591 if (mali_freq_table == NULL) {
592 printk("mali freq table not assigned yet,use default\n");
595 D("we got valid gpu_clk_freq_table, to init mali_dvfs_level_table with it.");
601 mali_freq_table[i].frequency != CPUFREQ_TABLE_END
602 && i < MAX_NUM_OF_MALI_DVFS_LEVELS;
605 mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency;
609 if(MALI_DVFS_STEP > 1)
610 div_dvfs = round_up( ( (levelf_max - level0_max) / (MALI_DVFS_STEP - 1) ), 1);
612 printk("MALI_DVFS_STEP = %d, div_dvfs = %d \n",MALI_DVFS_STEP, div_dvfs);
614 for(i=0;i<MALI_DVFS_STEP;i++)
615 calculate_dvfs_max_min_threshold(i);
617 p_mali_dvfs_infotbl = mali_dvfs_infotbl;
622 mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
624 spin_lock_init(&mali_dvfs_spinlock);
625 mutex_init(&mali_set_clock_lock);
626 mutex_init(&mali_enable_clock_lock);
628 /*add a error handling here */
629 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
630 mali_dvfs_status_current.kbdev = kbdev;
631 mali_dvfs_status_current.utilisation = 0;
632 mali_dvfs_status_current.step = 0;
633 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
634 mali_dvfs_status_current.upper_lock = -1; // 初始时, 未设置.
635 mali_dvfs_status_current.under_lock = -1;
637 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
639 spin_lock_init(&platform->gpu_in_touch_lock);
640 rc = input_register_handler(&gpufreq_input_handler);
643 E("fail to register gpufreq_input_handler.");
649 void kbase_platform_dvfs_term(void)
652 destroy_workqueue(mali_dvfs_wq);
656 input_unregister_handler(&gpufreq_input_handler);
658 #endif /*CONFIG_MALI_MIDGARD_DVFS*/
660 int mali_get_dvfs_upper_locked_freq(void)
663 int gpu_clk_freq = -1; // gpu_clk_freq_of_upper_limit
665 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
666 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
667 if (mali_dvfs_status_current.upper_lock >= 0)
669 gpu_clk_freq = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
671 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
676 int mali_get_dvfs_under_locked_freq(void)
679 int gpu_clk_freq = -1; // gpu_clk_freq_of_upper_limit
681 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
682 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
683 if (mali_dvfs_status_current.under_lock >= 0)
685 gpu_clk_freq = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
687 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
692 int mali_get_dvfs_current_level(void)
695 int current_level = -1;
697 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
698 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
699 current_level = mali_dvfs_status_current.step;
700 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
702 return current_level;
705 int mali_dvfs_freq_lock(int level)
708 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
709 /*-----------------------------------*/
710 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
712 if (mali_dvfs_status_current.under_lock >= 0
713 && mali_dvfs_status_current.under_lock > level)
715 printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n");
716 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
720 V("to set current dvfs_upper_lock to level '%d'.", level);
721 mali_dvfs_status_current.upper_lock = level;
723 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
724 /*-----------------------------------*/
726 printk(KERN_DEBUG " Upper Lock Set : %d\n", level);
731 void mali_dvfs_freq_unlock(void)
734 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
735 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
736 mali_dvfs_status_current.upper_lock = -1;
737 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
739 printk(KERN_DEBUG "mali Upper Lock Unset\n");
742 int mali_dvfs_freq_under_lock(int level)
745 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
746 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
747 if (mali_dvfs_status_current.upper_lock >= 0 &&
748 mali_dvfs_status_current.upper_lock < level) {
749 printk(KERN_ERR "mali Under lock Error : Attempting to set under lock to above upper lock\n");
750 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
753 mali_dvfs_status_current.under_lock = level;
754 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
756 printk(KERN_DEBUG "mali Under Lock Set : %d\n", level);
761 void mali_dvfs_freq_under_unlock(void)
764 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
765 spin_lock_irqsave(&mali_dvfs_spinlock, flags);
766 mali_dvfs_status_current.under_lock = -1;
767 spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
769 printk(KERN_DEBUG " mali clock Under Lock Unset\n");
772 void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq)
774 struct rk_context *platform;
779 platform = (struct rk_context *)kbdev->platform_context;
780 if (NULL == platform)
783 if (!platform->mali_clk_node) {
784 printk("mali_clk_node not init\n");
787 /* .KP : 将调用平台特定接口, 设置 gpu_clk. */
788 mali_dvfs_clk_set(platform->mali_clk_node,freq);
793 int kbase_platform_dvfs_get_level(int freq)
796 for (i = 0; i < MALI_DVFS_STEP; i++) {
797 if (mali_dvfs_infotbl[i].clock == freq)
803 void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level)
805 static int prev_level = -1;
807 if (level == prev_level)
810 if (WARN_ON((level >= MALI_DVFS_STEP) || (level < 0))) {
811 printk("unkown mali dvfs level:level = %d,set clock not done \n",level);
814 /*panic("invalid level");*/
815 #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK
816 if (mali_dvfs_status_current.upper_lock >= 0 &&
817 level > mali_dvfs_status_current.upper_lock)
818 level = mali_dvfs_status_current.upper_lock;
819 if (mali_dvfs_status_current.under_lock >= 0 &&
820 level < mali_dvfs_status_current.under_lock)
821 level = mali_dvfs_status_current.under_lock;
823 #ifdef CONFIG_MALI_MIDGARD_DVFS
824 mutex_lock(&mali_set_clock_lock);
827 /* 令 mali_dvfs_status_current 的 current_dvfs_level 的具体时钟配置生效. */
828 kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
829 #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS)
830 // 将实际退出 prev_level, update mali_dvfs_level_table 中 prev_level 的 total_time_in_this_level.
831 update_time_in_state(prev_level);
834 #ifdef CONFIG_MALI_MIDGARD_DVFS
835 mutex_unlock(&mali_set_clock_lock);
839 #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS
840 #ifdef CONFIG_MALI_MIDGARD_DVFS
841 static u64 prev_time = 0;
843 * update mali_dvfs_level_table 中当前 dvfs_level 'level' 的 total_time_in_this_level.
845 static void update_time_in_state(int level)
853 /* 若当前 mali_dvfs "未开启", 则... */
854 if (!kbase_platform_dvfs_get_enable_status())
861 prev_time=get_jiffies_64();
863 current_time = get_jiffies_64();
864 mali_dvfs_infotbl[level].time += current_time - prev_time;
866 prev_time = current_time;
870 ssize_t show_time_in_state(struct device *dev,
871 struct device_attribute *attr,
874 struct kbase_device *kbdev;
878 kbdev = dev_get_drvdata(dev);
880 #ifdef CONFIG_MALI_MIDGARD_DVFS
881 update_time_in_state(mali_dvfs_status_current.step);
888 ret += snprintf(buf + ret,
890 "------------------------------------------------------------------------------");
891 ret += snprintf(buf + ret,
893 "\n%-16s\t%-24s\t%-24s",
895 "gpu_clk_freq (KHz)",
896 "time_in_this_level (s)");
897 ret += snprintf(buf + ret,
899 "\n------------------------------------------------------------------------------");
901 for ( i = 0; i < MALI_DVFS_STEP; i++ )
903 ret += snprintf(buf + ret,
905 "\n%-16d\t%-24u\t%-24u",
907 mali_dvfs_infotbl[i].clock / 1000,
908 jiffies_to_msecs(mali_dvfs_infotbl[i].time) / 1000);
910 ret += snprintf(buf + ret,
912 "\n------------------------------------------------------------------------------");
914 if (ret < PAGE_SIZE - 1)
915 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
917 buf[PAGE_SIZE - 2] = '\n';
918 buf[PAGE_SIZE - 1] = '\0';
925 ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr,
926 const char *buf, size_t count)
930 /* reset 所有 level 的 total_time_in_this_level. */
931 for (i = 0; i < MALI_DVFS_STEP; i++)
933 mali_dvfs_infotbl[i].time = 0;
938 printk(KERN_DEBUG "time_in_state value is reset complete.\n");