Exemple #1
0
/*
 * cpu_pdn:
 *    true  = CPU dormant
 *    false = CPU standby
 * pwrlevel:
 *    0 = AXI is off
 *    1 = AXI is 26M
 */
wake_reason_t spm_go_to_dpidle(bool cpu_pdn, u16 pwrlevel)
{
    wake_status_t wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    const pcm_desc_t *pcmdesc = &pcm_dpidle;
    const bool pcmwdt_en = false;

    spin_lock_irqsave(&spm_lock, flags);
    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(MT_SPM_IRQ_ID);
    mt_cirq_clone_gic();
    mt_cirq_enable();

    spm_reset_and_init_pcm();

    spm_kick_im_to_fetch(pcmdesc);

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

    spm_init_pcm_register();

    spm_init_event_vector(pcmdesc);

    spm_set_pwrctl_for_dpidle(pwrlevel);

    spm_set_wakeup_event(0, WAKE_SRC_FOR_DPIDLE);

    spm_kick_pcm_to_run(cpu_pdn, false, pcmwdt_en);     /* keep INFRA/DDRPHY power */

    spm_dpidle_before_wfi();

    spm_trigger_wfi_for_dpidle(cpu_pdn);

    spm_dpidle_after_wfi();

    spm_get_wakeup_status(&wakesta);

    spm_clean_after_wakeup(pcmwdt_en);

    wr = spm_output_wake_reason(&wakesta, true);

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);
    spin_unlock_irqrestore(&spm_lock, flags);

    return wr;
}
/*
 * go_to_sleep_after_wfi() - get wakeup reason after
 * leaving suspend scenario and clean up SPM settings
 */
static enum wake_reason_t go_to_sleep_after_wfi(void)
{
	struct wake_status wakesta;
	static enum wake_reason_t last_wr = WR_NONE;

	spm_get_wakeup_status(&wakesta);
	spm_clean_after_wakeup();
	last_wr = spm_output_wake_reason(&wakesta);

