145d50759SJames Liao /*
245d50759SJames Liao * Copyright (c) 2023, MediaTek Inc. All rights reserved.
345d50759SJames Liao *
445d50759SJames Liao * SPDX-License-Identifier: BSD-3-Clause
545d50759SJames Liao */
645d50759SJames Liao
745d50759SJames Liao #include <assert.h>
845d50759SJames Liao #include <stddef.h>
945d50759SJames Liao #include <stdio.h>
1045d50759SJames Liao #include <string.h>
1145d50759SJames Liao
1245d50759SJames Liao #include <common/debug.h>
1345d50759SJames Liao #include <lib/mmio.h>
1445d50759SJames Liao #include <plat/common/platform.h>
1545d50759SJames Liao #include <lib/pm/mtk_pm.h>
1645d50759SJames Liao #include <lpm/mt_lp_rqm.h>
1745d50759SJames Liao #include "mt_spm.h"
1845d50759SJames Liao #include "mt_spm_conservation.h"
1945d50759SJames Liao #include "mt_spm_reg.h"
2045d50759SJames Liao #include <platform_def.h>
2145d50759SJames Liao
2245d50759SJames Liao #define INFRA_EMI_DCM_CFG0 U(0x10002028)
2345d50759SJames Liao
2445d50759SJames Liao static struct wake_status spm_wakesta; /* record last wakesta */
2545d50759SJames Liao static wake_reason_t spm_wake_reason = WR_NONE;
2645d50759SJames Liao static unsigned int emi_bak;
2745d50759SJames Liao
go_to_spm_before_wfi(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,unsigned int resource_req)2845d50759SJames Liao static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
2945d50759SJames Liao struct spm_lp_scen *spm_lp,
3045d50759SJames Liao unsigned int resource_req)
3145d50759SJames Liao {
3245d50759SJames Liao int ret = 0;
3345d50759SJames Liao struct pwr_ctrl *pwrctrl;
3445d50759SJames Liao unsigned int cpu = plat_my_core_pos();
3545d50759SJames Liao
3645d50759SJames Liao pwrctrl = spm_lp->pwrctrl;
3745d50759SJames Liao
3845d50759SJames Liao /* EMI workaround */
3945d50759SJames Liao emi_bak = mmio_read_32(INFRA_EMI_DCM_CFG0) & BIT(22);
4045d50759SJames Liao mmio_setbits_32(INFRA_EMI_DCM_CFG0, BIT(22));
4145d50759SJames Liao
4245d50759SJames Liao __spm_set_cpu_status(cpu);
4345d50759SJames Liao __spm_set_power_control(pwrctrl);
4445d50759SJames Liao __spm_set_wakeup_event(pwrctrl);
4545d50759SJames Liao
4645d50759SJames Liao __spm_set_pcm_flags(pwrctrl);
4745d50759SJames Liao
4845d50759SJames Liao __spm_src_req_update(pwrctrl, resource_req);
4945d50759SJames Liao
5045d50759SJames Liao if ((ext_opand & MT_SPM_EX_OP_CLR_26M_RECORD) != 0U) {
5145d50759SJames Liao __spm_clean_before_wfi();
5245d50759SJames Liao }
5345d50759SJames Liao
5445d50759SJames Liao if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
5545d50759SJames Liao __spm_set_pcm_wdt(1);
5645d50759SJames Liao }
5745d50759SJames Liao
5845d50759SJames Liao if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
5945d50759SJames Liao spm_hw_s1_state_monitor_resume();
6045d50759SJames Liao }
6145d50759SJames Liao
6245d50759SJames Liao __spm_send_cpu_wakeup_event();
6345d50759SJames Liao
64*f85b34b1SJason Chen INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
65*f85b34b1SJason Chen cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
66*f85b34b1SJason Chen (mmio_read_32(PCM_TIMER_VAL) / 32768));
67*f85b34b1SJason Chen INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
68*f85b34b1SJason Chen pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
69*f85b34b1SJason Chen mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
70*f85b34b1SJason Chen mmio_read_32(PWR_STATUS_2ND));
71*f85b34b1SJason Chen
7245d50759SJames Liao return ret;
7345d50759SJames Liao }
7445d50759SJames Liao
go_to_spm_after_wfi(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)7545d50759SJames Liao static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
7645d50759SJames Liao struct spm_lp_scen *spm_lp,
7745d50759SJames Liao struct wake_status **status)
7845d50759SJames Liao {
7945d50759SJames Liao unsigned int ext_status = 0U;
8045d50759SJames Liao
8145d50759SJames Liao if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
8245d50759SJames Liao __spm_set_pcm_wdt(0);
8345d50759SJames Liao }
8445d50759SJames Liao
8545d50759SJames Liao if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
8645d50759SJames Liao spm_hw_s1_state_monitor_pause(&ext_status);
8745d50759SJames Liao }
8845d50759SJames Liao
8945d50759SJames Liao __spm_ext_int_wakeup_req_clr();
9045d50759SJames Liao
9145d50759SJames Liao __spm_get_wakeup_status(&spm_wakesta, ext_status);
9245d50759SJames Liao
9345d50759SJames Liao if (status != NULL) {
9445d50759SJames Liao *status = &spm_wakesta;
9545d50759SJames Liao }
9645d50759SJames Liao
9745d50759SJames Liao __spm_clean_after_wakeup();
9845d50759SJames Liao spm_wake_reason = __spm_output_wake_reason(&spm_wakesta);
9945d50759SJames Liao
10045d50759SJames Liao /* EMI workaround */
10145d50759SJames Liao if (emi_bak == 0U) {
10245d50759SJames Liao mmio_clrbits_32(INFRA_EMI_DCM_CFG0, BIT(22));
10345d50759SJames Liao }
10445d50759SJames Liao }
10545d50759SJames Liao
spm_conservation(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,unsigned int resource_req)10645d50759SJames Liao int spm_conservation(int state_id, unsigned int ext_opand,
10745d50759SJames Liao struct spm_lp_scen *spm_lp,
10845d50759SJames Liao unsigned int resource_req)
10945d50759SJames Liao {
11045d50759SJames Liao unsigned int rc_state = resource_req;
11145d50759SJames Liao
11245d50759SJames Liao if (spm_lp == NULL) {
11345d50759SJames Liao return -1;
11445d50759SJames Liao }
11545d50759SJames Liao
11645d50759SJames Liao spin_lock(&spm_lock);
11745d50759SJames Liao go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state);
11845d50759SJames Liao spin_unlock(&spm_lock);
11945d50759SJames Liao
12045d50759SJames Liao return 0;
12145d50759SJames Liao }
12245d50759SJames Liao
spm_conservation_finish(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)12345d50759SJames Liao void spm_conservation_finish(int state_id, unsigned int ext_opand, struct spm_lp_scen *spm_lp,
12445d50759SJames Liao struct wake_status **status)
12545d50759SJames Liao {
12645d50759SJames Liao spin_lock(&spm_lock);
12745d50759SJames Liao go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
12845d50759SJames Liao spin_unlock(&spm_lock);
12945d50759SJames Liao }
13045d50759SJames Liao
spm_conservation_get_result(struct wake_status ** res)13145d50759SJames Liao int spm_conservation_get_result(struct wake_status **res)
13245d50759SJames Liao {
13345d50759SJames Liao if (res == NULL) {
13445d50759SJames Liao return -1;
13545d50759SJames Liao }
13645d50759SJames Liao *res = &spm_wakesta;
13745d50759SJames Liao return 0;
13845d50759SJames Liao }
139