From 425c1cef9769e72284dd355ea6614666e00e7d19 Mon Sep 17 00:00:00 2001
From: cym <cym@rock-chips.com>
Date: Fri, 8 Jun 2012 15:12:59 +0800
Subject: [PATCH] rk30sdk:reduce DDR frequency and enable auto self refresh
 when earlysuspend.

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           |   1 +
 arch/arm/mach-rk30/ddr.c              | 179 +++++++++++++++--
 arch/arm/mach-rk30/ddr_freq.c         | 273 ++++++++++++++++++++++++++
 arch/arm/mach-rk30/include/mach/ddr.h |   1 +
 arch/arm/plat-rk/Kconfig              |   1 +
 5 files changed, 438 insertions(+), 17 deletions(-)
 create mode 100644 arch/arm/mach-rk30/ddr_freq.c

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 <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
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"
-- 
2.34.1