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

source code of linux/arch/arm/mach-davinci/sleep.S