]>
Commit | Line | Data |
---|---|---|
41c79775 PD |
1 | // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
2 | /* | |
3 | * Copyright (C) 2018, STMicroelectronics - All Rights Reserved | |
4 | */ | |
5 | ||
6 | #include <config.h> | |
7 | #include <common.h> | |
8 | #include <asm/armv7.h> | |
90526e9f | 9 | #include <asm/cache.h> |
41c79775 PD |
10 | #include <asm/gic.h> |
11 | #include <asm/io.h> | |
12 | #include <asm/psci.h> | |
13 | #include <asm/secure.h> | |
b4910532 | 14 | #include <hang.h> |
cd93d625 | 15 | #include <linux/bitops.h> |
41c79775 | 16 | |
b4910532 MV |
17 | /* PWR */ |
18 | #define PWR_CR3 0x0c | |
19 | #define PWR_MPUCR 0x10 | |
20 | ||
21 | #define PWR_CR3_DDRSREN BIT(10) | |
22 | #define PWR_CR3_DDRRETEN BIT(12) | |
23 | ||
24 | #define PWR_MPUCR_PDDS BIT(0) | |
25 | #define PWR_MPUCR_CSTDBYDIS BIT(3) | |
26 | #define PWR_MPUCR_CSSF BIT(9) | |
27 | ||
28 | /* RCC */ | |
d6ae1839 | 29 | #define RCC_MSSCKSELR 0x48 |
b4910532 MV |
30 | #define RCC_DDRITFCR 0xd8 |
31 | ||
32 | #define RCC_DDRITFCR_DDRC1EN BIT(0) | |
33 | #define RCC_DDRITFCR_DDRC1LPEN BIT(1) | |
34 | #define RCC_DDRITFCR_DDRC2EN BIT(2) | |
35 | #define RCC_DDRITFCR_DDRC2LPEN BIT(3) | |
36 | #define RCC_DDRITFCR_DDRPHYCEN BIT(4) | |
37 | #define RCC_DDRITFCR_DDRPHYCLPEN BIT(5) | |
38 | #define RCC_DDRITFCR_DDRCAPBEN BIT(6) | |
39 | #define RCC_DDRITFCR_DDRCAPBLPEN BIT(7) | |
40 | #define RCC_DDRITFCR_AXIDCGEN BIT(8) | |
41 | #define RCC_DDRITFCR_DDRPHYCAPBEN BIT(9) | |
42 | #define RCC_DDRITFCR_DDRPHYCAPBLPEN BIT(10) | |
43 | #define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) | |
44 | #define RCC_DDRITFCR_GSKPCTRL BIT(24) | |
45 | ||
46 | #define RCC_MP_SREQSETR 0x104 | |
47 | #define RCC_MP_SREQCLRR 0x108 | |
48 | ||
49 | #define RCC_MP_CIER 0x414 | |
50 | #define RCC_MP_CIFR 0x418 | |
51 | #define RCC_MP_CIFR_WKUPF BIT(20) | |
52 | ||
d6ae1839 MV |
53 | #define RCC_MCUDIVR 0x830 |
54 | #define RCC_PLL3CR 0x880 | |
55 | #define RCC_PLL4CR 0x894 | |
56 | ||
b4910532 MV |
57 | /* SYSCFG */ |
58 | #define SYSCFG_CMPCR 0x20 | |
59 | #define SYSCFG_CMPCR_SW_CTRL BIT(2) | |
60 | #define SYSCFG_CMPENSETR 0x24 | |
61 | #define SYSCFG_CMPENCLRR 0x28 | |
62 | #define SYSCFG_CMPENR_MPUEN BIT(0) | |
63 | ||
64 | /* DDR Controller registers offsets */ | |
65 | #define DDRCTRL_STAT 0x004 | |
66 | #define DDRCTRL_PWRCTL 0x030 | |
67 | #define DDRCTRL_PWRTMG 0x034 | |
68 | #define DDRCTRL_HWLPCTL 0x038 | |
69 | #define DDRCTRL_DFIMISC 0x1b0 | |
70 | #define DDRCTRL_SWCTL 0x320 | |
71 | #define DDRCTRL_SWSTAT 0x324 | |
72 | #define DDRCTRL_PSTAT 0x3fc | |
73 | #define DDRCTRL_PCTRL_0 0x490 | |
74 | #define DDRCTRL_PCTRL_1 0x540 | |
75 | ||
76 | /* DDR Controller Register fields */ | |
77 | #define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK(2, 0) | |
78 | #define DDRCTRL_STAT_OPERATING_MODE_NORMAL 0x1 | |
79 | #define DDRCTRL_STAT_OPERATING_MODE_SR 0x3 | |
80 | #define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4) | |
81 | #define DDRCTRL_STAT_SELFREF_TYPE_ASR (0x3 << 4) | |
82 | #define DDRCTRL_STAT_SELFREF_TYPE_SR (0x2 << 4) | |
83 | ||
84 | #define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) | |
85 | #define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) | |
86 | #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) | |
87 | ||
88 | #define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK(23, 16) | |
89 | #define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16) | |
90 | ||
91 | #define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) | |
92 | ||
93 | #define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0) | |
94 | ||
95 | #define DDRCTRL_SWCTL_SW_DONE BIT(0) | |
96 | ||
97 | #define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0) | |
98 | ||
99 | #define DDRCTRL_PSTAT_RD_PORT_BUSY_0 BIT(0) | |
100 | #define DDRCTRL_PSTAT_RD_PORT_BUSY_1 BIT(1) | |
101 | #define DDRCTRL_PSTAT_WR_PORT_BUSY_0 BIT(16) | |
102 | #define DDRCTRL_PSTAT_WR_PORT_BUSY_1 BIT(17) | |
103 | ||
104 | #define DDRCTRL_PCTRL_N_PORT_EN BIT(0) | |
105 | ||
106 | /* DDR PHY registers offsets */ | |
107 | #define DDRPHYC_PIR 0x004 | |
108 | #define DDRPHYC_PGSR 0x00c | |
109 | #define DDRPHYC_ACDLLCR 0x014 | |
110 | #define DDRPHYC_ACIOCR 0x024 | |
111 | #define DDRPHYC_DXCCR 0x028 | |
112 | #define DDRPHYC_DSGCR 0x02c | |
113 | #define DDRPHYC_ZQ0CR0 0x180 | |
114 | #define DDRPHYC_DX0DLLCR 0x1cc | |
115 | #define DDRPHYC_DX1DLLCR 0x20c | |
116 | #define DDRPHYC_DX2DLLCR 0x24c | |
117 | #define DDRPHYC_DX3DLLCR 0x28c | |
118 | ||
119 | /* DDR PHY Register fields */ | |
120 | #define DDRPHYC_PIR_INIT BIT(0) | |
121 | #define DDRPHYC_PIR_DLLSRST BIT(1) | |
122 | #define DDRPHYC_PIR_DLLLOCK BIT(2) | |
123 | #define DDRPHYC_PIR_ITMSRST BIT(4) | |
124 | ||
125 | #define DDRPHYC_PGSR_IDONE BIT(0) | |
126 | ||
127 | #define DDRPHYC_ACDLLCR_DLLSRST BIT(30) | |
128 | #define DDRPHYC_ACDLLCR_DLLDIS BIT(31) | |
129 | ||
130 | #define DDRPHYC_ACIOCR_ACOE BIT(1) | |
131 | #define DDRPHYC_ACIOCR_ACPDD BIT(3) | |
132 | #define DDRPHYC_ACIOCR_ACPDR BIT(4) | |
133 | #define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK(10, 8) | |
134 | #define DDRPHYC_ACIOCR_CKPDD_0 BIT(8) | |
135 | #define DDRPHYC_ACIOCR_CKPDR_MASK GENMASK(13, 11) | |
136 | #define DDRPHYC_ACIOCR_CKPDR_0 BIT(11) | |
137 | #define DDRPHYC_ACIOCR_CSPDD_MASK GENMASK(20, 18) | |
138 | #define DDRPHYC_ACIOCR_CSPDD_0 BIT(18) | |
139 | ||
140 | #define DDRPHYC_DXCCR_DXPDD BIT(2) | |
141 | #define DDRPHYC_DXCCR_DXPDR BIT(3) | |
142 | ||
143 | #define DDRPHYC_DSGCR_CKEPDD_MASK GENMASK(19, 16) | |
144 | #define DDRPHYC_DSGCR_CKEPDD_0 BIT(16) | |
145 | #define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK(23, 20) | |
146 | #define DDRPHYC_DSGCR_ODTPDD_0 BIT(20) | |
147 | #define DDRPHYC_DSGCR_NL2PD BIT(24) | |
148 | #define DDRPHYC_DSGCR_CKOE BIT(28) | |
149 | ||
150 | #define DDRPHYC_ZQ0CRN_ZQPD BIT(31) | |
151 | ||
152 | #define DDRPHYC_DXNDLLCR_DLLDIS BIT(31) | |
153 | ||
154 | #define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xca7face0 | |
155 | #define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xca7face1 | |
156 | ||
157 | #define MPIDR_AFF0 GENMASK(7, 0) | |
158 | ||
159 | #define RCC_MP_GRSTCSETR (STM32_RCC_BASE + 0x0404) | |
160 | #define RCC_MP_GRSTCSETR_MPSYSRST BIT(0) | |
161 | #define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) | |
162 | #define RCC_MP_GRSTCSETR_MPUP1RST BIT(5) | |
163 | ||
164 | #define STM32MP1_PSCI_NR_CPUS 2 | |
41c79775 PD |
165 | #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS |
166 | #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS" | |
167 | #endif | |
168 | ||
169 | u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = { | |
170 | PSCI_AFFINITY_LEVEL_ON, | |
171 | PSCI_AFFINITY_LEVEL_OFF}; | |
172 | ||
40e70ab8 LB |
173 | static u32 __secure_data cntfrq; |
174 | ||
175 | static u32 __secure cp15_read_cntfrq(void) | |
176 | { | |
177 | u32 frq; | |
178 | ||
179 | asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq)); | |
180 | ||
181 | return frq; | |
182 | } | |
183 | ||
184 | static void __secure cp15_write_cntfrq(u32 frq) | |
185 | { | |
186 | asm volatile ("mcr p15, 0, %0, c14, c0, 0" : : "r" (frq)); | |
187 | } | |
188 | ||
e21e3ffd | 189 | static inline void psci_set_state(int cpu, u8 state) |
41c79775 PD |
190 | { |
191 | psci_state[cpu] = state; | |
192 | dsb(); | |
193 | isb(); | |
194 | } | |
195 | ||
196 | static u32 __secure stm32mp_get_gicd_base_address(void) | |
197 | { | |
198 | u32 periphbase; | |
199 | ||
200 | /* get the GIC base address from the CBAR register */ | |
201 | asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (periphbase)); | |
202 | ||
203 | return (periphbase & CBAR_MASK) + GIC_DIST_OFFSET; | |
204 | } | |
205 | ||
bb7288ef | 206 | static void __secure stm32mp_raise_sgi0(int cpu) |
41c79775 PD |
207 | { |
208 | u32 gic_dist_addr; | |
209 | ||
210 | gic_dist_addr = stm32mp_get_gicd_base_address(); | |
211 | ||
bb7288ef PD |
212 | /* ask cpu with SGI0 */ |
213 | writel((BIT(cpu) << 16), gic_dist_addr + GICD_SGIR); | |
41c79775 PD |
214 | } |
215 | ||
216 | void __secure psci_arch_cpu_entry(void) | |
217 | { | |
218 | u32 cpu = psci_get_cpu_id(); | |
219 | ||
220 | psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON); | |
bb7288ef | 221 | |
40e70ab8 LB |
222 | /* write the saved cntfrq */ |
223 | cp15_write_cntfrq(cntfrq); | |
224 | ||
bb7288ef PD |
225 | /* reset magic in TAMP register */ |
226 | writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER); | |
41c79775 PD |
227 | } |
228 | ||
e21e3ffd | 229 | s32 __secure psci_features(u32 function_id, u32 psci_fid) |
41c79775 PD |
230 | { |
231 | switch (psci_fid) { | |
232 | case ARM_PSCI_0_2_FN_PSCI_VERSION: | |
233 | case ARM_PSCI_0_2_FN_CPU_OFF: | |
234 | case ARM_PSCI_0_2_FN_CPU_ON: | |
235 | case ARM_PSCI_0_2_FN_AFFINITY_INFO: | |
236 | case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE: | |
237 | case ARM_PSCI_0_2_FN_SYSTEM_OFF: | |
238 | case ARM_PSCI_0_2_FN_SYSTEM_RESET: | |
b4910532 | 239 | case ARM_PSCI_1_0_FN_SYSTEM_SUSPEND: |
41c79775 PD |
240 | return 0x0; |
241 | } | |
242 | return ARM_PSCI_RET_NI; | |
243 | } | |
244 | ||
e21e3ffd | 245 | u32 __secure psci_version(void) |
41c79775 PD |
246 | { |
247 | return ARM_PSCI_VER_1_0; | |
248 | } | |
249 | ||
e21e3ffd | 250 | s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity, |
41c79775 PD |
251 | u32 lowest_affinity_level) |
252 | { | |
253 | u32 cpu = target_affinity & MPIDR_AFF0; | |
254 | ||
255 | if (lowest_affinity_level > 0) | |
256 | return ARM_PSCI_RET_INVAL; | |
257 | ||
258 | if (target_affinity & ~MPIDR_AFF0) | |
259 | return ARM_PSCI_RET_INVAL; | |
260 | ||
261 | if (cpu >= STM32MP1_PSCI_NR_CPUS) | |
262 | return ARM_PSCI_RET_INVAL; | |
263 | ||
264 | return psci_state[cpu]; | |
265 | } | |
266 | ||
e21e3ffd | 267 | u32 __secure psci_migrate_info_type(void) |
41c79775 | 268 | { |
b496eec6 PD |
269 | /* |
270 | * in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf | |
271 | * return 2 = Trusted OS is either not present or does not require | |
272 | * migration, system of this type does not require the caller | |
273 | * to use the MIGRATE function. | |
274 | * MIGRATE function calls return NOT_SUPPORTED. | |
275 | */ | |
41c79775 PD |
276 | return 2; |
277 | } | |
278 | ||
e21e3ffd | 279 | s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, |
41c79775 PD |
280 | u32 context_id) |
281 | { | |
282 | u32 cpu = target_cpu & MPIDR_AFF0; | |
283 | ||
284 | if (target_cpu & ~MPIDR_AFF0) | |
285 | return ARM_PSCI_RET_INVAL; | |
286 | ||
287 | if (cpu >= STM32MP1_PSCI_NR_CPUS) | |
288 | return ARM_PSCI_RET_INVAL; | |
289 | ||
290 | if (psci_state[cpu] == PSCI_AFFINITY_LEVEL_ON) | |
291 | return ARM_PSCI_RET_ALREADY_ON; | |
292 | ||
40e70ab8 LB |
293 | /* read and save cntfrq of current cpu to write on target cpu */ |
294 | cntfrq = cp15_read_cntfrq(); | |
295 | ||
bb7288ef PD |
296 | /* reset magic in TAMP register */ |
297 | if (readl(TAMP_BACKUP_MAGIC_NUMBER)) | |
298 | writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER); | |
299 | /* | |
300 | * ROM code need a first SGI0 after core reset | |
301 | * core is ready when magic is set to 0 in ROM code | |
302 | */ | |
303 | while (readl(TAMP_BACKUP_MAGIC_NUMBER)) | |
304 | stm32mp_raise_sgi0(cpu); | |
305 | ||
41c79775 PD |
306 | /* store target PC and context id*/ |
307 | psci_save(cpu, pc, context_id); | |
308 | ||
309 | /* write entrypoint in backup RAM register */ | |
310 | writel((u32)&psci_cpu_entry, TAMP_BACKUP_BRANCH_ADDRESS); | |
311 | psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON_PENDING); | |
312 | ||
313 | /* write magic number in backup register */ | |
314 | if (cpu == 0x01) | |
315 | writel(BOOT_API_A7_CORE1_MAGIC_NUMBER, | |
316 | TAMP_BACKUP_MAGIC_NUMBER); | |
317 | else | |
318 | writel(BOOT_API_A7_CORE0_MAGIC_NUMBER, | |
319 | TAMP_BACKUP_MAGIC_NUMBER); | |
320 | ||
bb7288ef PD |
321 | /* Generate an IT to start the core */ |
322 | stm32mp_raise_sgi0(cpu); | |
41c79775 PD |
323 | |
324 | return ARM_PSCI_RET_SUCCESS; | |
325 | } | |
326 | ||
e21e3ffd | 327 | s32 __secure psci_cpu_off(void) |
41c79775 PD |
328 | { |
329 | u32 cpu; | |
330 | ||
331 | cpu = psci_get_cpu_id(); | |
332 | ||
333 | psci_cpu_off_common(); | |
334 | psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF); | |
335 | ||
336 | /* reset core: wfi is managed by BootRom */ | |
337 | if (cpu == 0x01) | |
338 | writel(RCC_MP_GRSTCSETR_MPUP1RST, RCC_MP_GRSTCSETR); | |
339 | else | |
340 | writel(RCC_MP_GRSTCSETR_MPUP0RST, RCC_MP_GRSTCSETR); | |
341 | ||
342 | /* just waiting reset */ | |
343 | while (1) | |
344 | wfi(); | |
345 | } | |
346 | ||
e21e3ffd | 347 | void __secure psci_system_reset(void) |
41c79775 PD |
348 | { |
349 | /* System reset */ | |
350 | writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR); | |
351 | /* just waiting reset */ | |
352 | while (1) | |
353 | wfi(); | |
354 | } | |
355 | ||
e21e3ffd | 356 | void __secure psci_system_off(void) |
41c79775 PD |
357 | { |
358 | /* System Off is not managed, waiting user power off | |
359 | * TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF | |
360 | */ | |
361 | while (1) | |
362 | wfi(); | |
363 | } | |
b4910532 MV |
364 | |
365 | static void __secure secure_udelay(unsigned int delay) | |
366 | { | |
367 | u32 freq = cp15_read_cntfrq() / 1000000; | |
368 | u64 start, end; | |
369 | ||
370 | delay *= freq; | |
371 | ||
372 | asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start)); | |
373 | for (;;) { | |
374 | asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end)); | |
375 | if ((end - start) > delay) | |
376 | break; | |
377 | } | |
378 | } | |
379 | ||
380 | static int __secure secure_waitbits(u32 reg, u32 mask, u32 val) | |
381 | { | |
382 | u32 freq = cp15_read_cntfrq() / 1000000; | |
383 | u32 delay = 500 * freq; /* 500 us */ | |
384 | u64 start, end; | |
385 | u32 tmp; | |
386 | ||
387 | asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (start)); | |
388 | for (;;) { | |
389 | tmp = readl(reg); | |
390 | tmp &= mask; | |
391 | if ((tmp & val) == val) | |
392 | return 0; | |
393 | asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (end)); | |
394 | if ((end - start) > delay) | |
395 | return -ETIMEDOUT; | |
396 | } | |
397 | } | |
398 | ||
399 | static void __secure ddr_sr_mode_ssr(u32 *saved_pwrctl) | |
400 | { | |
401 | setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, | |
402 | RCC_DDRITFCR_DDRC1LPEN | RCC_DDRITFCR_DDRC1EN | | |
403 | RCC_DDRITFCR_DDRC2LPEN | RCC_DDRITFCR_DDRC2EN | | |
404 | RCC_DDRITFCR_DDRCAPBLPEN | RCC_DDRITFCR_DDRPHYCAPBLPEN | | |
405 | RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN | | |
406 | RCC_DDRITFCR_DDRPHYCEN); | |
407 | ||
408 | clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, | |
409 | RCC_DDRITFCR_AXIDCGEN | RCC_DDRITFCR_DDRCKMOD_MASK); | |
410 | ||
411 | /* Disable HW LP interface of uMCTL2 */ | |
412 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_HWLPCTL, | |
413 | DDRCTRL_HWLPCTL_HW_LP_EN); | |
414 | ||
415 | /* Configure Automatic LP modes of uMCTL2 */ | |
416 | clrsetbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRTMG, | |
417 | DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, | |
418 | DDRCTRL_PWRTMG_SELFREF_TO_X32_0); | |
419 | ||
420 | /* Save PWRCTL register to restart ASR after suspend (if applicable) */ | |
421 | *saved_pwrctl = readl(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL); | |
422 | ||
423 | /* | |
424 | * Disable Clock disable with LP modes | |
425 | * (used in RUN mode for LPDDR2 with specific timing). | |
426 | */ | |
427 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, | |
428 | DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); | |
429 | ||
430 | /* Disable automatic Self-Refresh mode */ | |
431 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, | |
432 | DDRCTRL_PWRCTL_SELFREF_EN); | |
433 | } | |
434 | ||
435 | static void __secure ddr_sr_mode_restore(u32 saved_pwrctl) | |
436 | { | |
437 | saved_pwrctl &= DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | | |
438 | DDRCTRL_PWRCTL_SELFREF_EN; | |
439 | ||
440 | /* Restore ASR mode in case it was enabled before suspend. */ | |
441 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, saved_pwrctl); | |
442 | } | |
443 | ||
444 | static int __secure ddr_sw_self_refresh_in(void) | |
445 | { | |
446 | int ret; | |
447 | ||
448 | clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); | |
449 | ||
450 | /* Blocks AXI ports from taking anymore transactions */ | |
451 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, | |
452 | DDRCTRL_PCTRL_N_PORT_EN); | |
453 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, | |
454 | DDRCTRL_PCTRL_N_PORT_EN); | |
455 | ||
456 | /* | |
457 | * Waits unit all AXI ports are idle | |
458 | * Poll PSTAT.rd_port_busy_n = 0 | |
459 | * Poll PSTAT.wr_port_busy_n = 0 | |
460 | */ | |
461 | ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_PSTAT, | |
462 | DDRCTRL_PSTAT_RD_PORT_BUSY_0 | | |
463 | DDRCTRL_PSTAT_RD_PORT_BUSY_1 | | |
464 | DDRCTRL_PSTAT_WR_PORT_BUSY_0 | | |
465 | DDRCTRL_PSTAT_WR_PORT_BUSY_1, 0); | |
466 | if (ret) | |
467 | goto pstat_failed; | |
468 | ||
469 | /* SW Self-Refresh entry */ | |
470 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); | |
471 | ||
472 | /* | |
473 | * Wait operating mode change in self-refresh mode | |
474 | * with STAT.operating_mode[1:0]==11. | |
475 | * Ensure transition to self-refresh was due to software | |
476 | * by checking also that STAT.selfref_type[1:0]=2. | |
477 | */ | |
478 | ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT, | |
479 | DDRCTRL_STAT_OPERATING_MODE_MASK | | |
480 | DDRCTRL_STAT_SELFREF_TYPE_MASK, | |
481 | DDRCTRL_STAT_OPERATING_MODE_SR | | |
482 | DDRCTRL_STAT_SELFREF_TYPE_SR); | |
483 | if (ret) | |
484 | goto selfref_sw_failed; | |
485 | ||
486 | /* IOs powering down (PUBL registers) */ | |
487 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); | |
488 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR); | |
489 | ||
490 | clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, | |
491 | DDRPHYC_ACIOCR_CKPDD_MASK, | |
492 | DDRPHYC_ACIOCR_CKPDD_0); | |
493 | ||
494 | clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, | |
495 | DDRPHYC_ACIOCR_CKPDR_MASK, | |
496 | DDRPHYC_ACIOCR_CKPDR_0); | |
497 | ||
498 | clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, | |
499 | DDRPHYC_ACIOCR_CSPDD_MASK, | |
500 | DDRPHYC_ACIOCR_CSPDD_0); | |
501 | ||
502 | /* Disable command/address output driver */ | |
503 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); | |
504 | ||
505 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); | |
506 | ||
507 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); | |
508 | ||
509 | clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, | |
510 | DDRPHYC_DSGCR_ODTPDD_MASK, | |
511 | DDRPHYC_DSGCR_ODTPDD_0); | |
512 | ||
513 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); | |
514 | ||
515 | clrsetbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, | |
516 | DDRPHYC_DSGCR_CKEPDD_MASK, | |
517 | DDRPHYC_DSGCR_CKEPDD_0); | |
518 | ||
519 | /* Disable PZQ cell (PUBL register) */ | |
520 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); | |
521 | ||
522 | /* Set latch */ | |
523 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE); | |
524 | ||
525 | /* Additional delay to avoid early latch */ | |
526 | secure_udelay(10); | |
527 | ||
528 | /* Activate sw retention in PWRCTRL */ | |
529 | setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN); | |
530 | ||
531 | /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ | |
532 | setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); | |
533 | ||
534 | /* Disable all DLLs: GLITCH window */ | |
535 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLDIS); | |
536 | ||
537 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
538 | ||
539 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
540 | ||
541 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
542 | ||
543 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
544 | ||
545 | /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */ | |
546 | clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); | |
547 | ||
548 | /* Deactivate all DDR clocks */ | |
549 | clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, | |
550 | RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN | | |
551 | RCC_DDRITFCR_DDRCAPBEN | RCC_DDRITFCR_DDRPHYCAPBEN); | |
552 | ||
553 | return 0; | |
554 | ||
555 | selfref_sw_failed: | |
556 | /* This bit should be cleared to restore DDR in its previous state */ | |
557 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, | |
558 | DDRCTRL_PWRCTL_SELFREF_SW); | |
559 | ||
560 | pstat_failed: | |
561 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, | |
562 | DDRCTRL_PCTRL_N_PORT_EN); | |
563 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, | |
564 | DDRCTRL_PCTRL_N_PORT_EN); | |
565 | ||
566 | return -EINVAL; | |
567 | }; | |
568 | ||
569 | static void __secure ddr_sw_self_refresh_exit(void) | |
570 | { | |
571 | int ret; | |
572 | ||
573 | /* Enable all clocks */ | |
574 | setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, | |
575 | RCC_DDRITFCR_DDRC1EN | RCC_DDRITFCR_DDRC2EN | | |
576 | RCC_DDRITFCR_DDRPHYCEN | RCC_DDRITFCR_DDRPHYCAPBEN | | |
577 | RCC_DDRITFCR_DDRCAPBEN); | |
578 | ||
579 | /* Handshake */ | |
580 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); | |
581 | ||
582 | /* Mask dfi_init_complete_en */ | |
583 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC, | |
584 | DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); | |
585 | ||
586 | /* Ack */ | |
587 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); | |
588 | ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT, | |
589 | DDRCTRL_SWSTAT_SW_DONE_ACK, | |
590 | DDRCTRL_SWSTAT_SW_DONE_ACK); | |
591 | if (ret) | |
592 | hang(); | |
593 | ||
594 | /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ | |
595 | setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); | |
596 | ||
597 | /* Enable all DLLs: GLITCH window */ | |
598 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, | |
599 | DDRPHYC_ACDLLCR_DLLDIS); | |
600 | ||
601 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX0DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
602 | ||
603 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX1DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
604 | ||
605 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX2DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
606 | ||
607 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DX3DLLCR, DDRPHYC_DXNDLLCR_DLLDIS); | |
608 | ||
609 | /* Additional delay to avoid early DLL clock switch */ | |
610 | secure_udelay(50); | |
611 | ||
612 | /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ | |
613 | clrbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); | |
614 | ||
615 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); | |
616 | ||
617 | secure_udelay(10); | |
618 | ||
619 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); | |
620 | ||
621 | /* PHY partial init: (DLL lock and ITM reset) */ | |
622 | writel(DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | | |
623 | DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT, | |
624 | STM32_DDRPHYC_BASE + DDRPHYC_PIR); | |
625 | ||
626 | /* Need to wait at least 10 clock cycles before accessing PGSR */ | |
627 | secure_udelay(1); | |
628 | ||
629 | /* Pool end of init */ | |
630 | ret = secure_waitbits(STM32_DDRPHYC_BASE + DDRPHYC_PGSR, | |
631 | DDRPHYC_PGSR_IDONE, DDRPHYC_PGSR_IDONE); | |
632 | if (ret) | |
633 | hang(); | |
634 | ||
635 | /* Handshake */ | |
636 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); | |
637 | ||
638 | /* Unmask dfi_init_complete_en to uMCTL2 */ | |
639 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_DFIMISC, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); | |
640 | ||
641 | /* Ack */ | |
642 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); | |
643 | ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_SWSTAT, | |
644 | DDRCTRL_SWSTAT_SW_DONE_ACK, | |
645 | DDRCTRL_SWSTAT_SW_DONE_ACK); | |
646 | if (ret) | |
647 | hang(); | |
648 | ||
649 | /* Deactivate sw retention in PWR */ | |
650 | clrbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRRETEN); | |
651 | ||
652 | /* Enable PZQ cell (PUBL register) */ | |
653 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); | |
654 | ||
655 | /* Enable pad drivers */ | |
656 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); | |
657 | ||
658 | /* Enable command/address output driver */ | |
659 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); | |
660 | ||
661 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CKPDD_MASK); | |
662 | ||
663 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_CSPDD_MASK); | |
664 | ||
665 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); | |
666 | ||
667 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); | |
668 | ||
669 | /* Release latch */ | |
670 | setbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE); | |
671 | ||
672 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_ODTPDD_MASK); | |
673 | ||
674 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); | |
675 | ||
676 | clrbits_le32(STM32_DDRPHYC_BASE + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKEPDD_MASK); | |
677 | ||
678 | /* Remove selfrefresh */ | |
679 | clrbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW); | |
680 | ||
681 | /* Wait operating_mode == normal */ | |
682 | ret = secure_waitbits(STM32_DDRCTRL_BASE + DDRCTRL_STAT, | |
683 | DDRCTRL_STAT_OPERATING_MODE_MASK, | |
684 | DDRCTRL_STAT_OPERATING_MODE_NORMAL); | |
685 | if (ret) | |
686 | hang(); | |
687 | ||
688 | /* AXI ports are no longer blocked from taking transactions */ | |
689 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_0, DDRCTRL_PCTRL_N_PORT_EN); | |
690 | setbits_le32(STM32_DDRCTRL_BASE + DDRCTRL_PCTRL_1, DDRCTRL_PCTRL_N_PORT_EN); | |
691 | ||
692 | setbits_le32(STM32_RCC_BASE + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); | |
693 | } | |
694 | ||
695 | void __secure psci_system_suspend(u32 __always_unused function_id, | |
696 | u32 ep, u32 context_id) | |
697 | { | |
d6ae1839 | 698 | u32 saved_mcudivr, saved_pll3cr, saved_pll4cr, saved_mssckselr; |
b4910532 MV |
699 | u32 saved_pwrctl, reg; |
700 | ||
701 | /* Disable IO compensation */ | |
702 | ||
703 | /* Place current APSRC/ANSRC into RAPSRC/RANSRC */ | |
704 | reg = readl(STM32_SYSCFG_BASE + SYSCFG_CMPCR); | |
705 | reg >>= 8; | |
706 | reg &= 0xff << 16; | |
707 | reg |= SYSCFG_CMPCR_SW_CTRL; | |
708 | writel(reg, STM32_SYSCFG_BASE + SYSCFG_CMPCR); | |
709 | writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENCLRR); | |
710 | ||
711 | writel(RCC_MP_CIFR_WKUPF, STM32_RCC_BASE + RCC_MP_CIFR); | |
712 | setbits_le32(STM32_RCC_BASE + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); | |
713 | ||
714 | setbits_le32(STM32_PWR_BASE + PWR_MPUCR, | |
715 | PWR_MPUCR_CSSF | PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_PDDS); | |
716 | ||
d6ae1839 MV |
717 | saved_mcudivr = readl(STM32_RCC_BASE + RCC_MCUDIVR); |
718 | saved_pll3cr = readl(STM32_RCC_BASE + RCC_PLL3CR); | |
719 | saved_pll4cr = readl(STM32_RCC_BASE + RCC_PLL4CR); | |
720 | saved_mssckselr = readl(STM32_RCC_BASE + RCC_MSSCKSELR); | |
721 | ||
b4910532 MV |
722 | psci_v7_flush_dcache_all(); |
723 | ddr_sr_mode_ssr(&saved_pwrctl); | |
724 | ddr_sw_self_refresh_in(); | |
725 | setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN); | |
726 | writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR); | |
727 | ||
728 | /* Zzz, enter stop mode */ | |
729 | asm volatile( | |
730 | "isb\n" | |
731 | "dsb\n" | |
732 | "wfi\n"); | |
733 | ||
734 | writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); | |
735 | ddr_sw_self_refresh_exit(); | |
736 | ddr_sr_mode_restore(saved_pwrctl); | |
737 | ||
d6ae1839 MV |
738 | writel(saved_mcudivr, STM32_RCC_BASE + RCC_MCUDIVR); |
739 | writel(saved_pll3cr, STM32_RCC_BASE + RCC_PLL3CR); | |
740 | writel(saved_pll4cr, STM32_RCC_BASE + RCC_PLL4CR); | |
741 | writel(saved_mssckselr, STM32_RCC_BASE + RCC_MSSCKSELR); | |
742 | ||
b4910532 MV |
743 | writel(SYSCFG_CMPENR_MPUEN, STM32_SYSCFG_BASE + SYSCFG_CMPENSETR); |
744 | clrbits_le32(STM32_SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); | |
745 | } |