pm.c 5.2 KB

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