rk3168: dvfs with uoc optimization
authorchenxing <chenxing@rock-chips.com>
Wed, 17 Apr 2013 04:07:08 +0000 (12:07 +0800)
committerchenxing <chenxing@rock-chips.com>
Wed, 17 Apr 2013 06:09:00 +0000 (14:09 +0800)
arch/arm/mach-rk30/dvfs-rk3066b.c

index 41940e0c6a545eb9903ddf9cfefe882185804455..f7eb4c825c242139d03152caa954be1f0862bfb6 100755 (executable)
 #define CLK_LOOPS_JIFFY_REF 11996091ULL\r
 #define CLK_LOOPS_RATE_REF (1200) //Mhz\r
 #define CLK_LOOPS_RECALC(new_rate)  div_u64(CLK_LOOPS_JIFFY_REF*(new_rate),CLK_LOOPS_RATE_REF*MHZ)\r
-struct clk *clk_cpu_div = NULL, *arm_pll_clk = NULL, *general_pll_clk = NULL;\r
+struct clk *clk_cpu = NULL, *clk_cpu_div = NULL, *arm_pll_clk = NULL, *general_pll_clk = NULL;\r
 unsigned long lpj_24m;\r
 \r
+struct gate_delay_table {\r
+       unsigned long arm_perf;\r
+       unsigned long log_perf;\r
+       unsigned long delay;\r
+};\r
+\r
+struct cycle_by_rate {\r
+       unsigned long rate_khz;\r
+       unsigned long cycle_ns;\r
+};\r
+\r
+struct uoc_val_xx2delay {\r
+       unsigned long volt;\r
+       unsigned long perf;\r
+       unsigned long uoc_val_01;\r
+       unsigned long uoc_val_11;\r
+};\r
+\r
+struct dvfs_volt_performance {\r
+       unsigned long   volt;\r
+       unsigned long   perf;   // Gate performance\r
+};\r
 static int rk_dvfs_clk_notifier_event(struct notifier_block *this,\r
                unsigned long event, void *ptr)\r
 {\r
@@ -132,24 +154,6 @@ static unsigned long dvfs_volt_log_support_table[] = {
        1300 * 1000,\r
 };\r
 \r
-static struct clk_node *dvfs_clk_cpu;\r
-static struct vd_node vd_core;\r
-static struct vd_node vd_cpu;\r
-struct dvfs_volt_performance {\r
-       unsigned long   volt;\r
-       unsigned long   perf;   // Gate performance\r
-};\r
-\r
-struct gate_delay_table {\r
-       unsigned long arm_perf;\r
-       unsigned long log_perf;\r
-       unsigned long delay;\r
-};\r
-\r
-struct cycle_by_rate {\r
-       unsigned long rate_khz;\r
-       unsigned long cycle_ns;\r
-};\r
 /*\r
  * 电压 dly_line 每增加0.1V的增量 每增加0.1V增加的比例 与1v对比增加的比例\r
  * 1.00  128\r
@@ -215,7 +219,15 @@ int uoc_val = 0;
 #define SIZE_SUPPORT_ARM_VOLT  ARRAY_SIZE(dvfs_volt_arm_support_table)\r
 #define SIZE_SUPPORT_LOG_VOLT  ARRAY_SIZE(dvfs_volt_log_support_table)\r
 #define SIZE_VP_TABLE          ARRAY_SIZE(dvfs_vp_table)\r
+#define SIZE_ARM_FREQ_TABLE    10\r
+static struct cycle_by_rate rate_cycle[SIZE_ARM_FREQ_TABLE];\r
+int size_dvfs_arm_table = 0;\r
+\r
+static struct clk_node *dvfs_clk_cpu;\r
+static struct vd_node vd_core;\r
+static struct vd_node vd_cpu;\r
 \r
+static struct uoc_val_xx2delay uoc_val_xx[SIZE_VP_TABLE];\r
 static struct gate_delay_table gate_delay[SIZE_VP_TABLE][SIZE_VP_TABLE];\r
 \r
 static unsigned long dvfs_get_perf_byvolt(unsigned long volt)\r
@@ -252,9 +264,9 @@ static int dvfs_gate_delay_init(void)
                        gate_delay[i][j].delay = dvfs_get_gate_delay_per_volt(gate_delay[i][j].arm_perf,\r
                                        gate_delay[i][j].log_perf);\r
 \r
-                       DVFS_DBG("%s: arm_perf=%lu, log_perf=%lu, delay=%lu\n", __func__,\r
-                                       gate_delay[i][j].arm_perf, gate_delay[i][j].log_perf,\r
-                                       gate_delay[i][j].delay);\r
+                       //DVFS_DBG("%s: arm_perf=%lu, log_perf=%lu, delay=%lu\n", __func__,\r
+                       //              gate_delay[i][j].arm_perf, gate_delay[i][j].log_perf,\r
+                       //              gate_delay[i][j].delay);\r
                }\r
        return 0;\r
 }\r
@@ -276,13 +288,6 @@ static unsigned long dvfs_get_gate_delay(unsigned long arm_perf, unsigned long l
        //              __func__, gate_delay[i][j].arm_perf , gate_delay[i][j].log_perf , gate_delay[i][j].delay);\r
        return gate_delay[i][j].delay;\r
 }\r
-struct uoc_val_xx2delay {\r
-       unsigned long volt;\r
-       unsigned long perf;\r
-       unsigned long uoc_val_01;\r
-       unsigned long uoc_val_11;\r
-};\r
-static struct uoc_val_xx2delay uoc_val_xx[SIZE_VP_TABLE];\r
 static int dvfs_uoc_val_delay_init(void)\r
 {\r
        int i = 0;\r
@@ -291,8 +296,8 @@ static int dvfs_uoc_val_delay_init(void)
                uoc_val_xx[i].perf = dvfs_vp_table[i].perf;\r
                uoc_val_xx[i].uoc_val_01 = UOC_VAL_01 * 1000 / uoc_val_xx[i].perf;\r
                uoc_val_xx[i].uoc_val_11 = UOC_VAL_11 * 1000 / uoc_val_xx[i].perf;\r
-               DVFS_DBG("%lu, %lu, %lu, %lu\n", uoc_val_xx[i].volt, uoc_val_xx[i].perf,\r
-                               uoc_val_xx[i].uoc_val_01, uoc_val_xx[i].uoc_val_11);\r
+               //DVFS_DBG("volt=%lu, perf=%lu, uoc_01=%lu, uoc_11=%lu\n", uoc_val_xx[i].volt, uoc_val_xx[i].perf,\r
+               //              uoc_val_xx[i].uoc_val_01, uoc_val_xx[i].uoc_val_11);\r
        }\r
        return 0;\r
 }\r
@@ -317,39 +322,77 @@ static unsigned long dvfs_get_uoc_val_xx_by_volt(unsigned long uoc_val_xx_delay,
        DVFS_ERR("%s can not find uoc_val_xx=%lu, with volt=%lu\n", __func__, uoc_val_xx_delay, volt);\r
        return uoc_val_xx_delay;\r
 }\r
-#define SIZE_ARM_FREQ_TABLE    10\r
-static struct cycle_by_rate rate_cycle[SIZE_ARM_FREQ_TABLE];\r
-int size_dvfs_arm_table = 0;\r
+struct dvfs_volt_uoc {\r
+       unsigned long   volt_log;\r
+       unsigned long   volt_arm_new;\r
+       unsigned long   volt_log_new;\r
+       int     uoc_val;\r
+};\r
+struct dvfs_uoc_val_table {\r
+       unsigned long   rate_arm;\r
+       unsigned long   volt_arm;\r
+       struct dvfs_volt_uoc    vu_list[SIZE_SUPPORT_LOG_VOLT];\r
+};\r
+struct dvfs_uoc_val_table dvfs_uoc_val_list[SIZE_ARM_FREQ_TABLE];\r
+\r
+static int dvfs_get_uoc_val_init(unsigned long *p_volt_arm_new, unsigned long *p_volt_log_new, \r
+               unsigned long rate_khz);\r
 static int dvfs_with_uoc_init(void)\r
 {\r
-       struct cpufreq_frequency_table *arm_freq_table;\r
+       struct cpufreq_frequency_table *dvfs_arm_table;\r
        struct clk *cpu_clk;\r
-       int i = 0;\r
+       int i = 0, j = 0;\r
+       unsigned long arm_volt_save = 0;\r
        cpu_clk = clk_get(NULL, "cpu");\r
        if (IS_ERR(cpu_clk))\r
                return PTR_ERR(cpu_clk);\r
 \r
-       arm_freq_table = dvfs_get_freq_volt_table(cpu_clk);\r
-\r
+       dvfs_arm_table = dvfs_get_freq_volt_table(cpu_clk);\r
        lpj_24m = CLK_LOOPS_RECALC(24 * MHZ);\r
        DVFS_DBG("24M=%lu cur_rate=%lu lpj=%lu\n", lpj_24m, arm_pll_clk->rate, loops_per_jiffy);\r
        dvfs_gate_delay_init();\r
        dvfs_uoc_val_delay_init();\r
 \r
-       for (i = 0; arm_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
+       for (i = 0; dvfs_arm_table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
                if (i > SIZE_ARM_FREQ_TABLE - 1) {\r
                        DVFS_WARNING("mach-rk30/dvfs.c:%s:%d: dvfs arm table to large, use only [%d] frequency\n",\r
                                        __func__, __LINE__, SIZE_ARM_FREQ_TABLE);\r
                        break;\r
                }\r
-               rate_cycle[i].rate_khz = arm_freq_table[i].frequency;\r
+               rate_cycle[i].rate_khz = dvfs_arm_table[i].frequency;\r
                rate_cycle[i].cycle_ns = (1000UL * VD_DELAY_ZOOM) / (rate_cycle[i].rate_khz / 1000);\r
                DVFS_DBG("%s: rate=%lu, cycle_ns=%lu\n",\r
                                __func__, rate_cycle[i].rate_khz, rate_cycle[i].cycle_ns);\r
        }\r
-\r
        size_dvfs_arm_table = i + 1;\r
 \r
+       //dvfs_uoc_val_list[];\r
+       for (i = 0; dvfs_arm_table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
+               dvfs_uoc_val_list[i].rate_arm = dvfs_arm_table[i].frequency;\r
+               dvfs_uoc_val_list[i].volt_arm = dvfs_arm_table[i].index;\r
+               arm_volt_save = dvfs_uoc_val_list[i].volt_arm;\r
+               for (j = 0; j < SIZE_SUPPORT_LOG_VOLT - 1; j++) {\r
+                       dvfs_uoc_val_list[i].vu_list[j].volt_log = dvfs_volt_log_support_table[j];\r
+                       dvfs_uoc_val_list[i].vu_list[j].volt_arm_new = arm_volt_save;\r
+                       dvfs_uoc_val_list[i].vu_list[j].volt_log_new = dvfs_uoc_val_list[i].vu_list[j].volt_log;\r
+                       //DVFS_DBG("%s: Rarm=%lu,Varm=%lu,Vlog=%lu\n", __func__,\r
+                       //              dvfs_uoc_val_list[i].rate_arm, dvfs_uoc_val_list[i].volt_arm,\r
+                       //              dvfs_uoc_val_list[i].vu_list[j].volt_log);\r
+\r
+                       dvfs_uoc_val_list[i].vu_list[j].uoc_val = dvfs_get_uoc_val_init(\r
+                                       &dvfs_uoc_val_list[i].vu_list[j].volt_arm_new, \r
+                                       &dvfs_uoc_val_list[i].vu_list[j].volt_log_new, \r
+                                       dvfs_uoc_val_list[i].rate_arm);\r
+                       DVFS_DBG("%s: Rarm=%lu,(Varm=%lu,Vlog=%lu)--->(Vn_arm=%lu,Vn_log=%lu), uoc=%d\n", __func__,\r
+                                       dvfs_uoc_val_list[i].rate_arm, dvfs_uoc_val_list[i].volt_arm,\r
+                                       dvfs_uoc_val_list[i].vu_list[j].volt_log,\r
+                                       dvfs_uoc_val_list[i].vu_list[j].volt_arm_new, \r
+                                       dvfs_uoc_val_list[i].vu_list[j].volt_log_new, \r
+                                       dvfs_uoc_val_list[i].vu_list[j].uoc_val);\r
+                       mdelay(10);\r
+               }\r
+       }\r
+\r
        return 0;\r
 }\r
 arch_initcall(dvfs_with_uoc_init);\r
@@ -420,7 +463,7 @@ static unsigned long dvfs_recalc_volt(unsigned long *p_volt_arm_new, unsigned lo
        return curr_delay;\r
 }\r
 \r
-static int dvfs_get_uoc_val(unsigned long *p_volt_arm_new, unsigned long *p_volt_log_new, unsigned long rate_khz)\r
+static int dvfs_get_uoc_val_init(unsigned long *p_volt_arm_new, unsigned long *p_volt_log_new, unsigned long rate_khz)\r
 {\r
        int uoc_val = 0;\r
        unsigned long arm_perf = 0, log_perf = 0;\r
@@ -456,23 +499,24 @@ static int dvfs_get_uoc_val(unsigned long *p_volt_arm_new, unsigned long *p_volt
                curr_delay = dvfs_recalc_volt(p_volt_arm_new, p_volt_log_new, arm_perf, log_perf,\r
                                hold, setup, UOC_NEED_INCREASE_LOG);\r
 \r
-               log_perf = dvfs_get_perf_byvolt(*p_volt_log_new);\r
+               //log_perf = dvfs_get_perf_byvolt(*p_volt_log_new);\r
+               uoc_val_01 = dvfs_get_uoc_val_xx_by_volt(UOC_VAL_01, *p_volt_log_new);\r
                uoc_val_11 = dvfs_get_uoc_val_xx_by_volt(UOC_VAL_11, *p_volt_log_new);\r
 \r
        } else if (curr_delay >= setup) {\r
                DVFS_DBG("%s Need to increase arm voltage\n", __func__);\r
                curr_delay = dvfs_recalc_volt(p_volt_arm_new, p_volt_log_new, arm_perf, log_perf,\r
                                hold, setup, UOC_NEED_INCREASE_ARM);\r
-               arm_perf = dvfs_get_perf_byvolt(*p_volt_arm_new);\r
-               uoc_val_01 = dvfs_get_uoc_val_xx_by_volt(UOC_VAL_01, *p_volt_log_new);\r
+               //arm_perf = dvfs_get_perf_byvolt(*p_volt_arm_new);\r
        }\r
 \r
-       DVFS_DBG("%s TARGET VOLT:arm(%lu), log(%lu);\tget perf arm(%lu), log(%lu)\n", __func__,\r
-                       *p_volt_arm_new, *p_volt_log_new, arm_perf, log_perf);\r
+       DVFS_DBG("TARGET VOLT:arm(%lu), log(%lu);\tget perf arm(%lu), log(%lu)\n",\r
+                       *p_volt_arm_new, *p_volt_log_new, \r
+                       dvfs_get_perf_byvolt(*p_volt_arm_new), dvfs_get_perf_byvolt(*p_volt_log_new));\r
        // update uoc_val_01/11 with new volt\r
-       //DVFS_DBG("%s cycle=%lu, hold-val11=%lu, hold-val01=%lu, (hold=%lu, setup=%lu), curr_delay=%lu\n",\r
-       //              __func__, cycle, get_uoc_delay(hold, uoc_val_11), get_uoc_delay(hold, uoc_val_01),\r
-       //              hold, setup, curr_delay);\r
+       DVFS_DBG("cycle=%lu, hold-val11=%lu, hold-val01=%lu, (hold=%lu, setup=%lu), curr_delay=%lu\n",\r
+                       cycle, get_uoc_delay(hold, uoc_val_11), get_uoc_delay(hold, uoc_val_01),\r
+                       hold, setup, curr_delay);\r
        if (curr_delay > hold && curr_delay < setup)\r
                uoc_val = 0;\r
        else if (curr_delay <= hold && curr_delay > get_uoc_delay(hold, uoc_val_01))\r
@@ -484,6 +528,28 @@ static int dvfs_get_uoc_val(unsigned long *p_volt_arm_new, unsigned long *p_volt
 \r
        return uoc_val;\r
 }\r
+static int dvfs_get_uoc_val(unsigned long *p_volt_arm_new, unsigned long *p_volt_log_new, \r
+               unsigned long rate_khz)\r
+{      \r
+       int i = 0, j = 0;\r
+       for (i = 0; i < size_dvfs_arm_table; i++) {\r
+               if (dvfs_uoc_val_list[i].rate_arm != rate_khz)\r
+                       continue;\r
+               for (j = 0; j < SIZE_SUPPORT_LOG_VOLT - 1; j++) {\r
+                       if (dvfs_uoc_val_list[i].vu_list[j].volt_log < *p_volt_log_new)\r
+                               continue;\r
+                       *p_volt_arm_new = dvfs_uoc_val_list[i].vu_list[j].volt_arm_new;\r
+                       *p_volt_log_new = dvfs_uoc_val_list[i].vu_list[j].volt_log_new;\r
+                       DVFS_DBG("%s: Varm_set=%lu, Vlog_set=%lu, uoc=%d\n", __func__,\r
+                                       *p_volt_arm_new, *p_volt_log_new,\r
+                                       dvfs_uoc_val_list[i].vu_list[j].uoc_val);\r
+                       return dvfs_uoc_val_list[i].vu_list[j].uoc_val;\r
+               }\r
+       }\r
+       DVFS_ERR("%s: can not get uoc_val(Va=%lu, Vl=%lu, Ra=%lu)\n", __func__, \r
+                       *p_volt_arm_new, *p_volt_log_new, rate_khz);\r
+       return -1;\r
+}\r
 static int dvfs_set_uoc_val(int uoc_val)\r
 {\r
        DVFS_DBG("%s set UOC = %d\n", __func__, uoc_val);\r
@@ -520,7 +586,9 @@ static int dvfs_balance_volt(unsigned long volt_arm_old, unsigned long volt_log_
                DVFS_ERR("%s error, volt_arm_old=%lu, volt_log_old=%lu\n", __func__, volt_arm_old, volt_log_old);\r
        return ret;\r
 }\r
-\r
+#if 0\r
+// use 24M to switch uoc bits\r
+static int uoc_pre = 0;\r
 static int dvfs_scale_volt_rate_with_uoc(\r
                unsigned long volt_arm_new, unsigned long volt_log_new,\r
                unsigned long volt_arm_old, unsigned long volt_log_old,\r
@@ -534,56 +602,126 @@ static int dvfs_scale_volt_rate_with_uoc(
                        rate_arm_new);\r
        axi_div = readl_relaxed(RK30_CRU_BASE + CRU_CLKSELS_CON(1));\r
        uoc_val = dvfs_get_uoc_val(&volt_arm_new, &volt_log_new, rate_arm_new);\r
-       local_irq_save(flags);\r
-       lpj_save = loops_per_jiffy;\r
-\r
-       //arm slow mode\r
-       writel_relaxed(PLL_MODE_SLOW(APLL_ID), RK30_CRU_BASE + CRU_MODE_CON);\r
-       loops_per_jiffy = lpj_24m;\r
-       smp_wmb();\r
-\r
-       arm_pll_clk->rate = arm_pll_clk->recalc(arm_pll_clk);\r
-\r
-       //cpu_axi parent to apll\r
-       //writel_relaxed(0x00200000, RK30_CRU_BASE + CRU_CLKSELS_CON(0));\r
-       clk_set_parent_nolock(clk_cpu_div, arm_pll_clk);\r
-\r
-       //set axi/ahb/apb to 1:1:1\r
-       writel_relaxed(axi_div & (~(0x3 << 0)) & (~(0x3 << 8)) & (~(0x3 << 12)), RK30_CRU_BASE + CRU_CLKSELS_CON(1));\r
-\r
-       /*********************/\r
-       //balance voltage before set UOC bits\r
-       dvfs_balance_volt(volt_arm_old, volt_log_old);\r
+       if (uoc_val == uoc_pre) {\r
+               dvfs_scale_volt_bystep(&vd_cpu, &vd_core, volt_arm_new, volt_log_new,\r
+                               100 * 1000, 100 * 1000,\r
+                               volt_arm_new > volt_log_new ? (volt_arm_new - volt_log_new) : 0,\r
+                               volt_log_new > volt_arm_new ? (volt_log_new - volt_arm_new) : 0);\r
+       } else {\r
 \r
-       //set UOC bits\r
-       dvfs_set_uoc_val(uoc_val);\r
+               //local_irq_save(flags);\r
+               preempt_disable();\r
+               u32 t[10];\r
+               t[0] = readl_relaxed(RK30_TIMER1_BASE + 4);\r
+               lpj_save = loops_per_jiffy;\r
+\r
+               //arm slow mode\r
+               writel_relaxed(PLL_MODE_SLOW(APLL_ID), RK30_CRU_BASE + CRU_MODE_CON);\r
+               loops_per_jiffy = lpj_24m;\r
+               smp_wmb();\r
+\r
+               arm_pll_clk->rate = arm_pll_clk->recalc(arm_pll_clk);\r
+\r
+               //cpu_axi parent to apll\r
+               //writel_relaxed(0x00200000, RK30_CRU_BASE + CRU_CLKSELS_CON(0));\r
+               clk_set_parent_nolock(clk_cpu_div, arm_pll_clk);\r
+\r
+               //set axi/ahb/apb to 1:1:1\r
+               writel_relaxed(axi_div & (~(0x3 << 0)) & (~(0x3 << 8)) & (~(0x3 << 12)), RK30_CRU_BASE + CRU_CLKSELS_CON(1));\r
+\r
+               t[1] = readl_relaxed(RK30_TIMER1_BASE + 4);\r
+               /*********************/\r
+               //balance voltage before set UOC bits\r
+               dvfs_balance_volt(volt_arm_old, volt_log_old);\r
+               t[2] = readl_relaxed(RK30_TIMER1_BASE + 4);\r
+\r
+               //set UOC bits\r
+               dvfs_set_uoc_val(uoc_val);\r
+               t[3] = readl_relaxed(RK30_TIMER1_BASE + 4);\r
+\r
+               //voltage up\r
+               dvfs_scale_volt_bystep(&vd_cpu, &vd_core, volt_arm_new, volt_log_new,\r
+                               100 * 1000, 100 * 1000,\r
+                               volt_arm_new > volt_log_new ? (volt_arm_new - volt_log_new) : 0,\r
+                               volt_log_new > volt_arm_new ? (volt_log_new - volt_arm_new) : 0);\r
+               t[4] = readl_relaxed(RK30_TIMER1_BASE + 4);\r
+\r
+               /*********************/\r
+               //set axi/ahb/apb to default\r
+               writel_relaxed(axi_div, RK30_CRU_BASE + CRU_CLKSELS_CON(1));\r
+\r
+               //cpu_axi parent to gpll\r
+               //writel_relaxed(0x00200020, RK30_CRU_BASE + CRU_CLKSELS_CON(0));\r
+               clk_set_parent_nolock(clk_cpu_div, general_pll_clk);\r
+\r
+               //arm normal mode\r
+               writel_relaxed(PLL_MODE_NORM(APLL_ID), RK30_CRU_BASE + CRU_MODE_CON);\r
+               loops_per_jiffy = lpj_save;\r
+               smp_wmb();\r
+\r
+               arm_pll_clk->rate = arm_pll_clk->recalc(arm_pll_clk);\r
+\r
+               t[5] = readl_relaxed(RK30_TIMER1_BASE + 4);\r
+               preempt_enable();\r
+               //local_irq_restore(flags);\r
+               DVFS_DBG(KERN_DEBUG "T %d %d %d %d %d\n", t[0] - t[1], t[1] - t[2], t[2] - t[3], t[3] - t[4], t[4] - t[5]);\r
+               uoc_pre = uoc_val;\r
+       }\r
+       return 0;\r
+}\r
+#else\r
+// use 312M to switch uoc bits\r
+static int uoc_pre = 0;\r
+static int dvfs_scale_volt_rate_with_uoc(\r
+               unsigned long volt_arm_new, unsigned long volt_log_new,\r
+               unsigned long volt_arm_old, unsigned long volt_log_old,\r
+               unsigned long rate_arm_new)\r
+{\r
+       int uoc_val = 0;\r
+       unsigned long arm_freq = 0;\r
+       uoc_val = dvfs_get_uoc_val(&volt_arm_new, &volt_log_new, rate_arm_new);\r
+       DVFS_DBG("Va_new=%lu uV, Vl_new=%lu uV;(was Va_old=%lu uV, Vl_old=%lu uV); Ra_new=%luHz, uoc=%d\n",\r
+                       volt_arm_new, volt_log_new, volt_arm_old, volt_log_old, rate_arm_new, uoc_val);\r
+       if (uoc_val == uoc_pre) {\r
+               dvfs_scale_volt_bystep(&vd_cpu, &vd_core, volt_arm_new, volt_log_new,\r
+                               100 * 1000, 100 * 1000,\r
+                               volt_arm_new > volt_log_new ? (volt_arm_new - volt_log_new) : 0,\r
+                               volt_log_new > volt_arm_new ? (volt_log_new - volt_arm_new) : 0);\r
+       } else {\r
+               //save arm freq\r
+               arm_freq = clk_get_rate(clk_cpu);\r
+               target_set_rate(dvfs_clk_cpu, 312 * MHZ);\r
 \r
-       //voltage up\r
-       dvfs_scale_volt_bystep(&vd_cpu, &vd_core, volt_arm_new, volt_log_new,\r
-                       100 * 1000, 100 * 1000,\r
-                       volt_arm_new > volt_log_new ? (volt_arm_new - volt_log_new) : 0,\r
-                       volt_log_new > volt_arm_new ? (volt_log_new - volt_arm_new) : 0);\r
+               //cpu_axi parent to apll\r
+               //writel_relaxed(0x00200000, RK30_CRU_BASE + CRU_CLKSELS_CON(0));\r
+               clk_set_parent_nolock(clk_cpu_div, arm_pll_clk);\r
 \r
-       /*********************/\r
-       //set axi/ahb/apb to default\r
-       writel_relaxed(axi_div, RK30_CRU_BASE + CRU_CLKSELS_CON(1));\r
+               /*********************/\r
+               //balance voltage before set UOC bits\r
+               dvfs_balance_volt(volt_arm_old, volt_log_old);\r
 \r
-       //cpu_axi parent to gpll\r
-       //writel_relaxed(0x00200020, RK30_CRU_BASE + CRU_CLKSELS_CON(0));\r
-       clk_set_parent_nolock(clk_cpu_div, general_pll_clk);\r
+               //set UOC bits\r
+               dvfs_set_uoc_val(uoc_val);\r
 \r
-       //arm normal mode\r
-       writel_relaxed(PLL_MODE_NORM(APLL_ID), RK30_CRU_BASE + CRU_MODE_CON);\r
-       loops_per_jiffy = lpj_save;\r
-       smp_wmb();\r
+               //voltage up\r
+               dvfs_scale_volt_bystep(&vd_cpu, &vd_core, volt_arm_new, volt_log_new,\r
+                               100 * 1000, 100 * 1000,\r
+                               volt_arm_new > volt_log_new ? (volt_arm_new - volt_log_new) : 0,\r
+                               volt_log_new > volt_arm_new ? (volt_log_new - volt_arm_new) : 0);\r
 \r
-       arm_pll_clk->rate = arm_pll_clk->recalc(arm_pll_clk);\r
+               /*********************/\r
+               //cpu_axi parent to gpll\r
+               //writel_relaxed(0x00200020, RK30_CRU_BASE + CRU_CLKSELS_CON(0));\r
+               clk_set_parent_nolock(clk_cpu_div, general_pll_clk);\r
 \r
-       local_irq_restore(flags);\r
+               //reset arm freq as normal freq\r
+               target_set_rate(dvfs_clk_cpu, arm_freq);\r
 \r
+               uoc_pre = uoc_val;\r
+       }\r
        return 0;\r
 }\r
-\r
+#endif\r
 int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz)\r
 {\r
        struct clk_node *dvfs_clk;\r
@@ -953,6 +1091,11 @@ int rk_dvfs_init(void)
                rk_regist_depends(&rk30_depends[i]);\r
        }\r
        dvfs_clk_cpu = dvfs_get_dvfs_clk_byname("cpu");\r
+       clk_cpu = clk_get(NULL, "cpu");\r
+       if (IS_ERR_OR_NULL(clk_cpu)) {\r
+               DVFS_ERR("%s get clk_cpu error\n", __func__);\r
+               return -1;\r
+       }\r
 \r
        clk_cpu_div = clk_get(NULL, "logic");\r
        if (IS_ERR_OR_NULL(clk_cpu_div)) {\r