From: xxx Date: Mon, 2 Apr 2012 10:13:18 +0000 (-0700) Subject: rk30: add cpufreq support X-Git-Tag: firefly_0821_release~9496 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=be98d880957b961a0172d083106bb46e6c051f80;p=firefly-linux-kernel-4.4.55.git rk30: add cpufreq support --- diff --git a/arch/arm/mach-rk30/Makefile b/arch/arm/mach-rk30/Makefile index 1f2133674bd2..21cc5ec14986 100755 --- a/arch/arm/mach-rk30/Makefile +++ b/arch/arm/mach-rk30/Makefile @@ -3,7 +3,6 @@ obj-y += clock_data.o obj-y += common.o obj-y += ddr.o obj-y += devices.o -obj-y += dvfs.o obj-y += io.o obj-y += iomux.o obj-y += pmu.o @@ -16,6 +15,8 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o +obj-$(CONFIG_CPU_FREQ) += cpufreq.o +obj-$(CONFIG_DVFS) += dvfs.o obj-$(CONFIG_MACH_RK30_SDK) += board-rk30-sdk.o board-rk30-sdk-key.o board-rk30-sdk-rfkill.o obj-$(CONFIG_MACH_RK30_PHONE) += board-rk30-phone.o board-rk30-phone-key.o board-rk30-phone-rfkill.o diff --git a/arch/arm/mach-rk30/clock.c b/arch/arm/mach-rk30/clock.c index 78b3fa8230bf..bf68a8bbcde6 100755 --- a/arch/arm/mach-rk30/clock.c +++ b/arch/arm/mach-rk30/clock.c @@ -162,7 +162,7 @@ static void __clk_reparent(struct clk *child, struct clk *parent) { if (child->parent == parent) return; - CLOCK_PRINTK_DBG("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL")); + //CLOCK_PRINTK_DBG("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL")); list_del_init(&child->sibling); if (parent) @@ -267,7 +267,7 @@ int clk_set_rate_nolock(struct clk *clk, unsigned long rate) if (ret == 0) { __clk_recalc(clk); - //CLOCK_PRINTK_LOG("**set %s rate recalc=%lu\n",clk->name,clk->rate); + CLOCK_PRINTK_LOG("**set %s rate recalc=%lu\n",clk->name,clk->rate); __propagate_rate(clk); } diff --git a/arch/arm/mach-rk30/clock.h b/arch/arm/mach-rk30/clock.h old mode 100644 new mode 100755 diff --git a/arch/arm/mach-rk30/clock_data.c b/arch/arm/mach-rk30/clock_data.c index 254963453765..b127b02d4847 100755 --- a/arch/arm/mach-rk30/clock_data.c +++ b/arch/arm/mach-rk30/clock_data.c @@ -165,7 +165,7 @@ void rk30_clkdev_add(struct clk_lookup *cl); #endif -#define CRU_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args); +#define CRU_PRINTK_DBG(fmt, args...) {while(0);}//pr_debug(fmt, ## args); #define CRU_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args); #define CRU_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args); @@ -491,7 +491,7 @@ static void pll_wait_lock(int pll_idx) { u32 pll_state[4]={1,0,2,3}; u32 bit = 0x10u << pll_state[pll_idx]; - int delay = 2400000; + int delay = 24000000; while (delay > 0) { if (regfile_readl(GRF_SOC_STATUS0) & bit) break; @@ -499,6 +499,7 @@ static void pll_wait_lock(int pll_idx) } if (delay == 0) { CRU_PRINTK_ERR("wait pll bit 0x%x time out!\n", bit); + while(1); } } @@ -773,6 +774,43 @@ static long arm_pll_clk_round_rate(struct clk *clk, unsigned long rate) { return arm_pll_clk_get_best_pll_set(rate,clk->pll->table)->rate; } +#if 1 +struct arm_clks_div_set { + u32 rate; + u32 clksel0; + u32 clksel1; +}; + +#define _arm_clks_div_set(_mhz,_periph_div,_axi_div,_ahb_div, _apb_div,_ahb2apb) \ + { \ + .rate =_mhz,\ + .clksel0 = CORE_PERIPH_W_MSK|CORE_PERIPH_##_periph_div,\ + .clksel1 = CORE_ACLK_W_MSK|CORE_ACLK_##_axi_div\ + |ACLK_HCLK_W_MSK|ACLK_HCLK_##_ahb_div\ + |ACLK_PCLK_W_MSK|ACLK_PCLK_##_apb_div\ + |AHB2APB_W_MSK |AHB2APB_##_ahb2apb,\ +} +struct arm_clks_div_set arm_clk_div_tlb[]={ + _arm_clks_div_set(50 , 2, 11, 11, 11, 11),//25,50,50,50,50 + _arm_clks_div_set(100 , 4, 11, 21, 21, 11),//25,100,50,50,50 + _arm_clks_div_set(150 , 4, 11, 21, 21, 11),//37,150,75,75,75 + _arm_clks_div_set(200 , 8, 21, 21, 21, 11),//25,100,50,50,50 + _arm_clks_div_set(300 , 8, 21, 21, 11, 11),//37,150,75,75,75 + _arm_clks_div_set(400 , 8, 21, 21, 41, 21),//50,200,100,50,50 + _arm_clks_div_set(0 , 2, 11, 11, 11, 11),//25,50,50,50,50 +}; +struct arm_clks_div_set * arm_clks_get_div(u32 rate) +{ + int i=0; + for(i=0;arm_clk_div_tlb[i].rate!=0;i++) + { + if(arm_clk_div_tlb[i].rate>=rate) + return &arm_clk_div_tlb[i]; + } + return NULL; +} + +#endif static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) { @@ -780,7 +818,9 @@ static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) const struct apll_clk_set *ps; u32 pll_id=clk->pll->id; u32 temp_div; - u32 old_aclk_div=0,new_aclk_div; + u32 old_aclk_div=0,new_aclk_div,gpll_arm_aclk_div; + struct arm_clks_div_set *temp_clk_div; + unsigned long arm_gpll_rate; ps = arm_pll_clk_get_best_pll_set(rate,(struct apll_clk_set *)clk->pll->table); @@ -790,21 +830,54 @@ static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) CRU_PRINTK_LOG("apll will set rate(%lu) tlb con(%x,%x,%x),sel(%x,%x)\n", ps->rate,ps->pllcon0,ps->pllcon1,ps->pllcon2,ps->clksel0,ps->clksel1); + //rk30_l2_cache_latency(ps->rate/MHZ); + if(general_pll_clk.rate>clk->rate) { temp_div=clk_get_freediv(clk->rate,general_pll_clk.rate,10); - cru_writel(CORE_CLK_DIV(temp_div)|CORE_CLK_DIV_W_MSK, CRU_CLKSELS_CON(0)); } - + else + { + temp_div=1; + } + //sel gpll + //cru_writel(CORE_CLK_DIV(temp_div)|CORE_CLK_DIV_W_MSK, CRU_CLKSELS_CON(0)); + + arm_gpll_rate=general_pll_clk.rate/temp_div; + temp_clk_div=arm_clks_get_div(arm_gpll_rate/MHZ); + if(!temp_clk_div) + temp_clk_div=&arm_clk_div_tlb[4]; + + gpll_arm_aclk_div=GET_CORE_ACLK_VAL(temp_clk_div->clksel1&CORE_ACLK_MSK); + + CRU_PRINTK_LOG("gpll_arm_rate=%lu,sel rate%u,sel0%x,sel1%x\n",arm_gpll_rate,temp_clk_div->rate, + temp_clk_div->clksel0,temp_clk_div->clksel1); + + local_irq_save(flags); // open gpu gpll path - cru_writel(CLK_GATE_W_MSK(CLK_GATE_CPU_GPLL_PATH)|CLK_UN_GATE(CLK_GATE_CPU_GPLL_PATH) - , CLK_GATE_CLKID_CONS(CLK_GATE_CPU_GPLL_PATH)); - local_irq_save(flags); + cru_writel(CLK_GATE_W_MSK(CLK_GATE_CPU_GPLL_PATH)|CLK_UN_GATE(CLK_GATE_CPU_GPLL_PATH),CLK_GATE_CLKID_CONS(CLK_GATE_CPU_GPLL_PATH)); + cru_writel(CORE_SEL_GPLL|CORE_SEL_PLL_W_MSK, CRU_CLKSELS_CON(0)); - loops_per_jiffy = lpj_gpll; + + loops_per_jiffy = lpj_gpll/temp_div; + if((old_aclk_div==3||gpll_arm_aclk_div==3)&&(gpll_arm_aclk_div!=old_aclk_div)) + { + cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON); + cru_writel((temp_clk_div->clksel1), CRU_CLKSELS_CON(1)); + cru_writel((temp_clk_div->clksel0|CORE_CLK_DIV(temp_div)|CORE_CLK_DIV_W_MSK), + CRU_CLKSELS_CON(0)); + cru_writel(PLL_MODE_NORM(APLL_ID), CRU_MODE_CON); + } + else + { + cru_writel((temp_clk_div->clksel1), CRU_CLKSELS_CON(1)); + cru_writel((temp_clk_div->clksel0)|CORE_CLK_DIV(temp_div)|CORE_CLK_DIV_W_MSK, + CRU_CLKSELS_CON(0)); + } + /*if core src don't select gpll ,apll neet to enter slow mode */ //cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON); @@ -814,30 +887,27 @@ static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) cru_writel(ps->pllcon1, PLL_CONS(pll_id,1)); cru_writel(ps->pllcon2, PLL_CONS(pll_id,2)); - local_irq_restore(flags); rk30_clock_udelay(5); //return form rest cru_writel(PLL_REST_W_MSK|PLL_REST_RESM, PLL_CONS(pll_id,3)); //wating lock state - rk30_clock_udelay(ps->rst_dly); + ///rk30_clock_udelay(ps->rst_dly);//lcdc flash + pll_wait_lock(pll_id); - local_irq_save(flags); - //return form slow //cru_writel(PLL_MODE_NORM(APLL_ID), CRU_MODE_CON); - //a/h/p clk sel - if((old_aclk_div==3||new_aclk_div==3)&&(new_aclk_div!=old_aclk_div)) + if((gpll_arm_aclk_div==3||new_aclk_div==3)&&(new_aclk_div!=gpll_arm_aclk_div)) { cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON); cru_writel((ps->clksel1), CRU_CLKSELS_CON(1)); cru_writel((ps->clksel0)|CORE_CLK_DIV(1)|CORE_CLK_DIV_W_MSK, CRU_CLKSELS_CON(0)); cru_writel(PLL_MODE_NORM(APLL_ID), CRU_MODE_CON); } - else + else { cru_writel((ps->clksel1), CRU_CLKSELS_CON(1)); cru_writel((ps->clksel0)|CORE_CLK_DIV(1)|CORE_CLK_DIV_W_MSK, CRU_CLKSELS_CON(0)); @@ -866,16 +936,34 @@ static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate) static const struct apll_clk_set apll_clks[] = { //rate, nr ,nf ,no,core_div,peri,axi,hclk,pclk,_ahb2apb - _APLL_SET_CLKS(1416, 1, 59, 1, 8, 31, 21, 81, 41), - _APLL_SET_CLKS(1200, 1, 50, 1, 8, 31, 21, 81, 41), - _APLL_SET_CLKS(1008, 1, 42, 1, 8, 31, 21, 81, 41), - _APLL_SET_CLKS(816 , 1, 34, 1, 8, 21, 21, 81, 41), - _APLL_SET_CLKS(504 , 1, 21, 1, 4, 21, 21, 81, 41), - _APLL_SET_CLKS(252 , 1, 21, 2, 2, 21, 21, 41, 21), + //_APLL_SET_CLKS(1800, 1, 75, 1, 8, 31, 41, 81), + //_APLL_SET_CLKS(1752, 1, 73, 1, 8, 31, 41, 81), + //_APLL_SET_CLKS(1704, 1, 71, 1, 8, 31, 41, 81), + //_APLL_SET_CLKS(1656, 1, 69, 1, 8, 31, 41, 81), + _APLL_SET_CLKS(1608, 1, 67, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1560, 1, 65, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1512, 1, 63, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1464, 1, 61, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1416, 1, 59, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1368, 1, 57, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1272, 1, 53, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1200, 1, 50, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1176, 1, 49, 1, 8, 41, 21, 41, 21), + _APLL_SET_CLKS(1008, 1, 42, 1, 8, 31, 21, 41, 21), + _APLL_SET_CLKS(888, 1, 37, 1, 8, 31, 21, 41, 21), + _APLL_SET_CLKS(816 , 1, 34, 1, 8, 31, 21, 41, 21), + _APLL_SET_CLKS(792 , 1, 33, 1, 8, 31, 21, 41, 21), + _APLL_SET_CLKS(696 , 1, 29, 1, 8, 31, 21, 41, 21), + _APLL_SET_CLKS(600 , 1, 25, 1, 4, 31, 21, 41, 21), + _APLL_SET_CLKS(504 , 1, 21, 1, 4, 21, 21, 41, 21), + _APLL_SET_CLKS(408 , 1, 17, 1, 4, 21, 21, 41, 21), + _APLL_SET_CLKS(312 , 1, 13, 1, 2, 21, 21, 21, 21), + _APLL_SET_CLKS(252 , 1, 21, 2, 2, 21, 21, 21, 21), + _APLL_SET_CLKS(216 , 1, 18, 2, 2, 21, 21, 21, 21), _APLL_SET_CLKS(126 , 1, 21, 4, 2, 21, 11, 11, 11), - //_APLL_SET_CLKS(63 , 1, 21, 8, 2, 11, 11, 11, 11), - //_APLL_SET_CLKS(48 , 1, 16, 8, 2, 11, 11, 11, 11), - _APLL_SET_CLKS(0 , 1, 21, 4, 2, 21, 21, 41, 11), + _APLL_SET_CLKS(48 , 1, 16, 8, 2, 11, 11, 11, 11), + _APLL_SET_CLKS(0 , 1, 21, 4, 2, 21, 21, 41, 21), + }; static struct _pll_data apll_data=SET_PLL_DATA(APLL_ID,(void *)apll_clks); static struct clk arm_pll_clk ={ @@ -1789,9 +1877,10 @@ static int clksel_set_rate_hdmi(struct clk *clk, unsigned long rate) u32 div; div=clk_get_freediv(rate,clk->parent->rate,clk->div_max); if(rate==(clk->parent->rate/div)&&!(clk->parent->rate%div)) - return 0; - set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); - return -ENOENT; + set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con); + else + return -ENOENT; + return 0; } //hdmi static struct clk dclk_lcdc1_div = { @@ -1857,7 +1946,6 @@ static struct clk dclk_lcdc1 = { CRU_PARENTS_SET(dclk_lcdc1_parents), }; - static struct clk *cifout_sel_pll_parents[2]={&codec_pll_clk,&general_pll_clk}; static struct clk cif_out_pll = { .name = "cif_out_pll", @@ -2819,7 +2907,7 @@ struct clk_dump_ops dump_ops; static void clk_dump_regs(void); -void __init rk30_clock_data_init(unsigned long gpll,unsigned long cpll,unsigned long max_i2s_rate) +void __init _rk30_clock_data_init(unsigned long gpll,unsigned long cpll,unsigned long max_i2s_rate) { struct clk_lookup *lk; @@ -2856,7 +2944,12 @@ void __init rk30_clock_data_init(unsigned long gpll,unsigned long cpll,unsigned //cru_writel(0x07000000,CRU_MISC_CON); } -extern int rk30_dvfs_init(void); + +void __init rk30_clock_data_init(unsigned long gpll,unsigned long cpll,unsigned long max_i2s_rate) +{ + _rk30_clock_data_init(gpll,cpll,max_i2s_rate); + rk30_dvfs_init(); +} /* * You can override arm_clk rate with armclk= cmdline option. diff --git a/arch/arm/mach-rk30/dvfs.c b/arch/arm/mach-rk30/dvfs.c old mode 100644 new mode 100755 index 6283fda952b3..f2a2492239b9 --- a/arch/arm/mach-rk30/dvfs.c +++ b/arch/arm/mach-rk30/dvfs.c @@ -20,75 +20,15 @@ #include #include #include - #include "clock.h" #include #include +#include +#include -#if 0 -#define DVFS_DBG(fmt, args...) pr_debug(fmt, ##args) +#define DVFS_DBG(fmt, args...) {while(0);}//pr_debug(fmt, ##args) #define DVFS_ERR(fmt, args...) pr_err(fmt, ##args) -#else -#define DEBUG_RK30_DVFS -#define DVFS_DBG(fmt, args...) printk(fmt, ##args) -#define DVFS_ERR(fmt, args...) printk(fmt, ##args) -#endif - -#ifndef CONFIG_ARCH_RK30 -#define DVFS_TEST_OFF_BOARD -#endif - - - -#ifdef DVFS_TEST_OFF_BOARD -/* Just for simulation */ - -struct regulator { - int min_uV; -}; -#if 0 -static void test_regulator_put(struct regulator *regulator) -{ - kfree(regulator); -} -#endif -struct regulator regulators[100]; -static struct regulator *test_regulator_get(struct device *dev, const char *id) { - static int ret_cnt = 0; - return ®ulators[ret_cnt++]; -} - -static int test_regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) -{ - regulator->min_uV = min_uV; - return 0; -} - -static int test_regulator_get_voltage(struct regulator *regulator) -{ - return regulator->min_uV; -} - -int rk30_clk_set_rate(struct clk *clk, unsigned long rate); -static void dump_dbg_map(void); -int rk30_dvfs_init_test(void); -int rk30_clk_enable(struct clk *clk); -int rk30_clk_disable(struct clk *clk); - -#define dvfs_regulator_get(dev,id) test_regulator_get((dev),(id)) -#define dvfs_regulator_put(regu) test_regulator_get((regu)) -#define dvfs_regulator_set_voltage(regu,min_uV,max_uV) test_regulator_set_voltage((regu),(min_uV),(max_uV)) -#define dvfs_regulator_get_voltage(regu) test_regulator_get_voltage((regu)) - -/* clock */ -#define dvfs_clk_get(a,b) rk30_clk_get((a),(b)) -#define dvfs_clk_set_rate(a,b) rk30_clk_set_rate((a),(b)) -#define dvfs_clk_enable(a) rk30_clk_enable((a)) -#define dvfs_clk_disable(a) rk30_clk_disable((a)) - -#else -/* board runing */ -#include +#define DVFS_LOG(fmt, args...) pr_debug(fmt, ##args)//while(0) #define dvfs_regulator_get(dev,id) regulator_get((dev),(id)) #define dvfs_regulator_put(regu) regulator_get((regu)) @@ -96,81 +36,234 @@ int rk30_clk_disable(struct clk *clk); #define dvfs_regulator_get_voltage(regu) regulator_get_voltage((regu)) #define dvfs_clk_get(a,b) clk_get((a),(b)) +#define dvfs_clk_get_rate_kz(a) (clk_get_rate((a))/1000) #define dvfs_clk_set_rate(a,b) clk_set_rate((a),(b)) #define dvfs_clk_enable(a) clk_enable((a)) #define dvfs_clk_disable(a) clk_disable((a)) -#endif + +#define DVFS_MHZ (1000*1000) +#define DVFS_KHZ (1000) + +#define DVFS_V (1000*1000) +#define DVFS_MV (1000) static LIST_HEAD(rk_dvfs_tree); static DEFINE_MUTEX(mutex); -/* -int dvfs_target_core(struct clk *clk, unsigned int rate); -int dvfs_target(struct clk *clk, unsigned int rate); -int dvfs_clk_set_rate(struct clk *clk, unsigned long rate); -*/ + extern int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb); extern int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); -#define FV_TABLE_END 0 #define PD_ON 1 #define PD_OFF 0 - -static void dvfs_clk_scale_volt(struct clk_node *dvfs_clk, unsigned int volt); -static int dvfs_clk_get_volt(struct clk_node *dvfs_clk, unsigned long rate, - struct cpufreq_frequency_table *clk_fv); - -/** - * **************************FUNCTIONS*********************************** - */ - -#ifdef DEBUG_RK30_DVFS -/** - * dump_dbg_map() : Draw all informations of dvfs while debug - */ -static void dump_dbg_map(void) +int is_support_dvfs(struct clk_node *dvfs_info) { - int i; - struct vd_node *vd; - struct pd_node *pd, *clkparent; - struct clk_list *child; - struct clk_node *dvfs_clk; - - DVFS_DBG("-------------DVFS DEBUG-----------\n\n\n"); - DVFS_DBG("RK30 DVFS TREE:\n"); - list_for_each_entry(vd, &rk_dvfs_tree, node) { - DVFS_DBG("|\n|- voltage domain:%s\n", vd->name); - DVFS_DBG("|- current voltage:%d\n", vd->cur_volt); + return (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target && dvfs_info->enable_dvfs); +} +int dvfs_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = 0; + struct vd_node *vd; + DVFS_DBG("%s(%s(%lu))\n",__func__,clk->name,rate); + if(!clk->dvfs_info) { + DVFS_ERR("%s :This clk do not support dvfs!\n", __func__); + ret = -1; + } else { + vd = clk->dvfs_info->vd; + mutex_lock(&vd->dvfs_mutex); + ret = vd->vd_dvfs_target(clk, rate); + mutex_unlock(&vd->dvfs_mutex); + } + DVFS_DBG("%s(%s(%lu)),is end\n",__func__,clk->name,rate); + return ret; +} - list_for_each_entry(pd, &vd->pd_list, node) { - DVFS_DBG("| |\n| |- power domain:%s, status = %s, current volt = %d\n", - pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt); +static int dvfs_clk_get_ref_volt(struct clk_node *dvfs_clk,int rate_khz, + struct cpufreq_frequency_table *clk_fv) +{ + int i = 0; + if (rate_khz == 0||!dvfs_clk||!dvfs_clk->dvfs_table) { + /* since no need*/ + return -1; + } + clk_fv->frequency = rate_khz; + clk_fv->index = 0; + + for(i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if(dvfs_clk->dvfs_table[i].frequency >= rate_khz) { + clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency; + clk_fv->index = dvfs_clk->dvfs_table[i].index; + // DVFS_DBG("%s,%s rate=%ukhz(vol=%d)\n",__func__,dvfs_clk->name, clk_fv->frequency, clk_fv->index); + return 0; + } + } + clk_fv->frequency = 0; + clk_fv->index = 0; + // DVFS_DBG("%s get corresponding voltage error! out of bound\n", dvfs_clk->name); + return -1; +} - list_for_each_entry(child, &pd->clk_list, node) { - dvfs_clk = child->dvfs_clk; - DVFS_DBG("| | |\n| | |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n", - dvfs_clk->name, dvfs_clk->cur_freq, dvfs_clk->cur_volt, dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE"); - for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) { - clkparent = dvfs_clk->pds[i].pd; - DVFS_DBG("| | | |- clock parents: %s, vd_parent = %s\n", clkparent->name, clkparent->vd->name); - } +static int dvfs_pd_get_newvolt_for_clk(struct pd_node *pd,struct clk_node *dvfs_clk) +{ + struct clk_list *child; + int volt_max = 0; + + if(!pd||!dvfs_clk) + return 0; + + if(dvfs_clk->set_volt>=pd->cur_volt) + { + return dvfs_clk->set_volt; + } + + list_for_each_entry(child, &pd->clk_list, node){ + //DVFS_DBG("%s ,pd(%s),dvfs(%s),volt(%u)\n",__func__,pd->name,dvfs_clk->name,dvfs_clk->set_volt); + volt_max = max(volt_max,child->dvfs_clk->set_volt); + } + return volt_max; +} - for (i = 0; (dvfs_clk->dvfs_table[i].frequency != FV_TABLE_END); i++) { - DVFS_DBG("| | | |- freq = %d, volt = %d\n", dvfs_clk->dvfs_table[i].frequency, dvfs_clk->dvfs_table[i].index); +void dvfs_update_clk_pds_volt(struct clk_node *dvfs_clk) +{ + struct pd_node *pd; + int i; + if(!dvfs_clk) + return; + for(i = 0; (dvfs_clk->pds[i].pd != NULL); i++) { + pd = dvfs_clk->pds[i].pd; + // DVFS_DBG("%s dvfs(%s),pd(%s)\n",__func__,dvfs_clk->name,pd->name); + pd->cur_volt=dvfs_pd_get_newvolt_for_clk(pd,dvfs_clk); + } +} - } - } +static int dvfs_get_vd_volt_bypd(struct vd_node *vd) +{ + struct pd_node *pd; + int volt_max_vd=0; + list_for_each_entry(pd, &vd->pd_list, node) { + //DVFS_DBG("%s pd(%s,%u)\n",__func__,pd->name,pd->cur_volt); + volt_max_vd = max(volt_max_vd, pd->cur_volt); + } + return volt_max_vd; +} +static int dvfs_vd_get_newvolt_for_clk(struct clk_node *dvfs_clk) +{ + if(!dvfs_clk) + return -1; + dvfs_update_clk_pds_volt(dvfs_clk); + return dvfs_get_vd_volt_bypd(dvfs_clk->vd); +} +void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) +{ + struct clk_node *dvfs_clk = clk_get_dvfs_info(clk); + dvfs_clk->clk_dvfs_target = clk_dvfs_target; +} +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) +{ + struct clk_node *info = clk_get_dvfs_info(clk); + + if(!info||!info->dvfs_table) { + return NULL; + } + mutex_lock(&mutex); + return info->dvfs_table; + mutex_unlock(&mutex); +} +int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table) +{ + struct clk_node *info = clk_get_dvfs_info(clk); + if(!table || !info) + return -1; + + mutex_lock(&mutex); + info->dvfs_table = table; + mutex_unlock(&mutex); + return 0; +} +int clk_enable_dvfs(struct clk *clk) +{ + struct regulator *regulator; + struct clk_node *dvfs_clk; + struct cpufreq_frequency_table clk_fv; + if(!clk){ + DVFS_ERR("clk enable dvfs error\n"); + return -1; + } + dvfs_clk=clk_get_dvfs_info(clk); + if(!dvfs_clk||!dvfs_clk->vd) { + DVFS_ERR("%s clk(%s) not support dvfs!\n",__func__,clk->name); + return -1; + } + if(dvfs_clk->enable_dvfs==0){ + + if(!dvfs_clk->vd->regulator) { + regulator=NULL; + if(dvfs_clk->vd->regulator_name) + regulator = dvfs_regulator_get(NULL,dvfs_clk->vd->regulator_name); + if(regulator) + { + //DVFS_DBG("dvfs_regulator_get(%s)\n",dvfs_clk->vd->regulator_name); + dvfs_clk->vd->regulator = regulator; + } + else + { + dvfs_clk->vd->regulator = NULL; + dvfs_clk->enable_dvfs=0; + DVFS_ERR("%s can't get regulator in %s\n",dvfs_clk->name,__func__); + return -1; + } + } + else + { + dvfs_clk->vd->cur_volt = dvfs_regulator_get_voltage(dvfs_clk->vd->regulator); + //DVFS_DBG("%s(%s) vd volt=%u\n",__func__,dvfs_clk->name,dvfs_clk->vd->cur_volt); + } + + dvfs_clk->set_freq=dvfs_clk_get_rate_kz(clk); + //DVFS_DBG("%s ,%s get freq%u!\n",__func__,dvfs_clk->name,dvfs_clk->set_freq); + + if(dvfs_clk_get_ref_volt(dvfs_clk,dvfs_clk->set_freq,&clk_fv)) + { + dvfs_clk->enable_dvfs=0; + return -1; + } + dvfs_clk->set_volt=clk_fv.index; + //DVFS_DBG("%s,%s,freq%u(ref vol %u)\n",__func__,dvfs_clk->name, + // dvfs_clk->set_freq,dvfs_clk->set_volt); +#if 0 + if(dvfs_clk->dvfs_nb) { + // must unregister when clk disable + rk30_clk_notifier_register(clk, dvfs_clk->dvfs_nb); } +#endif + dvfs_vd_get_newvolt_for_clk(dvfs_clk); + dvfs_clk->enable_dvfs++; + } else { + DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs); + dvfs_clk->enable_dvfs++; } - DVFS_DBG("-------------DVFS DEBUG END------------\n"); + return 0; } -#endif -int is_support_dvfs(struct clk_node *dvfs_info) +int clk_disable_dvfs(struct clk *clk) { - return (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target && dvfs_info->enable_dvfs); + struct clk_node *dvfs_clk; + dvfs_clk = clk->dvfs_info; + if(!dvfs_clk->enable_dvfs) { + DVFS_DBG("clk is already closed!\n"); + return -1; + } else { + dvfs_clk->enable_dvfs--; + if(0 == dvfs_clk->enable_dvfs) { + DVFS_ERR("clk closed!\n"); + rk30_clk_notifier_unregister(clk, dvfs_clk->dvfs_nb); + DVFS_DBG("clk unregister nb!\n"); + } + } + return 0; } + static int rk_dvfs_clk_notifier_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -205,8 +298,7 @@ static int rk_dvfs_clk_notifier_event(struct notifier_block *this, break; case CLK_POST_DISABLE: DVFS_DBG("%s CLK_POST_DISABLE\n", __func__); - dvfs_clk->cur_freq = 0; - dvfs_clk_scale_volt(dvfs_clk, 0); + dvfs_clk->set_freq = 0; break; case CLK_ABORT_DISABLE: DVFS_DBG("%s CLK_ABORT_DISABLE\n", __func__); @@ -220,385 +312,276 @@ static int rk_dvfs_clk_notifier_event(struct notifier_block *this, static struct notifier_block rk_dvfs_clk_notifier = { .notifier_call = rk_dvfs_clk_notifier_event, }; -int clk_disable_dvfs(struct clk *clk) + +static int rk_regist_vd(struct vd_node *vd) { - struct clk_node *dvfs_clk; - dvfs_clk = clk->dvfs_info; - if(dvfs_clk->enable_dvfs - 1 < 0) { - DVFS_ERR("clk is already closed!\n"); + if(!vd) return -1; - } else { - DVFS_ERR("clk is disable now!\n"); - dvfs_clk->enable_dvfs--; - if(0 == dvfs_clk->enable_dvfs) { - DVFS_ERR("clk closed!\n"); - rk30_clk_notifier_unregister(clk, dvfs_clk->dvfs_nb); - DVFS_ERR("clk unregister nb!\n"); - dvfs_clk_scale_volt(dvfs_clk, 0); - } - } - dump_dbg_map(); + mutex_lock(&mutex); + mutex_init(&vd->dvfs_mutex); + list_add(&vd->node, &rk_dvfs_tree); + INIT_LIST_HEAD(&vd->pd_list); + + mutex_unlock(&mutex); return 0; } - -int clk_enable_dvfs(struct clk *clk) +static int rk_regist_pd(struct pd_node_lookup *pd_lookup) { - struct regulator *regulator; - struct clk_node *dvfs_clk; - struct cpufreq_frequency_table clk_fv; - - if(!clk->dvfs_info) { - DVFS_ERR("This clk(%s) not support dvfs!\n", clk->name); - return -1; - } + struct vd_node *vd; + struct pd_node *pd; - dvfs_clk = clk->dvfs_info; - DVFS_ERR("dvfs clk enable dvfs %s\n", dvfs_clk->name); - if(0 == dvfs_clk->enable_dvfs) { - dvfs_clk->enable_dvfs++; - if(!dvfs_clk->vd->regulator) { - regulator = dvfs_regulator_get(NULL, dvfs_clk->vd->regulator_name); - if(regulator) - dvfs_clk->vd->regulator = regulator; - else - dvfs_clk->vd->regulator = NULL; - } - if(dvfs_clk->dvfs_nb) { - // must unregister when clk disable - rk30_clk_notifier_register(clk, dvfs_clk->dvfs_nb); - } + mutex_lock(&mutex); + pd = pd_lookup->pd; - if(!clk || IS_ERR(clk)) { - DVFS_ERR("%s get clk %s error\n", __func__, dvfs_clk->name); - return -1; + list_for_each_entry(vd, &rk_dvfs_tree, node) { + if (vd == pd->vd) { + list_add(&pd->node, &vd->pd_list); + INIT_LIST_HEAD(&pd->clk_list); + break; } - //DVFS_DBG("%s get clk %s rate = %lu\n", __func__, clk->name, clk->rate); - if(dvfs_clk->cur_freq == 0) - dvfs_clk_get_volt(dvfs_clk, clk->rate, &clk_fv); - else - dvfs_clk_get_volt(dvfs_clk, dvfs_clk->cur_freq, &clk_fv); - dvfs_clk->cur_volt = clk_fv.index; - dvfs_clk->cur_freq = clk_fv.frequency; - dvfs_clk_scale_volt(dvfs_clk, dvfs_clk->cur_volt); - dump_dbg_map(); - - } else { - DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs); - dvfs_clk->enable_dvfs++; } + mutex_unlock(&mutex); return 0; } -int dvfs_set_rate(struct clk *clk, unsigned long rate) -{ - int ret = 0; - struct vd_node *vd; - DVFS_DBG("%s dvfs start\n", clk->name); - if(!clk->dvfs_info) { - DVFS_ERR("%s :This clk do not support dvfs!\n", __func__); - ret = -1; - } else { - vd = clk->dvfs_info->vd; - mutex_lock(&vd->dvfs_mutex); - ret = vd->vd_dvfs_target(clk, rate); - mutex_unlock(&vd->dvfs_mutex); - } - return ret; -} - -/** - * get correspond voltage khz - */ -static int dvfs_clk_get_volt(struct clk_node *dvfs_clk, unsigned long rate, - struct cpufreq_frequency_table *clk_fv) -{ - int i = 0; - if (rate == 0) { - /* since no need*/ - return -1; - } - clk_fv->frequency = rate; - clk_fv->index = 0; - for(i = 0; (dvfs_clk->dvfs_table[i].frequency != FV_TABLE_END); i++) { - if(dvfs_clk->dvfs_table[i].frequency >= rate) { - clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency; - clk_fv->index = dvfs_clk->dvfs_table[i].index; - DVFS_DBG("%s dvfs_clk_get_volt rate=%u hz ref vol=%d uV\n", dvfs_clk->name, clk_fv->frequency, clk_fv->index); - return 0; - } - } - clk_fv->frequency = 0; - clk_fv->index = 0; - DVFS_ERR("%s get corresponding voltage error! out of bound\n", dvfs_clk->name); - return -1; -} - -static int dvfs_clk_round_volt(struct clk_node *dvfs_clk, int volt) +static int rk_regist_clk(struct clk_node *dvfs_clk) { struct pd_node *pd; - struct clk_node *dvfs_clk_tmp; - int volt_max = 0; - int i; - - for(i = 0; (dvfs_clk->pds[i].pd != NULL); i++) { - pd = dvfs_clk->pds[i].pd; - if(volt > pd->cur_volt) { - /** - * if dvfs_clk parent power domain's voltage is smaller then - * this dvfs_clk's voltage ignore this power domain - */ - volt_max = max(volt_max, volt); - continue; - } - list_for_each_entry(dvfs_clk_tmp, &pd->clk_list, node) { - /** - * found the max voltage uninclude dvfs_clk - */ - if(dvfs_clk_tmp != dvfs_clk) { - volt_max = max(volt_max, dvfs_clk_tmp->cur_volt); - } - } - } - - volt_max = max(volt_max, volt); - return volt_max; -} - -static void dvfs_clk_scale_volt(struct clk_node *dvfs_clk, unsigned int volt) -{ - struct vd_node *vd; - struct pd_node *pd; struct clk_list *child; - struct clk_node *dvfs_clk_tmp; - int volt_max_vd = 0, volt_max_pd = 0, i; - - dvfs_clk->cur_volt = volt;//set clk node volt - vd = dvfs_clk->vd;// vd - for(i = 0; (dvfs_clk->pds[i].pd != NULL); i++) { - pd = dvfs_clk->pds[i].pd; - volt_max_pd = 0; - /** - * set corresponding voltage, clk do not need to set voltage,just for - * powerdomain - */ - - if(volt > pd->cur_volt) { - pd->cur_volt = volt; - pd->pd_status = (pd->cur_volt == 0) ? PD_OFF : PD_ON; - continue; - } - - /* set power domain voltage */ - list_for_each_entry(child, &pd->clk_list, node) { - dvfs_clk_tmp = child->dvfs_clk; - if(dvfs_clk_tmp->enable_dvfs){ - volt_max_pd = max(volt_max_pd, dvfs_clk_tmp->cur_volt); - } - } - pd->cur_volt = volt_max_pd; + struct clk *clk; + int i = 0; - pd->pd_status = (volt_max_pd == 0) ? PD_OFF : PD_ON; - } + if(!dvfs_clk) + return -1; - /* set voltage domain voltage */ - volt_max_vd = 0; - list_for_each_entry(pd, &vd->pd_list, node) { - volt_max_vd = max(volt_max_vd, pd->cur_volt); + if(!dvfs_clk->pds) + return -1; + mutex_lock(&mutex); + dvfs_clk->enable_dvfs = 0; + dvfs_clk->vd = dvfs_clk->pds[0].pd->vd; + for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) { + child = &(dvfs_clk->pds[i].clk_list); + child->dvfs_clk = dvfs_clk; + pd = dvfs_clk->pds[i].pd; + list_add(&child->node, &pd->clk_list); } - vd->cur_volt = volt_max_vd; + clk = dvfs_clk_get(NULL, dvfs_clk->name); + dvfs_clk->ck=clk; + clk_register_dvfs(dvfs_clk, clk); + mutex_unlock(&mutex); + return 0; } -int dvfs_target_set_rate_core(struct clk *clk, unsigned long rate) +int dvfs_target_core(struct clk *clk, unsigned long rate_hz) { struct clk_node *dvfs_clk; - int volt_new = 0, volt_old = 0; - struct cpufreq_frequency_table clk_fv; + unsigned int volt_vd_new = 0,volt_vd_old = 0,volt_clk_old=0; + struct cpufreq_frequency_table clk_fv = {0, 0}; int ret = 0; - dvfs_clk = clk_get_dvfs_info(clk); + unsigned long temp_hz; + + if(!clk) + { + DVFS_ERR("%s is not clk\n",__func__); + return -1; + } + dvfs_clk = clk_get_dvfs_info(clk); - DVFS_ERR("%s get clk %s\n", __func__, clk->name); - if(dvfs_clk->vd->regulator == NULL) { + if(!dvfs_clk||dvfs_clk->vd->regulator == NULL) { DVFS_ERR("%s can't get dvfs regulater\n", clk->name); return -1; } + + temp_hz = rate_hz;//clk_round_rate_nolock(clk, rate_hz); + + //DVFS_DBG("dvfs(%s) round rate(%lu)(rount %lu)\n",dvfs_clk->name,rate_hz,temp_hz); - /* If power domain off do scale in the notify function */ - /* - if (rate == 0) { - dvfs_clk->cur_freq = 0; - dvfs_clk_scale_volt(dvfs_clk, 0); - return 0; - } - */ - /* need round rate */ - DVFS_ERR("%s going to round rate = %lu\n", clk->name, rate); - rate = clk_round_rate_nolock(clk, rate); - DVFS_ERR("%s round get rate = %lu\n", clk->name, rate); /* find the clk corresponding voltage */ - if (0 != dvfs_clk_get_volt(dvfs_clk, rate, &clk_fv)) { - DVFS_ERR("%s rate %lukhz is larger,not support\n", clk->name, rate); + if (dvfs_clk_get_ref_volt(dvfs_clk, temp_hz/1000, &clk_fv)) { + DVFS_ERR("%s--%s:rate%lu,Get corresponding voltage error!\n",__func__,dvfs_clk->name,temp_hz); return -1; } - volt_old = dvfs_clk->vd->cur_volt; - volt_new = clk_fv.index; + volt_vd_old = dvfs_clk->vd->cur_volt; - DVFS_DBG("vol_new = %d mV(was %d mV)\n", volt_new, volt_old); + volt_clk_old=dvfs_clk->set_volt; - /* if up the voltage*/ - if (volt_old < volt_new) { - if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) { - DVFS_ERR("set voltage err\n"); + dvfs_clk->set_volt=clk_fv.index; + volt_vd_new = dvfs_vd_get_newvolt_for_clk(dvfs_clk); + + DVFS_LOG("dvfs--(%s),volt=%d(was %dmV),rate=%lu(was %lu),vd%u=(was%u)\n", + dvfs_clk->name,clk_fv.index,dvfs_clk->set_volt,temp_hz,clk_get_rate(clk) + ,volt_vd_new,volt_vd_old); + // if up the voltage + #if 1 + if (volt_vd_old < volt_vd_new) { + if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_vd_new, volt_vd_new) < 0) { + DVFS_ERR("set voltage err\n"); return -1; } - dvfs_clk->vd->cur_volt = volt_new; - /* CPU do not use power domain, so save scale times */ - //dvfs_clk_scale_volt(dvfs_clk, clk_fv.index); + dvfs_clk->vd->cur_volt=volt_vd_new; } - + #endif if(dvfs_clk->clk_dvfs_target) { - ret = dvfs_clk->clk_dvfs_target(clk, rate, clk_set_rate_locked); + ret = dvfs_clk->clk_dvfs_target(clk, temp_hz, clk_set_rate_locked); } else { - ret = clk_set_rate_locked(clk, rate); + ret = clk_set_rate_locked(clk, temp_hz); } if (ret < 0) { + + dvfs_clk->set_volt=volt_vd_old; + dvfs_vd_get_newvolt_for_clk(dvfs_clk); DVFS_ERR("set rate err\n"); return -1; } - dvfs_clk->cur_freq = rate; - dvfs_clk->cur_volt = volt_new; - - /* if down the voltage */ - if (volt_old > volt_new) { - if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) { + dvfs_clk->set_freq = temp_hz/1000; + #if 1 + if (volt_vd_old > volt_vd_new){ + if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_vd_new, volt_vd_new) < 0) { DVFS_ERR("set voltage err\n"); - - return -1; + return -1; } - dvfs_clk->vd->cur_volt = volt_new; - /* CPU do not use power domain, so save scale times */ - //dvfs_clk_scale_volt(dvfs_clk, clk_fv.index); + dvfs_clk->vd->cur_volt=volt_vd_new; } - - return ret; + #endif + return 0; } +#define get_volt_up_delay(new_volt,old_volt) ((new_volt)>(old_volt)?\ + (((new_volt)-(old_volt))>>10):0) -int dvfs_target_set_rate_normal(struct clk *clk, unsigned long rate) +int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz) { struct clk_node *dvfs_clk; - unsigned int volt_new = 0, volt_old = 0; - struct cpufreq_frequency_table clk_fv = {0, 0}; + int volt_new = 0, volt_old = 0; + struct cpufreq_frequency_table clk_fv; int ret = 0; - - dvfs_clk = clk_get_dvfs_info(clk); - DVFS_ERR("%s get clk %s\n", __func__, clk->name); - if(dvfs_clk->vd->regulator == NULL) { - DVFS_DBG("%s can't get dvfs regulater\n", clk->name); + unsigned long temp_hz; + + if(!clk) + { + DVFS_ERR("%s is not clk\n",__func__); + return -1; + } + dvfs_clk = clk_get_dvfs_info(clk); + + if(!dvfs_clk||dvfs_clk->vd->regulator == NULL) { + DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name); return -1; } - /* need round rate */ - DVFS_ERR("%s going to round rate = %lu\n", clk->name, rate); - rate = clk_round_rate_nolock(clk, rate); - DVFS_ERR("%s round get rate = %lu\n", clk->name, rate); + temp_hz = clk_round_rate_nolock(clk, rate_hz); + + DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu)\n",dvfs_clk->name,rate_hz,temp_hz); + /* find the clk corresponding voltage */ - if (dvfs_clk_get_volt(dvfs_clk, rate, &clk_fv)) { - DVFS_DBG("dvfs_clk_get_volt:rate = Get corresponding voltage error!\n"); + if (0 != dvfs_clk_get_ref_volt(dvfs_clk, temp_hz/1000, &clk_fv)) { + DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n",dvfs_clk->name, rate_hz); return -1; } - volt_old = dvfs_clk->vd->cur_volt; - volt_new = dvfs_clk_round_volt(dvfs_clk, clk_fv.index); + volt_new = clk_fv.index; - // if up the voltage + DVFS_LOG("%s--(%s),volt=%d(was %dmV),rate=%lu(was %lu),vd=%u(was %u)\n",__func__, + dvfs_clk->name,volt_new,volt_old,temp_hz,clk_get_rate(clk) + ,volt_new,volt_old); + /* if up the voltage*/ if (volt_old < volt_new) { - if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) { - DVFS_DBG("set voltage err\n"); + if(dvfs_clk->vd->regulator&&dvfs_regulator_set_voltage(dvfs_clk->vd->regulator,volt_new, volt_new) < 0) { + DVFS_ERR("set voltage err\n"); return -1; } - dvfs_clk_scale_volt(dvfs_clk, clk_fv.index); + dvfs_clk->vd->cur_volt = volt_new; + DVFS_LOG("%s set volt ok up\n",dvfs_clk->name); + udelay(get_volt_up_delay(volt_new,volt_old)); + //DVFS_DBG("get_volt_up_delay%u",get_volt_up_delay(volt_new,volt_old)); } - + if(dvfs_clk->clk_dvfs_target) { - ret = dvfs_clk->clk_dvfs_target(clk, rate, clk_set_rate_locked); + ret = dvfs_clk->clk_dvfs_target(clk, temp_hz, clk_set_rate_locked); } else { - ret = clk_set_rate_locked(clk, rate); + ret = clk_set_rate_locked(clk, temp_hz); } if (ret < 0) { DVFS_ERR("set rate err\n"); return -1; - } - dvfs_clk->cur_freq = rate; - dvfs_clk->cur_volt = volt_new; - - // if down the voltage + } + dvfs_clk->set_freq = temp_hz/1000; + + DVFS_LOG("dvfs %s set rate%lu ok\n",dvfs_clk->name,clk_get_rate(clk)); + + /* if down the voltage */ if (volt_old > volt_new) { - if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) { - DVFS_DBG("set voltage err\n"); - return -1; - + if(dvfs_clk->vd->regulator&&dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) { + DVFS_ERR("set voltage err\n"); + return -1; } - dvfs_clk_scale_volt(dvfs_clk, clk_fv.index); + dvfs_clk->vd->cur_volt = volt_new; + DVFS_LOG("dvfs %s set volt ok dn\n",dvfs_clk->name); + } - - return 0; + return ret; } + /*****************************init**************************/ /** - * rate must be raising sequence - */ - -struct cpufreq_frequency_table cpu_dvfs_table[] = { - {.frequency = 126000000, .index = 800000}, - {.frequency = 252000000, .index = 850000}, - {.frequency = 504000000, .index = 900000}, - {.frequency = 816000000, .index = 1050000}, - {.frequency = 1008000000, .index = 1100000}, - {.frequency = 1200000000, .index = 1200000}, - {.frequency = FV_TABLE_END}, +* rate must be raising sequence +*/ +static struct cpufreq_frequency_table cpu_dvfs_table[] = { + //{.frequency = 48*DVFS_KHZ, .index = 920*DVFS_MV}, + //{.frequency = 126*DVFS_KHZ, .index = 970*DVFS_MV}, + // {.frequency = 252*DVFS_KHZ, .index = 1040*DVFS_MV}, + // {.frequency = 504*DVFS_KHZ, .index = 1060*DVFS_MV}, + {.frequency = 816*DVFS_KHZ, .index = 1080*DVFS_MV}, + // {.frequency = 1008*DVFS_KHZ, .index = 1100*DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, }; -struct cpufreq_frequency_table ddr_dvfs_table[] = { - {.frequency = 24000000, .index = 600000}, - {.frequency = 64000000, .index = 700000}, - {.frequency = 126000000, .index = 800000}, - {.frequency = 252000000, .index = 850000}, - {.frequency = 504000000, .index = 900000}, - {.frequency = FV_TABLE_END}, +static struct cpufreq_frequency_table ddr_dvfs_table[] = { + //{.frequency = 100*DVFS_KHZ, .index = 1100*DVFS_MV}, + {.frequency = 200*DVFS_KHZ, .index = 1000*DVFS_MV}, + {.frequency = 300*DVFS_KHZ, .index = 1050*DVFS_MV}, + {.frequency = 400*DVFS_KHZ, .index = 1100*DVFS_MV}, + {.frequency = 500*DVFS_KHZ, .index = 1150*DVFS_MV}, + {.frequency = 600*DVFS_KHZ, .index = 1200*DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, }; -struct cpufreq_frequency_table gpu_dvfs_table[] = { - {.frequency = 64000000, .index = 700000}, - {.frequency = 126000000, .index = 800000}, - {.frequency = 360000000, .index = 850000}, - {.frequency = FV_TABLE_END}, +static struct cpufreq_frequency_table gpu_dvfs_table[] = { + {.frequency = 100*DVFS_KHZ, .index = 1000*DVFS_MV}, + {.frequency = 200*DVFS_KHZ, .index = 1050*DVFS_MV}, + {.frequency = 300*DVFS_KHZ, .index = 1100*DVFS_MV}, + {.frequency = 400*DVFS_KHZ, .index = 1150*DVFS_MV}, + {.frequency = 500*DVFS_KHZ, .index = 1200*DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, +}; + +static struct cpufreq_frequency_table peri_aclk_dvfs_table[] = { + {.frequency = 100*DVFS_KHZ, .index = 1000*DVFS_MV}, + {.frequency = 200*DVFS_KHZ, .index = 1050*DVFS_MV}, + {.frequency = 300*DVFS_KHZ, .index = 1070*DVFS_MV}, + {.frequency = 500*DVFS_KHZ, .index = 1100*DVFS_MV}, + {.frequency = CPUFREQ_TABLE_END}, }; static struct vd_node vd_cpu = { .name = "vd_cpu", - .vd_dvfs_target = dvfs_target_set_rate_core, + .regulator_name = "vdd_cpu", + .vd_dvfs_target = dvfs_target_cpu, }; static struct vd_node vd_core = { .name = "vd_core", - .vd_dvfs_target = dvfs_target_set_rate_normal, + .regulator_name = "vdd_core", + .vd_dvfs_target = dvfs_target_core, }; static struct vd_node vd_rtc = { .name = "vd_rtc", + .regulator_name = "vdd_rtc", .vd_dvfs_target = NULL, }; -#define LOOKUP_VD(_pvd, _regulator_name) \ -{ \ - .vd = _pvd, \ - .regulator_name = _regulator_name, \ -} -static struct vd_node_lookup rk30_vds[] = { - LOOKUP_VD(&vd_cpu, "cpu"), - LOOKUP_VD(&vd_core, "core"), - LOOKUP_VD(&vd_rtc, "rtc"), -}; +static struct vd_node *rk30_vds[] = {&vd_cpu,&vd_core,&vd_rtc}; static struct pd_node pd_a9_0 = { .name = "pd_a9_0", @@ -681,134 +664,32 @@ static struct pds_list gpu_pds[] = { CLK_PDS(NULL), }; -#define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \ -{ \ - .name = _clk_name, \ - .pds = _ppds, \ +#define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \ + { \ + .name = _clk_name, \ + .pds = _ppds,\ .dvfs_table = _dvfs_table, \ .dvfs_nb = _dvfs_nb, \ -} + } + +static struct pds_list aclk_periph_pds[] = { + CLK_PDS(&pd_peri), + CLK_PDS(NULL), +}; + + static struct clk_node rk30_clks[] = { RK_CLKS("cpu", cpu_pds, cpu_dvfs_table, &rk_dvfs_clk_notifier), RK_CLKS("ddr", ddr_pds, ddr_dvfs_table, &rk_dvfs_clk_notifier), RK_CLKS("gpu", gpu_pds, gpu_dvfs_table, &rk_dvfs_clk_notifier), + RK_CLKS("aclk_periph", aclk_periph_pds, peri_aclk_dvfs_table,&rk_dvfs_clk_notifier), }; -/** - * first scale regulator volt - */ -static int rk_dvfs_check_regulator_volt(void) -{ - struct vd_node *vd; - struct pd_node *pd; - struct clk_list *child; - struct clk_node *dvfs_clk; - struct clk *clk; - struct cpufreq_frequency_table clk_fv; - unsigned int vmax_pd = 0, vmax_vd = 0; - list_for_each_entry(vd, &rk_dvfs_tree, node) { - vmax_vd = 0; - list_for_each_entry(pd, &vd->pd_list, node) { - vmax_pd = 0; - list_for_each_entry(child, &pd->clk_list, node) { - - dvfs_clk = child->dvfs_clk; - clk = dvfs_clk_get(NULL, dvfs_clk->name); - if(!clk || IS_ERR(clk)) { - DVFS_ERR("%s get clk %s error\n", __func__, dvfs_clk->name); - continue; - } - //DVFS_DBG("%s get clk %s rate = %lu\n", __func__, clk->name, clk->rate); - dvfs_clk_get_volt(dvfs_clk, clk->rate, &clk_fv); - dvfs_clk->cur_volt = clk_fv.index; - dvfs_clk->cur_freq = clk_fv.frequency; - vmax_pd = max(vmax_pd, clk_fv.index); - pd->pd_status = (vmax_pd == 0) ? PD_OFF : PD_ON; - } - pd->cur_volt = vmax_pd; - vmax_vd = max(vmax_vd, vmax_pd); - } - - vd->cur_volt = vmax_vd; - //DVFS_DBG("%s check error: %d, %d\n", vd->name, vd->cur_volt, dvfs_regulator_get_voltage(vd->regulator)); - //if (vd->cur_volt != dvfs_regulator_get_voltage(vd->regulator)) { - // DVFS_ERR("%s default voltage domain value error!\n", vd->name); - //} - } - return 0; -} - -static int rk_regist_vd(struct vd_node_lookup *vd_lookup) -{ - struct vd_node *vd; - if(!vd_lookup) - return -1; - vd = vd_lookup->vd; - vd->regulator_name = vd_lookup->regulator_name; - - mutex_lock(&mutex); - - mutex_init(&vd->dvfs_mutex); - list_add(&vd->node, &rk_dvfs_tree); - INIT_LIST_HEAD(&vd->pd_list); - - mutex_unlock(&mutex); - - return 0; -} -static int rk_regist_pd(struct pd_node_lookup *pd_lookup) -{ - struct vd_node *vd; - struct pd_node *pd; - - mutex_lock(&mutex); - pd = pd_lookup->pd; - - list_for_each_entry(vd, &rk_dvfs_tree, node) { - if (vd == pd->vd) { - list_add(&pd->node, &vd->pd_list); - INIT_LIST_HEAD(&pd->clk_list); - break; - } - } - mutex_unlock(&mutex); - return 0; -} -//extern int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb); - -static int rk_regist_clk(struct clk_node *dvfs_clk) -{ - struct pd_node *pd; - struct clk_list *child; - struct clk *clk; - int i = 0; - - if(!dvfs_clk) - return -1; - - if(!dvfs_clk->pds) - return -1; - - mutex_lock(&mutex); - // set clk unsupport dvfs - dvfs_clk->enable_dvfs = 0; - dvfs_clk->vd = dvfs_clk->pds[0].pd->vd; - for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) { - child = &(dvfs_clk->pds[i].clk_list); - child->dvfs_clk = dvfs_clk; - pd = dvfs_clk->pds[i].pd; - list_add(&child->node, &pd->clk_list); - } - clk = dvfs_clk_get(NULL, dvfs_clk->name); - clk_register_dvfs(dvfs_clk, clk); - mutex_unlock(&mutex); - return 0; -} int rk30_dvfs_init(void) { int i = 0; for (i = 0; i < ARRAY_SIZE(rk30_vds); i++) { - rk_regist_vd(&rk30_vds[i]); + rk_regist_vd(rk30_vds[i]); } for (i = 0; i < ARRAY_SIZE(rk30_pds); i++) { rk_regist_pd(&rk30_pds[i]); @@ -816,127 +697,51 @@ int rk30_dvfs_init(void) for (i = 0; i < ARRAY_SIZE(rk30_clks); i++) { rk_regist_clk(&rk30_clks[i]); } - dump_dbg_map(); - //DVFS_DBG("%s dvfs tree create finish!\n", __func__); - //rk_dvfs_check_regulator_volt(); + return 0; } -void dvfs_clk_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) -{ - struct clk_node *dvfs_clk = clk_get_dvfs_info(clk); - dvfs_clk->clk_dvfs_target = clk_dvfs_target; -} -// - -/* - *cpufreq_frequency_table->index for cpufreq is index - *cpufreq_frequency_table->index for dvfstable is volt +#if 1 +/** + * dump_dbg_map() : Draw all informations of dvfs while debug */ -int cpufreq_dvfs_init(struct clk *clk, struct cpufreq_frequency_table **table, clk_dvfs_target_callback clk_dvfs_target) +static void dump_dbg_map(void) { + int i; + struct vd_node *vd; + struct pd_node *pd, *clkparent; + struct clk_list *child; + struct clk_node *dvfs_clk; - struct cpufreq_frequency_table *freq_table; - struct clk_node *info = clk_get_dvfs_info(clk); - struct cpufreq_frequency_table *dvfs_table;//dvfs volt freq table - int i = 0; - DVFS_DBG("%s clk name %s\n", __func__, clk->name); - if(!info) { - return -1; - } - dvfs_table = info->dvfs_table; + DVFS_DBG("-------------DVFS DEBUG-----------\n\n\n"); + DVFS_DBG("RK30 DVFS TREE:\n"); + list_for_each_entry(vd, &rk_dvfs_tree, node) { + DVFS_DBG("|\n|- voltage domain:%s\n", vd->name); + DVFS_DBG("|- current voltage:%d\n", vd->cur_volt); - if(!dvfs_table) { - return -1; - } + list_for_each_entry(pd, &vd->pd_list, node) { + DVFS_DBG("| |\n| |- power domain:%s, status = %s, current volt = %d\n", + pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt); - /********************************count table num****************************/ - i = 0; - while(dvfs_table[i].frequency != FV_TABLE_END) { - //DVFS_DBG("dvfs_table1 %lu\n",dvfs_table[i].frequency); - i++; - } + list_for_each_entry(child, &pd->clk_list, node) { + dvfs_clk = child->dvfs_clk; + DVFS_DBG("| | |\n| | |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n", + dvfs_clk->name, dvfs_clk->set_freq, dvfs_clk->set_volt, dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE"); + for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) { + clkparent = dvfs_clk->pds[i].pd; + DVFS_DBG("| | | |- clock parents: %s, vd_parent = %s\n", clkparent->name, clkparent->vd->name); + } - freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * (i + 1), GFP_KERNEL); - //last freq is end tab - freq_table[i].index = i; - freq_table[i].frequency = CPUFREQ_TABLE_END; - - //set freq table - i = 0; - while(dvfs_table[i].frequency != FV_TABLE_END) { - freq_table[i].index = i; - freq_table[i].frequency = dvfs_table[i].frequency; - //DVFS_DBG("dvfs_table %d %lu\n",i,dvfs_table[i].frequency); - i++; - } - *table = &freq_table[0]; - dvfs_clk_set_rate_callback(clk, clk_dvfs_target); - return 0; -} + for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { + DVFS_DBG("| | | |- freq = %d, volt = %d\n", dvfs_clk->dvfs_table[i].frequency, dvfs_clk->dvfs_table[i].index); -int clk_dvfs_set_dvfs_table(struct clk *clk, struct cpufreq_frequency_table *table) -{ - struct clk_node *info = clk_get_dvfs_info(clk); - if(!table || !info) - return -1; - info->dvfs_table = table; - return 0; + } + } + } + } + DVFS_DBG("-------------DVFS DEBUG END------------\n"); } -/********************************simulation cases****************************/ - -#ifdef DVFS_TEST_OFF_BOARD -int rk30_dvfs_init_test(void) -{ - struct clk *clk1; - DVFS_DBG("********************************simulation cases****************************\n"); -#ifdef DEBUG_RK30_DVFS - DVFS_DBG("\n\n"); - dump_dbg_map(); #endif - clk1 = dvfs_clk_get(NULL, "cpu"); - if (clk1) { - dvfs_clk_set_rate(clk1, 1008000000); - dump_dbg_map(); - dvfs_clk_set_rate(clk1, 816000000); - dump_dbg_map(); - dvfs_clk_set_rate(clk1, 0); - dump_dbg_map(); - dvfs_clk_set_rate(clk1, 1200000000); - dump_dbg_map(); - dvfs_clk_set_rate(clk1, 1009000000); - dump_dbg_map(); - dvfs_clk_set_rate(clk1, 1416000000); - dump_dbg_map(); - - } else { - DVFS_DBG("\t\t%s:\t can not find clk cpu\n", __func__); - } - - clk1 = dvfs_clk_get(NULL, "gpu"); - if (clk1) { - dvfs_clk_set_rate(clk1, 120000000); - dump_dbg_map(); - dvfs_clk_enable(clk1); - dvfs_clk_disable(clk1); - dump_dbg_map(); - } else { - DVFS_DBG("\t\t%s:\t can not find clk gpu\n", __func__); - dump_dbg_map(); - } - clk1 = dvfs_clk_get(NULL, "arm_pll"); - if (clk1) { - dvfs_clk_set_rate(clk1, 24000000); - dump_dbg_map(); - } else { - DVFS_DBG("\t\t%s:\t can not find clk arm_pll\n", __func__); - } - DVFS_DBG("********************************simulation cases end***************************\n"); - - return 0; - -} -#endif diff --git a/arch/arm/mach-rk30/include/mach/dvfs.h b/arch/arm/mach-rk30/include/mach/dvfs.h old mode 100644 new mode 100755 index 92cef0e0ff00..67d79d8beaee --- a/arch/arm/mach-rk30/include/mach/dvfs.h +++ b/arch/arm/mach-rk30/include/mach/dvfs.h @@ -79,9 +79,10 @@ struct pds_list { struct clk_node { char *name; - int cur_freq; - int cur_volt; + int set_freq;//khz + int set_volt; int enable_dvfs; + struct clk *ck; struct pds_list *pds; struct vd_node *vd; struct cpufreq_frequency_table *dvfs_table; @@ -90,13 +91,33 @@ struct clk_node { clk_dvfs_target_callback clk_dvfs_target; }; +#ifdef CONFIG_DVFS int rk30_dvfs_init(void); int is_support_dvfs(struct clk_node *dvfs_info); int dvfs_set_rate(struct clk *clk, unsigned long rate); -void clk_set_dvfs_target_rate_callback(struct clk *ck, clk_dvfs_target_callback clk_dvfs_target); int clk_enable_dvfs(struct clk *clk); int clk_disable_dvfs(struct clk *clk); int cpufreq_dvfs_init(struct clk *ck, struct cpufreq_frequency_table **table, clk_dvfs_target_callback clk_dvfs_target); -int clk_dvfs_set_dvfs_table(struct clk *clk,struct cpufreq_frequency_table *table); +void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target); +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk); +int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table); +int rk30_dvfs_init(void); +#else +int rk30_dvfs_init(void){}; +int is_support_dvfs(struct clk_node *dvfs_info){}; +int dvfs_set_rate(struct clk *clk, unsigned long rate){}; +int clk_enable_dvfs(struct clk *clk){}; +int clk_disable_dvfs(struct clk *clk){}; +int cpufreq_dvfs_init(struct clk *ck, struct cpufreq_frequency_table **table, clk_dvfs_target_callback clk_dvfs_target){}; +void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target){}; +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk){}; +int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table); +int rk30_dvfs_init(void){}; + + + + +#endif + #endif diff --git a/arch/arm/plat-rk/Kconfig b/arch/arm/plat-rk/Kconfig index 9ba0b4d7c71a..caa635d836fa 100644 --- a/arch/arm/plat-rk/Kconfig +++ b/arch/arm/plat-rk/Kconfig @@ -95,6 +95,11 @@ config DDR_TEST select CRC32 default y +config DVFS + bool "Enable dvfs" + depends on REGULATOR&&CPU_FREQ + default y + config WIFI_CONTROL_FUNC bool "Enable WiFi control function abstraction" help