static inline int dpidle_handler(int cpu)
{
    int ret = 0;
    if (idle_switch[IDLE_TYPE_DP]) {
#ifdef SPM_DEEPIDLE_PROFILE_TIME
        gpt_get_cnt(SPM_PROFILE_APXGPT,&dpidle_profile[0]);
#endif
        if (dpidle_can_enter()) {
            dpidle_pre_handler();
            spm_go_to_dpidle(slp_spm_deepidle_flags, 0);
            dpidle_post_handler();
            ret = 1;

#ifdef CONFIG_SMP
            idle_ver("DP:timer_left=%d, timer_left2=%d, delta=%d\n",
                dpidle_timer_left, dpidle_timer_left2, dpidle_timer_left-dpidle_timer_left2);
#else
            idle_ver("DP:timer_left=%d, timer_left2=%d, delta=%d, timeout val=%d\n",
                dpidle_timer_left, dpidle_timer_left2, dpidle_timer_left2-dpidle_timer_left,dpidle_timer_cmp-dpidle_timer_left);
#endif
#ifdef SPM_DEEPIDLE_PROFILE_TIME
            gpt_get_cnt(SPM_PROFILE_APXGPT,&dpidle_profile[3]);
            idle_ver("1:%u, 2:%u, 3:%u, 4:%u\n",
                 dpidle_profile[0], dpidle_profile[1], dpidle_profile[2],dpidle_profile[3]);
#endif
        }
    }

    return ret;
}
void soidle_before_wfi(void)
{
#ifdef CONFIG_SMP
    int err = 0;

    soidle_timer_left2 = localtimer_get_counter();

    free_gpt(GPT4);
    err = request_gpt(GPT4, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
                      0, NULL, GPT_NOAUTOEN);
    if (err) {
        idle_info("[%s]fail to request GPT4\n", __func__);
    }

    soidle_timer_left2 = localtimer_get_counter();

    if( soidle_timer_left2 <=0 )
        gpt_set_cmp(GPT4, 1);//Trigger GPT4 Timerout imediately
    else
        gpt_set_cmp(GPT4, soidle_timer_left2);

    start_gpt(GPT4);
#else
    gpt_get_cnt(GPT1, &soidle_timer_left2);
#endif

}
Example #3
0
void spm_dpidle_after_wfi(void)
{
#if 0
    idle_info("[%s]timer_left=%u, timer_left2=%u, delta=%u\n", 
        dpidle_timer_left, dpidle_timer_left2, dpidle_timer_left-dpidle_timer_left2);
#endif

    //if (gpt_check_irq(GPT4)) {
    if (gpt_check_and_ack_irq(GPT4)) {
        /* waked up by WAKEUP_GPT */
        localtimer_set_next_event(1);
    } else {
        /* waked up by other wakeup source */
        unsigned int cnt, cmp;
        gpt_get_cnt(GPT4, &cnt);
        gpt_get_cmp(GPT4, &cmp);
        if (unlikely(cmp < cnt)) {
            idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__, 
                    GPT4 + 1, cnt, cmp);
            BUG();
        }

        localtimer_set_next_event(cmp-cnt);
        stop_gpt(GPT4);
        //GPT_ClearCount(WAKEUP_GPT);
    }

    faudintbus_sq2pll();

    bus_dcm_disable();
    
    dpidle_cnt[0]++;
}
void spm_dpidle_after_wfi(void)
{

#ifdef CONFIG_SMP
    //if (gpt_check_irq(GPT4)) {
    if (gpt_check_and_ack_irq(GPT4)) {
        /* waked up by WAKEUP_GPT */
        localtimer_set_next_event(1);
    } else {
        /* waked up by other wakeup source */
        unsigned int cnt, cmp;
        gpt_get_cnt(GPT4, &cnt);
        gpt_get_cmp(GPT4, &cmp);
        if (unlikely(cmp < cnt)) {
            idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__,
                     GPT4 + 1, cnt, cmp);
            BUG();
        }

        localtimer_set_next_event(cmp-cnt);
        stop_gpt(GPT4);
        //GPT_ClearCount(WAKEUP_GPT);
        free_gpt(GPT4);

    }
