/* * 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(); }
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; }
/* * 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; }