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