1 /*
2 * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch_helpers.h>
8 #include <common/debug.h>
9 #include <drivers/delay_timer.h>
10 #include <mt_gic_v3.h>
11 #include <lib/mmio.h>
12 #include <platform_def.h>
13 #include <pmic.h>
14 #include <spm.h>
15 #include <uart.h>
16
17 #define SPM_SYSCLK_SETTLE 99
18
19 #define WAKE_SRC_FOR_SUSPEND \
20 (WAKE_SRC_R12_PCM_TIMER | \
21 WAKE_SRC_R12_SSPM_WDT_EVENT_B | \
22 WAKE_SRC_R12_KP_IRQ_B | \
23 WAKE_SRC_R12_CONN2AP_SPM_WAKEUP_B | \
24 WAKE_SRC_R12_EINT_EVENT_B | \
25 WAKE_SRC_R12_CONN_WDT_IRQ_B | \
26 WAKE_SRC_R12_CCIF0_EVENT_B | \
27 WAKE_SRC_R12_SSPM_SPM_IRQ_B | \
28 WAKE_SRC_R12_SCP_SPM_IRQ_B | \
29 WAKE_SRC_R12_SCP_WDT_EVENT_B | \
30 WAKE_SRC_R12_USB_CDSC_B | \
31 WAKE_SRC_R12_USB_POWERDWN_B | \
32 WAKE_SRC_R12_SYS_TIMER_EVENT_B | \
33 WAKE_SRC_R12_EINT_EVENT_SECURE_B | \
34 WAKE_SRC_R12_CCIF1_EVENT_B | \
35 WAKE_SRC_R12_MD2AP_PEER_EVENT_B | \
36 WAKE_SRC_R12_MD1_WDT_B | \
37 WAKE_SRC_R12_CLDMA_EVENT_B | \
38 WAKE_SRC_R12_SEJ_WDT_GPT_B)
39
40 #define SLP_PCM_FLAGS \
41 (SPM_FLAG_DIS_VCORE_DVS | SPM_FLAG_DIS_VCORE_DFS | \
42 SPM_FLAG_DIS_ATF_ABORT | SPM_FLAG_DISABLE_MMSYS_DVFS | \
43 SPM_FLAG_DIS_INFRA_PDN | SPM_FLAG_SUSPEND_OPTION)
44
45 #define SLP_PCM_FLAGS1 \
46 (SPM_FLAG1_DISABLE_MCDSR)
47
48 static const struct pwr_ctrl suspend_ctrl = {
49 .wake_src = WAKE_SRC_FOR_SUSPEND,
50 .pcm_flags = SLP_PCM_FLAGS,
51 .pcm_flags1 = SLP_PCM_FLAGS1,
52
53 /* SPM_AP_STANDBY_CON */
54 .wfi_op = 0x1,
55 .mp0_cputop_idle_mask = 0,
56 .mp1_cputop_idle_mask = 0,
57 .mcusys_idle_mask = 0,
58 .mm_mask_b = 0,
59 .md_ddr_en_0_dbc_en = 0x1,
60 .md_ddr_en_1_dbc_en = 0,
61 .md_mask_b = 0x1,
62 .sspm_mask_b = 0x1,
63 .scp_mask_b = 0x1,
64 .srcclkeni_mask_b = 0x1,
65 .md_apsrc_1_sel = 0,
66 .md_apsrc_0_sel = 0,
67 .conn_ddr_en_dbc_en = 0x1,
68 .conn_mask_b = 0x1,
69 .conn_apsrc_sel = 0,
70
71 /* SPM_SRC_REQ */
72 .spm_apsrc_req = 0,
73 .spm_f26m_req = 0,
74 .spm_infra_req = 0,
75 .spm_vrf18_req = 0,
76 .spm_ddren_req = 0,
77 .spm_rsv_src_req = 0,
78 .spm_ddren_2_req = 0,
79 .cpu_md_dvfs_sop_force_on = 0,
80
81 /* SPM_SRC_MASK */
82 .csyspwreq_mask = 0x1,
83 .ccif0_md_event_mask_b = 0x1,
84 .ccif0_ap_event_mask_b = 0x1,
85 .ccif1_md_event_mask_b = 0x1,
86 .ccif1_ap_event_mask_b = 0x1,
87 .ccif2_md_event_mask_b = 0x1,
88 .ccif2_ap_event_mask_b = 0x1,
89 .ccif3_md_event_mask_b = 0x1,
90 .ccif3_ap_event_mask_b = 0x1,
91 .md_srcclkena_0_infra_mask_b = 0x1,
92 .md_srcclkena_1_infra_mask_b = 0,
93 .conn_srcclkena_infra_mask_b = 0,
94 .ufs_infra_req_mask_b = 0,
95 .srcclkeni_infra_mask_b = 0,
96 .md_apsrc_req_0_infra_mask_b = 0x1,
97 .md_apsrc_req_1_infra_mask_b = 0x1,
98 .conn_apsrcreq_infra_mask_b = 0x1,
99 .ufs_srcclkena_mask_b = 0,
100 .md_vrf18_req_0_mask_b = 0,
101 .md_vrf18_req_1_mask_b = 0,
102 .ufs_vrf18_req_mask_b = 0,
103 .gce_vrf18_req_mask_b = 0,
104 .conn_infra_req_mask_b = 0x1,
105 .gce_apsrc_req_mask_b = 0,
106 .disp0_apsrc_req_mask_b = 0,
107 .disp1_apsrc_req_mask_b = 0,
108 .mfg_req_mask_b = 0,
109 .vdec_req_mask_b = 0,
110
111 /* SPM_SRC2_MASK */
112 .md_ddr_en_0_mask_b = 0x1,
113 .md_ddr_en_1_mask_b = 0,
114 .conn_ddr_en_mask_b = 0x1,
115 .ddren_sspm_apsrc_req_mask_b = 0x1,
116 .ddren_scp_apsrc_req_mask_b = 0x1,
117 .disp0_ddren_mask_b = 0x1,
118 .disp1_ddren_mask_b = 0x1,
119 .gce_ddren_mask_b = 0x1,
120 .ddren_emi_self_refresh_ch0_mask_b = 0,
121 .ddren_emi_self_refresh_ch1_mask_b = 0,
122
123 /* SPM_WAKEUP_EVENT_MASK */
124 .spm_wakeup_event_mask = 0xF1782218,
125
126 /* SPM_WAKEUP_EVENT_EXT_MASK */
127 .spm_wakeup_event_ext_mask = 0xFFFFFFFF,
128
129 /* SPM_SRC3_MASK */
130 .md_ddr_en_2_0_mask_b = 0x1,
131 .md_ddr_en_2_1_mask_b = 0,
132 .conn_ddr_en_2_mask_b = 0x1,
133 .ddren2_sspm_apsrc_req_mask_b = 0x1,
134 .ddren2_scp_apsrc_req_mask_b = 0x1,
135 .disp0_ddren2_mask_b = 0,
136 .disp1_ddren2_mask_b = 0,
137 .gce_ddren2_mask_b = 0,
138 .ddren2_emi_self_refresh_ch0_mask_b = 0,
139 .ddren2_emi_self_refresh_ch1_mask_b = 0,
140
141 .mp0_cpu0_wfi_en = 0x1,
142 .mp0_cpu1_wfi_en = 0x1,
143 .mp0_cpu2_wfi_en = 0x1,
144 .mp0_cpu3_wfi_en = 0x1,
145
146 .mp1_cpu0_wfi_en = 0x1,
147 .mp1_cpu1_wfi_en = 0x1,
148 .mp1_cpu2_wfi_en = 0x1,
149 .mp1_cpu3_wfi_en = 0x1
150 };
151
spm_set_sysclk_settle(void)152 static uint32_t spm_set_sysclk_settle(void)
153 {
154 mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
155 return mmio_read_32(SPM_CLK_SETTLE);
156 }
157
go_to_sleep_before_wfi(void)158 void go_to_sleep_before_wfi(void)
159 {
160 int cpu = MPIDR_AFFLVL0_VAL(read_mpidr());
161 uint32_t settle;
162
163 settle = spm_set_sysclk_settle();
164 spm_set_cpu_status(cpu);
165 spm_set_power_control(&suspend_ctrl);
166 spm_set_wakeup_event(&suspend_ctrl);
167 spm_set_pcm_flags(&suspend_ctrl);
168 spm_send_cpu_wakeup_event();
169 spm_set_pcm_wdt(0);
170 spm_disable_pcm_timer();
171
172 if (is_infra_pdn(suspend_ctrl.pcm_flags))
173 mt_uart_save();
174
175 if (!mt_console_uart_cg_status())
176 console_switch_state(CONSOLE_FLAG_BOOT);
177
178 INFO("cpu%d: \"%s\", wakesrc = 0x%x, pcm_con1 = 0x%x\n",
179 cpu, spm_get_firmware_version(), suspend_ctrl.wake_src,
180 mmio_read_32(PCM_CON1));
181 INFO("settle = %u, sec = %u, sw_flag = 0x%x 0x%x, src_req = 0x%x\n",
182 settle, mmio_read_32(PCM_TIMER_VAL) / 32768,
183 suspend_ctrl.pcm_flags, suspend_ctrl.pcm_flags1,
184 mmio_read_32(SPM_SRC_REQ));
185
186 if (!mt_console_uart_cg_status())
187 console_switch_state(CONSOLE_FLAG_RUNTIME);
188 }
189
go_to_sleep_after_wfi(void)190 static void go_to_sleep_after_wfi(void)
191 {
192 struct wake_status spm_wakesta;
193
194 if (is_infra_pdn(suspend_ctrl.pcm_flags))
195 mt_uart_restore();
196
197 spm_set_pcm_wdt(0);
198 spm_get_wakeup_status(&spm_wakesta);
199 spm_clean_after_wakeup();
200
201 if (!mt_console_uart_cg_status())
202 console_switch_state(CONSOLE_FLAG_BOOT);
203
204 spm_output_wake_reason(&spm_wakesta, "suspend");
205
206 if (!mt_console_uart_cg_status())
207 console_switch_state(CONSOLE_FLAG_RUNTIME);
208 }
209
spm_enable_armpll_l(void)210 static void spm_enable_armpll_l(void)
211 {
212 /* power on */
213 mmio_setbits_32(ARMPLL_L_PWR_CON0, 0x1);
214
215 /* clear isolation */
216 mmio_clrbits_32(ARMPLL_L_PWR_CON0, 0x2);
217
218 /* enable pll */
219 mmio_setbits_32(ARMPLL_L_CON0, 0x1);
220
221 /* Add 20us delay for turning on PLL */
222 udelay(20);
223 }
224
spm_disable_armpll_l(void)225 static void spm_disable_armpll_l(void)
226 {
227 /* disable pll */
228 mmio_clrbits_32(ARMPLL_L_CON0, 0x1);
229
230 /* isolation */
231 mmio_setbits_32(ARMPLL_L_PWR_CON0, 0x2);
232
233 /* power off */
234 mmio_clrbits_32(ARMPLL_L_PWR_CON0, 0x1);
235 }
236
spm_system_suspend(void)237 void spm_system_suspend(void)
238 {
239 spm_disable_armpll_l();
240 bcpu_enable(0);
241 bcpu_sram_enable(0);
242 spm_lock_get();
243 go_to_sleep_before_wfi();
244 spm_lock_release();
245 }
246
spm_system_suspend_finish(void)247 void spm_system_suspend_finish(void)
248 {
249 spm_lock_get();
250 go_to_sleep_after_wfi();
251 spm_lock_release();
252 spm_enable_armpll_l();
253 bcpu_sram_enable(1);
254 bcpu_enable(1);
255 }
256