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
#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
#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)
#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)
#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
{
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
break;
}
switch(value)
-
{
case Init_mem:
pDDR_Reg->SCTL = CFG_STATE;
{
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;
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;
{
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;
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();
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;
/** 1. Make sure there is no host access */
local_irq_save(flags);
+ local_fiq_disable();
flush_cache_all();
outer_flush_all();
flush_tlb_all();
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;
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;
/** 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];
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:
--- /dev/null
+#include <mach/ddr.h>
+
+#include <linux/earlysuspend.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+
+#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 <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <sound/pcm.h>
+#include <linux/random.h>
+
+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
//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
config DDR_FREQ
bool "Enable DDR frequency scaling"
+ select RK_SRAM_DMA
config DDR_TEST
bool "DDR Test"