/*
 * 设置profile
 * success: return BSP_OK
 * fail:    return BSP_ERROR
 */
int pwrctrl_dfs_set_profile(int profile)
{
	struct cpufreq_msg set_msg = {0,0,0,0};
	if ((profile < BALONG_FREQ_MIN) || (profile > BALONG_FREQ_MAX))
	{
		cpufreq_err("profile in right bound??%d\n", profile);
		return BSP_ERROR;
	}
	set_msg.msg_type = CPUFREQ_ADJUST_FREQ;
	set_msg.source = CPUFREQ_ACORE;
	if (pwrctrl_dfs_get_profile() < profile)
	{
		set_msg.content = DFS_PROFILE_UP_TARGET;
	}
	else if (pwrctrl_dfs_get_profile() > profile)
	{
		set_msg.content = DFS_PROFILE_DOWN_TARGET;
	}
	else
	{
		return BSP_OK;
	}
	set_msg.profile = (u32)profile;
	return balong_cpufreq_icc_send(&set_msg);
}
int balong_cpufreq_icc_send(struct cpufreq_msg *msg)
{

	u32 channel_id = ICC_CHN_MCORE_ACORE << 16 | MCU_ACORE_CPUFREQ;
	s32 ret = 0;
	u32 msg_len = sizeof(struct cpufreq_msg);
	if (!g_cpufreq_lock_status_flag)
	{
		return BSP_ERROR;
	}
	ret = balong_check_msg(msg);
	if (BSP_ERROR == ret)
	{
		return BSP_OK;
	}
	if (msg->msg_type != CPUFREQ_GET_FREQ_FROM_M)
	{
		debug_msg.msg_type = msg->msg_type;
		debug_msg.source = msg->source;
		debug_msg.content = msg->content;
		debug_msg.profile = msg->profile;
	}

	ret = bsp_icc_send(ICC_CPU_MCU, channel_id, (u8 *)msg, msg_len);

	if(ret != (s32)msg_len)
	{
		cpufreq_err("mcore return an ERROR please check m3 %d\n", ret);
		return BSP_ERROR;
	}
	
    return BSP_OK;
}
static void register_icc_for_cpufreq(void)
{
	s32 ret;
	u32 channel_id_set = ICC_CHN_MCORE_CCORE << 16 | MCU_CCORE_CPUFREQ;
	ret = bsp_icc_event_register(channel_id_set, (read_cb_func)balong_cpufreq_cb_getprofile, (void *)NULL, (write_cb_func)NULL, (void *)NULL);
	if (ret != BSP_OK)
	{
		cpufreq_err("icc register failed %d\n", ret);
	}
	cpufreq_info("register icc %d\n", ret);
}
/***********************************************************
*调频任务初始化
***********************************************************/
static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
{
    /* We want all CPUs to do sampling nearly on same jiffy */
    unsigned long delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
    if (NULL == dbs_info) {
        cpufreq_err("!!!!!!dbs_timer_init!!!!!!error\n");
        return;
    }

    INIT_DELAYED_WORK_DEFERRABLE(&(dbs_info->work), balong_do_dbs_timer);/*lint !e613*/
    schedule_delayed_work_on(dbs_info->cpu, &(dbs_info->work), delay);/*lint !e613*/
}
/*****************************************************************************
 函 数 名  : DRV_PWRCTRL_GetCcpuLoadCB
 功能描述  : arm 提供给TTF的回调函数,该接口中回调不可再中断中使用
 输入参数  : pFunc:TTF函数指针
 输出参数  : 无
 返 回 值  : 申请空间的地址 。
*****************************************************************************/
 void BSP_PWRCTRL_GetCcpuLoadCB(PWRCTRLFUNCPTR pFunc )
 {
	 if (NULL == pFunc)
    {
        cpufreq_err("BSP_PWRCTRL_FlowCtrlCallBackRegister param is Null,pls check\n");
        return;
    }
    else
    {
        FlowCtrlCallBack = pFunc;
    }
 }
