rk30sdk:reduce DDR frequency and enable auto self refresh when earlysuspend.
authorcym <cym@rock-chips.com>
Fri, 8 Jun 2012 07:12:59 +0000 (15:12 +0800)
committercym <cym@rock-chips.com>
Fri, 8 Jun 2012 07:12:59 +0000 (15:12 +0800)
select "Enable DDR frequency scaling" to enable this function,and when select
"Enable DDR frequency scaling" auto select "Sound DMA buffer in internal SRAM"

arch/arm/mach-rk30/Makefile
arch/arm/mach-rk30/ddr.c
arch/arm/mach-rk30/ddr_freq.c [new file with mode: 0644]
arch/arm/mach-rk30/include/mach/ddr.h
arch/arm/plat-rk/Kconfig

index f688abc484250d63fe170ec4ca406a78f6af37ea..85fa2de46b93f679c4e27b87ffeb7978ccabe1eb 100755 (executable)
@@ -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
index 29e9853c000195ef2e88339ee972ceb5a3897a00..e10fc09b1e8e0c3517ba7c9633c898fd76f5fdca 100755 (executable)
@@ -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 (file)
index 0000000..3d8ce2e
--- /dev/null
@@ -0,0 +1,273 @@
+#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
index 435136566bd1657adb2a68b1d3789272c47a54d7..6fa7881f273214cf756e60b387031b3172f4ac32 100755 (executable)
@@ -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
index feeb4da065c11ba34ad90d0f0e03d9e957c78627..04f708017a24e9146241d789971cb303265fb581 100644 (file)
@@ -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"