diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index f688abc48425..85fa2de46b93 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_DVFS) += dvfs.o +obj-$(CONFIG_DDR_FREQ) += ddr_freq.o obj-$(CONFIG_MACH_RK3066_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o diff --git a/arch/arm/mach-rk30/ddr.c b/arch/arm/mach-rk30/ddr.c index 29e9853c0001..e10fc09b1e8e 100755 --- a/arch/arm/mach-rk30/ddr.c +++ b/arch/arm/mach-rk30/ddr.c @@ -26,6 +26,8 @@ typedef uint32_t uint32; #define DDR3_DDR2_DLL_DISABLE_FREQ (125) #define DDR3_DDR2_ODT_DISABLE_FREQ (333) +#define SR_IDLE (0x0) //unit:32*DDR clk cycle, and 0 for disable auto self-refresh +#define PD_IDLE (0X40) //unit:DDR clk cycle, and 0 for disable auto power-down #define PMU_BASE_ADDR RK30_PMU_BASE #define SDRAMC_BASE_ADDR RK30_DDR_PCTL_BASE @@ -117,9 +119,11 @@ typedef uint32_t uint32; #define DDR3_CL(n) (((((n)-4)&0x7)<<4)|((((n)-4)&0x8)>>1)) #define DDR3_WR(n) (((n)&0x7)<<9) #define DDR3_DLL_RESET (1<<8) -#define DDR3_DLL_DISABLE (0<<8) +#define DDR3_DLL_DeRESET (0<<8) - //mr1 for ddr3 +//mr1 for ddr3 +#define DDR3_DLL_ENABLE (0) +#define DDR3_DLL_DISABLE (1) #define DDR3_MR1_AL(n) (((n)&0x7)<<3) #define DDR3_DS_40 (0) @@ -144,9 +148,12 @@ typedef uint32_t uint32; #define DDR2_CL(n) (((n)&0x7)<<4) #define DDR2_WR(n) ((((n)-1)&0x7)<<9) #define DDR2_DLL_RESET (1<<8) -#define DDR2_DLL_DISABLE (0<<8) +#define DDR2_DLL_DeRESET (0<<8) //EMR; //Extended Mode Register +#define DDR2_DLL_ENABLE (0) +#define DDR2_DLL_DISABLE (1) + #define DDR2_STR_FULL (0) #define DDR2_STR_REDUCE (1<<1) #define DDR2_AL(n) (((n)&0x7)<<3) @@ -184,6 +191,14 @@ typedef uint32_t uint32; #define idle_video (1<<23) #define idle_vio (1<<22) +#define pd_a9_0_pwr_st (1<<0) +#define pd_a9_1_pwr_st (1<<1) +#define pd_peri_pwr_st (1<<6) +#define pd_vio_pwr_st (1<<7) +#define pd_video_pwr_st (1<<8) +#define pd_gpu_pwr_st (1<<9) + + //PMU registers typedef volatile struct tagPMU_FILE { @@ -890,6 +905,7 @@ __sramdata uint32_t mem_type; // 0:LPDDR, 1:DDR, 2:DDR2, 3:DDR3, 4:LPDDR2 static __sramdata uint32_t ddr_speed_bin; // used for ddr3 only static __sramdata uint32_t ddr_capability_per_die; // one chip cs capability static __sramdata uint32_t ddr_freq; +static __sramdata uint32_t ddr_sr_idle; /**************************************************************************** Internal sram us delay function @@ -1016,7 +1032,6 @@ __sramfunc void ddr_move_to_Lowpower_state(void) break; } switch(value) - { case Init_mem: pDDR_Reg->SCTL = CFG_STATE; @@ -1038,15 +1053,18 @@ __sramfunc void ddr_move_to_Access_state(void) { volatile uint32 value; + //set auto self-refresh idle + pDDR_Reg->MCFG1=(pDDR_Reg->MCFG1&0xffffff00)|ddr_sr_idle; + while(1) { value = pDDR_Reg->STAT.b.ctl_stat; - if(value == Access) + if((value == Access) + || ((pDDR_Reg->STAT.b.lp_trig == 1) && ((pDDR_Reg->STAT.b.ctl_stat) == Low_power))) { break; } switch(value) - { case Low_power: pDDR_Reg->SCTL = WAKEUP_STATE; @@ -1058,7 +1076,8 @@ __sramfunc void ddr_move_to_Access_state(void) while((pDDR_Reg->STAT.b.ctl_stat) != Config); case Config: pDDR_Reg->SCTL = GO_STATE; - while((pDDR_Reg->STAT.b.ctl_stat) != Access); + while(!(((pDDR_Reg->STAT.b.ctl_stat) == Access) + || ((pDDR_Reg->STAT.b.lp_trig == 1) && ((pDDR_Reg->STAT.b.ctl_stat) == Low_power)))); break; default: //Transitional state break; @@ -1070,6 +1089,13 @@ __sramfunc void ddr_move_to_Config_state(void) { volatile uint32 value; + //clear auto self-refresh idle + if(pDDR_Reg->MCFG1 & 0xFF) + { + pDDR_Reg->MCFG1=(pDDR_Reg->MCFG1&0xffffff00)|0x0; + dsb(); + } + while(1) { value = pDDR_Reg->STAT.b.ctl_stat; @@ -2653,7 +2679,12 @@ __sramfunc void ddr_adjust_config(uint32_t dram_type) pPHY_Reg->DTAR = value; //set auto power down idle - pDDR_Reg->MCFG=(pDDR_Reg->MCFG&0xffff00ff)|(0x40<<8); + pDDR_Reg->MCFG=(pDDR_Reg->MCFG&0xffff00ff)|(PD_IDLE<<8); + + //set auto self-refresh idle + ddr_sr_idle = SR_IDLE; + + pPHY_Reg->PGCR &= ~(0x3<<12); ddr_update_odt(); @@ -2663,6 +2694,106 @@ __sramfunc void ddr_adjust_config(uint32_t dram_type) DDR_RESTORE_SP(save_sp); } + +void __sramlocalfunc idle_port(void) +{ + int i; + uint32 clk_gate[10]; + + //save clock gate status + for(i=0;i<10;i++) + clk_gate[i]=pCRU_Reg->CRU_CLKGATE_CON[i]; + + //enable all clock gate for request idle + for(i=0;i<10;i++) + pCRU_Reg->CRU_CLKGATE_CON[i]=0xffff0000; + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_a9_0_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 |= idle_req_cpu_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_cpu) == 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_peri_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 |= idle_req_peri_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_peri) == 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_vio_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 |= idle_req_vio_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_vio) == 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_video_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 |= idle_req_video_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_video) == 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_gpu_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 |= idle_req_gpu_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_gpu) == 0 ); + } + + //resume clock gate status + for(i=0;i<10;i++) + pCRU_Reg->CRU_CLKGATE_CON[i]= (clk_gate[i] | 0xffff0000); +} + +void __sramlocalfunc deidle_port(void) +{ + int i; + uint32 clk_gate[10]; + + //save clock gate status + for(i=0;i<10;i++) + clk_gate[i]=pCRU_Reg->CRU_CLKGATE_CON[i]; + + //enable all clock gate for request idle + for(i=0;i<10;i++) + pCRU_Reg->CRU_CLKGATE_CON[i]=0xffff0000; + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_a9_0_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_cpu_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_cpu) != 0 ); + } + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_peri_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_peri_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_peri) != 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_vio_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_vio_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_vio) != 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_video_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_video_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_video) != 0 ); + } + + if ( (pPMU_Reg->PMU_PWRDN_ST & pd_gpu_pwr_st) == 0 ) + { + pPMU_Reg->PMU_MISC_CON1 &= ~idle_req_gpu_cfg; + while( (pPMU_Reg->PMU_PWRDN_ST & idle_gpu) != 0 ); + } + + //resume clock gate status + for(i=0;i<10;i++) + pCRU_Reg->CRU_CLKGATE_CON[i]= (clk_gate[i] | 0xffff0000); + +} + + + + void __sramlocalfunc ddr_selfrefresh_enter(uint32 nMHz) { uint32 cs; @@ -2730,6 +2861,7 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) /** 1. Make sure there is no host access */ local_irq_save(flags); + local_fiq_disable(); flush_cache_all(); outer_flush_all(); flush_tlb_all(); @@ -2748,16 +2880,20 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) dsb(); /** 2. ddr enter self-refresh mode or precharge power-down mode */ + idle_port(); ddr_selfrefresh_enter(ret); - + /** 3. change frequence */ ddr_set_pll(ret,1); ddr_freq = ret; /** 5. Issues a Mode Exit command */ ddr_selfrefresh_exit(); - dsb(); + deidle_port(); + + dsb(); DDR_RESTORE_SP(save_sp); + local_fiq_enable(); local_irq_restore(flags); clk_set_rate(clk_get(NULL, "ddr_pll"), 0); return ret; @@ -2765,6 +2901,14 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz) EXPORT_SYMBOL(ddr_change_freq); +void ddr_set_auto_self_refresh(uint32_t sr_idle_time) +{ + ddr_sr_idle=sr_idle_time; +} + +EXPORT_SYMBOL(ddr_set_auto_self_refresh); + + void __sramfunc ddr_suspend(void) { u32 i; @@ -2773,14 +2917,14 @@ void __sramfunc ddr_suspend(void) /** 1. Make sure there is no host access */ flush_cache_all(); - outer_flush_all(); - flush_tlb_all(); + outer_flush_all(); + flush_tlb_all(); - for(i=0;i<16;i++) - { - n=temp[1024*i]; + for(i=0;i<16;i++) + { + n=temp[1024*i]; barrier(); - } + } n= pDDR_Reg->SCFG.d32; n= pPHY_Reg->RIDR; n= pCRU_Reg->CRU_PLL_CON[0][0]; @@ -2866,7 +3010,8 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq) mem_type = pPHY_Reg->DCR.b.DDRMD; ddr_speed_bin = dram_speed_bin; - ddr_freq = freq; + ddr_freq = freq; + ddr_sr_idle = 0; switch(mem_type) { case DDR3: diff --git a/arch/arm/mach-rk30/ddr_freq.c b/arch/arm/mach-rk30/ddr_freq.c new file mode 100644 index 000000000000..3d8ce2ea0448 --- /dev/null +++ b/arch/arm/mach-rk30/ddr_freq.c @@ -0,0 +1,273 @@ +#include + +#include +#include +#include +#include + +#define ddr_print(x...) printk( "DDR DEBUG: " x ) + +struct ddr{ + int suspend; + struct early_suspend early_suspend; +}; +struct ddr *ddr = NULL; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ddr_early_suspend(struct early_suspend *h) +{ + + uint32_t value; + bool cpu1_online; + + //Enable auto self refresh 0x01*32 DDR clk cycle + ddr_set_auto_self_refresh(0x01); + + cpu1_online = cpu_online(1); + if(cpu1_online) + cpu_down(1); + + value=ddr_change_freq(100); + + if(cpu1_online) + cpu_up(1); + ddr_print("init success!!! freq=%dMHz\n", value); + + return; +} + +static void ddr_early_resume(struct early_suspend *h) +{ + + uint32_t value; + bool cpu1_online; + + //Disable auto self refresh + ddr_set_auto_self_refresh(0x00); + + cpu1_online = cpu_online(1); + if(cpu1_online) + cpu_down(1); + + value=ddr_change_freq(DDR_FREQ); + + if(cpu1_online) + cpu_up(1); + ddr_print("init success!!! freq=%dMHz\n", value); + + return; +} +#endif + + +static int rk30_ddr_late_init (void) +{ + + ddr = kmalloc(sizeof(struct ddr), GFP_KERNEL); + if(!ddr) + { + ddr_print("%s: kmalloc fail!\n",__FUNCTION__); + return -ENOMEM; + } + memset(ddr, 0, sizeof(struct ddr)); +#ifdef CONFIG_HAS_EARLYSUSPEND + ddr->early_suspend.suspend = ddr_early_suspend; + ddr->early_suspend.resume = ddr_early_resume; + ddr->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50; + register_early_suspend(&ddr->early_suspend); +#endif + return 0; +} +late_initcall(rk30_ddr_late_init); + + +#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); + cpu1_online=cpu_online(1); + if(cpu1_online) + cpu_down(1); + value=ddr_change_freq(value); + if(cpu1_online) + cpu_up(1); + printk("success!!! freq=%dMHz\n", value); + 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); + + cpu1_online=cpu_online(1); + if(cpu1_online) + cpu_down(1); + msleep(32); + value=ddr_change_freq(value); + if(cpu1_online) + cpu_up(1); + printk("success!!! freq=%dMHz\n", value); + + 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); + cpu1_online=cpu_online(1); + if(cpu1_online) + cpu_down(1); + msleep(32); + value=ddr_change_freq(value); + if(cpu1_online) + cpu_up(1); + printk("success!!! freq=%dMHz\n", value); + 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; + + 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 diff --git a/arch/arm/mach-rk30/include/mach/ddr.h b/arch/arm/mach-rk30/include/mach/ddr.h index 435136566bd1..6fa7881f2732 100755 --- a/arch/arm/mach-rk30/include/mach/ddr.h +++ b/arch/arm/mach-rk30/include/mach/ddr.h @@ -148,5 +148,6 @@ void __sramfunc ddr_resume(void); //void __sramlocalfunc delayus(uint32_t us); uint32_t __sramfunc ddr_change_freq(uint32_t nMHz); int ddr_init(uint32_t dram_type, uint32_t freq); +void ddr_set_auto_self_refresh(uint32_t sr_idle_time); #endif diff --git a/arch/arm/plat-rk/Kconfig b/arch/arm/plat-rk/Kconfig index feeb4da065c1..04f708017a24 100644 --- a/arch/arm/plat-rk/Kconfig +++ b/arch/arm/plat-rk/Kconfig @@ -88,6 +88,7 @@ config DDR_SDRAM_FREQ config DDR_FREQ bool "Enable DDR frequency scaling" + select RK_SRAM_DMA config DDR_TEST bool "DDR Test"