/*
 * 设置profile下限
 * success: return BSP_OK
 * fail:    return BSP_ERROR
 */
int pwrctrl_dfs_set_baseprofile(int baseprofile)
{
	struct cpufreq_msg set_msg = {0,0,0,0};
	if ((baseprofile < BALONG_FREQ_MIN) || (baseprofile > BALONG_FREQ_MAX))
	{
		cpufreq_err("profile in right bound??%d\n", baseprofile);
		return BSP_ERROR;
	}
	set_msg.msg_type = CPUFREQ_ADJUST_FREQ;
	set_msg.source = CPUFREQ_ACORE;
	set_msg.content = DFS_PROFILE_DOWN_LIMIT;
	set_msg.profile = (u32)baseprofile;
	return balong_cpufreq_icc_send(&set_msg);
}
static s32 balong_cpufreq_cb_getprofile(u32 channel_id , u32 len, void* context)
{
	s32 ret = 0;
	struct cpufreq_msg cm = {0};
	ret = bsp_icc_read(channel_id, (u8*)&cm, len);

	if(len != (u32)ret)
	{
		cpufreq_err("balong_cpufreq_cb_getload error \r\n");
		return -1;
	}
	g_stDfsCpuControl.enCurProfile = cm.profile;
	cpufreq_info("get icc from Mcore msg_type->>%d, source->>%d, profile->>%d\n", cm.msg_type, cm.source, cm.profile);
	return 0;
}
void test_for_v9r1_interface(int inter_id, int request_id, int request_freq, int req_id)
{
	int req_request_id = 0;
	switch(inter_id)
	{
		case 0://request
			if (PWRCTRL_DfsQosRequest(request_id, (u32)request_freq, &req_request_id))
			{
				cpufreq_err("QosRequest error\n");
			}
			break;
		case 1://release
			if (PWRCTRL_DfsQosRelease(request_id, &req_request_id))
			{
				cpufreq_err("QosRelease error\n");
			}
			break;
		case 2: //update
			(void)PWRCTRL_DfsQosUpdate(request_id, req_id, (u32)request_freq);
			break;
		default:
			break;
	}
}
void register_icc_for_cpufreq(void)
{
    s32 ret;
    u32 channel_id_set = ICC_CHN_MCORE_ACORE << 16 | MCU_ACORE_CPUFREQ;
    ret = bsp_icc_event_register(channel_id_set, (read_cb_func)balong_cpufreq_cb_getprofile, (void *)NULL, (write_cb_func)NULL, (void *)NULL);
    if (ret != BSP_OK)
    {
        cpufreq_err("icc register failed %d\n", ret);
    }
    else
    {
        ;
    }
    cpufreq_debug("register icc to mcore %d\n", ret);
}/*lint !e533 */
s32 balong_cpufreq_cb_getprofile(u32 channel_id , u32 len, void* context)
{

	s32 ret = 0;
	struct cpufreq_msg cm = {0};
	ret = bsp_icc_read(channel_id, (u8*)&cm, len);

	if((s32)len != ret)
	{
		cpufreq_err("balong_cpufreq_cb_getload error \r\n");
		return BSP_ERROR;
	}

	cpufreq_info("get icc from Mcore msg_type->>%d, source->>%d, profile->>%d\n", cm.msg_type, cm.source, cm.profile);

	return BSP_OK;
}
/*
 * 获取当前频率 BSP_ERROR 设置失败;BSP_OK 设置成功
 * 
 */