#endif
    disable_clock(MT_CG_PMIC_SW_CG_AP, "DEEP_IDLE");
    clkmux_sel(MT_CLKMUX_AUD_INTBUS_SEL,g_clk_aud_intbus_sel,"Deep_Idle");

    dpidle_cnt[0]++;
}
Example #5
0
void spm_mcdi_after_wfi(int cpu)
{
    unsigned int id = mcidle_gpt_percpu[cpu];
    if (cpu != 0) {
        if (gpt_check_and_ack_irq(id)) {
            localtimer_set_next_event(1);
        } else {
            /* waked up by other wakeup source */
            unsigned int cnt, cmp;
            gpt_get_cnt(id, &cnt);
            gpt_get_cmp(id, &cmp);
            if (unlikely(cmp < cnt)) {
                printk("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__, 
                        id + 1, cnt, cmp);
                BUG();
            }
        
            localtimer_set_next_event(cmp-cnt);
            stop_gpt(id);
#ifdef SPM_SUSPEND_GPT_EN
            free_gpt(id);
#endif
        }
    }

}
void spm_dpidle_before_wfi(void)
{

    int err = 0;


    g_clk_aud_intbus_sel = clkmux_get(MT_CLKMUX_AUD_INTBUS_SEL,"Deep_Idle");
    clkmux_sel(MT_CLKMUX_AUD_INTBUS_SEL, MT_CG_SYS_26M,"Deep_Idle");

    enable_clock(MT_CG_PMIC_SW_CG_AP, "DEEP_IDLE");//PMIC CG bit for AP. SPM need PMIC wrapper clock to change Vcore voltage
#ifdef CONFIG_SMP

    free_gpt(GPT4);
    err = request_gpt(GPT4, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
                      0, NULL, GPT_NOAUTOEN);

    if (err) {
        idle_info("[%s]fail to request GPT4\n", __func__);
    }

    dpidle_timer_left2 = localtimer_get_counter();

    if( dpidle_timer_left2 <=0 )
        gpt_set_cmp(GPT4, 1);//Trigger GPT4 Timerout imediately
    else
        gpt_set_cmp(GPT4, dpidle_timer_left2);

    start_gpt(GPT4);
#else
    gpt_get_cnt(GPT1, &dpidle_timer_left2);
#endif

}
void spm_dpidle_after_wfi(void)
{
#ifdef CONFIG_SMP
        //if (gpt_check_irq(GPT4)) {
        if (gpt_check_and_ack_irq(idle_gpt)) {
            /* waked up by WAKEUP_GPT */
            localtimer_set_next_event(1);
        } else {
            /* waked up by other wakeup source */
            unsigned int cnt, cmp;
            gpt_get_cnt(idle_gpt, &cnt);
            gpt_get_cmp(idle_gpt, &cmp);
            if (unlikely(cmp < cnt)) {
                idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__,
                        idle_gpt + 1, cnt, cmp);
                BUG();
            }

            localtimer_set_next_event(cmp-cnt);
            stop_gpt(idle_gpt);
            //GPT_ClearCount(WAKEUP_GPT);
        }
#endif

    //clkmux_sel(MT_MUX_AUDINTBUS, 1, "Deepidle"); //mainpll
    clkmgr_faudintbus_sq2pll();
    bus_dcm_disable();

    dpidle_cnt[0]++;
}
void mcidle_after_wfi(int cpu)
{
#ifdef CONFIG_SMP
    unsigned int id = mcidle_gpt_percpu[cpu];
    //if (cpu != 0) {
    if (gpt_check_and_ack_irq(id)) {
        localtimer_set_next_event(1);
    } else {
        /* waked up by other wakeup source */
        unsigned int cnt, cmp;
        gpt_get_cnt(id, &cnt);
        gpt_get_cmp(id, &cmp);
        if (unlikely(cmp < cnt)) {
            idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__,
                     id + 1, cnt, cmp);
            BUG();
        }

        localtimer_set_next_event(cmp-cnt);
        stop_gpt(id);

        free_gpt(id);

    }
    //}
