pm.c 4.3 KB

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