static void spm_trigger_wfi_for_sodi(struct pwr_ctrl *pwrctrl) { if (is_cpu_pdn(pwrctrl->pcm_flags)) { //sodi_debug("enter mt_cpu_dormant(CPU_SODI_MODE)\n"); mt_cpu_dormant(CPU_SODI_MODE); //sodi_debug("exit mt_cpu_dormant(CPU_SODI_MODE)\n"); } else { u32 val = 0; //backup MP0_AXI_CONFIG val = reg_read(MP0_AXI_CONFIG); //disable snoop function MCUSYS_SMC_WRITE(MP0_AXI_CONFIG, val | ACINACTM); sodi_debug("enter legacy WIFI, MP0_AXI_CONFIG=0x%x\n", reg_read(MP0_AXI_CONFIG)); //enter WFI wfi_with_sync(); //restore MP0_AXI_CONFIG MCUSYS_SMC_WRITE(MP0_AXI_CONFIG, val); sodi_debug("exit legacy WIFI, MP0_AXI_CONFIG=0x%x\n", reg_read(MP0_AXI_CONFIG)); } }
static void spm_trigger_wfi_for_sleep(struct pwr_ctrl *pwrctrl) { // sync_hw_gating_value(); /* for Vcore DVFS */ if (is_cpu_pdn(pwrctrl->pcm_flags)) { spm_dormant_sta = mt_cpu_dormant(CPU_SHUTDOWN_MODE/* | DORMANT_SKIP_WFI*/); switch (spm_dormant_sta) { case MT_CPU_DORMANT_RESET: break; case MT_CPU_DORMANT_ABORT: break; case MT_CPU_DORMANT_BREAK: break; case MT_CPU_DORMANT_BYPASS: break; } } else { spm_dormant_sta = -1; spm_write(CA7_BUS_CONFIG, spm_read(CA7_BUS_CONFIG) | 0x10); wfi_with_sync(); spm_write(CA7_BUS_CONFIG, spm_read(CA7_BUS_CONFIG) & ~0x10); } if (is_infra_pdn(pwrctrl->pcm_flags)) mtk_uart_restore(); }
static void spm_trigger_wfi_for_sleep(struct pwr_ctrl *pwrctrl) { //FIXME: for K2 fpga early porting #if 0 sync_hw_gating_value(); /* for Vcore DVFS */ #endif if (is_cpu_pdn(pwrctrl->pcm_flags)) { spm_dormant_sta = mt_cpu_dormant(CPU_SHUTDOWN_MODE/* | DORMANT_SKIP_WFI*/); switch (spm_dormant_sta) { case MT_CPU_DORMANT_RESET: break; case MT_CPU_DORMANT_ABORT: break; case MT_CPU_DORMANT_BREAK: break; case MT_CPU_DORMANT_BYPASS: break; } } else { spm_dormant_sta = -1; //spm_write(MP0_AXI_CONFIG, spm_read(MP0_AXI_CONFIG) | ACINACTM); wfi_with_sync(); // spm_write(MP0_AXI_CONFIG, spm_read(MP0_AXI_CONFIG) & ~ACINACTM); } if (is_infra_pdn(pwrctrl->pcm_flags)) mtk_uart_restore(); }
static void spm_trigger_wfi_for_dpidle(struct pwr_ctrl *pwrctrl) { if (is_cpu_pdn(pwrctrl->pcm_flags)) { mt_cpu_dormant(CPU_DEEPIDLE_MODE); } else { wfi_with_sync(); } }
static void spm_trigger_wfi_for_dpidle(struct pwr_ctrl *pwrctrl) { if (is_cpu_pdn(pwrctrl->pcm_flags)) { mt_cpu_dormant(CPU_DEEPIDLE_MODE); } else { //Mp0_axi_config[4] is one by default. No need to program it before entering suspend. wfi_with_sync(); } }
static int slp_suspend_ops_begin(suspend_state_t state) { /* legacy log */ slp_notice("@@@@@@@@@@@@@@@@@@@@\n"); slp_notice("Chip_pm_begin(%u)(%u)\n", is_cpu_pdn(slp_spm_flags), is_infra_pdn(slp_spm_flags)); slp_notice("@@@@@@@@@@@@@@@@@@@@\n"); slp_wake_reason = WR_NONE; return 0; }
static void spm_trigger_wfi_for_sodi(struct pwr_ctrl *pwrctrl) { //sync_hw_gating_value(); /* for Vcore DVFS */ if (is_cpu_pdn(pwrctrl->pcm_flags)) { mt_cpu_dormant(CPU_SODI_MODE); } else { // spm_write(CA7_BUS_CONFIG, spm_read(CA7_BUS_CONFIG) | 0x10); wfi_with_sync(); // spm_write(CA7_BUS_CONFIG, spm_read(CA7_BUS_CONFIG) & ~0x10); } }
static void spm_trigger_wfi_for_sodi(struct pwr_ctrl *pwrctrl) { if (is_cpu_pdn(pwrctrl->pcm_flags)) { //sodi_debug("enter mt_cpu_dormant(CPU_SODI_MODE)\n"); mt_cpu_dormant(CPU_SODI_MODE); //sodi_debug("exit mt_cpu_dormant(CPU_SODI_MODE)\n"); } else { sodi_debug("enter legacy WIFI\n"); //enter WFI wfi_with_sync(); sodi_debug("exit legacy WIFI\n"); } }
static void spm_trigger_wfi_for_dpidle(struct pwr_ctrl *pwrctrl) { //sync_hw_gating_value(); /* for Vcore DVFS */ #if 0 //deepidle no need, vproc(ext buck) can't set to 0v, because SRAM perpheral control from vproc spm_i2c_control(mt6333_BUSNUM, 1); #endif if (is_cpu_pdn(pwrctrl->pcm_flags)) { mt_cpu_dormant(CPU_DEEPIDLE_MODE); } else { wfi_with_sync(); } #if 0 //deepidle no need, vproc(ext buck) can't set to 0v, because SRAM perpheral control from vproc spm_i2c_control(mt6333_BUSNUM, 0); /* restore I2C1 power */ #endif }
/* * 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); }
static void spm_trigger_wfi_for_dpidle(struct pwr_ctrl *pwrctrl) { u32 v0, v1; if (is_cpu_pdn(pwrctrl->pcm_flags)) { mt_cpu_dormant(CPU_DEEPIDLE_MODE); } else { //Mp0_axi_config[4] is one by default. No need to program it before entering suspend. //backup MPx_AXI_CONFIG v0 = reg_read(MP0_AXI_CONFIG); v1 = reg_read(MP1_AXI_CONFIG); //disable snoop function MCUSYS_SMC_WRITE(MP0_AXI_CONFIG, v0 | ACINACTM); MCUSYS_SMC_WRITE(MP1_AXI_CONFIG, v1 | ACINACTM); wfi_with_sync(); //restore MP0_AXI_CONFIG MCUSYS_SMC_WRITE(MP0_AXI_CONFIG, v0); MCUSYS_SMC_WRITE(MP1_AXI_CONFIG, v1); } }
/* * cpu_pdn: * true = CPU dormant * false = CPU standby * pwrlevel: * 0 = AXI is off * 1 = AXI is 26M * pwake_time: * >= 0 = specific wakeup period */ wake_reason_t spm_go_to_sleep_dpidle(u32 spm_flags, u32 spm_data) { u32 sec = 0; u32 dpidle_timer_val = 0; u32 dpidle_wake_src = 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_dpidle.pcmdesc; struct pwr_ctrl *pwrctrl = __spm_dpidle.pwrctrl; /* backup original dpidle setting */ dpidle_timer_val = pwrctrl->timer_val; dpidle_wake_src = pwrctrl->wake_src; set_pwrctrl_pcm_flags(pwrctrl, spm_flags); #if SPM_PWAKE_EN sec = spm_get_wake_period(-1 /* FIXME */, last_wr); #endif pwrctrl->timer_val = sec * 32768; pwrctrl->wake_src = spm_get_sleep_wakesrc(); 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(SPM_IRQ0_ID); mt_cirq_clone_gic(); mt_cirq_enable(); /* set PMIC WRAP table for deepidle power control */ mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE); spm_crit2("sleep_deepidle, sec = %u, wakesrc = 0x%x [%u]\n", sec, pwrctrl->wake_src, is_cpu_pdn(pwrctrl->pcm_flags)); __spm_reset_and_init_pcm(pcmdesc); __spm_kick_im_to_fetch(pcmdesc); if (request_uart_to_sleep()) { last_wr = WR_UART_BUSY; goto RESTORE_IRQ; } __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); spm_dpidle_pre_process(); spm_trigger_wfi_for_dpidle(pwrctrl); spm_dpidle_post_process(); __spm_get_wakeup_status(&wakesta); __spm_clean_after_wakeup(); request_uart_to_wakeup(); last_wr = __spm_output_wake_reason(&wakesta, pcmdesc, true); RESTORE_IRQ: /* set PMIC WRAP table for normal power control */ mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL); mt_cirq_flush(); mt_cirq_disable(); mt_irq_mask_restore(&mask); spin_unlock_irqrestore(&__spm_lock, flags); if (!wd_ret) wd_api->wd_resume_notify(); /* restore original dpidle setting */ pwrctrl->timer_val = dpidle_timer_val; pwrctrl->wake_src = dpidle_wake_src; return last_wr; }
static int slp_suspend_ops_enter(suspend_state_t state) { int ret = 0; #ifdef CONFIG_MTK_TC1_FM_AT_SUSPEND int fm_radio_is_playing = 0; if ( ConditionEnterSuspend() == true ) fm_radio_is_playing = 0; else fm_radio_is_playing = 1; #endif /* CONFIG_MTK_TC1_FM_AT_SUSPEND */ #ifdef CONFIG_MTKPASR /* PASR SW operations */ enter_pasrdpd(); #endif /* legacy log */ slp_notice("@@@@@@@@@@@@@@@@@@@@\n"); slp_crit2("Chip_pm_enter\n"); slp_notice("@@@@@@@@@@@@@@@@@@@@\n"); //FIXME: for K2 bring up if (slp_dump_gpio) gpio_dump_regs(); #if 0 if (slp_dump_regs) slp_dump_pm_regs(); #endif if (slp_check_mtcmos_pll) slp_check_pm_mtcmos_pll(); if (!spm_cpusys0_can_power_down()) { slp_error("CANNOT SLEEP DUE TO CPU1~x PON, SPM_PWR_STATUS = 0x%x, SPM_PWR_STATUS_2ND = 0x%x\n", slp_read(SPM_PWR_STATUS), slp_read(SPM_PWR_STATUS_2ND)); //return -EPERM; ret = -EPERM; goto LEAVE_SLEEP; } if (is_infra_pdn(slp_spm_flags) && !is_cpu_pdn(slp_spm_flags)) { slp_error("CANNOT SLEEP DUE TO INFRA PDN BUT CPU PON\n"); //return -EPERM; ret = -EPERM; goto LEAVE_SLEEP; } /* only for test */ #if 0 slp_pasr_en(1, 0x0); slp_dpd_en(1); #endif #if SLP_SLEEP_DPIDLE_EN #ifdef CONFIG_MTK_TC1_FM_AT_SUSPEND if (slp_ck26m_on | fm_radio_is_playing) #else if (slp_ck26m_on) #endif slp_wake_reason = spm_go_to_sleep_dpidle(slp_spm_deepidle_flags, slp_spm_data); else #endif slp_wake_reason = spm_go_to_sleep(slp_spm_flags, slp_spm_data); LEAVE_SLEEP: #ifdef CONFIG_MTKPASR /* PASR SW operations */ leave_pasrdpd(); #endif #ifdef CONFIG_MTK_SYSTRACKER systracker_enable(); #endif return ret; }
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; }