#endif
    mcidle_cnt[cpu]++;
}
void spm_dpidle_before_wfi(void)
{
    if (TRUE == mt_dpidle_chk_golden)
    {
    //FIXME:
#if 0
        mt_power_gs_dump_dpidle();
#endif
    }
    bus_dcm_enable();
    clkmgr_faudintbus_pll2sq();
    //clkmux_sel(MT_MUX_AUDINTBUS, 0, "Deepidle"); //select 26M


#ifdef CONFIG_SMP
    dpidle_timer_left2 = localtimer_get_counter();

    if( (int)dpidle_timer_left2 <=0 )
        gpt_set_cmp(idle_gpt, 1);//Trigger GPT4 Timerout imediately
    else
        gpt_set_cmp(idle_gpt, dpidle_timer_left2);

    start_gpt(idle_gpt);
#else
    gpt_get_cnt(idle_gpt, &dpidle_timer_left2);
#endif
}
static inline int soidle_handler(int cpu)
{
    if (idle_switch[IDLE_TYPE_SO]) {
#ifdef SPM_SODI_PROFILE_TIME
        gpt_get_cnt(SPM_SODI_PROFILE_APXGPT,&soidle_profile[0]);
#endif
        if (soidle_can_enter(cpu)) {
            
            soidle_pre_handler();
            
            #ifdef DEFAULT_MMP_ENABLE
			MMProfileLogEx(sodi_mmp_get_events()->sodi_enable, MMProfileFlagStart, 0, 0);
			#endif //DEFAULT_MMP_ENABLE
			
            spm_go_to_sodi(slp_spm_SODI_flags, 0);
            
            #ifdef DEFAULT_MMP_ENABLE
            MMProfileLogEx(sodi_mmp_get_events()->sodi_enable, MMProfileFlagEnd, 0, spm_read(SPM_PCM_PASR_DPD_3));
			#endif //DEFAULT_MMP_ENABLE

            soidle_post_handler();

            #if 0 //removed unused log
            #ifdef CONFIG_SMP
            idle_ver("SO:timer_left=%d, timer_left2=%d, delta=%d\n",
                soidle_timer_left, soidle_timer_left2, soidle_timer_left-soidle_timer_left2);
            #else
            idle_ver("SO:timer_left=%d, timer_left2=%d, delta=%d,timeout val=%d\n",
                soidle_timer_left, soidle_timer_left2, soidle_timer_left2-soidle_timer_left,soidle_timer_cmp-soidle_timer_left);
            #endif
            #endif
            
            #if 0 //for DVT test only
            idle_switch[IDLE_TYPE_SO] = 0;
            #endif

#ifdef SPM_SODI_PROFILE_TIME
            gpt_get_cnt(SPM_SODI_PROFILE_APXGPT,&soidle_profile[3]);
            idle_ver("SODI: cpu_freq:%u, 1=>2:%u, 2=>3:%u, 3=>4:%u\n", mt_cpufreq_get_cur_freq(0),
                 soidle_profile[1]-soidle_profile[0], soidle_profile[2]-soidle_profile[1], soidle_profile[3]-soidle_profile[2]);
#endif
            return 1;
        }
    }

    return 0;
}
Example #11
0
bool soidle_can_enter(int cpu)
{
    int reason = NR_REASONS;

#ifdef CONFIG_SMP
    if ((atomic_read(&is_in_hotplug) == 1)||(num_online_cpus() != 1)) {
        reason = BY_CPU;
        goto out;
    }
#endif

    if(idle_spm_lock){
        reason = BY_VTG;
        goto out;
    }

    //FIXED ME. this checking is needed in 6735?
    // decide when to enable SODI by display driver
    if(spm_get_sodi_en()==0){
        reason = BY_OTH;
        goto out;
	}
	
    memset(soidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
    if (!clkmgr_idle_can_enter(soidle_condition_mask, soidle_block_mask)) {
        reason = BY_CLK;
        goto out;
    }

#ifdef CONFIG_SMP
    soidle_timer_left = localtimer_get_counter();
    if ((int)soidle_timer_left < soidle_time_critera ||
            ((int)soidle_timer_left) < 0) {
        reason = BY_TMR;
        goto out;
    }
#else
    gpt_get_cnt(GPT1, &soidle_timer_left);
    gpt_get_cmp(GPT1, &soidle_timer_cmp);
    if((soidle_timer_cmp-soidle_timer_left)<soidle_time_critera)
    {
        reason = BY_TMR;
        goto out;
    }
#endif

out:
    if (reason < NR_REASONS) {
        soidle_block_cnt[cpu][reason]++;
        return false;
    } else {
        return true;
    }
}
bool soidle_can_enter(int cpu)
{
    int reason = NR_REASONS;

#ifdef CONFIG_SMP
    if ((atomic_read(&is_in_hotplug) == 1)||(atomic_read(&hotplug_cpu_count) != 1)) {
        reason = BY_CPU;
        goto out;
    }
#endif
    if(idle_spm_lock){
        reason = BY_VTG;
        goto out;
    }


    if(spm_get_sodi_en()==0){
        reason = BY_OTH;
        goto out;
	}

    memset(soidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
    if (!clkmgr_idle_can_enter(soidle_condition_mask, soidle_block_mask)) {
        reason = BY_CLK;
        goto out;
    }

#ifdef CONFIG_SMP
    soidle_timer_left = localtimer_get_counter();
    if ((int)soidle_timer_left < soidle_time_critera ||
            ((int)soidle_timer_left) < 0) {
        reason = BY_TMR;
        goto out;
    }
#else
    gpt_get_cnt(GPT1, &soidle_timer_left);
    gpt_get_cmp(GPT1, &soidle_timer_cmp);
    if((soidle_timer_cmp-soidle_timer_left)<soidle_time_critera)
    {
        reason = BY_TMR;
        goto out;
    }
#endif


out:
    if (reason < NR_REASONS) {
        soidle_block_cnt[cpu][reason]++;
        return false;
    } else {
        return true;
    }
}
bool mcidle_can_enter(int cpu)
{
    int reason = NR_REASONS;

#ifndef CONFIG_SMP
    unsigned int cmp;
#endif

    /* MCDI Only */
    if (cpu == 0) {
        reason = BY_OTH;
        goto mcidle_out;
    }

#ifdef CONFIG_SMP
    if (atomic_read(&hotplug_cpu_count) == 1) {
        reason = BY_CPU;
        goto mcidle_out;
    }
#endif

    if (atomic_read(&is_in_hotplug) == 1) {
        reason = BY_CPU;
        goto mcidle_out;
    }
#ifdef CONFIG_SMP
    mcidle_timer_left[cpu] = localtimer_get_counter();
    if (mcidle_timer_left[cpu] < mcidle_time_critera ||
            ((int)mcidle_timer_left[cpu]) < 0) {
        reason = BY_TMR;
        goto mcidle_out;
    }
#else
    gpt_get_cnt(GPT1, &mcidle_timer_left[cpu]);
    gpt_get_cmp(GPT1, &cmp);
    if((cmp-mcidle_timer_left[cpu])<mcidle_time_critera)
    {
        reason = BY_TMR;
        goto mcidle_out;
    }
#endif

mcidle_out:
    if (reason < NR_REASONS) {
        mcidle_block_cnt[cpu][reason]++;
        return false;
    } else {
        return true;
    }
}
void soidle_before_wfi(int cpu)
{
#ifdef CONFIG_SMP
    soidle_timer_left2 = localtimer_get_counter();

    if( (int)soidle_timer_left2 <=0 )
    {
        gpt_set_cmp(idle_gpt, 1);//Trigger idle_gpt Timerout imediately
    }
    else
        gpt_set_cmp(idle_gpt, soidle_timer_left2);

    start_gpt(idle_gpt);
#else
    gpt_get_cnt(GPT1, &soidle_timer_left2);
#endif

}
unsigned char soidle_can_enter(int cpu)
{
    int reason = NR_REASONS;


#ifdef CONFIG_SMP
    if ((atomic_read(&is_in_hotplug) == 1)||(atomic_read(&hotplug_cpu_count) != 1)) {
        reason = BY_CPU;
        goto soidle_out;
    }
#endif

    memset(soidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
    if (!clkmgr_idle_can_enter(soidle_condition_mask, soidle_block_mask)) {
        reason = BY_CLK;
        goto soidle_out;
    }

#ifdef CONFIG_SMP
    soidle_timer_left = localtimer_get_counter();
    if (soidle_timer_left < soidle_time_critera ||
            ((int)soidle_timer_left) < 0) {
        reason = BY_TMR;
        goto soidle_out;
    }
#else
    gpt_get_cnt(GPT1, &soidle_timer_left);
    gpt_get_cmp(GPT1, &soidle_timer_cmp);
    if((soidle_timer_cmp-soidle_timer_left)<soidle_time_critera)
    {
        reason = BY_TMR;
        goto soidle_out;
    }
#endif


soidle_out:
    if (reason < NR_REASONS)
        soidle_block_cnt[cpu][reason]++;
    return reason;
}
void mcidle_before_wfi(int cpu)
{
#ifdef CONFIG_SMP
    int err = 0;

    unsigned int id = mcidle_gpt_percpu[cpu];

    mcidle_timer_left2[cpu] = localtimer_get_counter();

    free_gpt(id);
    err = request_gpt(id, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
                      0, NULL, GPT_NOAUTOEN);
    if (err) {
        idle_info("[%s]fail to request GPT4\n", __func__);
    }

    mcidle_timer_left2[cpu] = localtimer_get_counter();


    if(cpu!=0)//core1~n, avoid gpt clear by core0
    {
        if( mcidle_timer_left2[cpu] <=2600 ) //200us(todo)
        {
            if(mcidle_timer_left2[cpu]<=0)
                gpt_set_cmp(id, 1);//Trigger GPT4 Timerout imediately
            else
                gpt_set_cmp(id, mcidle_timer_left2[cpu]);

            spm_write(SPM_SLEEP_CPU_WAKEUP_EVENT,spm_read(SPM_SLEEP_CPU_WAKEUP_EVENT)|0x1);//spm wake up directly

        }
        else
            gpt_set_cmp(id, mcidle_timer_left2[cpu]);

        start_gpt(id);
    }
#else
    gpt_get_cnt(GPT1, &mcidle_timer_left2);
#endif
}
void soidle_after_wfi(bool sodi_en)
{
#ifdef CONFIG_SMP
    if (gpt_check_and_ack_irq(GPT4)) {
        localtimer_set_next_event(1);
    } else {
        /* waked up by other wakeup source */
        unsigned int cnt, cmp;
        gpt_get_cnt(GPT4, &cnt);
        gpt_get_cmp(GPT4, &cmp);
        if (unlikely(cmp < cnt)) {
            idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__,
                     GPT4 + 1, cnt, cmp);
            BUG();
        }
        localtimer_set_next_event(cmp-cnt);
        stop_gpt(GPT4);
        free_gpt(GPT4);
    }
#endif
    if(sodi_en)
        soidle_cnt[0]++;
}
void soidle_before_wfi(int cpu)
{
#ifdef CONFIG_SMP
	#if !defined(SODI_APxGPT_TimerCount) || (SODI_APxGPT_TimerCount == 0)
	soidle_timer_left2 = localtimer_get_counter();
	#else
	soidle_timer_left2 = 13000000*SODI_APxGPT_TimerCount;
	#endif

    if( (int)soidle_timer_left2 <=0 )
    {
        gpt_set_cmp(idle_gpt, 1);//Trigger idle_gpt Timerout imediately
    }
    else
    {
        gpt_set_cmp(idle_gpt, soidle_timer_left2);
    }

    start_gpt(idle_gpt);
#else
    gpt_get_cnt(GPT1, &soidle_timer_left2);
#endif

}
wake_reason_t spm_go_to_dpidle(u32 spm_flags, u32 spm_data)
{
    struct wake_status wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    struct pcm_desc *pcmdesc = __spm_dpidle.pcmdesc;
    struct pwr_ctrl *pwrctrl = __spm_dpidle.pwrctrl;

#if SPM_AEE_RR_REC
    aee_rr_rec_deepidle_val(1<<SPM_DEEPIDLE_ENTER);
#endif 

    set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
    
    //pwrctrl->timer_val = 1 * 32768;

    spm_dpidle_before_wfi();

    lockdep_off();
    spin_lock_irqsave(&__spm_lock, flags);    
    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(SPM_IRQ0_ID);
    mt_cirq_clone_gic();
    mt_cirq_enable();

#if SPM_AEE_RR_REC
    aee_rr_rec_deepidle_val(aee_rr_curr_deepidle_val()|(1<<SPM_DEEPIDLE_ENTER_UART_SLEEP));
#endif     

    if (request_uart_to_sleep()) {
        wr = WR_UART_BUSY;
        goto RESTORE_IRQ;
    }

    __spm_reset_and_init_pcm(pcmdesc);

    __spm_kick_im_to_fetch(pcmdesc);
	
    __spm_init_pcm_register();

    __spm_init_event_vector(pcmdesc);

    __spm_set_power_control(pwrctrl);

    __spm_set_wakeup_event(pwrctrl);

    spm_dpidle_pre_process();

    __spm_kick_pcm_to_run(pwrctrl);

#if SPM_AEE_RR_REC
    aee_rr_rec_deepidle_val(aee_rr_curr_deepidle_val()|(1<<SPM_DEEPIDLE_ENTER_WFI));
#endif

#ifdef SPM_DEEPIDLE_PROFILE_TIME
    gpt_get_cnt(SPM_PROFILE_APXGPT,&dpidle_profile[1]);
#endif   
    spm_trigger_wfi_for_dpidle(pwrctrl);
#ifdef SPM_DEEPIDLE_PROFILE_TIME
    gpt_get_cnt(SPM_PROFILE_APXGPT,&dpidle_profile[2]);
#endif

#if SPM_AEE_RR_REC
    aee_rr_rec_deepidle_val(aee_rr_curr_deepidle_val()|(1<<SPM_DEEPIDLE_LEAVE_WFI));
#endif 

    spm_dpidle_post_process();

    __spm_get_wakeup_status(&wakesta);

    __spm_clean_after_wakeup();

#if SPM_AEE_RR_REC
    aee_rr_rec_deepidle_val(aee_rr_curr_deepidle_val()|(1<<SPM_DEEPIDLE_ENTER_UART_AWAKE));
#endif

    request_uart_to_wakeup();

    wr = __spm_output_wake_reason(&wakesta, pcmdesc, false);

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);  
    spin_unlock_irqrestore(&__spm_lock, flags);
    lockdep_on();
    spm_dpidle_after_wfi();

#if SPM_AEE_RR_REC
    aee_rr_rec_deepidle_val(0);
#endif 
    return wr;
}
static bool dpidle_can_enter(void)
{

    int reason = NR_REASONS;
    int i;
    unsigned long long dpidle_block_curr_time = 0;
#ifdef SPM_MCDI_FUNC
    if (En_SPM_MCDI != 0) {
        reason = BY_OTH;
        goto out;
    }
#endif

#ifdef CONFIG_SMP
    if ((atomic_read(&is_in_hotplug) == 1)||(atomic_read(&hotplug_cpu_count) != 1)) {
        reason = BY_CPU;
        goto out;
    }
#endif


    memset(dpidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
    if (!clkmgr_idle_can_enter(dpidle_condition_mask, dpidle_block_mask)) {
        reason = BY_CLK;
        goto out;
    }

#ifdef CONFIG_SMP
    dpidle_timer_left = localtimer_get_counter();
    if (dpidle_timer_left < dpidle_time_critera ||
            ((int)dpidle_timer_left) < 0) {
        reason = BY_TMR;
        goto out;
    }
#else
    gpt_get_cnt(GPT1, &dpidle_timer_left);
    gpt_get_cmp(GPT1, &dpidle_timer_cmp);
    if((dpidle_timer_cmp-dpidle_timer_left)<dpidle_time_critera)
    {
        reason = BY_TMR;
        goto out;
    }
#endif


out:
    if (reason < NR_REASONS) {
        if( dpidle_block_prev_time == 0 )
            dpidle_block_prev_time = idle_get_current_time_ms();

        dpidle_block_curr_time = idle_get_current_time_ms();
        if((dpidle_block_curr_time - dpidle_block_prev_time) > dpidle_block_time_critera)
        {
            if ((smp_processor_id() == 0))
            {
                for (i = 0; i < nr_cpu_ids; i++) {
                    idle_ver("dpidle_cnt[%d]=%lu, rgidle_cnt[%d]=%lu\n",
                             i, dpidle_cnt[i], i, rgidle_cnt[i]);
                }

                for (i = 0; i < NR_REASONS; i++) {
                    idle_ver("[%d]dpidle_block_cnt[%s]=%lu\n", i, reason_name[i],
                             dpidle_block_cnt[i]);
                }

                for (i = 0; i < NR_GRPS; i++) {
                    idle_ver("[%02d]dpidle_condition_mask[%-8s]=0x%08x\t\t"
                             "dpidle_block_mask[%-8s]=0x%08x\n", i,
                             grp_get_name(i), dpidle_condition_mask[i],
                             grp_get_name(i), dpidle_block_mask[i]);
                }

                //printk("dpidle_block_prev_time =%lu, dpidle_block_curr_time = %lu\n",dpidle_block_prev_time,dpidle_block_curr_time);

                memset(dpidle_block_cnt, 0, sizeof(dpidle_block_cnt));
                dpidle_block_prev_time = idle_get_current_time_ms();

            }


        }
        dpidle_block_cnt[reason]++;
        return false;
    } else {
        dpidle_block_prev_time = idle_get_current_time_ms();
        return true;
    }

}
void spm_go_to_sodi(u32 spm_flags, u32 spm_data)
{
    struct wake_status wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    struct pcm_desc *pcmdesc = __spm_sodi.pcmdesc;
    struct pwr_ctrl *pwrctrl = __spm_sodi.pwrctrl;
    int vcore_status = 0; //0:disable, 1:HPM, 2:LPM

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(1<<SPM_SODI_ENTER);
#endif

#if defined (CONFIG_ARM_PSCI)||defined(CONFIG_MTK_PSCI)
    spm_flags &= ~SPM_DISABLE_ATF_ABORT;
#else
    spm_flags |= SPM_DISABLE_ATF_ABORT;
#endif

	if(gSpm_SODI_mempll_pwr_mode == 1)
	{
		spm_flags |= SPM_MEMPLL_CG_EN; //MEMPLL CG mode
	}
	else
	{
		spm_flags &= ~SPM_MEMPLL_CG_EN; //DDRPHY power down mode
	}

    set_pwrctrl_pcm_flags(pwrctrl, spm_flags);

    //If Vcore DVFS is disable, force to disable SODI internal Vcore DVS
    if (pwrctrl->pcm_flags_cust == 0)
    {
        if ((pwrctrl->pcm_flags & SPM_VCORE_DVFS_EN) == 0) 
        {
            pwrctrl->pcm_flags |= SPM_VCORE_DVS_EVENT_DIS;
        }
    }

    //SODI will not decrease Vcore voltage in HPM mode.
    if ((pwrctrl->pcm_flags & SPM_VCORE_DVS_EVENT_DIS) == 0)
    {
        if (get_ddr_khz() != FDDR_S1_KHZ)
        {
		#if SPM_AEE_RR_REC
		aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_VCORE_HPM));
		#endif 
/*            	//modify by mtk
		//if DRAM freq is high,SPM will not enter event_vector to enter EMI self-refresh
		if(pwrctrl->pcm_flags_cust == 0)
		{
			pwrctrl->pcm_flags|=0x80;		
		}
*/
            	vcore_status = 1;
            	//printk("SODI: get_ddr_khz() = %d\n", get_ddr_khz());
        }
        else
        {
			#if SPM_AEE_RR_REC
            aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_VCORE_LPM));
			#endif            
            
            vcore_status = 2;
        }
    }

    //enable APxGPT timer
	soidle_before_wfi(0);

	lockdep_off();
    spin_lock_irqsave(&__spm_lock, flags);

    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(SPM_IRQ0_ID);
    mt_cirq_clone_gic();
    mt_cirq_enable();

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_ENTER_UART_SLEEP));
#endif     

    if (request_uart_to_sleep()) {
        wr = WR_UART_BUSY;
        goto RESTORE_IRQ;
    }
    
