xref: /openbmc/linux/arch/arm/mach-davinci/sleep.S (revision 0c6dfa75)
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * (C) Copyright 2009, Texas Instruments, Inc. https://www.ti.com/
4 */
5
6/* replicated define because linux/bitops.h cannot be included in assembly */
7#define BIT(nr)			(1 << (nr))
8
9#include <linux/linkage.h>
10#include <asm/assembler.h>
11#include "psc.h"
12#include "ddr2.h"
13
14#include "clock.h"
15
16/* Arbitrary, hardware currently does not update PHYRDY correctly */
17#define PHYRDY_CYCLES		0x1000
18
19/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
20#define PLL_BYPASS_CYCLES	(PLL_BYPASS_TIME * 25)
21#define PLL_RESET_CYCLES	(PLL_RESET_TIME	* 25)
22#define PLL_LOCK_CYCLES		(PLL_LOCK_TIME * 25)
23
24#define DEEPSLEEP_SLEEPENABLE_BIT	BIT(31)
25
26	.text
27	.arch	armv5te
28/*
29 * Move DaVinci into deep sleep state
30 *
31 * Note: This code is copied to internal SRAM by PM code. When the DaVinci
32 *	 wakes up it continues execution at the point it went to sleep.
33 * Register Usage:
34 * 	r0: contains virtual base for DDR2 controller
35 * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
36 * 	r2: contains PSC number for DDR2
37 * 	r3: contains virtual base DDR2 PLL controller
38 * 	r4: contains virtual address of the DEEPSLEEP register
39 */
40ENTRY(davinci_cpu_suspend)
41	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
42
43	ldr 	ip, CACHE_FLUSH
44	blx	ip
45
46	ldmia	r0, {r0-r4}
47
48	/*
49	 * Switch DDR to self-refresh mode.
50	 */
51
52	/* calculate SDRCR address */
53	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
54	bic	ip, ip, #DDR2_SRPD_BIT
55	orr	ip, ip, #DDR2_LPMODEN_BIT
56	str	ip, [r0, #DDR2_SDRCR_OFFSET]
57
58	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
59	orr	ip, ip, #DDR2_MCLKSTOPEN_BIT
60	str	ip, [r0, #DDR2_SDRCR_OFFSET]
61
62       mov	ip, #PHYRDY_CYCLES
631:     subs	ip, ip, #0x1
64       bne	1b
65
66       /* Disable DDR2 LPSC */
67	mov	r7, r0
68	mov	r0, #0x2
69	bl davinci_ddr_psc_config
70	mov	r0, r7
71
72	/* Disable clock to DDR PHY */
73	ldr	ip, [r3, #PLLDIV1]
74	bic	ip, ip, #PLLDIV_EN
75	str	ip, [r3, #PLLDIV1]
76
77	/* Put the DDR PLL in bypass and power down */
78	ldr	ip, [r3, #PLLCTL]
79	bic	ip, ip, #PLLCTL_PLLENSRC
80	bic	ip, ip, #PLLCTL_PLLEN
81	str	ip, [r3, #PLLCTL]
82
83	/* Wait for PLL to switch to bypass */
84       mov	ip, #PLL_BYPASS_CYCLES
852:     subs	ip, ip, #0x1
86       bne	2b
87
88       /* Power down the PLL */
89	ldr	ip, [r3, #PLLCTL]
90	orr	ip, ip, #PLLCTL_PLLPWRDN
91	str	ip, [r3, #PLLCTL]
92
93	/* Go to deep sleep */
94	ldr	ip, [r4]
95	orr	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
96	/* System goes to sleep beyond after this instruction */
97	str	ip, [r4]
98
99	/* Wake up from sleep */
100
101	/* Clear sleep enable */
102	ldr	ip, [r4]
103	bic	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
104	str	ip, [r4]
105
106	/* initialize the DDR PLL controller */
107
108	/* Put PLL in reset */
109	ldr	ip, [r3, #PLLCTL]
110	bic	ip, ip, #PLLCTL_PLLRST
111	str	ip, [r3, #PLLCTL]
112
113	/* Clear PLL power down */
114	ldr	ip, [r3, #PLLCTL]
115	bic	ip, ip, #PLLCTL_PLLPWRDN
116	str	ip, [r3, #PLLCTL]
117
118       mov	ip, #PLL_RESET_CYCLES
1193:     subs	ip, ip, #0x1
120       bne	3b
121
122       /* Bring PLL out of reset */
123	ldr	ip, [r3, #PLLCTL]
124	orr	ip, ip, #PLLCTL_PLLRST
125	str	ip, [r3, #PLLCTL]
126
127	/* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
128       mov	ip, #PLL_LOCK_CYCLES
1294:     subs	ip, ip, #0x1
130       bne	4b
131
132       /* Remove PLL from bypass mode */
133	ldr	ip, [r3, #PLLCTL]
134	bic	ip, ip, #PLLCTL_PLLENSRC
135	orr	ip, ip, #PLLCTL_PLLEN
136	str	ip, [r3, #PLLCTL]
137
138	/* Start 2x clock to DDR2 */
139
140	ldr	ip, [r3, #PLLDIV1]
141	orr	ip, ip, #PLLDIV_EN
142	str	ip, [r3, #PLLDIV1]
143
144	/* Enable VCLK */
145
146       /* Enable DDR2 LPSC */
147	mov	r7, r0
148	mov	r0, #0x3
149	bl davinci_ddr_psc_config
150	mov	r0, r7
151
152	/* clear  MCLKSTOPEN */
153
154	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
155	bic	ip, ip, #DDR2_MCLKSTOPEN_BIT
156	str	ip, [r0, #DDR2_SDRCR_OFFSET]
157
158	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
159	bic	ip, ip, #DDR2_LPMODEN_BIT
160	str	ip, [r0, #DDR2_SDRCR_OFFSET]
161
162	/* Restore registers and return */
163	ldmfd   sp!, {r0-r12, pc}
164
165ENDPROC(davinci_cpu_suspend)
166
167/*
168 * Disables or Enables DDR2 LPSC
169 * Register Usage:
170 * 	r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
171 * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
172 * 	r2: contains PSC number for DDR2
173 */
174ENTRY(davinci_ddr_psc_config)
175	/* Set next state in mdctl for DDR2 */
176	mov	r6, #MDCTL
177	add	r6, r6, r2, lsl #2
178	ldr	ip, [r1, r6]
179	bic	ip, ip, #MDSTAT_STATE_MASK
180	orr	ip, ip, r0
181	str	ip, [r1, r6]
182
183	/* Enable the Power Domain Transition Command */
184	ldr	ip, [r1, #PTCMD]
185	orr	ip, ip, #0x1
186	str	ip, [r1, #PTCMD]
187
188	/* Check for Transition Complete (PTSTAT) */
189ptstat_done:
190	ldr	ip, [r1, #PTSTAT]
191	and	ip, ip, #0x1
192	cmp 	ip, #0x0
193	bne	ptstat_done
194
195	/* Check for DDR2 clock disable completion; */
196	mov	r6, #MDSTAT
197	add	r6, r6, r2, lsl #2
198ddr2clk_stop_done:
199	ldr	ip, [r1, r6]
200	and	ip, ip, #MDSTAT_STATE_MASK
201	cmp	ip, r0
202	bne	ddr2clk_stop_done
203
204	ret	lr
205ENDPROC(davinci_ddr_psc_config)
206
207CACHE_FLUSH:
208#ifdef CONFIG_CPU_V6
209	.word	v6_flush_kern_cache_all
210#else
211	.word   arm926_flush_kern_cache_all
212#endif
213
214ENTRY(davinci_cpu_suspend_sz)
215	.word	. - davinci_cpu_suspend
216ENDPROC(davinci_cpu_suspend_sz)
217