162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/linkage.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define M4IF_MCR0_OFFSET			(0x008C)
1162306a36Sopenharmony_ci#define M4IF_MCR0_FDVFS				(0x1 << 11)
1262306a36Sopenharmony_ci#define M4IF_MCR0_FDVACK			(0x1 << 27)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	.align 3
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/*
1762306a36Sopenharmony_ci * ==================== low level suspend ====================
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * On entry
2062306a36Sopenharmony_ci * r0: pm_info structure address;
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * suspend ocram space layout:
2362306a36Sopenharmony_ci * ======================== high address ======================
2462306a36Sopenharmony_ci *                              .
2562306a36Sopenharmony_ci *                              .
2662306a36Sopenharmony_ci *                              .
2762306a36Sopenharmony_ci *                              ^
2862306a36Sopenharmony_ci *                              ^
2962306a36Sopenharmony_ci *                              ^
3062306a36Sopenharmony_ci *                      imx53_suspend code
3162306a36Sopenharmony_ci *              PM_INFO structure(imx5_cpu_suspend_info)
3262306a36Sopenharmony_ci * ======================== low address =======================
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* Offsets of members of struct imx5_cpu_suspend_info */
3662306a36Sopenharmony_ci#define SUSPEND_INFO_MX53_M4IF_V_OFFSET		0x0
3762306a36Sopenharmony_ci#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET	0x4
3862306a36Sopenharmony_ci#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET	0x8
3962306a36Sopenharmony_ci#define SUSPEND_INFO_MX53_IO_STATE_OFFSET	0xc
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciENTRY(imx53_suspend)
4262306a36Sopenharmony_ci	stmfd	sp!, {r4,r5,r6,r7}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* Save pad config */
4562306a36Sopenharmony_ci	ldr	r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
4662306a36Sopenharmony_ci	cmp	r1, #0
4762306a36Sopenharmony_ci	beq	skip_pad_conf_1
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	add	r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
5062306a36Sopenharmony_ci	ldr	r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci1:
5362306a36Sopenharmony_ci	ldr	r5, [r2], #12	/* IOMUXC register offset */
5462306a36Sopenharmony_ci	ldr	r6, [r3, r5]	/* current value */
5562306a36Sopenharmony_ci	str	r6, [r2], #4	/* save area */
5662306a36Sopenharmony_ci	subs	r1, r1, #1
5762306a36Sopenharmony_ci	bne	1b
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciskip_pad_conf_1:
6062306a36Sopenharmony_ci	/* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */
6162306a36Sopenharmony_ci	ldr	r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
6262306a36Sopenharmony_ci	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
6362306a36Sopenharmony_ci	orr	r2, r2, #M4IF_MCR0_FDVFS
6462306a36Sopenharmony_ci	str	r2,[r1, #M4IF_MCR0_OFFSET]
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */
6762306a36Sopenharmony_ciwait_sr_ack:
6862306a36Sopenharmony_ci	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
6962306a36Sopenharmony_ci	ands	r2, r2, #M4IF_MCR0_FDVACK
7062306a36Sopenharmony_ci	beq	wait_sr_ack
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Set pad config */
7362306a36Sopenharmony_ci	ldr	r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
7462306a36Sopenharmony_ci	cmp	r1, #0
7562306a36Sopenharmony_ci	beq	skip_pad_conf_2
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	add	r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
7862306a36Sopenharmony_ci	ldr	r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci2:
8162306a36Sopenharmony_ci	ldr	r5, [r2], #4	/* IOMUXC register offset */
8262306a36Sopenharmony_ci	ldr	r6, [r2], #4	/* clear */
8362306a36Sopenharmony_ci	ldr	r7, [r3, r5]
8462306a36Sopenharmony_ci	bic	r7, r7, r6
8562306a36Sopenharmony_ci	ldr	r6, [r2], #8	/* set */
8662306a36Sopenharmony_ci	orr	r7, r7, r6
8762306a36Sopenharmony_ci	str	r7, [r3, r5]
8862306a36Sopenharmony_ci	subs	r1, r1, #1
8962306a36Sopenharmony_ci	bne	2b
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciskip_pad_conf_2:
9262306a36Sopenharmony_ci	/* Zzz, enter stop mode */
9362306a36Sopenharmony_ci	wfi
9462306a36Sopenharmony_ci	nop
9562306a36Sopenharmony_ci	nop
9662306a36Sopenharmony_ci	nop
9762306a36Sopenharmony_ci	nop
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Restore pad config */
10062306a36Sopenharmony_ci	ldr	r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
10162306a36Sopenharmony_ci	cmp	r1, #0
10262306a36Sopenharmony_ci	beq	skip_pad_conf_3
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	add	r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
10562306a36Sopenharmony_ci	ldr	r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci3:
10862306a36Sopenharmony_ci	ldr	r5, [r2], #12	/* IOMUXC register offset */
10962306a36Sopenharmony_ci	ldr	r6, [r2], #4	/* saved value */
11062306a36Sopenharmony_ci	str	r6, [r3, r5]
11162306a36Sopenharmony_ci	subs	r1, r1, #1
11262306a36Sopenharmony_ci	bne	3b
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ciskip_pad_conf_3:
11562306a36Sopenharmony_ci	/* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */
11662306a36Sopenharmony_ci	ldr	r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
11762306a36Sopenharmony_ci	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
11862306a36Sopenharmony_ci	bic	r2, r2, #M4IF_MCR0_FDVFS
11962306a36Sopenharmony_ci	str	r2,[r1, #M4IF_MCR0_OFFSET]
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */
12262306a36Sopenharmony_ciwait_ar_ack:
12362306a36Sopenharmony_ci	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
12462306a36Sopenharmony_ci	ands	r2, r2, #M4IF_MCR0_FDVACK
12562306a36Sopenharmony_ci	bne	wait_ar_ack
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Restore registers */
12862306a36Sopenharmony_ci	ldmfd	sp!, {r4,r5,r6,r7}
12962306a36Sopenharmony_ci	mov	pc, lr
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciENDPROC(imx53_suspend)
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciENTRY(imx53_suspend_sz)
13462306a36Sopenharmony_ci        .word   . - imx53_suspend
135