static wake_reason_t spm_output_wake_reason(struct wake_status *wakesta, struct pcm_desc *pcmdesc) { wake_reason_t wr; wr = __spm_output_wake_reason(wakesta, pcmdesc, true); #if 1 memcpy(&suspend_info[log_wakesta_cnt], wakesta, sizeof(struct wake_status)); suspend_info[log_wakesta_cnt].log_index = log_wakesta_index; log_wakesta_cnt++; log_wakesta_index++; if (10 <= log_wakesta_cnt) { log_wakesta_cnt = 0; spm_snapshot_golden_setting = 0; } #if 0 else { if (2 != spm_snapshot_golden_setting) { if ((0x90100000 == wakesta->event_reg) && (0x140001f == wakesta->debug_flag)) spm_snapshot_golden_setting = 1; } } #endif if (0xFFFFFFF0 <= log_wakesta_index) log_wakesta_index = 0; #endif spm_crit2("big core = %d, suspend dormant state = %d, chip = %d\n", SPM_CTRL_BIG_CPU, spm_dormant_sta, mt_get_chip_sw_ver()); if (0 != spm_ap_mdsrc_req_cnt) spm_crit2("warning: spm_ap_mdsrc_req_cnt = %d, r7[ap_mdsrc_req] = 0x%x\n", spm_ap_mdsrc_req_cnt, spm_read(SPM_POWER_ON_VAL1) & (1<<17)); if (wakesta->r12 & WAKE_SRC_EINT) mt_eint_print_status(); if (wakesta->r12 & WAKE_SRC_CLDMA_MD) exec_ccci_kern_func_by_md_id(0, ID_GET_MD_WAKEUP_SRC, NULL, 0); return wr; }
void read_pcm_data(int *sram_data, int length) { int data_addr; if (length <= last_pc_size) { for (data_addr =0 ; data_addr < length; data_addr++) sram_data[data_addr] = pcm_im_read_data(last_pcm_sram_addr -data_addr); } else { spm_crit2("over size: %d\n", last_pc_size); } }
bool spm_check_wakeup_src(void) { u32 wakeup_src; /* check wanek event raw status */ wakeup_src = spm_read(SPM_SLEEP_ISR_RAW_STA); if (wakeup_src) { spm_crit2("WARNING: spm_check_wakeup_src = 0x%x", wakeup_src); return 1; } else return 0; }
static void spm_set_sysclk_settle(void) { u32 md_settle, settle; /* get MD SYSCLK settle */ spm_write(SPM_CLK_CON, spm_read(SPM_CLK_CON) | CC_SYSSETTLE_SEL); spm_write(SPM_CLK_SETTLE, 0); md_settle = spm_read(SPM_CLK_SETTLE); /* SYSCLK settle = MD SYSCLK settle but set it again for MD PDN */ spm_write(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE - md_settle); settle = spm_read(SPM_CLK_SETTLE); spm_crit2("md_settle = %u, settle = %u\n", md_settle, settle); }
static void spm_set_sysclk_settle(void) { u32 md_settle, settle; /* MD SYSCLK settle is from MD1 */ spm_write(SPM_CLK_CON, spm_read(SPM_CLK_CON) | CC_SYSSETTLE_SEL); /* get MD SYSCLK settle */ spm_write(SPM_CLK_SETTLE, 0); md_settle = spm_read(SPM_CLK_SETTLE); /* SYSCLK settle = MD SYSCLK settle but change it if needed */ #if SPM_AP_ONLY_SLEEP spm_write(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE - md_settle); #endif settle = spm_read(SPM_CLK_SETTLE); spm_crit2("md_settle = %u, settle = %u\n", md_settle, settle); }
static u32 spm_get_wake_period(int pwake_time, wake_reason_t last_wr) { int period = SPM_WAKE_PERIOD; if (pwake_time < 0) { /* use FG to get the period of 1% battery decrease */ period = get_dynamic_period(last_wr != WR_PCM_TIMER ? 1 : 0, SPM_WAKE_PERIOD, 1); if (period <= 0) { spm_warn("CANNOT GET PERIOD FROM FUEL GAUGE\n"); period = SPM_WAKE_PERIOD; } } else { period = pwake_time; spm_crit2("pwake = %d\n", pwake_time); } if (period > 36 * 3600) /* max period is 36.4 hours */ period = 36 * 3600; return period; }
/* * if in talking, modify @spm_flags based on @lpscen and return __spm_talking, * otherwise, do nothing and return @lpscen */ struct spm_lp_scen *spm_check_talking_get_lpscen(struct spm_lp_scen *lpscen, u32 *spm_flags) { if (can_enter_talking_dpidle()) { if (lpscen == &__spm_suspend) { *spm_flags &= ~SPM_CPU_DORMANT; spm_crit2("in talking\n"); } else { *spm_flags |= SPM_CPU_DORMANT; spm_debug("in talking\n"); } set_flags_for_mainpll(spm_flags); /* ANC needs MAINPLL on */ __spm_talking.pwrctrl->wake_src = lpscen->pwrctrl->wake_src; __spm_talking.pwrctrl->wake_src_md32 = lpscen->pwrctrl->wake_src_md32; lpscen = &__spm_talking; } return lpscen; }
/* static bool spm_set_suspend_pcm_ver(u32 *suspend_flags) { u32 flag; flag = *suspend_flags; if(mt_get_clk_mem_sel()==MEMPLL3PLL) { __spm_suspend.pcmdesc = &suspend_pcm_3pll; flag |= SPM_VCORE_DVS_DIS; } else if(mt_get_clk_mem_sel()==MEMPLL1PLL) { __spm_suspend.pcmdesc = &suspend_pcm_1pll; flag &= ~SPM_VCORE_DVS_DIS; } else return false; *suspend_flags = flag; return true; } */ static void spm_suspend_pre_process(struct pwr_ctrl *pwrctrl) { #if 0 u32 rdata1 = 0, rdata2 = 0; #endif /* set PMIC WRAP table for suspend power control */ mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_SUSPEND); spm_i2c_control(I2C_CHANNEL, 1); #if 0 /* for infra pdn (emi driving) */ spm_write(0xF0004000, spm_read(0xF0004000) | (1 << 24)); /* MEMPLL control for SPM */ spm_write(0xF000F5C8, 0x3010F030); spm_write(0xF000F5CC, 0x50101010); #endif //spm_write(0xF0001070 , spm_read(0xF0001070) | (1 << 21)); // 26:26 enable //spm_write(0xF0000204 , spm_read(0xF0000204) | (1 << 0)); // BUS 26MHz enable //spm_write(0xF0001108 , 0x0); #ifdef CONFIG_MD32_SUPPORT //spm_write(MD32_BASE+0x2C, (spm_read(MD32_BASE+0x2C) & ~0xFFFF) | 0xcafe); #endif #if 0 pwrap_read(0x2c2, &rdata1); pwrap_write(0x2c2, 0x0123); pwrap_read(0x2c2, &rdata2); if(rdata2 != 0x0123) { spm_crit2("suspend pmic wrapper 0x2c2, rdata1 = 0x%x, rdata2 = 0x%x\n", rdata1, rdata2); BUG(); } #endif }
static void spm_suspend_post_process(struct pwr_ctrl *pwrctrl) { #if 0 u32 rdata1 = 0, rdata2 = 0; pwrap_read(0x2c2, &rdata1); pwrap_write(0x2c2, 0x3210); pwrap_read(0x2c2, &rdata2); if(rdata2 != 0x3210) { spm_crit2("resume pmic wrapper 0x2c2, rdata1 = 0x%x, rdata2 = 0x%x\n", rdata1, rdata2); BUG(); } #endif #ifdef CONFIG_MD32_SUPPORT //spm_write(MD32_BASE+0x2C, spm_read(MD32_BASE+0x2C) & ~0xFFFF); #endif /* set PMIC WRAP table for normal power control */ mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL); spm_i2c_control(I2C_CHANNEL, 0); }
/* * 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 bool pcm_sysfs_write(const char *buf,unsigned long count) { char field[30]; int value; if(buf[0]=='0' && buf[1]=='x') sscanf(buf,"%x%s",&value,field); else sscanf(buf,"%d%s",&value,field); if(strcmp(field,"monitor_signal_0")==0) { if(value >= 0 && value < twam_signal_num) { pcm_fs_curr->monitor_signal[0]=value; } } else if(strcmp(field,"monitor_signal_1")==0) { if(value >= 0 && value < twam_signal_num) { pcm_fs_curr->monitor_signal[1]=value; } } else if(strcmp(field,"twam_log_en")==0) pcm_fs_curr->twam_log_en=value; else if(strcmp(field,"cpu_pdn")==0) { if(pcm_fs_curr->scenario == SPM_PCM_KERNEL_SUSPEND) pcm_fs_curr->cpu_pdn=value; else if(pcm_fs_curr->scenario == SPM_PCM_DEEP_IDLE) { if( value == 0 ) idle_state_en( IDLE_TYPE_DP , value );//dpidle disable else { pcm_fs_curr->cpu_pdn=(value-1); idle_state_en( IDLE_TYPE_DP , 1 );//dpidle enable } } } else if(strcmp(field,"infra_pdn")==0) pcm_fs_curr->infra_pdn=value; else if(strcmp(field,"timer_val_ms")==0) pcm_fs_curr->timer_val_ms=value; else if(strcmp(field,"wfi_sel0")==0) pcm_fs_curr->wfi_sel[0]=value; else if(strcmp(field,"wfi_sel1")==0) pcm_fs_curr->wfi_sel[1]=value; else if(strcmp(field,"wake_src")==0) { if(value == 0) { BUG_ON(pcm_wakesrc_backup[pcm_fs_curr->scenario]!=0);//you need to restore previous mask first pcm_wakesrc_backup[pcm_fs_curr->scenario] = spm_wakesrc_mask_all(pcm_fs_curr->scenario); } else if(value >= 0 && value < 32) spm_wakesrc_set(pcm_fs_curr->scenario,value); else if(value < 0 && value > -32) spm_wakesrc_clear(pcm_fs_curr->scenario,value* -1); else if(pcm_wakesrc_backup[pcm_fs_curr->scenario]!=0) { spm_wakesrc_restore(pcm_fs_curr->scenario,pcm_wakesrc_backup[pcm_fs_curr->scenario]); pcm_wakesrc_backup[pcm_fs_curr->scenario]=0; } } else if(strcmp(field,"md_mask")==0) { if(value >= 0 && value<=3) pcm_fs_curr->md_mask=value; } else if(strcmp(field,"mm_mask")==0) { if(value >= 0 && value<=3) pcm_fs_curr->mm_mask=value; } else if(strcmp(field,"reserved")==0) pcm_fs_curr->reserved=value; else if(strcmp(field,"pcm_reserved")==0) pcm_fs_curr->pcm_reserved=value; else { spm_crit2("spm_fs write FAIL: field = %s, value=%d\n",field,value); return false;//Can't not find field } spm_crit2("spm_fs write success: field = %s, value=%d\n",field,value); return true; }
void spm_ap_mdsrc_req(u8 set) { unsigned long flags; u32 i = 0; u32 md_sleep = 0; if (set) { spin_lock_irqsave(&__spm_lock, flags); if (spm_ap_mdsrc_req_cnt < 0) { spm_crit2("warning: set = %d, spm_ap_mdsrc_req_cnt = %d\n", set, spm_ap_mdsrc_req_cnt); //goto AP_MDSRC_REC_CNT_ERR; spin_unlock_irqrestore(&__spm_lock, flags); } else { spm_ap_mdsrc_req_cnt++; hw_spin_lock_for_ddrdfs(); spm_write(SPM_POWER_ON_VAL1, spm_read(SPM_POWER_ON_VAL1) | (1 << 17)); hw_spin_unlock_for_ddrdfs(); spin_unlock_irqrestore(&__spm_lock, flags); /* if md_apsrc_req = 1'b0, wait 26M settling time (3ms) */ if (0 == (spm_read(SPM_PCM_REG13_DATA) & R13_MD1_APSRC_REQ)) { md_sleep = 1; mdelay(3); } /* Check ap_mdsrc_ack = 1'b1 */ while(0 == (spm_read(SPM_PCM_REG13_DATA) & R13_AP_MD1SRC_ACK)) { if (10 > i++) { mdelay(1); } else { spm_crit2("WARNING: MD SLEEP = %d, spm_ap_mdsrc_req CAN NOT polling AP_MD1SRC_ACK\n", md_sleep); //goto AP_MDSRC_REC_CNT_ERR; break; } } } } else { spin_lock_irqsave(&__spm_lock, flags); spm_ap_mdsrc_req_cnt--; if (spm_ap_mdsrc_req_cnt < 0) { spm_crit2("warning: set = %d, spm_ap_mdsrc_req_cnt = %d\n", set, spm_ap_mdsrc_req_cnt); //goto AP_MDSRC_REC_CNT_ERR; } else { if (0 == spm_ap_mdsrc_req_cnt) { hw_spin_lock_for_ddrdfs(); spm_write(SPM_POWER_ON_VAL1, spm_read(SPM_POWER_ON_VAL1) & ~(1 << 17)); hw_spin_unlock_for_ddrdfs(); } } spin_unlock_irqrestore(&__spm_lock, flags); } //AP_MDSRC_REC_CNT_ERR: // spin_unlock_irqrestore(&__spm_lock, flags); }
static wake_reason_t spm_output_wake_reason(const wake_status_t *wakesta, bool dpidle) { char str[200] = { 0 }; wake_reason_t wr = WR_NONE; if (wakesta->debug_reg != 0) { spm_error2("PCM ASSERT AND PC = %u (0x%x)(0x%x)\n", wakesta->debug_reg, wakesta->r13, wakesta->event_reg); return WR_PCM_ASSERT; } if (dpidle) { /* bypass wakeup event check */ spm_info("[DP] r12 = 0x%x, r13 = 0x%x, r7 = 0x%x (0x%x)\n", wakesta->r12, wakesta->r13, spm_read(SPM_PCM_REG7_DATA), spm_read(SPM_POWER_ON_VAL1)); return WR_WAKE_SRC; } if (wakesta->r12 & (1U << 0)) { if (!(wakesta->isr & ISR_TWAM) && !wakesta->cpu_wake) { strcat(str, "PCM_TIMER "); wr = WR_PCM_TIMER; } else { if (wakesta->isr & ISR_TWAM) { strcat(str, "TWAM "); wr = WR_WAKE_SRC; } if (wakesta->cpu_wake) { strcat(str, "CPU "); wr = WR_WAKE_SRC; } } } if (wakesta->r12 & WAKE_SRC_TS) { strcat(str, "TS "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_KP) { strcat(str, "KP "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_WDT) { strcat(str, "WDT "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_GPT) { strcat(str, "GPT "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_EINT) { strcat(str, "EINT "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CONN_WDT) { strcat(str, "CONN_WDT "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CCIF_MD) { strcat(str, "CCIF_MD "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_LOW_BAT) { strcat(str, "LOW_BAT "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CONN) { strcat(str, "CONN "); wr = WR_WAKE_SRC; } if (wakesta->r12 & (1U << 13)) { strcat(str, "PCM_WDT "); wr = WR_PCM_WDT; } if (wakesta->r12 & WAKE_SRC_USB_CD) { strcat(str, "USB_CD "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_USB_PDN) { strcat(str, "USB_PDN "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_DBGSYS) { strcat(str, "DBGSYS "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_UART0) { strcat(str, "UART0 "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_AFE) { strcat(str, "AFE "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_THERM) { strcat(str, "THERM "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CIRQ) { strcat(str, "CIRQ "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_SYSPWREQ) { strcat(str, "SYSPWREQ "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_MD_WDT) { strcat(str, "MD_WDT "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CPU0_IRQ) { strcat(str, "CPU0_IRQ "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CPU1_IRQ) { strcat(str, "CPU1_IRQ "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CPU2_IRQ) { strcat(str, "CPU2_IRQ "); wr = WR_WAKE_SRC; } if (wakesta->r12 & WAKE_SRC_CPU3_IRQ) { strcat(str, "CPU3_IRQ "); wr = WR_WAKE_SRC; } if (wr == WR_NONE) { strcat(str, "UNKNOWN "); wr = WR_UNKNOWN; } spm_crit2("wake up by %s(0x%x)(0x%x)(%u)\n", str, wakesta->r12, wakesta->raw_sta, wakesta->timer_out); spm_crit2("event_reg = 0x%x, isr = 0x%x, r13 = 0x%x\n", wakesta->event_reg, wakesta->isr, wakesta->r13); if (wakesta->r12 & WAKE_SRC_EINT) mt_eint_print_status(); if (wakesta->r12 & WAKE_SRC_CCIF_MD) exec_ccci_kern_func_by_md_id(0, ID_GET_MD_WAKEUP_SRC, NULL, 0); return 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; }
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; }
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; }