/* * 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_before_wfi() - trigger SPM to enter suspend scenario */ static void go_to_sleep_before_wfi(const unsigned int spm_flags) { struct pwr_ctrl *pwrctrl; pwrctrl = &spm_ctrl; set_pwrctrl_pcm_flags(pwrctrl, spm_flags); spm_set_sysclk_settle(); INFO("sec = %u, wakesrc = 0x%x (%u)(%u)\n", pwrctrl->timer_val, pwrctrl->wake_src, is_cpu_pdn(pwrctrl->pcm_flags), is_infra_pdn(pwrctrl->pcm_flags)); spm_reset_and_init_pcm(); spm_init_pcm_register(); spm_set_power_control(pwrctrl); spm_set_wakeup_event(pwrctrl); spm_kick_pcm_to_run(pwrctrl); spm_init_event_vector(&suspend_pcm_ca7); spm_kick_im_to_fetch(&suspend_pcm_ca7); }
bool spm_init_pcm(SPM_PCM_CONFIG* pcm_config) { u32 timer_val,wdt_timer_val; bool wfi_sel[2] = {false,false}; pcm_config_curr = pcm_config; if(pcm_config->scenario == SPM_PCM_DEEP_IDLE) spm_crit2("%s with cpu_pdn=%d, pwr_level=%d, infra_pdn=%d\n",pcm_scenario[pcm_config->scenario],pcm_config->cpu_pdn,pcm_config->pcm_pwrlevel,pcm_config->infra_pdn); else spm_crit2("%s with cpu_pdn=%d, infra_pdn=%d\n",pcm_scenario[pcm_config->scenario],pcm_config->cpu_pdn,pcm_config->infra_pdn); //spm_crit2("spm_init_pcm():%s, timer_val: %d, wake_src:0x%X \n",pcm_scenario[pcm_config->scenario],pcm_config->timer_val_sec,pcm_config->wake_src); /* if(pcm_config->scenario == SPM_PCM_KERNEL_SUSPEND) pcm_config_curr->cpu_status = SHUTDOWN_MODE; else if(pcm_config->scenario == SPM_PCM_DEEP_IDLE) pcm_config_curr->cpu_status = DORMANT_MODE;*/ pcm_config->wakesta[pcm_config->wakesta_idx].wake_reason = WR_NONE ; spm_write(SPM_POWERON_CONFIG_SET, (SPM_PROJECT_CODE << 16) | (1U << 0)); //if pcm will turn on and off the 26Mhz, we need to setup the settle time if(pcm_config->spm_turn_off_26m) spm_set_sysclk_settle(); spm_reset_and_init_pcm(); /*init Instruction Memory*/ spm_kick_im_to_fetch(pcm_config->pcm_firmware_addr,pcm_config->pcm_firmware_len); if (pcm_config->spm_request_uart_sleep) if(spm_request_uart_to_sleep()){ return false; } /*init R0 ,R7*/ if(pcm_config->sync_r0r7) spm_init_pcm_register(); /*init VSRs*/ spm_init_event_vector(pcm_config->pcm_vsr); /*Setup pwr level if necessary*/ spm_set_ap_pwrctl(pcm_config->pcm_pwrlevel); if(pcm_config->scenario == SPM_PCM_MCDI) { /* set standby wfi */ spm_set_ap_standbywfi(pcm_config->md_mask, pcm_config->mm_mask, pcm_config->wfi_scu_mask, pcm_config->wfi_l2c_mask, pcm_config->wfi_op, wfi_sel); } else { /* set standby wfi */ spm_set_ap_standbywfi(pcm_config->md_mask, pcm_config->mm_mask, pcm_config->wfi_scu_mask, pcm_config->wfi_l2c_mask, pcm_config->wfi_op, pcm_config->wfi_sel); } timer_val= (unsigned int)((pcm_config->timer_val_ms * 32768)/1024);//In the unit of 32Khz wdt_timer_val = (unsigned int)((pcm_config->wdt_val_ms * 32768)/1024);//In the unit of 32Khz //spm_set_wakeup_event(pcm_config->timer_val_sec * 32768,pcm_config->wake_src); //if(pcm_config->scenario != SPM_PCM_WDT) spm_set_wakeup_event(timer_val,wdt_timer_val,pcm_config->wake_src); return true; }
/* * 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; }