RK3168/RK3188:add DDR_CHANGE_FREQ_IN_LCDC_VSYNC

This commit is contained in:
cym
2013-08-05 17:20:35 +08:00
parent 55dd5d2c89
commit c57530ce46
5 changed files with 276 additions and 50 deletions

View File

@@ -23,10 +23,11 @@
#include <mach/ddr.h>
#include <mach/cpu.h>
#include <plat/efuse.h>
#include <linux/rk_fb.h>
typedef uint32_t uint32;
#define ENABLE_DDR_CLCOK_GPLL_PATH //for RK3188
//#define ENABLE_DDR_CLCOK_GPLL_PATH //for RK3188
#define DDR3_DDR2_DLL_DISABLE_FREQ (125)
#define DDR3_DDR2_ODT_DISABLE_FREQ (333)
@@ -3525,7 +3526,7 @@ int ddr_get_datatraing_value_3168(bool end_flag,uint32_t dqstr_value,uint32_t mi
data8_dqstr[dqstr_value][3]=pPHY_Reg->DATX8[0].DXDQSTR;
ddr_print("training %luMhz[%d]:0x%x-0x%x-0x%x-0x%x\n",
clk_get_rate(clk_get(NULL, "ddr_pll"))/1000000,dqstr_value,data8_dqstr[dqstr_value][0],data8_dqstr[dqstr_value][1],
clk_get_rate(clk_get(NULL, "ddr"))/1000000,dqstr_value,data8_dqstr[dqstr_value][0],data8_dqstr[dqstr_value][1],
data8_dqstr[dqstr_value][2],data8_dqstr[dqstr_value][3]);
return 0;
}
@@ -3594,7 +3595,7 @@ void __sramlocalfunc ddr_set_pll_exit_3168(uint32 freq_slew,uint32_t dqstr_value
}
#endif
uint32_t __sramfunc ddr_change_freq_sram(uint32_t nMHz)
uint32_t __sramfunc ddr_change_freq_sram(uint32_t nMHz , struct ddr_freq_t ddr_freq_t)
{
uint32_t ret;
u32 i;
@@ -3608,7 +3609,7 @@ uint32_t __sramfunc ddr_change_freq_sram(uint32_t nMHz)
uint32_t freq_slew=0,dqstr_value=0;
if(dqstr_flag==true)
{
dqstr_value=(nMHz-min_ddr_freq+1)/50;
dqstr_value=((nMHz-min_ddr_freq+1)/25 + 1) /2;
freq_slew = (nMHz>ddr_freq)? 1 : 0;
}
#endif
@@ -3653,6 +3654,26 @@ uint32_t __sramfunc ddr_change_freq_sram(uint32_t nMHz)
#endif
dsb();
#if defined (DDR_CHANGE_FREQ_IN_LCDC_VSYNC)
if(ddr_freq_t.screen_ft_us > 0)
{
ddr_freq_t.t1 = cpu_clock(0);
ddr_freq_t.t2 = (u32)(ddr_freq_t.t1 - ddr_freq_t.t0)/1000;
if(ddr_freq_t.t2 > ddr_freq_t.screen_ft_us)
{
DDR_RESTORE_SP(save_sp);
local_fiq_enable();
local_irq_restore(flags);
return 0;
}
else
{
rk_fb_poll_wait_frame_complete();
}
}
#endif
/** 2. ddr enter self-refresh mode or precharge power-down mode */
idle_port();
#if defined(CONFIG_ARCH_RK3066B)
@@ -3682,6 +3703,8 @@ uint32_t __sramfunc ddr_change_freq_sram(uint32_t nMHz)
uint32_t ddr_change_freq_gpll_dpll(uint32_t nMHz)
{
uint32_t gpll_freq,gpll_div;
struct ddr_freq_t ddr_freq_t;
ddr_freq_t.screen_ft_us = 0;
gpllvaluel = ddr_get_pll_freq(GPLL);
@@ -3704,7 +3727,7 @@ uint32_t ddr_change_freq_gpll_dpll(uint32_t nMHz)
}
ddr_select_gpll_div=gpll_div; //select GPLL
ddr_change_freq_sram(gpll_freq);
ddr_change_freq_sram(gpll_freq,ddr_freq_t);
ddr_select_gpll_div=0;
ddr_set_pll(nMHz,0); //count DPLL
@@ -3715,7 +3738,7 @@ uint32_t ddr_change_freq_gpll_dpll(uint32_t nMHz)
ddr_print("GPLL frequency = %dMHz,Not suitable for ddr_clock \n",gpllvaluel);
}
return ddr_change_freq_sram(nMHz);
return ddr_change_freq_sram(nMHz,ddr_freq_t);
}
@@ -3729,19 +3752,14 @@ if rk3188 DPLL is bad,use GPLL
******************************************/
uint32_t ddr_change_freq(uint32_t nMHz)
{
struct ddr_freq_t ddr_freq_t;
ddr_freq_t.screen_ft_us = 0;
if(ddr_rk3188_dpll_is_good == false) //if rk3188 DPLL is bad,use GPLL
{
return ddr_change_freq_sram(nMHz);
}
else
{
#if defined(ENABLE_DDR_CLCOK_GPLL_PATH) && defined(CONFIG_ARCH_RK3188)
return ddr_change_freq_gpll_dpll(nMHz);
return ddr_change_freq_gpll_dpll(nMHz);
#else
return ddr_change_freq_sram(nMHz);
return ddr_change_freq_sram(nMHz,ddr_freq_t);
#endif
}
}
EXPORT_SYMBOL(ddr_change_freq);
@@ -3982,7 +4000,7 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq)
uint32_t die=1;
uint32_t gsr,dqstr;
ddr_print("version 1.00 20130712 \n");
ddr_print("version 1.00 20130805 0 \n");
mem_type = pPHY_Reg->DCR.b.DDRMD;
ddr_speed_bin = dram_speed_bin;

