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;
}
Ejemplo n.º 3
0
/**
 * 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;
}
Ejemplo n.º 4
0
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;
}