xref: /openbmc/linux/arch/arm/mach-omap2/sleep33xx.S (revision a9ff6961)
18a94cd7eSDave Gerlach/* SPDX-License-Identifier: GPL-2.0 */
28a94cd7eSDave Gerlach/*
38a94cd7eSDave Gerlach * Low level suspend code for AM33XX SoCs
48a94cd7eSDave Gerlach *
583bf6db0SAlexander A. Klimov * Copyright (C) 2012-2018 Texas Instruments Incorporated - https://www.ti.com/
68a94cd7eSDave Gerlach *	Dave Gerlach, Vaibhav Bedia
78a94cd7eSDave Gerlach */
88a94cd7eSDave Gerlach
98a94cd7eSDave Gerlach#include <linux/linkage.h>
1074655749SDave Gerlach#include <linux/platform_data/pm33xx.h>
118a94cd7eSDave Gerlach#include <linux/ti-emif-sram.h>
128a94cd7eSDave Gerlach#include <asm/assembler.h>
13*a9ff6961SLinus Walleij#include <asm/page.h>
148a94cd7eSDave Gerlach
158a94cd7eSDave Gerlach#include "iomap.h"
168a94cd7eSDave Gerlach#include "cm33xx.h"
17ccf4975dSMasahiro Yamada#include "pm-asm-offsets.h"
188a94cd7eSDave Gerlach
198a94cd7eSDave Gerlach#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED			0x00030000
208a94cd7eSDave Gerlach#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE			0x0003
218a94cd7eSDave Gerlach#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE			0x0002
228a94cd7eSDave Gerlach
2374655749SDave Gerlach/* replicated define because linux/bitops.h cannot be included in assembly */
2474655749SDave Gerlach#define BIT(nr)			(1 << (nr))
2574655749SDave Gerlach
268a94cd7eSDave Gerlach	.arm
273fe1ee40SStefan Agner	.arch armv7-a
288a94cd7eSDave Gerlach	.align 3
298a94cd7eSDave Gerlach
308a94cd7eSDave GerlachENTRY(am33xx_do_wfi)
318a94cd7eSDave Gerlach	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
328a94cd7eSDave Gerlach
3374655749SDave Gerlach	/* Save wfi_flags arg to data space */
3474655749SDave Gerlach	mov	r4, r0
3574655749SDave Gerlach	adr	r3, am33xx_pm_ro_sram_data
3674655749SDave Gerlach	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
3774655749SDave Gerlach	str	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]
3874655749SDave Gerlach
3974655749SDave Gerlach	/* Only flush cache is we know we are losing MPU context */
4074655749SDave Gerlach	tst	r4, #WFI_FLAG_FLUSH_CACHE
4174655749SDave Gerlach	beq	cache_skip_flush
4274655749SDave Gerlach
438a94cd7eSDave Gerlach	/*
448a94cd7eSDave Gerlach	 * Flush all data from the L1 and L2 data cache before disabling
458a94cd7eSDave Gerlach	 * SCTLR.C bit.
468a94cd7eSDave Gerlach	 */
478a94cd7eSDave Gerlach	ldr	r1, kernel_flush
488a94cd7eSDave Gerlach	blx	r1
498a94cd7eSDave Gerlach
508a94cd7eSDave Gerlach	/*
518a94cd7eSDave Gerlach	 * Clear the SCTLR.C bit to prevent further data cache
528a94cd7eSDave Gerlach	 * allocation. Clearing SCTLR.C would make all the data accesses
538a94cd7eSDave Gerlach	 * strongly ordered and would not hit the cache.
548a94cd7eSDave Gerlach	 */
558a94cd7eSDave Gerlach	mrc	p15, 0, r0, c1, c0, 0
568a94cd7eSDave Gerlach	bic	r0, r0, #(1 << 2)	@ Disable the C bit
578a94cd7eSDave Gerlach	mcr	p15, 0, r0, c1, c0, 0
588a94cd7eSDave Gerlach	isb
598a94cd7eSDave Gerlach
608a94cd7eSDave Gerlach	/*
618a94cd7eSDave Gerlach	 * Invalidate L1 and L2 data cache.
628a94cd7eSDave Gerlach	 */
638a94cd7eSDave Gerlach	ldr	r1, kernel_flush
648a94cd7eSDave Gerlach	blx	r1
658a94cd7eSDave Gerlach
6674655749SDave Gerlach	adr	r3, am33xx_pm_ro_sram_data
6774655749SDave Gerlach	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
6874655749SDave Gerlach	ldr	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]
6974655749SDave Gerlach
7074655749SDave Gerlachcache_skip_flush:
7174655749SDave Gerlach	/* Check if we want self refresh */
7274655749SDave Gerlach	tst	r4, #WFI_FLAG_SELF_REFRESH
7374655749SDave Gerlach	beq	emif_skip_enter_sr
7474655749SDave Gerlach
758a94cd7eSDave Gerlach	adr	r9, am33xx_emif_sram_table
768a94cd7eSDave Gerlach
778a94cd7eSDave Gerlach	ldr	r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
788a94cd7eSDave Gerlach	blx	r3
798a94cd7eSDave Gerlach
8074655749SDave Gerlachemif_skip_enter_sr:
8174655749SDave Gerlach	/* Only necessary if PER is losing context */
8274655749SDave Gerlach	tst	r4, #WFI_FLAG_SAVE_EMIF
8374655749SDave Gerlach	beq	emif_skip_save
8474655749SDave Gerlach
858a94cd7eSDave Gerlach	ldr	r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
868a94cd7eSDave Gerlach	blx	r3
878a94cd7eSDave Gerlach
8874655749SDave Gerlachemif_skip_save:
8974655749SDave Gerlach	/* Only can disable EMIF if we have entered self refresh */
9074655749SDave Gerlach	tst     r4, #WFI_FLAG_SELF_REFRESH
9174655749SDave Gerlach	beq     emif_skip_disable
9274655749SDave Gerlach
938a94cd7eSDave Gerlach	/* Disable EMIF */
948a94cd7eSDave Gerlach	ldr     r1, virt_emif_clkctrl
958a94cd7eSDave Gerlach	ldr     r2, [r1]
968a94cd7eSDave Gerlach	bic     r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
978a94cd7eSDave Gerlach	str     r2, [r1]
988a94cd7eSDave Gerlach
998a94cd7eSDave Gerlach	ldr	r1, virt_emif_clkctrl
1008a94cd7eSDave Gerlachwait_emif_disable:
1018a94cd7eSDave Gerlach	ldr	r2, [r1]
1028a94cd7eSDave Gerlach	mov	r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED
1038a94cd7eSDave Gerlach	cmp	r2, r3
1048a94cd7eSDave Gerlach	bne	wait_emif_disable
1058a94cd7eSDave Gerlach
10674655749SDave Gerlachemif_skip_disable:
10774655749SDave Gerlach	tst	r4, #WFI_FLAG_WAKE_M3
10874655749SDave Gerlach	beq	wkup_m3_skip
10974655749SDave Gerlach
1108a94cd7eSDave Gerlach	/*
1118a94cd7eSDave Gerlach	 * For the MPU WFI to be registered as an interrupt
1128a94cd7eSDave Gerlach	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
1138a94cd7eSDave Gerlach	 * to DISABLED
1148a94cd7eSDave Gerlach	 */
1158a94cd7eSDave Gerlach	ldr	r1, virt_mpu_clkctrl
1168a94cd7eSDave Gerlach	ldr	r2, [r1]
1178a94cd7eSDave Gerlach	bic	r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
1188a94cd7eSDave Gerlach	str	r2, [r1]
1198a94cd7eSDave Gerlach
12074655749SDave Gerlachwkup_m3_skip:
1218a94cd7eSDave Gerlach	/*
1228a94cd7eSDave Gerlach	 * Execute an ISB instruction to ensure that all of the
1238a94cd7eSDave Gerlach	 * CP15 register changes have been committed.
1248a94cd7eSDave Gerlach	 */
1258a94cd7eSDave Gerlach	isb
1268a94cd7eSDave Gerlach
1278a94cd7eSDave Gerlach	/*
1288a94cd7eSDave Gerlach	 * Execute a barrier instruction to ensure that all cache,
1298a94cd7eSDave Gerlach	 * TLB and branch predictor maintenance operations issued
1308a94cd7eSDave Gerlach	 * have completed.
1318a94cd7eSDave Gerlach	 */
1328a94cd7eSDave Gerlach	dsb
1338a94cd7eSDave Gerlach	dmb
1348a94cd7eSDave Gerlach
1358a94cd7eSDave Gerlach	/*
1368a94cd7eSDave Gerlach	 * Execute a WFI instruction and wait until the
1378a94cd7eSDave Gerlach	 * STANDBYWFI output is asserted to indicate that the
1388a94cd7eSDave Gerlach	 * CPU is in idle and low power state. CPU can specualatively
1398a94cd7eSDave Gerlach	 * prefetch the instructions so add NOPs after WFI. Thirteen
1408a94cd7eSDave Gerlach	 * NOPs as per Cortex-A8 pipeline.
1418a94cd7eSDave Gerlach	 */
1428a94cd7eSDave Gerlach	wfi
1438a94cd7eSDave Gerlach
1448a94cd7eSDave Gerlach	nop
1458a94cd7eSDave Gerlach	nop
1468a94cd7eSDave Gerlach	nop
1478a94cd7eSDave Gerlach	nop
1488a94cd7eSDave Gerlach	nop
1498a94cd7eSDave Gerlach	nop
1508a94cd7eSDave Gerlach	nop
1518a94cd7eSDave Gerlach	nop
1528a94cd7eSDave Gerlach	nop
1538a94cd7eSDave Gerlach	nop
1548a94cd7eSDave Gerlach	nop
1558a94cd7eSDave Gerlach	nop
1568a94cd7eSDave Gerlach	nop
1578a94cd7eSDave Gerlach
1588a94cd7eSDave Gerlach	/* We come here in case of an abort due to a late interrupt */
1598a94cd7eSDave Gerlach
1608a94cd7eSDave Gerlach	/* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
1618a94cd7eSDave Gerlach	ldr	r1, virt_mpu_clkctrl
1628a94cd7eSDave Gerlach	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
1638a94cd7eSDave Gerlach	str	r2, [r1]
1648a94cd7eSDave Gerlach
1658a94cd7eSDave Gerlach	/* Re-enable EMIF */
1668a94cd7eSDave Gerlach	ldr	r1, virt_emif_clkctrl
1678a94cd7eSDave Gerlach	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
1688a94cd7eSDave Gerlach	str	r2, [r1]
1698a94cd7eSDave Gerlachwait_emif_enable:
1708a94cd7eSDave Gerlach	ldr	r3, [r1]
1718a94cd7eSDave Gerlach	cmp	r2, r3
1728a94cd7eSDave Gerlach	bne	wait_emif_enable
1738a94cd7eSDave Gerlach
17474655749SDave Gerlach	/* Only necessary if PER is losing context */
17574655749SDave Gerlach	tst	r4, #WFI_FLAG_SELF_REFRESH
17674655749SDave Gerlach	beq	emif_skip_exit_sr_abt
1778a94cd7eSDave Gerlach
17874655749SDave Gerlach	adr	r9, am33xx_emif_sram_table
1798a94cd7eSDave Gerlach	ldr	r1, [r9, #EMIF_PM_ABORT_SR_OFFSET]
1808a94cd7eSDave Gerlach	blx	r1
1818a94cd7eSDave Gerlach
18274655749SDave Gerlachemif_skip_exit_sr_abt:
18374655749SDave Gerlach	tst	r4, #WFI_FLAG_FLUSH_CACHE
18474655749SDave Gerlach	beq	cache_skip_restore
18574655749SDave Gerlach
1868a94cd7eSDave Gerlach	/*
1878a94cd7eSDave Gerlach	 * Set SCTLR.C bit to allow data cache allocation
1888a94cd7eSDave Gerlach	 */
1898a94cd7eSDave Gerlach	mrc	p15, 0, r0, c1, c0, 0
1908a94cd7eSDave Gerlach	orr	r0, r0, #(1 << 2)	@ Enable the C bit
1918a94cd7eSDave Gerlach	mcr	p15, 0, r0, c1, c0, 0
1928a94cd7eSDave Gerlach	isb
1938a94cd7eSDave Gerlach
19474655749SDave Gerlachcache_skip_restore:
1958a94cd7eSDave Gerlach	/* Let the suspend code know about the abort */
1968a94cd7eSDave Gerlach	mov	r0, #1
1978a94cd7eSDave Gerlach	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
1988a94cd7eSDave GerlachENDPROC(am33xx_do_wfi)
1998a94cd7eSDave Gerlach
2008a94cd7eSDave Gerlach	.align
2018a94cd7eSDave GerlachENTRY(am33xx_resume_offset)
2028a94cd7eSDave Gerlach	.word . - am33xx_do_wfi
2038a94cd7eSDave Gerlach
2048a94cd7eSDave GerlachENTRY(am33xx_resume_from_deep_sleep)
2058a94cd7eSDave Gerlach	/* Re-enable EMIF */
2068a94cd7eSDave Gerlach	ldr	r0, phys_emif_clkctrl
2078a94cd7eSDave Gerlach	mov	r1, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
2088a94cd7eSDave Gerlach	str	r1, [r0]
2098a94cd7eSDave Gerlachwait_emif_enable1:
2108a94cd7eSDave Gerlach	ldr	r2, [r0]
2118a94cd7eSDave Gerlach	cmp	r1, r2
2128a94cd7eSDave Gerlach	bne	wait_emif_enable1
2138a94cd7eSDave Gerlach
2148a94cd7eSDave Gerlach	adr	r9, am33xx_emif_sram_table
2158a94cd7eSDave Gerlach
2168a94cd7eSDave Gerlach	ldr	r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET]
2178a94cd7eSDave Gerlach	blx	r1
2188a94cd7eSDave Gerlach
2198a94cd7eSDave Gerlach	ldr	r1, [r9, #EMIF_PM_EXIT_SR_OFFSET]
2208a94cd7eSDave Gerlach	blx	r1
2218a94cd7eSDave Gerlach
2228a94cd7eSDave Gerlachresume_to_ddr:
2238a94cd7eSDave Gerlach	/* We are back. Branch to the common CPU resume routine */
2248a94cd7eSDave Gerlach	mov	r0, #0
2258a94cd7eSDave Gerlach	ldr	pc, resume_addr
2268a94cd7eSDave GerlachENDPROC(am33xx_resume_from_deep_sleep)
2278a94cd7eSDave Gerlach
2288a94cd7eSDave Gerlach/*
2298a94cd7eSDave Gerlach * Local variables
2308a94cd7eSDave Gerlach */
2318a94cd7eSDave Gerlach	.align
2328a94cd7eSDave Gerlachkernel_flush:
2338a94cd7eSDave Gerlach	.word   v7_flush_dcache_all
2348a94cd7eSDave Gerlachvirt_mpu_clkctrl:
2358a94cd7eSDave Gerlach	.word	AM33XX_CM_MPU_MPU_CLKCTRL
2368a94cd7eSDave Gerlachvirt_emif_clkctrl:
2378a94cd7eSDave Gerlach	.word	AM33XX_CM_PER_EMIF_CLKCTRL
2388a94cd7eSDave Gerlachphys_emif_clkctrl:
2398a94cd7eSDave Gerlach	.word	(AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
2408a94cd7eSDave Gerlach		AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)
2418a94cd7eSDave Gerlach
2428a94cd7eSDave Gerlach.align 3
2438a94cd7eSDave Gerlach/* DDR related defines */
2448a94cd7eSDave Gerlacham33xx_emif_sram_table:
2458a94cd7eSDave Gerlach	.space EMIF_PM_FUNCTIONS_SIZE
2468a94cd7eSDave Gerlach
2478a94cd7eSDave GerlachENTRY(am33xx_pm_sram)
2488a94cd7eSDave Gerlach	.word am33xx_do_wfi
2498a94cd7eSDave Gerlach	.word am33xx_do_wfi_sz
2508a94cd7eSDave Gerlach	.word am33xx_resume_offset
2518a94cd7eSDave Gerlach	.word am33xx_emif_sram_table
2528a94cd7eSDave Gerlach	.word am33xx_pm_ro_sram_data
2538a94cd7eSDave Gerlach
2548c5a916fSKeerthyresume_addr:
2558c5a916fSKeerthy.word  cpu_resume - PAGE_OFFSET + 0x80000000
2568c5a916fSKeerthy
2578a94cd7eSDave Gerlach.align 3
2588a94cd7eSDave GerlachENTRY(am33xx_pm_ro_sram_data)
2598a94cd7eSDave Gerlach	.space AMX3_PM_RO_SRAM_DATA_SIZE
2608a94cd7eSDave Gerlach
2618a94cd7eSDave GerlachENTRY(am33xx_do_wfi_sz)
2628a94cd7eSDave Gerlach	.word	. - am33xx_do_wfi
263