View File

@@ -18,6 +18,13 @@
#include <mach/ddr.h>
#include <mach/dvfs.h>
#include <linux/rk_fb.h>
//#include <linux/delay.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <linux/vmalloc.h>
enum {
DEBUG_DDR = 1U << 0,
DEBUG_VIDEO_STATE = 1U << 1,
@@ -34,13 +41,15 @@ module_param(debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
enum SYS_STATUS {
SYS_STATUS_SUSPEND = 0, // 0x01
SYS_STATUS_VIDEO, // 0x02
SYS_STATUS_GPU, // 0x04
SYS_STATUS_RGA, // 0x08
SYS_STATUS_CIF0, // 0x10
SYS_STATUS_CIF1, // 0x20
SYS_STATUS_REBOOT, // 0x40
SYS_STATUS_LCDC0, // 0x80
SYS_STATUS_LCDC1, // 0x100
SYS_STATUS_VIDEO_720P, // 0x04
SYS_STATUS_VIDEO_1080P, // 0x08
SYS_STATUS_GPU, // 0x10
SYS_STATUS_RGA, // 0x20
SYS_STATUS_CIF0, // 0x40
SYS_STATUS_CIF1, // 0x80
SYS_STATUS_REBOOT, // 0x100
SYS_STATUS_LCDC0, // 0x200
SYS_STATUS_LCDC1, // 0x400
};
struct ddr {
@@ -51,6 +60,7 @@ struct ddr {
struct clk *clk;
unsigned long normal_rate;
unsigned long video_rate;
unsigned long video_low_rate;
unsigned long dualview_rate;
unsigned long idle_rate;
unsigned long suspend_rate;
@@ -117,8 +127,13 @@ static noinline void ddrfreq_work(unsigned long sys_status)
&& (s & (1 << SYS_STATUS_LCDC1))
) {
ddrfreq_mode(false, &ddr.dualview_rate, "dual-view");
} else if (ddr.video_rate && (s & (1 << SYS_STATUS_VIDEO))) {
ddrfreq_mode(false, &ddr.video_rate, "video");
} else if ((ddr.video_rate || ddr.video_low_rate) && (s & (1 << SYS_STATUS_VIDEO))) {
if(ddr.video_low_rate && (s & (1 << SYS_STATUS_VIDEO_720P)))
ddrfreq_mode(false, &ddr.video_low_rate, "video low");
else if(ddr.video_rate && (s & (1 << SYS_STATUS_VIDEO_1080P)))
ddrfreq_mode(false, &ddr.video_rate, "video");
else
ddrfreq_mode(false, &ddr.normal_rate, "video normal");
} else if (ddr.idle_rate
&& !(s & (1 << SYS_STATUS_GPU))
&& !(s & (1 << SYS_STATUS_RGA))
@@ -174,11 +189,12 @@ static void __sramfunc pause_cpu(void *info)
local_irq_restore(flags);
}
static void _ddr_change_freq(uint32_t nMHz)
static int _ddr_change_freq_(uint32_t nMHz,struct ddr_freq_t ddr_freq_t)
{
u32 timeout = MAX_TIMEOUT;
unsigned int cpu;
unsigned int this_cpu = smp_processor_id();
int ret;
cpu_maps_update_begin();
@@ -195,12 +211,45 @@ static void _ddr_change_freq(uint32_t nMHz)
}
}
ddr_change_freq(nMHz);
ret = ddr_change_freq_sram(nMHz,ddr_freq_t);
set_other_cpus_pause(false);
out:
cpu_maps_update_done();
return ret;
}
static void _ddr_change_freq(uint32_t nMHz)
{
struct ddr_freq_t ddr_freq_t;
int test_count=0;
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();
test_count++;
//dprintk(DEBUG_VERBOSE,"test_count=%d\n",test_count);
usleep_range(ddr_freq_t.screen_ft_us-test_count*1000,ddr_freq_t.screen_ft_us-test_count*1000);
flush_cache_all();
outer_flush_all();
flush_tlb_all();
}
}while(_ddr_change_freq_(nMHz,ddr_freq_t)==0);
#else
_ddr_change_freq_(nMHz,ddr_freq_t);
#endif
}
#else
static void _ddr_change_freq(uint32_t nMHz)
@@ -237,27 +286,67 @@ static int video_state_release(struct inode *inode, struct file *file)
return 0;
}
#define VIDEO_LOW_RESOLUTION (1080*720)
static ssize_t video_state_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char state;
char *cookie_pot;
char *p;
char *buf = vzalloc(count);
uint32_t v_width=0,v_height=0,v_sync=0;
cookie_pot = buf;
if (count < 1)
return count;
if (copy_from_user(&state, buffer, 1)) {
if (copy_from_user(cookie_pot, buffer, count)) {
return -EFAULT;
}
dprintk(DEBUG_VIDEO_STATE, "video_state write %c\n", state);
dprintk(DEBUG_VIDEO_STATE, "video_state write %s,len %d\n", cookie_pot,count);
state=cookie_pot[0];
if( (count>=3) && (cookie_pot[2]=='w') )
{
strsep(&cookie_pot,",");
strsep(&cookie_pot,"=");
p=strsep(&cookie_pot,",");
v_width = simple_strtol(p,NULL,10);
strsep(&cookie_pot,"=");
p=strsep(&cookie_pot,",");
v_height= simple_strtol(p,NULL,10);
strsep(&cookie_pot,"=");
p=strsep(&cookie_pot,",");
v_sync= simple_strtol(p,NULL,10);
dprintk(DEBUG_VIDEO_STATE, "video_state %c,width=%d,height=%d,sync=%d\n", state,v_width,v_height,v_sync);
}
switch (state) {
case '0':
ddrfreq_clear_sys_status(SYS_STATUS_VIDEO);
ddrfreq_clear_sys_status(SYS_STATUS_VIDEO_720P);
ddrfreq_clear_sys_status(SYS_STATUS_VIDEO_1080P);
break;
case '1':
ddrfreq_set_sys_status(SYS_STATUS_VIDEO);
if( (v_width == 0) && (v_height == 0)){
ddrfreq_set_sys_status(SYS_STATUS_VIDEO_1080P);
}
else if(v_sync==1){
if(ddr.video_low_rate && ((v_width*v_height) <= VIDEO_LOW_RESOLUTION) )
ddrfreq_set_sys_status(SYS_STATUS_VIDEO_720P);
else
ddrfreq_set_sys_status(SYS_STATUS_VIDEO_1080P);
}
else{
ddrfreq_clear_sys_status(SYS_STATUS_VIDEO_720P);
ddrfreq_clear_sys_status(SYS_STATUS_VIDEO_1080P);
}
break;
default:
return -EINVAL;
}
ddr.video_state = state;
return count;
@@ -383,7 +472,7 @@ static int ddrfreq_init(void)
{
int i, ret;
struct cpufreq_frequency_table *table;
bool new_version = false;
int ddrfreq_version = 0;
init_waitqueue_head(&ddr.wait);
ddr.video_state = '0';
@@ -409,16 +498,22 @@ static int ddrfreq_init(void)
for (i = 0; table && table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (table[i].frequency % 1000) {
new_version = true;
ddrfreq_version = 1;
}
if (table[i].frequency % 1000 > 100) {
ddrfreq_version = 2;
break;
}
}
if (!new_version) {
if (ddrfreq_version==0) {
ddr.video_rate = 300 * MHZ;
ddr.dualview_rate = ddr.normal_rate;
ddr.suspend_rate = 200 * MHZ;
}
for (i = 0; new_version && table && table[i].frequency != CPUFREQ_TABLE_END; i++) {
for (i = 0; ddrfreq_version == 1 && table && table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int mode = table[i].frequency % 1000;
unsigned long rate;
@@ -429,6 +524,9 @@ static int ddrfreq_init(void)
case DDR_FREQ_NORMAL:
ddr.normal_rate = rate;
break;
case DDR_FREQ_VIDEO_LOW:
ddr.video_low_rate = rate;
break;
case DDR_FREQ_VIDEO:
ddr.video_rate = rate;
break;
@@ -444,6 +542,32 @@ static int ddrfreq_init(void)
}
}
for (i = 0; ddrfreq_version == 2 && table && table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int mode = table[i].frequency % 1000;
unsigned long rate;
table[i].frequency -= mode;
rate = table[i].frequency * 1000;
if( (mode&DDR_FREQ_NORMAL) == DDR_FREQ_NORMAL)
ddr.normal_rate = rate;
if( (mode&DDR_FREQ_VIDEO_LOW) == DDR_FREQ_VIDEO_LOW)
ddr.video_low_rate = rate;
if( (mode&DDR_FREQ_VIDEO) == DDR_FREQ_VIDEO)
ddr.video_rate = rate;
if( (mode&DDR_FREQ_DUALVIEW) == DDR_FREQ_DUALVIEW)
ddr.dualview_rate= rate;
if( (mode&DDR_FREQ_IDLE) == DDR_FREQ_IDLE)
ddr.idle_rate = rate;
if( (mode&DDR_FREQ_SUSPEND) == DDR_FREQ_SUSPEND)
ddr.suspend_rate = rate;
}
if (ddr.idle_rate) {
REGISTER_CLK_NOTIFIER(pd_gpu);
REGISTER_CLK_NOTIFIER(pd_rga);
@@ -501,9 +625,9 @@ static int ddrfreq_late_init(void)
register_reboot_notifier(&ddrfreq_reboot_notifier);
pr_info("verion 2.4 20130427\n");
dprintk(DEBUG_DDR, "normal %luMHz video %luMHz dualview %luMHz idle %luMHz suspend %luMHz reboot %luMHz\n",
ddr.normal_rate / MHZ, ddr.video_rate / MHZ, ddr.dualview_rate / MHZ,ddr.idle_rate / MHZ, ddr.suspend_rate / MHZ, ddr.reboot_rate / MHZ);
pr_info("verion 3.1 20130805\n");
dprintk(DEBUG_DDR, "normal %luMHz video %luMHz video_low %luMHz dualview %luMHz idle %luMHz suspend %luMHz reboot %luMHz\n",
ddr.normal_rate / MHZ, ddr.video_rate / MHZ, ddr.video_low_rate / MHZ, ddr.dualview_rate / MHZ, ddr.idle_rate / MHZ, ddr.suspend_rate / MHZ, ddr.reboot_rate / MHZ);
return 0;

87
arch/arm/plat-rk/ddr_test.c Normal file → Executable file
View File

@@ -8,6 +8,21 @@
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <mach/ddr.h>
struct ddrtest {
struct clk *pll;
struct clk *clk;
volatile unsigned int freq;
volatile bool change_end;
struct task_struct *task;
wait_queue_head_t wait;
};
static struct ddrtest ddrtest;
static ssize_t ddr_proc_write(struct file *file, const char __user *buffer,
unsigned long len, void *data)
{
@@ -52,10 +67,14 @@ static ssize_t ddr_proc_write(struct file *file, const char __user *buffer,
p=strsep(&cookie_pot,"M");
value = simple_strtol(p,NULL,10);
printk("change!!! freq=%dMHz\n", value);
clk_set_rate(clk_ddr, value * 1000000);
//clk_set_rate(clk_ddr, value * 1000000);
ddrtest.freq = value;
ddrtest.change_end = false;
wake_up(&ddrtest.wait);
while(ddrtest.change_end != true); //wait change freq end
value = clk_get_rate(clk_ddr) / 1000000;
printk("success!!! freq=%dMHz\n", value);
msleep(32);
msleep(64);
printk("\n");
}
else
@@ -92,10 +111,14 @@ static ssize_t ddr_proc_write(struct file *file, const char __user *buffer,
}while(value < value1);
printk("change!!! freq=%dMHz\n", value);
clk_set_rate(clk_ddr, value * 1000000);
//clk_set_rate(clk_ddr, value * 1000000);
ddrtest.freq = value;
ddrtest.change_end = false;
wake_up(&ddrtest.wait);
while(ddrtest.change_end != true); //wait change freq end
value = clk_get_rate(clk_ddr) / 1000000;
printk("success!!! freq=%dMHz\n", value);
msleep(32);
msleep(64);
count++;
}
@@ -140,10 +163,14 @@ static ssize_t ddr_proc_write(struct file *file, const char __user *buffer,
}
printk("change!!! freq=%dMHz\n", value);
clk_set_rate(clk_ddr, value * 1000000);
//clk_set_rate(clk_ddr, value * 1000000);
ddrtest.freq = value;
ddrtest.change_end = false;
wake_up(&ddrtest.wait);
while(ddrtest.change_end != true); //wait change freq end
value = clk_get_rate(clk_ddr) / 1000000;
printk("success!!! freq=%dMHz\n", value);
msleep(32);
msleep(64);
count++;
}
@@ -176,19 +203,65 @@ static const struct file_operations ddr_proc_fops = {
.owner = THIS_MODULE,
};
static void ddrtest_work(unsigned int value)
{
clk_set_rate(ddrtest.clk, value * 1000000);
ddrtest.change_end = true;
}
static int ddrtest_task(void *data)
{
set_freezable();
do {
//unsigned long status = ddr.sys_status;
ddrtest_work(ddrtest.freq);
wait_event_freezable(ddrtest.wait, (ddrtest.change_end == false ) || kthread_should_stop());
} while (!kthread_should_stop());
return 0;
}
static int ddr_proc_init(void)
{
struct proc_dir_entry *ddr_proc_entry;
int ret;
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
init_waitqueue_head(&ddrtest.wait);
ddrtest.pll = clk_get(NULL, "ddr_pll");
ddrtest.clk = clk_get(NULL, "ddr");
if (IS_ERR(ddrtest.clk)) {
ret = PTR_ERR(ddrtest.clk);
ddrtest.clk = NULL;
pr_err("failed to get ddr clk, error %d\n", ret);
return ret;
}
ddr_proc_entry = create_proc_entry("driver/ddr_ts", 0777, NULL);
if(ddr_proc_entry != NULL)
{
ddr_proc_entry->write_proc = ddr_proc_write;
return -1;
//return -1;
}
else
{
printk("create proc error !\n");
}
ddrtest.task = kthread_create(ddrtest_task, NULL, "ddrtestd");
if (IS_ERR(ddrtest.task)) {
ret = PTR_ERR(ddrtest.task);
pr_err("failed to create kthread! error %d\n", ret);
goto err;
}
sched_setscheduler_nocheck(ddrtest.task,SCHED_FIFO, &param);
get_task_struct(ddrtest.task);
kthread_bind(ddrtest.task, 0);
wake_up_process(ddrtest.task);
err:
return 0;
}

View File

@@ -555,8 +555,7 @@ void __sramfunc board_pmu_resume(void);
* For DDR frequency scaling setup. Board code something like this:
*
* This array _must_ be sorted in ascending frequency (without DDR_FREQ_*) order.
* 必须按频率不必考虑DDR_FREQ_*)递增
*static struct cpufreq_frequency_table dvfs_ddr_table[] = {
* 必须按频率不必考虑DDR_FREQ_*)递增<EFBFBD><EFBFBD>? *static struct cpufreq_frequency_table dvfs_ddr_table[] = {
* {.frequency = 200 * 1000 + DDR_FREQ_SUSPEND, .index = xxxx * 1000},
* {.frequency = 200 * 1000 + DDR_FREQ_IDLE, .index = xxxx * 1000},
* {.frequency = 300 * 1000 + DDR_FREQ_VIDEO, .index = xxxx * 1000},
@@ -565,11 +564,12 @@ void __sramfunc board_pmu_resume(void);
*};
*/
enum ddr_freq_mode {
DDR_FREQ_NORMAL = 1, // default
DDR_FREQ_VIDEO, // when video is playing
DDR_FREQ_DUALVIEW, // when dual view,lcdc0 and lcdc1 open at the same time
DDR_FREQ_IDLE, // when screen is idle
DDR_FREQ_SUSPEND, // when early suspend
DDR_FREQ_SUSPEND=(0x1<<0), // when early suspend
DDR_FREQ_VIDEO=(0x1<<1), // when video is playing
DDR_FREQ_VIDEO_LOW=(0x1<<2), // when video is playing low
DDR_FREQ_DUALVIEW=(0x1<<3), // when dual view,lcdc0 and lcdc1 open at the same time
DDR_FREQ_IDLE=(0x1<<4), // when screen is idle
DDR_FREQ_NORMAL=(0x1<<8), // default
};
#endif

View File

@@ -149,7 +149,14 @@ void __sramfunc ddr_resume(void);
#if defined(CONFIG_ARCH_RK2928) || defined(CONFIG_ARCH_RK3026)
uint32_t __sramfunc ddr_change_freq(uint32_t nMHz);
#else
struct ddr_freq_t {
unsigned long screen_ft_us;
unsigned long long t0;
unsigned long long t1;
unsigned long t2;
};
uint32_t ddr_change_freq(uint32_t nMHz);
uint32_t __sramfunc ddr_change_freq_sram(uint32_t nMHz , struct ddr_freq_t ddr_freq_t);
#endif
uint32_t ddr_get_cap(void);
int ddr_init(uint32_t dram_type, uint32_t freq);
@@ -160,4 +167,8 @@ uint32_t __sramlocalfunc ddr_set_pll_rk3066b(uint32_t nMHz, uint32_t set);
int ddr_get_datatraing_value_3168(bool end_flag,uint32_t dqstr_value,uint32_t min_freq);
#endif
#if defined(CONFIG_ARCH_RK3066B) || defined(CONFIG_ARCH_RK3188)
#define DDR_CHANGE_FREQ_IN_LCDC_VSYNC
#endif
#endif