From: cym Date: Wed, 26 Sep 2012 08:05:50 +0000 (+0800) Subject: rk2928:add reduce DDR frequency and enable auto self refresh when earlysuspend. X-Git-Tag: firefly_0821_release~8564 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=94e02f9c88cc505f0b7468ac718a67417bc69270;p=firefly-linux-kernel-4.4.55.git rk2928:add reduce DDR frequency and enable auto self refresh when earlysuspend. select "System Type"--->"Enable DDR frequency scaling" to enable this function. --- diff --git a/arch/arm/mach-rk2928/ddr_freq.c b/arch/arm/mach-rk2928/ddr_freq.c index 5a42d4ae58f9..357f3196b5c6 100644 --- a/arch/arm/mach-rk2928/ddr_freq.c +++ b/arch/arm/mach-rk2928/ddr_freq.c @@ -1,7 +1,10 @@ #include #include +#include +#include #include +#include #define ddr_print(x...) printk( "DDR DEBUG: " x ) @@ -22,29 +25,224 @@ static struct ddr ddr = { }, }; +uint32_t ddr_set_rate(uint32_t nMHz) +{ + nMHz = ddr_change_freq(nMHz); + clk_set_rate(ddr.ddr_pll, 0); + return nMHz; +} #ifdef CONFIG_HAS_EARLYSUSPEND +static uint32_t ddr_resume_freq=DDR_FREQ; +static uint32_t ddr_suspend_freq=130; static void ddr_early_suspend(struct early_suspend *h) { + uint32_t value; + //Enable auto self refresh 0x01*32 DDR clk cycle - ddr_print("run in %s\n",__func__); ddr_set_auto_self_refresh(true); + ddr_resume_freq=clk_get_rate(ddr.ddr_pll)/1000000; + value = ddr_set_rate(ddr_suspend_freq); + ddr_print("init success!!! freq=%dMHz\n", value); + return; } static void ddr_late_resume(struct early_suspend *h) { + uint32_t value; + //Disable auto self refresh - ddr_print("run in %s\n",__func__); ddr_set_auto_self_refresh(false); + value = ddr_set_rate(ddr_resume_freq); + ddr_print("init success!!! freq=%dMHz\n", value); + return; } static int rk30_ddr_late_init (void) { + ddr.ddr_pll = clk_get(NULL, "ddr_pll"); register_early_suspend(&ddr.early_suspend); return 0; } late_initcall(rk30_ddr_late_init); #endif + +#ifdef CONFIG_DDR_TEST +#include +#include +#include +#include +#include +#include +#include + +static ssize_t ddr_proc_write(struct file *file, const char __user *buffer, + unsigned long len, void *data) +{ + char *cookie_pot; + char *p; + uint32_t value, value1, value2; + uint32_t count, total; + char tmp; + bool cpu1_online; + cookie_pot = (char *)vmalloc( len ); + memset(cookie_pot,0,len); + + if (!cookie_pot) + { + return -ENOMEM; + } + else + { + if (copy_from_user( cookie_pot, buffer, len )) + return -EFAULT; + } + + switch(cookie_pot[0]) + { + case 'c': + case 'C': + printk("change ddr freq:\n"); + if(cookie_pot[1] ==':') + { + strsep(&cookie_pot,":"); + p=strsep(&cookie_pot,"M"); + value = simple_strtol(p,NULL,10); + printk("change!!! freq=%dMHz\n", value); + value=ddr_set_rate(value); + printk("success!!! freq=%dMHz\n", value); + msleep(32); + printk("\n"); + } + else + { + printk("Error auto change ddr freq debug.\n"); + printk("-->'c&&C' change freq,Example: echo 'c:400M' > ddr_test\n"); + } + break; + + case 'a': + case 'A': + printk("auto change ddr freq test (random):\n"); + if(cookie_pot[1] ==':') + { + strsep(&cookie_pot,":"); + p=strsep(&cookie_pot,"M"); + value1 = simple_strtol(p,NULL,10); + strsep(&cookie_pot,"-"); + p=strsep(&cookie_pot,"M"); + value2 = simple_strtol(p,NULL,10); + strsep(&cookie_pot,"-"); + p=strsep(&cookie_pot,"T"); + total = simple_strtol(p,NULL,10); + + count = 0; + + while ( count < total ) + { + printk("auto change ddr freq test (random):[%d-%d]\n",count,total); + do + { + value = value1 + random32(); + value %= value2; + }while(value < value1); + + printk("change!!! freq=%dMHz\n", value); + value=ddr_set_rate(value); + printk("success!!! freq=%dMHz\n", value); + msleep(32); + count++; + } + + } + else + { + printk("Error auto change ddr freq test debug.\n"); + printk("-->'a&&A' auto change ddr freq test (random),Example: echo 'a:200M-400M-1000T' > ddr_test\n"); + } + break; + + case 'b': + case 'B': + printk("auto change ddr freq test (specific):\n"); + if(cookie_pot[1] ==':') + { + strsep(&cookie_pot,":"); + p=strsep(&cookie_pot,"M"); + value1 = simple_strtol(p,NULL,10); + strsep(&cookie_pot,"-"); + p=strsep(&cookie_pot,"M"); + value2 = simple_strtol(p,NULL,10); + strsep(&cookie_pot,"-"); + p=strsep(&cookie_pot,"T"); + total = simple_strtol(p,NULL,10); + + count = 0; + + while ( count < total ) + { + printk("auto change ddr freq test (specific):[%d-%d]\n",count,total); + if(tmp == 1) + { + value = value1; + tmp = 0; + } + else + { + value = value2; + tmp = 1; + } + + printk("change!!! freq=%dMHz\n", value); + value=ddr_set_rate(value); + printk("success!!! freq=%dMHz\n", value); + msleep(32); + count++; + } + + } + else + { + printk("Error auto change ddr freq test debug.\n"); + printk("-->'b&&B' auto change ddr freq test (specific),Example: echo 'a:200M-400M-1000T' > ddr_test\n"); + } + break; + + case 'h': + case 'H': + default: + printk("Help for ddr_ts .\n-->The Cmd list: \n"); + printk("-->'a&&A' auto change ddr freq test (random),Example: echo 'a:200M-400M-100T' > ddr_test\n"); + printk("-->'b&&B' auto change ddr freq test (specific),Example: echo 'b:200M-400M-100T' > ddr_test\n"); + printk("-->'c&&C' change freq,Example: echo 'c:400M' > ddr_test\n"); + break; + } + + return len; +} + +static const struct file_operations ddr_proc_fops = { + .owner = THIS_MODULE, +}; + +static int ddr_proc_init(void) +{ + struct proc_dir_entry *ddr_proc_entry; + 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; + } + else + { + printk("create proc error !\n"); + } + return 0; +} + +late_initcall(ddr_proc_init); +#endif //CONFIG_DDR_TEST