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 | */ |
40 | ENTRY(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 |
63 | 1: 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 |
85 | 2: 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 |
119 | 3: 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 |
129 | 4: 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 | |
165 | ENDPROC(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 | */ |
174 | ENTRY(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) */ |
189 | ptstat_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 |
198 | ddr2clk_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 |
205 | ENDPROC(davinci_ddr_psc_config) |
206 | |
207 | CACHE_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 | |
214 | ENTRY(davinci_cpu_suspend_sz) |
215 | .word . - davinci_cpu_suspend |
216 | ENDPROC(davinci_cpu_suspend_sz) |
217 | |