[kernel] rk3288_mali_t760_driver_r6p0-02rel0_13_x@0
(cherry picked from commit 1075a28e369596f902a832a5e4fe2ce0abcccbd0)
This commit is contained in:
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -28,6 +28,16 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/reboot.h>
|
||||
/**
|
||||
* @file mali_kbase_config_rk.c
|
||||
* 对 platform_config_of_rk 的具体实现.
|
||||
*
|
||||
* mali_device_driver 包含两部分 :
|
||||
* .DP : platform_dependent_part_in_mdd : 依赖 platform 部分, 源码在 <mdd_src_dir>/platform/<platform_name> 目录下.
|
||||
* 在 mali_device_driver 内部, 记为 platform_dependent_part.
|
||||
* .DP : common_parts_in_mdd : arm 实现的通用的部分, 源码在 <mdd_src_dir> 目录下.
|
||||
* 在 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))
|
||||
|
||||
@ -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 <mali_kbase.h>
|
||||
#include <mali_kbase_uku.h>
|
||||
#include <mali_kbase_mem.h>
|
||||
@ -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);
|
||||
*/
|
||||
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);
|
||||
}
|
||||
level_down_time = 0;
|
||||
} 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_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);
|
||||
*/
|
||||
mali_dvfs_infotbl[dvfs_status->step].clock,
|
||||
fps,
|
||||
dvfs_status->temperature);
|
||||
/* 预置 current_dvfs_level 上跳. */ // 具体生效将在最后.
|
||||
dvfs_status->step++;
|
||||
/* 清 上跳请求计数. */
|
||||
level_up_time = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 否则, 若 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)
|
||||
{
|
||||
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);
|
||||
|
||||
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;i<MALI_DVFS_STEP;i++)
|
||||
calculate_dvfs_max_min_threshold(i);
|
||||
|
||||
p_mali_dvfs_infotbl = mali_dvfs_infotbl;
|
||||
}
|
||||
|
||||
not_assigned :
|
||||
if (!mali_dvfs_wq)
|
||||
mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
|
||||
@ -488,21 +625,24 @@ not_assigned :
|
||||
mutex_init(&mali_set_clock_lock);
|
||||
mutex_init(&mali_enable_clock_lock);
|
||||
|
||||
spin_lock_init(&platform->gpu_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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -9,8 +9,10 @@
|
||||
|
||||
/**
|
||||
* @file mali_kbase_platform.c
|
||||
* Platform-dependent init.
|
||||
*
|
||||
* 对 mali_kbase_platform.h 声明的 pm, clk 等接口的具体实现.
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
#include <mali_kbase_uku.h>
|
||||
@ -43,6 +45,7 @@
|
||||
|
||||
#include <linux/rockchip/dvfs.h>
|
||||
|
||||
// #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;i<MALI_DVFS_STEP;i++)
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ",p_mali_dvfs_infotbl[i].clock/1000);
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Mhz");
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible_freqs : ");
|
||||
for ( i = 0; i < MALI_DVFS_STEP; i++ )
|
||||
{
|
||||
if ( i < (MALI_DVFS_STEP - 1) )
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
|
||||
}
|
||||
}
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
|
||||
|
||||
if (ret < PAGE_SIZE - 1)
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
|
||||
}
|
||||
else {
|
||||
buf[PAGE_SIZE - 2] = '\n';
|
||||
buf[PAGE_SIZE - 1] = '\0';
|
||||
@ -360,6 +484,7 @@ static ssize_t set_clock(struct device *dev, struct device_attribute *attr, cons
|
||||
}
|
||||
#endif
|
||||
freq = simple_strtoul(buf, NULL, 10);
|
||||
D("freq : %u.", freq);
|
||||
|
||||
kbase_platform_dvfs_set_level(kbdev, kbase_platform_dvfs_get_level(freq));
|
||||
return count;
|
||||
@ -377,7 +502,15 @@ static ssize_t show_fbdev(struct device *dev, struct device_attribute *attr, cha
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < num_registered_fb; i++)
|
||||
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);
|
||||
{
|
||||
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<MALI_DVFS_STEP;i++)
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ",p_mali_dvfs_infotbl[i].clock/1000);
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Mhz");
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, ", If you want to unlock : off");
|
||||
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible upper_lock_freqs : ");
|
||||
for ( i = 0; i < MALI_DVFS_STEP; i++ )
|
||||
{
|
||||
if ( i < (MALI_DVFS_STEP - 1) )
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
|
||||
}
|
||||
}
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
|
||||
|
||||
if ( gpu_clk_freq > 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;
|
||||
unsigned int freq = 0; // 可能由 caller 传入的, 待设置的 gpu_freq_upper_limit.
|
||||
int ret = 0;
|
||||
|
||||
kbdev = dev_get_drvdata(dev);
|
||||
freq = 0;
|
||||
|
||||
if (!kbdev)
|
||||
return -ENODEV;
|
||||
|
||||
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<MALI_DVFS_STEP;i++)
|
||||
{
|
||||
D("p_mali_dvfs_infotbl[%d].clock : %d", i, p_mali_dvfs_infotbl[i].clock);
|
||||
if (p_mali_dvfs_infotbl[i].clock == freq)
|
||||
{
|
||||
mali_dvfs_freq_lock(i);
|
||||
D("target_freq is acceptable in level '%d', to set '%d' as index of dvfs_level_upper_limit.", i, i);
|
||||
ret = mali_dvfs_freq_lock(i);
|
||||
if ( 0 != ret )
|
||||
{
|
||||
E("fail to set dvfs_level_upper_limit, ret : %d.", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(i==MALI_DVFS_STEP)
|
||||
{
|
||||
dev_err(dev, "set_clock: invalid value\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
/* 若 "没有" 找到和 target_freq match 的 level, 则... */
|
||||
if ( MALI_DVFS_STEP == i )
|
||||
{
|
||||
// dev_err(dev, "set_clock: invalid value\n");
|
||||
E("invalid target_freq : %d", freq);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_MALI_MIDGARD_DVFS */
|
||||
printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
|
||||
#endif
|
||||
@ -751,7 +936,7 @@ static ssize_t show_under_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);
|
||||
@ -760,18 +945,34 @@ static ssize_t show_under_lock_dvfs(struct device *dev, struct device_attribute
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
locked_level = mali_get_dvfs_under_locked_freq();
|
||||
if (locked_level > 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<MALI_DVFS_STEP;i++)
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ",p_mali_dvfs_infotbl[i].clock/1000);
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "Mhz");
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, ", If you want to unlock : off");
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\npossible under_lock_freqs : ");
|
||||
for ( i = 0; i < MALI_DVFS_STEP; i++ )
|
||||
{
|
||||
if ( i < (MALI_DVFS_STEP - 1) )
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d, ", p_mali_dvfs_infotbl[i].clock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%d ", p_mali_dvfs_infotbl[i].clock);
|
||||
}
|
||||
}
|
||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "(KHz)");
|
||||
|
||||
if ( gpu_clk_freq > 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;i<MALI_DVFS_STEP;i++)
|
||||
{
|
||||
if (p_mali_dvfs_infotbl[i].clock == freq)
|
||||
{
|
||||
mali_dvfs_freq_lock(i);
|
||||
D("to set '%d' as the index of dvfs_level_lower_limit", i);
|
||||
ret = mali_dvfs_freq_under_lock(i);
|
||||
if ( 0 != ret )
|
||||
{
|
||||
E("fail to set dvfs_level_lower_limit, ret : %d.", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(i==MALI_DVFS_STEP)
|
||||
{
|
||||
dev_err(dev, "set_clock: invalid value\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
/* 若 "没有" 找到和 target_freq match 的 level, 则... */
|
||||
if( i == MALI_DVFS_STEP )
|
||||
{
|
||||
dev_err(dev, "set_clock: invalid value\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_MALI_MIDGARD_DVFS */
|
||||
printk(KERN_DEBUG "mali DVFS is disabled. You can not set\n");
|
||||
#endif
|
||||
@ -836,6 +1051,7 @@ DEVICE_ATTR(dvfs, S_IRUGO | S_IWUSR, show_dvfs, set_dvfs);
|
||||
DEVICE_ATTR(dvfs_upper_lock, S_IRUGO | S_IWUSR, show_upper_lock_dvfs, set_upper_lock_dvfs);
|
||||
DEVICE_ATTR(dvfs_under_lock, S_IRUGO | S_IWUSR, show_under_lock_dvfs, set_under_lock_dvfs);
|
||||
DEVICE_ATTR(time_in_state, S_IRUGO | S_IWUSR, show_time_in_state, set_time_in_state);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
int kbase_platform_create_sysfs_file(struct device *dev)
|
||||
{
|
||||
@ -849,12 +1065,12 @@ int kbase_platform_create_sysfs_file(struct device *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* rk_ext : device will crash after "cat /sys/devices/ffa30000.gpu/dtlb".
|
||||
/* rk_ext : device will crash after "cat /sys/devices/ffa30000.gpu/dtlb".
|
||||
if (device_create_file(dev, &dev_attr_dtlb)) {
|
||||
dev_err(dev, "Couldn't create sysfs file [dtlb]\n");
|
||||
goto out;
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
||||
if (device_create_file(dev, &dev_attr_dvfs)) {
|
||||
dev_err(dev, "Couldn't create sysfs file [dvfs]\n");
|
||||
@ -876,6 +1092,7 @@ int kbase_platform_create_sysfs_file(struct device *dev)
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return -ENOENT;
|
||||
}
|
||||
@ -902,6 +1119,7 @@ mali_error kbase_platform_init(struct kbase_device *kbdev)
|
||||
if (NULL == platform)
|
||||
return MALI_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* .KP : 将 'rk_context' 关联到 mali_device. */
|
||||
kbdev->platform_context = (void *)platform;
|
||||
|
||||
platform->cmu_pmu_status = 0;
|
||||
|
||||
@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user