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