1 /* 2 * Copyright (c) 2023, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stddef.h> 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <common/debug.h> 13 #include <lib/mmio.h> 14 #include <plat/common/platform.h> 15 #include <lib/pm/mtk_pm.h> 16 #include <lpm/mt_lp_rqm.h> 17 #include "mt_spm.h" 18 #include "mt_spm_conservation.h" 19 #include "mt_spm_reg.h" 20 #include <platform_def.h> 21 22 #define INFRA_EMI_DCM_CFG0 U(0x10002028) 23 24 static struct wake_status spm_wakesta; /* record last wakesta */ 25 static wake_reason_t spm_wake_reason = WR_NONE; 26 static unsigned int emi_bak; 27 28 static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand, 29 struct spm_lp_scen *spm_lp, 30 unsigned int resource_req) 31 { 32 int ret = 0; 33 struct pwr_ctrl *pwrctrl; 34 unsigned int cpu = plat_my_core_pos(); 35 36 pwrctrl = spm_lp->pwrctrl; 37 38 /* EMI workaround */ 39 emi_bak = mmio_read_32(INFRA_EMI_DCM_CFG0) & BIT(22); 40 mmio_setbits_32(INFRA_EMI_DCM_CFG0, BIT(22)); 41 42 __spm_set_cpu_status(cpu); 43 __spm_set_power_control(pwrctrl); 44 __spm_set_wakeup_event(pwrctrl); 45 46 __spm_set_pcm_flags(pwrctrl); 47 48 __spm_src_req_update(pwrctrl, resource_req); 49 50 if ((ext_opand & MT_SPM_EX_OP_CLR_26M_RECORD) != 0U) { 51 __spm_clean_before_wfi(); 52 } 53 54 if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) { 55 __spm_set_pcm_wdt(1); 56 } 57 58 if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) { 59 spm_hw_s1_state_monitor_resume(); 60 } 61 62 __spm_send_cpu_wakeup_event(); 63 64 INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n", 65 cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE), 66 (mmio_read_32(PCM_TIMER_VAL) / 32768)); 67 INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n", 68 pwrctrl->pcm_flags, pwrctrl->pcm_flags1, 69 mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS), 70 mmio_read_32(PWR_STATUS_2ND)); 71 72 return ret; 73 } 74 75 static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand, 76 struct spm_lp_scen *spm_lp, 77 struct wake_status **status) 78 { 79 unsigned int ext_status = 0U; 80 81 if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) { 82 __spm_set_pcm_wdt(0); 83 } 84 85 if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) { 86 spm_hw_s1_state_monitor_pause(&ext_status); 87 } 88 89 __spm_ext_int_wakeup_req_clr(); 90 91 __spm_get_wakeup_status(&spm_wakesta, ext_status); 92 93 if (status != NULL) { 94 *status = &spm_wakesta; 95 } 96 97 __spm_clean_after_wakeup(); 98 spm_wake_reason = __spm_output_wake_reason(&spm_wakesta); 99 100 /* EMI workaround */ 101 if (emi_bak == 0U) { 102 mmio_clrbits_32(INFRA_EMI_DCM_CFG0, BIT(22)); 103 } 104 } 105 106 int spm_conservation(int state_id, unsigned int ext_opand, 107 struct spm_lp_scen *spm_lp, 108 unsigned int resource_req) 109 { 110 unsigned int rc_state = resource_req; 111 112 if (spm_lp == NULL) { 113 return -1; 114 } 115 116 spin_lock(&spm_lock); 117 go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state); 118 spin_unlock(&spm_lock); 119 120 return 0; 121 } 122 123 void spm_conservation_finish(int state_id, unsigned int ext_opand, struct spm_lp_scen *spm_lp, 124 struct wake_status **status) 125 { 126 spin_lock(&spm_lock); 127 go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status); 128 spin_unlock(&spm_lock); 129 } 130 131 int spm_conservation_get_result(struct wake_status **res) 132 { 133 if (res == NULL) { 134 return -1; 135 } 136 *res = &spm_wakesta; 137 return 0; 138 } 139