xref: /optee_os/core/drivers/pm/sam/pm_suspend.S (revision 46f0e73383512fcc3244674c764c81a1d19c9055)
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
2/*
3 * This file was imported from Linux arch/arm/mach-at91/pm_suspend.S and
4 * relicensed with dual GPL-2.0/BSD-2-Clause with Microchip agreement.
5 *
6 * Copyright (c) 2021, Microchip
7 */
8
9#include <arm.h>
10#include <arm32_macros.S>
11#include <asm.S>
12#include <at91_pmc.h>
13#include <drivers/sam/at91_ddr.h>
14#include <generated/pm-defines.h>
15
16#include "at91_pm.h"
17
18#define	SRAMC_SELF_FRESH_ACTIVE		0x01
19#define	SRAMC_SELF_FRESH_EXIT		0x00
20
21pmc	.req	r0
22tmp1	.req	r4
23tmp2	.req	r5
24tmp3	.req	r6
25
26/*
27 * Wait until master clock is ready (after switching master clock source)
28 * @r_mckid:	register holding master clock identifier
29 *
30 * Side effects: overwrites tmp1
31 */
32.macro wait_mckrdy r_mckid
33#ifdef CFG_SAMA7G5
34	cmp	\r_mckid, #0
35	beq	1f
362:	ldr	tmp1, [pmc, #AT91_PMC_SR]
37	tst	tmp1, #AT91_PMC_MCKXRDY
38	beq	2b
39	b	3f
40#endif
411:	ldr	tmp1, [pmc, #AT91_PMC_SR]
42	tst	tmp1, #AT91_PMC_MCKRDY
43	beq	1b
443:
45.endm
46
47/*
48 * Wait until master oscillator has stabilized.
49 */
50.macro wait_moscrdy
511:	ldr	tmp1, [pmc, #AT91_PMC_SR]
52	tst	tmp1, #AT91_PMC_MOSCS
53	beq	1b
54.endm
55
56/*
57 * Wait for main oscillator selection is done
58 */
59.macro wait_moscsels
601:	ldr	tmp1, [pmc, #AT91_PMC_SR]
61	tst	tmp1, #AT91_PMC_MOSCSELS
62	beq	1b
63.endm
64
65/*
66 * Put the processor to enter the idle state
67 */
68.macro at91_cpu_idle
69
70	mov	tmp1, #AT91_PMC_PCK
71	str	tmp1, [pmc, #AT91_PMC_SCDR]
72
73	dsb
74
75	wfi		@ Wait For Interrupt
76
77.endm
78
79.section .text.psci.suspend
80
81.arm
82
83
84#define SUSPEND_FUNC(__name) \
85__name:
86
87#define SUSPEND_END_FUNC(__name) \
88	.size __name, .-__name
89
90.macro check_fit_in_sram since
91	.if (. - \since) > 0x10000
92		.error "Suspend assembly code exceeds dedicated SRAM size"
93	.endif
94.endm
95
96/*
97 * void at91_suspend_sram_fn(struct at91_pm_data*)
98 * @input param:
99 * 	@r0: base address of struct at91_pm_data
100 */
101.align 3
102.global at91_pm_suspend_in_sram
103SUSPEND_FUNC(at91_pm_suspend_in_sram)
104	/* Save registers on stack */
105	stmfd	sp!, {r4 - r12, lr}
106
107	/* Drain write buffer */
108	mov	tmp1, #0
109	mcr	p15, 0, tmp1, c7, c10, 4
110
111	ldr	tmp1, [r0, #PM_DATA_PMC]
112	str	tmp1, .pmc_base
113	ldr	tmp1, [r0, #PM_DATA_RAMC0]
114	str	tmp1, .sramc_base
115	ldr	tmp1, [r0, #PM_DATA_RAMC_PHY]
116	str	tmp1, .sramc_phy_base
117	ldr	tmp1, [r0, #PM_DATA_MODE]
118	str	tmp1, .pm_mode
119	/* Both ldrne below are here to preload their address in the TLB */
120	ldr	tmp1, [r0, #PM_DATA_SHDWC]
121	str	tmp1, .shdwc
122	cmp	tmp1, #0
123	ldrne	tmp2, [tmp1, #0]
124	ldr	tmp1, [r0, #PM_DATA_SFRBU]
125	str	tmp1, .sfrbu
126	cmp	tmp1, #0
127	ldrne	tmp2, [tmp1, #0x10]
128
129	/* Active the self-refresh mode */
130	mov	r0, #SRAMC_SELF_FRESH_ACTIVE
131	bl	at91_sramc_self_refresh
132
133	ldr	r0, .pm_mode
134	cmp	r0, #AT91_PM_STANDBY
135	beq	standby
136	cmp	r0, #AT91_PM_BACKUP
137	beq	backup_mode
138
139	bl	at91_ulp_mode
140	b	exit_suspend
141
142standby:
143	/* Wait for interrupt */
144	ldr	pmc, .pmc_base
145	at91_cpu_idle
146	b	exit_suspend
147
148backup_mode:
149	bl	at91_backup_mode
150	b	exit_suspend
151
152exit_suspend:
153	/* Exit the self-refresh mode */
154	mov	r0, #SRAMC_SELF_FRESH_EXIT
155	bl	at91_sramc_self_refresh
156
157	/* Restore registers, and return */
158	ldmfd	sp!, {r4 - r12, pc}
159SUSPEND_END_FUNC(at91_pm_suspend_in_sram)
160
161SUSPEND_FUNC(at91_backup_mode)
162	/* Switch the master clock source to slow clock. */
163	ldr	pmc, .pmc_base
164	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
165	bic	tmp1, tmp1, #AT91_PMC_CSS
166	str	tmp1, [pmc, #AT91_PMC_MCKR]
167
168	mov	tmp3, #0
169	wait_mckrdy tmp3
170
171	/*BUMEN*/
172	ldr	r0, .sfrbu
173	mov	tmp1, #0x1
174	str	tmp1, [r0, #0x10]
175
176	/* Shutdown */
177	ldr	r0, .shdwc
178	mov	tmp1, #0xA5000000
179	add	tmp1, tmp1, #0x1
180#ifdef CFG_SAMA7G5
181	/* LPM Pad Enable: The LPM pad is set high */
182	orr	tmp1, tmp1, #0x200000
183#endif
184	str	tmp1, [r0, #0]
185SUSPEND_END_FUNC(at91_backup_mode)
186
187/*
188 * Set LPM
189 * @ena: 0 - disable LPM
190 *	 1 - enable LPM
191 *
192 * Side effects: overwrites tmp1, tmp3
193 */
194.macro at91_set_lpm ena
195#ifdef CFG_SAMA7G5
196	mov	tmp1, #\ena
197	cmp	tmp1, #1
198	movne	tmp3, #0x400000 /* LPM Pad Disable: The LPM pad is set low */
199	moveq	tmp3, #0x200000 /* LPM Pad Enable: The LPM pad is set high */
200	add	tmp3, #0xA5000000
201	ldr	tmp1, .shdwc
202	cmp	tmp1, #0
203	strne	tmp3, [tmp1]
204#endif
205.endm
206
207.macro at91_pm_ulp0_mode
208	ldr	pmc, .pmc_base
209	ldr	tmp2, .pm_mode
210
211	/* Check if ULP0 fast variant has been requested. */
212	cmp	tmp2, #AT91_PM_ULP0_FAST
213	bne	0f
214
215	/* Set highest prescaler for power saving */
216	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
217	bic	tmp1, tmp1, #AT91_PMC_PRES
218	orr	tmp1, tmp1, #AT91_PMC_PRES_64
219	str	tmp1, [pmc, #AT91_PMC_MCKR]
220
221	mov	tmp3, #0
222	wait_mckrdy tmp3
223	b	1f
224
2250:
226	/* Turn off the crystal oscillator */
227	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
228	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
229	orr	tmp1, tmp1, #AT91_PMC_KEY
230	str	tmp1, [pmc, #AT91_CKGR_MOR]
231
232	/* Save RC oscillator state */
233	ldr	tmp1, [pmc, #AT91_PMC_SR]
234	str	tmp1, .saved_osc_status
235	tst	tmp1, #AT91_PMC_MOSCRCS
236	bne	7f
237
238	/* Turn off RC oscillator */
239	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
240	bic	tmp1, tmp1, #AT91_PMC_MOSCRCEN
241	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
242	orr	tmp1, tmp1, #AT91_PMC_KEY
243	str	tmp1, [pmc, #AT91_CKGR_MOR]
244
245	/* Wait main RC disabled done */
2462:	ldr	tmp1, [pmc, #AT91_PMC_SR]
247	tst	tmp1, #AT91_PMC_MOSCRCS
248	bne	2b
249
250	/* Enable LPM. */
2517:	at91_set_lpm 1
252
253	/* Wait for interrupt */
2541:	at91_cpu_idle
255
256	/* Check if ULP0 fast variant has been requested. */
257	cmp	tmp2, #AT91_PM_ULP0_FAST
258	bne	8f
259
260	/* Set lowest prescaler for fast resume. */
261	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
262	bic	tmp1, tmp1, #AT91_PMC_PRES
263	str	tmp1, [pmc, #AT91_PMC_MCKR]
264
265	mov	tmp3, #0
266	wait_mckrdy tmp3
267	b	6f
268
2698:	at91_set_lpm 0
270
2715:	/* Restore RC oscillator state */
272	ldr	tmp1, .saved_osc_status
273	tst	tmp1, #AT91_PMC_MOSCRCS
274	beq	4f
275
276	/* Turn on RC oscillator */
277	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
278	orr	tmp1, tmp1, #AT91_PMC_MOSCRCEN
279	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
280	orr	tmp1, tmp1, #AT91_PMC_KEY
281	str	tmp1, [pmc, #AT91_CKGR_MOR]
282
283	/* Wait main RC stabilization */
2843:	ldr	tmp1, [pmc, #AT91_PMC_SR]
285	tst	tmp1, #AT91_PMC_MOSCRCS
286	beq	3b
287
288	/* Turn on the crystal oscillator */
2894:	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
290	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
291	orr	tmp1, tmp1, #AT91_PMC_KEY
292	str	tmp1, [pmc, #AT91_CKGR_MOR]
293
294	wait_moscrdy
2956:
296.endm
297
298/**
299 * Note: This procedure only applies on the platform which uses
300 * the external crystal oscillator as a main clock source.
301 */
302.macro at91_pm_ulp1_mode
303	ldr	pmc, .pmc_base
304
305	/* Save RC oscillator state and check if it is enabled. */
306	ldr	tmp1, [pmc, #AT91_PMC_SR]
307	str	tmp1, .saved_osc_status
308	tst	tmp1, #AT91_PMC_MOSCRCS
309	bne	2f
310
311	/* Enable RC oscillator */
312	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
313	orr	tmp1, tmp1, #AT91_PMC_MOSCRCEN
314	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
315	orr	tmp1, tmp1, #AT91_PMC_KEY
316	str	tmp1, [pmc, #AT91_CKGR_MOR]
317
318	/* Wait main RC stabilization */
3191:	ldr	tmp1, [pmc, #AT91_PMC_SR]
320	tst	tmp1, #AT91_PMC_MOSCRCS
321	beq	1b
322
323	/* Switch the main clock source to 12-MHz RC oscillator */
3242:	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
325	bic	tmp1, tmp1, #AT91_PMC_MOSCSEL
326	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
327	orr	tmp1, tmp1, #AT91_PMC_KEY
328	str	tmp1, [pmc, #AT91_CKGR_MOR]
329
330	wait_moscsels
331
332	/* Disable the crystal oscillator */
333	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
334	bic	tmp1, tmp1, #AT91_PMC_MOSCEN
335	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
336	orr	tmp1, tmp1, #AT91_PMC_KEY
337	str	tmp1, [pmc, #AT91_CKGR_MOR]
338
339	/* Switch the master clock source to main clock */
340	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
341	bic	tmp1, tmp1, #AT91_PMC_CSS
342	orr	tmp1, tmp1, #AT91_PMC_CSS_MAIN
343	str	tmp1, [pmc, #AT91_PMC_MCKR]
344
345	mov	tmp3, #0
346	wait_mckrdy tmp3
347
348	/* Enable LPM */
349	at91_set_lpm 1
350
351	/* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */
352	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
353	orr	tmp1, tmp1, #AT91_PMC_WAITMODE
354	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
355	orr	tmp1, tmp1, #AT91_PMC_KEY
356	str	tmp1, [pmc, #AT91_CKGR_MOR]
357
358	/* Quirk for SAM9X60's PMC */
359	nop
360	nop
361
362	mov	tmp3, #0
363	wait_mckrdy tmp3
364
365	/* Disable LPM. */
366	at91_set_lpm 0
367
368	/* Enable the crystal oscillator */
369	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
370	orr	tmp1, tmp1, #AT91_PMC_MOSCEN
371	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
372	orr	tmp1, tmp1, #AT91_PMC_KEY
373	str	tmp1, [pmc, #AT91_CKGR_MOR]
374
375	wait_moscrdy
376
377	/* Switch the master clock source to slow clock */
378	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
379	bic	tmp1, tmp1, #AT91_PMC_CSS
380	str	tmp1, [pmc, #AT91_PMC_MCKR]
381
382	mov	tmp3, #0
383	wait_mckrdy tmp3
384
385	/* Switch main clock source to crystal oscillator */
386	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
387	orr	tmp1, tmp1, #AT91_PMC_MOSCSEL
388	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
389	orr	tmp1, tmp1, #AT91_PMC_KEY
390	str	tmp1, [pmc, #AT91_CKGR_MOR]
391
392	wait_moscsels
393
394	/* Switch the master clock source to main clock */
395	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
396	bic	tmp1, tmp1, #AT91_PMC_CSS
397	orr	tmp1, tmp1, #AT91_PMC_CSS_MAIN
398	str	tmp1, [pmc, #AT91_PMC_MCKR]
399
400	wait_mckrdy tmp3
401
402	/* Restore RC oscillator state */
403	ldr	tmp1, .saved_osc_status
404	tst	tmp1, #AT91_PMC_MOSCRCS
405	bne	3f
406
407	/* Disable RC oscillator */
408	ldr	tmp1, [pmc, #AT91_CKGR_MOR]
409	bic	tmp1, tmp1, #AT91_PMC_MOSCRCEN
410	bic	tmp1, tmp1, #AT91_PMC_KEY_MASK
411	orr	tmp1, tmp1, #AT91_PMC_KEY
412	str	tmp1, [pmc, #AT91_CKGR_MOR]
413
414	/* Wait RC oscillator disable done */
4154:	ldr	tmp1, [pmc, #AT91_PMC_SR]
416	tst	tmp1, #AT91_PMC_MOSCRCS
417	bne	4b
418
4193:
420.endm
421
422/*
423 * Save PLLA setting and disable it
424 *
425 * Side effects: overwrites tmp1, tmp2
426 */
427.macro at91_plla_disable
428#ifdef CFG_SAMA7G5
429	/* Save PLLA settings */
430	ldr	tmp2, [pmc, #AT91_PMC_PLL_UPDT]
431	bic	tmp2, tmp2, #AT91_PMC_PLL_UPDT_ID
432	str	tmp2, [pmc, #AT91_PMC_PLL_UPDT]
433
434	/* save div */
435	mov	tmp1, #0
436	ldr	tmp2, [pmc, #AT91_PMC_PLL_CTRL0]
437	bic	tmp2, tmp2, #0xffffff00
438	orr	tmp1, tmp1, tmp2
439
440	/* save mul */
441	ldr	tmp2, [pmc, #AT91_PMC_PLL_CTRL1]
442	bic	tmp2, tmp2, #0xffffff
443	orr	tmp1, tmp1, tmp2
444	str	tmp1, .saved_pllar
445
446	/* step 2 */
447	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
448	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
449	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
450	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
451
452	/* step 3 */
453	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
454	bic	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLLCK
455	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL
456	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
457
458	/* step 4 */
459	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
460	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
461	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
462	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
463
464	/* step 5 */
465	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
466	bic	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL
467	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
468
469	/* step 6 */
470	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
471	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
472	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
473	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
474#else
475	/* Save PLLA setting and disable it */
476	ldr	tmp1, [pmc, #AT91_CKGR_PLLAR]
477	str	tmp1, .saved_pllar
478
479	/* Disable PLLA. */
480	mov	tmp1, #AT91_PMC_PLLCOUNT
481	orr	tmp1, tmp1, #(1 << 29)		/* bit 29 always set */
482	str	tmp1, [pmc, #AT91_CKGR_PLLAR]
483#endif
4842:
485.endm
486
487/*
488 * Enable PLLA with the saved setting
489 *
490 * Side effects: overwrites tmp1, tmp2
491 */
492.macro at91_plla_enable
493#ifdef CFG_SAMA7G5
494	/* step 1 */
495	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
496	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
497	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
498	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
499
500	/* step 2 */
501	ldr	tmp1, =AT91_PMC_PLL_ACR_DEFAULT_PLLA
502	str	tmp1, [pmc, #AT91_PMC_PLL_ACR]
503
504	/* step 3 */
505	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL1]
506	ldr	tmp2, .saved_pllar
507	bic	tmp2, tmp2, #0xffffff
508	orr	tmp1, tmp1, tmp2
509	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL1]
510
511	/* step 4 */
512	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
513	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
514	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
515	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
516
517	/* step 5 */
518	ldr	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
519	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENLOCK
520	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL
521	orr	tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLLCK
522	bic	tmp1, tmp1, #0xff
523	ldr	tmp2, .saved_pllar
524	bic	tmp2, tmp2, #0xffffff00
525	orr	tmp1, tmp1, tmp2
526	str	tmp1, [pmc, #AT91_PMC_PLL_CTRL0]
527
528	/* step 6 */
529	ldr	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
530	orr	tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE
531	bic	tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
532	str	tmp1, [pmc, #AT91_PMC_PLL_UPDT]
533
534	/* step 7 */
5353:	ldr	tmp1, [pmc, #AT91_PMC_PLL_ISR0]
536	tst	tmp1, #0x1
537	beq	3b
538#else
539	ldr	tmp2, .saved_pllar
540
541	/* Restore PLLA setting */
542	str	tmp2, [pmc, #AT91_CKGR_PLLAR]
543
544	/* Enable PLLA. */
545	tst	tmp2, #(AT91_PMC_MUL &  0xff0000)
546	bne	1f
547	tst	tmp2, #(AT91_PMC_MUL & ~0xff0000)
548	beq	2f
549
5501:	ldr	tmp1, [pmc, #AT91_PMC_SR]
551	tst	tmp1, #AT91_PMC_LOCKA
552	beq	1b
5532:
554#endif
555.endm
556
557#ifdef CFG_SAMA7G5
558/*
559 * at91_mckx_ps_enable:	save MCK1..4 settings and switch it to main clock
560 *
561 * Side effects: overwrites tmp1, tmp2, tmp3
562 */
563.macro at91_mckx_ps_enable
564	ldr	pmc, .pmc_base
565
566	/* There are 4 MCKs we need to handle: MCK1..4 */
567	mov	tmp1, #1
568e_loop:
569	/* Write MCK ID to retrieve the settings */
570	str	tmp1, [pmc, #AT91_PMC_MCR_V2]
571	ldr	tmp2, [pmc, #AT91_PMC_MCR_V2]
572
573	cmp	tmp1, #1
574	streq	tmp2, .saved_mck1
575	cmp	tmp1, #2
576	streq	tmp2, .saved_mck2
577	cmp	tmp1, #3
578	streq	tmp2, .saved_mck3
579	cmp	tmp1, #4
580	streq	tmp2, .saved_mck4
581
582	/* Use CSS=MD_SLOW_CLK and DIV=64. */
583	bic	tmp2, tmp2, #AT91_PMC_MCR_V2_CSS_MASK
584	bic	tmp2, tmp2, #AT91_PMC_MCR_V2_DIV_MASK
585	orr	tmp2, tmp2, #AT91_PMC_MCR_V2_CSS_MD_SLCK
586	orr	tmp2, tmp2, #AT91_PMC_MCR_V2_DIV64
587	orr	tmp2, tmp2, #AT91_PMC_MCR_V2_CMD
588	str	tmp2, [pmc, #AT91_PMC_MCR_V2]
589
590	mov	tmp2, tmp1
591	wait_mckrdy tmp1
592	mov	tmp1, tmp2
593
594	add	tmp1, tmp1, #1
595	cmp	tmp1, #5
596	bne	e_loop
597.endm
598
599/*
600 * at91_mckx_ps_restore: restore MCK1..4 settings
601 *
602 * Side effects: overwrites tmp1, tmp2, tmp3
603 */
604.macro at91_mckx_ps_restore
605	ldr	pmc, .pmc_base
606
607	/* There are 4 MCKs we need to handle: MCK1..4 */
608	mov	tmp1, #1
609	ldr	tmp2, .saved_mck1
610r_loop:
611	cmp	tmp1, #2
612	ldreq	tmp2, .saved_mck2
613	cmp	tmp1, #3
614	ldreq	tmp2, .saved_mck3
615	cmp	tmp1, #4
616	ldreq	tmp2, .saved_mck4
617
618	/* Write MCK ID to retrieve the settings */
619	str	tmp1, [pmc, #AT91_PMC_MCR_V2]
620	ldr	tmp3, [pmc, #AT91_PMC_MCR_V2]
621
622	/* We need to restore CSS and DIV. */
623	bic	tmp3, tmp3, #AT91_PMC_MCR_V2_CSS_MASK
624	bic	tmp3, tmp3, #AT91_PMC_MCR_V2_DIV_MASK
625	orr	tmp3, tmp3, tmp2
626	bic	tmp3, tmp3, #AT91_PMC_MCR_V2_ID_MASK
627	orr	tmp3, tmp3, tmp1
628	orr	tmp3, tmp3, #AT91_PMC_MCR_V2_CMD
629	str	tmp3, [pmc, #AT91_PMC_MCR_V2]
630
631	mov	tmp2, tmp1
632	wait_mckrdy tmp1
633	mov	tmp1, tmp2
634
635	add	tmp1, tmp1, #1
636	cmp	tmp1, #5
637	bne	r_loop
638.endm
639#endif
640
641SUSPEND_FUNC(at91_ulp_mode)
642#ifdef CFG_SAMA7G5
643	at91_mckx_ps_enable
644#endif
645
646	ldr	pmc, .pmc_base
647	ldr	tmp3, .pm_mode
648
649	/* Save Master clock setting */
650	ldr	tmp1, [pmc, #AT91_PMC_MCKR]
651	str	tmp1, .saved_mckr
652
653	/*
654	 * Set master clock source to:
655	 * - MAINCK if using ULP0 fast variant
656	 * - slow clock, otherwise
657	 */
658	bic	tmp1, tmp1, #AT91_PMC_CSS
659	cmp	tmp3, #AT91_PM_ULP0_FAST
660	bne	save_mck
661	orr	tmp1, tmp1, #AT91_PMC_CSS_MAIN
662save_mck:
663	str	tmp1, [pmc, #AT91_PMC_MCKR]
664
665	mov	tmp3, #0
666	wait_mckrdy tmp3
667
668	at91_plla_disable
669
670	ldr	tmp3, .pm_mode
671	cmp	tmp3, #AT91_PM_ULP1
672	beq	ulp1_mode
673
674	at91_pm_ulp0_mode
675	b	ulp_exit
676
677ulp1_mode:
678	at91_pm_ulp1_mode
679	b	ulp_exit
680
681ulp_exit:
682	ldr	pmc, .pmc_base
683
684	at91_plla_enable
685
686	/*
687	 * Restore master clock setting
688	 */
689	ldr	tmp2, .saved_mckr
690	str	tmp2, [pmc, #AT91_PMC_MCKR]
691
692	mov	tmp3, #0
693	wait_mckrdy tmp3
694
695#ifdef CFG_SAMA7G5
696	at91_mckx_ps_restore
697#endif
698
699	mov	pc, lr
700SUSPEND_END_FUNC(at91_ulp_mode)
701
702/*
703 * void at91_sramc_self_refresh(unsigned int is_active)
704 *
705 * @input param:
706 *	@r0: 1 - active self-refresh mode
707 *	     0 - exit self-refresh mode
708 * register usage:
709 *	@r2: base address of the sram controller
710 */
711
712SUSPEND_FUNC(at91_sramc_self_refresh)
713	ldr	r2, .sramc_base
714
715	/*
716	 * DDR Memory controller
717	 */
718	tst	r0, #SRAMC_SELF_FRESH_ACTIVE
719	beq	ddrc_exit_sf
720
721	/* LPDDR1 --> force DDR2 mode during self-refresh */
722	ldr	r3, [r2, #AT91_DDRSDRC_MDR]
723	str	r3, .saved_sam9_mdr
724	bic	r3, r3, #~AT91_DDRSDRC_MD
725	cmp	r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
726	ldreq	r3, [r2, #AT91_DDRSDRC_MDR]
727	biceq	r3, r3, #AT91_DDRSDRC_MD
728	orreq	r3, r3, #AT91_DDRSDRC_MD_DDR2
729	streq	r3, [r2, #AT91_DDRSDRC_MDR]
730
731	/* Active DDRC self-refresh mode */
732	ldr	r3, [r2, #AT91_DDRSDRC_LPR]
733	str	r3, .saved_sam9_lpr
734	bic	r3, r3, #AT91_DDRSDRC_LPCB
735	orr	r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
736	str	r3, [r2, #AT91_DDRSDRC_LPR]
737
738	b	exit_sramc_sf
739
740ddrc_exit_sf:
741	/* Restore MDR in case of LPDDR1 */
742	ldr	r3, .saved_sam9_mdr
743	str	r3, [r2, #AT91_DDRSDRC_MDR]
744	/* Restore LPR on AT91 with DDRAM */
745	ldr	r3, .saved_sam9_lpr
746	str	r3, [r2, #AT91_DDRSDRC_LPR]
747
748exit_sramc_sf:
749	mov	pc, lr
750SUSPEND_END_FUNC(at91_sramc_self_refresh)
751
752.pmc_base:
753	.word 0
754.sramc_base:
755	.word 0
756.sramc_phy_base:
757	.word 0
758.shdwc:
759	.word 0
760.sfrbu:
761	.word 0
762.pm_mode:
763	.word 0
764.saved_mckr:
765	.word 0
766.saved_pllar:
767	.word 0
768.saved_sam9_lpr:
769	.word 0
770.saved_sam9_mdr:
771	.word 0
772.saved_osc_status:
773	.word 0
774#ifdef CFG_SAMA7G5
775.saved_mck1:
776	.word 0
777.saved_mck2:
778	.word 0
779.saved_mck3:
780	.word 0
781.saved_mck4:
782	.word 0
783#endif
784
785.global at91_pm_suspend_in_sram_sz
786at91_pm_suspend_in_sram_sz:
787	.word .-at91_pm_suspend_in_sram
788
789check_fit_in_sram at91_pm_suspend_in_sram
790