#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_ENTER_SPM_FLOW));
#endif

    __spm_reset_and_init_pcm(pcmdesc);

	/*
	 * When commond-queue is in shut-down mode, SPM will hang if it tries to access commond-queue status.
     * Follwoing patch is to let SODI driver to notify SPM that commond-queue is in shut-down mode or not to avoid above SPM hang issue.
     * But, now display can automatically notify SPM that command-queue is shut-down or not, so following code is not needed anymore.
	 */
	#if 0
    //check GCE
	if(clock_is_on(MT_CG_INFRA_GCE))
	{
		pwrctrl->pcm_flags &= ~SPM_DDR_HIGH_SPEED;
	}
	else
	{
		pwrctrl->pcm_flags |= SPM_DDR_HIGH_SPEED;
	}
	#endif

    __spm_kick_im_to_fetch(pcmdesc);

    __spm_init_pcm_register();

    __spm_init_event_vector(pcmdesc);

#if 0 //In D2, can not set apsrc_req bit in SODI. It is used by Vcore DVS for GPU 550M in HPM mode
    //Display set SPM_PCM_SRC_REQ[0]=1'b1 to force DRAM not enter self-refresh mode
   	if((spm_read(SPM_PCM_SRC_REQ)&0x00000001))
    {
    	pwrctrl->pcm_apsrc_req = 1;
    }
    else
    {
    	pwrctrl->pcm_apsrc_req = 0;
    }