int pwrctrl_dfs_current(int *a9freq, int *ddrfreq, int *slowfreq)
{
	int cur_profile = 0;
	int ret = BSP_OK;
	if ((a9freq != NULL) && (ddrfreq != NULL) && (slowfreq != NULL))
	{
		cur_profile = pwrctrl_dfs_get_profile();
		*a9freq = (s32)balong_query_profile_table[cur_profile].cpu_frequency;
		*ddrfreq = (s32)balong_query_profile_table[cur_profile].ddr_frequency;
		*slowfreq = (s32)balong_query_profile_table[cur_profile].sbus_frequency;
	}
	else
	{
		cpufreq_err("argv is NULL,check it\n");
		ret = BSP_ERROR;
	}
	return ret;
}
/***********************************************************
*调频任务
***********************************************************/
void balong_do_dbs_timer(struct work_struct *work)
{
    struct cpu_dbs_info_s *dbs_info = &per_cpu(g_acpu_dbs_info, 0);
    s32 cpu = 0;
    unsigned long delay = 0;
    if (dbs_info == NULL) {
        cpufreq_err("dbs_info error\n");
        return;
    }
    cpu = dbs_info->cpu;
    mutex_lock(&info_mutex);
    /*检查CPU占用率,调频*/
    balong_dbs_check_cpu();

    delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);

    schedule_delayed_work_on(cpu, &dbs_info->work, delay);
    mutex_unlock(&info_mutex);
}
/*设置调频阈值 不用配置的项输入负值*/
void cpufreq_exc_change_limit(u32 sample, u32 up_cpuloadlimit, u32 down_cpuloadlimit, u32 down_times, u32 up_times)
{
    unsigned long flags = 0;
    local_irq_save(flags);
    if (up_cpuloadlimit <= down_cpuloadlimit)
    {
        cpufreq_err("ERROE: up_cpuloadlimit <= down_cpuloadlimit")	;
        goto out;
    }
    dbs_tuners_ins.sampling_rate = sample;

    dbs_tuners_ins.up_threshold = up_cpuloadlimit;

    dbs_tuners_ins.down_threshold = down_cpuloadlimit;

    dbs_tuners_ins.down_threshold_times = down_times;

    dbs_tuners_ins.up_threshold_times = up_times;
out:
    local_irq_restore(flags);
}
/*
 * 发送消息 BSP_ERROR 发送失败;BSP_OK 发送成功
 */
