pm.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /* linux/arch/arm/mach-s5p64x0/pm.c
  2. *
  3. * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  4. * http://www.samsung.com
  5. *
  6. * S5P64X0 Power Management Support
  7. *
  8. * Based on arch/arm/mach-s3c64xx/pm.c by Ben Dooks
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. #include <linux/suspend.h>
  15. #include <linux/syscore_ops.h>
  16. #include <linux/io.h>
  17. #include <plat/cpu.h>
  18. #include <plat/pm.h>
  19. #include <plat/regs-timer.h>
  20. #include <plat/wakeup-mask.h>
  21. #include <mach/regs-clock.h>
  22. #include <mach/regs-gpio.h>
  23. static struct sleep_save s5p64x0_core_save[] = {
  24. SAVE_ITEM(S5P64X0_APLL_CON),
  25. SAVE_ITEM(S5P64X0_MPLL_CON),
  26. SAVE_ITEM(S5P64X0_EPLL_CON),
  27. SAVE_ITEM(S5P64X0_EPLL_CON_K),
  28. SAVE_ITEM(S5P64X0_CLK_SRC0),
  29. SAVE_ITEM(S5P64X0_CLK_SRC1),
  30. SAVE_ITEM(S5P64X0_CLK_DIV0),
  31. SAVE_ITEM(S5P64X0_CLK_DIV1),
  32. SAVE_ITEM(S5P64X0_CLK_DIV2),
  33. SAVE_ITEM(S5P64X0_CLK_DIV3),
  34. SAVE_ITEM(S5P64X0_CLK_GATE_MEM0),
  35. SAVE_ITEM(S5P64X0_CLK_GATE_HCLK1),
  36. SAVE_ITEM(S5P64X0_CLK_GATE_SCLK1),
  37. };
  38. static struct sleep_save s5p64x0_misc_save[] = {
  39. SAVE_ITEM(S5P64X0_AHB_CON0),
  40. SAVE_ITEM(S5P64X0_SPCON0),
  41. SAVE_ITEM(S5P64X0_SPCON1),
  42. SAVE_ITEM(S5P64X0_MEM0CONSLP0),
  43. SAVE_ITEM(S5P64X0_MEM0CONSLP1),
  44. SAVE_ITEM(S5P64X0_MEM0DRVCON),
  45. SAVE_ITEM(S5P64X0_MEM1DRVCON),
  46. SAVE_ITEM(S3C64XX_TINT_CSTAT),
  47. };
  48. /* DPLL is present only in S5P6450 */
  49. static struct sleep_save s5p6450_core_save[] = {
  50. SAVE_ITEM(S5P6450_DPLL_CON),
  51. SAVE_ITEM(S5P6450_DPLL_CON_K),
  52. };
  53. void s3c_pm_configure_extint(void)
  54. {
  55. __raw_writel(s3c_irqwake_eintmask, S5P64X0_EINT_WAKEUP_MASK);
  56. }
  57. void s3c_pm_restore_core(void)
  58. {
  59. __raw_writel(0, S5P64X0_EINT_WAKEUP_MASK);
  60. s3c_pm_do_restore_core(s5p64x0_core_save,
  61. ARRAY_SIZE(s5p64x0_core_save));
  62. if (soc_is_s5p6450())
  63. s3c_pm_do_restore_core(s5p6450_core_save,
  64. ARRAY_SIZE(s5p6450_core_save));
  65. s3c_pm_do_restore(s5p64x0_misc_save, ARRAY_SIZE(s5p64x0_misc_save));
  66. }
  67. void s3c_pm_save_core(void)
  68. {
  69. s3c_pm_do_save(s5p64x0_misc_save, ARRAY_SIZE(s5p64x0_misc_save));
  70. if (soc_is_s5p6450())
  71. s3c_pm_do_save(s5p6450_core_save,
  72. ARRAY_SIZE(s5p6450_core_save));
  73. s3c_pm_do_save(s5p64x0_core_save, ARRAY_SIZE(s5p64x0_core_save));
  74. }
  75. static int s5p64x0_cpu_suspend(unsigned long arg)
  76. {
  77. unsigned long tmp = 0;
  78. /*
  79. * Issue the standby signal into the pm unit. Note, we
  80. * issue a write-buffer drain just in case.
  81. */
  82. asm("b 1f\n\t"
  83. ".align 5\n\t"
  84. "1:\n\t"
  85. "mcr p15, 0, %0, c7, c10, 5\n\t"
  86. "mcr p15, 0, %0, c7, c10, 4\n\t"
  87. "mcr p15, 0, %0, c7, c0, 4" : : "r" (tmp));
  88. /* we should never get past here */
  89. panic("sleep resumed to originator?");
  90. }
  91. /* mapping of interrupts to parts of the wakeup mask */
  92. static struct samsung_wakeup_mask s5p64x0_wake_irqs[] = {
  93. { .irq = IRQ_RTC_ALARM, .bit = S5P64X0_PWR_CFG_RTC_ALRM_DISABLE, },
  94. { .irq = IRQ_RTC_TIC, .bit = S5P64X0_PWR_CFG_RTC_TICK_DISABLE, },
  95. { .irq = IRQ_HSMMC0, .bit = S5P64X0_PWR_CFG_MMC0_DISABLE, },
  96. { .irq = IRQ_HSMMC1, .bit = S5P64X0_PWR_CFG_MMC1_DISABLE, },
  97. };
  98. static void s5p64x0_pm_prepare(void)
  99. {
  100. u32 tmp;
  101. samsung_sync_wakemask(S5P64X0_PWR_CFG,
  102. s5p64x0_wake_irqs, ARRAY_SIZE(s5p64x0_wake_irqs));
  103. /* store the resume address in INFORM0 register */
  104. __raw_writel(virt_to_phys(s3c_cpu_resume), S5P64X0_INFORM0);
  105. /* setup clock gating for FIMGVG block */
  106. __raw_writel((__raw_readl(S5P64X0_CLK_GATE_HCLK1) | \
  107. (S5P64X0_CLK_GATE_HCLK1_FIMGVG)), S5P64X0_CLK_GATE_HCLK1);
  108. __raw_writel((__raw_readl(S5P64X0_CLK_GATE_SCLK1) | \
  109. (S5P64X0_CLK_GATE_SCLK1_FIMGVG)), S5P64X0_CLK_GATE_SCLK1);
  110. /* Configure the stabilization counter with wait time required */
  111. __raw_writel(S5P64X0_PWR_STABLE_PWR_CNT_VAL4, S5P64X0_PWR_STABLE);
  112. /* set WFI to SLEEP mode configuration */
  113. tmp = __raw_readl(S5P64X0_SLEEP_CFG);
  114. tmp &= ~(S5P64X0_SLEEP_CFG_OSC_EN);
  115. __raw_writel(tmp, S5P64X0_SLEEP_CFG);
  116. tmp = __raw_readl(S5P64X0_PWR_CFG);
  117. tmp &= ~(S5P64X0_PWR_CFG_WFI_MASK);
  118. tmp |= S5P64X0_PWR_CFG_WFI_SLEEP;
  119. __raw_writel(tmp, S5P64X0_PWR_CFG);
  120. /*
  121. * set OTHERS register to disable interrupt before going to
  122. * sleep. This bit is present only in S5P6450, it is reserved
  123. * in S5P6440.
  124. */
  125. if (soc_is_s5p6450()) {
  126. tmp = __raw_readl(S5P64X0_OTHERS);
  127. tmp |= S5P6450_OTHERS_DISABLE_INT;
  128. __raw_writel(tmp, S5P64X0_OTHERS);
  129. }
  130. /* ensure previous wakeup state is cleared before sleeping */
  131. __raw_writel(__raw_readl(S5P64X0_WAKEUP_STAT), S5P64X0_WAKEUP_STAT);
  132. }
  133. static int s5p64x0_pm_add(struct device *dev, struct subsys_interface *sif)
  134. {
  135. pm_cpu_prep = s5p64x0_pm_prepare;
  136. pm_cpu_sleep = s5p64x0_cpu_suspend;
  137. pm_uart_udivslot = 1;
  138. return 0;
  139. }
  140. static struct subsys_interface s5p64x0_pm_interface = {
  141. .name = "s5p64x0_pm",
  142. .subsys = &s5p64x0_subsys,
  143. .add_dev = s5p64x0_pm_add,
  144. };
  145. static __init int s5p64x0_pm_drvinit(void)
  146. {
  147. s3c_pm_init();
  148. return subsys_interface_register(&s5p64x0_pm_interface);
  149. }
  150. arch_initcall(s5p64x0_pm_drvinit);
  151. static void s5p64x0_pm_resume(void)
  152. {
  153. u32 tmp;
  154. tmp = __raw_readl(S5P64X0_OTHERS);
  155. tmp |= (S5P64X0_OTHERS_RET_MMC0 | S5P64X0_OTHERS_RET_MMC1 | \
  156. S5P64X0_OTHERS_RET_UART);
  157. __raw_writel(tmp , S5P64X0_OTHERS);
  158. }
  159. static struct syscore_ops s5p64x0_pm_syscore_ops = {
  160. .resume = s5p64x0_pm_resume,
  161. };
  162. static __init int s5p64x0_pm_syscore_init(void)
  163. {
  164. register_syscore_ops(&s5p64x0_pm_syscore_ops);
  165. return 0;
  166. }
  167. arch_initcall(s5p64x0_pm_syscore_init);