#endif

    __spm_set_power_control(pwrctrl);

    __spm_set_wakeup_event(pwrctrl);

#if SODI_DVT_PCM_TIMER_DISABLE
	//PCM_Timer is enable in above '__spm_set_wakeup_event(pwrctrl);', disable PCM Timer here
	spm_write(SPM_PCM_CON1 ,spm_read(SPM_PCM_CON1)&(~CON1_PCM_TIMER_EN));
#endif

    spm_sodi_pre_process();

    __spm_kick_pcm_to_run(pwrctrl);

#if SPM_SODI_DUMP_REGS
    printk("============SODI Before============\n");
    spm_sodi_dump_regs(); //dump debug info
#endif

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_ENTER_WFI));
#endif

#ifdef SPM_SODI_PROFILE_TIME
    gpt_get_cnt(SPM_SODI_PROFILE_APXGPT,&soidle_profile[1]);
#endif

    spm_trigger_wfi_for_sodi(pwrctrl);

#ifdef SPM_SODI_PROFILE_TIME
    gpt_get_cnt(SPM_SODI_PROFILE_APXGPT,&soidle_profile[2]);
#endif

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_LEAVE_WFI));
#endif

#if SPM_SODI_DUMP_REGS
    printk("============SODI After=============\n");
    spm_sodi_dump_regs();//dump debug info