int balong_cpufreq_icc_send(struct cpufreq_msg *msg)
{
	u32 channel_id = ICC_CHN_MCORE_CCORE << 16 | MCU_CCORE_CPUFREQ;
	s32 ret = 0;
	u32 time_value = 0;
	u32 msg_len = sizeof(struct cpufreq_msg);
	if (!g_cpufreq_lock_status_flag)
	{
		return BSP_ERROR;
	}
	ret = balong_check_msg(msg);
	if (BSP_ERROR == ret)
	{
		bsp_trace(BSP_LOG_LEVEL_DEBUG, BSP_MUDU_CPUFREQ,"msg is: msg_type:%d source:%d content:%d profile:%d\n",
																								msg->msg_type, msg->source, msg->content, msg->profile);
		return BSP_OK;
	}
	if(g_lowpower_shared_addr)
	{
		time_value=  bsp_get_slice_value();
		writel(time_value, g_lowpower_shared_addr + 0x210);
	}
	debug_msg.msg_type = msg->msg_type;
	debug_msg.source = msg->source;
	debug_msg.content = msg->content;
	debug_msg.profile = msg->profile;
	cpufreq_pm_om_log(msg);
	
	ret = bsp_icc_send(ICC_CPU_MCU, channel_id, (u8 *)msg, msg_len);

	if((ret < 0) && (ret != BSP_ERR_ICC_CCORE_RESETTING))
	{
		cpufreq_err("mcore return an ERROR please check m3 %d\n", ret);
		return BSP_ERROR;
	}

    return BSP_OK;
}
/*设置调频阈值 不用配置的项输入负值*/
void cpufreq_exc_change_limit(u32 sample, u32 up_cpuloadlimit, u32 down_cpuloadlimit, u32 down_times, u32 up_times)
{
	unsigned long flags = 0;
	local_irq_save(flags);
	if (up_cpuloadlimit <= down_cpuloadlimit)
	{
		cpufreq_err("ERROE: up_cpuloadlimit <= down_cpuloadlimit")	;
		goto out;
	}
	g_stDfsCpuConfigInfo.ulTimerLen = sample;
	
	g_test_in_interr_times = sample;

	g_stDfsCpuConfigInfo.astThresHold[0].usProfileUpLimit = up_cpuloadlimit;

	g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit = down_cpuloadlimit;

	g_stDfsCpuConfigInfo.usProfileDownTime = down_times;

	g_stDfsCpuConfigInfo.usProfileUpTime = up_times;

out:
	local_irq_restore(flags);
}
void cpufreq_print_debug(void)
{
    struct cpu_dbs_info_s *dbs_info;
    dbs_info = &per_cpu(g_acpu_dbs_info, 0);
    pwrctrl_dfs_get_profile();
    cpufreq_err("cur    profile: %d\n", g_cur_profile);
    cpufreq_err("acore    load: %d\n", g_ulACpuload);
    cpufreq_err("up      times: %d\n", dbs_info->cpu_up_time);
    cpufreq_err("down  times: %d\n", dbs_info->cpu_down_time);
    cpufreq_err("up_threshold: %d\n", dbs_tuners_ins.up_threshold);
    cpufreq_err("up_threshold_times: %d\n", dbs_tuners_ins.up_threshold_times);
    cpufreq_err("down_threshold: %d\n", dbs_tuners_ins.down_threshold);
    cpufreq_err("down_threshold_times: %d\n", dbs_tuners_ins.down_threshold_times);
    cpufreq_err("sampling_rate: %d\n", dbs_tuners_ins.sampling_rate);
    cpufreq_err("last icc msg\n");
    cpufreq_err("icc msg_type: %d\n", debug_msg.msg_type);
    cpufreq_err("icc source: %d\n", debug_msg.source);
    cpufreq_err("icc content: %d\n", debug_msg.content);
    cpufreq_err("icc profile: %d\n", debug_msg.profile);
    cpufreq_err("cur max limit:%d\n", CPUFREQ_MAX_PROFILE_LIMIT);
    cpufreq_err("cur min limit:%d\n", CPUFREQ_MIN_PROFILE_LIMIT);
}
static s32 cpufreq_governor_dbs(struct cpufreq_policy *policy, u32 event)
{
    s32 cpu = (s32)policy->cpu;
    struct cpu_dbs_info_s *dbs_info = NULL;
    u32 retValue = 0;
    ST_PWC_SWITCH_STRU cpufreq_control_nv = {0} ;
    /*cpu 信息*/
    dbs_info = &per_cpu(g_acpu_dbs_info, (u32)cpu);
    /*lint --e{744 } */
    switch (event) {
    case CPUFREQ_GOV_START:
        cpufreq_debug("CPUFREQ_GOV_START\n");
        mutex_lock(&dbs_mutex);

        dbs_enable++;

        /*cpu 信息初始化  函数??idle_time*/
        dbs_info->prev_cpu_idle = get_cpu_idle_time(0,
                                  &dbs_info->prev_cpu_wall);
        dbs_info->cur_policy = policy;
        dbs_info->cpu = cpu;
        dbs_info->freq_table = cpufreq_frequency_get_table((u32)cpu);
        dbs_info->cpu_down_time = 0;
        dbs_info->cpu_up_time = 0;
        retValue = bsp_nvm_read(NV_ID_DRV_NV_PWC_SWITCH,(u8*)&cpufreq_control_nv,sizeof(ST_PWC_SWITCH_STRU));
        if (NV_OK == retValue)
        {
            g_cpufreq_lock_status_flag = cpufreq_control_nv.dfs;
        }
        else
        {
            cpufreq_err("read nv failed %d\n", retValue);
        }

        if (1 == dbs_enable) {
            retValue = bsp_nvm_read(NV_ID_DRV_NV_DFS_SWITCH,(u8*)&g_stDfsSwitch,sizeof(ST_PWC_DFS_STRU));
            if (NV_OK != retValue)
            {
                cpufreq_err("read nv failed use default value\n");
                g_stDfsSwitch.AcpuDownLimit = 20;
                g_stDfsSwitch.AcpuDownNum = 3;
                g_stDfsSwitch.AcpuUpLimit = 80;
                g_stDfsSwitch.AcpuUpNum = 1;
                g_stDfsSwitch.DFSTimerLen = 400;
            }

            dbs_tuners_ins.up_threshold = g_stDfsSwitch.AcpuUpLimit;
            dbs_tuners_ins.down_threshold = g_stDfsSwitch.AcpuDownLimit;
            dbs_tuners_ins.down_threshold_times = g_stDfsSwitch.AcpuDownNum;
            dbs_tuners_ins.up_threshold_times = g_stDfsSwitch.AcpuUpNum;
            dbs_tuners_ins.sampling_rate = g_stDfsSwitch.DFSTimerLen * 10000; /*unit:us*/
            /*
             * Start the timerschedule work, when this governor
             * is used for first time
             */

            register_icc_for_cpufreq();

            dbs_timer_init(dbs_info);
        }
        mutex_unlock(&dbs_mutex);
        break;

    case CPUFREQ_GOV_STOP:
        dbs_timer_exit(dbs_info);

        mutex_lock(&dbs_mutex);
        dbs_enable--;
        mutex_unlock(&dbs_mutex);
        break;

    case CPUFREQ_GOV_LIMITS:

        mutex_lock(&info_mutex);
        dbs_info->cpu_down_time = 0;
        dbs_info->cpu_up_time = 0;
        mutex_unlock(&info_mutex);
        if (policy->max < dbs_info->cur_policy->cur)
            __cpufreq_driver_target(dbs_info->cur_policy,
                                    policy->max, CPUFREQ_RELATION_H);
        else if (policy->min > dbs_info->cur_policy->cur)
            __cpufreq_driver_target(dbs_info->cur_policy,
                                    policy->min, CPUFREQ_RELATION_L);

        break;
    }
    return 0;
}
/*
	调频策略
*/
static u32  cpufreq_calccpu_result(u32 *next_freq)
{
    u32 ulSleepTime;
    u32 ulCpuFree;
    u32 ulCpuLoad_C;
    u32 ulProTime;
    u32 ulEndTime;
    int cur_profile = 0;
    PWRCTRLFUNCPTR pRoutine = NULL;

    /*这里是读取时间,暂时大桩*/
	ulEndTime = bsp_get_slice_value();
  	ulProTime = ulEndTime - g_stDfsCpuControl.ulStartTime;
	ulSleepTime = g_ulDfsCcpuIdleTime;
	g_ulDfsCcpuIdleTime = 0;
	g_stDfsCpuControl.ulStartTime = ulEndTime;
	ulCpuFree= (ulSleepTime* 100) / (ulProTime);    /*Calc the Cpu Free Value*/

	if (ulCpuFree > 100)
    {
		cpufreq_err("calc cpuload error!\n");
        return DFS_PROFILE_NOCHANGE;
    }
	ulCpuLoad_C= 100 - ulCpuFree;
	g_ulCCpuload = ulCpuLoad_C;
	 /*调用ttf回调函数*/
    if (NULL != FlowCtrlCallBack)
    {
        pRoutine = FlowCtrlCallBack;
        (void)(*pRoutine)(g_ulCCpuload);
    }
    else
    {
	}
    if (ulCpuLoad_C > g_stDfsCpuConfigInfo.astThresHold[0].usProfileUpLimit)
    {
        /*Clean the Value of the System Down Counter*/
        g_stDfsCpuControl.ulCurSysDownTime = 0;
		g_stDfsCpuControl.ulCurSysUpTime++;
	}
    else if (ulCpuLoad_C < g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit)
    {
        /*Clean the Value of the System Over Load Counter*/
		g_stDfsCpuControl.ulCurSysUpTime = 0;
		g_stDfsCpuControl.ulCurSysDownTime++;
    }
    else /*The System Load is Normal Value*/
    {
		g_stDfsCpuControl.ulCurSysDownTime = 0;
        g_stDfsCpuControl.ulCurSysUpTime = 0;

        return DFS_PROFILE_NOCHANGE;
    }
	cur_profile = pwrctrl_dfs_get_profile();
    if (g_stDfsCpuControl.ulCurSysDownTime >= g_stDfsCpuConfigInfo.usProfileDownTime)
    {
		g_stDfsCpuControl.ulCurSysDownTime = 0;
        g_stDfsCpuControl.ulCurSysUpTime = 0;

        *next_freq =( ulCpuLoad_C * (balong_query_profile_table[cur_profile].cpu_frequency))
        							/ (g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit);
        return DFS_PROFILE_DOWN;
    }

    if (g_stDfsCpuControl.ulCurSysUpTime >= g_stDfsCpuConfigInfo.usProfileUpTime)
    {
		 g_stDfsCpuControl.ulCurSysDownTime = 0;
        g_stDfsCpuControl.ulCurSysUpTime = 0;
        *next_freq = balong_query_profile_table[BALONG_FREQ_MAX].cpu_frequency;/*max cpufreq*/
        return DFS_PROFILE_UP_TARGET;
    }

	return DFS_PROFILE_NOCHANGE;

}
/*find a freq in all table*/
static int cpufreq_frequency_table_target(struct cpufreq_frequency_table *table,
				   unsigned int target_freq,
				   unsigned int relation,
				   unsigned int *index)
{/*lint !e578 */
	struct cpufreq_frequency_table optimal = {
		.index = ~0,
		.frequency = 0,
	};
	struct cpufreq_frequency_table suboptimal = {
		.index = ~0,
		.frequency = 0,
	};
	unsigned int i;
	/*lint --e{744} */
	switch (relation) {
	case DFS_PROFILE_UP:
		suboptimal.frequency = ~0;
		break;
	case DFS_PROFILE_DOWN:
		optimal.frequency = ~0;
		break;
	}

	for (i = 0; (table[i].frequency != (u32)CPUFREQ_TABLE_END); i++) {
		unsigned int freq = table[i].frequency;
		if (freq == (u32)CPUFREQ_ENTRY_INVALID)
			continue;
		if ((freq < balong_query_profile_table[BALONG_FREQ_MIN].cpu_frequency) || (freq > balong_query_profile_table[BALONG_FREQ_MAX].cpu_frequency))
			continue;
		switch (relation) {
		case DFS_PROFILE_UP:
			if (freq <= target_freq) {
				if (freq >= optimal.frequency) {
					optimal.frequency = freq;
					optimal.index = i;
				}
			} else {
				if (freq <= suboptimal.frequency) {
					suboptimal.frequency = freq;
					suboptimal.index = i;
				}
			}
			break;
		case DFS_PROFILE_DOWN:
			if (freq >= target_freq) {
				if (freq <= optimal.frequency) {
					optimal.frequency = freq;
					optimal.index = i;
				}
			} else {
				if (freq >= suboptimal.frequency) {
					suboptimal.frequency = freq;
					suboptimal.index = i;
				}
			}
			break;
		}
	}
	if (optimal.index > i) {
		if (suboptimal.index > i)
			return BSP_ERROR;
		*index = suboptimal.index;
	} else
		*index = optimal.index;

	return BSP_OK;
}
/*****************************************************************************
Function:   PWRCTRL_DfsMgrExcuteVoteResultCpu
Description:Handle the Profile Vote Result
Input:      enResult:   The Vote Value
Output:     None
Return:     None
Others:
*****************************************************************************/
static int  cpufreq_excute_result_cpu(u32 relation, u32 target_freq)
{
	u32 result = 2;
	u32 new_index = 0;
	int cur_profile = 0;
	struct cpufreq_msg task_msg = {0,0,0,0};

	cpufreq_frequency_table_target(balong_clockrate_table,
					   target_freq, relation, &new_index);

	cpufreq_debug("target_freq %d new_index%d\n", target_freq, new_index);

	cur_profile = pwrctrl_dfs_get_profile();
	if ((DFS_PROFILE_UP == relation) && (BALONG_FREQ_MAX != cur_profile))
	{
		result = DFS_PROFILE_UP_TARGET;
	}
	else if ((DFS_PROFILE_DOWN == relation) && (BALONG_FREQ_MIN != cur_profile))
	{
		result = DFS_PROFILE_DOWN_TARGET;
	}
	else
	{
		cpufreq_err("set target relation %d, cur pro %d\n", relation, cur_profile);
		return BSP_ERROR;
	}

	cpufreq_frequency_target_profile(balong_clockrate_table[new_index].frequency, relation, &new_index);

	task_msg.msg_type = CPUFREQ_ADJUST_FREQ;
	task_msg.source = CPUFREQ_CCORE;
	task_msg.content = result;
	task_msg.profile = new_index;
	balong_cpufreq_icc_send(&task_msg);
	g_stDfsCpuControl.enCurProfile = (u32)cur_profile;
	return BSP_OK;

}