	return last_wr;
}
void spm_mcdi_wakeup_all_cores(void)
{
	if (is_mcdi_ready() == 0)
		return;

	spm_mcdi_cpu_wake_up_event(1, 1);
	while (mmio_read_32(SPM_PCM_REG5_DATA) != PCM_MCDI_ALL_CORE_AWAKE)
		;
	spm_mcdi_cpu_wake_up_event(1, 0);
	while (mmio_read_32(SPM_PCM_REG5_DATA) != PCM_MCDI_OFFLOADED)
		;

	spm_clean_after_wakeup();
	clear_all_ready();
}
Exemple #4
0
wake_reason_t spm_go_to_sleep(void)
{
    wake_status_t *wakesta;
    unsigned long flags,i;
    struct mtk_irq_mask mask;
    static wake_reason_t last_wr = WR_NONE;

    if(pcm_config_suspend.reserved & SPM_SUSPEND_GET_FGUAGE)
        pcm_config_suspend.timer_val_ms = spm_get_wake_period(last_wr)*1000;
    
    mtk_wdt_suspend();

    spin_lock_irqsave(&spm_lock, flags);
    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(MT_SPM0_IRQ_ID);

    if (spm_init_pcm(&pcm_config_suspend)==false)
        goto RESTORE_IRQ;

    spm_kick_pcm(&pcm_config_suspend);

    snapshot_golden_setting(__FUNCTION__, __LINE__);
    spm_trigger_wfi(&pcm_config_suspend);
    
    wakesta = spm_get_wakeup_status(&pcm_config_suspend);
    
    last_wr = wakesta->wake_reason;

    spm_clean_after_wakeup();
    
 RESTORE_IRQ:
    mt_irq_mask_restore(&mask);
    spin_unlock_irqrestore(&spm_lock, flags);
   
    mtk_wdt_resume();
       
    return last_wr;
}
wake_reason_t spm_go_to_sleep(u32 spm_flags, u32 spm_data)
{
    u32 sec = 0;
    int wd_ret;
    struct wake_status wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    struct wd_api *wd_api;
    static wake_reason_t last_wr = WR_NONE;
    struct pcm_desc *pcmdesc = __spm_suspend.pcmdesc;
    struct pwr_ctrl *pwrctrl = __spm_suspend.pwrctrl;
    struct spm_lp_scen *lpscen;

    lpscen = spm_check_talking_get_lpscen(&__spm_suspend, &spm_flags);
    pcmdesc = lpscen->pcmdesc;
    pwrctrl = lpscen->pwrctrl;

    set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
    set_pwrctrl_pcm_data(pwrctrl, spm_data);

#if SPM_PWAKE_EN
    sec = spm_get_wake_period(-1 /* FIXME */, last_wr);
#endif
    pwrctrl->timer_val = sec * 32768;

    wd_ret = get_wd_api(&wd_api);
    if (!wd_ret)
        wd_api->wd_suspend_notify();

    spm_suspend_pre_process(pwrctrl);

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

    spm_set_sysclk_settle();

    spm_crit2("sec = %u, wakesrc = 0x%x (%u)(%u)\n",
              sec, pwrctrl->wake_src, is_cpu_pdn(pwrctrl->pcm_flags), is_infra_pdn(pwrctrl->pcm_flags));

    if (request_uart_to_sleep()) {
        last_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_kick_pcm_to_run(pwrctrl);

#if 0
    if (1 == spm_snapshot_golden_setting)
    {
        snapshot_golden_setting(__FUNCTION__, __LINE__);
        spm_snapshot_golden_setting = 2;
    }
#endif

    spm_trigger_wfi_for_sleep(pwrctrl);

    __spm_get_wakeup_status(&wakesta);

    spm_clean_after_wakeup();

    request_uart_to_wakeup();

    last_wr = spm_output_wake_reason(&wakesta, pcmdesc);

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

    spm_suspend_post_process(pwrctrl);

    if (!wd_ret)
        wd_api->wd_resume_notify();

    return last_wr;
}
Exemple #6
0
/*
 * cpu_pdn:
 *    true  = CPU shutdown
 *    false = CPU standby
 * infra_pdn:
 *    true  = INFRA/DDRPHY power down
 *    false = keep INFRA/DDRPHY power
 * pwake_time:
 *    >= 0  = specific wakeup period
 */
wake_reason_t spm_go_to_sleep(bool cpu_pdn, bool infra_pdn, int pwake_time)
{
    u32 sec = 0;
    int wd_ret;
    wake_status_t wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    struct wd_api *wd_api;
    static wake_reason_t last_wr = WR_NONE;
    const pcm_desc_t *pcmdesc = &pcm_suspend;
    const bool pcmwdt_en = true;

#if SPM_PWAKE_EN
    sec = spm_get_wake_period(pwake_time, last_wr);
#endif

    wd_ret = get_wd_api(&wd_api);
    if (!wd_ret)
        wd_api->wd_suspend_notify();

    spin_lock_irqsave(&spm_lock, flags);
    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(MT_SPM_IRQ_ID);
    mt_cirq_clone_gic();
    mt_cirq_enable();

    spm_set_sysclk_settle();

    spm_crit2("sec = %u, wakesrc = 0x%x (%u)(%u)\n",
              sec, spm_sleep_wakesrc, cpu_pdn, infra_pdn);

    spm_reset_and_init_pcm();

    spm_kick_im_to_fetch(pcmdesc);

    if (spm_request_uart_to_sleep()) {
        last_wr = WR_UART_BUSY;
        goto RESTORE_IRQ;
    }

    spm_init_pcm_register();

    spm_init_event_vector(pcmdesc);

    spm_set_pwrctl_for_sleep();

    spm_set_wakeup_event(sec * 32768, spm_sleep_wakesrc);

    spm_kick_pcm_to_run(cpu_pdn, infra_pdn, pcmwdt_en);

    spm_trigger_wfi_for_sleep(cpu_pdn, infra_pdn);

    spm_get_wakeup_status(&wakesta);

    spm_clean_after_wakeup(pcmwdt_en);

    last_wr = spm_output_wake_reason(&wakesta, false);

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);
    spin_unlock_irqrestore(&spm_lock, flags);

    //spm_go_to_normal();   /* included in pcm_suspend */

    if (!wd_ret)
        wd_api->wd_resume_notify();

    return last_wr;
}
wake_reason_t spm_go_to_mcdi_ipi_test(int cpu)
{
    wake_status_t *wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    u32 con0;
    bool sodi_en = 0;

    spin_lock_irqsave(&spm_lock, flags);
    //mt_irq_mask_all(&mask);
    //mt_irq_unmask_for_sleep(MT_SPM0_IRQ_ID);       
    
    if(cpu==0)//except mcdi
    {
        mt_irq_mask_all(&mask);
        mt_irq_unmask_for_sleep(MT_SPM0_IRQ_ID);
        
        //spm_wdt_config(false);
        
        mt_cirq_clone_gic();
        mt_cirq_enable();
    }

    pcm_config_sodi.spm_request_uart_sleep = true;
    pcm_config_sodi.wake_src=WAKE_SRC_FOR_SODI;


    if((sodi_en==1)&&(cpu==0))//SODI
    {
        spm_direct_enable_sodi();
        pcm_config_sodi.wfi_sel[0]=true;
        pcm_config_sodi.wfi_sel[1]=true;        
        pcm_config_sodi.wfi_scu_mask=false;
        pcm_config_sodi.wfi_l2c_mask=false;

        
        spm_write(SPM_PCM_RESERVE,spm_read(SPM_PCM_RESERVE)&~0x1);
    }
    else if((sodi_en==0)&&(cpu==0))//CPU Dormant
    {
        pcm_config_sodi.wfi_sel[0]=true;
        pcm_config_sodi.wfi_sel[1]=true;    
        pcm_config_sodi.wfi_scu_mask=false;
        pcm_config_sodi.wfi_l2c_mask=false;        
        spm_direct_disable_sodi();
        spm_write(SPM_PCM_RESERVE,spm_read(SPM_PCM_RESERVE)&~0x1);
    }
    else if((sodi_en==0)&&(cpu!=0))//MCDI
    {
        //pcm_config_sodi.wake_src=WAKE_SRC_FOR_MCDI;
        pcm_config_sodi.wake_src=0x0;//for test IPI only
        pcm_config_sodi.wfi_sel[0]=false;
        pcm_config_sodi.wfi_sel[1]=true;
        pcm_config_sodi.wfi_scu_mask=true;
        pcm_config_sodi.wfi_l2c_mask=true;        
        pcm_config_sodi.spm_request_uart_sleep = false;
        spm_direct_disable_sodi();
        spm_write(SPM_PCM_RESERVE,spm_read(SPM_PCM_RESERVE)|0x1);
    }
    else
    {
        printk("[SPM]Wrong para!!\n");
        goto RESTORE_IRQ;
    }

    if( spm_last_senario != pcm_config_sodi.scenario)//MCDI SPM Initialize
    {
        //spm_direct_enable_sodi();
        if (spm_init_pcm(&pcm_config_sodi)==false)
            goto  RESTORE_IRQ;

        if(cpu==1)//except mcdi
        {
            spm_write(SPM_SLEEP_CPU_IRQ_MASK,0x2); 

        spm_mcdi_init_core_mux();
        }
        else
            spm_write(SPM_SLEEP_CPU_IRQ_MASK,0x1);


        spm_write(SPM_PCM_CON1,(spm_read(SPM_PCM_CON1)| CON1_CFG_KEY )&0xffffffdf);//temporary disable pcm timer
        
        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE0_WFI_SEL_SW_MASK );
        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE1_WFI_SEL_SW_MASK ); 


        spm_kick_pcm(&pcm_config_sodi);

        //spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE0_WFI_SEL_SW_MASK );
        //spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE1_WFI_SEL_SW_MASK );
        spm_change_fw = 1;
    }
    else
    {
        if(cpu==1)//except mcdi
        {
            spm_write(SPM_SLEEP_CPU_IRQ_MASK,0x2); 

            //spm_mcdi_init_core_mux();
        }
        else
            spm_write(SPM_SLEEP_CPU_IRQ_MASK,0x1);

        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE0_WFI_SEL_SW_MASK );
        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE1_WFI_SEL_SW_MASK );     
        if( spm_secondary_kick(&pcm_config_sodi)==false)
            goto RESTORE_IRQ;

        spm_change_fw = 0;
    }
   

    if(cpu==0)
    {
        soidle_before_wfi();

        spm_trigger_wfi_for_dpidle(1);//SODI with cpu dormant

        soidle_after_wfi(sodi_en);
    }
    else
    {
    spm_pre_SPM_PCM_SW_INT_SET=spm_read(SPM_PCM_SW_INT_SET);

    spm_pre_SPM_SLEEP_ISR_STATUS=spm_read(SPM_SLEEP_ISR_STATUS);
    spm_write(SPM_PCM_SW_INT_CLEAR,0xf);

        //mcidle_before_wfi(cpu);
        if (!cpu_power_down(DORMANT_MODE)) 
        {
            switch_to_amp();  
            
            /* do not add code here */
            wfi_with_sync();
        }
        switch_to_smp(); 
        cpu_check_dormant_abort();
        //mcidle_after_wfi(cpu);

    spm_post_SPM_PCM_SW_INT_SET=spm_read(SPM_PCM_SW_INT_SET);

    spm_post_SPM_SLEEP_ISR_STATUS=spm_read(SPM_SLEEP_ISR_STATUS);  
    spm_post_SPM_PCM_RESERVE = spm_read(SPM_PCM_RESERVE );
    } 

