xref: /optee_os/core/drivers/pm/sam/pm_suspend.S (revision f73055a13ef9d3f6900453c7ab16d0b8e721b17d)
115300b40SClément Léger/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
215300b40SClément Léger/*
3dc0db863SClément Léger * This file was imported from Linux arch/arm/mach-at91/pm_suspend.S and
4dc0db863SClément Léger * relicensed with dual GPL-2.0/BSD-2-Clause with Microchip agreement.
5dc0db863SClément Léger *
615300b40SClément Léger * Copyright (c) 2021, Microchip
715300b40SClément Léger */
815300b40SClément Léger
915300b40SClément Léger#include <arm.h>
1015300b40SClément Léger#include <arm32_macros.S>
1115300b40SClément Léger#include <asm.S>
1215300b40SClément Léger#include <at91_pmc.h>
139ba91637STony Han#ifdef CFG_SAMA7G5
149ba91637STony Han#include <drivers/sam/sama7-ddr.h>
159ba91637STony Han#else
1615300b40SClément Léger#include <drivers/sam/at91_ddr.h>
179ba91637STony Han#endif
1815300b40SClément Léger#include <generated/pm-defines.h>
1915300b40SClément Léger
2015300b40SClément Léger#include "at91_pm.h"
2115300b40SClément Léger
2215300b40SClément Léger#define	SRAMC_SELF_FRESH_ACTIVE		0x01
2315300b40SClément Léger#define	SRAMC_SELF_FRESH_EXIT		0x00
2415300b40SClément Léger
2515300b40SClément Légerpmc	.req	r0
2615300b40SClément Légertmp1	.req	r4
2715300b40SClément Légertmp2	.req	r5
2815300b40SClément Légertmp3	.req	r6
2915300b40SClément Léger
3015300b40SClément Léger/*
3115300b40SClément Léger * Wait until master clock is ready (after switching master clock source)
32b22418ebSTony Han * @r_mckid:	register holding master clock identifier
33b22418ebSTony Han *
34b22418ebSTony Han * Side effects: overwrites tmp1
3515300b40SClément Léger */
36b22418ebSTony Han.macro wait_mckrdy r_mckid
37b22418ebSTony Han#ifdef CFG_SAMA7G5
38b22418ebSTony Han	cmp	\r_mckid, #0
39b22418ebSTony Han	beq	1f
40b22418ebSTony Han2:	ldr	tmp1, [pmc, #AT91_PMC_SR]
41b22418ebSTony Han	tst	tmp1, #AT91_PMC_MCKXRDY
42b22418ebSTony Han	beq	2b
43b22418ebSTony Han	b	3f
44b22418ebSTony Han#endif
4515300b40SClément Léger1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
4615300b40SClément Léger	tst	tmp1, #AT91_PMC_MCKRDY
4715300b40SClément Léger	beq	1b
48b22418ebSTony Han3:
4915300b40SClément Léger.endm
5015300b40SClément Léger
5115300b40SClément Léger/*
5215300b40SClément Léger * Wait until master oscillator has stabilized.
5315300b40SClément Léger */
5415300b40SClément Léger.macro wait_moscrdy
5515300b40SClément Léger1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
5615300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCS
5715300b40SClément Léger	beq	1b
5815300b40SClément Léger.endm
5915300b40SClément Léger
6015300b40SClément Léger/*
6115300b40SClément Léger * Wait for main oscillator selection is done
6215300b40SClément Léger */
6315300b40SClément Léger.macro wait_moscsels
6415300b40SClément Léger1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
6515300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCSELS
6615300b40SClément Léger	beq	1b
6715300b40SClément Léger.endm
6815300b40SClément Léger
6915300b40SClément Léger/*
7015300b40SClément Léger * Put the processor to enter the idle state
7115300b40SClément Léger */
7215300b40SClément Léger.macro at91_cpu_idle
7315300b40SClément Léger
7415300b40SClément Léger	mov	tmp1, #AT91_PMC_PCK
7515300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_SCDR]
7615300b40SClément Léger
7715300b40SClément Léger	dsb
7815300b40SClément Léger
7915300b40SClément Léger	wfi		@ Wait For Interrupt
8015300b40SClément Léger
8115300b40SClément Léger.endm
8215300b40SClément Léger
8315300b40SClément Léger.section .text.psci.suspend
8415300b40SClément Léger
8515300b40SClément Léger.arm
8615300b40SClément Léger
879ba91637STony Han#ifdef CFG_SAMA7G5
889ba91637STony Han/*
899ba91637STony Han * Enable self-refresh
909ba91637STony Han *
919ba91637STony Han * Side effects: overwrites tmp1, tmp2, tmp3
929ba91637STony Han */
939ba91637STony Han.macro at91_sramc_self_refresh_ena
949ba91637STony Han	dsb
959ba91637STony Han
969ba91637STony Han	ldr	tmp2, .sramc_base
979ba91637STony Han
989ba91637STony Han	/* Disable all AXI ports. */
999ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_0]
1009ba91637STony Han	bic	tmp1, tmp1, #0x1
1019ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_0]
1029ba91637STony Han
1039ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_1]
1049ba91637STony Han	bic	tmp1, tmp1, #0x1
1059ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_1]
1069ba91637STony Han
1079ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_2]
1089ba91637STony Han	bic	tmp1, tmp1, #0x1
1099ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_2]
1109ba91637STony Han
1119ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_3]
1129ba91637STony Han	bic	tmp1, tmp1, #0x1
1139ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_3]
1149ba91637STony Han
1159ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_4]
1169ba91637STony Han	bic	tmp1, tmp1, #0x1
1179ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_4]
1189ba91637STony Han
1199ba91637STony Hansr_ena_1:
1209ba91637STony Han	/* Wait for all ports to disable. */
1219ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PSTAT]
1229ba91637STony Han	ldr	tmp3, =UDDRC_PSTAT_ALL_PORTS
1239ba91637STony Han	tst	tmp1, tmp3
1249ba91637STony Han	bne	sr_ena_1
1259ba91637STony Han
1269ba91637STony Han	/* Switch to self-refresh. */
1279ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PWRCTL]
1289ba91637STony Han	orr	tmp1, tmp1, #UDDRC_PWRCTL_SELFREF_SW
1299ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PWRCTL]
1309ba91637STony Han
1319ba91637STony Hansr_ena_2:
1329ba91637STony Han	/* Wait for self-refresh enter. */
1339ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_STAT]
1349ba91637STony Han	bic	tmp1, tmp1, #~UDDRC_STAT_SELFREF_TYPE_MSK
1359ba91637STony Han	cmp	tmp1, #UDDRC_STAT_SELFREF_TYPE_SW
1369ba91637STony Han	bne	sr_ena_2
1379ba91637STony Han
1389ba91637STony Han	ldr	tmp2, .sramc_phy_base
1399ba91637STony Han
1409ba91637STony Han	/* Disable DX DLLs for non-backup modes. */
1419ba91637STony Han	ldr	tmp1, .pm_mode
1429ba91637STony Han	cmp	tmp1, #AT91_PM_BACKUP
1439ba91637STony Han	beq	sr_ena_3
1449ba91637STony Han
1459ba91637STony Han	/* Do not soft reset the AC DLL. */
1469ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_ACDLLCR]
1479ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_ACDLLCR_DLLSRST
1489ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_ACDLLCR]
1499ba91637STony Han
1509ba91637STony Han	/* Disable DX DLLs. */
1519ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DX0DLLCR]
1529ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
1539ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DX0DLLCR]
1549ba91637STony Han
1559ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DX1DLLCR]
1569ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
1579ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DX1DLLCR]
1589ba91637STony Han
1599ba91637STony Hansr_ena_3:
1609ba91637STony Han	/* Power down DDR PHY data receivers. */
1619ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DXCCR]
1629ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_DXCCR_DXPDR
1639ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DXCCR]
1649ba91637STony Han
1659ba91637STony Han	/* Power down ADDR/CMD IO. */
1669ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_ACIOCR]
1679ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_ACIORC_ACPDD
1689ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_ACIOCR_CKPDD_CK0
1699ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_ACIOCR_CSPDD_CS0
1709ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_ACIOCR]
1719ba91637STony Han
1729ba91637STony Han	/* Power down ODT. */
1739ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DSGCR]
1749ba91637STony Han	orr	tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
1759ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DSGCR]
1769ba91637STony Han.endm
1779ba91637STony Han
1789ba91637STony Han/*
1799ba91637STony Han * Disable self-refresh
1809ba91637STony Han *
1819ba91637STony Han * Side effects: overwrites tmp1, tmp2
1829ba91637STony Han */
1839ba91637STony Han.macro at91_sramc_self_refresh_dis
1849ba91637STony Han	ldr	tmp2, .sramc_phy_base
1859ba91637STony Han
1869ba91637STony Han	/* Power up DDR PHY data receivers. */
1879ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DXCCR]
1889ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_DXCCR_DXPDR
1899ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DXCCR]
1909ba91637STony Han
1919ba91637STony Han	/* Power up the output of CK and CS pins. */
1929ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_ACIOCR]
1939ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_ACIORC_ACPDD
1949ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_ACIOCR_CKPDD_CK0
1959ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_ACIOCR_CSPDD_CS0
1969ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_ACIOCR]
1979ba91637STony Han
1989ba91637STony Han	/* Power up ODT. */
1999ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DSGCR]
2009ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
2019ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DSGCR]
2029ba91637STony Han
2039ba91637STony Han	/* Enable DX DLLs. */
2049ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DX0DLLCR]
2059ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
2069ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DX0DLLCR]
2079ba91637STony Han
2089ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_DX1DLLCR]
2099ba91637STony Han	bic	tmp1, tmp1, #DDR3PHY_DXDLLCR_DLLDIS
2109ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_DX1DLLCR]
2119ba91637STony Han
2129ba91637STony Han	ldr	tmp2, .sramc_base
2139ba91637STony Han
2149ba91637STony Han	/* Enable quasi-dynamic programming. */
2159ba91637STony Han	mov	tmp1, #0
2169ba91637STony Han	str	tmp1, [tmp2, #UDDRC_SWCTRL]
2179ba91637STony Han
2189ba91637STony Han	/* De-assert SDRAM initialization. */
2199ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_DFIMISC]
2209ba91637STony Han	bic	tmp1, tmp1, #UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN
2219ba91637STony Han	str	tmp1, [tmp2, #UDDRC_DFIMISC]
2229ba91637STony Han
2239ba91637STony Han	/* Quasi-dynamic programming done. */
2249ba91637STony Han	mov	tmp1, #UDDRC_SWCTRL_SW_DONE
2259ba91637STony Han	str	tmp1, [tmp2, #UDDRC_SWCTRL]
2269ba91637STony Han
2279ba91637STony Hansr_dis_1:
2289ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_SWSTAT]
2299ba91637STony Han	tst	tmp1, #UDDRC_SWSTAT_SW_DONE_ACK
2309ba91637STony Han	beq	sr_dis_1
2319ba91637STony Han
2329ba91637STony Han	ldr	tmp2, .sramc_phy_base
2339ba91637STony Han
2349ba91637STony Han	/* DLL soft-reset + DLL lock wait + ITM reset */
2359ba91637STony Han	mov	tmp1, #(DDR3PHY_PIR_INIT | DDR3PHY_PIR_DLLSRST | \
2369ba91637STony Han			DDR3PHY_PIR_DLLLOCK | DDR3PHY_PIR_ITMSRST)
2379ba91637STony Han	str	tmp1, [tmp2, #DDR3PHY_PIR]
2389ba91637STony Han
2399ba91637STony Hansr_dis_4:
2409ba91637STony Han	/* Wait for it. */
2419ba91637STony Han	ldr	tmp1, [tmp2, #DDR3PHY_PGSR]
2429ba91637STony Han	tst	tmp1, #DDR3PHY_PGSR_IDONE
2439ba91637STony Han	beq	sr_dis_4
2449ba91637STony Han
2459ba91637STony Han	ldr	tmp2, .sramc_base
2469ba91637STony Han
2479ba91637STony Han	/* Enable quasi-dynamic programming. */
2489ba91637STony Han	mov	tmp1, #0
2499ba91637STony Han	str	tmp1, [tmp2, #UDDRC_SWCTRL]
2509ba91637STony Han
2519ba91637STony Han	/* Assert PHY init complete enable signal. */
2529ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_DFIMISC]
2539ba91637STony Han	orr	tmp1, tmp1, #UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN
2549ba91637STony Han	str	tmp1, [tmp2, #UDDRC_DFIMISC]
2559ba91637STony Han
2569ba91637STony Han	/* Programming is done. Set sw_done. */
2579ba91637STony Han	mov	tmp1, #UDDRC_SWCTRL_SW_DONE
2589ba91637STony Han	str	tmp1, [tmp2, #UDDRC_SWCTRL]
2599ba91637STony Han
2609ba91637STony Hansr_dis_5:
2619ba91637STony Han	/* Wait for it. */
2629ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_SWSTAT]
2639ba91637STony Han	tst	tmp1, #UDDRC_SWSTAT_SW_DONE_ACK
2649ba91637STony Han	beq	sr_dis_5
2659ba91637STony Han
2669ba91637STony Han	/* Trigger self-refresh exit. */
2679ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PWRCTL]
2689ba91637STony Han	bic	tmp1, tmp1, #UDDRC_PWRCTL_SELFREF_SW
2699ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PWRCTL]
2709ba91637STony Han
2719ba91637STony Hansr_dis_6:
2729ba91637STony Han	/* Wait for self-refresh exit done. */
2739ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_STAT]
2749ba91637STony Han	bic	tmp1, tmp1, #~UDDRC_STAT_OPMODE_MSK
2759ba91637STony Han	cmp	tmp1, #UDDRC_STAT_OPMODE_NORMAL
2769ba91637STony Han	bne	sr_dis_6
2779ba91637STony Han
2789ba91637STony Han	/* Enable all AXI ports. */
2799ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_0]
2809ba91637STony Han	orr	tmp1, tmp1, #0x1
2819ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_0]
2829ba91637STony Han
2839ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_1]
2849ba91637STony Han	orr	tmp1, tmp1, #0x1
2859ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_1]
2869ba91637STony Han
2879ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_2]
2889ba91637STony Han	orr	tmp1, tmp1, #0x1
2899ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_2]
2909ba91637STony Han
2919ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_3]
2929ba91637STony Han	orr	tmp1, tmp1, #0x1
2939ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_3]
2949ba91637STony Han
2959ba91637STony Han	ldr	tmp1, [tmp2, #UDDRC_PCTRL_4]
2969ba91637STony Han	orr	tmp1, tmp1, #0x1
2979ba91637STony Han	str	tmp1, [tmp2, #UDDRC_PCTRL_4]
2989ba91637STony Han
2999ba91637STony Han	dsb
3009ba91637STony Han.endm
3019ba91637STony Han#endif
30215300b40SClément Léger
30315300b40SClément Léger#define SUSPEND_FUNC(__name) \
30415300b40SClément Léger__name:
30515300b40SClément Léger
30615300b40SClément Léger#define SUSPEND_END_FUNC(__name) \
30715300b40SClément Léger	.size __name, .-__name
30815300b40SClément Léger
30915300b40SClément Léger.macro check_fit_in_sram since
31015300b40SClément Léger	.if (. - \since) > 0x10000
31115300b40SClément Léger		.error "Suspend assembly code exceeds dedicated SRAM size"
31215300b40SClément Léger	.endif
31315300b40SClément Léger.endm
31415300b40SClément Léger
31515300b40SClément Léger/*
31615300b40SClément Léger * void at91_suspend_sram_fn(struct at91_pm_data*)
31715300b40SClément Léger * @input param:
31815300b40SClément Léger * 	@r0: base address of struct at91_pm_data
31915300b40SClément Léger */
32015300b40SClément Léger.align 3
32115300b40SClément Léger.global at91_pm_suspend_in_sram
32215300b40SClément LégerSUSPEND_FUNC(at91_pm_suspend_in_sram)
32315300b40SClément Léger	/* Save registers on stack */
32415300b40SClément Léger	stmfd	sp!, {r4 - r12, lr}
32515300b40SClément Léger
32615300b40SClément Léger	/* Drain write buffer */
32715300b40SClément Léger	mov	tmp1, #0
32815300b40SClément Léger	mcr	p15, 0, tmp1, c7, c10, 4
32915300b40SClément Léger
330*f73055a1STony Han	write_tlbiall
331*f73055a1STony Han	isb
332*f73055a1STony Han
333*f73055a1STony Han	/*
334*f73055a1STony Han	 * ldrne below are here to preload their address in the TLB as access
335*f73055a1STony Han	 * to RAM may be limited while in self-refresh.
336*f73055a1STony Han	 */
33715300b40SClément Léger	ldr	tmp1, [r0, #PM_DATA_PMC]
33815300b40SClément Léger	str	tmp1, .pmc_base
339*f73055a1STony Han	cmp	tmp1, #0
340*f73055a1STony Han	ldrne	tmp2, [tmp1, #0]
341*f73055a1STony Han
34215300b40SClément Léger	ldr	tmp1, [r0, #PM_DATA_RAMC0]
34315300b40SClément Léger	str	tmp1, .sramc_base
344*f73055a1STony Han	cmp	tmp1, #0
345*f73055a1STony Han	ldrne	tmp2, [tmp1, #0]
346*f73055a1STony Han
34746f0e733STony Han	ldr	tmp1, [r0, #PM_DATA_RAMC_PHY]
34846f0e733STony Han	str	tmp1, .sramc_phy_base
349*f73055a1STony Han	cmp	tmp1, #0
350*f73055a1STony Han	ldrne	tmp2, [tmp1, #0]
351*f73055a1STony Han
35215300b40SClément Léger	ldr	tmp1, [r0, #PM_DATA_MODE]
35315300b40SClément Léger	str	tmp1, .pm_mode
35415300b40SClément Léger	/* Both ldrne below are here to preload their address in the TLB */
35515300b40SClément Léger	ldr	tmp1, [r0, #PM_DATA_SHDWC]
35615300b40SClément Léger	str	tmp1, .shdwc
35715300b40SClément Léger	cmp	tmp1, #0
35815300b40SClément Léger	ldrne	tmp2, [tmp1, #0]
35915300b40SClément Léger	ldr	tmp1, [r0, #PM_DATA_SFRBU]
36015300b40SClément Léger	str	tmp1, .sfrbu
36115300b40SClément Léger	cmp	tmp1, #0
36215300b40SClément Léger	ldrne	tmp2, [tmp1, #0x10]
36315300b40SClément Léger
36415300b40SClément Léger	/* Active the self-refresh mode */
3659ba91637STony Han#ifdef CFG_SAMA5D2
36615300b40SClément Léger	mov	r0, #SRAMC_SELF_FRESH_ACTIVE
36715300b40SClément Léger	bl	at91_sramc_self_refresh
3689ba91637STony Han#endif
3699ba91637STony Han#ifdef CFG_SAMA7G5
3709ba91637STony Han	at91_sramc_self_refresh_ena
3719ba91637STony Han#endif
37215300b40SClément Léger
37315300b40SClément Léger	ldr	r0, .pm_mode
37415300b40SClément Léger	cmp	r0, #AT91_PM_STANDBY
37515300b40SClément Léger	beq	standby
37615300b40SClément Léger	cmp	r0, #AT91_PM_BACKUP
37715300b40SClément Léger	beq	backup_mode
37815300b40SClément Léger
37915300b40SClément Léger	bl	at91_ulp_mode
38015300b40SClément Léger	b	exit_suspend
38115300b40SClément Léger
38215300b40SClément Légerstandby:
38315300b40SClément Léger	/* Wait for interrupt */
38415300b40SClément Léger	ldr	pmc, .pmc_base
38515300b40SClément Léger	at91_cpu_idle
38615300b40SClément Léger	b	exit_suspend
38715300b40SClément Léger
38815300b40SClément Légerbackup_mode:
38915300b40SClément Léger	bl	at91_backup_mode
39015300b40SClément Léger	b	exit_suspend
39115300b40SClément Léger
39215300b40SClément Légerexit_suspend:
39315300b40SClément Léger	/* Exit the self-refresh mode */
3949ba91637STony Han#ifdef CFG_SAMA5D2
39515300b40SClément Léger	mov	r0, #SRAMC_SELF_FRESH_EXIT
39615300b40SClément Léger	bl	at91_sramc_self_refresh
3979ba91637STony Han#endif
3989ba91637STony Han#ifdef CFG_SAMA7G5
3999ba91637STony Han	at91_sramc_self_refresh_dis
4009ba91637STony Han#endif
40115300b40SClément Léger
40215300b40SClément Léger	/* Restore registers, and return */
40315300b40SClément Léger	ldmfd	sp!, {r4 - r12, pc}
40415300b40SClément LégerSUSPEND_END_FUNC(at91_pm_suspend_in_sram)
40515300b40SClément Léger
40615300b40SClément LégerSUSPEND_FUNC(at91_backup_mode)
40715300b40SClément Léger	/* Switch the master clock source to slow clock. */
40815300b40SClément Léger	ldr	pmc, .pmc_base
40915300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
41015300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_CSS
41115300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
41215300b40SClément Léger
413b22418ebSTony Han	mov	tmp3, #0
414b22418ebSTony Han	wait_mckrdy tmp3
41515300b40SClément Léger
41615300b40SClément Léger	/*BUMEN*/
41715300b40SClément Léger	ldr	r0, .sfrbu
41815300b40SClément Léger	mov	tmp1, #0x1
41915300b40SClément Léger	str	tmp1, [r0, #0x10]
42015300b40SClément Léger
42115300b40SClément Léger	/* Shutdown */
42215300b40SClément Léger	ldr	r0, .shdwc
42315300b40SClément Léger	mov	tmp1, #0xA5000000
42415300b40SClément Léger	add	tmp1, tmp1, #0x1
4256ea2ed2aSTony Han#ifdef CFG_SAMA7G5
4266ea2ed2aSTony Han	/* LPM Pad Enable: The LPM pad is set high */
4276ea2ed2aSTony Han	orr	tmp1, tmp1, #0x200000
4286ea2ed2aSTony Han#endif
42915300b40SClément Léger	str	tmp1, [r0, #0]
43015300b40SClément LégerSUSPEND_END_FUNC(at91_backup_mode)
43115300b40SClément Léger
4326ea2ed2aSTony Han/*
4336ea2ed2aSTony Han * Set LPM
4346ea2ed2aSTony Han * @ena: 0 - disable LPM
4356ea2ed2aSTony Han *	 1 - enable LPM
4366ea2ed2aSTony Han *
4376ea2ed2aSTony Han * Side effects: overwrites tmp1, tmp3
4386ea2ed2aSTony Han */
4396ea2ed2aSTony Han.macro at91_set_lpm ena
4406ea2ed2aSTony Han#ifdef CFG_SAMA7G5
4416ea2ed2aSTony Han	mov	tmp1, #\ena
4426ea2ed2aSTony Han	cmp	tmp1, #1
4436ea2ed2aSTony Han	movne	tmp3, #0x400000 /* LPM Pad Disable: The LPM pad is set low */
4446ea2ed2aSTony Han	moveq	tmp3, #0x200000 /* LPM Pad Enable: The LPM pad is set high */
4456ea2ed2aSTony Han	add	tmp3, #0xA5000000
4466ea2ed2aSTony Han	ldr	tmp1, .shdwc
4476ea2ed2aSTony Han	cmp	tmp1, #0
4486ea2ed2aSTony Han	strne	tmp3, [tmp1]
4496ea2ed2aSTony Han#endif
4506ea2ed2aSTony Han.endm
4516ea2ed2aSTony Han
45215300b40SClément Léger.macro at91_pm_ulp0_mode
45315300b40SClément Léger	ldr	pmc, .pmc_base
45415300b40SClément Léger	ldr	tmp2, .pm_mode
45515300b40SClément Léger
45615300b40SClément Léger	/* Check if ULP0 fast variant has been requested. */
45715300b40SClément Léger	cmp	tmp2, #AT91_PM_ULP0_FAST
45815300b40SClément Léger	bne	0f
45915300b40SClément Léger
46015300b40SClément Léger	/* Set highest prescaler for power saving */
46115300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
46215300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_PRES
46315300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_PRES_64
46415300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
465b22418ebSTony Han
466b22418ebSTony Han	mov	tmp3, #0
467b22418ebSTony Han	wait_mckrdy tmp3
46815300b40SClément Léger	b	1f
46915300b40SClément Léger
47015300b40SClément Léger0:
47115300b40SClément Léger	/* Turn off the crystal oscillator */
47215300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
47315300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
47415300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
47515300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
47615300b40SClément Léger
47715300b40SClément Léger	/* Save RC oscillator state */
47815300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_SR]
47915300b40SClément Léger	str	tmp1, .saved_osc_status
48015300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
4816ea2ed2aSTony Han	bne	7f
48215300b40SClément Léger
48315300b40SClément Léger	/* Turn off RC oscillator */
48415300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
48515300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_MOSCRCEN
48615300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
48715300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
48815300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
48915300b40SClément Léger
49015300b40SClément Léger	/* Wait main RC disabled done */
49115300b40SClément Léger2:	ldr	tmp1, [pmc, #AT91_PMC_SR]
49215300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
49315300b40SClément Léger	bne	2b
49415300b40SClément Léger
4956ea2ed2aSTony Han	/* Enable LPM. */
4966ea2ed2aSTony Han7:	at91_set_lpm 1
4976ea2ed2aSTony Han
49815300b40SClément Léger	/* Wait for interrupt */
49915300b40SClément Léger1:	at91_cpu_idle
50015300b40SClément Léger
50115300b40SClément Léger	/* Check if ULP0 fast variant has been requested. */
50215300b40SClément Léger	cmp	tmp2, #AT91_PM_ULP0_FAST
5036ea2ed2aSTony Han	bne	8f
50415300b40SClément Léger
50515300b40SClément Léger	/* Set lowest prescaler for fast resume. */
50615300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
50715300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_PRES
50815300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
509b22418ebSTony Han
510b22418ebSTony Han	mov	tmp3, #0
511b22418ebSTony Han	wait_mckrdy tmp3
51215300b40SClément Léger	b	6f
51315300b40SClément Léger
5146ea2ed2aSTony Han8:	at91_set_lpm 0
5156ea2ed2aSTony Han
51615300b40SClément Léger5:	/* Restore RC oscillator state */
51715300b40SClément Léger	ldr	tmp1, .saved_osc_status
51815300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
51915300b40SClément Léger	beq	4f
52015300b40SClément Léger
52115300b40SClément Léger	/* Turn on RC oscillator */
52215300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
52315300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_MOSCRCEN
52415300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
52515300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
52615300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
52715300b40SClément Léger
52815300b40SClément Léger	/* Wait main RC stabilization */
52915300b40SClément Léger3:	ldr	tmp1, [pmc, #AT91_PMC_SR]
53015300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
53115300b40SClément Léger	beq	3b
53215300b40SClément Léger
53315300b40SClément Léger	/* Turn on the crystal oscillator */
53415300b40SClément Léger4:	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
53515300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
53615300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
53715300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
53815300b40SClément Léger
53915300b40SClément Léger	wait_moscrdy
54015300b40SClément Léger6:
54115300b40SClément Léger.endm
54215300b40SClément Léger
54315300b40SClément Léger/**
54415300b40SClément Léger * Note: This procedure only applies on the platform which uses
54515300b40SClément Léger * the external crystal oscillator as a main clock source.
54615300b40SClément Léger */
54715300b40SClément Léger.macro at91_pm_ulp1_mode
54815300b40SClément Léger	ldr	pmc, .pmc_base
54915300b40SClément Léger
55015300b40SClément Léger	/* Save RC oscillator state and check if it is enabled. */
55115300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_SR]
55215300b40SClément Léger	str	tmp1, .saved_osc_status
55315300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
55415300b40SClément Léger	bne	2f
55515300b40SClément Léger
55615300b40SClément Léger	/* Enable RC oscillator */
55715300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
55815300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_MOSCRCEN
55915300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
56015300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
56115300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
56215300b40SClément Léger
56315300b40SClément Léger	/* Wait main RC stabilization */
56415300b40SClément Léger1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
56515300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
56615300b40SClément Léger	beq	1b
56715300b40SClément Léger
56815300b40SClément Léger	/* Switch the main clock source to 12-MHz RC oscillator */
56915300b40SClément Léger2:	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
57015300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_MOSCSEL
57115300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
57215300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
57315300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
57415300b40SClément Léger
57515300b40SClément Léger	wait_moscsels
57615300b40SClément Léger
57715300b40SClément Léger	/* Disable the crystal oscillator */
57815300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
57915300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
58015300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
58115300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
58215300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
58315300b40SClément Léger
58415300b40SClément Léger	/* Switch the master clock source to main clock */
58515300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
58615300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_CSS
58715300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_CSS_MAIN
58815300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
58915300b40SClément Léger
590b22418ebSTony Han	mov	tmp3, #0
591b22418ebSTony Han	wait_mckrdy tmp3
59215300b40SClément Léger
5936ea2ed2aSTony Han	/* Enable LPM */
5946ea2ed2aSTony Han	at91_set_lpm 1
5956ea2ed2aSTony Han
59615300b40SClément Léger	/* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */
59715300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
59815300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_WAITMODE
59915300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
60015300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
60115300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
60215300b40SClément Léger
60315300b40SClément Léger	/* Quirk for SAM9X60's PMC */
60415300b40SClément Léger	nop
60515300b40SClément Léger	nop
60615300b40SClément Léger
6076ea2ed2aSTony Han	mov	tmp3, #0
608b22418ebSTony Han	wait_mckrdy tmp3
60915300b40SClément Léger
6106ea2ed2aSTony Han	/* Disable LPM. */
6116ea2ed2aSTony Han	at91_set_lpm 0
6126ea2ed2aSTony Han
61315300b40SClément Léger	/* Enable the crystal oscillator */
61415300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
61515300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
61615300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
61715300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
61815300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
61915300b40SClément Léger
62015300b40SClément Léger	wait_moscrdy
62115300b40SClément Léger
62215300b40SClément Léger	/* Switch the master clock source to slow clock */
62315300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
62415300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_CSS
62515300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
62615300b40SClément Léger
6276ea2ed2aSTony Han	mov	tmp3, #0
628b22418ebSTony Han	wait_mckrdy tmp3
62915300b40SClément Léger
63015300b40SClément Léger	/* Switch main clock source to crystal oscillator */
63115300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
63215300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_MOSCSEL
63315300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
63415300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
63515300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
63615300b40SClément Léger
63715300b40SClément Léger	wait_moscsels
63815300b40SClément Léger
63915300b40SClément Léger	/* Switch the master clock source to main clock */
64015300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
64115300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_CSS
64215300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_CSS_MAIN
64315300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
64415300b40SClément Léger
645b22418ebSTony Han	wait_mckrdy tmp3
64615300b40SClément Léger
64715300b40SClément Léger	/* Restore RC oscillator state */
64815300b40SClément Léger	ldr	tmp1, .saved_osc_status
64915300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
65015300b40SClément Léger	bne	3f
65115300b40SClément Léger
65215300b40SClément Léger	/* Disable RC oscillator */
65315300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
65415300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_MOSCRCEN
65515300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
65615300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_KEY
65715300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_MOR]
65815300b40SClément Léger
65915300b40SClément Léger	/* Wait RC oscillator disable done */
66015300b40SClément Léger4:	ldr	tmp1, [pmc, #AT91_PMC_SR]
66115300b40SClément Léger	tst	tmp1, #AT91_PMC_MOSCRCS
66215300b40SClément Léger	bne	4b
66315300b40SClément Léger
66415300b40SClément Léger3:
66515300b40SClément Léger.endm
66615300b40SClément Léger
66761ecdd1dSTony Han/*
66861ecdd1dSTony Han * Save PLLA setting and disable it
66961ecdd1dSTony Han *
67061ecdd1dSTony Han * Side effects: overwrites tmp1, tmp2
67161ecdd1dSTony Han */
67215300b40SClément Léger.macro at91_plla_disable
67361ecdd1dSTony Han#ifdef CFG_SAMA7G5
67461ecdd1dSTony Han	/* Save PLLA settings */
67561ecdd1dSTony Han	ldr	tmp2, [pmc, #AT91_PMC_PLL_UPDT]
67661ecdd1dSTony Han	bic	tmp2, tmp2, #AT91_PMC_PLL_UPDT_ID
67761ecdd1dSTony Han	str	tmp2, [pmc, #AT91_PMC_PLL_UPDT]
67861ecdd1dSTony Han
67961ecdd1dSTony Han	/* save div */
68061ecdd1dSTony Han	mov	tmp1, #0
68161ecdd1dSTony Han	ldr	tmp2, [pmc, #AT91_PMC_PLL_CTRL0]
68261ecdd1dSTony Han	bic	tmp2, tmp2, #0xffffff00
68361ecdd1dSTony Han	orr	tmp1, tmp1, tmp2
68461ecdd1dSTony Han
68561ecdd1dSTony Han	/* save mul */
68661ecdd1dSTony Han	ldr	tmp2, [pmc, #AT91_PMC_PLL_CTRL1]
68761ecdd1dSTony Han	bic	tmp2, tmp2, #0xffffff
68861ecdd1dSTony Han	orr	tmp1, tmp1, tmp2
68961ecdd1dSTony Han	str	tmp1, .saved_pllar
69061ecdd1dSTony Han
69161ecdd1dSTony Han	/* step 2 */
69261ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
69361ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
69461ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
69561ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
69661ecdd1dSTony Han
69761ecdd1dSTony Han	/* step 3 */
69861ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
69961ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLLCK
70061ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL
70161ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
70261ecdd1dSTony Han
70361ecdd1dSTony Han	/* step 4 */
70461ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
70561ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
70661ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
70761ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
70861ecdd1dSTony Han
70961ecdd1dSTony Han	/* step 5 */
71061ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
71161ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL
71261ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
71361ecdd1dSTony Han
71461ecdd1dSTony Han	/* step 6 */
71561ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
71661ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
71761ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
71861ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
71961ecdd1dSTony Han#else
72015300b40SClément Léger	/* Save PLLA setting and disable it */
72115300b40SClément Léger	ldr	tmp1, [pmc, #AT91_CKGR_PLLAR]
72215300b40SClément Léger	str	tmp1, .saved_pllar
72315300b40SClément Léger
72415300b40SClément Léger	/* Disable PLLA. */
72515300b40SClément Léger	mov	tmp1, #AT91_PMC_PLLCOUNT
72615300b40SClément Léger	orr	tmp1, tmp1, #(1 << 29)		/* bit 29 always set */
72715300b40SClément Léger	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
72861ecdd1dSTony Han#endif
72915300b40SClément Léger2:
73015300b40SClément Léger.endm
73115300b40SClément Léger
73261ecdd1dSTony Han/*
73361ecdd1dSTony Han * Enable PLLA with the saved setting
73461ecdd1dSTony Han *
73561ecdd1dSTony Han * Side effects: overwrites tmp1, tmp2
73661ecdd1dSTony Han */
73715300b40SClément Léger.macro at91_plla_enable
73861ecdd1dSTony Han#ifdef CFG_SAMA7G5
73961ecdd1dSTony Han	/* step 1 */
74061ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
74161ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
74261ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
74361ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
74461ecdd1dSTony Han
74561ecdd1dSTony Han	/* step 2 */
74661ecdd1dSTony Han	ldr	tmp1, =AT91_PMC_PLL_ACR_DEFAULT_PLLA
74761ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_ACR]
74861ecdd1dSTony Han
74961ecdd1dSTony Han	/* step 3 */
75061ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL1]
75161ecdd1dSTony Han	ldr	tmp2, .saved_pllar
75261ecdd1dSTony Han	bic	tmp2, tmp2, #0xffffff
75361ecdd1dSTony Han	orr	tmp1, tmp1, tmp2
75461ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL1]
75561ecdd1dSTony Han
75661ecdd1dSTony Han	/* step 4 */
75761ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
75861ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
75961ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
76061ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
76161ecdd1dSTony Han
76261ecdd1dSTony Han	/* step 5 */
76361ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
76461ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENLOCK
76561ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL
76661ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLLCK
76761ecdd1dSTony Han	bic	tmp1, tmp1, #0xff
76861ecdd1dSTony Han	ldr	tmp2, .saved_pllar
76961ecdd1dSTony Han	bic	tmp2, tmp2, #0xffffff00
77061ecdd1dSTony Han	orr	tmp1, tmp1, tmp2
77161ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
77261ecdd1dSTony Han
77361ecdd1dSTony Han	/* step 6 */
77461ecdd1dSTony Han	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
77561ecdd1dSTony Han	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
77661ecdd1dSTony Han	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
77761ecdd1dSTony Han	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
77861ecdd1dSTony Han
77961ecdd1dSTony Han	/* step 7 */
78061ecdd1dSTony Han3:	ldr	tmp1, [pmc, #AT91_PMC_PLL_ISR0]
78161ecdd1dSTony Han	tst	tmp1, #0x1
78261ecdd1dSTony Han	beq	3b
78361ecdd1dSTony Han#else
78415300b40SClément Léger	ldr	tmp2, .saved_pllar
78515300b40SClément Léger
78615300b40SClément Léger	/* Restore PLLA setting */
78715300b40SClément Léger	str	tmp2, [pmc, #AT91_CKGR_PLLAR]
78815300b40SClément Léger
78915300b40SClément Léger	/* Enable PLLA. */
79015300b40SClément Léger	tst	tmp2, #(AT91_PMC_MUL &  0xff0000)
79115300b40SClément Léger	bne	1f
79215300b40SClément Léger	tst	tmp2, #(AT91_PMC_MUL & ~0xff0000)
79315300b40SClément Léger	beq	2f
79415300b40SClément Léger
79515300b40SClément Léger1:	ldr	tmp1, [pmc, #AT91_PMC_SR]
79615300b40SClément Léger	tst	tmp1, #AT91_PMC_LOCKA
79715300b40SClément Léger	beq	1b
79815300b40SClément Léger2:
79961ecdd1dSTony Han#endif
80015300b40SClément Léger.endm
80115300b40SClément Léger
802735a1effSTony Han#ifdef CFG_SAMA7G5
803735a1effSTony Han/*
804735a1effSTony Han * at91_mckx_ps_enable:	save MCK1..4 settings and switch it to main clock
805735a1effSTony Han *
806735a1effSTony Han * Side effects: overwrites tmp1, tmp2, tmp3
807735a1effSTony Han */
808735a1effSTony Han.macro at91_mckx_ps_enable
809735a1effSTony Han	ldr	pmc, .pmc_base
810735a1effSTony Han
811735a1effSTony Han	/* There are 4 MCKs we need to handle: MCK1..4 */
812735a1effSTony Han	mov	tmp1, #1
813735a1effSTony Hane_loop:
814735a1effSTony Han	/* Write MCK ID to retrieve the settings */
815735a1effSTony Han	str	tmp1, [pmc, #AT91_PMC_MCR_V2]
816735a1effSTony Han	ldr	tmp2, [pmc, #AT91_PMC_MCR_V2]
817735a1effSTony Han
818735a1effSTony Han	cmp	tmp1, #1
819735a1effSTony Han	streq	tmp2, .saved_mck1
820735a1effSTony Han	cmp	tmp1, #2
821735a1effSTony Han	streq	tmp2, .saved_mck2
822735a1effSTony Han	cmp	tmp1, #3
823735a1effSTony Han	streq	tmp2, .saved_mck3
824735a1effSTony Han	cmp	tmp1, #4
825735a1effSTony Han	streq	tmp2, .saved_mck4
826735a1effSTony Han
827735a1effSTony Han	/* Use CSS=MD_SLOW_CLK and DIV=64. */
828735a1effSTony Han	bic	tmp2, tmp2, #AT91_PMC_MCR_V2_CSS_MASK
829735a1effSTony Han	bic	tmp2, tmp2, #AT91_PMC_MCR_V2_DIV_MASK
830735a1effSTony Han	orr	tmp2, tmp2, #AT91_PMC_MCR_V2_CSS_MD_SLCK
831735a1effSTony Han	orr	tmp2, tmp2, #AT91_PMC_MCR_V2_DIV64
832735a1effSTony Han	orr	tmp2, tmp2, #AT91_PMC_MCR_V2_CMD
833735a1effSTony Han	str	tmp2, [pmc, #AT91_PMC_MCR_V2]
834735a1effSTony Han
835735a1effSTony Han	mov	tmp2, tmp1
836735a1effSTony Han	wait_mckrdy tmp1
837735a1effSTony Han	mov	tmp1, tmp2
838735a1effSTony Han
839735a1effSTony Han	add	tmp1, tmp1, #1
840735a1effSTony Han	cmp	tmp1, #5
841735a1effSTony Han	bne	e_loop
842735a1effSTony Han.endm
843735a1effSTony Han
844735a1effSTony Han/*
845735a1effSTony Han * at91_mckx_ps_restore: restore MCK1..4 settings
846735a1effSTony Han *
847735a1effSTony Han * Side effects: overwrites tmp1, tmp2, tmp3
848735a1effSTony Han */
849735a1effSTony Han.macro at91_mckx_ps_restore
850735a1effSTony Han	ldr	pmc, .pmc_base
851735a1effSTony Han
852735a1effSTony Han	/* There are 4 MCKs we need to handle: MCK1..4 */
853735a1effSTony Han	mov	tmp1, #1
854735a1effSTony Han	ldr	tmp2, .saved_mck1
855735a1effSTony Hanr_loop:
856735a1effSTony Han	cmp	tmp1, #2
857735a1effSTony Han	ldreq	tmp2, .saved_mck2
858735a1effSTony Han	cmp	tmp1, #3
859735a1effSTony Han	ldreq	tmp2, .saved_mck3
860735a1effSTony Han	cmp	tmp1, #4
861735a1effSTony Han	ldreq	tmp2, .saved_mck4
862735a1effSTony Han
863735a1effSTony Han	/* Write MCK ID to retrieve the settings */
864735a1effSTony Han	str	tmp1, [pmc, #AT91_PMC_MCR_V2]
865735a1effSTony Han	ldr	tmp3, [pmc, #AT91_PMC_MCR_V2]
866735a1effSTony Han
867735a1effSTony Han	/* We need to restore CSS and DIV. */
868735a1effSTony Han	bic	tmp3, tmp3, #AT91_PMC_MCR_V2_CSS_MASK
869735a1effSTony Han	bic	tmp3, tmp3, #AT91_PMC_MCR_V2_DIV_MASK
870735a1effSTony Han	orr	tmp3, tmp3, tmp2
871735a1effSTony Han	bic	tmp3, tmp3, #AT91_PMC_MCR_V2_ID_MASK
872735a1effSTony Han	orr	tmp3, tmp3, tmp1
873735a1effSTony Han	orr	tmp3, tmp3, #AT91_PMC_MCR_V2_CMD
874735a1effSTony Han	str	tmp3, [pmc, #AT91_PMC_MCR_V2]
875735a1effSTony Han
876735a1effSTony Han	mov	tmp2, tmp1
877735a1effSTony Han	wait_mckrdy tmp1
878735a1effSTony Han	mov	tmp1, tmp2
879735a1effSTony Han
880735a1effSTony Han	add	tmp1, tmp1, #1
881735a1effSTony Han	cmp	tmp1, #5
882735a1effSTony Han	bne	r_loop
883735a1effSTony Han.endm
884735a1effSTony Han#endif
885735a1effSTony Han
88615300b40SClément LégerSUSPEND_FUNC(at91_ulp_mode)
887735a1effSTony Han#ifdef CFG_SAMA7G5
888735a1effSTony Han	at91_mckx_ps_enable
889735a1effSTony Han#endif
890735a1effSTony Han
89115300b40SClément Léger	ldr	pmc, .pmc_base
89215300b40SClément Léger	ldr	tmp3, .pm_mode
89315300b40SClément Léger
89415300b40SClément Léger	/* Save Master clock setting */
89515300b40SClément Léger	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
89615300b40SClément Léger	str	tmp1, .saved_mckr
89715300b40SClément Léger
89815300b40SClément Léger	/*
89915300b40SClément Léger	 * Set master clock source to:
90015300b40SClément Léger	 * - MAINCK if using ULP0 fast variant
90115300b40SClément Léger	 * - slow clock, otherwise
90215300b40SClément Léger	 */
90315300b40SClément Léger	bic	tmp1, tmp1, #AT91_PMC_CSS
90415300b40SClément Léger	cmp	tmp3, #AT91_PM_ULP0_FAST
90515300b40SClément Léger	bne	save_mck
90615300b40SClément Léger	orr	tmp1, tmp1, #AT91_PMC_CSS_MAIN
90715300b40SClément Légersave_mck:
90815300b40SClément Léger	str	tmp1, [pmc, #AT91_PMC_MCKR]
90915300b40SClément Léger
910b22418ebSTony Han	mov	tmp3, #0
911b22418ebSTony Han	wait_mckrdy tmp3
91215300b40SClément Léger
91315300b40SClément Léger	at91_plla_disable
91415300b40SClément Léger
915b22418ebSTony Han	ldr	tmp3, .pm_mode
91615300b40SClément Léger	cmp	tmp3, #AT91_PM_ULP1
91715300b40SClément Léger	beq	ulp1_mode
91815300b40SClément Léger
91915300b40SClément Léger	at91_pm_ulp0_mode
92015300b40SClément Léger	b	ulp_exit
92115300b40SClément Léger
92215300b40SClément Légerulp1_mode:
92315300b40SClément Léger	at91_pm_ulp1_mode
92415300b40SClément Léger	b	ulp_exit
92515300b40SClément Léger
92615300b40SClément Légerulp_exit:
92715300b40SClément Léger	ldr	pmc, .pmc_base
92815300b40SClément Léger
92915300b40SClément Léger	at91_plla_enable
93015300b40SClément Léger
93115300b40SClément Léger	/*
93215300b40SClément Léger	 * Restore master clock setting
93315300b40SClément Léger	 */
93415300b40SClément Léger	ldr	tmp2, .saved_mckr
93515300b40SClément Léger	str	tmp2, [pmc, #AT91_PMC_MCKR]
93615300b40SClément Léger
937b22418ebSTony Han	mov	tmp3, #0
938b22418ebSTony Han	wait_mckrdy tmp3
93915300b40SClément Léger
940735a1effSTony Han#ifdef CFG_SAMA7G5
941735a1effSTony Han	at91_mckx_ps_restore
942735a1effSTony Han#endif
943735a1effSTony Han
94415300b40SClément Léger	mov	pc, lr
94515300b40SClément LégerSUSPEND_END_FUNC(at91_ulp_mode)
94615300b40SClément Léger
9479ba91637STony Han#ifdef CFG_SAMA5D2
94815300b40SClément Léger/*
94915300b40SClément Léger * void at91_sramc_self_refresh(unsigned int is_active)
95015300b40SClément Léger *
95115300b40SClément Léger * @input param:
95215300b40SClément Léger *	@r0: 1 - active self-refresh mode
95315300b40SClément Léger *	     0 - exit self-refresh mode
95415300b40SClément Léger * register usage:
95515300b40SClément Léger *	@r2: base address of the sram controller
95615300b40SClément Léger */
95715300b40SClément Léger
95815300b40SClément LégerSUSPEND_FUNC(at91_sramc_self_refresh)
95915300b40SClément Léger	ldr	r2, .sramc_base
96015300b40SClément Léger
96115300b40SClément Léger	/*
96215300b40SClément Léger	 * DDR Memory controller
96315300b40SClément Léger	 */
96415300b40SClément Léger	tst	r0, #SRAMC_SELF_FRESH_ACTIVE
96515300b40SClément Léger	beq	ddrc_exit_sf
96615300b40SClément Léger
96715300b40SClément Léger	/* LPDDR1 --> force DDR2 mode during self-refresh */
96815300b40SClément Léger	ldr	r3, [r2, #AT91_DDRSDRC_MDR]
96915300b40SClément Léger	str	r3, .saved_sam9_mdr
97015300b40SClément Léger	bic	r3, r3, #~AT91_DDRSDRC_MD
97115300b40SClément Léger	cmp	r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
97215300b40SClément Léger	ldreq	r3, [r2, #AT91_DDRSDRC_MDR]
97315300b40SClément Léger	biceq	r3, r3, #AT91_DDRSDRC_MD
97415300b40SClément Léger	orreq	r3, r3, #AT91_DDRSDRC_MD_DDR2
97515300b40SClément Léger	streq	r3, [r2, #AT91_DDRSDRC_MDR]
97615300b40SClément Léger
97715300b40SClément Léger	/* Active DDRC self-refresh mode */
97815300b40SClément Léger	ldr	r3, [r2, #AT91_DDRSDRC_LPR]
97915300b40SClément Léger	str	r3, .saved_sam9_lpr
98015300b40SClément Léger	bic	r3, r3, #AT91_DDRSDRC_LPCB
98115300b40SClément Léger	orr	r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
98215300b40SClément Léger	str	r3, [r2, #AT91_DDRSDRC_LPR]
98315300b40SClément Léger
98415300b40SClément Léger	b	exit_sramc_sf
98515300b40SClément Léger
98615300b40SClément Légerddrc_exit_sf:
98715300b40SClément Léger	/* Restore MDR in case of LPDDR1 */
98815300b40SClément Léger	ldr	r3, .saved_sam9_mdr
98915300b40SClément Léger	str	r3, [r2, #AT91_DDRSDRC_MDR]
99015300b40SClément Léger	/* Restore LPR on AT91 with DDRAM */
99115300b40SClément Léger	ldr	r3, .saved_sam9_lpr
99215300b40SClément Léger	str	r3, [r2, #AT91_DDRSDRC_LPR]
99315300b40SClément Léger
99415300b40SClément Légerexit_sramc_sf:
99515300b40SClément Léger	mov	pc, lr
99615300b40SClément LégerSUSPEND_END_FUNC(at91_sramc_self_refresh)
9979ba91637STony Han#endif
99815300b40SClément Léger
99915300b40SClément Léger.pmc_base:
100015300b40SClément Léger	.word 0
100115300b40SClément Léger.sramc_base:
100215300b40SClément Léger	.word 0
100346f0e733STony Han.sramc_phy_base:
100446f0e733STony Han	.word 0
100515300b40SClément Léger.shdwc:
100615300b40SClément Léger	.word 0
100715300b40SClément Léger.sfrbu:
100815300b40SClément Léger	.word 0
100915300b40SClément Léger.pm_mode:
101015300b40SClément Léger	.word 0
101115300b40SClément Léger.saved_mckr:
101215300b40SClément Léger	.word 0
101315300b40SClément Léger.saved_pllar:
101415300b40SClément Léger	.word 0
101515300b40SClément Léger.saved_sam9_lpr:
101615300b40SClément Léger	.word 0
101715300b40SClément Léger.saved_sam9_mdr:
101815300b40SClément Léger	.word 0
101915300b40SClément Léger.saved_osc_status:
102015300b40SClément Léger	.word 0
1021735a1effSTony Han#ifdef CFG_SAMA7G5
1022735a1effSTony Han.saved_mck1:
1023735a1effSTony Han	.word 0
1024735a1effSTony Han.saved_mck2:
1025735a1effSTony Han	.word 0
1026735a1effSTony Han.saved_mck3:
1027735a1effSTony Han	.word 0
1028735a1effSTony Han.saved_mck4:
1029735a1effSTony Han	.word 0
1030735a1effSTony Han#endif
103115300b40SClément Léger
103215300b40SClément Léger.global at91_pm_suspend_in_sram_sz
103315300b40SClément Légerat91_pm_suspend_in_sram_sz:
103415300b40SClément Léger	.word .-at91_pm_suspend_in_sram
103515300b40SClément Léger
103615300b40SClément Légercheck_fit_in_sram at91_pm_suspend_in_sram
1037