suspend.S 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * arch/arm/mach-lpc32xx/suspend.S
  3. *
  4. * Original authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com>
  5. * Modified by Kevin Wells <kevin.wells@nxp.com>
  6. *
  7. * 2005 (c) MontaVista Software, Inc. This file is licensed under
  8. * the terms of the GNU General Public License version 2. This program
  9. * is licensed "as is" without any warranty of any kind, whether express
  10. * or implied.
  11. */
  12. #include <linux/linkage.h>
  13. #include <asm/assembler.h>
  14. #include <mach/platform.h>
  15. #include <mach/hardware.h>
  16. /* Using named register defines makes the code easier to follow */
  17. #define WORK1_REG r0
  18. #define WORK2_REG r1
  19. #define SAVED_HCLK_DIV_REG r2
  20. #define SAVED_HCLK_PLL_REG r3
  21. #define SAVED_DRAM_CLKCTRL_REG r4
  22. #define SAVED_PWR_CTRL_REG r5
  23. #define CLKPWRBASE_REG r6
  24. #define EMCBASE_REG r7
  25. #define LPC32XX_EMC_STATUS_OFFS 0x04
  26. #define LPC32XX_EMC_STATUS_BUSY 0x1
  27. #define LPC32XX_EMC_STATUS_SELF_RFSH 0x4
  28. #define LPC32XX_CLKPWR_PWR_CTRL_OFFS 0x44
  29. #define LPC32XX_CLKPWR_HCLK_DIV_OFFS 0x40
  30. #define LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS 0x58
  31. #define CLKPWR_PCLK_DIV_MASK 0xFFFFFE7F
  32. .text
  33. ENTRY(lpc32xx_sys_suspend)
  34. @ Save a copy of the used registers in IRAM, r0 is corrupted
  35. adr r0, tmp_stack_end
  36. stmfd r0!, {r3 - r7, sp, lr}
  37. @ Load a few common register addresses
  38. adr WORK1_REG, reg_bases
  39. ldr CLKPWRBASE_REG, [WORK1_REG, #0]
  40. ldr EMCBASE_REG, [WORK1_REG, #4]
  41. ldr SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
  42. #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  43. orr WORK1_REG, SAVED_PWR_CTRL_REG, #LPC32XX_CLKPWR_SDRAM_SELF_RFSH
  44. @ Wait for SDRAM busy status to go busy and then idle
  45. @ This guarantees a small windows where DRAM isn't busy
  46. 1:
  47. ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
  48. and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
  49. cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
  50. bne 1b @ Branch while idle
  51. 2:
  52. ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
  53. and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
  54. cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
  55. beq 2b @ Branch until idle
  56. @ Setup self-refresh with support for manual exit of
  57. @ self-refresh mode
  58. str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  59. orr WORK2_REG, WORK1_REG, #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
  60. str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  61. str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  62. @ Wait for self-refresh acknowledge, clocks to the DRAM device
  63. @ will automatically stop on start of self-refresh
  64. 3:
  65. ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
  66. and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
  67. cmp WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
  68. bne 3b @ Branch until self-refresh mode starts
  69. @ Enter direct-run mode from run mode
  70. bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_SELECT_RUN_MODE
  71. str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  72. @ Safe disable of DRAM clock in EMC block, prevents DDR sync
  73. @ issues on restart
  74. ldr SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
  75. #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
  76. and WORK2_REG, SAVED_HCLK_DIV_REG, #CLKPWR_PCLK_DIV_MASK
  77. str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
  78. @ Save HCLK PLL state and disable HCLK PLL
  79. ldr SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
  80. #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
  81. bic WORK2_REG, SAVED_HCLK_PLL_REG, #LPC32XX_CLKPWR_HCLKPLL_POWER_UP
  82. str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
  83. @ Enter stop mode until an enabled event occurs
  84. orr WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
  85. str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  86. .rept 9
  87. nop
  88. .endr
  89. @ Clear stop status
  90. bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
  91. @ Restore original HCLK PLL value and wait for PLL lock
  92. str SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
  93. #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
  94. 4:
  95. ldr WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
  96. and WORK2_REG, WORK2_REG, #LPC32XX_CLKPWR_HCLKPLL_PLL_STS
  97. bne 4b
  98. @ Re-enter run mode with self-refresh flag cleared, but no DRAM
  99. @ update yet. DRAM is still in self-refresh
  100. str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
  101. #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  102. @ Restore original DRAM clock mode to restore DRAM clocks
  103. str SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
  104. #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
  105. @ Clear self-refresh mode
  106. orr WORK1_REG, SAVED_PWR_CTRL_REG,\
  107. #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
  108. str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  109. str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
  110. #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
  111. @ Wait for EMC to clear self-refresh mode
  112. 5:
  113. ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
  114. and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
  115. bne 5b @ Branch until self-refresh has exited
  116. @ restore regs and return
  117. adr r0, tmp_stack
  118. ldmfd r0!, {r3 - r7, sp, pc}
  119. reg_bases:
  120. .long IO_ADDRESS(LPC32XX_CLK_PM_BASE)
  121. .long IO_ADDRESS(LPC32XX_EMC_BASE)
  122. tmp_stack:
  123. .long 0, 0, 0, 0, 0, 0, 0
  124. tmp_stack_end:
  125. ENTRY(lpc32xx_sys_suspend_sz)
  126. .word . - lpc32xx_sys_suspend