]>
Commit | Line | Data |
---|---|---|
8428e5ad DG |
1 | /* |
2 | * Low level PM code for TI EMIF | |
3 | * | |
4 | * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ | |
5 | * Dave Gerlach | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation version 2. | |
10 | * | |
11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
12 | * kind, whether express or implied; without even the implied warranty | |
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <generated/ti-emif-asm-offsets.h> | |
18 | #include <linux/linkage.h> | |
19 | #include <asm/assembler.h> | |
20 | #include <asm/memory.h> | |
21 | ||
22 | #include "emif.h" | |
23 | ||
24 | #define EMIF_POWER_MGMT_WAIT_SELF_REFRESH_8192_CYCLES 0x00a0 | |
25 | #define EMIF_POWER_MGMT_SR_TIMER_MASK 0x00f0 | |
26 | #define EMIF_POWER_MGMT_SELF_REFRESH_MODE 0x0200 | |
27 | #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700 | |
28 | ||
29 | #define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT | |
30 | #define EMIF_STATUS_READY 0x4 | |
31 | ||
32 | #define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120 | |
33 | ||
34 | #define EMIF_AM437X_REGISTERS 0x1 | |
35 | ||
36 | .arm | |
37 | .align 3 | |
38 | ||
39 | ENTRY(ti_emif_sram) | |
40 | ||
41 | /* | |
42 | * void ti_emif_save_context(void) | |
43 | * | |
44 | * Used during suspend to save the context of all required EMIF registers | |
45 | * to local memory if the EMIF is going to lose context during the sleep | |
46 | * transition. Operates on the VIRTUAL address of the EMIF. | |
47 | */ | |
48 | ENTRY(ti_emif_save_context) | |
49 | stmfd sp!, {r4 - r11, lr} @ save registers on stack | |
50 | ||
51 | adr r4, ti_emif_pm_sram_data | |
52 | ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET] | |
53 | ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET] | |
54 | ||
55 | /* Save EMIF configuration */ | |
56 | ldr r1, [r0, #EMIF_SDRAM_CONFIG] | |
57 | str r1, [r2, #EMIF_SDCFG_VAL_OFFSET] | |
58 | ||
59 | ldr r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL] | |
60 | str r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET] | |
61 | ||
62 | ldr r1, [r0, #EMIF_SDRAM_TIMING_1] | |
63 | str r1, [r2, #EMIF_TIMING1_VAL_OFFSET] | |
64 | ||
65 | ldr r1, [r0, #EMIF_SDRAM_TIMING_2] | |
66 | str r1, [r2, #EMIF_TIMING2_VAL_OFFSET] | |
67 | ||
68 | ldr r1, [r0, #EMIF_SDRAM_TIMING_3] | |
69 | str r1, [r2, #EMIF_TIMING3_VAL_OFFSET] | |
70 | ||
71 | ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
72 | str r1, [r2, #EMIF_PMCR_VAL_OFFSET] | |
73 | ||
74 | ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW] | |
75 | str r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET] | |
76 | ||
77 | ldr r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG] | |
78 | str r1, [r2, #EMIF_ZQCFG_VAL_OFFSET] | |
79 | ||
80 | ldr r1, [r0, #EMIF_DDR_PHY_CTRL_1] | |
81 | str r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET] | |
82 | ||
83 | ldr r1, [r0, #EMIF_COS_CONFIG] | |
84 | str r1, [r2, #EMIF_COS_CONFIG_OFFSET] | |
85 | ||
86 | ldr r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING] | |
87 | str r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET] | |
88 | ||
89 | ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING] | |
90 | str r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET] | |
91 | ||
92 | ldr r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING] | |
93 | str r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET] | |
94 | ||
95 | ldr r1, [r0, #EMIF_OCP_CONFIG] | |
96 | str r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET] | |
97 | ||
98 | ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET] | |
99 | cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT | |
100 | bne emif_skip_save_extra_regs | |
101 | ||
102 | ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL] | |
103 | str r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET] | |
104 | ||
105 | ldr r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD] | |
106 | str r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET] | |
107 | ||
108 | ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING] | |
109 | str r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET] | |
110 | ||
111 | ldr r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW] | |
112 | str r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET] | |
113 | ||
114 | ldr r1, [r0, #EMIF_DLL_CALIB_CTRL] | |
115 | str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET] | |
116 | ||
117 | ldr r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW] | |
118 | str r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET] | |
119 | ||
120 | /* Loop and save entire block of emif phy regs */ | |
121 | mov r5, #0x0 | |
122 | add r4, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET | |
123 | add r3, r0, #EMIF_EXT_PHY_CTRL_1 | |
124 | ddr_phy_ctrl_save: | |
125 | ldr r1, [r3, r5] | |
126 | str r1, [r4, r5] | |
127 | add r5, r5, #0x4 | |
128 | cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT | |
129 | bne ddr_phy_ctrl_save | |
130 | ||
131 | emif_skip_save_extra_regs: | |
132 | ldmfd sp!, {r4 - r11, pc} @ restore regs and return | |
133 | ENDPROC(ti_emif_save_context) | |
134 | ||
135 | /* | |
136 | * void ti_emif_restore_context(void) | |
137 | * | |
138 | * Used during resume to restore the context of all required EMIF registers | |
139 | * from local memory after the EMIF has lost context during a sleep transition. | |
140 | * Operates on the PHYSICAL address of the EMIF. | |
141 | */ | |
142 | ENTRY(ti_emif_restore_context) | |
143 | adr r4, ti_emif_pm_sram_data | |
144 | ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET] | |
145 | ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET] | |
146 | ||
147 | /* Config EMIF Timings */ | |
148 | ldr r1, [r2, #EMIF_DDR_PHY_CTLR_1_OFFSET] | |
149 | str r1, [r0, #EMIF_DDR_PHY_CTRL_1] | |
150 | str r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW] | |
151 | ||
152 | ldr r1, [r2, #EMIF_TIMING1_VAL_OFFSET] | |
153 | str r1, [r0, #EMIF_SDRAM_TIMING_1] | |
154 | str r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW] | |
155 | ||
156 | ldr r1, [r2, #EMIF_TIMING2_VAL_OFFSET] | |
157 | str r1, [r0, #EMIF_SDRAM_TIMING_2] | |
158 | str r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW] | |
159 | ||
160 | ldr r1, [r2, #EMIF_TIMING3_VAL_OFFSET] | |
161 | str r1, [r0, #EMIF_SDRAM_TIMING_3] | |
162 | str r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW] | |
163 | ||
164 | ldr r1, [r2, #EMIF_REF_CTRL_VAL_OFFSET] | |
165 | str r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL] | |
166 | str r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW] | |
167 | ||
168 | ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET] | |
169 | str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
170 | ||
171 | ldr r1, [r2, #EMIF_PMCR_SHDW_VAL_OFFSET] | |
172 | str r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW] | |
173 | ||
174 | ldr r1, [r2, #EMIF_COS_CONFIG_OFFSET] | |
175 | str r1, [r0, #EMIF_COS_CONFIG] | |
176 | ||
177 | ldr r1, [r2, #EMIF_PRIORITY_TO_COS_MAPPING_OFFSET] | |
178 | str r1, [r0, #EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING] | |
179 | ||
180 | ldr r1, [r2, #EMIF_CONNECT_ID_SERV_1_MAP_OFFSET] | |
181 | str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING] | |
182 | ||
183 | ldr r1, [r2, #EMIF_CONNECT_ID_SERV_2_MAP_OFFSET] | |
184 | str r1, [r0, #EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING] | |
185 | ||
186 | ldr r1, [r2, #EMIF_OCP_CONFIG_VAL_OFFSET] | |
187 | str r1, [r0, #EMIF_OCP_CONFIG] | |
188 | ||
189 | ldr r5, [r4, #EMIF_PM_CONFIG_OFFSET] | |
190 | cmp r5, #EMIF_SRAM_AM43_REG_LAYOUT | |
191 | bne emif_skip_restore_extra_regs | |
192 | ||
193 | ldr r1, [r2, #EMIF_RD_WR_LEVEL_RAMP_CTRL_OFFSET] | |
194 | str r1, [r0, #EMIF_READ_WRITE_LEVELING_RAMP_CONTROL] | |
195 | ||
196 | ldr r1, [r2, #EMIF_RD_WR_EXEC_THRESH_OFFSET] | |
197 | str r1, [r0, #EMIF_READ_WRITE_EXECUTION_THRESHOLD] | |
198 | ||
199 | ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_OFFSET] | |
200 | str r1, [r0, #EMIF_LPDDR2_NVM_TIMING] | |
201 | ||
202 | ldr r1, [r2, #EMIF_LPDDR2_NVM_TIM_SHDW_OFFSET] | |
203 | str r1, [r0, #EMIF_LPDDR2_NVM_TIMING_SHDW] | |
204 | ||
205 | ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_OFFSET] | |
206 | str r1, [r0, #EMIF_DLL_CALIB_CTRL] | |
207 | ||
208 | ldr r1, [r2, #EMIF_DLL_CALIB_CTRL_VAL_SHDW_OFFSET] | |
209 | str r1, [r0, #EMIF_DLL_CALIB_CTRL_SHDW] | |
210 | ||
211 | ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET] | |
212 | str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG] | |
213 | ||
214 | /* Loop and restore entire block of emif phy regs */ | |
215 | mov r5, #0x0 | |
216 | /* Load ti_emif_regs_amx3 + EMIF_EXT_PHY_CTRL_VALS_OFFSET for address | |
217 | * to phy register save space | |
218 | */ | |
219 | add r3, r2, #EMIF_EXT_PHY_CTRL_VALS_OFFSET | |
220 | add r4, r0, #EMIF_EXT_PHY_CTRL_1 | |
221 | ddr_phy_ctrl_restore: | |
222 | ldr r1, [r3, r5] | |
223 | str r1, [r4, r5] | |
224 | add r5, r5, #0x4 | |
225 | cmp r5, #AM43XX_EMIF_PHY_CTRL_REG_COUNT | |
226 | bne ddr_phy_ctrl_restore | |
227 | ||
228 | emif_skip_restore_extra_regs: | |
229 | /* | |
230 | * Output impedence calib needed only for DDR3 | |
231 | * but since the initial state of this will be | |
232 | * disabled for DDR2 no harm in restoring the | |
233 | * old configuration | |
234 | */ | |
235 | ldr r1, [r2, #EMIF_ZQCFG_VAL_OFFSET] | |
236 | str r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG] | |
237 | ||
238 | /* Write to sdcfg last for DDR2 only */ | |
239 | ldr r1, [r2, #EMIF_SDCFG_VAL_OFFSET] | |
240 | and r2, r1, #SDRAM_TYPE_MASK | |
241 | cmp r2, #EMIF_SDCFG_TYPE_DDR2 | |
242 | streq r1, [r0, #EMIF_SDRAM_CONFIG] | |
243 | ||
244 | mov pc, lr | |
245 | ENDPROC(ti_emif_restore_context) | |
246 | ||
247 | /* | |
248 | * void ti_emif_enter_sr(void) | |
249 | * | |
250 | * Programs the EMIF to tell the SDRAM to enter into self-refresh | |
251 | * mode during a sleep transition. Operates on the VIRTUAL address | |
252 | * of the EMIF. | |
253 | */ | |
254 | ENTRY(ti_emif_enter_sr) | |
255 | stmfd sp!, {r4 - r11, lr} @ save registers on stack | |
256 | ||
257 | adr r4, ti_emif_pm_sram_data | |
258 | ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET] | |
259 | ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET] | |
260 | ||
261 | ldr r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
262 | bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK | |
263 | orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE | |
264 | str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
265 | ||
266 | ldmfd sp!, {r4 - r11, pc} @ restore regs and return | |
267 | ENDPROC(ti_emif_enter_sr) | |
268 | ||
269 | /* | |
270 | * void ti_emif_exit_sr(void) | |
271 | * | |
272 | * Programs the EMIF to tell the SDRAM to exit self-refresh mode | |
273 | * after a sleep transition. Operates on the PHYSICAL address of | |
274 | * the EMIF. | |
275 | */ | |
276 | ENTRY(ti_emif_exit_sr) | |
277 | adr r4, ti_emif_pm_sram_data | |
278 | ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET] | |
279 | ldr r2, [r4, #EMIF_PM_REGS_PHYS_OFFSET] | |
280 | ||
281 | /* | |
282 | * Toggle EMIF to exit refresh mode: | |
283 | * if EMIF lost context, PWR_MGT_CTRL is currently 0, writing disable | |
284 | * (0x0), wont do diddly squat! so do a toggle from SR(0x2) to disable | |
285 | * (0x0) here. | |
286 | * *If* EMIF did not lose context, nothing broken as we write the same | |
287 | * value(0x2) to reg before we write a disable (0x0). | |
288 | */ | |
289 | ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET] | |
290 | bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK | |
291 | orr r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE | |
292 | str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
293 | bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK | |
294 | str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
295 | ||
296 | /* Wait for EMIF to become ready */ | |
297 | 1: ldr r1, [r0, #EMIF_STATUS] | |
298 | tst r1, #EMIF_STATUS_READY | |
299 | beq 1b | |
300 | ||
301 | mov pc, lr | |
302 | ENDPROC(ti_emif_exit_sr) | |
303 | ||
304 | /* | |
305 | * void ti_emif_abort_sr(void) | |
306 | * | |
307 | * Disables self-refresh after a failed transition to a low-power | |
308 | * state so the kernel can jump back to DDR and follow abort path. | |
309 | * Operates on the VIRTUAL address of the EMIF. | |
310 | */ | |
311 | ENTRY(ti_emif_abort_sr) | |
312 | stmfd sp!, {r4 - r11, lr} @ save registers on stack | |
313 | ||
314 | adr r4, ti_emif_pm_sram_data | |
315 | ldr r0, [r4, #EMIF_PM_BASE_ADDR_VIRT_OFFSET] | |
316 | ldr r2, [r4, #EMIF_PM_REGS_VIRT_OFFSET] | |
317 | ||
318 | ldr r1, [r2, #EMIF_PMCR_VAL_OFFSET] | |
319 | bic r1, r1, #EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK | |
320 | str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL] | |
321 | ||
322 | /* Wait for EMIF to become ready */ | |
323 | 1: ldr r1, [r0, #EMIF_STATUS] | |
324 | tst r1, #EMIF_STATUS_READY | |
325 | beq 1b | |
326 | ||
327 | ldmfd sp!, {r4 - r11, pc} @ restore regs and return | |
328 | ENDPROC(ti_emif_abort_sr) | |
329 | ||
330 | .align 3 | |
331 | ENTRY(ti_emif_pm_sram_data) | |
332 | .space EMIF_PM_DATA_SIZE | |
333 | ENTRY(ti_emif_sram_sz) | |
334 | .word . - ti_emif_save_context |