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 #include <mt_spm.h>
10 #include <mt_spm_conservation.h>
11 #include <mt_spm_internal.h>
12 #include <mt_spm_rc_internal.h>
13 #include <mt_spm_reg.h>
14 #include <mt_spm_resource_req.h>
15 #include <mt_spm_suspend.h>
16 #include <plat_pm.h>
17 #include <uart.h>
18 
19 #define SPM_SUSPEND_SLEEP_PCM_FLAG			\
20 	(SPM_FLAG_DISABLE_INFRA_PDN |			\
21 	 SPM_FLAG_DISABLE_VCORE_DVS |			\
22 	 SPM_FLAG_DISABLE_VCORE_DFS |			\
23 	 SPM_FLAG_KEEP_CSYSPWRACK_HIGH |		\
24 	 SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP |	\
25 	 SPM_FLAG_SRAM_SLEEP_CTRL)
26 
27 #define SPM_SUSPEND_SLEEP_PCM_FLAG1	0
28 
29 #define SPM_SUSPEND_PCM_FLAG				\
30 	(SPM_FLAG_DISABLE_VCORE_DVS |			\
31 	 SPM_FLAG_DISABLE_VCORE_DFS |			\
32 	 SPM_FLAG_ENABLE_TIA_WORKAROUND |		\
33 	 SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP |	\
34 	 SPM_FLAG_SRAM_SLEEP_CTRL)
35 
36 #define SPM_SUSPEND_PCM_FLAG1		0
37 
38 /* Suspend spm power control */
39 #define __WAKE_SRC_FOR_SUSPEND_COMMON__			\
40 	(R12_PCM_TIMER |				\
41 	 R12_KP_IRQ_B |					\
42 	 R12_APWDT_EVENT_B |				\
43 	 R12_CONN2AP_SPM_WAKEUP_B |			\
44 	 R12_EINT_EVENT_B |				\
45 	 R12_CONN_WDT_IRQ_B |				\
46 	 R12_CCIF0_EVENT_B |				\
47 	 R12_SSPM2SPM_WAKEUP_B |			\
48 	 R12_SCP2SPM_WAKEUP_B |				\
49 	 R12_ADSP2SPM_WAKEUP_B |			\
50 	 R12_USBX_CDSC_B |				\
51 	 R12_USBX_POWERDWN_B |				\
52 	 R12_SYS_TIMER_EVENT_B |			\
53 	 R12_EINT_EVENT_SECURE_B |			\
54 	 R12_SYS_CIRQ_IRQ_B |				\
55 	 R12_MD2AP_PEER_EVENT_B |			\
56 	 R12_MD1_WDT_B |				\
57 	 R12_CLDMA_EVENT_B |				\
58 	 R12_REG_CPU_WAKEUP |				\
59 	 R12_APUSYS_WAKE_HOST_B)
60 
61 #if defined(CFG_MICROTRUST_TEE_SUPPORT)
62 #define WAKE_SRC_FOR_SUSPEND (__WAKE_SRC_FOR_SUSPEND_COMMON__)
63 #else
64 #define WAKE_SRC_FOR_SUSPEND			\
65 	(__WAKE_SRC_FOR_SUSPEND_COMMON__ |	\
66 	 R12_SEJ_EVENT_B)
67 #endif
68 
69 static struct pwr_ctrl suspend_ctrl = {
70 	.wake_src = WAKE_SRC_FOR_SUSPEND,
71 
72 	/* SPM_AP_STANDBY_CON */
73 	/* [0] */
74 	.reg_wfi_op = 0,
75 	/* [1] */
76 	.reg_wfi_type = 0,
77 	/* [2] */
78 	.reg_mp0_cputop_idle_mask = 0,
79 	/* [3] */
80 	.reg_mp1_cputop_idle_mask = 0,
81 	/* [4] */
82 	.reg_mcusys_idle_mask = 0,
83 	/* [25] */
84 	.reg_md_apsrc_1_sel = 0,
85 	/* [26] */
86 	.reg_md_apsrc_0_sel = 0,
87 	/* [29] */
88 	.reg_conn_apsrc_sel = 0,
89 
90 	/* SPM_SRC_REQ */
91 	/* [0] */
92 	.reg_spm_apsrc_req = 0,
93 	/* [1] */
94 	.reg_spm_f26m_req = 0,
95 	/* [3] */
96 	.reg_spm_infra_req = 0,
97 	/* [4] */
98 	.reg_spm_vrf18_req = 0,
99 	/* [7] FIXME: default disable HW Auto S1*/
100 	.reg_spm_ddr_en_req = 1,
101 	/* [8] */
102 	.reg_spm_dvfs_req = 0,
103 	/* [9] */
104 	.reg_spm_sw_mailbox_req = 0,
105 	/* [10] */
106 	.reg_spm_sspm_mailbox_req = 0,
107 	/* [11] */
108 	.reg_spm_adsp_mailbox_req = 0,
109 	/* [12] */
110 	.reg_spm_scp_mailbox_req = 0,
111 
112 	/* SPM_SRC_MASK */
113 	/* [0] */
114 	.reg_sspm_srcclkena_0_mask_b = 1,
115 	/* [1] */
116 	.reg_sspm_infra_req_0_mask_b = 1,
117 	/* [2] */
118 	.reg_sspm_apsrc_req_0_mask_b = 1,
119 	/* [3] */
120 	.reg_sspm_vrf18_req_0_mask_b = 1,
121 	/* [4] */
122 	.reg_sspm_ddr_en_0_mask_b = 1,
123 	/* [5] */
124 	.reg_scp_srcclkena_mask_b = 1,
125 	/* [6] */
126 	.reg_scp_infra_req_mask_b = 1,
127 	/* [7] */
128 	.reg_scp_apsrc_req_mask_b = 1,
129 	/* [8] */
130 	.reg_scp_vrf18_req_mask_b = 1,
131 	/* [9] */
132 	.reg_scp_ddr_en_mask_b = 1,
133 	/* [10] */
134 	.reg_audio_dsp_srcclkena_mask_b = 1,
135 	/* [11] */
136 	.reg_audio_dsp_infra_req_mask_b = 1,
137 	/* [12] */
138 	.reg_audio_dsp_apsrc_req_mask_b = 1,
139 	/* [13] */
140 	.reg_audio_dsp_vrf18_req_mask_b = 1,
141 	/* [14] */
142 	.reg_audio_dsp_ddr_en_mask_b = 1,
143 	/* [15] */
144 	.reg_apu_srcclkena_mask_b = 1,
145 	/* [16] */
146 	.reg_apu_infra_req_mask_b = 1,
147 	/* [17] */
148 	.reg_apu_apsrc_req_mask_b = 1,
149 	/* [18] */
150 	.reg_apu_vrf18_req_mask_b = 1,
151 	/* [19] */
152 	.reg_apu_ddr_en_mask_b = 1,
153 	/* [20] */
154 	.reg_cpueb_srcclkena_mask_b = 1,
155 	/* [21] */
156 	.reg_cpueb_infra_req_mask_b = 1,
157 	/* [22] */
158 	.reg_cpueb_apsrc_req_mask_b = 1,
159 	/* [23] */
160 	.reg_cpueb_vrf18_req_mask_b = 1,
161 	/* [24] */
162 	.reg_cpueb_ddr_en_mask_b = 1,
163 	/* [25] */
164 	.reg_bak_psri_srcclkena_mask_b = 0,
165 	/* [26] */
166 	.reg_bak_psri_infra_req_mask_b = 0,
167 	/* [27] */
168 	.reg_bak_psri_apsrc_req_mask_b = 0,
169 	/* [28] */
170 	.reg_bak_psri_vrf18_req_mask_b = 0,
171 	/* [29] */
172 	.reg_bak_psri_ddr_en_mask_b = 0,
173 
174 	/* SPM_SRC2_MASK */
175 	/* [0] */
176 	.reg_msdc0_srcclkena_mask_b = 1,
177 	/* [1] */
178 	.reg_msdc0_infra_req_mask_b = 1,
179 	/* [2] */
180 	.reg_msdc0_apsrc_req_mask_b = 1,
181 	/* [3] */
182 	.reg_msdc0_vrf18_req_mask_b = 1,
183 	/* [4] */
184 	.reg_msdc0_ddr_en_mask_b = 1,
185 	/* [5] */
186 	.reg_msdc1_srcclkena_mask_b = 1,
187 	/* [6] */
188 	.reg_msdc1_infra_req_mask_b = 1,
189 	/* [7] */
190 	.reg_msdc1_apsrc_req_mask_b = 1,
191 	/* [8] */
192 	.reg_msdc1_vrf18_req_mask_b = 1,
193 	/* [9] */
194 	.reg_msdc1_ddr_en_mask_b = 1,
195 	/* [10] */
196 	.reg_msdc2_srcclkena_mask_b = 1,
197 	/* [11] */
198 	.reg_msdc2_infra_req_mask_b = 1,
199 	/* [12] */
200 	.reg_msdc2_apsrc_req_mask_b = 1,
201 	/* [13] */
202 	.reg_msdc2_vrf18_req_mask_b = 1,
203 	/* [14] */
204 	.reg_msdc2_ddr_en_mask_b = 1,
205 	/* [15] */
206 	.reg_ufs_srcclkena_mask_b = 0,
207 	/* [16] */
208 	.reg_ufs_infra_req_mask_b = 0,
209 	/* [17] */
210 	.reg_ufs_apsrc_req_mask_b = 0,
211 	/* [18] */
212 	.reg_ufs_vrf18_req_mask_b = 0,
213 	/* [19] */
214 	.reg_ufs_ddr_en_mask_b = 0,
215 	/* [20] */
216 	.reg_usb_srcclkena_mask_b = 1,
217 	/* [21] */
218 	.reg_usb_infra_req_mask_b = 1,
219 	/* [22] */
220 	.reg_usb_apsrc_req_mask_b = 1,
221 	/* [23] */
222 	.reg_usb_vrf18_req_mask_b = 1,
223 	/* [24] */
224 	.reg_usb_ddr_en_mask_b = 1,
225 	/* [25] */
226 	.reg_pextp_p0_srcclkena_mask_b = 1,
227 	/* [26] */
228 	.reg_pextp_p0_infra_req_mask_b = 1,
229 	/* [27] */
230 	.reg_pextp_p0_apsrc_req_mask_b = 1,
231 	/* [28] */
232 	.reg_pextp_p0_vrf18_req_mask_b = 1,
233 	/* [29] */
234 	.reg_pextp_p0_ddr_en_mask_b = 1,
235 
236 	/* SPM_SRC3_MASK */
237 	/* [0] */
238 	.reg_pextp_p1_srcclkena_mask_b = 1,
239 	/* [1] */
240 	.reg_pextp_p1_infra_req_mask_b = 1,
241 	/* [2] */
242 	.reg_pextp_p1_apsrc_req_mask_b = 1,
243 	/* [3] */
244 	.reg_pextp_p1_vrf18_req_mask_b = 1,
245 	/* [4] */
246 	.reg_pextp_p1_ddr_en_mask_b = 1,
247 	/* [5] */
248 	.reg_gce0_infra_req_mask_b = 1,
249 	/* [6] */
250 	.reg_gce0_apsrc_req_mask_b = 1,
251 	/* [7] */
252 	.reg_gce0_vrf18_req_mask_b = 1,
253 	/* [8] */
254 	.reg_gce0_ddr_en_mask_b = 1,
255 	/* [9] */
256 	.reg_gce1_infra_req_mask_b = 1,
257 	/* [10] */
258 	.reg_gce1_apsrc_req_mask_b = 1,
259 	/* [11] */
260 	.reg_gce1_vrf18_req_mask_b = 1,
261 	/* [12] */
262 	.reg_gce1_ddr_en_mask_b = 1,
263 	/* [13] */
264 	.reg_spm_srcclkena_reserved_mask_b = 1,
265 	/* [14] */
266 	.reg_spm_infra_req_reserved_mask_b = 1,
267 	/* [15] */
268 	.reg_spm_apsrc_req_reserved_mask_b = 1,
269 	/* [16] */
270 	.reg_spm_vrf18_req_reserved_mask_b = 1,
271 	/* [17] */
272 	.reg_spm_ddr_en_reserved_mask_b = 1,
273 	/* [18] */
274 	.reg_disp0_apsrc_req_mask_b = 1,
275 	/* [19] */
276 	.reg_disp0_ddr_en_mask_b = 1,
277 	/* [20] */
278 	.reg_disp1_apsrc_req_mask_b = 1,
279 	/* [21] */
280 	.reg_disp1_ddr_en_mask_b = 1,
281 	/* [22] */
282 	.reg_disp2_apsrc_req_mask_b = 1,
283 	/* [23] */
284 	.reg_disp2_ddr_en_mask_b = 1,
285 	/* [24] */
286 	.reg_disp3_apsrc_req_mask_b = 1,
287 	/* [25] */
288 	.reg_disp3_ddr_en_mask_b = 1,
289 	/* [26] */
290 	.reg_infrasys_apsrc_req_mask_b = 0,
291 	/* [27] */
292 	.reg_infrasys_ddr_en_mask_b = 1,
293 
294 	/* [28] */
295 	.reg_cg_check_srcclkena_mask_b = 1,
296 	/* [29] */
297 	.reg_cg_check_apsrc_req_mask_b = 1,
298 	/* [30] */
299 	.reg_cg_check_vrf18_req_mask_b = 1,
300 	/* [31] */
301 	.reg_cg_check_ddr_en_mask_b = 1,
302 
303 	/* SPM_SRC4_MASK */
304 	/* [8:0] */
305 	.reg_mcusys_merge_apsrc_req_mask_b = 0x17,
306 	/* [17:9] */
307 	.reg_mcusys_merge_ddr_en_mask_b = 0x17,
308 	/* [19:18] */
309 	.reg_dramc_md32_infra_req_mask_b = 0,
310 	/* [21:20] */
311 	.reg_dramc_md32_vrf18_req_mask_b = 0,
312 	/* [23:22] */
313 	.reg_dramc_md32_ddr_en_mask_b = 0,
314 	/* [24] */
315 	.reg_dvfsrc_event_trigger_mask_b = 1,
316 
317 	/* SPM_WAKEUP_EVENT_MASK2 */
318 	/* [3:0] */
319 	.reg_sc_sw2spm_wakeup_mask_b = 0,
320 	/* [4] */
321 	.reg_sc_adsp2spm_wakeup_mask_b = 0,
322 	/* [8:5] */
323 	.reg_sc_sspm2spm_wakeup_mask_b = 0,
324 	/* [9] */
325 	.reg_sc_scp2spm_wakeup_mask_b = 0,
326 	/* [10] */
327 	.reg_csyspwrup_ack_mask = 0,
328 	/* [11] */
329 	.reg_csyspwrup_req_mask = 1,
330 
331 	/* SPM_WAKEUP_EVENT_MASK */
332 	/* [31:0] */
333 	.reg_wakeup_event_mask = 0xC1382213,
334 
335 	/* SPM_WAKEUP_EVENT_EXT_MASK */
336 	/* [31:0] */
337 	.reg_ext_wakeup_event_mask = 0xFFFFFFFF,
338 };
339 
340 struct spm_lp_scen __spm_suspend = {
341 	.pwrctrl = &suspend_ctrl,
342 };
343 
mt_spm_suspend_mode_set(int mode)344 int mt_spm_suspend_mode_set(int mode)
345 {
346 	if (mode == MT_SPM_SUSPEND_SLEEP) {
347 		suspend_ctrl.pcm_flags = SPM_SUSPEND_SLEEP_PCM_FLAG;
348 		suspend_ctrl.pcm_flags1 = SPM_SUSPEND_SLEEP_PCM_FLAG1;
349 	} else {
350 		suspend_ctrl.pcm_flags = SPM_SUSPEND_PCM_FLAG;
351 		suspend_ctrl.pcm_flags1 = SPM_SUSPEND_PCM_FLAG1;
352 	}
353 
354 	return 0;
355 }
356 
mt_spm_suspend_enter(int state_id,unsigned int ext_opand,unsigned int resource_req)357 int mt_spm_suspend_enter(int state_id, unsigned int ext_opand,
358 			 unsigned int resource_req)
359 {
360 	/* If FMAudio / ADSP is active, change to sleep suspend mode */
361 	if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
362 		mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SLEEP);
363 	}
364 
365 	/* Notify MCUPM that device is going suspend flow */
366 	mmio_write_32(MCUPM_MBOX_OFFSET_PDN, MCUPM_POWER_DOWN);
367 
368 	/* Notify UART to sleep */
369 	mt_uart_save();
370 
371 	return spm_conservation(state_id, ext_opand,
372 				&__spm_suspend, resource_req);
373 }
374 
mt_spm_suspend_resume(int state_id,unsigned int ext_opand,struct wake_status ** status)375 void mt_spm_suspend_resume(int state_id, unsigned int ext_opand,
376 			   struct wake_status **status)
377 {
378 	spm_conservation_finish(state_id, ext_opand, &__spm_suspend, status);
379 
380 	/* Notify UART to wakeup */
381 	mt_uart_restore();
382 
383 	/* Notify MCUPM that device leave suspend */
384 	mmio_write_32(MCUPM_MBOX_OFFSET_PDN, 0);
385 
386 	/* If FMAudio / ADSP is active, change back to suspend mode */
387 	if ((ext_opand & MT_SPM_EX_OP_SET_SUSPEND_MODE) != 0U) {
388 		mt_spm_suspend_mode_set(MT_SPM_SUSPEND_SYSTEM_PDN);
389 	}
390 }
391 
mt_spm_suspend_init(void)392 void mt_spm_suspend_init(void)
393 {
394 	spm_conservation_pwrctrl_init(__spm_suspend.pwrctrl);
395 }
396