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 62 #ifdef MTK_SPM_IVI_SUPPORT 63 pwrctrl->pcm_flags |= SPM_FLAG_ENABLE_MT8196_IVI; 64 #endif 65 __spm_set_pcm_flags(pwrctrl); 66 67 #ifdef HW_S1_DETECT 68 if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) 69 spm_hw_s1_state_monitor_resume(); 70 #endif 71 do_spm_run(pwrctrl); 72 return ret; 73 } 74 75 static void go_to_spm_after_wfi(int state_id, uint32_t ext_opand, 76 struct spm_lp_scen *spm_lp, 77 struct wake_status **status) 78 { 79 uint32_t ext_status = 0; 80 81 spm_wakesta.tr.comm.resumetime = 0; 82 spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0; 83 84 if (ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) 85 spm_hw_s1_state_monitor_pause(&ext_status); 86 87 __spm_ext_int_wakeup_req_clr(); 88 89 __spm_get_wakeup_status(&spm_wakesta, ext_status); 90 91 if (status) 92 *status = &spm_wakesta; 93 94 #ifndef MT_SPM_COMMON_SODI_SUPPORT 95 __spm_clean_after_wakeup(); 96 #endif 97 spm_wake_reason = __spm_output_wake_reason(&spm_wakesta); 98 } 99 100 int spm_conservation(int state_id, uint32_t ext_opand, 101 struct spm_lp_scen *spm_lp, uint32_t resource_req) 102 { 103 uint32_t rc_state = resource_req; 104 105 if (!spm_lp) 106 return -1; 107 108 spm_lock_get(); 109 110 /* Uart bk/rs is needed if infra off for legacy project 111 * leave code here for reference. 112 */ 113 if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) { 114 #ifndef MTK_PLAT_SPM_UART_UNSUPPORT 115 /* Notify UART to sleep */ 116 mt_uart_save(); 117 #endif 118 } 119 120 if (!(ext_opand & MT_SPM_EX_OP_NON_GENERIC_RESOURCE_REQ)) { 121 /* Resource request */ 122 mt_lp_rq_get_status(PLAT_RQ_REQ_USAGE, 123 &generic_spm_resource_req); 124 rc_state |= generic_spm_resource_req.val; 125 } 126 go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state); 127 128 spm_lock_release(); 129 130 return 0; 131 } 132 133 void spm_conservation_finish(int state_id, uint32_t ext_opand, 134 struct spm_lp_scen *spm_lp, 135 struct wake_status **status) 136 { 137 /* Uart bk/rs is needed if infra off for legacy project 138 * leave code here for reference. 139 */ 140 if (ext_opand & MT_SPM_EX_OP_NOTIFY_INFRA_OFF) { 141 #ifndef MTK_PLAT_SPM_UART_UNSUPPORT 142 /* Notify UART to wakeup */ 143 mt_uart_restore(); 144 #endif 145 } 146 147 spm_lock_get(); 148 go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status); 149 #ifdef MT_SPM_COMMON_SODI_SUPPORT 150 /* Restore common sodi mask and resource req setting */ 151 mt_spm_set_common_sodi_pwrctr(); 152 mt_spm_set_common_sodi_pcm_flags(); 153 #endif 154 spm_lock_release(); 155 } 156 157 int spm_conservation_get_result(struct wake_status **res) 158 { 159 if (!res) 160 return -1; 161 *res = &spm_wakesta; 162 return 0; 163 } 164