mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
rk3288: new ddrfreq policy, change freq by vop request
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
#include <linux/rockchip/iomap.h>
|
||||
#include <linux/clk-private.h>
|
||||
#include "../../../drivers/clk/rockchip/clk-pd.h"
|
||||
#include "cpu_axi.h"
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
extern int rockchip_cpufreq_reboot_limit_freq(void);
|
||||
@@ -39,6 +40,11 @@ static inline int rockchip_cpufreq_reboot_limit_freq(void) { return 0; }
|
||||
static DECLARE_COMPLETION(ddrfreq_completion);
|
||||
static DEFINE_MUTEX(ddrfreq_mutex);
|
||||
|
||||
#define VOP_REQ_BLOCK
|
||||
#ifdef VOP_REQ_BLOCK
|
||||
static DECLARE_COMPLETION(vop_req_completion);
|
||||
#endif
|
||||
|
||||
static struct dvfs_node *clk_cpu_dvfs_node = NULL;
|
||||
static int reboot_config_done = 0;
|
||||
static int ddr_boost = 0;
|
||||
@@ -47,11 +53,12 @@ static int watch=0;
|
||||
static int high_load = 70;
|
||||
static int low_load = 60;
|
||||
static int auto_freq_interval_ms = 20;
|
||||
static int high_load_last_ms = 0;
|
||||
static int low_load_last_ms = 200;
|
||||
static long down_rate_delay_ms = 500;
|
||||
static unsigned long *auto_freq_table = NULL;
|
||||
static int cur_freq_index;
|
||||
static int auto_freq_table_size;
|
||||
static unsigned long vop_bandwidth_update_jiffies = 0, vop_bandwidth = 0;
|
||||
static int vop_bandwidth_update_flag = 0;
|
||||
|
||||
enum {
|
||||
DEBUG_DDR = 1U << 0,
|
||||
@@ -73,12 +80,11 @@ enum ddr_bandwidth_id{
|
||||
ddrbw_id_end
|
||||
};
|
||||
|
||||
#define ddr_monitor_start() grf_writel((((readl_relaxed(RK_PMU_VIRT + 0x9c)>>13)&7)==3)?0xc000c000:0xe000e000,RK3288_GRF_SOC_CON4)
|
||||
#define ddr_monitor_stop() grf_writel(0xc0000000,RK3288_GRF_SOC_CON4)
|
||||
|
||||
#define grf_readl(offset) readl_relaxed(RK_GRF_VIRT + offset)
|
||||
#define grf_writel(v, offset) do { writel_relaxed(v, RK_GRF_VIRT + offset); dsb(); } while (0)
|
||||
|
||||
#define noc_readl(offset) readl_relaxed(RK3288_SERVICE_BUS_VIRT + offset)
|
||||
#define noc_writel(v, offset) do { writel_relaxed(v, RK3288_SERVICE_BUS_VIRT + offset); dsb(); } while (0)
|
||||
|
||||
#define MHZ (1000*1000)
|
||||
#define KHZ 1000
|
||||
@@ -93,6 +99,24 @@ struct video_info {
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct ddr_bw_info{
|
||||
u32 ddr_wr;
|
||||
u32 ddr_rd;
|
||||
u32 ddr_act;
|
||||
u32 ddr_time;
|
||||
u32 ddr_total;
|
||||
u32 ddr_percent;
|
||||
|
||||
u32 cpum;
|
||||
u32 gpu;
|
||||
u32 peri;
|
||||
u32 video;
|
||||
u32 vio0;
|
||||
u32 vio1;
|
||||
u32 vio2;
|
||||
};
|
||||
static struct ddr_bw_info ddr_bw_ch0={0}, ddr_bw_ch1={0};
|
||||
|
||||
struct ddr {
|
||||
struct dvfs_node *clk_dvfs_node;
|
||||
struct list_head video_info_list;
|
||||
@@ -120,12 +144,12 @@ module_param_named(sys_status, ddr.sys_status, ulong, S_IRUGO);
|
||||
module_param_named(auto_self_refresh, ddr.auto_self_refresh, bool, S_IRUGO);
|
||||
module_param_named(mode, ddr.mode, charp, S_IRUGO);
|
||||
|
||||
static unsigned long get_freq_from_table(unsigned long freq)
|
||||
static unsigned long auto_freq_round(unsigned long freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!auto_freq_table)
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; auto_freq_table[i] != 0; i++) {
|
||||
if (auto_freq_table[i] >= freq) {
|
||||
@@ -136,7 +160,7 @@ static unsigned long get_freq_from_table(unsigned long freq)
|
||||
return auto_freq_table[i-1];
|
||||
}
|
||||
|
||||
static unsigned long get_index_from_table(unsigned long freq)
|
||||
static unsigned long auto_freq_get_index(unsigned long freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -151,6 +175,23 @@ static unsigned long get_index_from_table(unsigned long freq)
|
||||
return i-1;
|
||||
}
|
||||
|
||||
static unsigned int auto_freq_update_index(unsigned long freq)
|
||||
{
|
||||
cur_freq_index = auto_freq_get_index(freq);
|
||||
|
||||
return cur_freq_index;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long auto_freq_get_next_step(void)
|
||||
{
|
||||
if (cur_freq_index < auto_freq_table_size-1) {
|
||||
return auto_freq_table[cur_freq_index+1];
|
||||
}
|
||||
|
||||
return auto_freq_table[cur_freq_index];
|
||||
}
|
||||
|
||||
static void ddrfreq_mode(bool auto_self_refresh, unsigned long target_rate, char *name)
|
||||
{
|
||||
unsigned int min_rate, max_rate;
|
||||
@@ -163,14 +204,13 @@ static void ddrfreq_mode(bool auto_self_refresh, unsigned long target_rate, char
|
||||
dprintk(DEBUG_DDR, "change auto self refresh to %d when %s\n", auto_self_refresh, name);
|
||||
}
|
||||
|
||||
cur_freq_index = get_index_from_table(target_rate);
|
||||
|
||||
if (target_rate != dvfs_clk_get_last_set_rate(ddr.clk_dvfs_node)) {
|
||||
freq_limit_en = dvfs_clk_get_limit(clk_cpu_dvfs_node, &min_rate, &max_rate);
|
||||
|
||||
dvfs_clk_enable_limit(clk_cpu_dvfs_node, 600000000, -1);
|
||||
if (dvfs_clk_set_rate(ddr.clk_dvfs_node, target_rate) == 0) {
|
||||
target_rate = dvfs_clk_get_rate(ddr.clk_dvfs_node);
|
||||
auto_freq_update_index(target_rate);
|
||||
dprintk(DEBUG_DDR, "change freq to %lu MHz when %s\n", target_rate / MHZ, name);
|
||||
}
|
||||
|
||||
@@ -182,84 +222,173 @@ static void ddrfreq_mode(bool auto_self_refresh, unsigned long target_rate, char
|
||||
}
|
||||
}
|
||||
|
||||
void ddr_bandwidth_get(u32 *ch0_eff, u32 *ch1_eff)
|
||||
unsigned long req_freq_by_vop(unsigned long bandwidth)
|
||||
{
|
||||
u32 ddr_bw_val[2][ddrbw_id_end];
|
||||
if (time_after(jiffies, vop_bandwidth_update_jiffies+down_rate_delay_ms))
|
||||
return 0;
|
||||
|
||||
if (bandwidth >= 5000){
|
||||
return 800000000;
|
||||
}
|
||||
|
||||
if (bandwidth >= 3500) {
|
||||
return 456000000;
|
||||
}
|
||||
|
||||
if (bandwidth >= 2600) {
|
||||
return 396000000;
|
||||
}
|
||||
if (bandwidth >= 2000) {
|
||||
return 324000000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ddr_monitor_start(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1;i<8;i++)
|
||||
{
|
||||
noc_writel(0x8, (0x400*i+0x8));
|
||||
noc_writel(0x1, (0x400*i+0xc));
|
||||
noc_writel(0x6, (0x400*i+0x138));
|
||||
noc_writel(0x10, (0x400*i+0x14c));
|
||||
noc_writel(0x8, (0x400*i+0x160));
|
||||
noc_writel(0x10, (0x400*i+0x174));
|
||||
}
|
||||
grf_writel((((readl_relaxed(RK_PMU_VIRT + 0x9c)>>13)&7)==3)?0xc000c000:0xe000e000,RK3288_GRF_SOC_CON4); // ddr
|
||||
for(i=1;i<8;i++)
|
||||
{
|
||||
noc_writel(0x1, (0x400*i+0x28));
|
||||
}
|
||||
}
|
||||
|
||||
void ddr_monitor_stop(void)
|
||||
{
|
||||
grf_writel(0xc0000000,RK3288_GRF_SOC_CON4); //ddr
|
||||
}
|
||||
|
||||
void ddr_bandwidth_get(struct ddr_bw_info *ddr_bw_ch0, struct ddr_bw_info *ddr_bw_ch1)
|
||||
{
|
||||
u32 ddr_bw_val[2][ddrbw_id_end], ddr_freq;
|
||||
u64 temp64;
|
||||
int i, j;
|
||||
|
||||
ddr_monitor_stop();
|
||||
for(j = 0; j < 2; j++) {
|
||||
for(i = 0; i < ddrbw_eff; i++ ){
|
||||
ddr_bw_val[j][i] = grf_readl(RK3288_GRF_SOC_STATUS11+i*4+j*16);
|
||||
}
|
||||
}
|
||||
|
||||
temp64 = ((u64)ddr_bw_val[0][0]+ddr_bw_val[0][1])*4*100;
|
||||
do_div(temp64, ddr_bw_val[0][ddrbw_time_num]);
|
||||
ddr_bw_val[0][ddrbw_eff] = temp64;
|
||||
*ch0_eff = temp64;
|
||||
if (ddr_bw_ch0) {
|
||||
ddr_freq = readl_relaxed(RK_DDR_VIRT + 0xc0);
|
||||
|
||||
temp64 = ((u64)ddr_bw_val[0][0]+ddr_bw_val[0][1])*4*100;
|
||||
do_div(temp64, ddr_bw_val[0][ddrbw_time_num]);
|
||||
ddr_bw_val[0][ddrbw_eff] = temp64;
|
||||
|
||||
ddr_bw_ch0->ddr_percent = temp64;
|
||||
ddr_bw_ch0->ddr_time = ddr_bw_val[0][ddrbw_time_num]/(ddr_freq*1000);
|
||||
ddr_bw_ch0->ddr_wr = (ddr_bw_val[0][ddrbw_wr_num]*8*4)*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->ddr_rd = (ddr_bw_val[0][ddrbw_rd_num]*8*4)*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->ddr_act = ddr_bw_val[0][ddrbw_act_num];
|
||||
ddr_bw_ch0->ddr_total = ddr_freq*2*4;
|
||||
|
||||
ddr_bw_ch0->cpum = (noc_readl(0x400+0x178)<<16)
|
||||
+ (noc_readl(0x400+0x164));
|
||||
ddr_bw_ch0->gpu = (noc_readl(0x800+0x178)<<16)
|
||||
+ (noc_readl(0x800+0x164));
|
||||
ddr_bw_ch0->peri = (noc_readl(0xc00+0x178)<<16)
|
||||
+ (noc_readl(0xc00+0x164));
|
||||
ddr_bw_ch0->video = (noc_readl(0x1000+0x178)<<16)
|
||||
+ (noc_readl(0x1000+0x164));
|
||||
ddr_bw_ch0->vio0 = (noc_readl(0x1400+0x178)<<16)
|
||||
+ (noc_readl(0x1400+0x164));
|
||||
ddr_bw_ch0->vio1 = (noc_readl(0x1800+0x178)<<16)
|
||||
+ (noc_readl(0x1800+0x164));
|
||||
ddr_bw_ch0->vio2 = (noc_readl(0x1c00+0x178)<<16)
|
||||
+ (noc_readl(0x1c00+0x164));
|
||||
|
||||
ddr_bw_ch0->cpum = ddr_bw_ch0->cpum*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->gpu = ddr_bw_ch0->gpu*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->peri = ddr_bw_ch0->peri*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->video = ddr_bw_ch0->video*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->vio0 = ddr_bw_ch0->vio0*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->vio1 = ddr_bw_ch0->vio1*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
ddr_bw_ch0->vio2 = ddr_bw_ch0->vio2*ddr_freq/ddr_bw_val[0][ddrbw_time_num];
|
||||
}
|
||||
|
||||
temp64 = ((u64)ddr_bw_val[1][0]+ddr_bw_val[1][1])*4*100;
|
||||
do_div(temp64, ddr_bw_val[1][ddrbw_time_num]);
|
||||
ddr_bw_val[1][ddrbw_eff] = temp64;
|
||||
*ch1_eff = temp64;
|
||||
ddr_monitor_start();
|
||||
}
|
||||
|
||||
static void ddr_auto_freq(void)
|
||||
{
|
||||
unsigned long freq, new_freq;
|
||||
u32 ch0_eff, ch1_eff, max_eff;
|
||||
static u32 high_load_last = 0, low_load_last = 0;
|
||||
unsigned long freq, new_freq=0, vop_req_freq=0, total_bw_req_freq=0;
|
||||
u32 ddr_percent, target_load;
|
||||
static u32 local_jiffies=0, max_ddr_percent=0;
|
||||
|
||||
if (!local_jiffies)
|
||||
local_jiffies = jiffies;
|
||||
freq = dvfs_clk_get_rate(ddr.clk_dvfs_node);
|
||||
|
||||
ddr_monitor_stop();
|
||||
ddr_bandwidth_get(&ch0_eff, &ch1_eff);
|
||||
max_eff = (ch0_eff > ch1_eff) ? ch0_eff : ch1_eff;
|
||||
|
||||
if (watch) {
|
||||
printk("%d %d\n", ch0_eff, ch1_eff);
|
||||
ddr_monitor_start();
|
||||
return;
|
||||
}
|
||||
ddr_bandwidth_get(&ddr_bw_ch0, &ddr_bw_ch1);
|
||||
ddr_percent = ddr_bw_ch0.ddr_percent;
|
||||
|
||||
if (print) {
|
||||
printk("%d %d\n", ch0_eff, ch1_eff);
|
||||
if ((watch)||(print)) {
|
||||
if((watch == 2)&& (ddr_bw_ch0.ddr_percent < max_ddr_percent)) {
|
||||
return;
|
||||
} else if(watch == 2) {
|
||||
max_ddr_percent = ddr_bw_ch0.ddr_percent;
|
||||
}
|
||||
printk("Unit:MB/s total use%% rd wr cpum gpu peri video vio0 vio1 vio2\n");
|
||||
printk("%3u(ms): %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u %5u\n",
|
||||
ddr_bw_ch0.ddr_time,
|
||||
ddr_bw_ch0.ddr_total,
|
||||
ddr_bw_ch0.ddr_percent,
|
||||
ddr_bw_ch0.ddr_rd,
|
||||
ddr_bw_ch0.ddr_wr,
|
||||
ddr_bw_ch0.cpum,
|
||||
ddr_bw_ch0.gpu,
|
||||
ddr_bw_ch0.peri,
|
||||
ddr_bw_ch0.video,
|
||||
ddr_bw_ch0.vio0,
|
||||
ddr_bw_ch0.vio1,
|
||||
ddr_bw_ch0.vio2);
|
||||
|
||||
if (watch)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ddr_boost) {
|
||||
ddr_boost = 0;
|
||||
if (freq < ddr.boost_rate) {
|
||||
low_load_last = low_load_last_ms/auto_freq_interval_ms;
|
||||
ddrfreq_mode(false, ddr.boost_rate, "boost");
|
||||
}
|
||||
} else if(max_eff > high_load){
|
||||
low_load_last = low_load_last_ms/auto_freq_interval_ms;
|
||||
|
||||
if (!high_load_last) {
|
||||
if (cur_freq_index < auto_freq_table_size-1) {
|
||||
new_freq = auto_freq_table[cur_freq_index+1];
|
||||
ddrfreq_mode(false, new_freq, "high load");
|
||||
}
|
||||
} else {
|
||||
high_load_last--;
|
||||
}
|
||||
} else if (max_eff < low_load){
|
||||
high_load_last = high_load_last_ms/auto_freq_interval_ms;
|
||||
|
||||
new_freq = max_eff*(freq/low_load);
|
||||
new_freq = get_freq_from_table(new_freq);
|
||||
if (new_freq > freq) {
|
||||
low_load_last = 0;
|
||||
ddrfreq_mode(false, new_freq, "low load");
|
||||
} else if (!low_load_last) {
|
||||
ddrfreq_mode(false, new_freq, "low load");
|
||||
} else {
|
||||
low_load_last--;
|
||||
}
|
||||
new_freq = max(ddr.boost_rate, new_freq);
|
||||
}
|
||||
|
||||
ddr_monitor_start();
|
||||
if(ddr_percent > high_load){
|
||||
total_bw_req_freq = auto_freq_get_next_step();
|
||||
} else if (ddr_percent < low_load){
|
||||
target_load = (low_load+high_load)/2;
|
||||
total_bw_req_freq = ddr_percent*(freq/target_load);
|
||||
}
|
||||
new_freq = max(total_bw_req_freq, new_freq);
|
||||
|
||||
vop_req_freq = req_freq_by_vop(vop_bandwidth);
|
||||
new_freq = max(vop_req_freq, new_freq);
|
||||
|
||||
new_freq = auto_freq_round(new_freq);
|
||||
|
||||
if (new_freq < freq) {
|
||||
if (time_after(jiffies, local_jiffies+down_rate_delay_ms/10)) {
|
||||
local_jiffies = jiffies;
|
||||
ddrfreq_mode(false, new_freq, "auto down rate");
|
||||
}
|
||||
} else if(new_freq > freq){
|
||||
local_jiffies = jiffies;
|
||||
ddrfreq_mode(false, new_freq, "auto up rate");
|
||||
}
|
||||
}
|
||||
|
||||
static noinline long ddrfreq_work(unsigned long sys_status)
|
||||
@@ -343,7 +472,7 @@ static noinline long ddrfreq_work(unsigned long sys_status)
|
||||
} else {
|
||||
if (ddr.auto_freq) {
|
||||
ddr_auto_freq();
|
||||
timeout = auto_freq_interval_ms;
|
||||
timeout = auto_freq_interval_ms/10;
|
||||
}
|
||||
else {
|
||||
ddrfreq_mode(false, ddr.normal_rate, "normal");
|
||||
@@ -404,11 +533,18 @@ static int ddrfreq_task(void *data)
|
||||
|
||||
do {
|
||||
status = ddr.sys_status;
|
||||
if (vop_bandwidth_update_flag) {
|
||||
vop_bandwidth_update_flag = 0;
|
||||
#ifdef VOP_REQ_BLOCK
|
||||
complete(&vop_req_completion);
|
||||
#endif
|
||||
}
|
||||
|
||||
timeout = ddrfreq_work(status);
|
||||
if (old_status != status) {
|
||||
complete(&ddrfreq_completion);
|
||||
}
|
||||
wait_event_freezable_timeout(ddr.wait, (status != ddr.sys_status) || kthread_should_stop(), timeout);
|
||||
wait_event_freezable_timeout(ddr.wait, vop_bandwidth_update_flag || (status != ddr.sys_status) || kthread_should_stop(), timeout);
|
||||
old_status = status;
|
||||
} while (!kthread_should_stop() && !reboot_config_done);
|
||||
|
||||
@@ -592,6 +728,41 @@ static struct miscdevice video_state_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
};
|
||||
|
||||
static long ddr_freq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned long bandwidth = *(int*)arg;
|
||||
unsigned long vop_req_freq;
|
||||
int ret = -1;
|
||||
|
||||
vop_bandwidth = bandwidth;
|
||||
vop_bandwidth_update_jiffies = jiffies;
|
||||
vop_req_freq = req_freq_by_vop(bandwidth);
|
||||
if (dvfs_clk_get_rate(ddr.clk_dvfs_node) >= vop_req_freq) {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
vop_bandwidth_update_flag = 1;
|
||||
wake_up(&ddr.wait);
|
||||
#ifdef VOP_REQ_BLOCK
|
||||
wait_for_completion(&vop_req_completion);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const struct file_operations ddr_freq_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = ddr_freq_ioctl,
|
||||
};
|
||||
|
||||
static struct miscdevice ddr_freq_dev = {
|
||||
.fops = &ddr_freq_fops,
|
||||
.name = "ddr_freq",
|
||||
.mode = S_IRUGO | S_IWUSR | S_IWUGO,
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_INPUT
|
||||
static void ddr_freq_input_event(struct input_handle *handle, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
@@ -915,6 +1086,7 @@ static int ddrfreq_init(void)
|
||||
//REGISTER_CLK_NOTIFIER(pd_vop1);
|
||||
|
||||
ret = misc_register(&video_state_dev);
|
||||
ret = misc_register(&ddr_freq_dev);
|
||||
if (unlikely(ret)) {
|
||||
pr_err("failed to register video_state misc device! error %d\n", ret);
|
||||
goto err;
|
||||
@@ -973,8 +1145,8 @@ static ssize_t ddrbw_dyn_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
str += sprintf(str, "high_load: %d\n", high_load);
|
||||
str += sprintf(str, "low_load: %d\n", low_load);
|
||||
str += sprintf(str, "auto_freq_interval_ms: %d\n", auto_freq_interval_ms);
|
||||
str += sprintf(str, "high_load_last_ms: %d\n", high_load_last_ms);
|
||||
str += sprintf(str, "low_load_last_ms: %d\n", low_load_last_ms);
|
||||
str += sprintf(str, "down_rate_delay_ms: %ld\n", down_rate_delay_ms);
|
||||
// str += sprintf(str, "low_load_last_ms: %d\n", low_load_last_ms);
|
||||
if (str != buf)
|
||||
*(str - 1) = '\n';
|
||||
return (str - buf);
|
||||
@@ -991,17 +1163,15 @@ static ssize_t ddrbw_dyn_store(struct kobject *kobj, struct kobj_attribute *attr
|
||||
if((strncmp(buf, "print", strlen("print")) == 0)) {
|
||||
print = value;
|
||||
} else if((strncmp(buf, "watch", strlen("watch")) == 0)) {
|
||||
watch = value;;
|
||||
watch = value;
|
||||
} else if((strncmp(buf, "high", strlen("high")) == 0)) {
|
||||
high_load = value;;
|
||||
high_load = value;
|
||||
} else if((strncmp(buf, "low", strlen("low")) == 0)) {
|
||||
low_load = value;;
|
||||
low_load = value;
|
||||
} else if((strncmp(buf, "interval", strlen("interval")) == 0)) {
|
||||
auto_freq_interval_ms = value;;
|
||||
} else if((strncmp(buf, "high_last", strlen("high_last")) == 0)) {
|
||||
high_load_last_ms = value;;
|
||||
} else if((strncmp(buf, "low_last", strlen("low_last")) == 0)) {
|
||||
low_load_last_ms = value;;
|
||||
auto_freq_interval_ms = value;
|
||||
} else if((strncmp(buf, "downdelay", strlen("downdelay")) == 0)) {
|
||||
down_rate_delay_ms = value;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@@ -1030,6 +1200,5 @@ static void ddrfreq_tst_init(void)
|
||||
printk("%s: create ddrfreq sysfs node error, ret: %d\n", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3714,7 +3714,7 @@ static noinline uint32 ddr_change_freq_sram(void *arg)
|
||||
}
|
||||
else
|
||||
{
|
||||
rk_fb_poll_wait_frame_complete();
|
||||
rk_fb_poll_wait_frame_complete();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -3990,31 +3990,57 @@ static int __ddr_change_freq(uint32_t nMHz, struct ddr_freq_t ddr_freq_t)
|
||||
static int _ddr_change_freq(uint32 nMHz)
|
||||
{
|
||||
struct ddr_freq_t ddr_freq_t;
|
||||
int test_count=0;
|
||||
int ret;
|
||||
unsigned long remain_t, vblank_t, pass_t;
|
||||
static unsigned long reserve_t = 800;//us
|
||||
unsigned long long tmp;
|
||||
int ret, test_count=0;
|
||||
|
||||
memset(&ddr_freq_t, 0x00, sizeof(ddr_freq_t));
|
||||
|
||||
ddr_freq_t.screen_ft_us = 0;
|
||||
ddr_freq_t.t0 = 0;
|
||||
ddr_freq_t.t1 = 0;
|
||||
#if defined (DDR_CHANGE_FREQ_IN_LCDC_VSYNC)
|
||||
do
|
||||
{
|
||||
if(rk_fb_poll_wait_frame_complete() == true)
|
||||
{
|
||||
ddr_freq_t.t0 = cpu_clock(0);
|
||||
ddr_freq_t.screen_ft_us = rk_fb_get_prmry_screen_ft();
|
||||
ddr_freq_t.screen_ft_us = rk_fb_get_prmry_screen_ft();
|
||||
ddr_freq_t.t0 = rk_fb_get_prmry_screen_framedone_t();
|
||||
tmp = cpu_clock(0) - ddr_freq_t.t0;
|
||||
do_div(tmp, 1000);
|
||||
pass_t = tmp;
|
||||
//lost frame interrupt
|
||||
while (pass_t > ddr_freq_t.screen_ft_us){
|
||||
int n = pass_t/ddr_freq_t.screen_ft_us;
|
||||
|
||||
test_count++;
|
||||
if(test_count > 10) //test 10 times
|
||||
{
|
||||
ddr_freq_t.screen_ft_us = 0xfefefefe;
|
||||
}
|
||||
usleep_range(ddr_freq_t.screen_ft_us-test_count*1000,ddr_freq_t.screen_ft_us-test_count*1000);
|
||||
|
||||
flush_tlb_all();
|
||||
//printk("lost frame int, pass_t:%lu\n", pass_t);
|
||||
pass_t -= n*ddr_freq_t.screen_ft_us;
|
||||
ddr_freq_t.t0 += n*ddr_freq_t.screen_ft_us*1000;
|
||||
}
|
||||
|
||||
remain_t = ddr_freq_t.screen_ft_us - pass_t;
|
||||
if (remain_t < reserve_t) {
|
||||
//printk("remain_t(%lu) < reserve_t(%lu)\n", remain_t, reserve_t);
|
||||
vblank_t = rk_fb_get_prmry_screen_vbt();
|
||||
usleep_range(remain_t+vblank_t, remain_t+vblank_t);
|
||||
continue;
|
||||
}
|
||||
|
||||
//test 10 times
|
||||
test_count++;
|
||||
if(test_count > 10)
|
||||
{
|
||||
ddr_freq_t.screen_ft_us = 0xfefefefe;
|
||||
}
|
||||
//printk("ft:%lu, pass_t:%lu, remaint_t:%lu, reservet_t:%lu\n",
|
||||
// ddr_freq_t.screen_ft_us, (unsigned long)pass_t, remain_t, reserve_t);
|
||||
usleep_range(remain_t-reserve_t, remain_t-reserve_t);
|
||||
flush_tlb_all();
|
||||
|
||||
ret = __ddr_change_freq(nMHz, ddr_freq_t);
|
||||
} while (ret == 0);
|
||||
if (ret) {
|
||||
return ret;
|
||||
} else {
|
||||
if (reserve_t < 10000)
|
||||
reserve_t += 200;
|
||||
}
|
||||
}while(1);
|
||||
#else
|
||||
ret = __ddr_change_freq(nMHz, ddr_freq_t);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user