#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)
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;
}
}
#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;
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
#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)
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);
}
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
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);
}
******************************************/
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);
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;
#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,
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 {
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;
&& (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))
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();
}
}
- 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)
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;
{
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';
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;
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;
}
}
+ 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);
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;
#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)
{
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
}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++;
}
}
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++;
}
.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, ¶m);
+ get_task_struct(ddrtest.task);
+ kthread_bind(ddrtest.task, 0);
+ wake_up_process(ddrtest.task);
+
+err:
return 0;
}
* 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[] = {
+ * å¿\85é¡»æ\8c\89é¢\91ç\8e\87ï¼\88ä¸\8då¿\85è\80\83è\99\91DDR_FREQ_*ï¼\89é\80\92å¢\9eã\80? *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},
*};
*/
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
#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);
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