#endif

    spm_sodi_post_process();

    __spm_get_wakeup_status(&wakesta);

    sodi_debug("emi-selfrefrsh cnt = %d, pcm_flag = 0x%x, SPM_PCM_RESERVE2 = 0x%x, vcore_status = %d, %s\n", 
                spm_read(SPM_PCM_PASR_DPD_3), spm_read(SPM_PCM_FLAGS), spm_read(SPM_PCM_RESERVE2), vcore_status, pcmdesc->version);

    __spm_clean_after_wakeup();

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_ENTER_UART_AWAKE));
#endif

    request_uart_to_wakeup();

    wr = __spm_output_wake_reason(&wakesta, pcmdesc, false);
    if (wr == WR_PCM_ASSERT)
    {
        sodi_err("PCM ASSERT AT %u (%s), r13 = 0x%x, debug_flag = 0x%x\n", wakesta.assert_pc, pcmdesc->version, wakesta.r13, wakesta.debug_flag);
    }

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_LEAVE_SPM_FLOW));
#endif

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);

    spin_unlock_irqrestore(&__spm_lock, flags);
    lockdep_on();

    //stop APxGPT timer and enable caore0 local timer
    soidle_after_wfi(0);

#if SODI_DVT_SPM_MEM_RW_TEST
    {
        static u32 magic_init = 0;
        int i =0;

        if(magic_init == 0){
		    magic_init++;
		    printk("magicNumArray:0x%p",magicArray);
	    }

    	for(i=0;i<16;i++)
    	{
    		if(magicArray[i]!=SODI_DVT_MAGIC_NUM)
    		{
    			printk("Error: sodi magic number no match!!!");
    			ASSERT(0);
    		}
    	}

    	if (i>=16)
    	    printk("SODI_DVT_SPM_MEM_RW_TEST pass (count = %d)\n", magic_init);
    }
