/* * 调试接口,设置频率 BSP_ERROR 设置失败;BSP_OK 设置成功 * */ int pwrctrl_dfs_target(int a9freq, int ddrfreq, int slowfreq) { int target_profile = 0; target_profile = pwrctrl_find_min_profile((u32)a9freq, (u32)ddrfreq, (u32)slowfreq); cpufreq_debug("prolfie : %d\n", target_profile); pwrctrl_dfs_set_baseprofile(target_profile); return target_profile; }
/* * 锁定调频 DFS_PROFILE_LOCKFREQ=0锁定;DFS_PROFILE_LOCKFREQ=1解锁 */ void pwrctrl_dfs_lock(u32 lock) { struct cpufreq_msg set_msg = {0,0,0,0}; cpufreq_debug("cpufreq lock status is: %d\n", g_cpufreq_lock_status_flag); g_cpufreq_lock_status_flag = (s32)lock; set_msg.content = lock; set_msg.msg_type = CPUFREQ_LOCK_MCORE_ACTION; set_msg.source = CPUFREQ_ACORE; balong_cpufreq_icc_send(&set_msg); }
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 */
/* * Here we notify other drivers of the proposed change and the final change. * * *根据relation做相应动作 */ static s32 balong_cpufreq_target(struct cpufreq_policy *policy, u32 target_freq, u32 relation) { u32 result = 2; u32 new_index = 0; int cur_profile = 0; struct cpufreq_msg task_msg = {0,0,0,0}; cpufreq_frequency_table_target(policy, 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 ((CPUFREQ_RELATION_H == relation) && (BALONG_FREQ_MAX != cur_profile)) { result = DFS_PROFILE_UP_TARGET; } else if ((CPUFREQ_RELATION_L == relation) && (BALONG_FREQ_MIN != cur_profile)) { result = DFS_PROFILE_DOWN_TARGET; } else { policy->cur = balong_clockrate_table[cur_profile].frequency; g_cur_freq = policy->cur; cpufreq_info("set target relation %d, cur pro %d\n", relation, policy->cur); 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_ACORE; task_msg.content = result; task_msg.profile = new_index; balong_cpufreq_icc_send(&task_msg); policy->cur = balong_clockrate_table[cur_profile].frequency; g_cur_freq = policy->cur; return BSP_OK; }
/*find the first profile that is the target*/ static void cpufreq_frequency_target_profile( unsigned int target_freq, unsigned int relation, unsigned int *new_profile) { int i = 0; int cur_profile = pwrctrl_dfs_get_profile(); switch (relation) { case DFS_PROFILE_UP: *new_profile = balong_clockrate_table[BALONG_FREQ_MAX].index; return; case DFS_PROFILE_DOWN: cpufreq_debug("down to frequency\n"); break; default : break; } for (i = cur_profile; i >= BALONG_FREQ_MIN; i--) { if (target_freq != balong_query_profile_table[i].cpu_frequency) { continue; } if ((u32)cur_profile == balong_query_profile_table[i].profile) { continue; } *new_profile = balong_query_profile_table[i].profile; goto out; } if (cur_profile != BALONG_FREQ_MIN) { *new_profile = balong_query_profile_table[cur_profile - 1].profile; } else { *new_profile = balong_query_profile_table[BALONG_FREQ_MIN].profile; } out: return; }
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; }
/*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; }