1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2022, MediaTek Inc. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <common/debug.h> 8*91f16700Schasinglulu #include <lib/mmio.h> 9*91f16700Schasinglulu #include <plat/common/platform.h> 10*91f16700Schasinglulu #include <mt_spm.h> 11*91f16700Schasinglulu #include <mt_spm_conservation.h> 12*91f16700Schasinglulu #include <mt_spm_internal.h> 13*91f16700Schasinglulu #include <mt_spm_reg.h> 14*91f16700Schasinglulu #include <mt_spm_resource_req.h> 15*91f16700Schasinglulu #include <mt_spm_vcorefs.h> 16*91f16700Schasinglulu #include <plat_mtk_lpm.h> 17*91f16700Schasinglulu #include <plat_pm.h> 18*91f16700Schasinglulu #include <platform_def.h> 19*91f16700Schasinglulu 20*91f16700Schasinglulu #define MT_RESUMETIME_THRESHOLD_MAX (5U) /*ms*/ 21*91f16700Schasinglulu #define IS_RESUME_OVERTIME(delta) (delta > MT_RESUMETIME_THRESHOLD_MAX) 22*91f16700Schasinglulu 23*91f16700Schasinglulu static struct wake_status spm_wakesta; /* record last wakesta */ 24*91f16700Schasinglulu 25*91f16700Schasinglulu static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand, 26*91f16700Schasinglulu struct spm_lp_scen *spm_lp, 27*91f16700Schasinglulu unsigned int resource_req) 28*91f16700Schasinglulu { 29*91f16700Schasinglulu int ret = 0; 30*91f16700Schasinglulu struct pwr_ctrl *pwrctrl; 31*91f16700Schasinglulu uint32_t cpu = plat_my_core_pos(); 32*91f16700Schasinglulu 33*91f16700Schasinglulu pwrctrl = spm_lp->pwrctrl; 34*91f16700Schasinglulu 35*91f16700Schasinglulu __spm_set_cpu_status(cpu); 36*91f16700Schasinglulu __spm_set_power_control(pwrctrl); 37*91f16700Schasinglulu __spm_set_wakeup_event(pwrctrl); 38*91f16700Schasinglulu __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl); 39*91f16700Schasinglulu __spm_set_pcm_flags(pwrctrl); 40*91f16700Schasinglulu 41*91f16700Schasinglulu __spm_src_req_update(pwrctrl, resource_req); 42*91f16700Schasinglulu 43*91f16700Schasinglulu if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) { 44*91f16700Schasinglulu __spm_set_pcm_wdt(1); 45*91f16700Schasinglulu } 46*91f16700Schasinglulu 47*91f16700Schasinglulu if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) { 48*91f16700Schasinglulu __spm_xo_soc_bblpm(1); 49*91f16700Schasinglulu } 50*91f16700Schasinglulu 51*91f16700Schasinglulu if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) { 52*91f16700Schasinglulu spm_hw_s1_state_monitor_resume(); 53*91f16700Schasinglulu } 54*91f16700Schasinglulu 55*91f16700Schasinglulu /* Disable auto resume by PCM in system suspend stage */ 56*91f16700Schasinglulu if (IS_PLAT_SUSPEND_ID(state_id)) { 57*91f16700Schasinglulu __spm_disable_pcm_timer(); 58*91f16700Schasinglulu __spm_set_pcm_wdt(0); 59*91f16700Schasinglulu } 60*91f16700Schasinglulu 61*91f16700Schasinglulu __spm_send_cpu_wakeup_event(); 62*91f16700Schasinglulu 63*91f16700Schasinglulu INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n", 64*91f16700Schasinglulu cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE), 65*91f16700Schasinglulu (mmio_read_32(PCM_TIMER_VAL) / 32768)); 66*91f16700Schasinglulu INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n", 67*91f16700Schasinglulu pwrctrl->pcm_flags, pwrctrl->pcm_flags1, 68*91f16700Schasinglulu mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS), 69*91f16700Schasinglulu mmio_read_32(PWR_STATUS_2ND)); 70*91f16700Schasinglulu 71*91f16700Schasinglulu return ret; 72*91f16700Schasinglulu } 73*91f16700Schasinglulu 74*91f16700Schasinglulu static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand, 75*91f16700Schasinglulu struct spm_lp_scen *spm_lp, 76*91f16700Schasinglulu struct wake_status **status) 77*91f16700Schasinglulu { 78*91f16700Schasinglulu unsigned int ext_status = 0U; 79*91f16700Schasinglulu 80*91f16700Schasinglulu spm_wakesta.tr.comm.resumetime = 0; 81*91f16700Schasinglulu spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0; 82*91f16700Schasinglulu 83*91f16700Schasinglulu /* system watchdog will be resumed at kernel stage */ 84*91f16700Schasinglulu if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) { 85*91f16700Schasinglulu __spm_set_pcm_wdt(0); 86*91f16700Schasinglulu } 87*91f16700Schasinglulu 88*91f16700Schasinglulu if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) { 89*91f16700Schasinglulu __spm_xo_soc_bblpm(0); 90*91f16700Schasinglulu } 91*91f16700Schasinglulu 92*91f16700Schasinglulu if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) { 93*91f16700Schasinglulu spm_hw_s1_state_monitor_pause(&ext_status); 94*91f16700Schasinglulu } 95*91f16700Schasinglulu 96*91f16700Schasinglulu __spm_ext_int_wakeup_req_clr(); 97*91f16700Schasinglulu 98*91f16700Schasinglulu __spm_get_wakeup_status(&spm_wakesta, ext_status); 99*91f16700Schasinglulu 100*91f16700Schasinglulu if (status != NULL) { 101*91f16700Schasinglulu *status = &spm_wakesta; 102*91f16700Schasinglulu } 103*91f16700Schasinglulu 104*91f16700Schasinglulu __spm_clean_after_wakeup(); 105*91f16700Schasinglulu 106*91f16700Schasinglulu if (IS_PLAT_SUSPEND_ID(state_id)) { 107*91f16700Schasinglulu __spm_output_wake_reason(state_id, &spm_wakesta); 108*91f16700Schasinglulu } 109*91f16700Schasinglulu 110*91f16700Schasinglulu } 111*91f16700Schasinglulu 112*91f16700Schasinglulu int spm_conservation(int state_id, unsigned int ext_opand, 113*91f16700Schasinglulu struct spm_lp_scen *spm_lp, unsigned int resource_req) 114*91f16700Schasinglulu { 115*91f16700Schasinglulu int ret = 0; 116*91f16700Schasinglulu 117*91f16700Schasinglulu if (spm_lp == NULL) { 118*91f16700Schasinglulu ret = -1; 119*91f16700Schasinglulu } else { 120*91f16700Schasinglulu spm_lock_get(); 121*91f16700Schasinglulu go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req); 122*91f16700Schasinglulu spm_lock_release(); 123*91f16700Schasinglulu } 124*91f16700Schasinglulu 125*91f16700Schasinglulu return ret; 126*91f16700Schasinglulu } 127*91f16700Schasinglulu 128*91f16700Schasinglulu void spm_conservation_finish(int state_id, unsigned int ext_opand, 129*91f16700Schasinglulu struct spm_lp_scen *spm_lp, 130*91f16700Schasinglulu struct wake_status **status) 131*91f16700Schasinglulu { 132*91f16700Schasinglulu spm_lock_get(); 133*91f16700Schasinglulu go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status); 134*91f16700Schasinglulu spm_lock_release(); 135*91f16700Schasinglulu } 136*91f16700Schasinglulu 137*91f16700Schasinglulu int spm_conservation_get_result(struct wake_status **res) 138*91f16700Schasinglulu { 139*91f16700Schasinglulu int ret = 0; 140*91f16700Schasinglulu 141*91f16700Schasinglulu if (res == NULL) { 142*91f16700Schasinglulu ret = -1; 143*91f16700Schasinglulu } else { 144*91f16700Schasinglulu *res = &spm_wakesta; 145*91f16700Schasinglulu } 146*91f16700Schasinglulu return ret; 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu #define GPIO_BANK (GPIO_BASE + 0x6F0) 150*91f16700Schasinglulu #define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */ 151*91f16700Schasinglulu 152*91f16700Schasinglulu void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl) 153*91f16700Schasinglulu { 154*91f16700Schasinglulu if (pwrctrl != NULL) { 155*91f16700Schasinglulu /* For ufs, emmc storage type */ 156*91f16700Schasinglulu if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) { 157*91f16700Schasinglulu /* If eMMC is used, mask UFS req */ 158*91f16700Schasinglulu pwrctrl->reg_ufs_srcclkena_mask_b = 0; 159*91f16700Schasinglulu pwrctrl->reg_ufs_infra_req_mask_b = 0; 160*91f16700Schasinglulu pwrctrl->reg_ufs_apsrc_req_mask_b = 0; 161*91f16700Schasinglulu pwrctrl->reg_ufs_vrf18_req_mask_b = 0; 162*91f16700Schasinglulu pwrctrl->reg_ufs_ddren_req_mask_b = 0; 163*91f16700Schasinglulu } 164*91f16700Schasinglulu } 165*91f16700Schasinglulu } 166