local_t dfs_ret pwrctrl_dfs_cmd_current(s32_t dev_id, u32_t *prof_id) { union mca_udata_req req = {0}; union mca_udata_rsp rsp = {0}; PRINT_PWC_DBG(PWC_SWITCH_DEBPT, "%s dev_id:%d\n", __FUNCTION__, dev_id); req.dfs_current_req.dev_id = dev_id; if(mca_send(MCA_CMD_DFS_CURRENT, req, &rsp, PWRCTRL_DFS_CMD_TIMEOUT)) return RET_ERR_CONNECT_FAIL; *prof_id = rsp.dfs_current_rsp.prof_id; PRINT_PWC_DBG(PWC_SWITCH_DEBPT, "%s prof_id:%d ret:%d\n", __FUNCTION__, *prof_id, rsp.dfs_current_rsp.ret); return rsp.dfs_current_rsp.ret; }
s32_t pwrctrl_sleep_mgr_get_next_schedule_time( u32_t ulAllTimer, u32_t *pTimerID, u32_t *pNextScheduleTime) { u32_t ulTimerValue = 0; u32_t i = 0; u32_t ulState = 0; u32_t ulTimclk = 0; u32_t ulCount = 0; u32_t ulTimerId = PWRCTRL_MAX_TIME; u32_t ulNextScheduleTime = PWRCTRL_MAX_TIME; if ((PWRCTRL_TRUE != ulAllTimer) && (PWRCTRL_FALSE != ulAllTimer)) { (int)PWC_TRACE(PWC_LOG_ERROR, "pwrctrl_sleep_mgr_get_next_scheduletime: ulAllTimer[%x] is err\n", ulAllTimer,0, 0, 0, 0, 0); return (s32_t)RET_ERR; } if (NULL == pTimerID) { (int)PWC_TRACE(PWC_LOG_ERROR, "pwrctrl_sleep_mgr_get_next_scheduletime: pTimerID is null\n", 0,0, 0, 0, 0, 0); return (s32_t)RET_ERR; } if (NULL == pNextScheduleTime) { (int)PWC_TRACE(PWC_LOG_ERROR, "pwrctrl_sleep_mgr_get_next_scheduletime: pNextScheduleTime is null\n", 0,0, 0, 0, 0, 0); return (s32_t)RET_ERR; } for (i = 0; i < PWRCTRL_ACPU_TIMER_TOTAL_NUM; i++) { ulTimerValue = 0; ulState = pwrctrl_get_timer_active(i); /*if the timer is disable*/ if (PWRCTRL_FALSE == ulState) { /*do nothing,see next timer*/ continue; } /*get the TIMCLK from SC .spc2.0 is 19.2M*/ /*时钟源频率*/ ulTimclk = pwrctrl_get_timer_clk(i); /*get the timer div*/ /*分频因子*/ /*ulDIV = pwrctrl_get_timer_div(g_ulPWRCTRLTimerAddr[i]);*/ /*get the timer count*/ /*获得剩余计数值*/ ulCount = pwrctrl_get_timer_cnt(i); /*calc the remain time, unit is ms */ ulTimerValue = (ulCount * PWRCTRL_THOUSAND_TIME) / (ulTimclk / PWRCTRL_THOUSAND_TIME); if (ulNextScheduleTime > ulTimerValue) { ulNextScheduleTime = ulTimerValue; ulTimerId = i; } } /*BBP TIMER IS TRANSLATE INTO TIMER*/ /*output the next schedule*/ *pNextScheduleTime = ulNextScheduleTime; *pTimerID = ulTimerId; PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE, "the timerID is %d, the left time is %d[ms]\n", ulTimerId,ulNextScheduleTime, 0, 0, 0, 0); /*Log timer id and timer value to Exc space.*/ return (s32_t)RET_OK; }
/** * menu_select - selects the next idle state to enter * @dev: the CPU */ static int menu_select(struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); int int_vote_req = pm_qos_request(PM_QOS_CPU_INT_LATENCY); unsigned int power_usage = -1; int i; int multiplier; struct timespec t; unsigned int timer_id = 0; unsigned int schedule_time = 0xffffffff; if (data->needs_update) { menu_update(dev); data->needs_update = 0; } data->last_state_idx = 0; data->exit_us = 0; if (unlikely(int_vote_req != PM_QOS_CPUIDLE_INT_DEFAULT_VALUE)) { PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,int_vote_req=0x%x\n",int_vote_req); return 0; } if(num_online_cpus() > 1) return 0; pwrctrl_sleep_mgr_get_next_schedule_time(0, &timer_id, &schedule_time); if(schedule_time > (0xFFFFFFFF / 1000)) { schedule_time = 0xFFFFFFFF; } else { schedule_time *= USEC_PER_MSEC; } /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) return 0; /* determine the expected residency time, round up */ t = ktime_to_timespec(tick_nohz_get_sleep_length()); data->expected_us = t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC; PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,data->expected_us=%d,schedule_time=%d\n",data->expected_us,schedule_time); if(schedule_time < data->expected_us) { /*PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,system time:%d private time:%d\n",data->expected_us, schedule_time);*/ data->expected_us = schedule_time; } data->bucket = which_bucket(data->expected_us); multiplier = performance_multiplier(); /* * if the correction factor is 0 (eg first time init or cpu hotplug * etc), we actually want to start out with a unity factor. */ if (data->correction_factor[data->bucket] == 0) data->correction_factor[data->bucket] = RESOLUTION * DECAY; /* Make sure to round up for half microseconds */ data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); detect_repeating_patterns(data); /* * We want to default to C1 (hlt), not to busy polling * unless the timer is happening really really soon. */ if (data->expected_us > 5) data->last_state_idx = CPUIDLE_DRIVER_STATE_START; /* * Find the idle state with the lowest power while satisfying * our constraints. */ PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"menu_select,multiplier=%d, latency_req=%d, predicted_us=%llu\n", multiplier,latency_req, data->predicted_us); for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; if (s->flags & CPUIDLE_FLAG_IGNORE) continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) continue; if (s->exit_latency * multiplier > data->predicted_us) continue; if (s->power_usage < power_usage) { power_usage = s->power_usage; data->last_state_idx = i; data->exit_us = s->exit_latency; } } return data->last_state_idx; }
int enter_lowpm(struct cpuidle_device *dev, struct cpuidle_state *state) { int icanidle = 0; int idle_time; int cpu_id = 0; int cpu_idle_flag = IDLE_DISABLE; struct cpuidle_state *new_state = state; struct timeval before, after; int enter_state; struct timespec t; unsigned int timer_id = 0; unsigned int schedule_time = 0xffffffff; unsigned int expected_us; local_irq_disable(); cpu_id = get_cpu(); put_cpu(); if(get_enter_state(state, &enter_state) != 0) { local_irq_enable(); return 0; } /* Used to keep track of the total time in idle */ getnstimeofday(&before); #if 1 /*启动过程中不允许ACPU下电*/ /*if((CPU_IDLE_C1 <= enter_state)&&(CPU_IDLE_C3 >= enter_state)&&(before.tv_sec < IDLE_ACTIVE_DELAY_S))*/ if((CPU_IDLE_C1 <= enter_state)&&(CPU_IDLE_C3 >= enter_state)&&(0 == g_pwc_init_flag)) { PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"before.tv_sec:0x%x\n",before.tv_sec); local_irq_enable(); return 0; } #endif if((RET_OK == pwrctrl_is_func_on(PWC_SWITCH_CPUIDLE))&&((CPU_IDLE_C0 < enter_state)&&(CPU_IDLE_C4 > enter_state))&&(0 == cpu_id)) { cpu_idle_flag = IDLE_ENABLE; } else { cpu_idle_flag = IDLE_DISABLE; } /*C3起定时器来唤醒 后续可优化*/ if((enter_state >= CPU_IDLE_C3)&&(IDLE_ENABLE == cpu_idle_flag)) { pwrctrl_sleep_mgr_get_next_schedule_time(0, &timer_id, &schedule_time); if(schedule_time > (0xFFFFFFFF / 1000)) { schedule_time = 0xFFFFFFFF; } else { schedule_time *= USEC_PER_MSEC; } /*C3停止所有TCXO定时器,待优化*/ /* determine the expected residency time, round up */ t = ktime_to_timespec(tick_nohz_get_sleep_length()); expected_us = t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC; if(schedule_time < expected_us) { PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"enter_lowpm,system time:%d private time:%d\n",expected_us, schedule_time); expected_us = schedule_time; } expected_us -= state->exit_latency; DRV_TIMER_STOP(CPU_IDLE_TIMER); DRV_TIMER_START((unsigned int)CPU_IDLE_TIMER, cpu_idle_timer_isr, (int)0, (expected_us / MSEC_PER_SEC), TIMER_ONCE_COUNT, TIMER_UNIT_MS); } if(IDLE_ENABLE == cpu_idle_flag) { *gp_cpuidle_state = (enter_state << CPUIDLE_STATE_START_BIT) | (CPU_IDLE_STAT_VALID << CPUIDLE_STATE_MAGIC_START_BIT); /*pwrctrl_wdt_disable();*/ } if(0 == cpu_id) { PRINT_PWC_DBG(PWC_SWITCH_CPUIDLE,"system will enter cpuidle state(%d)\n",enter_state); } if(CPU_IDLE_C0 == enter_state) { cpu_do_idle(); } else if(IDLE_ENABLE == cpu_idle_flag) { pwrctrl_deep_sleep(); } if(enter_state >= SPECIAL_HANDLE_STATE) { /*清除timer中断*/ /*C3恢复之前停止所有TCXO定时器,待优化*/ } if(IDLE_ENABLE == cpu_idle_flag) { *gp_cpuidle_state = (CPU_IDLE_C4 << CPUIDLE_STATE_START_BIT) | (CPU_IDLE_STAT_VALID << CPUIDLE_STATE_MAGIC_START_BIT); /*pwrctrl_wdt_enable();*/ } getnstimeofday(&after); idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + (after.tv_usec - before.tv_usec); local_irq_enable(); return idle_time; }