Commit | Line | Data |
---|---|---|
41d37e61 DG |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
3 | * Low level suspend code for AM43XX SoCs | |
4 | * | |
5 | * Copyright (C) 2013-2018 Texas Instruments Incorporated - http://www.ti.com/ | |
6 | * Dave Gerlach, Vaibhav Bedia | |
7 | */ | |
8 | ||
9 | #include <linux/linkage.h> | |
10 | #include <linux/ti-emif-sram.h> | |
74655749 | 11 | #include <linux/platform_data/pm33xx.h> |
41d37e61 DG |
12 | #include <asm/assembler.h> |
13 | #include <asm/hardware/cache-l2x0.h> | |
14 | #include <asm/memory.h> | |
15 | ||
16 | #include "cm33xx.h" | |
17 | #include "common.h" | |
18 | #include "iomap.h" | |
19 | #include "omap-secure.h" | |
20 | #include "omap44xx.h" | |
ccf4975d | 21 | #include "pm-asm-offsets.h" |
41d37e61 DG |
22 | #include "prm33xx.h" |
23 | #include "prcm43xx.h" | |
24 | ||
74655749 DG |
25 | /* replicated define because linux/bitops.h cannot be included in assembly */ |
26 | #define BIT(nr) (1 << (nr)) | |
27 | ||
41d37e61 DG |
28 | #define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED 0x00030000 |
29 | #define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE 0x0003 | |
30 | #define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE 0x0002 | |
31 | ||
32 | #define AM43XX_EMIF_POWEROFF_ENABLE 0x1 | |
33 | #define AM43XX_EMIF_POWEROFF_DISABLE 0x0 | |
34 | ||
35 | #define AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP 0x1 | |
36 | #define AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO 0x3 | |
37 | ||
38 | #define AM43XX_CM_BASE 0x44DF0000 | |
39 | ||
40 | #define AM43XX_CM_REGADDR(inst, reg) \ | |
41 | AM33XX_L4_WK_IO_ADDRESS(AM43XX_CM_BASE + (inst) + (reg)) | |
42 | ||
43 | #define AM43XX_CM_MPU_CLKSTCTRL AM43XX_CM_REGADDR(AM43XX_CM_MPU_INST, \ | |
44 | AM43XX_CM_MPU_MPU_CDOFFS) | |
45 | #define AM43XX_CM_MPU_MPU_CLKCTRL AM43XX_CM_REGADDR(AM43XX_CM_MPU_INST, \ | |
46 | AM43XX_CM_MPU_MPU_CLKCTRL_OFFSET) | |
47 | #define AM43XX_CM_PER_EMIF_CLKCTRL AM43XX_CM_REGADDR(AM43XX_CM_PER_INST, \ | |
48 | AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET) | |
49 | #define AM43XX_PRM_EMIF_CTRL_OFFSET 0x0030 | |
50 | ||
8c5a916f K |
51 | #define RTC_SECONDS_REG 0x0 |
52 | #define RTC_PMIC_REG 0x98 | |
53 | #define RTC_PMIC_POWER_EN BIT(16) | |
54 | #define RTC_PMIC_EXT_WAKEUP_STS BIT(12) | |
55 | #define RTC_PMIC_EXT_WAKEUP_POL BIT(4) | |
56 | #define RTC_PMIC_EXT_WAKEUP_EN BIT(0) | |
57 | ||
41d37e61 | 58 | .arm |
3fe1ee40 SA |
59 | .arch armv7-a |
60 | .arch_extension sec | |
41d37e61 DG |
61 | .align 3 |
62 | ||
63 | ENTRY(am43xx_do_wfi) | |
64 | stmfd sp!, {r4 - r11, lr} @ save registers on stack | |
65 | ||
74655749 DG |
66 | /* Save wfi_flags arg to data space */ |
67 | mov r4, r0 | |
68 | adr r3, am43xx_pm_ro_sram_data | |
69 | ldr r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] | |
70 | str r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET] | |
71 | ||
03de3727 | 72 | #ifdef CONFIG_CACHE_L2X0 |
41d37e61 DG |
73 | /* Retrieve l2 cache virt address BEFORE we shut off EMIF */ |
74 | ldr r1, get_l2cache_base | |
75 | blx r1 | |
76 | mov r8, r0 | |
03de3727 | 77 | #endif |
41d37e61 | 78 | |
74655749 DG |
79 | /* Only flush cache is we know we are losing MPU context */ |
80 | tst r4, #WFI_FLAG_FLUSH_CACHE | |
81 | beq cache_skip_flush | |
82 | ||
41d37e61 DG |
83 | /* |
84 | * Flush all data from the L1 and L2 data cache before disabling | |
85 | * SCTLR.C bit. | |
86 | */ | |
87 | ldr r1, kernel_flush | |
88 | blx r1 | |
89 | ||
90 | /* | |
91 | * Clear the SCTLR.C bit to prevent further data cache | |
92 | * allocation. Clearing SCTLR.C would make all the data accesses | |
93 | * strongly ordered and would not hit the cache. | |
94 | */ | |
95 | mrc p15, 0, r0, c1, c0, 0 | |
96 | bic r0, r0, #(1 << 2) @ Disable the C bit | |
97 | mcr p15, 0, r0, c1, c0, 0 | |
98 | isb | |
99 | dsb | |
100 | ||
101 | /* | |
102 | * Invalidate L1 and L2 data cache. | |
103 | */ | |
104 | ldr r1, kernel_flush | |
105 | blx r1 | |
106 | ||
107 | #ifdef CONFIG_CACHE_L2X0 | |
108 | /* | |
109 | * Clean and invalidate the L2 cache. | |
110 | */ | |
111 | #ifdef CONFIG_PL310_ERRATA_727915 | |
112 | mov r0, #0x03 | |
113 | mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX | |
114 | dsb | |
115 | smc #0 | |
116 | dsb | |
117 | #endif | |
118 | mov r0, r8 | |
119 | adr r4, am43xx_pm_ro_sram_data | |
120 | ldr r3, [r4, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] | |
121 | ||
122 | mov r2, r0 | |
123 | ldr r0, [r2, #L2X0_AUX_CTRL] | |
124 | str r0, [r3, #AMX3_PM_L2_AUX_CTRL_VAL_OFFSET] | |
125 | ldr r0, [r2, #L310_PREFETCH_CTRL] | |
126 | str r0, [r3, #AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET] | |
127 | ||
128 | ldr r0, l2_val | |
129 | str r0, [r2, #L2X0_CLEAN_INV_WAY] | |
130 | wait: | |
131 | ldr r0, [r2, #L2X0_CLEAN_INV_WAY] | |
132 | ldr r1, l2_val | |
133 | ands r0, r0, r1 | |
134 | bne wait | |
135 | #ifdef CONFIG_PL310_ERRATA_727915 | |
136 | mov r0, #0x00 | |
137 | mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX | |
138 | dsb | |
139 | smc #0 | |
140 | dsb | |
141 | #endif | |
142 | l2x_sync: | |
143 | mov r0, r8 | |
144 | mov r2, r0 | |
145 | mov r0, #0x0 | |
146 | str r0, [r2, #L2X0_CACHE_SYNC] | |
147 | sync: | |
148 | ldr r0, [r2, #L2X0_CACHE_SYNC] | |
149 | ands r0, r0, #0x1 | |
150 | bne sync | |
151 | #endif | |
152 | ||
74655749 DG |
153 | /* Restore wfi_flags */ |
154 | adr r3, am43xx_pm_ro_sram_data | |
155 | ldr r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET] | |
156 | ldr r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET] | |
157 | ||
158 | cache_skip_flush: | |
8c5a916f K |
159 | /* |
160 | * If we are trying to enter RTC+DDR mode we must perform | |
161 | * a read from the rtc address space to ensure translation | |
162 | * presence in the TLB to avoid page table walk after DDR | |
163 | * is unavailable. | |
164 | */ | |
165 | tst r4, #WFI_FLAG_RTC_ONLY | |
166 | beq skip_rtc_va_refresh | |
167 | ||
168 | adr r3, am43xx_pm_ro_sram_data | |
169 | ldr r1, [r3, #AMX3_PM_RTC_BASE_VIRT_OFFSET] | |
170 | ldr r0, [r1] | |
171 | ||
172 | skip_rtc_va_refresh: | |
74655749 DG |
173 | /* Check if we want self refresh */ |
174 | tst r4, #WFI_FLAG_SELF_REFRESH | |
175 | beq emif_skip_enter_sr | |
176 | ||
41d37e61 DG |
177 | adr r9, am43xx_emif_sram_table |
178 | ||
179 | ldr r3, [r9, #EMIF_PM_ENTER_SR_OFFSET] | |
180 | blx r3 | |
181 | ||
74655749 DG |
182 | emif_skip_enter_sr: |
183 | /* Only necessary if PER is losing context */ | |
184 | tst r4, #WFI_FLAG_SAVE_EMIF | |
185 | beq emif_skip_save | |
186 | ||
41d37e61 | 187 | ldr r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET] |
74655749 DG |
188 | blx r3 |
189 | ||
190 | emif_skip_save: | |
191 | /* Only can disable EMIF if we have entered self refresh */ | |
192 | tst r4, #WFI_FLAG_SELF_REFRESH | |
193 | beq emif_skip_disable | |
41d37e61 DG |
194 | |
195 | /* Disable EMIF */ | |
196 | ldr r1, am43xx_virt_emif_clkctrl | |
197 | ldr r2, [r1] | |
198 | bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE | |
199 | str r2, [r1] | |
200 | ||
201 | wait_emif_disable: | |
202 | ldr r2, [r1] | |
203 | mov r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED | |
204 | cmp r2, r3 | |
205 | bne wait_emif_disable | |
206 | ||
74655749 | 207 | emif_skip_disable: |
8c5a916f K |
208 | tst r4, #WFI_FLAG_RTC_ONLY |
209 | beq skip_rtc_only | |
210 | ||
211 | adr r3, am43xx_pm_ro_sram_data | |
212 | ldr r1, [r3, #AMX3_PM_RTC_BASE_VIRT_OFFSET] | |
213 | ||
214 | ldr r0, [r1, #RTC_PMIC_REG] | |
215 | orr r0, r0, #RTC_PMIC_POWER_EN | |
216 | orr r0, r0, #RTC_PMIC_EXT_WAKEUP_STS | |
217 | orr r0, r0, #RTC_PMIC_EXT_WAKEUP_EN | |
218 | orr r0, r0, #RTC_PMIC_EXT_WAKEUP_POL | |
219 | str r0, [r1, #RTC_PMIC_REG] | |
220 | ldr r0, [r1, #RTC_PMIC_REG] | |
221 | /* Wait for 2 seconds to lose power */ | |
222 | mov r3, #2 | |
223 | ldr r2, [r1, #RTC_SECONDS_REG] | |
224 | rtc_loop: | |
225 | ldr r0, [r1, #RTC_SECONDS_REG] | |
226 | cmp r0, r2 | |
227 | beq rtc_loop | |
228 | mov r2, r0 | |
229 | subs r3, r3, #1 | |
230 | bne rtc_loop | |
231 | ||
232 | b re_enable_emif | |
233 | ||
234 | skip_rtc_only: | |
235 | ||
74655749 DG |
236 | tst r4, #WFI_FLAG_WAKE_M3 |
237 | beq wkup_m3_skip | |
238 | ||
41d37e61 DG |
239 | /* |
240 | * For the MPU WFI to be registered as an interrupt | |
241 | * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set | |
242 | * to DISABLED | |
243 | */ | |
244 | ldr r1, am43xx_virt_mpu_clkctrl | |
245 | ldr r2, [r1] | |
246 | bic r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE | |
247 | str r2, [r1] | |
248 | ||
249 | /* | |
250 | * Put MPU CLKDM to SW_SLEEP | |
251 | */ | |
252 | ldr r1, am43xx_virt_mpu_clkstctrl | |
253 | mov r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP | |
254 | str r2, [r1] | |
255 | ||
74655749 | 256 | wkup_m3_skip: |
41d37e61 DG |
257 | /* |
258 | * Execute a barrier instruction to ensure that all cache, | |
259 | * TLB and branch predictor maintenance operations issued | |
260 | * have completed. | |
261 | */ | |
262 | dsb | |
263 | dmb | |
264 | ||
265 | /* | |
266 | * Execute a WFI instruction and wait until the | |
267 | * STANDBYWFI output is asserted to indicate that the | |
268 | * CPU is in idle and low power state. CPU can specualatively | |
269 | * prefetch the instructions so add NOPs after WFI. Sixteen | |
270 | * NOPs as per Cortex-A9 pipeline. | |
271 | */ | |
272 | wfi | |
273 | ||
274 | nop | |
275 | nop | |
276 | nop | |
277 | nop | |
278 | nop | |
279 | nop | |
280 | nop | |
281 | nop | |
282 | nop | |
283 | nop | |
284 | nop | |
285 | nop | |
286 | nop | |
287 | nop | |
288 | nop | |
289 | nop | |
290 | ||
291 | /* We come here in case of an abort due to a late interrupt */ | |
292 | ldr r1, am43xx_virt_mpu_clkstctrl | |
293 | mov r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO | |
294 | str r2, [r1] | |
295 | ||
296 | /* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */ | |
297 | ldr r1, am43xx_virt_mpu_clkctrl | |
298 | mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE | |
299 | str r2, [r1] | |
300 | ||
8c5a916f | 301 | re_enable_emif: |
41d37e61 DG |
302 | /* Re-enable EMIF */ |
303 | ldr r1, am43xx_virt_emif_clkctrl | |
304 | mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE | |
305 | str r2, [r1] | |
306 | wait_emif_enable: | |
307 | ldr r3, [r1] | |
308 | cmp r2, r3 | |
309 | bne wait_emif_enable | |
310 | ||
74655749 DG |
311 | tst r4, #WFI_FLAG_FLUSH_CACHE |
312 | beq cache_skip_restore | |
313 | ||
41d37e61 DG |
314 | /* |
315 | * Set SCTLR.C bit to allow data cache allocation | |
316 | */ | |
317 | mrc p15, 0, r0, c1, c0, 0 | |
318 | orr r0, r0, #(1 << 2) @ Enable the C bit | |
319 | mcr p15, 0, r0, c1, c0, 0 | |
320 | isb | |
321 | ||
74655749 DG |
322 | cache_skip_restore: |
323 | /* Only necessary if PER is losing context */ | |
324 | tst r4, #WFI_FLAG_SELF_REFRESH | |
325 | beq emif_skip_exit_sr_abt | |
326 | ||
327 | adr r9, am43xx_emif_sram_table | |
328 | ldr r1, [r9, #EMIF_PM_ABORT_SR_OFFSET] | |
329 | blx r1 | |
41d37e61 | 330 | |
74655749 | 331 | emif_skip_exit_sr_abt: |
41d37e61 DG |
332 | /* Let the suspend code know about the abort */ |
333 | mov r0, #1 | |
334 | ldmfd sp!, {r4 - r11, pc} @ restore regs and return | |
335 | ENDPROC(am43xx_do_wfi) | |
336 | ||
337 | .align | |
338 | ENTRY(am43xx_resume_offset) | |
339 | .word . - am43xx_do_wfi | |
340 | ||
341 | ENTRY(am43xx_resume_from_deep_sleep) | |
342 | /* Set MPU CLKSTCTRL to HW AUTO so that CPUidle works properly */ | |
343 | ldr r1, am43xx_virt_mpu_clkstctrl | |
344 | mov r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO | |
345 | str r2, [r1] | |
346 | ||
347 | /* For AM43xx, use EMIF power down until context is restored */ | |
348 | ldr r2, am43xx_phys_emif_poweroff | |
349 | mov r1, #AM43XX_EMIF_POWEROFF_ENABLE | |
350 | str r1, [r2, #0x0] | |
351 | ||
352 | /* Re-enable EMIF */ | |
353 | ldr r1, am43xx_phys_emif_clkctrl | |
354 | mov r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE | |
355 | str r2, [r1] | |
356 | wait_emif_enable1: | |
357 | ldr r3, [r1] | |
358 | cmp r2, r3 | |
359 | bne wait_emif_enable1 | |
360 | ||
361 | adr r9, am43xx_emif_sram_table | |
362 | ||
363 | ldr r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET] | |
364 | blx r1 | |
365 | ||
366 | ldr r1, [r9, #EMIF_PM_EXIT_SR_OFFSET] | |
367 | blx r1 | |
368 | ||
369 | ldr r2, am43xx_phys_emif_poweroff | |
370 | mov r1, #AM43XX_EMIF_POWEROFF_DISABLE | |
371 | str r1, [r2, #0x0] | |
372 | ||
11140cc4 DG |
373 | ldr r1, [r9, #EMIF_PM_RUN_HW_LEVELING] |
374 | blx r1 | |
375 | ||
41d37e61 DG |
376 | #ifdef CONFIG_CACHE_L2X0 |
377 | ldr r2, l2_cache_base | |
378 | ldr r0, [r2, #L2X0_CTRL] | |
379 | and r0, #0x0f | |
380 | cmp r0, #1 | |
381 | beq skip_l2en @ Skip if already enabled | |
382 | ||
383 | adr r4, am43xx_pm_ro_sram_data | |
384 | ldr r3, [r4, #AMX3_PM_RO_SRAM_DATA_PHYS_OFFSET] | |
385 | ldr r0, [r3, #AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET] | |
386 | ||
387 | ldr r12, l2_smc1 | |
388 | dsb | |
389 | smc #0 | |
390 | dsb | |
391 | set_aux_ctrl: | |
392 | ldr r0, [r3, #AMX3_PM_L2_AUX_CTRL_VAL_OFFSET] | |
393 | ldr r12, l2_smc2 | |
394 | dsb | |
395 | smc #0 | |
396 | dsb | |
397 | ||
398 | /* L2 invalidate on resume */ | |
399 | ldr r0, l2_val | |
400 | ldr r2, l2_cache_base | |
401 | str r0, [r2, #L2X0_INV_WAY] | |
402 | wait2: | |
403 | ldr r0, [r2, #L2X0_INV_WAY] | |
404 | ldr r1, l2_val | |
405 | ands r0, r0, r1 | |
406 | bne wait2 | |
407 | #ifdef CONFIG_PL310_ERRATA_727915 | |
408 | mov r0, #0x00 | |
409 | mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX | |
410 | dsb | |
411 | smc #0 | |
412 | dsb | |
413 | #endif | |
414 | l2x_sync2: | |
415 | ldr r2, l2_cache_base | |
416 | mov r0, #0x0 | |
417 | str r0, [r2, #L2X0_CACHE_SYNC] | |
418 | sync2: | |
419 | ldr r0, [r2, #L2X0_CACHE_SYNC] | |
420 | ands r0, r0, #0x1 | |
421 | bne sync2 | |
422 | ||
423 | mov r0, #0x1 | |
424 | ldr r12, l2_smc3 | |
425 | dsb | |
426 | smc #0 | |
427 | dsb | |
428 | #endif | |
429 | skip_l2en: | |
430 | /* We are back. Branch to the common CPU resume routine */ | |
431 | mov r0, #0 | |
432 | ldr pc, resume_addr | |
433 | ENDPROC(am43xx_resume_from_deep_sleep) | |
434 | ||
435 | /* | |
436 | * Local variables | |
437 | */ | |
438 | .align | |
41d37e61 DG |
439 | kernel_flush: |
440 | .word v7_flush_dcache_all | |
441 | ddr_start: | |
442 | .word PAGE_OFFSET | |
443 | ||
444 | am43xx_phys_emif_poweroff: | |
445 | .word (AM43XX_CM_BASE + AM43XX_PRM_DEVICE_INST + \ | |
446 | AM43XX_PRM_EMIF_CTRL_OFFSET) | |
447 | am43xx_virt_mpu_clkstctrl: | |
448 | .word (AM43XX_CM_MPU_CLKSTCTRL) | |
449 | am43xx_virt_mpu_clkctrl: | |
450 | .word (AM43XX_CM_MPU_MPU_CLKCTRL) | |
451 | am43xx_virt_emif_clkctrl: | |
452 | .word (AM43XX_CM_PER_EMIF_CLKCTRL) | |
453 | am43xx_phys_emif_clkctrl: | |
454 | .word (AM43XX_CM_BASE + AM43XX_CM_PER_INST + \ | |
455 | AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET) | |
456 | ||
03de3727 | 457 | #ifdef CONFIG_CACHE_L2X0 |
41d37e61 | 458 | /* L2 cache related defines for AM437x */ |
03de3727 AB |
459 | get_l2cache_base: |
460 | .word omap4_get_l2cache_base | |
41d37e61 DG |
461 | l2_cache_base: |
462 | .word OMAP44XX_L2CACHE_BASE | |
463 | l2_smc1: | |
464 | .word OMAP4_MON_L2X0_PREFETCH_INDEX | |
465 | l2_smc2: | |
466 | .word OMAP4_MON_L2X0_AUXCTRL_INDEX | |
467 | l2_smc3: | |
468 | .word OMAP4_MON_L2X0_CTRL_INDEX | |
469 | l2_val: | |
470 | .word 0xffff | |
03de3727 | 471 | #endif |
41d37e61 DG |
472 | |
473 | .align 3 | |
474 | /* DDR related defines */ | |
475 | ENTRY(am43xx_emif_sram_table) | |
476 | .space EMIF_PM_FUNCTIONS_SIZE | |
477 | ||
478 | ENTRY(am43xx_pm_sram) | |
479 | .word am43xx_do_wfi | |
480 | .word am43xx_do_wfi_sz | |
481 | .word am43xx_resume_offset | |
482 | .word am43xx_emif_sram_table | |
483 | .word am43xx_pm_ro_sram_data | |
484 | ||
8c5a916f K |
485 | resume_addr: |
486 | .word cpu_resume - PAGE_OFFSET + 0x80000000 | |
41d37e61 DG |
487 | .align 3 |
488 | ||
489 | ENTRY(am43xx_pm_ro_sram_data) | |
490 | .space AMX3_PM_RO_SRAM_DATA_SIZE | |
491 | ||
492 | ENTRY(am43xx_do_wfi_sz) | |
493 | .word . - am43xx_do_wfi |