a674a028e9a74ea66d0fd0ef3d2b18175cde5047
1 /*
2 * Low level suspend code for AM33XX SoCs
3 *
4 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation version 2.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
16 #include <linux/linkage.h>
17 #include <linux/init.h>
18 #include <asm/memory.h>
19 #include <asm/assembler.h>
20 #include <mach/io.h>
21 #include <plat/emif.h>
22 #include "cm33xx.h"
24 #include <plat/emif.h>
25 #include <plat/sram.h>
27 #include "cm33xx.h"
28 #include "pm33xx.h"
29 #include "control.h"
31 /* We should probably pass in the virtual address of PRCM, Control and EMIF
32 * along with the physical addresses
33 * load it into the registers and then continue
34 */
35 .align 3
36 ENTRY(am33xx_do_wfi)
37 stmfd sp!, {r4 - r11, lr} @ save registers on stack
39 .macro pll_bypass, name, clk_mode_addr, idlest_addr
40 pll_bypass_\name:
41 ldr r0, \clk_mode_addr
42 ldr r1, [r0]
43 bic r1, r1, #(7 << 0)
44 orr r1, r1, #0x5
45 str r1, [r0]
46 ldr r0, \idlest_addr
47 wait_pll_bypass_\name:
48 ldr r1, [r0]
49 tst r1, #0x0
50 bne wait_pll_bypass_\name
51 .endm
53 .macro pll_lock, name, clk_mode_addr, idlest_addr
54 pll_lock_\name:
55 ldr r0, \clk_mode_addr
56 ldr r1, [r0]
57 bic r1, r1, #(7 << 0)
58 orr r1, r1, #0x7
59 str r1, [r0]
60 ldr r0, \idlest_addr
61 wait_pll_lock_\name:
62 ldr r1, [r0]
63 tst r1, #0x1
64 bne wait_pll_lock_\name
65 .endm
67 /* Put DDR in Self-Refresh */
68 ldr r0, emif_addr_func
69 blx r0
70 add r1, r0, #EMIF4_0_SDRAM_MGMT_CTRL
71 ldr r2, [r1]
72 orr r2, r2, #0xa0 @ a reasonable delay for entering SR
73 str r2, [r1, #0]
75 ldr r2, ddr_start @ do a dummy access to DDR
76 ldr r3, [r2, #0]
77 ldr r3, [r1, #0]
78 orr r3, r3, #0x200
79 str r3, [r1, #0]
81 mov r1, #0x1000 @ Give some time for the system to enter SR
82 wait_sr:
83 subs r1, r1, #1
84 bne wait_sr
86 /* IO to work in mDDR mode */
87 ldr r0, virt_ddr_io_ctrl
88 ldr r1, [r0]
89 mov r2, #1
90 mov r3, r2, lsl #28
91 str r3, [r0]
93 /* Put the PLLs in bypass mode */
94 pll_bypass core, virt_core_clk_mode, virt_core_idlest
95 pll_bypass ddr, virt_ddr_clk_mode, virt_ddr_idlest
96 pll_bypass disp, virt_disp_clk_mode, virt_disp_idlest
97 pll_bypass per, virt_per_clk_mode, virt_per_idlest
98 pll_bypass mpu, virt_mpu_clk_mode, virt_mpu_idlest
100 dsb
101 dmb
102 isb
104 wfi
105 nop
106 nop
107 nop
108 nop
109 nop
110 nop
111 nop
112 nop
113 nop
114 nop
115 nop
117 /* We come here in case of an abort */
118 /* Revert the PHY and PLL related changes */
120 /* Relock the PLLs */
121 pll_lock mpu_abt, virt_mpu_clk_mode, virt_mpu_idlest
122 pll_lock per_abt, virt_per_clk_mode, virt_per_idlest
123 pll_lock disp_abt, virt_disp_clk_mode, virt_disp_idlest
124 pll_lock ddr_abt, virt_ddr_clk_mode, virt_ddr_idlest
125 pll_lock core_abt, virt_core_clk_mode, virt_core_idlest
127 /* IO to work in mDDR mode */
128 ldr r0, virt_ddr_io_ctrl
129 ldr r1, [r0]
130 mov r3, r2, lsl #28
131 str r3, [r0]
133 mov r0, #7
134 ldmfd sp!, {r4 - r11, pc} @ restore regs and return
136 nop
137 nop
138 nop
139 nop
140 nop
141 nop
142 nop
143 nop
144 nop
145 nop
146 nop
147 nop
148 nop
150 /* Take the PLLs out of LP_BYPASS */
151 pll_lock mpu, phys_mpu_clk_mode, phys_mpu_idlest
152 pll_lock per, phys_per_clk_mode, phys_per_idlest
153 pll_lock disp, phys_disp_clk_mode, phys_disp_idlest
154 pll_lock ddr, phys_ddr_clk_mode, phys_ddr_idlest
155 pll_lock core, phys_core_clk_mode, phys_core_idlest
157 /* Disable EMIF self-refresh */
158 ldr r0, emif_phys_addr
159 add r0, r0, #EMIF4_0_SDRAM_MGMT_CTRL
160 ldr r1, [r0]
161 bic r1, r1, #(0x7 << 7)
162 str r1, [r0]
164 /* Take out IO of mDDR mode */
165 ldr r0, phys_ddr_io_ctrl
166 ldr r1, [r0]
167 bic r1, r1, #28
168 str r1, [r0]
170 /*
171 * Instead of harcoding the EMIF and DDR PHY related settings
172 * in this file, the sane thing to do would have been to backup
173 * the register contents during suspend and restore it back in
174 * the resume path. However, due to the Si errata related to
175 * DDR PHY registers, these registers are read-only. So, we'll
176 * need to hardcode atleast the DDR PHY configuration over here.
177 * We _could_ back up the EMIF registers but in order to be
178 * consistent with the DDR setup procedure we skip this for now.
179 * The person updating the DDR PHY config values is expected
180 * to update the EMIF config values also.
181 */
183 config_vtp:
184 ldr r0, vtp0_addr
185 ldr r1, [r0]
186 ldr r2, vtp_enable
187 orr r1, r2
188 str r1, [r0]
190 ldr r1, [r0]
191 bic r1, #1
192 str r1, [r0]
194 ldr r1, [r0]
195 orr r1, #1
196 str r1, [r0]
198 poll_vtp_ready:
199 ldr r1, [r0]
200 tst r1, #(1 << 5)
201 beq poll_vtp_ready
203 cmd_macro_config:
204 ldr r0, ddr_phy_base
205 ldr r1, [r0]
206 ldr r2, ddr2_ratio_val
207 mov r3, r2
208 @ TODO: Need to use proper variable here
209 mov r4, #0
210 str r3, [r0, #28] @cmd0
211 str r4, [r0, #32]
212 str r4, [r0, #36]
213 str r4, [r0, #40]
214 str r4, [r0, #44]
215 str r3, [r0, #80] @cmd1
216 str r4, [r0, #84]
217 str r4, [r0, #88]
218 str r4, [r0, #92]
219 str r4, [r0, #96]
220 str r3, [r0, #132] @cmd2
221 str r4, [r0, #136]
222 str r4, [r0, #140]
223 str r4, [r0, #144]
224 str r4, [r0, #148]
226 mov r3, #0x0
227 bl data_macro_config
228 mov r3, #0xa4
229 bl data_macro_config
230 b setup_rank_delays
232 data_macro_config:
233 ldr r0, ddr_phy_base
234 add r0, r0, r3
235 rd_dqs:
236 ldr r1, data0_rd_dqs_slave_ratio0_val
237 mov r2, r1
238 /* shift by 30, 20, 10 and orr */
239 mov r5, r2, lsl #10
240 mov r6, r2, lsl #20
241 mov r7, r2, lsl #30
242 orr r2, r2, r5
243 orr r2, r2, r6
244 orr r2, r2, r7
245 /* Done with crazy bit ops. store it now */
246 str r2, [r0, #200]
247 ldr r1, data0_rd_dqs_slave_ratio1_val
248 mov r2, r1
249 mov r5, r2, lsr #2
250 mov r2, r5
251 str r2, [r0, #204]
252 wr_dqs:
253 ldr r1, data0_wr_dqs_slave_ratio0_val
254 mov r2, r1
255 /* shift by 30, 20, 10 and orr */
256 mov r5, r2, lsl #10
257 mov r6, r2, lsl #20
258 mov r7, r2, lsl #30
259 orr r2, r2, r5
260 orr r2, r2, r6
261 orr r2, r2, r7
262 /* Done with crazy bit ops. store it now */
263 str r2, [r0, #220]
264 ldr r1, data0_wr_dqs_slave_ratio1_val
265 mov r2, r1
266 mov r5, r2, lsr #2
267 mov r2, r5
268 str r2, [r0, #224]
269 wr_lvl:
270 ldr r1, data0_wr_lvl_init_ratio0_val
271 mov r2, r1
272 /* shift by 30, 20, 10 and orr */
273 mov r5, r2, lsl #10
274 mov r6, r2, lsl #20
275 mov r7, r2, lsl #30
276 orr r2, r2, r5
277 orr r2, r2, r6
278 orr r2, r2, r7
279 /* Done with crazy bit ops. store it now */
280 str r2, [r0, #240]
281 ldr r1, data0_wr_lvl_init_ratio1_val
282 mov r2, r1
283 mov r5, r2, lsr #2
284 mov r2, r5
285 str r2, [r0, #244]
286 gate_lvl:
287 ldr r1, data0_gate_lvl_init_ratio0_val
288 mov r2, r1
289 /* shift by 30, 20, 10 and orr */
290 mov r5, r2, lsl #10
291 mov r6, r2, lsl #20
292 mov r7, r2, lsl #30
293 orr r2, r2, r5
294 orr r2, r2, r6
295 orr r2, r2, r7
296 /* Done with crazy bit ops. store it now */
297 str r2, [r0, #248]
298 ldr r1, data0_gate_lvl_init_ratio1_val
299 mov r2, r1
300 mov r5, r2, lsr #2
301 mov r2, r5
302 str r2, [r0, #256]
303 we_slv:
304 ldr r1, data0_wr_lvl_slave_ratio0_val
305 mov r2, r1
306 /* shift by 30, 20, 10 and orr */
307 mov r5, r2, lsl #10
308 mov r6, r2, lsl #20
309 mov r7, r2, lsl #30
310 orr r2, r2, r5
311 orr r2, r2, r6
312 orr r2, r2, r7
313 /* Done with crazy bit ops. store it now */
314 str r2, [r0, #264]
315 ldr r1, data0_wr_lvl_slave_ratio1_val
316 mov r2, r1
317 mov r5, r2, lsr #2
318 mov r2, r5
319 str r2, [r0, #268]
320 wr_data:
321 ldr r1, data0_wr_data_slave_ratio0_val
322 mov r2, r1
323 /* shift by 30, 20, 10 and orr */
324 mov r5, r2, lsl #10
325 mov r6, r2, lsl #20
326 mov r7, r2, lsl #30
327 orr r2, r2, r5
328 orr r2, r2, r6
329 orr r2, r2, r7
330 /* Done with crazy bit ops. store it now */
331 str r2, [r0, #288]
332 ldr r1, data0_wr_data_slave_ratio1_val
333 mov r2, r1
334 mov r5, r2, lsr #2
335 mov r2, r5
336 str r2, [r0, #292]
337 dll_lock:
338 ldr r1, data0_dll_lock_diff_val
339 mov r2, r1
340 str r2, [r0, #312]
342 setup_rank_delays:
343 ldr r1, data0_rank0_delay0_val
344 mov r2, r1
345 str r2, [r0, #308]
346 ldr r1, data1_rank0_delay1_val
347 mov r2, r1
348 str r2, [r0, #472]
350 setup_io_ctrl:
351 ldr r0, control_base
352 ldr r1, ddr_ioctrl_val
353 mov r2, r1
354 ldr r4, ddr_cmd_offset
355 mov r3, r4
356 str r2, [r0, r3] @cmd0 0x1404
357 add r3, r3, #4
358 str r2, [r0, r3] @cmd1 0x1408
359 add r3, r3, #4
360 str r2, [r0, r3] @cmd2 0x140c
361 ldr r4, ddr_data_offset
362 mov r3, r4
363 str r2, [r0, r3] @data0 0x1440
364 add r3, r3, #4
365 str r2, [r0, r3] @data1 0x1444
367 misc_config:
368 ldr r1, ddr_io_ctrl_addr
369 ldr r2, [r1]
370 and r2, #0xefffffff
371 str r2, [r1]
372 ldr r1, ddr_cke_addr
373 ldr r2, [r1]
374 orr r2, #0x00000001
375 str r2, [r1]
377 config_emif_timings:
378 mov r3, #1275068416 @ 0x4c000000
379 disable_sr:
380 mov r4, #0
381 str r4, [r3, #56] @ 0x38
382 ldr r4, emif_rd_lat_val
383 mov r2, r4
384 rd_lat:
385 str r2, [r3, #228] @ 0xe4
386 str r2, [r3, #232] @ 0xe8
387 str r2, [r3, #236] @ 0xec
388 timing1:
389 ldr r4, emif_timing1_val
390 mov r2, r4
391 str r2, [r3, #24]
392 str r2, [r3, #28]
393 timing2:
394 ldr r4, emif_timing2_val
395 mov r2, r4
396 str r2, [r3, #32]
397 str r2, [r3, #36] @ 0x24
398 timing3:
399 ldr r4, emif_timing3_val
400 mov r2, r4
401 str r2, [r3, #40] @ 0x28
402 str r2, [r3, #44] @ 0x2c
403 sdcfg1:
404 ldr r4, emif_sdcfg_val
405 mov r2, r4
406 str r2, [r3, #8]
407 str r2, [r3, #12]
408 ref_ctrl_const:
409 ldr r4, emif_ref_ctrl_const_val
410 mov r2, r4
411 str r2, [r3, #16]
412 str r2, [r3, #20]
414 /* GEL had a loop with init value of 5000 */
415 mov r0, #0x1000
416 wait_loop1:
417 subs r0, r0, #1
418 bne wait_loop1
420 ref_ctrl_actual:
421 ldr r4, emif_ref_ctrl_val
422 mov r2, r4
423 str r2, [r3, #16]
424 str r2, [r3, #20]
425 sdcfg2:
426 ldr r4, emif_sdcfg_val
427 mov r2, r4
428 str r2, [r3, #8]
429 str r2, [r3, #12]
431 /* Back from la-la-land. Kill some time for sanity to settle in */
432 mov r0, #0x1000
433 wait_loop2:
434 subs r0, r0, #1
435 bne wait_loop2
437 /* We are back. Branch to the common CPU resume routine */
438 ENTRY(am33xx_resume_vector)
439 ldr pc, resume_addr
441 /*
442 * Local variables
443 */
445 resume_addr:
446 .word cpu_resume - PAGE_OFFSET + 0x80000000
448 emif_addr_func:
449 .word am33xx_get_ram_base
450 emif_phys_addr:
451 .word AM33XX_EMIF0_BASE
453 emif_pm_ctrl:
454 .word EMIF4_0_SDRAM_MGMT_CTRL
455 ddr_start:
456 .word PAGE_OFFSET
458 virt_mpu_idlest:
459 .word AM33XX_CM_IDLEST_DPLL_MPU
460 virt_mpu_clk_mode:
461 .word AM33XX_CM_CLKMODE_DPLL_MPU
463 phys_pll_mod:
464 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD
465 phys_mpu_clk_mode:
466 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_CLKMODE_DPLL_MPU_OFFSET
467 phys_mpu_idlest:
468 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_IDLEST_DPLL_MPU_OFFSET
470 virt_core_idlest:
471 .word AM33XX_CM_IDLEST_DPLL_CORE
472 virt_core_clk_mode:
473 .word AM33XX_CM_CLKMODE_DPLL_CORE
474 phys_core_clk_mode:
475 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_CLKMODE_DPLL_CORE_OFFSET
476 phys_core_idlest:
477 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_IDLEST_DPLL_CORE_OFFSET
479 virt_per_idlest:
480 .word AM33XX_CM_IDLEST_DPLL_PER
481 virt_per_clk_mode:
482 .word AM33XX_CM_CLKMODE_DPLL_PER
483 phys_per_clk_mode:
484 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_CLKMODE_DPLL_PER_OFFSET
485 phys_per_idlest:
486 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_IDLEST_DPLL_PER_OFFSET
488 virt_disp_idlest:
489 .word AM33XX_CM_IDLEST_DPLL_DISP
490 virt_disp_clk_mode:
491 .word AM33XX_CM_CLKMODE_DPLL_DISP
492 phys_disp_clk_mode:
493 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_CLKMODE_DPLL_DISP_OFFSET
494 phys_disp_idlest:
495 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_IDLEST_DPLL_DISP_OFFSET
497 virt_ddr_idlest:
498 .word AM33XX_CM_IDLEST_DPLL_DDR
499 virt_ddr_clk_mode:
500 .word AM33XX_CM_CLKMODE_DPLL_DDR
501 phys_ddr_clk_mode:
502 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_CLKMODE_DPLL_DDR_OFFSET
503 phys_ddr_idlest:
504 .word AM33XX_CM_BASE + AM33XX_CM_WKUP_MOD + AM33XX_CM_IDLEST_DPLL_DDR_OFFSET
507 /* DDR related stuff */
508 vtp0_addr:
509 .word VTP0_CTRL_REG
510 vtp_enable:
511 .word VTP_CTRL_ENABLE
512 vtp_start_en:
513 .word VTP_CTRL_START_EN
514 vtp_ready:
515 .word VTP_CTRL_READY
517 ddr_phy_base:
518 .word DDR_PHY_BASE_ADDR
519 ddr2_ratio_val:
520 .word DDR2_RATIO
521 data0_rd_dqs_slave_ratio0_val:
522 .word DDR2_RD_DQS
523 data0_rd_dqs_slave_ratio1_val:
524 .word DDR2_RD_DQS
525 data0_wr_dqs_slave_ratio0_val:
526 .word DDR2_WR_DQS
527 data0_wr_dqs_slave_ratio1_val:
528 .word DDR2_WR_DQS
529 data0_wr_lvl_init_ratio0_val:
530 .word DDR2_PHY_WRLVL
531 data0_wr_lvl_init_ratio1_val:
532 .word DDR2_PHY_WRLVL
533 data0_gate_lvl_init_ratio0_val:
534 .word DDR2_PHY_GATELVL
535 data0_gate_lvl_init_ratio1_val:
536 .word DDR2_PHY_GATELVL
537 data0_wr_lvl_slave_ratio0_val:
538 .word DDR2_PHY_FIFO_WE
539 data0_wr_lvl_slave_ratio1_val:
540 .word DDR2_PHY_FIFO_WE
541 data0_wr_data_slave_ratio0_val:
542 .word DDR2_PHY_WR_DATA
543 data0_wr_data_slave_ratio1_val:
544 .word DDR2_PHY_WR_DATA
545 data0_dll_lock_diff_val:
546 .word PHY_DLL_LOCK_DIFF
548 data0_rank0_delay0_val:
549 .word PHY_RANK0_DELAY
550 data1_rank0_delay1_val:
551 .word PHY_RANK0_DELAY
553 control_base:
554 .word AM33XX_CTRL_BASE
555 ddr_io_ctrl_addr:
556 .word DDR_IO_CTRL
557 ddr_ioctrl_val:
558 .word 0x18B
559 ddr_cmd_offset:
560 .word 0x1404
561 ddr_data_offset:
562 .word 0x1440
563 virt_ddr_io_ctrl:
564 .word AM33XX_CTRL_REGADDR(0x0E04)
565 phys_ddr_io_ctrl:
566 .word DDR_IO_CTRL
568 ddr_cke_addr:
569 .word DDR_CKE_CTRL
570 emif_rd_lat_val:
571 .word EMIF_READ_LATENCY
572 emif_timing1_val:
573 .word EMIF_TIM1
574 emif_timing2_val:
575 .word EMIF_TIM2
576 emif_timing3_val:
577 .word EMIF_TIM3
578 emif_sdcfg_val:
579 .word EMIF_SDCFG
580 emif_ref_ctrl_const_val:
581 .word 0x4650
582 emif_ref_ctrl_val:
583 .word EMIF_SDREF
585 ENTRY(am33xx_do_wfi_sz)
586 .word . - am33xx_do_wfi