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