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