pm.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * arch/arm/mach-lpc32xx/pm.c
  3. *
  4. * Original authors: Vitaly Wool, Dmitry Chigirev <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. /*
  13. * LPC32XX CPU and system power management
  14. *
  15. * The LPC32XX has three CPU modes for controlling system power: run,
  16. * direct-run, and halt modes. When switching between halt and run modes,
  17. * the CPU transistions through direct-run mode. For Linux, direct-run
  18. * mode is not used in normal operation. Halt mode is used when the
  19. * system is fully suspended.
  20. *
  21. * Run mode:
  22. * The ARM CPU clock (HCLK_PLL), HCLK bus clock, and PCLK bus clocks are
  23. * derived from the HCLK PLL. The HCLK and PCLK bus rates are divided from
  24. * the HCLK_PLL rate. Linux runs in this mode.
  25. *
  26. * Direct-run mode:
  27. * The ARM CPU clock, HCLK bus clock, and PCLK bus clocks are driven from
  28. * SYSCLK. SYSCLK is usually around 13MHz, but may vary based on SYSCLK
  29. * source or the frequency of the main oscillator. In this mode, the
  30. * HCLK_PLL can be safely enabled, changed, or disabled.
  31. *
  32. * Halt mode:
  33. * SYSCLK is gated off and the CPU and system clocks are halted.
  34. * Peripherals based on the 32KHz oscillator clock (ie, RTC, touch,
  35. * key scanner, etc.) still operate if enabled. In this state, an enabled
  36. * system event (ie, GPIO state change, RTC match, key press, etc.) will
  37. * wake the system up back into direct-run mode.
  38. *
  39. * DRAM refresh
  40. * DRAM clocking and refresh are slightly different for systems with DDR
  41. * DRAM or regular SDRAM devices. If SDRAM is used in the system, the
  42. * SDRAM will still be accessible in direct-run mode. In DDR based systems,
  43. * a transition to direct-run mode will stop all DDR accesses (no clocks).
  44. * Because of this, the code to switch power modes and the code to enter
  45. * and exit DRAM self-refresh modes must not be executed in DRAM. A small
  46. * section of IRAM is used instead for this.
  47. *
  48. * Suspend is handled with the following logic:
  49. * Backup a small area of IRAM used for the suspend code
  50. * Copy suspend code to IRAM
  51. * Transfer control to code in IRAM
  52. * Places DRAMs in self-refresh mode
  53. * Enter direct-run mode
  54. * Save state of HCLK_PLL PLL
  55. * Disable HCLK_PLL PLL
  56. * Enter halt mode - CPU and buses will stop
  57. * System enters direct-run mode when an enabled event occurs
  58. * HCLK PLL state is restored
  59. * Run mode is entered
  60. * DRAMS are placed back into normal mode
  61. * Code execution returns from IRAM
  62. * IRAM code are used for suspend is restored
  63. * Suspend mode is exited
  64. */
  65. #include <linux/suspend.h>
  66. #include <linux/io.h>
  67. #include <linux/slab.h>
  68. #include <asm/cacheflush.h>
  69. #include <mach/hardware.h>
  70. #include <mach/platform.h>
  71. #include "common.h"
  72. #define TEMP_IRAM_AREA IO_ADDRESS(LPC32XX_IRAM_BASE)
  73. /*
  74. * Both STANDBY and MEM suspend states are handled the same with no
  75. * loss of CPU or memory state
  76. */
  77. static int lpc32xx_pm_enter(suspend_state_t state)
  78. {
  79. int (*lpc32xx_suspend_ptr) (void);
  80. void *iram_swap_area;
  81. /* Allocate some space for temporary IRAM storage */
  82. iram_swap_area = kmalloc(lpc32xx_sys_suspend_sz, GFP_KERNEL);
  83. if (!iram_swap_area) {
  84. printk(KERN_ERR
  85. "PM Suspend: cannot allocate memory to save portion "
  86. "of SRAM\n");
  87. return -ENOMEM;
  88. }
  89. /* Backup a small area of IRAM used for the suspend code */
  90. memcpy(iram_swap_area, (void *) TEMP_IRAM_AREA,
  91. lpc32xx_sys_suspend_sz);
  92. /*
  93. * Copy code to suspend system into IRAM. The suspend code
  94. * needs to run from IRAM as DRAM may no longer be available
  95. * when the PLL is stopped.
  96. */
  97. memcpy((void *) TEMP_IRAM_AREA, &lpc32xx_sys_suspend,
  98. lpc32xx_sys_suspend_sz);
  99. flush_icache_range((unsigned long)TEMP_IRAM_AREA,
  100. (unsigned long)(TEMP_IRAM_AREA) + lpc32xx_sys_suspend_sz);
  101. /* Transfer to suspend code in IRAM */
  102. lpc32xx_suspend_ptr = (void *) TEMP_IRAM_AREA;
  103. flush_cache_all();
  104. (void) lpc32xx_suspend_ptr();
  105. /* Restore original IRAM contents */
  106. memcpy((void *) TEMP_IRAM_AREA, iram_swap_area,
  107. lpc32xx_sys_suspend_sz);
  108. kfree(iram_swap_area);
  109. return 0;
  110. }
  111. static const struct platform_suspend_ops lpc32xx_pm_ops = {
  112. .valid = suspend_valid_only_mem,
  113. .enter = lpc32xx_pm_enter,
  114. };
  115. #define EMC_DYN_MEM_CTRL_OFS 0x20
  116. #define EMC_SRMMC (1 << 3)
  117. #define EMC_CTRL_REG io_p2v(LPC32XX_EMC_BASE + EMC_DYN_MEM_CTRL_OFS)
  118. static int __init lpc32xx_pm_init(void)
  119. {
  120. /*
  121. * Setup SDRAM self-refresh clock to automatically disable o
  122. * start of self-refresh. This only needs to be done once.
  123. */
  124. __raw_writel(__raw_readl(EMC_CTRL_REG) | EMC_SRMMC, EMC_CTRL_REG);
  125. suspend_set_ops(&lpc32xx_pm_ops);
  126. return 0;
  127. }
  128. arch_initcall(lpc32xx_pm_init);