1 /* 2 * Copyright (c) 2021, 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 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 <plat_mtk_lpm.h> 15 #include <plat_pm.h> 16 #include <plat/common/platform.h> 17 #include <platform_def.h> 18 19 struct wake_status spm_wakesta; /* record last wakesta */ 20 21 static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand, 22 struct spm_lp_scen *spm_lp, 23 unsigned int resource_req) 24 { 25 int ret = 0; 26 struct pwr_ctrl *pwrctrl; 27 uint32_t cpu = plat_my_core_pos(); 28 29 pwrctrl = spm_lp->pwrctrl; 30 31 __spm_set_cpu_status(cpu); 32 __spm_set_power_control(pwrctrl); 33 __spm_set_wakeup_event(pwrctrl); 34 __spm_set_pcm_flags(pwrctrl); 35 __spm_src_req_update(pwrctrl, resource_req); 36 37 if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) { 38 __spm_set_pcm_wdt(1); 39 } 40 41 if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) { 42 __spm_xo_soc_bblpm(1); 43 } 44 45 if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) { 46 spm_hw_s1_state_monitor_resume(); 47 } 48 49 /* Disable auto resume by PCM in system suspend stage */ 50 if (IS_PLAT_SUSPEND_ID(state_id)) { 51 __spm_disable_pcm_timer(); 52 __spm_set_pcm_wdt(0); 53 } 54 55 __spm_send_cpu_wakeup_event(); 56 57 INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n", 58 cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE), 59 mmio_read_32(PCM_TIMER_VAL) / 32768); 60 INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n", 61 pwrctrl->pcm_flags, pwrctrl->pcm_flags1, 62 mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS), 63 mmio_read_32(PWR_STATUS_2ND)); 64 INFO("cpu_pwr = 0x%x 0x%x\n", mmio_read_32(CPU_PWR_STATUS), 65 mmio_read_32(CPU_PWR_STATUS_2ND)); 66 67 return ret; 68 } 69 70 static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand, 71 struct spm_lp_scen *spm_lp, 72 struct wake_status **status) 73 { 74 unsigned int ext_status = 0U; 75 76 /* system watchdog will be resumed at kernel stage */ 77 if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) { 78 __spm_set_pcm_wdt(0); 79 } 80 81 if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) { 82 __spm_xo_soc_bblpm(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 __spm_get_wakeup_status(&spm_wakesta, ext_status); 91 92 if (status != NULL) { 93 *status = &spm_wakesta; 94 } 95 96 __spm_clean_after_wakeup(); 97 98 if (IS_PLAT_SUSPEND_ID(state_id)) { 99 __spm_output_wake_reason(state_id, &spm_wakesta); 100 } 101 } 102 103 int spm_conservation(int state_id, unsigned int ext_opand, 104 struct spm_lp_scen *spm_lp, unsigned int resource_req) 105 { 106 if (spm_lp == NULL) { 107 return -1; 108 } 109 110 spm_lock_get(); 111 go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req); 112 spm_lock_release(); 113 114 return 0; 115 } 116 117 void spm_conservation_finish(int state_id, unsigned int ext_opand, 118 struct spm_lp_scen *spm_lp, 119 struct wake_status **status) 120 { 121 spm_lock_get(); 122 go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status); 123 spm_lock_release(); 124 } 125 126 int spm_conservation_get_result(struct wake_status **res) 127 { 128 if (res == NULL) { 129 return -1; 130 } 131 132 *res = &spm_wakesta; 133 134 return 0; 135 } 136 137 #define GPIO_BANK (GPIO_BASE + 0x6F0) 138 #define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */ 139 140 void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl) 141 { 142 if (pwrctrl == NULL) { 143 return; 144 } 145 146 /* For ufs, emmc storage type */ 147 if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) { 148 /* If eMMC is used, mask UFS req */ 149 pwrctrl->reg_ufs_srcclkena_mask_b = 0; 150 pwrctrl->reg_ufs_infra_req_mask_b = 0; 151 pwrctrl->reg_ufs_apsrc_req_mask_b = 0; 152 pwrctrl->reg_ufs_vrf18_req_mask_b = 0; 153 pwrctrl->reg_ufs_ddr_en_mask_b = 0; 154 } 155 } 156