unsigned int cpufreq_calccpu_cpuload(void)
{
	u32 end_time = 0;
	u32 idle_time = 0;
	u32 wall_time = 0;
	u32 cpu_load = 0;
	unsigned long irqlock = 0;
	local_irq_save(irqlock);
	end_time = bsp_get_slice_value();
	wall_time = get_timer_slice_delta(g_cpufreq_start_time, end_time);
	idle_time = g_ulDfsCcpuIdleTime_long;
	g_cpufreq_start_time = end_time;
	g_ulDfsCcpuIdleTime_long = 0;
	g_flowctrl_in_interr_times = 0;
	cpu_load = (wall_time == 0) ? (0) : (((wall_time - idle_time) * 100) / wall_time);
	local_irq_restore(irqlock);
	if (cpu_load > 100)
	{
		cpu_load = g_ulCCpuload;
		cpufreq_info("cpuload: %d, wall:%d, idle:%d\n", cpu_load, wall_time, idle_time);
	}
	return cpu_load;
}
void  cpufreq_init(void)
{
	/*lint --e{516}*/
	u32 i = 0;
	u32 retValue = 0;
	ST_PWC_SWITCH_STRU cpufreq_control_nv = {0} ;
    retValue = bsp_nvm_read(NV_ID_DRV_NV_DFS_SWITCH,(u8*)&g_stDfsSwitch,sizeof(ST_PWC_DFS_STRU));
    if (NV_OK != retValue)
    {
    	cpufreq_err("read nv failed use default value\n");
		g_stDfsSwitch.CcpuDownLimit = 60;
		g_stDfsSwitch.CcpuDownNum = 3;
		g_stDfsSwitch.CcpuUpLimit = 85;
		g_stDfsSwitch.CcpuUpNum = 1;
		g_stDfsSwitch.DFSTimerLen = 400;
		g_stDfsSwitch.Strategy = 0;/*使用4s检测一次的策略*/
		g_stDfsSwitch.DFSDdrUpLimit = 85;
		g_stDfsSwitch.DFSDdrDownLimit = 60;
		g_stDfsSwitch.DFSDdrprofile = 5;
		g_stDfsSwitch.reserved = 0;
    }
	retValue = bsp_nvm_read(NV_ID_DRV_NV_PWC_SWITCH,(u8*)&cpufreq_control_nv,sizeof(ST_PWC_SWITCH_STRU));
	if (NV_OK == retValue)
	{
		g_cpufreq_lock_status_flag = cpufreq_control_nv.dfs;
	}
	else
	{
		cpufreq_err("read nv failed %d\n", retValue);
	}

    memset(&g_stDfsCpuConfigInfo, 0, sizeof(g_stDfsCpuConfigInfo));
    memset(&g_stDfsCpuControl, 0, sizeof(g_stDfsCpuControl));
	g_stDfsCpuControl.enCurProfile = BALONG_FREQ_MAX;

	register_icc_for_cpufreq();
	cpufreq_table_init();
#ifdef CONFIG_CCORE_PM
    if (bsp_device_pm_add(&g_cpufreq_dpm_device))
    {
		cpufreq_err("register dpm failed,check it\n");
    }
#endif
    /*bit1 使用MS级调频策略*/
    if (g_stDfsSwitch.Strategy & 0x1)
    {
		  g_sem_calccpu_flag = semBCreate(SEM_Q_PRIORITY, SEM_FULL); /*lint !e64 */
		  if (NULL == g_sem_calccpu_flag)
		  {
		      cpufreq_err("Create g_sem_k3get_volt Failed %d\n", g_sem_calccpu_flag);
		  }
	}

    g_stDfsCpuConfigInfo.ulDFSFunEnableFlag = DFS_TRUE;
    g_stDfsCpuConfigInfo.usProfileDownTime = g_stDfsSwitch.CcpuDownNum;
    g_stDfsCpuConfigInfo.usProfileUpTime = g_stDfsSwitch.CcpuUpNum;
    g_stDfsCpuConfigInfo.ulProfileNum = DC_RESV;
    g_stDfsCpuConfigInfo.ulTimerLen = g_stDfsSwitch.DFSTimerLen;
    g_test_in_interr_times = g_stDfsSwitch.DFSTimerLen;

    for (i = 0; i < g_stDfsCpuConfigInfo.ulProfileNum; i++)
    {
        g_stDfsCpuConfigInfo.astThresHold[i].usProfileUpLimit   = g_stDfsSwitch.CcpuUpLimit;
        g_stDfsCpuConfigInfo.astThresHold[i].usProfileDownLimit = g_stDfsSwitch.CcpuDownLimit;
    }
    INIT_LIST_HEAD(&(g_v9_qos_list.entry));
    /*添加DDR调频请求*/
    (void)PWRCTRL_DfsQosRequest(DFS_QOS_ID_DDR_MINFREQ, BALONG_DDRFREQUENCY_MIN, &g_ddr_request_id);
    
    taskSpawn("dfs_task", 1, 0, 4096, (FUNCPTR)pwrctrl_dfs_mgrmsg_task, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);/*lint !e64 !e119 */
	g_cpufreq_start_time = bsp_get_slice_value();
	cpufreq_err("cpufreq init ok\n");
    return;
}
void cpufreq_print_debug(void)
{
	pwrctrl_dfs_get_profile();
	cpufreq_err("cur\t profile: %d\n", g_cur_profile);
	cpufreq_err("ccore\t load: %d\n", g_ulCCpuload);
	cpufreq_err("lase\t ddr: %d\n", g_last_ddr_value_id);
	cpufreq_err("up      times: %d\n", g_stDfsCpuControl.ulCurSysUpTime);
	cpufreq_err("down  times: %d\n", g_stDfsCpuControl.ulCurSysDownTime);
	cpufreq_err("up_threshold: %d\n", g_stDfsCpuConfigInfo.astThresHold[0].usProfileUpLimit);
	cpufreq_err("up_threshold_times: %d\n",  g_stDfsCpuConfigInfo.usProfileUpTime);
	cpufreq_err("down_threshold: %d\n", g_stDfsCpuConfigInfo.astThresHold[0].usProfileDownLimit);
	cpufreq_err("down_threshold_times: %d\n",  g_stDfsCpuConfigInfo.usProfileDownTime);
	cpufreq_err("sampling_rate: %d\n", g_stDfsCpuConfigInfo.ulTimerLen);
	cpufreq_err("last icc msg\n");
	cpufreq_err("icc msg_type: %d\n", debug_msg.msg_type);
	cpufreq_err("icc source: %d\n", debug_msg.source);
	cpufreq_err("icc content: %d\n", debug_msg.content);
	cpufreq_err("icc profile: %d\n", debug_msg.profile);
	cpufreq_err("cur max limit:%d\n", CPUFREQ_MAX_PROFILE_LIMIT);
	cpufreq_err("cur min limit:%d\n", CPUFREQ_MIN_PROFILE_LIMIT);
}