#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);
{
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;
}
if (delay == 0) {
CRU_PRINTK_ERR("wait pll bit 0x%x time out!\n", bit);
+ while(1);
}
}
{
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)
{
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);
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);
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));
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 ={
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 = {
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",
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;
//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.
#include <linux/slab.h>\r
#include <linux/clk.h>\r
#include <linux/cpufreq.h>\r
-\r
#include "clock.h"\r
#include <mach/dvfs.h>\r
#include <mach/clock.h>\r
+#include <linux/regulator/consumer.h>\r
+#include <linux/delay.h>\r
\r
-#if 0\r
-#define DVFS_DBG(fmt, args...) pr_debug(fmt, ##args)\r
+#define DVFS_DBG(fmt, args...) {while(0);}//pr_debug(fmt, ##args)\r
#define DVFS_ERR(fmt, args...) pr_err(fmt, ##args)\r
-#else\r
-#define DEBUG_RK30_DVFS\r
-#define DVFS_DBG(fmt, args...) printk(fmt, ##args)\r
-#define DVFS_ERR(fmt, args...) printk(fmt, ##args)\r
-#endif\r
-\r
-#ifndef CONFIG_ARCH_RK30\r
-#define DVFS_TEST_OFF_BOARD\r
-#endif\r
-\r
-\r
-\r
-#ifdef DVFS_TEST_OFF_BOARD\r
-/* Just for simulation */\r
-\r
-struct regulator {\r
- int min_uV;\r
-};\r
-#if 0\r
-static void test_regulator_put(struct regulator *regulator)\r
-{\r
- kfree(regulator);\r
-}\r
-#endif\r
-struct regulator regulators[100];\r
-static struct regulator *test_regulator_get(struct device *dev, const char *id) {\r
- static int ret_cnt = 0;\r
- return ®ulators[ret_cnt++];\r
-}\r
-\r
-static int test_regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)\r
-{\r
- regulator->min_uV = min_uV;\r
- return 0;\r
-}\r
-\r
-static int test_regulator_get_voltage(struct regulator *regulator)\r
-{\r
- return regulator->min_uV;\r
-}\r
-\r
-int rk30_clk_set_rate(struct clk *clk, unsigned long rate);\r
-static void dump_dbg_map(void);\r
-int rk30_dvfs_init_test(void);\r
-int rk30_clk_enable(struct clk *clk);\r
-int rk30_clk_disable(struct clk *clk);\r
-\r
-#define dvfs_regulator_get(dev,id) test_regulator_get((dev),(id))\r
-#define dvfs_regulator_put(regu) test_regulator_get((regu))\r
-#define dvfs_regulator_set_voltage(regu,min_uV,max_uV) test_regulator_set_voltage((regu),(min_uV),(max_uV))\r
-#define dvfs_regulator_get_voltage(regu) test_regulator_get_voltage((regu))\r
-\r
-/* clock */\r
-#define dvfs_clk_get(a,b) rk30_clk_get((a),(b))\r
-#define dvfs_clk_set_rate(a,b) rk30_clk_set_rate((a),(b))\r
-#define dvfs_clk_enable(a) rk30_clk_enable((a))\r
-#define dvfs_clk_disable(a) rk30_clk_disable((a))\r
-\r
-#else\r
-/* board runing */\r
-#include <linux/regulator/consumer.h>\r
+#define DVFS_LOG(fmt, args...) pr_debug(fmt, ##args)//while(0)\r
\r
#define dvfs_regulator_get(dev,id) regulator_get((dev),(id))\r
#define dvfs_regulator_put(regu) regulator_get((regu))\r
#define dvfs_regulator_get_voltage(regu) regulator_get_voltage((regu))\r
\r
#define dvfs_clk_get(a,b) clk_get((a),(b))\r
+#define dvfs_clk_get_rate_kz(a) (clk_get_rate((a))/1000)\r
#define dvfs_clk_set_rate(a,b) clk_set_rate((a),(b))\r
#define dvfs_clk_enable(a) clk_enable((a))\r
#define dvfs_clk_disable(a) clk_disable((a))\r
-#endif\r
+\r
+#define DVFS_MHZ (1000*1000)\r
+#define DVFS_KHZ (1000)\r
+\r
+#define DVFS_V (1000*1000)\r
+#define DVFS_MV (1000)\r
\r
\r
static LIST_HEAD(rk_dvfs_tree);\r
static DEFINE_MUTEX(mutex);\r
-/*\r
-int dvfs_target_core(struct clk *clk, unsigned int rate);\r
-int dvfs_target(struct clk *clk, unsigned int rate);\r
-int dvfs_clk_set_rate(struct clk *clk, unsigned long rate);\r
-*/\r
+\r
extern int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb);\r
extern int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);\r
\r
-#define FV_TABLE_END 0\r
#define PD_ON 1\r
#define PD_OFF 0\r
\r
-\r
-static void dvfs_clk_scale_volt(struct clk_node *dvfs_clk, unsigned int volt);\r
-static int dvfs_clk_get_volt(struct clk_node *dvfs_clk, unsigned long rate,\r
- struct cpufreq_frequency_table *clk_fv);\r
-\r
-/**\r
- * **************************FUNCTIONS***********************************\r
- */\r
-\r
-#ifdef DEBUG_RK30_DVFS\r
-/**\r
- * dump_dbg_map() : Draw all informations of dvfs while debug\r
- */\r
-static void dump_dbg_map(void)\r
+int is_support_dvfs(struct clk_node *dvfs_info)\r
{\r
- int i;\r
- struct vd_node *vd;\r
- struct pd_node *pd, *clkparent;\r
- struct clk_list *child;\r
- struct clk_node *dvfs_clk;\r
-\r
- DVFS_DBG("-------------DVFS DEBUG-----------\n\n\n");\r
- DVFS_DBG("RK30 DVFS TREE:\n");\r
- list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
- DVFS_DBG("|\n|- voltage domain:%s\n", vd->name);\r
- DVFS_DBG("|- current voltage:%d\n", vd->cur_volt);\r
+ return (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target && dvfs_info->enable_dvfs);\r
+}\r
+int dvfs_set_rate(struct clk *clk, unsigned long rate)\r
+{\r
+ int ret = 0;\r
+ struct vd_node *vd;\r
+ DVFS_DBG("%s(%s(%lu))\n",__func__,clk->name,rate);\r
+ if(!clk->dvfs_info) {\r
+ DVFS_ERR("%s :This clk do not support dvfs!\n", __func__);\r
+ ret = -1;\r
+ } else {\r
+ vd = clk->dvfs_info->vd;\r
+ mutex_lock(&vd->dvfs_mutex);\r
+ ret = vd->vd_dvfs_target(clk, rate);\r
+ mutex_unlock(&vd->dvfs_mutex);\r
+ }\r
+ DVFS_DBG("%s(%s(%lu)),is end\n",__func__,clk->name,rate);\r
+ return ret;\r
+}\r
\r
- list_for_each_entry(pd, &vd->pd_list, node) {\r
- DVFS_DBG("| |\n| |- power domain:%s, status = %s, current volt = %d\n",\r
- pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt);\r
+static int dvfs_clk_get_ref_volt(struct clk_node *dvfs_clk,int rate_khz,\r
+ struct cpufreq_frequency_table *clk_fv)\r
+{\r
+ int i = 0;\r
+ if (rate_khz == 0||!dvfs_clk||!dvfs_clk->dvfs_table) {\r
+ /* since no need*/\r
+ return -1;\r
+ }\r
+ clk_fv->frequency = rate_khz;\r
+ clk_fv->index = 0;\r
+ \r
+ for(i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {\r
+ if(dvfs_clk->dvfs_table[i].frequency >= rate_khz) {\r
+ clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency;\r
+ clk_fv->index = dvfs_clk->dvfs_table[i].index;\r
+ // DVFS_DBG("%s,%s rate=%ukhz(vol=%d)\n",__func__,dvfs_clk->name, clk_fv->frequency, clk_fv->index);\r
+ return 0;\r
+ }\r
+ }\r
+ clk_fv->frequency = 0;\r
+ clk_fv->index = 0;\r
+ // DVFS_DBG("%s get corresponding voltage error! out of bound\n", dvfs_clk->name);\r
+ return -1;\r
+}\r
\r
- list_for_each_entry(child, &pd->clk_list, node) {\r
- dvfs_clk = child->dvfs_clk;\r
- DVFS_DBG("| | |\n| | |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n",\r
- dvfs_clk->name, dvfs_clk->cur_freq, dvfs_clk->cur_volt, dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE");\r
- for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {\r
- clkparent = dvfs_clk->pds[i].pd;\r
- DVFS_DBG("| | | |- clock parents: %s, vd_parent = %s\n", clkparent->name, clkparent->vd->name);\r
- }\r
+static int dvfs_pd_get_newvolt_for_clk(struct pd_node *pd,struct clk_node *dvfs_clk)\r
+{\r
+ struct clk_list *child;\r
+ int volt_max = 0;\r
+ \r
+ if(!pd||!dvfs_clk)\r
+ return 0;\r
+\r
+ if(dvfs_clk->set_volt>=pd->cur_volt)\r
+ {\r
+ return dvfs_clk->set_volt;\r
+ }\r
+ \r
+ list_for_each_entry(child, &pd->clk_list, node){\r
+ //DVFS_DBG("%s ,pd(%s),dvfs(%s),volt(%u)\n",__func__,pd->name,dvfs_clk->name,dvfs_clk->set_volt);\r
+ volt_max = max(volt_max,child->dvfs_clk->set_volt);\r
+ }\r
+ return volt_max;\r
+}\r
\r
- for (i = 0; (dvfs_clk->dvfs_table[i].frequency != FV_TABLE_END); i++) {\r
- DVFS_DBG("| | | |- freq = %d, volt = %d\n", dvfs_clk->dvfs_table[i].frequency, dvfs_clk->dvfs_table[i].index);\r
+void dvfs_update_clk_pds_volt(struct clk_node *dvfs_clk)\r
+{\r
+ struct pd_node *pd;\r
+ int i;\r
+ if(!dvfs_clk)\r
+ return;\r
+ for(i = 0; (dvfs_clk->pds[i].pd != NULL); i++) {\r
+ pd = dvfs_clk->pds[i].pd;\r
+ // DVFS_DBG("%s dvfs(%s),pd(%s)\n",__func__,dvfs_clk->name,pd->name);\r
+ pd->cur_volt=dvfs_pd_get_newvolt_for_clk(pd,dvfs_clk);\r
+ }\r
+}\r
\r
- }\r
- }\r
+static int dvfs_get_vd_volt_bypd(struct vd_node *vd)\r
+{\r
+ struct pd_node *pd;\r
+ int volt_max_vd=0; \r
+ list_for_each_entry(pd, &vd->pd_list, node) {\r
+ //DVFS_DBG("%s pd(%s,%u)\n",__func__,pd->name,pd->cur_volt);\r
+ volt_max_vd = max(volt_max_vd, pd->cur_volt);\r
+ }\r
+ return volt_max_vd;\r
+}\r
+static int dvfs_vd_get_newvolt_for_clk(struct clk_node *dvfs_clk)\r
+{\r
+ if(!dvfs_clk)\r
+ return -1;\r
+ dvfs_update_clk_pds_volt(dvfs_clk);\r
+ return dvfs_get_vd_volt_bypd(dvfs_clk->vd);\r
+}\r
+void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target)\r
+{\r
+ struct clk_node *dvfs_clk = clk_get_dvfs_info(clk);\r
+ dvfs_clk->clk_dvfs_target = clk_dvfs_target;\r
+}\r
+struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk)\r
+{\r
+ struct clk_node *info = clk_get_dvfs_info(clk);\r
+\r
+ if(!info||!info->dvfs_table) {\r
+ return NULL;\r
+ }\r
+ mutex_lock(&mutex);\r
+ return info->dvfs_table;\r
+ mutex_unlock(&mutex);\r
+}\r
+int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table)\r
+{\r
+ struct clk_node *info = clk_get_dvfs_info(clk);\r
+ if(!table || !info)\r
+ return -1;\r
+\r
+ mutex_lock(&mutex);\r
+ info->dvfs_table = table;\r
+ mutex_unlock(&mutex);\r
+ return 0;\r
+}\r
+int clk_enable_dvfs(struct clk *clk)\r
+{\r
+ struct regulator *regulator;\r
+ struct clk_node *dvfs_clk;\r
+ struct cpufreq_frequency_table clk_fv;\r
+ if(!clk){\r
+ DVFS_ERR("clk enable dvfs error\n");\r
+ return -1;\r
+ } \r
+ dvfs_clk=clk_get_dvfs_info(clk);\r
+ if(!dvfs_clk||!dvfs_clk->vd) {\r
+ DVFS_ERR("%s clk(%s) not support dvfs!\n",__func__,clk->name);\r
+ return -1;\r
+ }\r
+ if(dvfs_clk->enable_dvfs==0){\r
+ \r
+ if(!dvfs_clk->vd->regulator) {\r
+ regulator=NULL;\r
+ if(dvfs_clk->vd->regulator_name)\r
+ regulator = dvfs_regulator_get(NULL,dvfs_clk->vd->regulator_name);\r
+ if(regulator)\r
+ { \r
+ //DVFS_DBG("dvfs_regulator_get(%s)\n",dvfs_clk->vd->regulator_name);\r
+ dvfs_clk->vd->regulator = regulator;\r
+ }\r
+ else\r
+ {\r
+ dvfs_clk->vd->regulator = NULL;\r
+ dvfs_clk->enable_dvfs=0;\r
+ DVFS_ERR("%s can't get regulator in %s\n",dvfs_clk->name,__func__);\r
+ return -1;\r
+ } \r
+ }\r
+ else\r
+ {\r
+ dvfs_clk->vd->cur_volt = dvfs_regulator_get_voltage(dvfs_clk->vd->regulator);\r
+ //DVFS_DBG("%s(%s) vd volt=%u\n",__func__,dvfs_clk->name,dvfs_clk->vd->cur_volt);\r
+ }\r
+ \r
+ dvfs_clk->set_freq=dvfs_clk_get_rate_kz(clk);\r
+ //DVFS_DBG("%s ,%s get freq%u!\n",__func__,dvfs_clk->name,dvfs_clk->set_freq);\r
+\r
+ if(dvfs_clk_get_ref_volt(dvfs_clk,dvfs_clk->set_freq,&clk_fv))\r
+ {\r
+ dvfs_clk->enable_dvfs=0;\r
+ return -1;\r
+ }\r
+ dvfs_clk->set_volt=clk_fv.index;\r
+ //DVFS_DBG("%s,%s,freq%u(ref vol %u)\n",__func__,dvfs_clk->name,\r
+ // dvfs_clk->set_freq,dvfs_clk->set_volt);\r
+#if 0\r
+ if(dvfs_clk->dvfs_nb) {\r
+ // must unregister when clk disable\r
+ rk30_clk_notifier_register(clk, dvfs_clk->dvfs_nb);\r
}\r
+#endif\r
+ dvfs_vd_get_newvolt_for_clk(dvfs_clk);\r
+ dvfs_clk->enable_dvfs++; \r
+ } else {\r
+ DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs);\r
+ dvfs_clk->enable_dvfs++;\r
}\r
- DVFS_DBG("-------------DVFS DEBUG END------------\n");\r
+ return 0;\r
}\r
-#endif\r
\r
-int is_support_dvfs(struct clk_node *dvfs_info)\r
+int clk_disable_dvfs(struct clk *clk)\r
{\r
- return (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target && dvfs_info->enable_dvfs);\r
+ struct clk_node *dvfs_clk;\r
+ dvfs_clk = clk->dvfs_info;\r
+ if(!dvfs_clk->enable_dvfs) {\r
+ DVFS_DBG("clk is already closed!\n");\r
+ return -1;\r
+ } else {\r
+ dvfs_clk->enable_dvfs--;\r
+ if(0 == dvfs_clk->enable_dvfs) {\r
+ DVFS_ERR("clk closed!\n");\r
+ rk30_clk_notifier_unregister(clk, dvfs_clk->dvfs_nb);\r
+ DVFS_DBG("clk unregister nb!\n");\r
+ }\r
+ }\r
+ return 0;\r
}\r
+\r
static int rk_dvfs_clk_notifier_event(struct notifier_block *this,\r
unsigned long event, void *ptr)\r
{\r
break;\r
case CLK_POST_DISABLE:\r
DVFS_DBG("%s CLK_POST_DISABLE\n", __func__);\r
- dvfs_clk->cur_freq = 0;\r
- dvfs_clk_scale_volt(dvfs_clk, 0);\r
+ dvfs_clk->set_freq = 0;\r
break;\r
case CLK_ABORT_DISABLE:\r
DVFS_DBG("%s CLK_ABORT_DISABLE\n", __func__);\r
static struct notifier_block rk_dvfs_clk_notifier = {\r
.notifier_call = rk_dvfs_clk_notifier_event,\r
};\r
-int clk_disable_dvfs(struct clk *clk)\r
+\r
+static int rk_regist_vd(struct vd_node *vd)\r
{\r
- struct clk_node *dvfs_clk;\r
- dvfs_clk = clk->dvfs_info;\r
- if(dvfs_clk->enable_dvfs - 1 < 0) {\r
- DVFS_ERR("clk is already closed!\n");\r
+ if(!vd)\r
return -1;\r
- } else {\r
- DVFS_ERR("clk is disable now!\n");\r
- dvfs_clk->enable_dvfs--;\r
- if(0 == dvfs_clk->enable_dvfs) {\r
- DVFS_ERR("clk closed!\n");\r
- rk30_clk_notifier_unregister(clk, dvfs_clk->dvfs_nb);\r
- DVFS_ERR("clk unregister nb!\n");\r
- dvfs_clk_scale_volt(dvfs_clk, 0);\r
- }\r
- }\r
- dump_dbg_map();\r
+ mutex_lock(&mutex);\r
+ mutex_init(&vd->dvfs_mutex);\r
+ list_add(&vd->node, &rk_dvfs_tree);\r
+ INIT_LIST_HEAD(&vd->pd_list);\r
+ \r
+ mutex_unlock(&mutex);\r
return 0;\r
}\r
-\r
-int clk_enable_dvfs(struct clk *clk)\r
+static int rk_regist_pd(struct pd_node_lookup *pd_lookup)\r
{\r
- struct regulator *regulator;\r
- struct clk_node *dvfs_clk;\r
- struct cpufreq_frequency_table clk_fv;\r
-\r
- if(!clk->dvfs_info) {\r
- DVFS_ERR("This clk(%s) not support dvfs!\n", clk->name);\r
- return -1;\r
- }\r
+ struct vd_node *vd;\r
+ struct pd_node *pd;\r
\r
- dvfs_clk = clk->dvfs_info;\r
- DVFS_ERR("dvfs clk enable dvfs %s\n", dvfs_clk->name);\r
- if(0 == dvfs_clk->enable_dvfs) {\r
- dvfs_clk->enable_dvfs++;\r
- if(!dvfs_clk->vd->regulator) {\r
- regulator = dvfs_regulator_get(NULL, dvfs_clk->vd->regulator_name);\r
- if(regulator)\r
- dvfs_clk->vd->regulator = regulator;\r
- else\r
- dvfs_clk->vd->regulator = NULL;\r
- }\r
- if(dvfs_clk->dvfs_nb) {\r
- // must unregister when clk disable\r
- rk30_clk_notifier_register(clk, dvfs_clk->dvfs_nb);\r
- }\r
+ mutex_lock(&mutex);\r
+ pd = pd_lookup->pd;\r
\r
- if(!clk || IS_ERR(clk)) {\r
- DVFS_ERR("%s get clk %s error\n", __func__, dvfs_clk->name);\r
- return -1;\r
+ list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+ if (vd == pd->vd) {\r
+ list_add(&pd->node, &vd->pd_list);\r
+ INIT_LIST_HEAD(&pd->clk_list);\r
+ break;\r
}\r
- //DVFS_DBG("%s get clk %s rate = %lu\n", __func__, clk->name, clk->rate);\r
- if(dvfs_clk->cur_freq == 0)\r
- dvfs_clk_get_volt(dvfs_clk, clk->rate, &clk_fv);\r
- else\r
- dvfs_clk_get_volt(dvfs_clk, dvfs_clk->cur_freq, &clk_fv);\r
- dvfs_clk->cur_volt = clk_fv.index;\r
- dvfs_clk->cur_freq = clk_fv.frequency;\r
- dvfs_clk_scale_volt(dvfs_clk, dvfs_clk->cur_volt);\r
- dump_dbg_map();\r
-\r
- } else {\r
- DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs);\r
- dvfs_clk->enable_dvfs++;\r
}\r
+ mutex_unlock(&mutex);\r
return 0;\r
}\r
\r
-int dvfs_set_rate(struct clk *clk, unsigned long rate)\r
-{\r
- int ret = 0;\r
- struct vd_node *vd;\r
- DVFS_DBG("%s dvfs start\n", clk->name);\r
- if(!clk->dvfs_info) {\r
- DVFS_ERR("%s :This clk do not support dvfs!\n", __func__);\r
- ret = -1;\r
- } else {\r
- vd = clk->dvfs_info->vd;\r
- mutex_lock(&vd->dvfs_mutex);\r
- ret = vd->vd_dvfs_target(clk, rate);\r
- mutex_unlock(&vd->dvfs_mutex);\r
- }\r
- return ret;\r
-}\r
-\r
-/**\r
- * get correspond voltage khz\r
- */\r
-static int dvfs_clk_get_volt(struct clk_node *dvfs_clk, unsigned long rate,\r
- struct cpufreq_frequency_table *clk_fv)\r
-{\r
- int i = 0;\r
- if (rate == 0) {\r
- /* since no need*/\r
- return -1;\r
- }\r
- clk_fv->frequency = rate;\r
- clk_fv->index = 0;\r
- for(i = 0; (dvfs_clk->dvfs_table[i].frequency != FV_TABLE_END); i++) {\r
- if(dvfs_clk->dvfs_table[i].frequency >= rate) {\r
- clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency;\r
- clk_fv->index = dvfs_clk->dvfs_table[i].index;\r
- DVFS_DBG("%s dvfs_clk_get_volt rate=%u hz ref vol=%d uV\n", dvfs_clk->name, clk_fv->frequency, clk_fv->index);\r
- return 0;\r
- }\r
- }\r
- clk_fv->frequency = 0;\r
- clk_fv->index = 0;\r
- DVFS_ERR("%s get corresponding voltage error! out of bound\n", dvfs_clk->name);\r
- return -1;\r
-}\r
-\r
-static int dvfs_clk_round_volt(struct clk_node *dvfs_clk, int volt)\r
+static int rk_regist_clk(struct clk_node *dvfs_clk)\r
{\r
struct pd_node *pd;\r
- struct clk_node *dvfs_clk_tmp;\r
- int volt_max = 0;\r
- int i;\r
-\r
- for(i = 0; (dvfs_clk->pds[i].pd != NULL); i++) {\r
- pd = dvfs_clk->pds[i].pd;\r
- if(volt > pd->cur_volt) {\r
- /**\r
- * if dvfs_clk parent power domain's voltage is smaller then\r
- * this dvfs_clk's voltage ignore this power domain\r
- */\r
- volt_max = max(volt_max, volt);\r
- continue;\r
- }\r
- list_for_each_entry(dvfs_clk_tmp, &pd->clk_list, node) {\r
- /**\r
- * found the max voltage uninclude dvfs_clk\r
- */\r
- if(dvfs_clk_tmp != dvfs_clk) {\r
- volt_max = max(volt_max, dvfs_clk_tmp->cur_volt);\r
- }\r
- }\r
- }\r
-\r
- volt_max = max(volt_max, volt);\r
- return volt_max;\r
-}\r
-\r
-static void dvfs_clk_scale_volt(struct clk_node *dvfs_clk, unsigned int volt)\r
-{\r
- struct vd_node *vd;\r
- struct pd_node *pd;\r
struct clk_list *child;\r
- struct clk_node *dvfs_clk_tmp;\r
- int volt_max_vd = 0, volt_max_pd = 0, i;\r
-\r
- dvfs_clk->cur_volt = volt;//set clk node volt\r
- vd = dvfs_clk->vd;// vd\r
- for(i = 0; (dvfs_clk->pds[i].pd != NULL); i++) {\r
- pd = dvfs_clk->pds[i].pd;\r
- volt_max_pd = 0;\r
- /**\r
- * set corresponding voltage, clk do not need to set voltage,just for\r
- * powerdomain\r
- */\r
-\r
- if(volt > pd->cur_volt) {\r
- pd->cur_volt = volt;\r
- pd->pd_status = (pd->cur_volt == 0) ? PD_OFF : PD_ON;\r
- continue;\r
- }\r
-\r
- /* set power domain voltage */\r
- list_for_each_entry(child, &pd->clk_list, node) {\r
- dvfs_clk_tmp = child->dvfs_clk;\r
- if(dvfs_clk_tmp->enable_dvfs){\r
- volt_max_pd = max(volt_max_pd, dvfs_clk_tmp->cur_volt);\r
- }\r
- }\r
- pd->cur_volt = volt_max_pd;\r
+ struct clk *clk;\r
+ int i = 0;\r
\r
- pd->pd_status = (volt_max_pd == 0) ? PD_OFF : PD_ON;\r
- }\r
+ if(!dvfs_clk)\r
+ return -1;\r
\r
- /* set voltage domain voltage */\r
- volt_max_vd = 0;\r
- list_for_each_entry(pd, &vd->pd_list, node) {\r
- volt_max_vd = max(volt_max_vd, pd->cur_volt);\r
+ if(!dvfs_clk->pds)\r
+ return -1;\r
+ mutex_lock(&mutex);\r
+ dvfs_clk->enable_dvfs = 0;\r
+ dvfs_clk->vd = dvfs_clk->pds[0].pd->vd;\r
+ for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {\r
+ child = &(dvfs_clk->pds[i].clk_list);\r
+ child->dvfs_clk = dvfs_clk;\r
+ pd = dvfs_clk->pds[i].pd;\r
+ list_add(&child->node, &pd->clk_list);\r
}\r
- vd->cur_volt = volt_max_vd;\r
+ clk = dvfs_clk_get(NULL, dvfs_clk->name);\r
+ dvfs_clk->ck=clk;\r
+ clk_register_dvfs(dvfs_clk, clk);\r
+ mutex_unlock(&mutex);\r
+ return 0;\r
}\r
\r
-int dvfs_target_set_rate_core(struct clk *clk, unsigned long rate)\r
+int dvfs_target_core(struct clk *clk, unsigned long rate_hz)\r
{\r
struct clk_node *dvfs_clk;\r
- int volt_new = 0, volt_old = 0;\r
- struct cpufreq_frequency_table clk_fv;\r
+ unsigned int volt_vd_new = 0,volt_vd_old = 0,volt_clk_old=0;\r
+ struct cpufreq_frequency_table clk_fv = {0, 0};\r
int ret = 0;\r
- dvfs_clk = clk_get_dvfs_info(clk);\r
+ unsigned long temp_hz;\r
+\r
+ if(!clk)\r
+ {\r
+ DVFS_ERR("%s is not clk\n",__func__);\r
+ return -1;\r
+ }\r
+ dvfs_clk = clk_get_dvfs_info(clk);\r
\r
- DVFS_ERR("%s get clk %s\n", __func__, clk->name);\r
- if(dvfs_clk->vd->regulator == NULL) {\r
+ if(!dvfs_clk||dvfs_clk->vd->regulator == NULL) {\r
DVFS_ERR("%s can't get dvfs regulater\n", clk->name);\r
return -1;\r
}\r
+ \r
+ temp_hz = rate_hz;//clk_round_rate_nolock(clk, rate_hz);\r
+ \r
+ //DVFS_DBG("dvfs(%s) round rate(%lu)(rount %lu)\n",dvfs_clk->name,rate_hz,temp_hz);\r
\r
- /* If power domain off do scale in the notify function */\r
- /*\r
- if (rate == 0) {\r
- dvfs_clk->cur_freq = 0;\r
- dvfs_clk_scale_volt(dvfs_clk, 0);\r
- return 0;\r
- }\r
- */\r
- /* need round rate */\r
- DVFS_ERR("%s going to round rate = %lu\n", clk->name, rate);\r
- rate = clk_round_rate_nolock(clk, rate);\r
- DVFS_ERR("%s round get rate = %lu\n", clk->name, rate);\r
/* find the clk corresponding voltage */\r
- if (0 != dvfs_clk_get_volt(dvfs_clk, rate, &clk_fv)) {\r
- DVFS_ERR("%s rate %lukhz is larger,not support\n", clk->name, rate);\r
+ if (dvfs_clk_get_ref_volt(dvfs_clk, temp_hz/1000, &clk_fv)) {\r
+ DVFS_ERR("%s--%s:rate%lu,Get corresponding voltage error!\n",__func__,dvfs_clk->name,temp_hz);\r
return -1;\r
}\r
- volt_old = dvfs_clk->vd->cur_volt;\r
- volt_new = clk_fv.index;\r
+ volt_vd_old = dvfs_clk->vd->cur_volt;\r
\r
- DVFS_DBG("vol_new = %d mV(was %d mV)\n", volt_new, volt_old);\r\r
+ volt_clk_old=dvfs_clk->set_volt;\r
\r
- /* if up the voltage*/\r
- if (volt_old < volt_new) {\r
- if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) {\r
- DVFS_ERR("set voltage err\n");\r
+ dvfs_clk->set_volt=clk_fv.index;\r
\r
+ volt_vd_new = dvfs_vd_get_newvolt_for_clk(dvfs_clk);\r
+\r
+ DVFS_LOG("dvfs--(%s),volt=%d(was %dmV),rate=%lu(was %lu),vd%u=(was%u)\n",\r
+ dvfs_clk->name,clk_fv.index,dvfs_clk->set_volt,temp_hz,clk_get_rate(clk)\r
+ ,volt_vd_new,volt_vd_old);\r
+ // if up the voltage\r
+ #if 1\r
+ if (volt_vd_old < volt_vd_new) {\r
+ if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_vd_new, volt_vd_new) < 0) {\r
+ DVFS_ERR("set voltage err\n");\r
return -1;\r
}\r
- dvfs_clk->vd->cur_volt = volt_new;\r
- /* CPU do not use power domain, so save scale times */\r
- //dvfs_clk_scale_volt(dvfs_clk, clk_fv.index);\r
+ dvfs_clk->vd->cur_volt=volt_vd_new;\r
}\r
-\r
+ #endif\r
if(dvfs_clk->clk_dvfs_target) {\r
- ret = dvfs_clk->clk_dvfs_target(clk, rate, clk_set_rate_locked);\r
+ ret = dvfs_clk->clk_dvfs_target(clk, temp_hz, clk_set_rate_locked);\r
} else {\r
- ret = clk_set_rate_locked(clk, rate);\r
+ ret = clk_set_rate_locked(clk, temp_hz);\r
}\r
if (ret < 0) {\r
+ \r
+ dvfs_clk->set_volt=volt_vd_old;\r
+ dvfs_vd_get_newvolt_for_clk(dvfs_clk); \r
DVFS_ERR("set rate err\n");\r
return -1;\r
}\r
- dvfs_clk->cur_freq = rate;\r
- dvfs_clk->cur_volt = volt_new;\r
-\r
- /* if down the voltage */\r
- if (volt_old > volt_new) {\r
- if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) {\r
+ dvfs_clk->set_freq = temp_hz/1000;\r
+ #if 1\r
+ if (volt_vd_old > volt_vd_new){\r
+ if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_vd_new, volt_vd_new) < 0) {\r
DVFS_ERR("set voltage err\n");\r
-\r
- return -1;\r
+ return -1;\r
}\r
- dvfs_clk->vd->cur_volt = volt_new;\r
- /* CPU do not use power domain, so save scale times */\r
- //dvfs_clk_scale_volt(dvfs_clk, clk_fv.index);\r
+ dvfs_clk->vd->cur_volt=volt_vd_new;\r
}\r
-\r
- return ret;\r
+ #endif\r
+ return 0;\r
}\r
+#define get_volt_up_delay(new_volt,old_volt) ((new_volt)>(old_volt)?\\r
+ (((new_volt)-(old_volt))>>10):0)\r
\r
-int dvfs_target_set_rate_normal(struct clk *clk, unsigned long rate)\r
+int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz)\r
{\r
struct clk_node *dvfs_clk;\r
- unsigned int volt_new = 0, volt_old = 0;\r
- struct cpufreq_frequency_table clk_fv = {0, 0};\r
+ int volt_new = 0, volt_old = 0;\r
+ struct cpufreq_frequency_table clk_fv;\r
int ret = 0;\r
-\r
- dvfs_clk = clk_get_dvfs_info(clk);\r
- DVFS_ERR("%s get clk %s\n", __func__, clk->name);\r
- if(dvfs_clk->vd->regulator == NULL) {\r
- DVFS_DBG("%s can't get dvfs regulater\n", clk->name);\r
+ unsigned long temp_hz;\r
+\r
+ if(!clk)\r
+ {\r
+ DVFS_ERR("%s is not clk\n",__func__);\r
+ return -1;\r
+ }\r
+ dvfs_clk = clk_get_dvfs_info(clk);\r
+ \r
+ if(!dvfs_clk||dvfs_clk->vd->regulator == NULL) {\r
+ DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name);\r
return -1;\r
}\r
-\r
/* need round rate */\r
- DVFS_ERR("%s going to round rate = %lu\n", clk->name, rate);\r
- rate = clk_round_rate_nolock(clk, rate);\r
- DVFS_ERR("%s round get rate = %lu\n", clk->name, rate);\r
+ temp_hz = clk_round_rate_nolock(clk, rate_hz);\r
+ \r
+ DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu)\n",dvfs_clk->name,rate_hz,temp_hz);\r
+\r
/* find the clk corresponding voltage */\r
- if (dvfs_clk_get_volt(dvfs_clk, rate, &clk_fv)) {\r
- DVFS_DBG("dvfs_clk_get_volt:rate = Get corresponding voltage error!\n");\r
+ if (0 != dvfs_clk_get_ref_volt(dvfs_clk, temp_hz/1000, &clk_fv)) {\r
+ DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n",dvfs_clk->name, rate_hz);\r
return -1;\r
}\r
-\r
volt_old = dvfs_clk->vd->cur_volt;\r
- volt_new = dvfs_clk_round_volt(dvfs_clk, clk_fv.index);\r
+ volt_new = clk_fv.index;\r
\r
- // if up the voltage\r
+ DVFS_LOG("%s--(%s),volt=%d(was %dmV),rate=%lu(was %lu),vd=%u(was %u)\n",__func__,\r
+ dvfs_clk->name,volt_new,volt_old,temp_hz,clk_get_rate(clk)\r
+ ,volt_new,volt_old);\r
+ /* if up the voltage*/\r
if (volt_old < volt_new) {\r
- if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) {\r
- DVFS_DBG("set voltage err\n");\r\r
+ if(dvfs_clk->vd->regulator&&dvfs_regulator_set_voltage(dvfs_clk->vd->regulator,volt_new, volt_new) < 0) {\r
+ DVFS_ERR("set voltage err\n");\r
return -1;\r
}\r
- dvfs_clk_scale_volt(dvfs_clk, clk_fv.index);\r
+ dvfs_clk->vd->cur_volt = volt_new;\r
+ DVFS_LOG("%s set volt ok up\n",dvfs_clk->name); \r
+ udelay(get_volt_up_delay(volt_new,volt_old));\r
+ //DVFS_DBG("get_volt_up_delay%u",get_volt_up_delay(volt_new,volt_old));\r
}\r
-\r
+ \r
if(dvfs_clk->clk_dvfs_target) {\r
- ret = dvfs_clk->clk_dvfs_target(clk, rate, clk_set_rate_locked);\r
+ ret = dvfs_clk->clk_dvfs_target(clk, temp_hz, clk_set_rate_locked);\r
} else {\r
- ret = clk_set_rate_locked(clk, rate);\r\r
+ ret = clk_set_rate_locked(clk, temp_hz);\r
}\r
if (ret < 0) {\r
DVFS_ERR("set rate err\n");\r
return -1;\r
- }\r
- dvfs_clk->cur_freq = rate;\r
- dvfs_clk->cur_volt = volt_new;\r
-\r
- // if down the voltage\r
+ } \r
+ dvfs_clk->set_freq = temp_hz/1000;\r
+ \r
+ DVFS_LOG("dvfs %s set rate%lu ok\n",dvfs_clk->name,clk_get_rate(clk));\r
+ \r
+ /* if down the voltage */\r
if (volt_old > volt_new) {\r
- if(dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) {\r
- DVFS_DBG("set voltage err\n");\r
- return -1;\r
-\r
+ if(dvfs_clk->vd->regulator&&dvfs_regulator_set_voltage(dvfs_clk->vd->regulator, volt_new, volt_new) < 0) {\r
+ DVFS_ERR("set voltage err\n");\r
+ return -1;\r
}\r
- dvfs_clk_scale_volt(dvfs_clk, clk_fv.index);\r
+ dvfs_clk->vd->cur_volt = volt_new;\r
+ DVFS_LOG("dvfs %s set volt ok dn\n",dvfs_clk->name);\r
+ \r
}\r
-\r
- return 0;\r
+ return ret;\r
}\r
\r
\r
+\r
/*****************************init**************************/\r
/**\r
- * rate must be raising sequence\r
- */\r
-\r
-struct cpufreq_frequency_table cpu_dvfs_table[] = {\r
- {.frequency = 126000000, .index = 800000},\r
- {.frequency = 252000000, .index = 850000},\r
- {.frequency = 504000000, .index = 900000},\r
- {.frequency = 816000000, .index = 1050000},\r
- {.frequency = 1008000000, .index = 1100000},\r
- {.frequency = 1200000000, .index = 1200000},\r
- {.frequency = FV_TABLE_END},\r
+* rate must be raising sequence\r
+*/\r
+static struct cpufreq_frequency_table cpu_dvfs_table[] = {\r
+ //{.frequency = 48*DVFS_KHZ, .index = 920*DVFS_MV},\r
+ //{.frequency = 126*DVFS_KHZ, .index = 970*DVFS_MV},\r
+ // {.frequency = 252*DVFS_KHZ, .index = 1040*DVFS_MV},\r
+ // {.frequency = 504*DVFS_KHZ, .index = 1060*DVFS_MV},\r
+ {.frequency = 816*DVFS_KHZ, .index = 1080*DVFS_MV},\r
+ // {.frequency = 1008*DVFS_KHZ, .index = 1100*DVFS_MV},\r
+ {.frequency = CPUFREQ_TABLE_END},\r
};\r
-struct cpufreq_frequency_table ddr_dvfs_table[] = {\r
- {.frequency = 24000000, .index = 600000},\r
- {.frequency = 64000000, .index = 700000},\r
- {.frequency = 126000000, .index = 800000},\r
- {.frequency = 252000000, .index = 850000},\r
- {.frequency = 504000000, .index = 900000},\r
- {.frequency = FV_TABLE_END},\r
+static struct cpufreq_frequency_table ddr_dvfs_table[] = {\r
+ //{.frequency = 100*DVFS_KHZ, .index = 1100*DVFS_MV},\r
+ {.frequency = 200*DVFS_KHZ, .index = 1000*DVFS_MV},\r
+ {.frequency = 300*DVFS_KHZ, .index = 1050*DVFS_MV},\r
+ {.frequency = 400*DVFS_KHZ, .index = 1100*DVFS_MV},\r
+ {.frequency = 500*DVFS_KHZ, .index = 1150*DVFS_MV},\r
+ {.frequency = 600*DVFS_KHZ, .index = 1200*DVFS_MV},\r
+ {.frequency = CPUFREQ_TABLE_END}, \r
};\r
-struct cpufreq_frequency_table gpu_dvfs_table[] = {\r
- {.frequency = 64000000, .index = 700000},\r
- {.frequency = 126000000, .index = 800000},\r
- {.frequency = 360000000, .index = 850000},\r
- {.frequency = FV_TABLE_END},\r
+static struct cpufreq_frequency_table gpu_dvfs_table[] = {\r
+ {.frequency = 100*DVFS_KHZ, .index = 1000*DVFS_MV},\r
+ {.frequency = 200*DVFS_KHZ, .index = 1050*DVFS_MV},\r
+ {.frequency = 300*DVFS_KHZ, .index = 1100*DVFS_MV},\r
+ {.frequency = 400*DVFS_KHZ, .index = 1150*DVFS_MV},\r
+ {.frequency = 500*DVFS_KHZ, .index = 1200*DVFS_MV},\r
+ {.frequency = CPUFREQ_TABLE_END}, \r
+};\r
+\r
+static struct cpufreq_frequency_table peri_aclk_dvfs_table[] = {\r
+ {.frequency = 100*DVFS_KHZ, .index = 1000*DVFS_MV},\r
+ {.frequency = 200*DVFS_KHZ, .index = 1050*DVFS_MV},\r
+ {.frequency = 300*DVFS_KHZ, .index = 1070*DVFS_MV},\r
+ {.frequency = 500*DVFS_KHZ, .index = 1100*DVFS_MV},\r
+ {.frequency = CPUFREQ_TABLE_END}, \r
};\r
\r
static struct vd_node vd_cpu = {\r
.name = "vd_cpu",\r
- .vd_dvfs_target = dvfs_target_set_rate_core,\r
+ .regulator_name = "vdd_cpu",\r
+ .vd_dvfs_target = dvfs_target_cpu,\r
};\r
\r
static struct vd_node vd_core = {\r
.name = "vd_core",\r
- .vd_dvfs_target = dvfs_target_set_rate_normal,\r
+ .regulator_name = "vdd_core",\r
+ .vd_dvfs_target = dvfs_target_core,\r
};\r
\r
static struct vd_node vd_rtc = {\r
.name = "vd_rtc",\r
+ .regulator_name = "vdd_rtc",\r
.vd_dvfs_target = NULL,\r
};\r
\r
-#define LOOKUP_VD(_pvd, _regulator_name) \\r
-{ \\r
- .vd = _pvd, \\r
- .regulator_name = _regulator_name, \\r
-}\r
-static struct vd_node_lookup rk30_vds[] = {\r
- LOOKUP_VD(&vd_cpu, "cpu"),\r
- LOOKUP_VD(&vd_core, "core"),\r
- LOOKUP_VD(&vd_rtc, "rtc"),\r
-};\r
+static struct vd_node *rk30_vds[] = {&vd_cpu,&vd_core,&vd_rtc};\r
\r
static struct pd_node pd_a9_0 = {\r
.name = "pd_a9_0",\r
CLK_PDS(NULL),\r
};\r
\r
-#define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \\r
-{ \\r
- .name = _clk_name, \\r
- .pds = _ppds, \\r
+#define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \\r
+ { \\r
+ .name = _clk_name, \\r
+ .pds = _ppds,\\r
.dvfs_table = _dvfs_table, \\r
.dvfs_nb = _dvfs_nb, \\r
-}\r
+ }\r
+\r
+static struct pds_list aclk_periph_pds[] = {\r
+ CLK_PDS(&pd_peri),\r
+ CLK_PDS(NULL),\r
+};\r
+\r
+\r
static struct clk_node rk30_clks[] = {\r
RK_CLKS("cpu", cpu_pds, cpu_dvfs_table, &rk_dvfs_clk_notifier),\r
RK_CLKS("ddr", ddr_pds, ddr_dvfs_table, &rk_dvfs_clk_notifier),\r
RK_CLKS("gpu", gpu_pds, gpu_dvfs_table, &rk_dvfs_clk_notifier),\r
+ RK_CLKS("aclk_periph", aclk_periph_pds, peri_aclk_dvfs_table,&rk_dvfs_clk_notifier),\r
};\r
-/**\r
- * first scale regulator volt\r
- */\r
-static int rk_dvfs_check_regulator_volt(void)\r
-{\r
- struct vd_node *vd;\r
- struct pd_node *pd;\r
- struct clk_list *child;\r
- struct clk_node *dvfs_clk;\r
- struct clk *clk;\r
- struct cpufreq_frequency_table clk_fv;\r
- unsigned int vmax_pd = 0, vmax_vd = 0;\r
\r
- list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
- vmax_vd = 0;\r
- list_for_each_entry(pd, &vd->pd_list, node) {\r
- vmax_pd = 0;\r
- list_for_each_entry(child, &pd->clk_list, node) {\r
-\r
- dvfs_clk = child->dvfs_clk;\r
- clk = dvfs_clk_get(NULL, dvfs_clk->name);\r
- if(!clk || IS_ERR(clk)) {\r
- DVFS_ERR("%s get clk %s error\n", __func__, dvfs_clk->name);\r
- continue;\r
- }\r
- //DVFS_DBG("%s get clk %s rate = %lu\n", __func__, clk->name, clk->rate);\r
- dvfs_clk_get_volt(dvfs_clk, clk->rate, &clk_fv);\r
- dvfs_clk->cur_volt = clk_fv.index;\r
- dvfs_clk->cur_freq = clk_fv.frequency;\r
- vmax_pd = max(vmax_pd, clk_fv.index);\r
- pd->pd_status = (vmax_pd == 0) ? PD_OFF : PD_ON;\r
- }\r
- pd->cur_volt = vmax_pd;\r
- vmax_vd = max(vmax_vd, vmax_pd);\r
- }\r
-\r
- vd->cur_volt = vmax_vd;\r
- //DVFS_DBG("%s check error: %d, %d\n", vd->name, vd->cur_volt, dvfs_regulator_get_voltage(vd->regulator));\r
- //if (vd->cur_volt != dvfs_regulator_get_voltage(vd->regulator)) {\r
- // DVFS_ERR("%s default voltage domain value error!\n", vd->name);\r
- //}\r
- }\r
- return 0;\r
-}\r
-\r
-static int rk_regist_vd(struct vd_node_lookup *vd_lookup)\r
-{\r
- struct vd_node *vd;\r
- if(!vd_lookup)\r
- return -1;\r
- vd = vd_lookup->vd;\r
- vd->regulator_name = vd_lookup->regulator_name;\r
-\r
- mutex_lock(&mutex);\r
-\r
- mutex_init(&vd->dvfs_mutex);\r
- list_add(&vd->node, &rk_dvfs_tree);\r
- INIT_LIST_HEAD(&vd->pd_list);\r
-\r
- mutex_unlock(&mutex);\r
-\r
- return 0;\r
-}\r
-static int rk_regist_pd(struct pd_node_lookup *pd_lookup)\r
-{\r
- struct vd_node *vd;\r
- struct pd_node *pd;\r
-\r
- mutex_lock(&mutex);\r
- pd = pd_lookup->pd;\r
-\r
- list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
- if (vd == pd->vd) {\r
- list_add(&pd->node, &vd->pd_list);\r
- INIT_LIST_HEAD(&pd->clk_list);\r
- break;\r
- }\r
- }\r
- mutex_unlock(&mutex);\r
- return 0;\r
-}\r
-//extern int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb);\r
-\r
-static int rk_regist_clk(struct clk_node *dvfs_clk)\r
-{\r
- struct pd_node *pd;\r
- struct clk_list *child;\r
- struct clk *clk;\r
- int i = 0;\r
-\r
- if(!dvfs_clk)\r
- return -1;\r
-\r
- if(!dvfs_clk->pds)\r
- return -1;\r
-\r
- mutex_lock(&mutex);\r
- // set clk unsupport dvfs\r
- dvfs_clk->enable_dvfs = 0;\r
- dvfs_clk->vd = dvfs_clk->pds[0].pd->vd;\r
- for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {\r
- child = &(dvfs_clk->pds[i].clk_list);\r
- child->dvfs_clk = dvfs_clk;\r
- pd = dvfs_clk->pds[i].pd;\r
- list_add(&child->node, &pd->clk_list);\r
- }\r
- clk = dvfs_clk_get(NULL, dvfs_clk->name);\r
- clk_register_dvfs(dvfs_clk, clk);\r
- mutex_unlock(&mutex);\r
- return 0;\r
-}\r
int rk30_dvfs_init(void)\r
{\r
int i = 0;\r
for (i = 0; i < ARRAY_SIZE(rk30_vds); i++) {\r
- rk_regist_vd(&rk30_vds[i]);\r
+ rk_regist_vd(rk30_vds[i]);\r
}\r
for (i = 0; i < ARRAY_SIZE(rk30_pds); i++) {\r
rk_regist_pd(&rk30_pds[i]);\r
for (i = 0; i < ARRAY_SIZE(rk30_clks); i++) {\r
rk_regist_clk(&rk30_clks[i]);\r
}\r
- dump_dbg_map();\r
- //DVFS_DBG("%s dvfs tree create finish!\n", __func__);\r
- //rk_dvfs_check_regulator_volt();\r
+ \r
return 0;\r
}\r
\r
-void dvfs_clk_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target)\r
-{\r
- struct clk_node *dvfs_clk = clk_get_dvfs_info(clk);\r
- dvfs_clk->clk_dvfs_target = clk_dvfs_target;\r
-}\r
-//\r
-\r
-/*\r
- *cpufreq_frequency_table->index for cpufreq is index\r
- *cpufreq_frequency_table->index for dvfstable is volt\r
+#if 1\r
+/**\r
+ * dump_dbg_map() : Draw all informations of dvfs while debug\r
*/\r
-int cpufreq_dvfs_init(struct clk *clk, struct cpufreq_frequency_table **table, clk_dvfs_target_callback clk_dvfs_target)\r
+static void dump_dbg_map(void)\r
{\r
+ int i;\r
+ struct vd_node *vd;\r
+ struct pd_node *pd, *clkparent;\r
+ struct clk_list *child;\r
+ struct clk_node *dvfs_clk;\r
\r
- struct cpufreq_frequency_table *freq_table;\r
- struct clk_node *info = clk_get_dvfs_info(clk);\r
- struct cpufreq_frequency_table *dvfs_table;//dvfs volt freq table\r
- int i = 0;\r
- DVFS_DBG("%s clk name %s\n", __func__, clk->name);\r
- if(!info) {\r
- return -1;\r
- }\r
- dvfs_table = info->dvfs_table;\r
+ DVFS_DBG("-------------DVFS DEBUG-----------\n\n\n");\r
+ DVFS_DBG("RK30 DVFS TREE:\n");\r
+ list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+ DVFS_DBG("|\n|- voltage domain:%s\n", vd->name);\r
+ DVFS_DBG("|- current voltage:%d\n", vd->cur_volt);\r
\r
- if(!dvfs_table) {\r
- return -1;\r
- }\r
+ list_for_each_entry(pd, &vd->pd_list, node) {\r
+ DVFS_DBG("| |\n| |- power domain:%s, status = %s, current volt = %d\n",\r
+ pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt);\r
\r
- /********************************count table num****************************/\r
- i = 0;\r
- while(dvfs_table[i].frequency != FV_TABLE_END) {\r
- //DVFS_DBG("dvfs_table1 %lu\n",dvfs_table[i].frequency);\r
- i++;\r
- }\r
+ list_for_each_entry(child, &pd->clk_list, node) {\r
+ dvfs_clk = child->dvfs_clk;\r
+ DVFS_DBG("| | |\n| | |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n",\r
+ dvfs_clk->name, dvfs_clk->set_freq, dvfs_clk->set_volt, dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE");\r
+ for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {\r
+ clkparent = dvfs_clk->pds[i].pd;\r
+ DVFS_DBG("| | | |- clock parents: %s, vd_parent = %s\n", clkparent->name, clkparent->vd->name);\r
+ }\r
\r
- freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * (i + 1), GFP_KERNEL);\r
- //last freq is end tab\r
- freq_table[i].index = i;\r
- freq_table[i].frequency = CPUFREQ_TABLE_END;\r
-\r
- //set freq table\r
- i = 0;\r
- while(dvfs_table[i].frequency != FV_TABLE_END) {\r
- freq_table[i].index = i;\r
- freq_table[i].frequency = dvfs_table[i].frequency;\r
- //DVFS_DBG("dvfs_table %d %lu\n",i,dvfs_table[i].frequency);\r
- i++;\r
- }\r
- *table = &freq_table[0];\r
- dvfs_clk_set_rate_callback(clk, clk_dvfs_target);\r
- return 0;\r
-}\r
+ for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {\r
+ DVFS_DBG("| | | |- freq = %d, volt = %d\n", dvfs_clk->dvfs_table[i].frequency, dvfs_clk->dvfs_table[i].index);\r
\r
-int clk_dvfs_set_dvfs_table(struct clk *clk, struct cpufreq_frequency_table *table)\r
-{\r
- struct clk_node *info = clk_get_dvfs_info(clk);\r
- if(!table || !info)\r
- return -1;\r
- info->dvfs_table = table;\r
- return 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ DVFS_DBG("-------------DVFS DEBUG END------------\n");\r
}\r
-/********************************simulation cases****************************/\r
-\r
-#ifdef DVFS_TEST_OFF_BOARD\r
-int rk30_dvfs_init_test(void)\r
-{\r
- struct clk *clk1;\r
- DVFS_DBG("********************************simulation cases****************************\n");\r
-#ifdef DEBUG_RK30_DVFS\r
- DVFS_DBG("\n\n");\r
- dump_dbg_map();\r
#endif\r
- clk1 = dvfs_clk_get(NULL, "cpu");\r
- if (clk1) {\r
- dvfs_clk_set_rate(clk1, 1008000000);\r
- dump_dbg_map();\r
- dvfs_clk_set_rate(clk1, 816000000);\r
- dump_dbg_map();\r
- dvfs_clk_set_rate(clk1, 0);\r
- dump_dbg_map();\r
- dvfs_clk_set_rate(clk1, 1200000000);\r
- dump_dbg_map();\r
- dvfs_clk_set_rate(clk1, 1009000000);\r
- dump_dbg_map();\r
- dvfs_clk_set_rate(clk1, 1416000000);\r
- dump_dbg_map();\r
-\r
- } else {\r
- DVFS_DBG("\t\t%s:\t can not find clk cpu\n", __func__);\r
- }\r
-\r
- clk1 = dvfs_clk_get(NULL, "gpu");\r
- if (clk1) {\r
- dvfs_clk_set_rate(clk1, 120000000);\r
- dump_dbg_map();\r
- dvfs_clk_enable(clk1);\r
- dvfs_clk_disable(clk1);\r
- dump_dbg_map();\r
- } else {\r
- DVFS_DBG("\t\t%s:\t can not find clk gpu\n", __func__);\r
- dump_dbg_map();\r
- }\r
\r
- clk1 = dvfs_clk_get(NULL, "arm_pll");\r
- if (clk1) {\r
- dvfs_clk_set_rate(clk1, 24000000);\r
- dump_dbg_map();\r
- } else {\r
- DVFS_DBG("\t\t%s:\t can not find clk arm_pll\n", __func__);\r
- }\r
\r
- DVFS_DBG("********************************simulation cases end***************************\n");\r
-\r
- return 0;\r
-\r
-}\r
-#endif\r
\r