From: chenzhen Date: Wed, 12 Aug 2015 09:54:35 +0000 (+0800) Subject: rk3288_mali_t760_driver_r6p0-02rel0_13_x@0 X-Git-Tag: firefly_0821_release~3850 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=1075a28e369596f902a832a5e4fe2ce0abcccbd0;p=firefly-linux-kernel-4.4.55.git rk3288_mali_t760_driver_r6p0-02rel0_13_x@0 --- diff --git a/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h b/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h index ce5d0703911c..bd48ed96e962 100644 --- a/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h +++ b/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h @@ -162,7 +162,8 @@ enum { /* * Default period for DVFS sampling */ -#define DEFAULT_PM_DVFS_PERIOD 100 /* 100ms */ +// #define DEFAULT_PM_DVFS_PERIOD 100 /* 100ms */ +#define DEFAULT_PM_DVFS_PERIOD 20 /* 20 ms */ /* * Power Management poweroff tick granuality. This is in nanoseconds to diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c index e0ad7f7872b6..1285ec7970a0 100644 --- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c +++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c @@ -104,7 +104,7 @@ EXPORT_SYMBOL(shared_kernel_test_data); #define KBASE_DRV_NAME "mali" /** rk_ext : version of rk_ext on mali_ko, aka. rk_ko_ver. */ -#define ROCKCHIP_VERSION (12) +#define ROCKCHIP_VERSION (13) static const char kbase_drv_name[] = KBASE_DRV_NAME; diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_platform.h b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_platform.h index 992434bec2ff..7def683e74fa 100644 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_platform.h +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_platform.h @@ -13,7 +13,12 @@ * */ - +/** + * @file mali_kbase_config_platform.h + * 声明 platform_config_of_rk (platform_rk 的 platform_config). + * + * 参见 文档 'mali_midgard_ddk_r6p0_integration_manual_DIT0023P_en' 中的 3.4.1. + */ /** * Maximum frequency diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c index 1a342bc9e454..68125f97e37c 100755 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c @@ -28,6 +28,16 @@ #include #include #include +/** + * @file mali_kbase_config_rk.c + * 对 platform_config_of_rk 的具体实现. + * + * mali_device_driver 包含两部分 : + * .DP : platform_dependent_part_in_mdd : 依赖 platform 部分, 源码在 /platform/ 目录下. + * 在 mali_device_driver 内部, 记为 platform_dependent_part. + * .DP : common_parts_in_mdd : arm 实现的通用的部分, 源码在 目录下. + * 在 mali_device_driver 内部, 记为 common_parts. + */ int get_cpu_clock_speed(u32 *cpu_clock); @@ -155,6 +165,7 @@ int kbase_platform_rk_init(struct kbase_device *kbdev) E("fail to register pm_notifier."); return -1; } + pr_info("%s,register_reboot_notifier\n",__func__); register_reboot_notifier(&mali_reboot_notifier); return 0; @@ -191,19 +202,30 @@ static int pm_callback_power_on(struct kbase_device *kbdev) struct rk_context *platform; platform = (struct rk_context *)kbdev->platform_context; + /* 若 mali_device 是 suspended 的, 则... */ if (pm_runtime_status_suspended(dev)) + { + /* 预置返回 1, 表征 gpu_state 可能已经 lost 了. */ ret_val = 1; + } else + { ret_val = 0; + } if(dev->power.disable_depth > 0) { if(platform->cmu_pmu_status == 0) + { + /* 使能 gpu_power_domain 和 clk_of_gpu_dvfs_node. */ kbase_platform_cmu_pmu_control(kbdev, 1); + } return ret_val; } + result = pm_runtime_resume(dev); - if (result < 0 && result == -EAGAIN) + // if (result < 0 && result == -EAGAIN) + if ( -EAGAIN == result ) kbase_platform_cmu_pmu_control(kbdev, 1); else if (result < 0) printk(KERN_ERR "pm_runtime_get_sync failed (%d)\n", result); @@ -220,6 +242,7 @@ static void pm_callback_power_off(struct kbase_device *kbdev) int kbase_device_runtime_init(struct kbase_device *kbdev) { pm_suspend_ignore_children(kbdev->dev, true); + /* 对 mali_device 使能 runtime_pm. */ pm_runtime_enable(kbdev->dev); #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS if (kbase_platform_create_sysfs_file(kbdev->dev)) diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.c index c2f0522c7c88..13cd2dd7ea5f 100755 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.c +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.c @@ -1,6 +1,6 @@ /* drivers/gpu/t6xx/kbase/src/platform/manta/mali_kbase_dvfs.c - * - * + * + * * Rockchip SoC Mali-T764 DVFS driver * * This program is free software; you can redistribute it and/or modify @@ -13,6 +13,9 @@ * DVFS */ +// #define ENABLE_DEBUG_LOG +#include "custom_log.h" + #include #include #include @@ -51,41 +54,91 @@ /* This table and variable are using the check time share of GPU Clock */ /***********************************************************/ extern int rockchip_tsadc_get_temp(int chn); +/** gpu 温度上限. */ #define gpu_temp_limit 110 +/** 经过 gpu_temp_statis_time 次测量记录之后, 对温度数据取平均. */ #define gpu_temp_statis_time 1 + #define level0_min 0 #define level0_max 70 #define levelf_max 100 + static u32 div_dvfs = 0 ; +/** + * .DP : mali_dvfs_level_table. + * 其中的 level_items 的 gpu_clk_freq 从低到高. + * + * 运行时初始化阶段, 将从 'mali_freq_table' 进行运行时初始化, + * 若获取 'mali_freq_table' 失败, 则使用这里的 缺省配置. + * 参见 kbase_platform_dvfs_init. + */ static mali_dvfs_info mali_dvfs_infotbl[] = { - {925000, 100000, 0, 70, 0}, - {925000, 160000, 50, 65, 0}, - {1025000, 266000, 60, 78, 0}, - {1075000, 350000, 65, 75, 0}, - {1125000, 400000, 70, 75, 0}, - {1200000, 500000, 90, 100, 0}, + {925000, 100000, 0, 70, 0}, + {925000, 160000, 50, 65, 0}, + {1025000, 266000, 60, 78, 0}, + {1075000, 350000, 65, 75, 0}, + {1125000, 400000, 70, 75, 0}, + {1200000, 500000, 90, 100, 0}, }; +/** + * pointer_to_mali_dvfs_level_table. + */ mali_dvfs_info *p_mali_dvfs_infotbl = NULL; +/** + * num_of_mali_dvfs_levels : mali_dvfs_level_table 中有效的 level_item 的数量. + */ unsigned int MALI_DVFS_STEP = ARRAY_SIZE(mali_dvfs_infotbl); +/** + * mali_dvfs_level_table 中可以容纳的 level_items 的最大数量. + */ +const unsigned int MAX_NUM_OF_MALI_DVFS_LEVELS = ARRAY_SIZE(mali_dvfs_infotbl); + +/** + * gpu_clk_freq_table_from_system_dvfs_module, 从 system_dvfs_module 得到的 gpu_clk 的 频点表. + * 原始的 频点配置信息在 .dts 文件中. + */ static struct cpufreq_frequency_table *mali_freq_table = NULL; #ifdef CONFIG_MALI_MIDGARD_DVFS + +/** mali_dvfs_status_t. */ typedef struct _mali_dvfs_status_type { struct kbase_device *kbdev; + /** + * .DP : current_dvfs_level : 当前使用的 mali_dvfs_level 在 mali_dvfs_level_table 中的 index. + * 参见 mali_dvfs_infotbl. + */ int step; + /** 最新的 由 metrics_system 报告的 current_calculated_utilisation. */ int utilisation; + /** 最近一次完成的 temperature_record_section 记录得到的温度数据. */ u32 temperature; + /** 当前 temperature_record_section 中, 已经记录温度的次数. */ u32 temperature_time; #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK + /** + * gpu_freq_upper_limit, 即 dvfs_level_upper_limit. + * 量纲是 index of mali_dvfs_level_table. + * 若是 -1, 则表示当前未设置 dvfs_level_upper_limit. + */ int upper_lock; + /** + * gpu_freq_lower_limit, 即 dvfs_level_lower_limit. + * 量纲是 index of mali_dvfs_level_table. + * 若是 -1, 则表示当前未设置 dvfs_level_lower_limit. + */ int under_lock; #endif } mali_dvfs_status; static struct workqueue_struct *mali_dvfs_wq = 0; + +/** + * 用来在并发环境下, 保护 mali_dvfs_status_current 等数据. + */ spinlock_t mali_dvfs_spinlock; struct mutex mali_set_clock_lock; struct mutex mali_enable_clock_lock; @@ -93,12 +146,13 @@ struct mutex mali_enable_clock_lock; #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS static void update_time_in_state(int level); #endif -/*dvfs status*/ +/* .DP : current_mali_dvfs_status. */ static mali_dvfs_status mali_dvfs_status_current; #define LIMIT_FPS 60 #define LIMIT_FPS_POWER_SAVE 50 +/*---------------------------------------------------------------------------*/ #ifdef CONFIG_MALI_MIDGARD_DVFS static void gpufreq_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) @@ -114,6 +168,7 @@ static void gpufreq_input_event(struct input_handle *handle, unsigned int type, platform = (struct rk_context *)dvfs_status->kbdev->platform_context; spin_lock_irqsave(&platform->gpu_in_touch_lock, flags); + /* 有 input_event 到来, 设置对应标识. */ platform->gpu_in_touch = true; spin_unlock_irqrestore(&platform->gpu_in_touch_lock, flags); } @@ -121,14 +176,14 @@ static void gpufreq_input_event(struct input_handle *handle, unsigned int type, static int gpufreq_input_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { - struct input_handle *handle; + struct input_handle *handle; // 用于关联 'dev' 和 'handler'. int error; handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); if (!handle) return -ENOMEM; - handle->dev = dev; + handle->dev = dev; // 'handle' 关联的 input_dev. handle->handler = handler; handle->name = "gpufreq"; @@ -141,6 +196,7 @@ static int gpufreq_input_connect(struct input_handler *handler, goto err1; pr_info("%s\n",__func__); return 0; + err1: input_unregister_handle(handle); err2: @@ -156,6 +212,9 @@ static void gpufreq_input_disconnect(struct input_handle *handle) pr_info("%s\n",__func__); } +/** + * 待处理(关联) 的 input_device_ids_table. + */ static const struct input_device_id gpufreq_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | @@ -183,16 +242,23 @@ static struct input_handler gpufreq_input_handler = { .id_table = gpufreq_ids, }; #endif +/*---------------------------------------------------------------------------*/ +/** + * mali_dvfs_work 的实现主体, 即对 dvfs_event 的处理流程的主体函数. + */ static void mali_dvfs_event_proc(struct work_struct *w) { unsigned long flags; mali_dvfs_status *dvfs_status; - static int level_down_time = 0; - static int level_up_time = 0; + + static int level_down_time = 0; // counter_of_requests_to_jump_down_in_dvfs_level_table : + // 对 mali_dvfs_level 下跳 请求 发生的次数的静态计数. + static int level_up_time = 0; // counter_of_requests_to_jump_up_in_dvfs_level_table : + // 对 mali_dvfs_level 上跳 请求发生的次数的静态计数. static u32 temp_tmp; struct rk_context *platform; - u32 fps=0; + u32 fps = 0; // real_fps. u32 fps_limit; u32 policy; mutex_lock(&mali_enable_clock_lock); @@ -207,9 +273,9 @@ static void mali_dvfs_event_proc(struct work_struct *w) fps = rk_get_real_fps(0); dvfs_status->temperature_time++; - - temp_tmp += rockchip_tsadc_get_temp(1); - + + temp_tmp += rockchip_tsadc_get_temp(1); // .Q : 获取当前温度? "1" : 意义? 指定特定的测试通道? + if(dvfs_status->temperature_time >= gpu_temp_statis_time) { dvfs_status->temperature_time = 0; dvfs_status->temperature = temp_tmp / gpu_temp_statis_time; @@ -226,68 +292,105 @@ static void mali_dvfs_event_proc(struct work_struct *w) dvfs_status->step = MALI_DVFS_STEP - 1; } else { fps_limit = (ROCKCHIP_PM_POLICY_NORMAL == policy)?LIMIT_FPS : LIMIT_FPS_POWER_SAVE; - /* - printk("policy : %d , fps_limit = %d\n",policy,fps_limit); - */ - + V("policy : %d , fps_limit = %d", policy, fps_limit); + /*give priority to temperature unless in performance mode */ - if (dvfs_status->temperature > gpu_temp_limit) { + if (dvfs_status->temperature > gpu_temp_limit) // 若记录的 gpu 温度 超过了 上限, 则 ... + { if(dvfs_status->step > 0) dvfs_status->step--; if(gpu_temp_statis_time > 1) dvfs_status->temperature = 0; /* - pr_info("decrease step for temperature over %d,next clock = %d\n", - gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock); - */ - } else if ((dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) && - (dvfs_status->step < MALI_DVFS_STEP-1) && fps < fps_limit) { + pr_info("decrease step for temperature over %d,next clock = %d\n", + gpu_temp_limit, mali_dvfs_infotbl[dvfs_status->step].clock); + */ + V("jump down in dvfs_level_table to level '%d', for temperature over %d, next clock = %d", + dvfs_status->step, + gpu_temp_limit, + mali_dvfs_infotbl[dvfs_status->step].clock); + } + // 若 current_calculated_utilisation 要求 上调 mali_dvfs_level, + // 且 current_dvfs_level 还可能被上调, + // 且 real_fps "小于" fps_limit, + // 则 .... + else if ( (dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) + && (dvfs_status->step < MALI_DVFS_STEP - 1) + && fps < fps_limit ) + { + // 至此, 可认为一次请求 mali_dvfs_level 上跳 发生. + level_up_time++; - if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL) { - /* - printk("up,utilisation=%d,current clock=%d,fps = %d,temperature = %d", - dvfs_status->utilisation, mali_dvfs_infotbl[dvfs_status->step].clock, - fps,dvfs_status->temperature); - */ + + /* 若 上跳请求的次数 达到 执行具体上跳 要求, 则... */ + if (level_up_time == MALI_DVFS_UP_TIME_INTERVAL) + { + V("to jump up in dvfs_level_table, utilisation=%d, current clock=%d, fps = %d, temperature = %d", + dvfs_status->utilisation, + mali_dvfs_infotbl[dvfs_status->step].clock, + fps, + dvfs_status->temperature); + /* 预置 current_dvfs_level 上跳. */ // 具体生效将在最后. dvfs_status->step++; + /* 清 上跳请求计数. */ level_up_time = 0; - /* - printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock); - */ - BUG_ON(dvfs_status->step >= MALI_DVFS_STEP); + + V(" next clock=%d.", mali_dvfs_infotbl[dvfs_status->step].clock); + BUG_ON(dvfs_status->step >= MALI_DVFS_STEP); // 数组中元素的 index 总是比 size 小. } + + /* 清 下跳请求计数. */ level_down_time = 0; - } else if ((dvfs_status->step > 0) && - (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) { + } + /* 否则, 若 current_calculated_utilisation 要求 current_dvfs_level 下跳, 且 还可以下跳, 则... */ + else if ((dvfs_status->step > 0) + && (dvfs_status->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) + { level_down_time++; - if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL) { - /* - printk("down,utilisation=%d,current clock=%d,fps = %d,temperature = %d", + + if (level_down_time==MALI_DVFS_DOWN_TIME_INTERVAL) + { + V("to jump down in dvfs_level_table ,utilisation=%d, current clock=%d, fps = %d, temperature = %d", dvfs_status->utilisation, - mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature); - */ + mali_dvfs_infotbl[dvfs_status->step].clock, + fps, + dvfs_status->temperature); + BUG_ON(dvfs_status->step <= 0); dvfs_status->step--; level_down_time = 0; - /* - printk(" next clock=%d\n",mali_dvfs_infotbl[dvfs_status->step].clock); - */ + + V(" next clock=%d",mali_dvfs_infotbl[dvfs_status->step].clock); } + level_up_time = 0; - } else { + } + /* 否则, ... */ + else + { level_down_time = 0; level_up_time = 0; - /* - printk("keep,utilisation=%d,current clock=%d,fps = %d,temperature = %d\n", + + V("keep current_dvfs_level, utilisation=%d,current clock=%d,fps = %d,temperature = %d\n", dvfs_status->utilisation, - mali_dvfs_infotbl[dvfs_status->step].clock,fps,dvfs_status->temperature); - */ + mali_dvfs_infotbl[dvfs_status->step].clock, + fps, + dvfs_status->temperature); } } #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK - if ((dvfs_status->upper_lock >= 0) && (dvfs_status->step > dvfs_status->upper_lock)) + // #error // 目前配置下, 本段代码有效. + + // 若 指定了 dvfs_level_upper_limit, + // 且 预置的 current_dvfs_level "大于" dvfs_level_upper_limit, + // 则... + if ((dvfs_status->upper_lock >= 0) + && (dvfs_status->step > dvfs_status->upper_lock)) + { + /* 将 预置的 current_dvfs_level 调整到 dvfs_level_upper_limit. */ dvfs_status->step = dvfs_status->upper_lock; + } if (dvfs_status->under_lock > 0) { if (dvfs_status->step < dvfs_status->under_lock) @@ -295,15 +398,26 @@ static void mali_dvfs_event_proc(struct work_struct *w) } #endif spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); + /* 将命令 dvfs_module 让 current_dvfs_level 具体生效. */ kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step); mutex_unlock(&mali_enable_clock_lock); } +/** + * mali_dvfs_work : 处理来自 kbase_platform_dvfs_event 的 dvfs_event 的 work. + */ static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc); + +/* ############################################################################################# */ +// callback_interface_to_common_parts_in_mdd + +/** + * 由 common_parts_in_mdd 调用的, 将 dvfs_event (utilisation_report_event) 通知回调到 platform_dependent_part_in_mdd. + */ int kbase_platform_dvfs_event(struct kbase_device *kbdev, - u32 utilisation, + u32 utilisation, // current_calculated_utilisation u32 util_gl_share_no_use, u32 util_cl_share_no_use[2] ) { @@ -330,13 +444,16 @@ int kbase_platform_dvfs_event(struct kbase_device *kbdev, platform->utilisation = (100 * platform->time_busy) / (platform->time_idle + platform->time_busy); + /* 记录 current_calculated_utilisation. */ mali_dvfs_status_current.utilisation = utilisation; spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); + /* 要求在 cpu_0 上, 使用 workqueue mali_dvfs_wq, 执行 mali_dvfs_work. */ queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work); /*add error handle here */ return MALI_TRUE; } +/* ############################################################################################# */ int kbase_platform_dvfs_get_utilisation(void) { @@ -380,6 +497,7 @@ int kbase_platform_dvfs_enable(bool enable, int freq) mutex_lock(&mali_enable_clock_lock); if (enable != kbdev->pm.backend.metrics.timer_active) { + /* 若要 使能 dvfs, 则... */ if (enable) { spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); kbdev->pm.backend.metrics.timer_active = MALI_TRUE; @@ -387,7 +505,9 @@ int kbase_platform_dvfs_enable(bool enable, int freq) hrtimer_start(&kbdev->pm.backend.metrics.timer, HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY), HRTIMER_MODE_REL); - } else { + } + /* 否则, 即要 disable dvfs, 则 ... */ + else { spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); kbdev->pm.backend.metrics.timer_active = MALI_FALSE; spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); @@ -404,14 +524,18 @@ int kbase_platform_dvfs_enable(bool enable, int freq) dvfs_status->step = kbase_platform_dvfs_get_level(freq); spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step); - } + } mutex_unlock(&mali_enable_clock_lock); return MALI_TRUE; } + #define dividend 7 #define fix_float(a) ((((a)*dividend)%10)?((((a)*dividend)/10)+1):(((a)*dividend)/10)) +/** + * 为 'mali_dvfs_info' 中 index 是 'level' 的 level_item, 计算 min_threshold 和 max_threshold. + */ static bool calculate_dvfs_max_min_threshold(u32 level) { u32 pre_level; @@ -440,9 +564,11 @@ static bool calculate_dvfs_max_min_threshold(u32 level) mali_dvfs_infotbl[level].min_threshold += fix_float(tmp); } + pr_info("mali_dvfs_infotbl[%d].clock=%d,min_threshold=%d,max_threshold=%d\n", level,mali_dvfs_infotbl[level].clock, mali_dvfs_infotbl[level].min_threshold, mali_dvfs_infotbl[level].max_threshold); + return MALI_TRUE; } @@ -460,26 +586,37 @@ int kbase_platform_dvfs_init(struct kbase_device *kbdev) if (NULL == platform) panic("oops"); + D("to get gpu_clk_freq_table from system_dvfs_module."); mali_freq_table = dvfs_get_freq_volt_table(platform->mali_clk_node); - if (mali_freq_table == NULL) { printk("mali freq table not assigned yet,use default\n"); goto not_assigned ; } else { + D("we got valid gpu_clk_freq_table, to init mali_dvfs_level_table with it."); + /*recalculte step*/ MALI_DVFS_STEP = 0; - for (i = 0; mali_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { + + for ( i = 0; + mali_freq_table[i].frequency != CPUFREQ_TABLE_END + && i < MAX_NUM_OF_MALI_DVFS_LEVELS; + i++ ) + { mali_dvfs_infotbl[i].clock = mali_freq_table[i].frequency; MALI_DVFS_STEP++; } + if(MALI_DVFS_STEP > 1) - div_dvfs = round_up(((levelf_max - level0_max)/(MALI_DVFS_STEP-1)),1); - printk("MALI_DVFS_STEP=%d,div_dvfs=%d\n",MALI_DVFS_STEP,div_dvfs); + div_dvfs = round_up( ( (levelf_max - level0_max) / (MALI_DVFS_STEP - 1) ), 1); + + printk("MALI_DVFS_STEP = %d, div_dvfs = %d \n",MALI_DVFS_STEP, div_dvfs); for(i=0;igpu_in_touch_lock); - rc = input_register_handler(&gpufreq_input_handler); - /*add a error handling here */ spin_lock_irqsave(&mali_dvfs_spinlock, flags); mali_dvfs_status_current.kbdev = kbdev; mali_dvfs_status_current.utilisation = 0; mali_dvfs_status_current.step = 0; #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK - mali_dvfs_status_current.upper_lock = -1; + mali_dvfs_status_current.upper_lock = -1; // 初始时, 未设置. mali_dvfs_status_current.under_lock = -1; #endif - spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); + spin_lock_init(&platform->gpu_in_touch_lock); + rc = input_register_handler(&gpufreq_input_handler); + if ( 0 != rc ) + { + E("fail to register gpufreq_input_handler."); + } + return MALI_TRUE; } @@ -520,29 +660,33 @@ void kbase_platform_dvfs_term(void) int mali_get_dvfs_upper_locked_freq(void) { unsigned long flags; - int locked_level = -1; + int gpu_clk_freq = -1; // gpu_clk_freq_of_upper_limit #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK spin_lock_irqsave(&mali_dvfs_spinlock, flags); if (mali_dvfs_status_current.upper_lock >= 0) - locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock; + { + gpu_clk_freq = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock; + } spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); #endif - return locked_level; + return gpu_clk_freq; } int mali_get_dvfs_under_locked_freq(void) { unsigned long flags; - int locked_level = -1; + int gpu_clk_freq = -1; // gpu_clk_freq_of_upper_limit #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK spin_lock_irqsave(&mali_dvfs_spinlock, flags); if (mali_dvfs_status_current.under_lock >= 0) - locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock; + { + gpu_clk_freq = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock; + } spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); #endif - return locked_level; + return gpu_clk_freq; } int mali_get_dvfs_current_level(void) @@ -562,15 +706,22 @@ int mali_dvfs_freq_lock(int level) { unsigned long flags; #ifdef CONFIG_MALI_MIDGARD_FREQ_LOCK + /*-----------------------------------*/ spin_lock_irqsave(&mali_dvfs_spinlock, flags); - if (mali_dvfs_status_current.under_lock >= 0 && - mali_dvfs_status_current.under_lock > level) { + + if (mali_dvfs_status_current.under_lock >= 0 + && mali_dvfs_status_current.under_lock > level) + { printk(KERN_ERR " Upper lock Error : Attempting to set upper lock to below under lock\n"); spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); return -1; } + + V("to set current dvfs_upper_lock to level '%d'.", level); mali_dvfs_status_current.upper_lock = level; + spin_unlock_irqrestore(&mali_dvfs_spinlock, flags); + /*-----------------------------------*/ printk(KERN_DEBUG " Upper Lock Set : %d\n", level); #endif @@ -633,12 +784,12 @@ void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq) printk("mali_clk_node not init\n"); return; } + /* .KP : 将调用平台特定接口, 设置 gpu_clk. */ mali_dvfs_clk_set(platform->mali_clk_node,freq); return; } - int kbase_platform_dvfs_get_level(int freq) { int i; @@ -648,6 +799,7 @@ int kbase_platform_dvfs_get_level(int freq) } return -1; } + void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level) { static int prev_level = -1; @@ -672,8 +824,10 @@ void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level) mutex_lock(&mali_set_clock_lock); #endif + /* 令 mali_dvfs_status_current 的 current_dvfs_level 的具体时钟配置生效. */ kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock); #if defined(CONFIG_MALI_MIDGARD_DEBUG_SYS) && defined(CONFIG_MALI_MIDGARD_DVFS) + // 将实际退出 prev_level, update mali_dvfs_level_table 中 prev_level 的 total_time_in_this_level. update_time_in_state(prev_level); #endif prev_level = level; @@ -684,29 +838,38 @@ void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level) #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS #ifdef CONFIG_MALI_MIDGARD_DVFS +static u64 prev_time = 0; +/** + * update mali_dvfs_level_table 中当前 dvfs_level 'level' 的 total_time_in_this_level. + */ static void update_time_in_state(int level) { u64 current_time; - static u64 prev_time=0; if (level < 0) return; +#if 0 + /* 若当前 mali_dvfs "未开启", 则... */ if (!kbase_platform_dvfs_get_enable_status()) + { return; + } +#endif if (prev_time ==0) prev_time=get_jiffies_64(); current_time = get_jiffies_64(); - mali_dvfs_infotbl[level].time += current_time-prev_time; + mali_dvfs_infotbl[level].time += current_time - prev_time; prev_time = current_time; } #endif -ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t show_time_in_state(struct device *dev, + struct device_attribute *attr, + char *buf) { struct kbase_device *kbdev; ssize_t ret = 0; @@ -718,12 +881,35 @@ ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, update_time_in_state(mali_dvfs_status_current.step); #endif if (!kbdev) + { return -ENODEV; + } - for (i = 0; i < MALI_DVFS_STEP; i++) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - "%d %llu\n", - mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].time); + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "------------------------------------------------------------------------------"); + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "\n%-16s\t%-24s\t%-24s", + "index_of_level", + "gpu_clk_freq (KHz)", + "time_in_this_level (s)"); + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "\n------------------------------------------------------------------------------"); + + for ( i = 0; i < MALI_DVFS_STEP; i++ ) + { + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "\n%-16d\t%-24u\t%-24u", + i, + mali_dvfs_infotbl[i].clock / 1000, + jiffies_to_msecs(mali_dvfs_infotbl[i].time) / 1000); + } + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "\n------------------------------------------------------------------------------"); if (ret < PAGE_SIZE - 1) ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); @@ -741,8 +927,13 @@ ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, { int i; + /* reset 所有 level 的 total_time_in_this_level. */ for (i = 0; i < MALI_DVFS_STEP; i++) + { mali_dvfs_infotbl[i].time = 0; + } + + prev_time = 0; printk(KERN_DEBUG "time_in_state value is reset complete.\n"); return count; diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.h b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.h index 52167d362cc5..8d885c8e83f2 100755 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.h +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_dvfs.h @@ -10,6 +10,10 @@ /** * @file mali_kbase_dvfs.h * DVFS + * 声明 平台相关的 mali_dvfs_facility 对外提供的接口, 比如初始化, 设置 gpu_clk_freq, ... + * 但这里 并没有 实现良好封装. + * + * .DP : mali_dvfs_facility : platform_dependent_part 中对 mali(gpu) DVFS 功能的具体实现. */ #ifndef _KBASE_DVFS_H_ @@ -19,18 +23,50 @@ #define KBASE_PM_DVFS_FREQUENCY 100 #define MALI_DVFS_KEEP_STAY_CNT 10 + +/** + * 一个门限, 当 counter_of_requests_to_jump_up_in_dvfs_level_table 到达该 value 的时候, + * 才执行具体的将 current_dvfs_level 上跳的操作. + */ #define MALI_DVFS_UP_TIME_INTERVAL 1 + +/** + * 一个门限, 当 counter_of_requests_to_jump_down_in_dvfs_level_table 到达该 value 的时候, + * 才执行具体的将 current_dvfs_level 下跳的操作. + */ #define MALI_DVFS_DOWN_TIME_INTERVAL 2 + +/** + * @see kbase_platform_dvfs_enable. + */ #define MALI_DVFS_CURRENT_FREQ 0 + #if 0 #define MALI_DVFS_BL_CONFIG_FREQ 500 #define MALI_DVFS_START_FREQ 400 #endif + +/** + * mali_dvfs_level_t, 某 mali_dvfs_level (功耗层级) 的具体配置信息. + */ typedef struct _mali_dvfs_info { + /** 使用的电压. .Q : 目前实际不起作用? */ unsigned int voltage; + /** + * gpu_clock_freq. 当前 level 使用的 GPU 时钟频率. 以 KHz 为单位. + */ unsigned int clock; + /** + * 若 current_calculated_utilisation 低于本成员, 将可能下跳到 mali_dvfs_level_table 中, 临近的低功耗 mali_dvfs_level. + */ int min_threshold; + /** + * 若 current_calculated_utilisation 高于本成员, 将可能上跳到 mali_dvfs_level_table 中, 临近的高功耗 mali_dvfs_level. + */ int max_threshold; + /** + * total_time_in_this_level : gpu 停留在当前 level 上的 累计时间. 以 jiffy 为单位. + */ unsigned long long time; } mali_dvfs_info; @@ -41,28 +77,96 @@ extern unsigned int MALI_DVFS_STEP; #define CONFIG_MALI_MIDGARD_FREQ_LOCK #endif +/** + * 将 gpu_clk 设置为 'freq', 'freq' 以 KHz 为单位. + */ void kbase_platform_dvfs_set_clock(struct kbase_device *kbdev, int freq); + +/** + * 命令 dvfs_module 为 gpu 配置 'level' 指定的 dvfs_level, 并具体生效. + * @param level + * 待使用的 mali_dvfs_level 在 mali_dvfs_level_table 中的 index. + */ void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level); + +/** + * 检索 mali_dvfs_level_table, 返回其中 gpu_clock_freq 精确是 'freq' 的 level_item 的 index. + * 若没有找到, 返回 -1. + * 'freq' 以 KHz 为单位. + */ int kbase_platform_dvfs_get_level(int freq); #ifdef CONFIG_MALI_MIDGARD_DVFS +/** + * 初始化 mali_dvfs_facility. + */ int kbase_platform_dvfs_init(struct kbase_device *dev); + +/** + * 中止化 mali_dvfs_facility. + */ void kbase_platform_dvfs_term(void); /*int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation);*/ /*int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation,u32 util_gl_share, u32 util_cl_share[2]);*/ + +/** + * 返回当前 mali_dvfs 是否是开启, 即 common_parts 是否会回调通知 dvfs_event. + */ int kbase_platform_dvfs_get_enable_status(void); + +/** + * 使能或者禁用 dvfs, 并将 gpu_clk 设置为 'freq'(最接近的 允许的 clk). + * 若 'freq' 是 MALI_DVFS_CURRENT_FREQ, 则 "不" 改变当前的 gpu_clk_freq. + */ int kbase_platform_dvfs_enable(bool enable, int freq); + +/** + * 返回 mali(gpu) 当前(最近的) utilisation. + */ int kbase_platform_dvfs_get_utilisation(void); #endif +/** + * 返回 current_dvfs_level 在 mali_dvfs_level_table 中的 index. + */ int mali_get_dvfs_current_level(void); + +/** + * 返回当前 dvfs_level_upper_limit 的 gpu_clk_freq, 以 KHz 为单位. + * 若没有设置, 返回 -1. + */ int mali_get_dvfs_upper_locked_freq(void); +/** + * 返回当前 dvfs_level_lower_limit 的 gpu_clk_freq, 以 KHz 为单位. + * 若没有设置, 返回 -1. + */ int mali_get_dvfs_under_locked_freq(void); + +/** + * 将 'level' 设置为当前的 dvfs_level_upper_limit.. + * 这里用 "freq_lock" 不贴切. + * @return + * 若成功, 返回 0. + * 否则, 返回其他 value. + */ int mali_dvfs_freq_lock(int level); +/** + * 清除当前的 dvfs_level_upper_limit 设置. + */ void mali_dvfs_freq_unlock(void); +/** + * 将 'level' 设置为当前的 dvfs_level_lower_limit. + * @return + * 若成功, 返回 0. + * 否则, 返回其他 value. + */ int mali_dvfs_freq_under_lock(int level); +/** + * 清除当前的 dvfs_level_lower_limit 设置. + */ void mali_dvfs_freq_under_unlock(void); +// @see 'time_in_state' in mali_kbase_platform.c. ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf); ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.c index 340f376332c4..226bddd927c3 100755 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.c +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.c @@ -9,8 +9,10 @@ /** * @file mali_kbase_platform.c - * Platform-dependent init. + * + * 对 mali_kbase_platform.h 声明的 pm, clk 等接口的具体实现. */ + #include #include #include @@ -43,6 +45,7 @@ #include +// #define ENABLE_DEBUG_LOG #include "custom_log.h" /* ############################################################################################# */ @@ -50,13 +53,24 @@ #define MALI_T7XX_DEFAULT_CLOCK 100000 +/** + * clk_of_gpu_dvfs_node 的状态. + * 1, clock 被使能. + * 0, 禁止. + */ static int mali_clk_status = 0; + +/** + * gpu_power_domain 的状态. + * 1, 上电. + * 0, 掉电. + */ static int mali_pd_status = 0; -u32 kbase_group_error = 0; +// u32 kbase_group_error = 0; static struct kobject *rk_gpu; -int mali_dvfs_clk_set(struct dvfs_node *node,unsigned long rate) +int mali_dvfs_clk_set(struct dvfs_node *node, unsigned long rate) { int ret = 0; if(!node) @@ -64,6 +78,7 @@ int mali_dvfs_clk_set(struct dvfs_node *node,unsigned long rate) printk("clk_get_dvfs_node error \r\n"); ret = -1; } + /* .KP : 调用 dvfs_module 设置 gpu_clk. */ ret = dvfs_clk_set_rate(node,rate * MALI_KHZ); if(ret) { @@ -71,6 +86,10 @@ int mali_dvfs_clk_set(struct dvfs_node *node,unsigned long rate) } return ret; } + +/** + * 初始化和 gpu_pm 和 gpu_clk. + */ static int kbase_platform_power_clock_init(struct kbase_device *kbdev) { /*struct device *dev = kbdev->dev;*/ @@ -108,9 +127,9 @@ static int kbase_platform_power_clock_init(struct kbase_device *kbdev) dvfs_clk_prepare_enable(platform->mali_clk_node); printk("clk enabled\n"); } - mali_dvfs_clk_set(platform->mali_clk_node,MALI_T7XX_DEFAULT_CLOCK); - + mali_dvfs_clk_set(platform->mali_clk_node, MALI_T7XX_DEFAULT_CLOCK); mali_clk_status = 1; + return 0; out: @@ -120,6 +139,7 @@ out: return -EPERM; } + int kbase_platform_clock_off(struct kbase_device *kbdev) { struct rk_context *platform; @@ -161,6 +181,7 @@ int kbase_platform_clock_on(struct kbase_device *kbdev) return 0; } + int kbase_platform_is_power_on(void) { return mali_pd_status; @@ -212,6 +233,7 @@ int kbase_platform_power_off(struct kbase_device *kbdev) return 0; } + int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control) { unsigned long flags; @@ -228,33 +250,45 @@ int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control) /* off */ if (control == 0) { + /* 若已经关闭, 则... */ if (platform->cmu_pmu_status == 0) { spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags); return 0; } + /* 关闭 gpu_power_domain. */ if (kbase_platform_power_off(kbdev)) + { panic("failed to turn off mali power domain\n"); + } + /* 关闭 gpu_dvfs_node 的 clock. */ if (kbase_platform_clock_off(kbdev)) + { panic("failed to turn off mali clock\n"); + } platform->cmu_pmu_status = 0; printk("turn off mali power \n"); } - else + else /* on */ { - /* on */ if (platform->cmu_pmu_status == 1) { spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags); return 0; } + /* 开启 gpu_power_domain. */ if (kbase_platform_power_on(kbdev)) + { panic("failed to turn on mali power domain\n"); + } + /* 使能 gpu_dvfs_node 的 clock. */ if (kbase_platform_clock_on(kbdev)) + { panic("failed to turn on mali clock\n"); + } platform->cmu_pmu_status = 1; printk(KERN_ERR "turn on mali power\n"); @@ -265,31 +299,110 @@ int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control) return 0; } +/*---------------------------------------------------------------------------*/ + static ssize_t error_count_show(struct device *dev,struct device_attribute *attr, char *buf) { struct kbase_device *kbdev = dev_get_drvdata(dev); ssize_t ret; - D_PTR(dev); - if ( NULL == kbdev ) - { - E("fail to get kbase_device instance."); - return 0; - } + D_PTR(dev); + if ( NULL == kbdev ) + { + E("fail to get kbase_device instance."); + return 0; + } - D_DEC(kbdev->kbase_group_error); - ret = scnprintf(buf, PAGE_SIZE, "%d\n", kbdev->kbase_group_error); + D_DEC(kbdev->kbase_group_error); + ret = scnprintf(buf, PAGE_SIZE, "%u\n", kbdev->kbase_group_error); return ret; } static DEVICE_ATTR(error_count, S_IRUGO, error_count_show, NULL); + +/*---------------------------------------------------------------------------*/ +/* < 对在 sysfs_dir_of_mali_device 下的 rk_ext_file_nodes 的具体实现, >*/ +// .DP : impl_of_rk_ext_file_nodes. + +/** + * .doc : 对 sysfs_dir_of_mali_device 下 rk_ext_file_nodes 提供的接口的定义 + * + * sysfs_dir_of_mali_device 通常是 sys/devices/ffa30000.gpu + * + * 其下有如下的 rk_ext_file_nodes : + * clock, + * 对该文件的 cat 操作, 将输出当前 gpu_clk_freq 和可能的 freq 的列表, 形如 : + * current_gpu_clk_freq : 99000 KHz + * possible_freqs : 99000, 179000, 297000, 417000, 480000 (KHz) + * 出现在 "possible_freqs" 中的有效频点, 依赖在 .dts 文件中的配置. + * 可以使用 echo 命令向本文件写入待设置的 gpu_clk_freq_in_khz, 比如 : + * echo 417000 > clock + * 注意, 这里写入的 gpu_clk_freq_in_khz "必须" 是出现在 possible_freqs 中的. + * 另外, mali_module 默认使能 dvfs, + * 所以若希望将 gpu_clk 固定在上面的特定 freq, 要关闭 dvfs 先 : + * echo off > dvfs + * fbdev, + * 只支持 cat. + * .R : 目前不确定该提供接口的用意. + * // dtlb, + * dvfs, + * cat 该节点, 将返回当前 mali_dvfs 的状态, 包括 mali_dvfs 是否开启, gpu 使用率, 当前 gpu_clk 频率. + * 若当前 mali_dvfs 被开启, 可能返回如下信息 : + * mali_dvfs is ON + * gpu_utilisation : 100 + * current_gpu_clk_freq : 480 MHz + * 若当前 mali_dvfs 被关闭, 可能返回 : + * mali_dvfs is OFF + * current_gpu_clk_freq : 99 MHz + * 若一段时间没有 job 下发到 gpu, common_parts 也会自动关闭 mali_dvfs. + * + * 将字串 off 写入该节点, 将关闭 mali_dvfs, + * 且会将 gpu_clk_freq 固定到可能的最高的频率 或者 gpu_clk_freq_of_upper_limit(若有指定). + * 之后, 若将字串 on 写入该节点, 将重新开启 mali_dvfs. + * + * dvfs_upper_lock, + * cat 该节点, 返回当前 dvfs_level_upper_limit 的信息, 诸如 + * upper_lock_freq : 417000 KHz + * possible upper_lock_freqs : 99000, 179000, 297000, 417000, 480000 (KHz) + * if you want to unset upper_lock_freq, to echo 'off' to this file. + * + * 对该节点写入上面 possible upper_lock_freqs 中的某个 频率, 可以将该频率设置为 gpu_clk_freq_of_upper_limit, 比如. + * echo 417000 > dvfs_upper_lock + * 若要清除之前设置的 dvfs_level_upper_limit, 写入 off 即可. + * + * dvfs_under_lock, + * cat 该节点, 返回当前 dvfs_level_lower_limit 的信息, 诸如 + * under_lock_freq : 179000 KHz + * possible under_lock_freqs : 99000, 179000, 297000, 417000, 480000 (KHz) + * if you want to unset under_lock_freq, to echo 'off' to this file. + * 对该节点写入上面 possible under_lock_freq 中的某个 频率, 可以将该频率设置为 gpu_clk_freq_of_lower_limit, 比如. + * echo 179000 > dvfs_under_lock + * 若要清除之前设置的 dvfs_level_lower_limit, 写入 off 即可. + * + * time_in_state + * cat 该节点, 返回 mali_dvfs 停留在不同 level 中的时间统计, 譬如 + * ------------------------------------------------------------------------------ + * index_of_level gpu_clk_freq (KHz) time_in_this_level (s) + * ------------------------------------------------------------------------------ + * 0 99 206 + * 1 179 9 + * 2 297 0 + * 3 417 0 + * 4 480 47 + * ------------------------------------------------------------------------------ + * 若通过 dvfs 节点, 开启/关闭 mali_dvfs, 则本节点输出的信息可能不准确. + * + * 若要复位上述时间统计, 可以向该节点写入任意字串, 比如 : + * echo dummy > time_in_state + */ + #ifdef CONFIG_MALI_MIDGARD_DEBUG_SYS static ssize_t show_clock(struct device *dev, struct device_attribute *attr, char *buf) { struct kbase_device *kbdev; struct rk_context *platform; ssize_t ret = 0; - unsigned int clkrate; + unsigned int clkrate = 0; // 从 dvfs_module 获取的 gpu_clk_freq, Hz 为单位. int i ; kbdev = dev_get_drvdata(dev); @@ -306,16 +419,27 @@ static ssize_t show_clock(struct device *dev, struct device_attribute *attr, cha return -ENODEV; } clkrate = dvfs_clk_get_rate(platform->mali_clk_node); - ret += snprintf(buf + ret, PAGE_SIZE - ret, "Current clk mali = %dMhz", clkrate / 1000000); - + ret += snprintf(buf + ret, PAGE_SIZE - ret, "current_gpu_clk_freq : %d KHz", clkrate / 1000); + /* To be revised */ - ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings:"); - for(i=0;ivar.xres, registered_fb[i]->var.yres, registered_fb[i]->fix.smem_start); + { + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "fb[%d] xres=%d, yres=%d, addr=0x%lx\n", + i, + registered_fb[i]->var.xres, + registered_fb[i]->var.yres, + registered_fb[i]->fix.smem_start); + } if (ret < PAGE_SIZE - 1) ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); @@ -611,15 +744,29 @@ static ssize_t show_dvfs(struct device *dev, struct device_attribute *attr, char if (!platform) return -ENODEV; + /* 获取当前 gpu_dvfs_node 的 clk_freq, Hz 为单位. */ clkrate = dvfs_clk_get_rate(platform->mali_clk_node); #ifdef CONFIG_MALI_MIDGARD_DVFS + /* 若 mali_dvfs 是 开启的, 则... */ if (kbase_platform_dvfs_get_enable_status()) - ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is on\nutilisation:%d\ncurrent clock:%dMhz", kbase_platform_dvfs_get_utilisation(),clkrate/1000000); + { + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "mali_dvfs is ON \ngpu_utilisation : %d \ncurrent_gpu_clk_freq : %u MHz", + kbase_platform_dvfs_get_utilisation(), + clkrate / 1000000); + } + /* 否则, ... */ else - ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is off,clock:%dMhz",clkrate/1000000); + { + ret += snprintf(buf + ret, + PAGE_SIZE - ret, + "mali_dvfs is OFF \ncurrent_gpu_clk_freq : %u MHz", + clkrate / 1000000); + } #else - ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali_dvfs is DISABLED"); #endif if (ret < PAGE_SIZE - 1) @@ -647,10 +794,12 @@ static ssize_t set_dvfs(struct device *dev, struct device_attribute *attr, const platform = (struct rk_context *)kbdev->platform_context; if (sysfs_streq("off", buf)) { /*kbase_platform_dvfs_enable(false, MALI_DVFS_BL_CONFIG_FREQ);*/ + D("to disable mali_dvfs, and set current_dvfs_level to the highest one."); kbase_platform_dvfs_enable(false, p_mali_dvfs_infotbl[MALI_DVFS_STEP-1].clock); platform->dvfs_enabled = false; } else if (sysfs_streq("on", buf)) { /*kbase_platform_dvfs_enable(true, MALI_DVFS_START_FREQ);*/ + D("to disable mali_dvfs, and set current_dvfs_level to the lowest one."); kbase_platform_dvfs_enable(true, p_mali_dvfs_infotbl[0].clock); platform->dvfs_enabled = true; } else { @@ -668,27 +817,47 @@ static ssize_t show_upper_lock_dvfs(struct device *dev, struct device_attribute ssize_t ret = 0; int i; #ifdef CONFIG_MALI_MIDGARD_DVFS - int locked_level = -1; + int gpu_clk_freq = 0; #endif kbdev = dev_get_drvdata(dev); if (!kbdev) + { + E("err."); return -ENODEV; + } #ifdef CONFIG_MALI_MIDGARD_DVFS - locked_level = mali_get_dvfs_upper_locked_freq(); - if (locked_level > 0) - ret += snprintf(buf + ret, PAGE_SIZE - ret, "Current Upper Lock Level = %dMhz", locked_level); + gpu_clk_freq = mali_get_dvfs_upper_locked_freq(); + if (gpu_clk_freq > 0) + { + ret += snprintf(buf + ret, PAGE_SIZE - ret, "upper_lock_freq : %d KHz", gpu_clk_freq); + } else - ret += snprintf(buf + ret, PAGE_SIZE - ret, "Unset the Upper Lock Level"); + { + ret += snprintf(buf + ret, PAGE_SIZE - ret, "upper_lock_freq is NOT set"); + } /*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 400, 350,266, 160, 100, If you want to unlock : 600 or off");*/ - ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings :"); - for(i=0;i 0 ) + { + ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nif you want to unset upper_lock_freq, to echo 'off' to this file."); + } #else ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set"); #endif @@ -706,16 +875,18 @@ static ssize_t show_upper_lock_dvfs(struct device *dev, struct device_attribute static ssize_t set_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct kbase_device *kbdev; + struct kbase_device *kbdev = NULL; int i; - unsigned int freq; - kbdev = dev_get_drvdata(dev); - freq = 0; + unsigned int freq = 0; // 可能由 caller 传入的, 待设置的 gpu_freq_upper_limit. + int ret = 0; - if (!kbdev) - return -ENODEV; + kbdev = dev_get_drvdata(dev); -freq = simple_strtoul(buf, NULL, 10); + if ( NULL == kbdev) + { + E("'kbdev' is NULL."); + return -ENODEV; + } #ifdef CONFIG_MALI_MIDGARD_DVFS if (sysfs_streq("off", buf)) @@ -724,20 +895,34 @@ freq = simple_strtoul(buf, NULL, 10); } else { + freq = simple_strtoul(buf, NULL, 10); + D_DEC(freq); + + D("to search the level that matches target_freq; num_of_mali_dvfs_levels : %d.", MALI_DVFS_STEP); for(i=0;i 0) - ret += snprintf(buf + ret, PAGE_SIZE - ret, "Current Under Lock Level = %dMhz", locked_level); + gpu_clk_freq = mali_get_dvfs_under_locked_freq(); + if (gpu_clk_freq > 0) + { + ret += snprintf(buf + ret, PAGE_SIZE - ret, "under_lock_freq : %d KHz",gpu_clk_freq); + } else - ret += snprintf(buf + ret, PAGE_SIZE - ret, "Unset the Under Lock Level"); + { + ret += snprintf(buf + ret, PAGE_SIZE - ret, "under_lock_freq is NOT set."); + } /*ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings : 600, 400, 350,266, 160, If you want to unlock : 100 or off");*/ - ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nPossible settings :"); - for(i=0;i 0 ) + { + ret += snprintf(buf + ret, PAGE_SIZE - ret, "\nif you want to unset under_lock_freq, to echo 'off' to this file."); + } #else ret += snprintf(buf + ret, PAGE_SIZE - ret, "mali DVFS is disabled. You can not set"); #endif @@ -790,35 +991,49 @@ static ssize_t show_under_lock_dvfs(struct device *dev, struct device_attribute static ssize_t set_under_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int i; - unsigned int freq; - struct kbase_device *kbdev; - kbdev = dev_get_drvdata(dev); - freq = 0; + unsigned int freq = 0; + struct kbase_device *kbdev = NULL; + int ret = 0; - if (!kbdev) + kbdev = dev_get_drvdata(dev); + if ( NULL == kbdev) + { + E("err.") return -ENODEV; + } #ifdef CONFIG_MALI_MIDGARD_DVFS if (sysfs_streq("off", buf)) { - mali_dvfs_freq_unlock(); + mali_dvfs_freq_under_unlock(); } else { + freq = simple_strtoul(buf, NULL, 10); + D_DEC(freq); + for(i=0;iplatform_context = (void *)platform; platform->cmu_pmu_status = 0; diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.h b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.h index e9c4e2ec9a15..8df43236a950 100755 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.h +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_platform.h @@ -8,18 +8,25 @@ /** * @file mali_kbase_platform.h - * Platform-dependent init + * // Platform-dependent init + * + * 声明 platform_dependent_part 的 work_context 类型, pm, clk 等操作的接口. */ #ifndef _KBASE_PLATFORM_H_ #define _KBASE_PLATFORM_H_ +/** + * work_context_of_platform_dependent_part_of_rk. + */ struct rk_context { /** Indicator if system clock to mail-t604 is active */ int cmu_pmu_status; /** cmd & pmu lock */ spinlock_t cmu_pmu_lock; + /** gpu_power_domain. */ struct clk *mali_pd; + /** gpu_dvfs_node. */ struct dvfs_node * mali_clk_node; #ifdef CONFIG_MALI_MIDGARD_DVFS /*To calculate utilization for x sec */ @@ -27,7 +34,9 @@ struct rk_context { int utilisation; u32 time_busy; u32 time_idle; + /** mali_dvfs 是否被使能. */ bool dvfs_enabled; + /** 标识当前有 touch_input_event 到来. */ bool gpu_in_touch; spinlock_t gpu_in_touch_lock; #endif @@ -158,20 +167,58 @@ typedef enum } mali_error; - -int mali_dvfs_clk_set(struct dvfs_node * node,unsigned long rate); +/** + * 将 gpu_clk 设置为 'rate', 'rate' 以 KHz 为单位. + * @param node: + * 指向 gpu_dvfs_node + * @param rate + * 预期设置的 gpu_clk 的 value, KHz 为单位. + */ +int mali_dvfs_clk_set(struct dvfs_node * node,unsigned long rate); // 'rate' 以 KHz 为单位. /* All things that are needed for the Linux port. */ +/** + * 关闭/开启 gpu 的 power 和 clock. + * @param kbdev + * 指向 mali_device. + * @param control + * 若是 1, 表征要开启. + * 若是 0, 表征要关闭. + */ int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control); +/** + * 在 sysfs_dir_of_mali_device 下创建 rk_ext_file_nodes. + */ int kbase_platform_create_sysfs_file(struct device *dev); +/** + * 删除 sysfs_dir_of_mali_device 下的 rk_ext_file_nodes. + */ void kbase_platform_remove_sysfs_file(struct device *dev); + +/** + * 返回 gpu_power_domain 是否开启. + */ int kbase_platform_is_power_on(void); + mali_error kbase_platform_init(struct kbase_device *kbdev); void kbase_platform_term(struct kbase_device *kbdev); +/** + * 使能 clk_of_gpu_dvfs_node. + */ int kbase_platform_clock_on(struct kbase_device *kbdev); +/** + * 禁止(关闭) clk_of_gpu_dvfs_node. + */ int kbase_platform_clock_off(struct kbase_device *kbdev); + +/** + * 开启 gpu_power_domain. + */ int kbase_platform_power_off(struct kbase_device *kbdev); +/** + * 关闭 gpu_power_domain. + */ int kbase_platform_power_on(struct kbase_device *kbdev); #endif /* _KBASE_PLATFORM_H_ */