#if 1
    wakesta = spm_get_wakeup_status(&pcm_config_sodi);

    wr = wakesta->wake_reason;
#endif
    spm_clean_after_wakeup();

    spm_write(SPM_PCM_CON1,(spm_read(SPM_PCM_CON1)| CON1_CFG_KEY )|(CON1_PCM_TIMER_EN)); 

RESTORE_IRQ:
    if(cpu==0)//except mcdi
    {
        mt_cirq_flush();
        mt_cirq_disable();
        mt_irq_mask_restore(&mask);
    }

    //mt_irq_mask_restore(&mask);
    spin_unlock_irqrestore(&spm_lock, flags);
    return wr;

}
/*
    status
    RESERVED[0] :  mcusys dormant 
    RESERVED[1] :  APSRCSLEEP - (pass CHECK_APSRCWAKE)
    RESERVED[2] :  EMI self-refresh & mem ck off
     
    Options
    RESERVED[16] :  skip arm pll cg/pd 
    RESERVED[17] :  skip arm pll pd 
    RESERVED[18] :  skip AXI 26 SWITCH 
    RESERVED[19] :  skip EMI self-refresh & mem ck off                         
    RESERVED[20] :  skip mem ck off
                                                                    
    RESERVED[24] :  stop after cpu power down / cpu pll off
    RESERVED[25] :  stop after emi  down / mem ck off

*/
wake_reason_t spm_go_to_sodi(bool sodi_en,int cpu)
{
    wake_status_t *wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    u32 con0;

    spin_lock_irqsave(&spm_lock, flags);
    spm_stop_normal();    

    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(MT_SPM0_IRQ_ID);    
    mt_cirq_clone_gic();
    mt_cirq_enable();
    spm_direct_enable_sodi();

    spm_write(SPM_PCM_RESERVE,pcm_config_sodi.pcm_reserved);

#ifdef SPM_SODI_SECONDARY_KICK_IMPROVE
    if( spm_last_senario != pcm_config_sodi.scenario)//MCDI SPM Initialize
#endif
    {
        //spm_direct_enable_sodi();
        if (spm_init_pcm(&pcm_config_sodi)==false)
            goto  RESTORE_IRQ;
        
        spm_write(SPM_SLEEP_CPU_IRQ_MASK,0x1); 

        spm_write(SPM_PCM_CON1,(spm_read(SPM_PCM_CON1)| CON1_CFG_KEY )&0xffffffdf);//temporary disable pcm timer

        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE0_WFI_SEL_SW_MASK );
        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE1_WFI_SEL_SW_MASK ); 

        spm_kick_pcm(&pcm_config_sodi);

        spm_change_fw = 1;
    }
