1 /* 2 * Copyright (c) 2025, Mediatek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <inttypes.h> 9 #include <stddef.h> 10 #include <stdint.h> 11 #include <stdio.h> 12 #include <string.h> 13 14 #include <common/debug.h> 15 #include <lib/mmio.h> 16 #include <plat/common/platform.h> 17 #include <platform_def.h> 18 19 #include <lib/pm/mtk_pm.h> 20 #include <lpm_v2/mt_lp_rqm.h> 21 #include <mt_spm.h> 22 #include <mt_spm_common.h> 23 #include <mt_spm_conservation.h> 24 #include <mt_spm_reg.h> 25 #include <mt_spm_vcorefs.h> 26 27 #define MT_RESUMETIME_THRESHOLD_MAX 5 28 #define IS_RESUME_OVERTIME(delta) \ 29 (delta > MT_RESUMETIME_THRESHOLD_MAX) 30 31 static struct wake_status spm_wakesta; /* Record last wakesta */ 32 static wake_reason_t spm_wake_reason = WR_NONE; 33 static struct resource_req_status generic_spm_resource_req = { 34 .id = MT_LP_RQ_ID_ALL_USAGE, 35 .val = 0, 36 }; 37 38 #define do_spm_init(pwrctrl) ({ int local_ret = 0; local_ret; }) 39 #define do_spm_run(pwrctrl) __spm_send_cpu_wakeup_event() 40 41 static int go_to_spm_before_wfi(int state_id, uint32_t ext_opand, 42 struct spm_lp_scen *spm_lp, 43 uint32_t resource_req) 44 { 45 int ret = 0; 46 struct pwr_ctrl *pwrctrl; 47 48 pwrctrl = spm_lp->pwrctrl; 49 50 #if SPM_FW_NO_RESUME == 0 51 ret = do_spm_init(pwrctrl); 52 53 if (ret) 54 return ret; 55 #endif 56 __spm_set_power_control(pwrctrl, resource_req); 57 __spm_set_wakeup_event(pwrctrl); 58 #if defined(CONFIG_MTK_VCOREDVFS_SUPPORT) 59 __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl); 60 #endif 61 if (mt_spm_version == MT_SPM_VERSION_ES) 62 pwrctrl->pcm_flags |= (SPM_FLAG_ENABLE_MT8196_E1_WA | 63 SPM_FLAG_ENABLE_MT8196_EMI_E1_WA); 64 65 #ifdef MTK_SPM_IVI_SUPPORT 66 pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_MT8196_IVI; 67 #endif 68 69 __spm_set_pcm_flags(pwrctrl); 70 71 #ifdef HW_S1_DETECT 72 if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) 73 spm_hw_s1_state_monitor_resume(); 74 #endif 75 do_spm_run(pwrctrl); 76 return ret; 77 } 78 79 static void go_to_spm_after_wfi(int state_id, uint32_t ext_opand, 80 struct spm_lp_scen *spm_lp, 81 struct wake_status **status) 82 { 83 uint32_t ext_status = 0; 84 85 spm_wakesta.tr.comm.resumetime = 0; 86 spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0; 87 88 if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) 89 spm_hw_s1_state_monitor_pause(&ext_status); 90 91 __spm_ext_int_wakeup_req_clr(); 92 93 __spm_get_wakeup_status(&spm_wakesta, ext_status); 94 95 if (status) 96 *status = &spm_wakesta; 97 98 #ifndef MT_SPM_COMMON_SODI_SUPPORT 99 __spm_clean_after_wakeup(); 100 #endif 101 spm_wake_reason = __spm_output_wake_reason(&spm_wakesta); 102 } 103 104 int spm_conservation(int state_id, uint32_t ext_opand, 105 struct spm_lp_scen *spm_lp, uint32_t resource_req) 106 { 107 uint32_t rc_state = resource_req; 108 109 if (!spm_lp) 110 return -1; 111 112 spm_lock_get(); 113 114 /* Uart bk/rs is needed if infra off for legacy project 115 * leave code here for reference. 116 */ 117 if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) { 118 #ifndef MTK_PLAT_SPM_UART_UNSUPPORT 119 /* Notify UART to sleep */ 120 mt_uart_save(); 121 #endif 122 } 123 124 if (!(ext_opand & MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ)) { 125 /* Resource request */ 126 mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE, 127 &generic_spm_resource_req); 128 rc_state |= generic_spm_resource_req.val; 129 } 130 go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state); 131 132 spm_lock_release(); 133 134 return 0; 135 } 136 137 void spm_conservation_finish(int state_id, uint32_t ext_opand, 138 struct spm_lp_scen *spm_lp, 139 struct wake_status **status) 140 { 141 /* Uart bk/rs is needed if infra off for legacy project 142 * leave code here for reference. 143 */ 144 if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) { 145 #ifndef MTK_PLAT_SPM_UART_UNSUPPORT 146 /* Notify UART to wakeup */ 147 mt_uart_restore(); 148 #endif 149 } 150 151 spm_lock_get(); 152 go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status); 153 #ifdef MT_SPM_COMMON_SODI_SUPPORT 154 /* Restore common sodi mask and resource req setting */ 155 mt_spm_set_common_sodi_pwrctr(); 156 mt_spm_set_common_sodi_pcm_flags(); 157 #endif 158 spm_lock_release(); 159 } 160 161 int spm_conservation_get_result(struct wake_status **res) 162 { 163 if (!res) 164 return -1; 165 *res = &spm_wakesta; 166 return 0; 167 } 168