#endif

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(0);
#endif
}
bool soidle_can_enter(int cpu)
{
    int reason = NR_REASONS;
    unsigned long long soidle_block_curr_time = 0;

#ifdef CONFIG_SMP
    if ((atomic_read(&is_in_hotplug) == 1)||(num_online_cpus() != 1)) {
        reason = BY_CPU;
        goto out;
    }
#endif

    if(idle_spm_lock){
        reason = BY_VTG;
        goto out;
    }

#if !defined(SODI_DISPLAY_DRV_CHK_DIS) || (SODI_DISPLAY_DRV_CHK_DIS == 0)
    // decide when to enable SODI by display driver
    if(spm_get_sodi_en()==0){
        reason = BY_OTH;
        goto out;
	}
#endif

    if (soidle_by_pass_cg == 0) {
        memset(soidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
        if (!clkmgr_idle_can_enter(soidle_condition_mask, soidle_block_mask)) {
#if !defined(SODI_CG_CHK_DIS) || (SODI_CG_CHK_DIS == 0)
            reason = BY_CLK;
            goto out;
#endif
        }
    }

#ifdef CONFIG_SMP
    soidle_timer_left = localtimer_get_counter();
    if ((int)soidle_timer_left < soidle_time_critera ||
            ((int)soidle_timer_left) < 0) {
        reason = BY_TMR;
        goto out;
    }
#else
    gpt_get_cnt(GPT1, &soidle_timer_left);
    gpt_get_cmp(GPT1, &soidle_timer_cmp);
    if((soidle_timer_cmp-soidle_timer_left)<soidle_time_critera)
    {
        reason = BY_TMR;
        goto out;
    }
#endif

out:
    if (reason < NR_REASONS) {
        if( soidle_block_prev_time == 0 )
            soidle_block_prev_time = idle_get_current_time_ms();

        soidle_block_curr_time = idle_get_current_time_ms();
        if((soidle_block_curr_time - soidle_block_prev_time) > soidle_block_time_critera)
        {
            if ((smp_processor_id() == 0))
            {
                int i = 0;

                for (i = 0; i < nr_cpu_ids; i++) {
                    idle_ver("soidle_cnt[%d]=%lu, rgidle_cnt[%d]=%lu\n",
                            i, soidle_cnt[i], i, rgidle_cnt[i]);
                }

                for (i = 0; i < NR_REASONS; i++) {
                    idle_ver("[%d]soidle_block_cnt[0][%s]=%lu\n", i, reason_name[i],
                            soidle_block_cnt[0][i]);
                }

                for (i = 0; i < NR_GRPS; i++) {
                    idle_ver("[%02d]soidle_condition_mask[%-8s]=0x%08x\t\t"
                            "soidle_block_mask[%-8s]=0x%08x\n", i,
                            grp_get_name(i), soidle_condition_mask[i],
                            grp_get_name(i), soidle_block_mask[i]);
                }

                memset(soidle_block_cnt, 0, sizeof(soidle_block_cnt));
                soidle_block_prev_time = idle_get_current_time_ms();
            }
        }

        soidle_block_cnt[cpu][reason]++;
        return false;
    } else {
        soidle_block_prev_time = idle_get_current_time_ms();
        return true;
    }
}
static bool dpidle_can_enter(void)
{
    int reason = NR_REASONS;
    int i = 0;
    unsigned long long dpidle_block_curr_time = 0;

    if(dpidle_by_pass_cg==0){
        if (!mt_cpufreq_earlysuspend_status_get()){
            reason = BY_VTG;
            goto out;
        }
    }

#ifdef CONFIG_SMP
    if ((atomic_read(&is_in_hotplug) >= 1)||(num_online_cpus() != 1)) {
        reason = BY_CPU;
        goto out;
    }
#endif

    if(idle_spm_lock){
        reason = BY_VTG;
        goto out;
    }

    if(dpidle_by_pass_cg==0){
	    memset(dpidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
	    if (!clkmgr_idle_can_enter(dpidle_condition_mask, dpidle_block_mask)) {
	        reason = BY_CLK;
	        goto out;
	    }
    }
#ifdef CONFIG_SMP
    dpidle_timer_left = localtimer_get_counter();
    if ((int)dpidle_timer_left < dpidle_time_critera ||
            ((int)dpidle_timer_left) < 0) {
        reason = BY_TMR;
        goto out;
    }
#else
    gpt_get_cnt(GPT1, &dpidle_timer_left);
    gpt_get_cmp(GPT1, &dpidle_timer_cmp);
    if((dpidle_timer_cmp-dpidle_timer_left)<dpidle_time_critera)
    {
        reason = BY_TMR;
        goto out;
    }
#endif

out:
    if (reason < NR_REASONS) {
        if( dpidle_block_prev_time == 0 )
            dpidle_block_prev_time = idle_get_current_time_ms();

        dpidle_block_curr_time = idle_get_current_time_ms();
        if((dpidle_block_curr_time - dpidle_block_prev_time) > dpidle_block_time_critera)
        {
            if ((smp_processor_id() == 0))
            {
                for (i = 0; i < nr_cpu_ids; i++) {
                    idle_ver("dpidle_cnt[%d]=%lu, rgidle_cnt[%d]=%lu\n",
                            i, dpidle_cnt[i], i, rgidle_cnt[i]);
                }

                for (i = 0; i < NR_REASONS; i++) {
                    idle_ver("[%d]dpidle_block_cnt[%s]=%lu\n", i, reason_name[i],
                            dpidle_block_cnt[i]);
                }

                for (i = 0; i < NR_GRPS; i++) {
                    idle_ver("[%02d]dpidle_condition_mask[%-8s]=0x%08x\t\t"
                            "dpidle_block_mask[%-8s]=0x%08x\n", i,
                            grp_get_name(i), dpidle_condition_mask[i],
                            grp_get_name(i), dpidle_block_mask[i]);
                }
                memset(dpidle_block_cnt, 0, sizeof(dpidle_block_cnt));
                dpidle_block_prev_time = idle_get_current_time_ms();

            }


        }
        dpidle_block_cnt[reason]++;
        return false;
    } else {
        dpidle_block_prev_time = idle_get_current_time_ms();
        return true;
    }

}