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; #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) { //force to bypass Vcore DVS in SODI. //In D3, low level of Vcore is 1.15V, and it is enough for MD/CONN. //So, SODI doesn't need to do Vcore DVS pwrctrl->pcm_flags |= SPM_VCORE_DVS_EVENT_DIS; } //If SODI internal Vcore DVS is enabled, DRAM must be in low frequency if ((pwrctrl->pcm_flags & SPM_VCORE_DVS_EVENT_DIS) == 0) { if (get_ddr_khz() != FDDR_S1_KHZ) { sodi_debug("warning: get_ddr_khz() = %d\n", get_ddr_khz()); } } //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(); __spm_enable_i2c4_clk(); #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 //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, %s\n", spm_read(SPM_PCM_PASR_DPD_3), spm_read(SPM_PCM_FLAGS), spm_read(SPM_PCM_RESERVE2), 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 __spm_disable_i2c4_clk(); 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 }
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 /* Workaround: do NOT lower VPROC for turbo mode */ /* Workaround (2015.04.17): do NOT lower VPROC for FW v0.2.5 */ #if 0 if (is_ext_buck_exist()) #endif spm_flags |= SPM_CPU_DVS_DIS; 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(); __spm_enable_i2c4_clk(); #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); __spm_disable_i2c4_clk(); 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; }