From: 陈亮 Date: Fri, 28 Feb 2014 08:33:02 +0000 (-0800) Subject: rk3188:linux3.10: add dvfs support X-Git-Tag: firefly_0821_release~6245 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=ecc299f99f07e7862a6cc667b58719dd76abba23;p=firefly-linux-kernel-4.4.55.git rk3188:linux3.10: add dvfs support --- diff --git a/arch/arm/mach-rockchip/dvfs.c b/arch/arm/mach-rockchip/dvfs.c index 83b959e13f70..9701ecc78b54 100644 --- a/arch/arm/mach-rockchip/dvfs.c +++ b/arch/arm/mach-rockchip/dvfs.c @@ -12,91 +12,133 @@ * GNU General Public License for more details. * */ -#include -#include -#include -#include -#include #include #include -#include #include #include -#include -#include #include #include -#include -#include #include - #include "dvfs.h" #define MHz (1000 * 1000) static LIST_HEAD(rk_dvfs_tree); -static DEFINE_MUTEX(mutex); static DEFINE_MUTEX(rk_dvfs_mutex); -int dump_dbg_map(char *buf); - -#define PD_ON 1 -#define PD_OFF 0 -#define DVFS_STR_DISABLE(on) ((on)?"enable":"disable") - -#define get_volt_up_delay(new_volt, old_volt) \ - ((new_volt) > (old_volt) ? (((new_volt) - (old_volt)) >> 9) : 0) -/**************************************vd regulator functions***************************************/ -static void dvfs_volt_up_delay(struct vd_node *vd,int new_volt, int old_volt) +static void dvfs_volt_up_delay(struct vd_node *vd, int new_volt, int old_volt) { int u_time; - if(new_volt<=old_volt) + + if(new_volt <= old_volt) return; - if(vd->volt_time_flag>0) - u_time=regulator_set_voltage_time(vd->regulator,old_volt,new_volt); + if(vd->volt_time_flag > 0) + u_time = regulator_set_voltage_time(vd->regulator, old_volt, new_volt); else - u_time=-1; - if(u_time<0)// regulator is not suported time,useing default time - { + u_time = -1; + if(u_time < 0) {// regulator is not suported time,useing default time DVFS_DBG("%s:vd %s is not suported getting delay time,so we use default\n", - __FUNCTION__,vd->name); - u_time=((new_volt) - (old_volt)) >> 9; + __func__, vd->name); + u_time = ((new_volt) - (old_volt)) >> 9; } - DVFS_DBG("%s:vd %s volt %d to %d delay %d us\n",__FUNCTION__,vd->name, - old_volt,new_volt,u_time); + + DVFS_DBG("%s: vd %s volt %d to %d delay %d us\n", + __func__, vd->name, old_volt, new_volt, u_time); + if (u_time >= 1000) { mdelay(u_time / 1000); udelay(u_time % 1000); - DVFS_ERR("regulator set vol delay is larger 1ms,old is %d,new is %d\n",old_volt,new_volt); + DVFS_WARNING("%s: regulator set vol delay is larger 1ms,old is %d,new is %d\n", + __func__, old_volt, new_volt); } else if (u_time) { udelay(u_time); } } -int dvfs_regulator_set_voltage_readback(struct regulator *regulator, int min_uV, int max_uV) +static int dvfs_regulator_set_voltage_readback(struct regulator *regulator, int min_uV, int max_uV) { int ret = 0, read_back = 0; + ret = dvfs_regulator_set_voltage(regulator, max_uV, max_uV); if (ret < 0) { - DVFS_ERR("%s now read back to check voltage\n", __func__); + DVFS_ERR("%s: now read back to check voltage\n", __func__); /* read back to judge if it is already effect */ mdelay(2); read_back = dvfs_regulator_get_voltage(regulator); if (read_back == max_uV) { - DVFS_ERR("%s set ERROR but already effected, volt=%d\n", __func__, read_back); + DVFS_ERR("%s: set ERROR but already effected, volt=%d\n", __func__, read_back); ret = 0; } else { - DVFS_ERR("%s set ERROR AND NOT effected, volt=%d\n", __func__, read_back); + DVFS_ERR("%s: set ERROR AND NOT effected, volt=%d\n", __func__, read_back); } } + return ret; } + +static int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new) +{ + int ret = 0; + + DVFS_DBG("%s: volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt); + + if (IS_ERR_OR_NULL(vd_clk)) { + DVFS_ERR("%s: vd_node error\n", __func__); + return -EINVAL; + } + + if (!IS_ERR_OR_NULL(vd_clk->regulator)) { + ret = dvfs_regulator_set_voltage_readback(vd_clk->regulator, volt_new, volt_new); + dvfs_volt_up_delay(vd_clk,volt_new, vd_clk->cur_volt); + if (ret < 0) { + vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; + DVFS_ERR("%s: %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", + __func__, vd_clk->name, ret, volt_new, vd_clk->cur_volt); + return -EAGAIN; + } + + } else { + DVFS_ERR("%s: invalid regulator\n", __func__); + return -EINVAL; + } + + vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS; + vd_clk->cur_volt = volt_new; + + return 0; + +} + +static int dvfs_reset_volt(struct vd_node *dvfs_vd) +{ + int flag_set_volt_correct = 0; + if (!IS_ERR_OR_NULL(dvfs_vd->regulator)) + flag_set_volt_correct = dvfs_regulator_get_voltage(dvfs_vd->regulator); + else { + DVFS_ERR("%s: invalid regulator\n", __func__); + return -EINVAL; + } + if (flag_set_volt_correct <= 0) { + DVFS_ERR("%s (vd:%s), try to reload volt ,by it is error again(%d)!!! stop scaling\n", + __func__, dvfs_vd->name, flag_set_volt_correct); + return -EAGAIN; + } + dvfs_vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS; + DVFS_WARNING("%s:vd(%s) try to reload volt = %d\n", + __func__, dvfs_vd->name, flag_set_volt_correct); + + /* Reset vd's voltage */ + dvfs_vd->cur_volt = flag_set_volt_correct; + + return dvfs_vd->cur_volt; +} + + // for clk enable case to get vd regulator info -void clk_enable_dvfs_regulator_check(struct vd_node *vd) +static void clk_enable_dvfs_regulator_check(struct vd_node *vd) { vd->cur_volt = dvfs_regulator_get_voltage(vd->regulator); - if(vd->cur_volt<=0) - { + if(vd->cur_volt <= 0){ vd->volt_set_flag = DVFS_SET_VOLT_FAILURE; } vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS; @@ -104,146 +146,143 @@ void clk_enable_dvfs_regulator_check(struct vd_node *vd) static void dvfs_get_vd_regulator_volt_list(struct vd_node *vd) { - unsigned i,selector=dvfs_regulator_count_voltages(vd->regulator); - int sel_volt=0; - - if(selector>VD_VOL_LIST_CNT) - selector=VD_VOL_LIST_CNT; + unsigned int i, selector = dvfs_regulator_count_voltages(vd->regulator); + int n = 0, sel_volt = 0; - mutex_lock(&mutex); - for (i = 0; iregulator,i); - if(sel_volt<=0) - { - DVFS_WARNING("%s : selector=%u,but volt <=0\n",vd->name,i); - break; + if(selector > VD_VOL_LIST_CNT) + selector = VD_VOL_LIST_CNT; + + for (i = 0; i < selector; i++) { + sel_volt = dvfs_regulator_list_voltage(vd->regulator, i); + if(sel_volt <= 0){ + //DVFS_WARNING("%s: vd(%s) list volt selector=%u, but volt(%d) <=0\n", + // __func__, vd->name, i, sel_volt); + continue; } - vd->volt_list[i]=sel_volt; - DVFS_DBG("%s:selector=%u,volt %d\n",vd->name,i,sel_volt); + vd->volt_list[n++] = sel_volt; + DVFS_DBG("%s: vd(%s) list volt selector=%u, n=%d, volt=%d\n", + __func__, vd->name, i, n, sel_volt); } - vd->n_voltages=selector; - mutex_unlock(&mutex); + + vd->n_voltages = n; } // >= volt static int vd_regulator_round_volt_max(struct vd_node *vd, int volt) { int sel_volt; - unsigned i; + int i; - for (i = 0; in_voltages; i++) { - sel_volt=vd->volt_list[i]; - if(sel_volt<=0) - { - DVFS_WARNING("%s:list_volt : selector=%u,but volt <=0\n",__FUNCTION__,i); - return -1; + for (i = 0; i < vd->n_voltages; i++) { + sel_volt = vd->volt_list[i]; + if(sel_volt <= 0){ + DVFS_WARNING("%s: selector=%u, but volt <=0\n", + __func__, i); + continue; } - if(sel_volt>=volt) - return sel_volt; + if(sel_volt >= volt) + return sel_volt; } - return -1; + return -EINVAL; } + // >=volt static int vd_regulator_round_volt_min(struct vd_node *vd, int volt) { int sel_volt; - unsigned i; + int i; - for (i = 0; in_voltages; i++) { - sel_volt=vd->volt_list[i]; - if(sel_volt<=0) - { - DVFS_WARNING("%s:list_volt : selector=%u,but volt <=0\n",__FUNCTION__,i); - return -1; + for (i = 0; i < vd->n_voltages; i++) { + sel_volt = vd->volt_list[i]; + if(sel_volt <= 0){ + DVFS_WARNING("%s: selector=%u, but volt <=0\n", + __func__, i); + continue; } - if(sel_volt>volt) - { - if(i>0) + if(sel_volt > volt){ + if(i > 0) return vd->volt_list[i-1]; else - return -1; + return -EINVAL; } } - return -1; + + return -EINVAL; } // >=volt -int vd_regulator_round_volt(struct vd_node *vd, int volt,int flags) +static int vd_regulator_round_volt(struct vd_node *vd, int volt, int flags) { if(!vd->n_voltages) - return -1; - if(flags==VD_LIST_RELATION_L) - return vd_regulator_round_volt_min(vd,volt); + return -EINVAL; + if(flags == VD_LIST_RELATION_L) + return vd_regulator_round_volt_min(vd, volt); else - return vd_regulator_round_volt_max(vd,volt); + return vd_regulator_round_volt_max(vd, volt); } -EXPORT_SYMBOL(vd_regulator_round_volt); - -static void dvfs_table_round_volt(struct dvfs_node *clk_dvfs_node) +static void dvfs_table_round_volt(struct dvfs_node *clk_dvfs_node) { - int i,test_volt; + int i, test_volt; - if(!clk_dvfs_node->dvfs_table||!clk_dvfs_node->vd||IS_ERR_OR_NULL(clk_dvfs_node->vd->regulator)) + if(!clk_dvfs_node->dvfs_table || !clk_dvfs_node->vd || + IS_ERR_OR_NULL(clk_dvfs_node->vd->regulator)) return; - mutex_lock(&mutex); + for (i = 0; (clk_dvfs_node->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { - test_volt=vd_regulator_round_volt(clk_dvfs_node->vd,clk_dvfs_node->dvfs_table[i].index,VD_LIST_RELATION_H); - if(test_volt<=0) + test_volt = vd_regulator_round_volt(clk_dvfs_node->vd, clk_dvfs_node->dvfs_table[i].index, VD_LIST_RELATION_H); + if(test_volt <= 0) { - DVFS_WARNING("clk %s:round_volt : is %d,but list <=0\n",clk_dvfs_node->name,clk_dvfs_node->dvfs_table[i].index); + DVFS_WARNING("%s: clk(%s) round volt(%d) but list <=0\n", + __func__, clk_dvfs_node->name, clk_dvfs_node->dvfs_table[i].index); break; } - DVFS_DBG("clk %s:round_volt %d to %d\n",clk_dvfs_node->name,clk_dvfs_node->dvfs_table[i].index,test_volt); + DVFS_DBG("clk %s:round_volt %d to %d\n", + clk_dvfs_node->name, clk_dvfs_node->dvfs_table[i].index, test_volt); + clk_dvfs_node->dvfs_table[i].index=test_volt; } - mutex_unlock(&mutex); } -void dvfs_vd_get_regulator_volt_time_info(struct vd_node *vd) + +static void dvfs_vd_get_regulator_volt_time_info(struct vd_node *vd) { - if(vd->volt_time_flag<=0)// check regulator support get uping vol timer - { - vd->volt_time_flag=dvfs_regulator_set_voltage_time(vd->regulator,vd->cur_volt,vd->cur_volt+200*1000); - if(vd->volt_time_flag<0) - { - DVFS_DBG("%s,vd %s volt_time is no support\n",__FUNCTION__,vd->name); + if(vd->volt_time_flag <= 0){// check regulator support get uping vol timer + vd->volt_time_flag = dvfs_regulator_set_voltage_time(vd->regulator, vd->cur_volt, vd->cur_volt+200*1000); + if(vd->volt_time_flag < 0){ + DVFS_DBG("%s,vd %s volt_time is no support\n", + __func__, vd->name); } - else - { - DVFS_DBG("%s,vd %s volt_time is support,up 200mv need delay %d us\n",__FUNCTION__,vd->name,vd->volt_time_flag); - + else{ + DVFS_DBG("%s,vd %s volt_time is support,up 200mv need delay %d us\n", + __func__, vd->name, vd->volt_time_flag); } } } - -void dvfs_vd_get_regulator_mode_info(struct vd_node *vd) +#if 0 +static void dvfs_vd_get_regulator_mode_info(struct vd_node *vd) { //REGULATOR_MODE_FAST - if(vd->mode_flag<=0)// check regulator support get uping vol timer - { - vd->mode_flag=dvfs_regulator_get_mode(vd->regulator); - if(vd->mode_flag==REGULATOR_MODE_FAST||vd->mode_flag==REGULATOR_MODE_NORMAL - ||vd->mode_flag==REGULATOR_MODE_IDLE||vd->mode_flag==REGULATOR_MODE_STANDBY) - { - if(dvfs_regulator_set_mode(vd->regulator,vd->mode_flag)<0) - { - vd->mode_flag=0;// check again - } + if(vd->mode_flag <= 0){// check regulator support get uping vol timer{ + vd->mode_flag = dvfs_regulator_get_mode(vd->regulator); + if(vd->mode_flag==REGULATOR_MODE_FAST || vd->mode_flag==REGULATOR_MODE_NORMAL + || vd->mode_flag == REGULATOR_MODE_IDLE || vd->mode_flag==REGULATOR_MODE_STANDBY){ + if(dvfs_regulator_set_mode(vd->regulator, vd->mode_flag) < 0){ + vd->mode_flag = 0;// check again + } } - if(vd->mode_flag>0) - { - DVFS_DBG("%s,vd %s mode(now is %d) support\n",__FUNCTION__,vd->name,vd->mode_flag); + if(vd->mode_flag > 0){ + DVFS_DBG("%s,vd %s mode(now is %d) support\n", + __func__, vd->name, vd->mode_flag); } - else - { - DVFS_DBG("%s,vd %s mode is not support now check\n",__FUNCTION__,vd->name); - + else{ + DVFS_DBG("%s,vd %s mode is not support now check\n", + __func__, vd->name); } - } } + struct regulator *dvfs_get_regulator1(char *regulator_name) { struct vd_node *vd; @@ -254,10 +293,10 @@ struct regulator *dvfs_get_regulator1(char *regulator_name) } return NULL; } +#endif -int dvfs_get_rate_range(struct clk *clk) +static int dvfs_get_rate_range(struct dvfs_node *clk_dvfs_node) { - struct dvfs_node *clk_dvfs_node = clk_get_dvfs_info(clk); struct cpufreq_frequency_table *table; int i = 0; @@ -280,122 +319,22 @@ int dvfs_get_rate_range(struct clk *clk) return 0; } -/**************************************dvfs clocks functions***************************************/ -int clk_dvfs_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate) -{ - struct dvfs_node *clk_dvfs_node; - u32 rate = 0, ret = 0; - clk_dvfs_node = clk_get_dvfs_info(clk); - - if (IS_ERR_OR_NULL(clk_dvfs_node)) { - DVFS_ERR("%s: can not get dvfs clk(%s)\n", __func__, __clk_get_name(clk)); - return -1; - - } - - if (clk_dvfs_node->vd && clk_dvfs_node->vd->vd_dvfs_target){ - mutex_lock(&rk_dvfs_mutex); - - dvfs_get_rate_range(clk); - clk_dvfs_node->freq_limit_en = 1; - clk_dvfs_node->min_rate = min_rate > clk_dvfs_node->min_rate ? min_rate : clk_dvfs_node->min_rate; - clk_dvfs_node->max_rate = max_rate < clk_dvfs_node->max_rate ? max_rate : clk_dvfs_node->max_rate; - if (clk_dvfs_node->last_set_rate == 0) - rate = clk_get_rate(clk); - else - rate = clk_dvfs_node->last_set_rate; - ret = clk_dvfs_node->vd->vd_dvfs_target(clk->hw, rate, rate); - clk_dvfs_node->last_set_rate = rate; - - mutex_unlock(&rk_dvfs_mutex); - - } - - DVFS_DBG("%s: clk(%s) last_set_rate=%u; [min_rate, max_rate]=[%u, %u]\n", - __func__, __clk_get_name(clk), clk_dvfs_node->last_set_rate, clk_dvfs_node->min_rate, clk_dvfs_node->max_rate); - - return 0; -} - -int clk_dvfs_disable_limit(struct clk *clk) -{ - struct dvfs_node *clk_dvfs_node; - u32 ret = 0; - clk_dvfs_node = clk_get_dvfs_info(clk); - if (IS_ERR_OR_NULL(clk_dvfs_node)) { - DVFS_ERR("%s: can not get dvfs clk(%s)\n", __func__, __clk_get_name(clk)); - return -1; - - } - - if (clk_dvfs_node->vd && clk_dvfs_node->vd->vd_dvfs_target){ - mutex_lock(&rk_dvfs_mutex); - /* To reset clk_dvfs_node->min_rate/max_rate */ - dvfs_get_rate_range(clk); - - clk_dvfs_node->freq_limit_en = 0; - ret = clk_dvfs_node->vd->vd_dvfs_target(clk->hw, clk_dvfs_node->last_set_rate, clk_dvfs_node->last_set_rate); - - mutex_unlock(&rk_dvfs_mutex); - } - - DVFS_DBG("%s: clk(%s) last_set_rate=%u; [min_rate, max_rate]=[%u, %u]\n", - __func__, __clk_get_name(clk), clk_dvfs_node->last_set_rate, clk_dvfs_node->min_rate, clk_dvfs_node->max_rate); - return 0; -} - -int dvfs_vd_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - int ret = -1; - struct dvfs_node *dvfs_info = clk_get_dvfs_info(hw->clk); - - DVFS_DBG("%s(%s(%lu))\n", __func__, dvfs_info->name, rate); - - #if 0 // judge by reference func in rk - if (dvfs_support_clk_set_rate(dvfs_info)==false) { - DVFS_ERR("dvfs func:%s is not support!\n", __func__); - return ret; - } - #endif - - if (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target) { - // mutex_lock(&vd->dvfs_mutex); - mutex_lock(&rk_dvfs_mutex); - ret = dvfs_info->vd->vd_dvfs_target(hw, rate, rate); - dvfs_info->last_set_rate = rate; - mutex_unlock(&rk_dvfs_mutex); - // mutex_unlock(&vd->dvfs_mutex); - } else { - //DVFS_WARNING("%s(%s),vd is no target callback\n", __func__, __clk_get_name(clk)); - return -1; - } - - //DVFS_DBG("%s(%s(%lu)),is end\n", __func__, clk->name, rate); - return ret; -} -EXPORT_SYMBOL(dvfs_vd_clk_set_rate); - static void dvfs_table_round_clk_rate(struct dvfs_node *clk_dvfs_node) { - int i; - unsigned long temp_rate; - int rate; - int flags; + int i, rate, temp_rate, flags; - if(!clk_dvfs_node->dvfs_table||clk_dvfs_node->clk==NULL)//||is_suport_round_rate(clk_dvfs_node->clk)<0) + if(!clk_dvfs_node || !clk_dvfs_node->dvfs_table || !clk_dvfs_node->clk) return; - - mutex_lock(&mutex); + for (i = 0; (clk_dvfs_node->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { //ddr rate = real rate+flags - flags=clk_dvfs_node->dvfs_table[i].frequency%1000; - rate=(clk_dvfs_node->dvfs_table[i].frequency/1000)*1000; - temp_rate=clk_round_rate(clk_dvfs_node->clk,rate*1000); - if(temp_rate<=0) - { - DVFS_WARNING("clk %s:round_clk_rate : is %d,but round <=0",clk_dvfs_node->name,clk_dvfs_node->dvfs_table[i].frequency); - break; + flags = clk_dvfs_node->dvfs_table[i].frequency%1000; + rate = (clk_dvfs_node->dvfs_table[i].frequency/1000)*1000; + temp_rate = clk_round_rate(clk_dvfs_node->clk, rate*1000); + if(temp_rate <= 0){ + DVFS_WARNING("%s: clk(%s) rate %d round return %d\n", + __func__, clk_dvfs_node->name, clk_dvfs_node->dvfs_table[i].frequency, temp_rate); + continue; } /* Set rate unit as MHZ */ @@ -405,14 +344,13 @@ static void dvfs_table_round_clk_rate(struct dvfs_node *clk_dvfs_node) temp_rate = (temp_rate / 1000) + flags; DVFS_DBG("clk %s round_clk_rate %d to %d\n", - clk_dvfs_node->name,clk_dvfs_node->dvfs_table[i].frequency,(int)(temp_rate)); + clk_dvfs_node->name,clk_dvfs_node->dvfs_table[i].frequency, temp_rate); - clk_dvfs_node->dvfs_table[i].frequency=temp_rate; + clk_dvfs_node->dvfs_table[i].frequency = temp_rate; } - mutex_unlock(&mutex); } -int clk_dvfs_node_get_ref_volt(struct dvfs_node *clk_dvfs_node, int rate_khz, +static int clk_dvfs_node_get_ref_volt(struct dvfs_node *clk_dvfs_node, int rate_khz, struct cpufreq_frequency_table *clk_fv) { int i = 0; @@ -441,7 +379,6 @@ int clk_dvfs_node_get_ref_volt(struct dvfs_node *clk_dvfs_node, int rate_khz, static int dvfs_pd_get_newvolt_byclk(struct pd_node *pd, struct dvfs_node *clk_dvfs_node) { - struct clk_list *child; int volt_max = 0; if (!pd || !clk_dvfs_node) @@ -451,15 +388,15 @@ static int dvfs_pd_get_newvolt_byclk(struct pd_node *pd, struct dvfs_node *clk_d return clk_dvfs_node->set_volt; } - list_for_each_entry(child, &pd->clk_list, node) { + list_for_each_entry(clk_dvfs_node, &pd->clk_list, node) { // DVFS_DBG("%s ,pd(%s),dvfs(%s),volt(%u)\n",__func__,pd->name, // clk_dvfs_node->name,clk_dvfs_node->set_volt); - volt_max = max(volt_max, child->clk_dvfs_node->set_volt); + volt_max = max(volt_max, clk_dvfs_node->set_volt); } return volt_max; } -void dvfs_update_clk_pds_volt(struct dvfs_node *clk_dvfs_node) +static void dvfs_update_clk_pds_volt(struct dvfs_node *clk_dvfs_node) { struct pd_node *pd; @@ -478,7 +415,7 @@ void dvfs_update_clk_pds_volt(struct dvfs_node *clk_dvfs_node) }*/ } -int dvfs_vd_get_newvolt_bypd(struct vd_node *vd) +static int dvfs_vd_get_newvolt_bypd(struct vd_node *vd) { int volt_max_vd = 0; struct pd_node *pd; @@ -501,7 +438,7 @@ int dvfs_vd_get_newvolt_bypd(struct vd_node *vd) return volt_max_vd; } -int dvfs_vd_get_newvolt_byclk(struct dvfs_node *clk_dvfs_node) +static int dvfs_vd_get_newvolt_byclk(struct dvfs_node *clk_dvfs_node) { if (!clk_dvfs_node) return -1; @@ -509,118 +446,181 @@ int dvfs_vd_get_newvolt_byclk(struct dvfs_node *clk_dvfs_node) return dvfs_vd_get_newvolt_bypd(clk_dvfs_node->vd); } -void clk_dvfs_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) +int dvfs_clk_enable_limit(struct dvfs_node *clk_dvfs_node, unsigned int min_rate, unsigned max_rate) { - struct dvfs_node *clk_dvfs_node = clk_get_dvfs_info(clk); - if (IS_ERR_OR_NULL(clk_dvfs_node)) { - DVFS_ERR("%s %s get clk_dvfs_node err\n", __func__, clk->name); - return ; + u32 rate = 0, ret = 0; + + if (!clk_dvfs_node) + return -EINVAL; + + if (clk_dvfs_node->vd && clk_dvfs_node->vd->vd_dvfs_target){ + mutex_lock(&clk_dvfs_node->vd->mutex); + + /* To reset clk_dvfs_node->min_rate/max_rate */ + dvfs_get_rate_range(clk_dvfs_node); + clk_dvfs_node->freq_limit_en = 1; + clk_dvfs_node->min_rate = min_rate > clk_dvfs_node->min_rate ? min_rate : clk_dvfs_node->min_rate; + clk_dvfs_node->max_rate = max_rate < clk_dvfs_node->max_rate ? max_rate : clk_dvfs_node->max_rate; + if (clk_dvfs_node->last_set_rate == 0) + rate = clk_get_rate(clk_dvfs_node->clk); + else + rate = clk_dvfs_node->last_set_rate; + ret = clk_dvfs_node->vd->vd_dvfs_target(clk_dvfs_node, rate); + + mutex_unlock(&clk_dvfs_node->vd->mutex); + + } + + DVFS_DBG("%s:clk(%s) last_set_rate=%u; [min_rate, max_rate]=[%u, %u]\n", + __func__, __clk_get_name(clk_dvfs_node->clk), clk_dvfs_node->last_set_rate, + clk_dvfs_node->min_rate, clk_dvfs_node->max_rate); + + return 0; +} +EXPORT_SYMBOL(dvfs_clk_enable_limit); + +int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node) +{ + u32 ret = 0; + + if (!clk_dvfs_node) + return -EINVAL; + + if (clk_dvfs_node->vd && clk_dvfs_node->vd->vd_dvfs_target){ + mutex_lock(&clk_dvfs_node->vd->mutex); + + /* To reset clk_dvfs_node->min_rate/max_rate */ + dvfs_get_rate_range(clk_dvfs_node); + clk_dvfs_node->freq_limit_en = 0; + ret = clk_dvfs_node->vd->vd_dvfs_target(clk_dvfs_node, clk_dvfs_node->last_set_rate); + + mutex_unlock(&clk_dvfs_node->vd->mutex); } + + DVFS_DBG("%s: clk(%s) last_set_rate=%u; [min_rate, max_rate]=[%u, %u]\n", + __func__, __clk_get_name(clk_dvfs_node->clk), clk_dvfs_node->last_set_rate, clk_dvfs_node->min_rate, clk_dvfs_node->max_rate); + return 0; +} +EXPORT_SYMBOL(dvfs_clk_disable_limit); + + +int dvfs_clk_register_set_rate_callback(struct dvfs_node *clk_dvfs_node, clk_set_rate_callback clk_dvfs_target) +{ + if (!clk_dvfs_node) + return -EINVAL; + + mutex_lock(&clk_dvfs_node->vd->mutex); clk_dvfs_node->clk_dvfs_target = clk_dvfs_target; + mutex_unlock(&clk_dvfs_node->vd->mutex); + + return 0; } +EXPORT_SYMBOL(dvfs_clk_register_set_rate_callback); -/************************************************ freq volt table************************************/ -struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct dvfs_node *clk_dvfs_node) { - struct dvfs_node *info = clk_get_dvfs_info(clk); struct cpufreq_frequency_table *table; - if (!info || !info->dvfs_table) { + + if (!clk_dvfs_node) return NULL; - } - mutex_lock(&mutex); - table = info->dvfs_table; - mutex_unlock(&mutex); + + mutex_lock(&clk_dvfs_node->vd->mutex); + table = clk_dvfs_node->dvfs_table; + mutex_unlock(&clk_dvfs_node->vd->mutex); + return table; } EXPORT_SYMBOL(dvfs_get_freq_volt_table); -int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table) +int dvfs_set_freq_volt_table(struct dvfs_node *clk_dvfs_node, struct cpufreq_frequency_table *table) { - struct dvfs_node *info = clk_get_dvfs_info(clk); - - if (!info) - return -1; - if (!table) - { - info->min_rate=0; - info->max_rate=0; - return -1; - } + if (!clk_dvfs_node) + return -EINVAL; - mutex_lock(&mutex); - info->dvfs_table = table; - dvfs_get_rate_range(clk); - mutex_unlock(&mutex); + if (IS_ERR_OR_NULL(table)){ + DVFS_ERR("%s:invalid table!\n", __func__); + return -EINVAL; + } + + mutex_lock(&clk_dvfs_node->vd->mutex); + clk_dvfs_node->dvfs_table = table; + dvfs_get_rate_range(clk_dvfs_node); + dvfs_table_round_clk_rate(clk_dvfs_node); + dvfs_table_round_volt(clk_dvfs_node); + mutex_unlock(&clk_dvfs_node->vd->mutex); - dvfs_table_round_clk_rate(info); - dvfs_table_round_volt(info); return 0; } EXPORT_SYMBOL(dvfs_set_freq_volt_table); -int clk_enable_dvfs(struct clk *clk) +int clk_enable_dvfs(struct dvfs_node *clk_dvfs_node) { - struct dvfs_node *clk_dvfs_node; struct cpufreq_frequency_table clk_fv; - - if (!clk) { - DVFS_ERR("clk enable dvfs error\n"); + + if (!clk_dvfs_node) return -EINVAL; - } - clk_dvfs_node = clk_get_dvfs_info(clk); - if (!clk_dvfs_node || !clk_dvfs_node->vd) { - DVFS_ERR("%s clk(%s) not support dvfs!\n", __func__, __clk_get_name(clk)); + DVFS_DBG("%s: dvfs clk(%s) enable dvfs!\n", + __func__, __clk_get_name(clk_dvfs_node->clk)); + + if (!clk_dvfs_node->vd) { + DVFS_ERR("%s: dvfs node(%s) has no vd node!\n", + __func__, clk_dvfs_node->name); return -EINVAL; } - if (clk_dvfs_node->enable_dvfs == 0) { + mutex_lock(&clk_dvfs_node->vd->mutex); + if (clk_dvfs_node->enable_count == 0) { if (IS_ERR_OR_NULL(clk_dvfs_node->vd->regulator)) { - //regulator = NULL; if (clk_dvfs_node->vd->regulator_name) clk_dvfs_node->vd->regulator = dvfs_regulator_get(NULL, clk_dvfs_node->vd->regulator_name); if (!IS_ERR_OR_NULL(clk_dvfs_node->vd->regulator)) { - // DVFS_DBG("dvfs_regulator_get(%s)\n",clk_dvfs_node->vd->regulator_name); + DVFS_DBG("%s: vd(%s) get regulator(%s) ok\n", + __func__, clk_dvfs_node->vd->name, clk_dvfs_node->vd->regulator_name); clk_enable_dvfs_regulator_check(clk_dvfs_node->vd); dvfs_get_vd_regulator_volt_list(clk_dvfs_node->vd); dvfs_vd_get_regulator_volt_time_info(clk_dvfs_node->vd); - //dvfs_vd_get_regulator_mode_info(clk_dvfs_node->vd); } else { - //clk_dvfs_node->vd->regulator = NULL; - clk_dvfs_node->enable_dvfs = 0; - DVFS_ERR("%s can't get regulator in %s\n", clk_dvfs_node->name, __func__); + clk_dvfs_node->enable_count = 0; + DVFS_ERR("%s: vd(%s) can't get regulator(%s)!\n", + __func__, clk_dvfs_node->vd->name, clk_dvfs_node->vd->regulator_name); + mutex_unlock(&clk_dvfs_node->vd->mutex); return -ENXIO; } } else { - clk_enable_dvfs_regulator_check(clk_dvfs_node->vd); - // DVFS_DBG("%s(%s) vd volt=%u\n",__func__,clk_dvfs_node->name,clk_dvfs_node->vd->cur_volt); + clk_enable_dvfs_regulator_check(clk_dvfs_node->vd); } + + DVFS_DBG("%s: vd(%s) cur volt=%d\n", + __func__, clk_dvfs_node->name, clk_dvfs_node->vd->cur_volt); dvfs_table_round_clk_rate(clk_dvfs_node); - - mutex_lock(&mutex); - dvfs_get_rate_range(clk); - mutex_unlock(&mutex); - + dvfs_get_rate_range(clk_dvfs_node); + clk_dvfs_node->freq_limit_en = 1; dvfs_table_round_volt(clk_dvfs_node); - clk_dvfs_node->set_freq = clk_dvfs_node_get_rate_kz(clk); - DVFS_DBG("%s ,%s get freq %u!\n", __func__, clk_dvfs_node->name, clk_dvfs_node->set_freq); + clk_dvfs_node->set_freq = clk_dvfs_node_get_rate_kz(clk_dvfs_node->clk); + + DVFS_DBG("%s: %s get freq %u!\n", + __func__, clk_dvfs_node->name, clk_dvfs_node->set_freq); if (clk_dvfs_node_get_ref_volt(clk_dvfs_node, clk_dvfs_node->set_freq, &clk_fv)) { if (clk_dvfs_node->dvfs_table[0].frequency == CPUFREQ_TABLE_END) { - DVFS_ERR("%s table empty\n", __func__); - clk_dvfs_node->enable_dvfs = 0; - return -1; + DVFS_ERR("%s: table empty\n", __func__); + clk_dvfs_node->enable_count = 0; + mutex_unlock(&clk_dvfs_node->vd->mutex); + return -EINVAL; } else { - DVFS_WARNING("%s table all value are smaller than default, use default, just enable dvfs\n", __func__); - clk_dvfs_node->enable_dvfs++; + DVFS_WARNING("%s: clk(%s) freq table all value are smaller than default(%d), use default, just enable dvfs\n", + __func__, clk_dvfs_node->name, clk_dvfs_node->set_freq); + clk_dvfs_node->enable_count++; + mutex_unlock(&clk_dvfs_node->vd->mutex); return 0; } } clk_dvfs_node->set_volt = clk_fv.index; dvfs_vd_get_newvolt_byclk(clk_dvfs_node); - DVFS_DBG("%s, %s, freq %u(ref vol %u)\n",__func__, clk_dvfs_node->name, - clk_dvfs_node->set_freq, clk_dvfs_node->set_volt); + DVFS_DBG("%s: %s, freq %u(ref vol %u)\n", + __func__, clk_dvfs_node->name, clk_dvfs_node->set_freq, clk_dvfs_node->set_volt); #if 0 if (clk_dvfs_node->dvfs_nb) { // must unregister when clk disable @@ -644,420 +644,104 @@ int clk_enable_dvfs(struct clk *clk) mutex_unlock(&rk_dvfs_mutex); } #endif - clk_dvfs_node->enable_dvfs++; + clk_dvfs_node->enable_count++; } else { - DVFS_ERR("dvfs already enable clk enable = %d!\n", clk_dvfs_node->enable_dvfs); - clk_dvfs_node->enable_dvfs++; + DVFS_DBG("%s: dvfs already enable clk enable = %d!\n", + __func__, clk_dvfs_node->enable_count); + clk_dvfs_node->enable_count++; } + + mutex_unlock(&clk_dvfs_node->vd->mutex); + return 0; } +EXPORT_SYMBOL(clk_enable_dvfs); -int clk_disable_dvfs(struct clk *clk) +int clk_disable_dvfs(struct dvfs_node *clk_dvfs_node) { - struct dvfs_node *clk_dvfs_node; - clk_dvfs_node = clk_get_dvfs_info(clk); - if (!clk_dvfs_node->enable_dvfs) { - DVFS_DBG("clk is already closed!\n"); - return -1; + if (!clk_dvfs_node) + return -EINVAL; + + DVFS_DBG("%s:dvfs clk(%s) disable dvfs!\n", + __func__, __clk_get_name(clk_dvfs_node->clk)); + + mutex_lock(&clk_dvfs_node->vd->mutex); + if (!clk_dvfs_node->enable_count) { + DVFS_WARNING("%s:clk(%s) is already closed!\n", + __func__, __clk_get_name(clk_dvfs_node->clk)); + return 0; } else { - clk_dvfs_node->enable_dvfs--; - if (0 == clk_dvfs_node->enable_dvfs) { - DVFS_ERR("clk closed!\n"); + clk_dvfs_node->enable_count--; + if (0 == clk_dvfs_node->enable_count) { + DVFS_DBG("%s:dvfs clk(%s) disable dvfs ok!\n", + __func__, __clk_get_name(clk_dvfs_node->clk)); #if 0 clk_notifier_unregister(clk, clk_dvfs_node->dvfs_nb); DVFS_DBG("clk unregister nb!\n"); #endif } } + mutex_unlock(&clk_dvfs_node->vd->mutex); return 0; } -struct dvfs_node *dvfs_get_clk_dvfs_node_byname(char *name) +EXPORT_SYMBOL(clk_disable_dvfs); + +static int dvfs_target(struct dvfs_node *clk_dvfs_node, unsigned long rate) { - struct vd_node *vd; - struct pd_node *pd; - struct clk_list *child; - list_for_each_entry(vd, &rk_dvfs_tree, node) { - list_for_each_entry(pd, &vd->pd_list, node) { - list_for_each_entry(child, &pd->clk_list, node) { - if (0 == strcmp(child->clk_dvfs_node->name, name)) { - return child->clk_dvfs_node; - } - } - } + struct cpufreq_frequency_table clk_fv; + unsigned long old_rate = 0, new_rate = 0, volt_new = 0, clk_volt_store = 0; + struct clk *clk = clk_dvfs_node->clk; + int ret; + + if (!clk) + return -EINVAL; + + if (!clk_dvfs_node->enable_count){ + DVFS_WARNING("%s:dvfs(%s) is disable\n", + __func__, clk_dvfs_node->name); + return 0; } - return NULL; -} -int rk_regist_vd(struct vd_node *vd) -{ - if (!vd) - return -EINVAL; - mutex_lock(&mutex); - //mutex_init(&vd->dvfs_mutex); - list_add(&vd->node, &rk_dvfs_tree); - INIT_LIST_HEAD(&vd->pd_list); - INIT_LIST_HEAD(&vd->req_volt_list); - vd->mode_flag=0; - vd->volt_time_flag=0; - vd->n_voltages=0; - mutex_unlock(&mutex); - return 0; -} - -int rk_regist_pd(struct pd_node *pd) -{ - struct vd_node *vd; - - vd = pd->vd; - if (!vd) - return -EINVAL; - - mutex_lock(&mutex); - - list_add(&pd->node, &vd->pd_list); - INIT_LIST_HEAD(&pd->clk_list); - - mutex_unlock(&mutex); - - return 0; -} - -int rk_regist_clk(struct dvfs_node *clk_dvfs_node) -{ - struct pd_node *pd; - struct clk_list *child; - - pd = clk_dvfs_node->pd; - if (!pd) - return -EINVAL; - - mutex_lock(&mutex); - - child = &clk_dvfs_node->clk_list; - child->clk_dvfs_node = clk_dvfs_node; - list_add(&child->node, &pd->clk_list); - - mutex_unlock(&mutex); - - return 0; -} - -int correct_volt(int *volt_clk, int *volt_dep, int clk_biger_than_dep, int dep_biger_than_clk) -{ - int up_boundary = 0, low_boundary = 0; - - up_boundary = *volt_clk + dep_biger_than_clk; - low_boundary = *volt_clk - clk_biger_than_dep; - - if (*volt_dep < low_boundary || *volt_dep > up_boundary) { - - if (*volt_dep < low_boundary) { - *volt_dep = low_boundary; - - } else if (*volt_dep > up_boundary) { - *volt_clk = *volt_dep - dep_biger_than_clk; - } - } - - return 0; -} - -int dvfs_scale_volt(struct vd_node *vd_clk, struct vd_node *vd_dep, - int volt_old, int volt_new, int volt_dep_old, int volt_dep_new, int clk_biger_than_dep, int dep_biger_than_clk) -{ - struct regulator *regulator, *regulator_dep; - int volt = 0, volt_dep = 0, step = 0, step_dep = 0; - int volt_tmp = 0, volt_dep_tmp = 0; - int volt_pre = 0, volt_dep_pre = 0; - int ret = 0; - - DVFS_DBG("ENTER %s, volt=%d(old=%d), volt_dep=%d(dep_old=%d)\n", __func__, volt_new, volt_old, volt_dep_new, volt_dep_old); - regulator = vd_clk->regulator; - regulator_dep = vd_dep->regulator; - - if (IS_ERR_OR_NULL(regulator) || IS_ERR(regulator_dep)) { - DVFS_ERR("%s clk_dvfs_node->vd->regulator or depend->dep_vd->regulator == NULL\n", __func__); - return -1; - } - - volt = volt_old; - volt_dep = volt_dep_old; - - step = volt_new - volt_old > 0 ? 1 : (-1); - step_dep = volt_dep_new - volt_dep_old > 0 ? 1 : (-1); - - DVFS_DBG("step=%d step_dep=%d %d\n", step, step_dep, step * step_dep); - - DVFS_DBG("Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n", - volt_new, volt_old, volt_dep_new, volt_dep_old); - do { - volt_pre = volt; - volt_dep_pre = volt_dep; - if (step * step_dep < 0) { - // target is between volt_old and volt_dep_old, just - // need one step - DVFS_DBG("step * step_dep < 0\n"); - volt = volt_new; - volt_dep = volt_dep_new; - - } else if (step > 0) { - // up voltage - DVFS_DBG("step > 0\n"); - volt_tmp = volt_dep + clk_biger_than_dep; - volt_dep_tmp = volt + dep_biger_than_clk; - - volt = volt_tmp > volt_new ? volt_new : volt_tmp; - volt_dep = volt_dep_tmp > volt_dep_new ? volt_dep_new : volt_dep_tmp; - - } else if (step < 0) { - // down voltage - DVFS_DBG("step < 0\n"); - - volt_tmp = volt_dep - dep_biger_than_clk; - volt_dep_tmp = volt - clk_biger_than_dep; - - volt = volt_tmp < volt_new ? volt_new : volt_tmp; - volt_dep = volt_dep_tmp < volt_dep_new ? volt_dep_new : volt_dep_tmp; - - } else { - DVFS_ERR("Oops, some bugs here:Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n", - volt_new, volt_old, volt_dep_new, volt_dep_old); - goto fail; - } - - if (vd_clk->cur_volt != volt) { - DVFS_DBG("\t\t%s:%d->%d\n", vd_clk->name, vd_clk->cur_volt, volt); - ret = dvfs_regulator_set_voltage_readback(regulator, volt, volt); - //udelay(get_volt_up_delay(volt, volt_pre)); - dvfs_volt_up_delay(vd_clk,volt, volt_pre); - if (ret < 0) { - DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_clk->name, ret, volt_new, volt_old); - goto fail; - } - vd_clk->cur_volt = volt; - } - if (vd_dep->cur_volt != volt_dep) { - DVFS_DBG("\t\t%s:%d->%d\n", vd_dep->name, vd_dep->cur_volt, volt_dep); - ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep, volt_dep); - //udelay(get_volt_up_delay(volt_dep, volt_dep_pre)); - dvfs_volt_up_delay(vd_dep,volt_dep, volt_dep_pre); - if (ret < 0) { - DVFS_ERR("depend %s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old); - goto fail; - } - vd_dep->cur_volt = volt_dep; - } - - DVFS_DBG("\t\tNOW:Volt=%d, volt_dep=%d\n", volt, volt_dep); - - } while (volt != volt_new || volt_dep != volt_dep_new); - - vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS; - vd_clk->cur_volt = volt_new; - - return 0; -fail: - DVFS_ERR("+++++++++++++++++FAIL AREA\n"); - vd_clk->cur_volt = volt_old; - vd_dep->cur_volt = volt_dep_old; - vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; - ret = dvfs_regulator_set_voltage_readback(regulator, volt_old, volt_old); - if (ret < 0) { - vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; - DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_clk->name, ret, volt_new, volt_old); - } - - ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep_old, volt_dep_old); - if (ret < 0) { - vd_dep->volt_set_flag = DVFS_SET_VOLT_FAILURE; - DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old); - } - - return -1; -} - -int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new) -{ - int ret = 0; - DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt); - - if (IS_ERR_OR_NULL(vd_clk)) { - DVFS_ERR("%s vd_node error\n", __func__); - return -EINVAL; - } - - if (!IS_ERR_OR_NULL(vd_clk->regulator)) { - ret = dvfs_regulator_set_voltage_readback(vd_clk->regulator, volt_new, volt_new); - //udelay(get_volt_up_delay(volt_new, vd_clk->cur_volt)); - dvfs_volt_up_delay(vd_clk,volt_new, vd_clk->cur_volt); + if (clk_dvfs_node->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) { + /* It means the last time set voltage error */ + ret = dvfs_reset_volt(clk_dvfs_node->vd); if (ret < 0) { - vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; - DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_clk->name, ret, volt_new, vd_clk->cur_volt); - return -1; + return -EAGAIN; } - - } else { - DVFS_ERR("%s up volt clk_dvfs_node->vd->regulator == NULL\n", __func__); - return -1; } - vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS; - vd_clk->cur_volt = volt_new; - - return 0; - -} - -int dvfs_scale_volt_bystep(struct vd_node *vd_clk, struct vd_node *vd_dep, int volt_new, int volt_dep_new, - int cur_clk_biger_than_dep, int cur_dep_biger_than_clk, int new_clk_biger_than_dep, int new_dep_biger_than_clk) -{ - - struct regulator *regulator, *regulator_dep; - int volt_new_corrected = 0, volt_dep_new_corrected = 0; - int volt_old = 0, volt_dep_old = 0; - int ret = 0; - - volt_old = vd_clk->cur_volt; - volt_dep_old = vd_dep->cur_volt; - - DVFS_DBG("ENTER %s, volt=%d(old=%d) vd_dep=%d(dep_old=%d)\n", __func__, - volt_new, volt_old, volt_dep_new, volt_dep_old); - DVFS_DBG("ENTER %s, VOLT_DIFF: clk_cur=%d(clk_new=%d) dep_cur=%d(dep_new=%d)\n", __func__, - cur_clk_biger_than_dep, new_clk_biger_than_dep, - cur_dep_biger_than_clk, new_dep_biger_than_clk); - - volt_new_corrected = volt_new; - volt_dep_new_corrected = volt_dep_new; - correct_volt(&volt_new_corrected, &volt_dep_new_corrected, cur_clk_biger_than_dep, cur_dep_biger_than_clk); - ret = dvfs_scale_volt(vd_clk, vd_dep, volt_old, volt_new_corrected, volt_dep_old, volt_dep_new_corrected, - cur_clk_biger_than_dep, cur_dep_biger_than_clk); - if (ret < 0) { - vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE; - DVFS_ERR("set volt error\n"); - return -1; - } - - if (cur_clk_biger_than_dep != new_clk_biger_than_dep || cur_dep_biger_than_clk != new_dep_biger_than_clk) { - regulator = vd_clk->regulator; - regulator_dep = vd_dep->regulator; - - volt_new_corrected = volt_new; - volt_dep_new_corrected = volt_dep_new; - correct_volt(&volt_new_corrected, &volt_dep_new_corrected, new_clk_biger_than_dep, new_dep_biger_than_clk); - - if (vd_clk->cur_volt != volt_new_corrected) { - DVFS_DBG("%s:%d->%d\n", vd_clk->name, vd_clk->cur_volt, volt_new_corrected); - ret = dvfs_regulator_set_voltage_readback(regulator, volt_new_corrected, volt_new_corrected); - //udelay(get_volt_up_delay(volt_new_corrected, vd_clk->cur_volt)); - dvfs_volt_up_delay(vd_clk,volt_new_corrected, vd_clk->cur_volt); - if (ret < 0) { - DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_clk->name, ret, volt_new_corrected, vd_clk->cur_volt); - return -1; - } - vd_clk->cur_volt = volt_new_corrected; - } - if (vd_dep->cur_volt != volt_dep_new_corrected) { - DVFS_DBG("%s:%d->%d\n", vd_clk->name, vd_clk->cur_volt, volt_dep_new_corrected); - ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep_new_corrected, volt_dep_new_corrected); - //udelay(get_volt_up_delay(volt_dep_new_corrected, vd_dep->cur_volt)); - dvfs_volt_up_delay(vd_dep,volt_dep_new_corrected, vd_dep->cur_volt); - if (ret < 0) { - DVFS_ERR("depend %s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", - __func__, vd_dep->name, ret, volt_dep_new_corrected, vd_dep->cur_volt); - return -1; - } - vd_dep->cur_volt = volt_dep_new_corrected; + /* Check limit rate */ + //if (clk_dvfs_node->freq_limit_en) { + if (rate < clk_dvfs_node->min_rate) { + rate = clk_dvfs_node->min_rate; + } else if (rate > clk_dvfs_node->max_rate) { + rate = clk_dvfs_node->max_rate; } - } - - return 0; -} - -int dvfs_reset_volt(struct vd_node *dvfs_vd) -{ - int flag_set_volt_correct = 0; - if (!IS_ERR_OR_NULL(dvfs_vd->regulator)) - flag_set_volt_correct = dvfs_regulator_get_voltage(dvfs_vd->regulator); - else { - DVFS_ERR("dvfs regulator is ERROR\n"); - return -1; - } - if (flag_set_volt_correct <= 0) { - DVFS_ERR("%s (vd:%s), try to reload volt ,by it is error again(%d)!!! stop scaling\n", - __func__, dvfs_vd->name, flag_set_volt_correct); - return -1; - } - dvfs_vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS; - DVFS_WARNING("%s (vd:%s), try to reload volt = %d\n", - __func__, dvfs_vd->name, flag_set_volt_correct); - - /* Reset vd's voltage */ - dvfs_vd->cur_volt = flag_set_volt_correct; - - return dvfs_vd->cur_volt; -} - - -/*********************************************************************************/ -int dvfs_target(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct cpufreq_frequency_table clk_fv; - const struct clk_ops *origin_clk_ops; - struct clk *clk = hw->clk; - struct dvfs_node *clk_dvfs_node; - unsigned long old_rate = 0, volt_new = 0, clk_volt_store = 0; - int ret = 0; - - if (!clk) { - DVFS_ERR("%s is not a clk\n", __func__); - return -EINVAL; - } + //} + new_rate = clk_round_rate(clk, rate); old_rate = clk_get_rate(clk); - if (rate == old_rate) + if (new_rate == old_rate) return 0; - - clk_dvfs_node = clk_get_dvfs_info(clk); - if (IS_ERR_OR_NULL(clk_dvfs_node)) - return PTR_ERR(clk_dvfs_node); - - DVFS_DBG("enter %s: clk(%s) new_rate = %lu Hz, old_rate = %lu Hz\n", - __func__, clk_dvfs_node->name, rate, old_rate); - - if (!clk_dvfs_node->enable_dvfs){ - DVFS_WARNING("dvfs(%s) is disable\n", clk_dvfs_node->name); - return 0; - } - origin_clk_ops = clk_dvfs_node->origin_clk_ops; - - if (clk_dvfs_node->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) { - /* It means the last time set voltage error */ - ret = dvfs_reset_volt(clk_dvfs_node->vd); - if (ret < 0) { - return -EAGAIN; - } - } + DVFS_DBG("enter %s: clk(%s) new_rate = %lu Hz, old_rate = %lu Hz\n", + __func__, clk_dvfs_node->name, rate, old_rate); /* find the clk corresponding voltage */ - ret = clk_dvfs_node_get_ref_volt(clk_dvfs_node, rate / 1000, &clk_fv); - if (ret) + ret = clk_dvfs_node_get_ref_volt(clk_dvfs_node, new_rate / 1000, &clk_fv); + if (ret) { + DVFS_ERR("%s:dvfs clk(%s) rate %luhz is larger,not support\n", + __func__, clk_dvfs_node->name, new_rate); return ret; + } clk_volt_store = clk_dvfs_node->set_volt; clk_dvfs_node->set_volt = clk_fv.index; volt_new = dvfs_vd_get_newvolt_byclk(clk_dvfs_node); - DVFS_DBG("%s %s new rate=%lu(was=%lu),new volt=%lu,(was=%d)\n", - __func__, clk_dvfs_node->name, rate, old_rate, volt_new,clk_dvfs_node->vd->cur_volt); + DVFS_DBG("%s:%s new rate=%lu(was=%lu),new volt=%lu,(was=%d)\n", + __func__, clk_dvfs_node->name, new_rate, old_rate, volt_new,clk_dvfs_node->vd->cur_volt); /* if up the rate */ - if (rate > old_rate) { + if (new_rate > old_rate) { ret = dvfs_scale_volt_direct(clk_dvfs_node->vd, volt_new); if (ret) goto fail_roll_back; @@ -1065,26 +749,30 @@ int dvfs_target(struct clk_hw *hw, unsigned long rate, /* scale rate */ if (clk_dvfs_node->clk_dvfs_target) { - ret = clk_dvfs_node->clk_dvfs_target(hw, rate, origin_clk_ops->set_rate); + ret = clk_dvfs_node->clk_dvfs_target(clk, new_rate); } else { - ret = origin_clk_ops->set_rate(hw, rate, clk->parent->rate); + ret = clk_set_rate(clk, new_rate); } if (ret) { - DVFS_ERR("%s set rate err\n", __func__); + DVFS_ERR("%s:clk(%s) set rate err\n", + __func__, __clk_get_name(clk)); goto fail_roll_back; } - clk_dvfs_node->set_freq = rate / 1000; + clk_dvfs_node->set_freq = new_rate / 1000; - DVFS_DBG("dvfs %s set rate %lu ok\n", clk_dvfs_node->name, clk_get_rate(clk)); + DVFS_DBG("%s:dvfs clk(%s) set rate %lu ok\n", + __func__, clk_dvfs_node->name, clk_get_rate(clk)); /* if down the rate */ - if (rate < old_rate) { + if (new_rate < old_rate) { ret = dvfs_scale_volt_direct(clk_dvfs_node->vd, volt_new); if (ret) goto out; } - + + clk_dvfs_node->last_set_rate = new_rate; + return 0; fail_roll_back: clk_dvfs_node->set_volt = clk_volt_store; @@ -1092,71 +780,159 @@ out: return ret; } +unsigned long dvfs_clk_get_rate(struct dvfs_node *clk_dvfs_node) +{ + return clk_get_rate(clk_dvfs_node->clk); +} +EXPORT_SYMBOL_GPL(dvfs_clk_get_rate); -static long _clk_dvfs_node_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) +int dvfs_clk_enable(struct dvfs_node *clk_dvfs_node) { - struct clk *clk = hw->clk; - struct dvfs_node *dvfs_node = clk_get_dvfs_info(clk); + return clk_enable(clk_dvfs_node->clk); +} +EXPORT_SYMBOL_GPL(dvfs_clk_enable); - if (rate < dvfs_node->min_rate) { - rate = dvfs_node->min_rate; - } else if (rate > dvfs_node->max_rate) { - rate = dvfs_node->max_rate; - } +void dvfs_clk_disable(struct dvfs_node *clk_dvfs_node) +{ + return clk_disable(clk_dvfs_node->clk); +} +EXPORT_SYMBOL_GPL(dvfs_clk_disable); - return dvfs_node->origin_clk_ops->round_rate(hw, rate, prate); +struct dvfs_node *clk_get_dvfs_node(char *clk_name) +{ + struct vd_node *vd; + struct pd_node *pd; + struct dvfs_node *clk_dvfs_node; + + mutex_lock(&rk_dvfs_mutex); + list_for_each_entry(vd, &rk_dvfs_tree, node) { + mutex_lock(&vd->mutex); + list_for_each_entry(pd, &vd->pd_list, node) { + list_for_each_entry(clk_dvfs_node, &pd->clk_list, node) { + if (0 == strcmp(clk_dvfs_node->name, clk_name)) { + mutex_unlock(&vd->mutex); + mutex_unlock(&rk_dvfs_mutex); + return clk_dvfs_node; + } + } + } + mutex_unlock(&vd->mutex); + } + mutex_unlock(&rk_dvfs_mutex); + + return NULL; } +EXPORT_SYMBOL_GPL(clk_get_dvfs_node); -static int _clk_dvfs_node_enable(struct clk_hw *hw) +void clk_put_dvfs_node(struct dvfs_node *clk_dvfs_node) { - struct clk *clk = hw->clk; - struct dvfs_node *dvfs_node = clk_get_dvfs_info(clk); + return; +} +EXPORT_SYMBOL_GPL(clk_put_dvfs_node); - return dvfs_node->origin_clk_ops->enable(hw); +int dvfs_clk_prepare_enable(struct dvfs_node *clk_dvfs_node) +{ + return clk_prepare_enable(clk_dvfs_node->clk); } +EXPORT_SYMBOL_GPL(dvfs_clk_prepare_enable); -static void _clk_dvfs_node_disable(struct clk_hw *hw) +void dvfs_clk_disable_unprepare(struct dvfs_node *clk_dvfs_node) { - struct clk *clk = hw->clk; - struct dvfs_node *dvfs_node = clk_get_dvfs_info(clk); + clk_disable_unprepare(clk_dvfs_node->clk); +} +EXPORT_SYMBOL_GPL(dvfs_clk_disable_unprepare); - dvfs_node->origin_clk_ops->disable(hw); +int dvfs_clk_set_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate) +{ + int ret = -EINVAL; + + if (!clk_dvfs_node) + return -EINVAL; + + DVFS_DBG("%s:dvfs node(%s) set rate(%lu)\n", + __func__, clk_dvfs_node->name, rate); + + #if 0 // judge by reference func in rk + if (dvfs_support_clk_set_rate(dvfs_info)==false) { + DVFS_ERR("dvfs func:%s is not support!\n", __func__); + return ret; + } + #endif + + if (clk_dvfs_node->vd && clk_dvfs_node->vd->vd_dvfs_target) { + mutex_lock(&clk_dvfs_node->vd->mutex); + ret = clk_dvfs_node->vd->vd_dvfs_target(clk_dvfs_node, rate); + mutex_unlock(&clk_dvfs_node->vd->mutex); + } else { + DVFS_ERR("%s:dvfs node(%s) has no vd node or target callback!\n", + __func__, clk_dvfs_node->name); + } + + return ret; } +EXPORT_SYMBOL_GPL(dvfs_clk_set_rate); +int rk_regist_vd(struct vd_node *vd) +{ + if (!vd) + return -EINVAL; -static int _clk_register_dvfs(struct clk *clk, struct dvfs_node *dvfs_node) + vd->mode_flag=0; + vd->volt_time_flag=0; + vd->n_voltages=0; + INIT_LIST_HEAD(&vd->pd_list); + mutex_lock(&rk_dvfs_mutex); + list_add(&vd->node, &rk_dvfs_tree); + mutex_unlock(&rk_dvfs_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(rk_regist_vd); + +int rk_regist_pd(struct pd_node *pd) { - struct clk_ops *ops; + struct vd_node *vd; + + if (!pd) + return -EINVAL; - if (IS_ERR(clk) || IS_ERR(dvfs_node)) + vd = pd->vd; + if (!vd) return -EINVAL; - //mutex_lock(&mutex); + INIT_LIST_HEAD(&pd->clk_list); + mutex_lock(&vd->mutex); + list_add(&pd->node, &vd->pd_list); + mutex_unlock(&vd->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(rk_regist_pd); - dvfs_node->clk = clk; - dvfs_node->origin_clk_ops = clk->ops; +int rk_regist_clk(struct dvfs_node *clk_dvfs_node) +{ + struct vd_node *vd; + struct pd_node *pd; - ops = kzalloc(sizeof(struct clk_ops), GFP_KERNEL); - if (!ops) - return -ENOMEM; - *ops = *(clk->ops); - ops->set_rate = dvfs_vd_clk_set_rate; - ops->round_rate = _clk_dvfs_node_round_rate; - ops->enable = _clk_dvfs_node_enable; - ops->disable = _clk_dvfs_node_disable; - - clk->ops = ops; - clk->private_data = dvfs_node; + if (!clk_dvfs_node) + return -EINVAL; + + vd = clk_dvfs_node->vd; + pd = clk_dvfs_node->pd; + if (!vd || !pd) + return -EINVAL; - //mutex_unlock(&mutex); + mutex_lock(&vd->mutex); + list_add(&clk_dvfs_node->node, &pd->clk_list); + mutex_unlock(&vd->mutex); return 0; } +EXPORT_SYMBOL_GPL(rk_regist_clk); -static int _rk_convert_cpufreq_table(struct dvfs_node *dvfs_node) +static int rk_convert_cpufreq_table(struct dvfs_node *dvfs_node) { struct opp *opp; struct device *dev; @@ -1175,8 +951,6 @@ static int _rk_convert_cpufreq_table(struct dvfs_node *dvfs_node) return 0; } - - int of_dvfs_init(void) { struct vd_node *vd; @@ -1186,7 +960,7 @@ int of_dvfs_init(void) struct clk *clk; int ret; - printk("%s\n", __func__); + DVFS_DBG("%s\n", __func__); dvfs_dev_node = of_find_node_by_name(NULL, "dvfs"); if (IS_ERR_OR_NULL(dvfs_dev_node)) { @@ -1199,10 +973,11 @@ int of_dvfs_init(void) if (!vd) return -ENOMEM; + mutex_init(&vd->mutex); vd->name = vd_dev_node->name; ret = of_property_read_string(vd_dev_node, "regulator_name", &vd->regulator_name); if (ret) { - DVFS_ERR("%s vd(%s) get regulator_name err, ret:%d\n", + DVFS_ERR("%s:vd(%s) get regulator_name err, ret:%d\n", __func__, vd_dev_node->name, ret); kfree(vd); continue; @@ -1221,12 +996,12 @@ int of_dvfs_init(void) vd->vd_dvfs_target = dvfs_target; ret = rk_regist_vd(vd); if (ret){ - DVFS_ERR("%s vd(%s) register err:%d\n", __func__, vd->name, ret); + DVFS_ERR("%s:vd(%s) register err:%d\n", __func__, vd->name, ret); kfree(vd); continue; } - DVFS_DBG("%s vd(%s) register ok, regulator name:%s,suspend volt:%d\n", + DVFS_DBG("%s:vd(%s) register ok, regulator name:%s,suspend volt:%d\n", __func__, vd->name, vd->regulator_name, vd->suspend_volt); for_each_available_child_of_node(vd_dev_node, pd_dev_node) { @@ -1239,11 +1014,11 @@ int of_dvfs_init(void) ret = rk_regist_pd(pd); if (ret){ - DVFS_ERR("%s pd(%s) register err:%d\n", __func__, pd->name, ret); + DVFS_ERR("%s:pd(%s) register err:%d\n", __func__, pd->name, ret); kfree(pd); continue; } - DVFS_DBG("%s pd(%s) register ok, parent vd:%s\n", + DVFS_DBG("%s:pd(%s) register ok, parent vd:%s\n", __func__, pd->name, vd->name); for_each_available_child_of_node(pd_dev_node, clk_dev_node) { dvfs_node = kzalloc(sizeof(struct dvfs_node), GFP_KERNEL); @@ -1256,18 +1031,18 @@ int of_dvfs_init(void) dvfs_node->dev.of_node = clk_dev_node; ret = of_init_opp_table(&dvfs_node->dev); if (ret) { - DVFS_ERR("%s clk(%s) get opp table err:%d\n", __func__, dvfs_node->name, ret); + DVFS_ERR("%s:clk(%s) get opp table err:%d\n", __func__, dvfs_node->name, ret); kfree(dvfs_node); continue; } ret = opp_init_cpufreq_table(&dvfs_node->dev, &dvfs_node->dvfs_table); if (ret) { - DVFS_ERR("%s clk(%s) get cpufreq table err:%d\n", __func__, dvfs_node->name, ret); + DVFS_ERR("%s:clk(%s) get cpufreq table err:%d\n", __func__, dvfs_node->name, ret); kfree(dvfs_node); continue; } - ret = _rk_convert_cpufreq_table(dvfs_node); + ret = rk_convert_cpufreq_table(dvfs_node); if (ret) { kfree(dvfs_node); continue; @@ -1275,22 +1050,20 @@ int of_dvfs_init(void) clk = clk_get(NULL, clk_dev_node->name); if (IS_ERR(clk)){ - DVFS_ERR("%s get clk(%s) err:%ld\n", __func__, dvfs_node->name, PTR_ERR(clk)); + DVFS_ERR("%s:get clk(%s) err:%ld\n", __func__, dvfs_node->name, PTR_ERR(clk)); kfree(dvfs_node); continue; } - - _clk_register_dvfs(clk, dvfs_node); - clk_put(clk); + dvfs_node->clk = clk; ret = rk_regist_clk(dvfs_node); if (ret){ - DVFS_ERR("%s dvfs_node(%s) register err:%d\n", __func__, dvfs_node->name, ret); + DVFS_ERR("%s:dvfs_node(%s) register err:%d\n", __func__, dvfs_node->name, ret); return ret; } - DVFS_DBG("%s dvfs_node(%s) register ok, parent pd:%s\n", + DVFS_DBG("%s:dvfs_node(%s) register ok, parent pd:%s\n", __func__, clk_dev_node->name, pd->name); } @@ -1304,46 +1077,36 @@ int of_dvfs_init(void) /** * dump_dbg_map() : Draw all informations of dvfs while debug */ -int dump_dbg_map(char *buf) +static int dump_dbg_map(char *buf) { int i; struct vd_node *vd; - struct pd_node *pd; //*clkparent; - struct clk_list *child; + struct pd_node *pd; struct dvfs_node *clk_dvfs_node; - //struct depend_list *depend; char *s = buf; + mutex_lock(&rk_dvfs_mutex); - printk( "-------------DVFS TREE-----------\n\n\n"); printk( "DVFS TREE:\n"); + list_for_each_entry(vd, &rk_dvfs_tree, node) { + mutex_lock(&vd->mutex); printk( "|\n|- voltage domain:%s\n", vd->name); printk( "|- current voltage:%d\n", vd->cur_volt); - //list_for_each_entry(depend, &vd->req_volt_list, node2vd) { - // printk( "|- request voltage:%d, clk:%s\n", depend->req_volt, depend->clk_dvfs_node->name); - //} list_for_each_entry(pd, &vd->pd_list, node) { printk( "| |\n| |- power domain:%s, status = %s, current volt = %d\n", - pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt); + pd->name, (pd->pd_status == 1) ? "ON" : "OFF", pd->cur_volt); - list_for_each_entry(child, &pd->clk_list, node) { - clk_dvfs_node = child->clk_dvfs_node; + list_for_each_entry(clk_dvfs_node, &pd->clk_list, node) { printk( "| | |\n| | |- clock: %s current: rate %d, volt = %d," " enable_dvfs = %s\n", clk_dvfs_node->name, clk_dvfs_node->set_freq, clk_dvfs_node->set_volt, - clk_dvfs_node->enable_dvfs == 0 ? "DISABLE" : "ENABLE"); + clk_dvfs_node->enable_count == 0 ? "DISABLE" : "ENABLE"); printk( "| | |- clk limit:[%u, %u]; last set rate = %u\n", clk_dvfs_node->min_rate, clk_dvfs_node->max_rate, clk_dvfs_node->last_set_rate); - /*for (i = 0; clk_dvfs_node->pds[i].pd != NULL; i++) { - clkparent = clk_dvfs_node->pds[i].pd; - printk( "| | | |- clock parents: %s, vd_parent = %s\n", - clkparent->name, clkparent->vd->name); - }*/ - for (i = 0; (clk_dvfs_node->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) { printk( "| | | |- freq = %d, volt = %d\n", clk_dvfs_node->dvfs_table[i].frequency, @@ -1352,10 +1115,12 @@ int dump_dbg_map(char *buf) } } } + mutex_unlock(&vd->mutex); } - printk( "-------------DVFS TREE END------------\n"); + printk( "-------------DVFS TREE END------------\n"); mutex_unlock(&rk_dvfs_mutex); + return s - buf; } /*******************************AVS AREA****************************************/ @@ -1383,18 +1148,6 @@ struct init_avs_st { static struct init_avs_st init_avs_paramet[init_avs_st_num]; -void avs_board_init(struct avs_ctr_st *data) -{ - - avs_ctr_data=data; -} -void avs_init(void) -{ - memset(&init_avs_paramet[0].is_set, 0, sizeof(init_avs_paramet)); - if(avs_ctr_data&&avs_ctr_data->avs_init) - avs_ctr_data->avs_init(); - avs_init_val_get(0, 1200000,"board_init"); -} static u8 rk_get_avs_val(void) { @@ -1405,7 +1158,7 @@ static u8 rk_get_avs_val(void) return 0; } -/******************************int val get**************************************/ + void avs_init_val_get(int index, int vol, char *s) { int i; @@ -1422,6 +1175,20 @@ void avs_init_val_get(int index, int vol, char *s) } printk("\n"); } + +void avs_board_init(struct avs_ctr_st *data) +{ + + avs_ctr_data=data; +} +void avs_init(void) +{ + memset(&init_avs_paramet[0].is_set, 0, sizeof(init_avs_paramet)); + if(avs_ctr_data&&avs_ctr_data->avs_init) + avs_ctr_data->avs_init(); + avs_init_val_get(0, 1200000,"board_init"); +} + int avs_set_scal_val(u8 avs_base) { return 0; diff --git a/arch/arm/mach-rockchip/dvfs.h b/arch/arm/mach-rockchip/dvfs.h index 0af28cc82c1b..9155786f572d 100644 --- a/arch/arm/mach-rockchip/dvfs.h +++ b/arch/arm/mach-rockchip/dvfs.h @@ -16,13 +16,11 @@ #define _RK30_DVFS_H_ #include -#include +#include -typedef int (*dvfs_set_rate_callback)(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -typedef int (*clk_dvfs_target_callback)(struct clk_hw *hw, unsigned long rate, - dvfs_set_rate_callback set_rate); -typedef int (*clk_dvfs_node_disable_callback)(struct clk *clk,int on); +struct dvfs_node; +typedef int (*dvfs_set_rate_callback)(struct dvfs_node *clk_dvfs_node, unsigned long rate); +typedef int (*clk_set_rate_callback)(struct clk *clk, unsigned long rate); /** * struct vd_node: To Store All Voltage Domains' info @@ -51,11 +49,9 @@ struct vd_node { struct regulator *regulator; struct list_head node; struct list_head pd_list; - struct list_head req_volt_list; - //struct mutex dvfs_mutex; - clk_dvfs_node_disable_callback vd_clk_disable_target; - dvfs_set_rate_callback vd_dvfs_target; - unsigned n_voltages; + struct mutex mutex; + dvfs_set_rate_callback vd_dvfs_target; + unsigned int n_voltages; int volt_list[VD_VOL_LIST_CNT]; }; @@ -78,10 +74,6 @@ struct pd_node { struct list_head clk_list; }; -struct clk_list{ - struct dvfs_node *clk_dvfs_node; - struct list_head node; -}; /** * struct dvfs_node: To Store All dvfs clocks' info * @name: Dvfs clock's Name @@ -100,7 +92,7 @@ struct dvfs_node { const char *name; int set_freq; //KHZ int set_volt; //MV - int enable_dvfs; + int enable_count; int freq_limit_en; //sign if use limit frequency unsigned int min_rate; //limit min frequency unsigned int max_rate; //limit max frequency @@ -108,21 +100,22 @@ struct dvfs_node { struct clk *clk; struct pd_node *pd; struct vd_node *vd; - struct clk_list clk_list; + struct list_head node; struct notifier_block *dvfs_nb; struct cpufreq_frequency_table *dvfs_table; - struct clk_disable_ctr *disable_ctr; - const struct clk_ops *origin_clk_ops; - clk_dvfs_target_callback clk_dvfs_target; + struct cpufreq_frequency_table *condition_freq_table; + clk_set_rate_callback clk_dvfs_target; }; + + #define DVFS_MHZ (1000*1000) #define DVFS_KHZ (1000) #define DVFS_V (1000*1000) #define DVFS_MV (1000) #if 0 -#define DVFS_DBG(fmt, args...) printk(KERN_DEBUG "DVFS DBG:\t"fmt, ##args) +#define DVFS_DBG(fmt, args...) printk(KERN_INFO "DVFS DBG:\t"fmt, ##args) #else #define DVFS_DBG(fmt, args...) {while(0);} #endif @@ -131,12 +124,9 @@ struct dvfs_node { #define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args) #define DVFS_WARNING(fmt, args...) printk(KERN_WARNING "DVFS WARNING:\t"fmt, ##args) - - #define DVFS_SET_VOLT_FAILURE 1 #define DVFS_SET_VOLT_SUCCESS 0 - #define dvfs_regulator_get(dev,id) regulator_get((dev),(id)) #define dvfs_regulator_put(regu) regulator_put((regu)) #define dvfs_regulator_set_voltage(regu,min_uV,max_uV) regulator_set_voltage((regu),(min_uV),(max_uV)) @@ -151,9 +141,6 @@ struct dvfs_node { #define clk_dvfs_node_get_rate_kz(a) (clk_get_rate((a))/1000) #define clk_dvfs_node_set_rate(a,b) clk_set_rate((a),(b)) - - - typedef void (*avs_init_fn)(void); typedef u8 (*avs_get_val_fn)(void); struct avs_ctr_st { @@ -162,70 +149,47 @@ struct avs_ctr_st { }; #ifdef CONFIG_DVFS -int of_dvfs_init(void); -int clk_dvfs_node_get_ref_volt(struct dvfs_node *clk_dvfs_node, int rate_khz, - struct cpufreq_frequency_table *clk_fv); -int dvfs_reset_volt(struct vd_node *dvfs_vd); -int dvfs_vd_get_newvolt_byclk(struct dvfs_node *clk_dvfs_node); -int dvfs_vd_get_newvolt_bypd(struct vd_node *vd); -int dvfs_scale_volt_bystep(struct vd_node *vd_clk, struct vd_node *vd_dep, int volt_new, int volt_dep_new, - int cur_clk_biger_than_dep, int cur_dep_biger_than_clk, int new_clk_biger_than_dep, int new_dep_biger_than_clk); +struct dvfs_node *clk_get_dvfs_node(char *clk_name); +void clk_put_dvfs_node(struct dvfs_node *clk_dvfs_node); +unsigned long dvfs_clk_get_rate(struct dvfs_node *clk_dvfs_node); +int dvfs_clk_set_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate); +int dvfs_clk_enable(struct dvfs_node *clk_dvfs_node); +void dvfs_clk_disable(struct dvfs_node *clk_dvfs_node); +int dvfs_clk_prepare_enable(struct dvfs_node *clk_dvfs_node); +void dvfs_clk_disable_unprepare(struct dvfs_node *clk_dvfs_node); +int dvfs_set_freq_volt_table(struct dvfs_node *clk_dvfs_node, struct cpufreq_frequency_table *table); +int dvfs_clk_register_set_rate_callback(struct dvfs_node *clk_dvfs_node, clk_set_rate_callback clk_dvfs_target); +int dvfs_clk_enable_limit(struct dvfs_node *clk_dvfs_node, unsigned int min_rate, unsigned max_rate); +int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node); +int clk_disable_dvfs(struct dvfs_node *clk_dvfs_node); +int clk_enable_dvfs(struct dvfs_node *clk_dvfs_node); +struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct dvfs_node *clk_dvfs_node); int rk_regist_vd(struct vd_node *vd); int rk_regist_pd(struct pd_node *pd); int rk_regist_clk(struct dvfs_node *clk_dvfs_node); -struct dvfs_node *dvfs_get_clk_dvfs_node_byname(char *name); -int vd_regulator_round_volt(struct vd_node *vd, int volt,int flags); -/*********************************if not define dvfs ,the following function is need defined func{}******************************/ -int dvfs_vd_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -int clk_enable_dvfs(struct clk *clk); -int clk_disable_dvfs(struct clk *clk); -void clk_dvfs_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); -struct regulator* dvfs_get_regulator(char *regulator_name); -int clk_dvfs_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate); -int clk_dvfs_disable_limit(struct clk *clk); -int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new); -/******************************** inline *******************************/ -static inline struct dvfs_node *clk_get_dvfs_info(struct clk *clk) -{ - return clk->private_data; -} -static inline bool dvfs_support_clk_set_rate(struct dvfs_node *dvfs_info) -{ - return (dvfs_info&&dvfs_info->enable_dvfs); -} -static inline bool dvfs_support_clk_disable(struct dvfs_node *dvfs_info) -{ - return (dvfs_info&&dvfs_info->disable_ctr&&dvfs_info->enable_dvfs); -} -/********************************avs*******************************/ -void avs_init(void); -void avs_init_val_get(int index,int vol,char *s); -int avs_set_scal_val(u8 avs_base); -void avs_board_init(struct avs_ctr_st *data); +int of_dvfs_init(void); #else + +static inline struct dvfs_node *clk_get_dvfs_node(char *clk_name){ return NULL; }; +static inline void clk_put_dvfs_node(struct dvfs_node *clk_dvfs_node){ return; }; +static inline unsigned long dvfs_clk_get_rate(struct dvfs_node *clk_dvfs_node){ return 0; }; +static inline int dvfs_clk_set_rate(struct dvfs_node *clk_dvfs_node, unsigned long rate){ return 0; }; +static inline int dvfs_clk_enable(struct dvfs_node *clk_dvfs_node){ return 0; }; +static inline void dvfs_clk_disable(struct dvfs_node *clk_dvfs_node){ }; +static inline int dvfs_clk_prepare_enable(struct dvfs_node *clk_dvfs_node){ return 0; }; +static inline void dvfs_clk_disable_unprepare(struct dvfs_node *clk_dvfs_node){ }; +static inline int dvfs_set_freq_volt_table(struct dvfs_node *clk_dvfs_node, struct cpufreq_frequency_table *table){ return 0; }; +static inline int dvfs_clk_register_set_rate_callback(struct dvfs_node *clk_dvfs_node, clk_set_rate_callback clk_dvfs_target){ return 0; }; +static inline int dvfs_clk_enable_limit(struct dvfs_node *clk_dvfs_node, unsigned int min_rate, unsigned max_rate){ return 0; }; +static inline int dvfs_clk_disable_limit(struct dvfs_node *clk_dvfs_node){ return 0; }; +static inline int clk_disable_dvfs(struct dvfs_node *clk_dvfs_node){ return 0; }; +static inline int clk_enable_dvfs(struct dvfs_node *clk_dvfs_node){ return 0; }; +static inline struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct dvfs_node *clk_dvfs_node){ return NULL; }; +static inline int rk_regist_vd(struct vd_node *vd){ return 0; }; +static inline int rk_regist_pd(struct pd_node *pd){ return 0; }; +static inline int rk_regist_clk(struct dvfs_node *clk_dvfs_node){ return 0; }; static inline int of_dvfs_init(void){ return 0; }; -static inline bool dvfs_support_clk_set_rate(struct dvfs_node *dvfs_info) { return 0; } -static inline bool dvfs_support_clk_disable(struct dvfs_node *dvfs_info) { return 0; } -static inline int dvfs_vd_clk_set_rate(struct clk *clk, unsigned long rate) { return 0; } -static inline int dvfs_vd_clk_disable(struct clk *clk, int on) { return 0; } -static inline int clk_enable_dvfs(struct clk *clk) { return 0; } -static inline int clk_disable_dvfs(struct clk *clk) { return 0; } -static inline void clk_dvfs_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) {} -static inline struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) { return NULL; } -static inline int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table) { return 0; } -static inline struct regulator* dvfs_get_regulator(char *regulator_name){ return NULL; } -static inline int clk_dvfs_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate){ return 0; } -static inline int clk_dvfs_disable_limit(struct clk *clk){ return 0; }; -static inline int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new){ return 0; }; - -static inline void avs_init(void){}; -static inline void avs_init_val_get(int index, int vol, char *s){}; -static inline int avs_set_scal_val(u8 avs_base){ return 0; }; -static inline void avs_board_init(struct avs_ctr_st *data){ return 0; }; #endif #endif