#ifdef SPM_SODI_SECONDARY_KICK_IMPROVE
    else
    {
        spm_write(SPM_SLEEP_CPU_IRQ_MASK,0x1);
        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE0_WFI_SEL_SW_MASK );
        spm_wfi_sel(pcm_config_sodi.wfi_sel, SPM_CORE1_WFI_SEL_SW_MASK ); 
        if( spm_secondary_kick(&pcm_config_sodi)==false)
            goto RESTORE_IRQ;

        spm_change_fw = 0;
    }
#endif    

    //gpiodbg_infra_dbg_out();//measure bus clock to LPD15
    soidle_before_wfi();

    spm_trigger_wfi_for_dpidle(1);//SODI with cpu dormant

    soidle_after_wfi(sodi_en);

    wakesta = spm_get_wakeup_status(&pcm_config_sodi);

    wr = wakesta->wake_reason;

    spm_clean_after_wakeup();
      
    spm_write(SPM_PCM_CON1,(spm_read(SPM_PCM_CON1)| CON1_CFG_KEY )|(CON1_PCM_TIMER_EN)); 

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);
    spm_go_to_normal();
    spin_unlock_irqrestore(&spm_lock, flags);
    return wr;

}
wake_reason_t spm_go_to_dpidle(bool cpu_pdn, u8 pwrlevel)
{
    wake_status_t *wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    u32 con0;
    u32 top_ckgen_val = 0;

    spin_lock_irqsave(&spm_lock, flags);
    spm_stop_normal();
    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(MT_SPM0_IRQ_ID);
    mt_cirq_clone_gic();
    mt_cirq_enable();

#ifdef SPM_DPIDLE_SECONDARY_KICK_IMPROVE
    if( spm_last_senario != pcm_config_dpidle.scenario)//dpidle SPM Initialize
#endif    
    {   
        if(pwrlevel>2) 
        {
            spm_crit2("Hey!! wrong PWR Level: %x",pwrlevel);//ASSERT Wrong Para!!
            goto RESTORE_IRQ;
        }
        pcm_config_dpidle.pcm_pwrlevel = 1 << pwrlevel ;
        pcm_config_dpidle.spm_request_uart_sleep = (pwrlevel == 0 ? true : false);
        pcm_config_dpidle.cpu_pdn = cpu_pdn;

        if (spm_init_pcm(&pcm_config_dpidle)==false)
            goto  RESTORE_IRQ;

#ifdef SPM_CLOCK_INIT
        enable_clock(MT_CG_MEMSLP_DLYER_SW_CG, "SPM_DPIDLE");
        enable_clock(MT_CG_SPM_SW_CG, "SPM_DPIDLE");
#endif

#ifdef SPM_DPIDLE_CLK_DBG_OUT
        //gpiodbg_monitor();
        gpiodbg_emi_dbg_out();
        gpiodbg_armcore_dbg_out();
#endif

        spm_kick_pcm(&pcm_config_dpidle);
        //spm_change_fw = 1;

    }
#ifdef SPM_DPIDLE_SECONDARY_KICK_IMPROVE    
    else       
    {
        if( spm_secondary_kick(&pcm_config_dpidle)==false)
            goto RESTORE_IRQ;

        //spm_change_fw = 0;
    }  
#endif     
        
    spm_dpidle_before_wfi();

    //hopping 33M-->fixed 26M, 20130902 HG.Wei
    top_ckgen_val = spm_read(TOPCKGEN_BASE);
    spm_write(TOPCKGEN_BASE,top_ckgen_val&(~(1<<26)));
        
    snapshot_golden_setting(__FUNCTION__, __LINE__);

    spm_trigger_wfi(&pcm_config_dpidle);

    //hopping fixed 26M-->hopping 33M, 20130902 HG.Wei
    spm_write(TOPCKGEN_BASE,top_ckgen_val);

    spm_dpidle_after_wfi();

    wakesta = spm_get_wakeup_status(&pcm_config_dpidle);

    wr = wakesta->wake_reason;

    spm_clean_after_wakeup();

#ifdef SPM_CLOCK_INIT
    disable_clock(MT_CG_SPM_SW_CG, "SPM_DPIDLE");
    disable_clock(MT_CG_MEMSLP_DLYER_SW_CG, "SPM_DPIDLE");
#endif

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);
    spm_go_to_normal();
    spin_unlock_irqrestore(&spm_lock, flags);
    return wr;
}