pm-mmp2.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * MMP2 Power Management Routines
  3. *
  4. * This software program is licensed subject to the GNU General Public License
  5. * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
  6. *
  7. * (C) Copyright 2012 Marvell International Ltd.
  8. * All Rights Reserved
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/errno.h>
  12. #include <linux/err.h>
  13. #include <linux/time.h>
  14. #include <linux/delay.h>
  15. #include <linux/suspend.h>
  16. #include <linux/irq.h>
  17. #include <linux/io.h>
  18. #include <linux/interrupt.h>
  19. #include <asm/mach-types.h>
  20. #include <mach/hardware.h>
  21. #include <mach/cputype.h>
  22. #include <mach/addr-map.h>
  23. #include <mach/pm-mmp2.h>
  24. #include <mach/regs-icu.h>
  25. #include <mach/irqs.h>
  26. int mmp2_set_wake(struct irq_data *d, unsigned int on)
  27. {
  28. unsigned long data = 0;
  29. int irq = d->irq;
  30. /* enable wakeup sources */
  31. switch (irq) {
  32. case IRQ_MMP2_RTC:
  33. case IRQ_MMP2_RTC_ALARM:
  34. data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM;
  35. break;
  36. case IRQ_MMP2_PMIC:
  37. data = MPMU_WUCRM_PJ_WAKEUP(7);
  38. break;
  39. case IRQ_MMP2_MMC2:
  40. /* mmc use WAKEUP2, same as GPIO wakeup source */
  41. data = MPMU_WUCRM_PJ_WAKEUP(2);
  42. break;
  43. }
  44. if (on) {
  45. if (data) {
  46. data |= __raw_readl(MPMU_WUCRM_PJ);
  47. __raw_writel(data, MPMU_WUCRM_PJ);
  48. }
  49. } else {
  50. if (data) {
  51. data = ~data & __raw_readl(MPMU_WUCRM_PJ);
  52. __raw_writel(data, MPMU_WUCRM_PJ);
  53. }
  54. }
  55. return 0;
  56. }
  57. static void pm_scu_clk_disable(void)
  58. {
  59. unsigned int val;
  60. /* close AXI fabric clock gate */
  61. __raw_writel(0x0, CIU_REG(0x64));
  62. __raw_writel(0x0, CIU_REG(0x68));
  63. /* close MCB master clock gate */
  64. val = __raw_readl(CIU_REG(0x1c));
  65. val |= 0xf0;
  66. __raw_writel(val, CIU_REG(0x1c));
  67. return ;
  68. }
  69. static void pm_scu_clk_enable(void)
  70. {
  71. unsigned int val;
  72. /* open AXI fabric clock gate */
  73. __raw_writel(0x03003003, CIU_REG(0x64));
  74. __raw_writel(0x00303030, CIU_REG(0x68));
  75. /* open MCB master clock gate */
  76. val = __raw_readl(CIU_REG(0x1c));
  77. val &= ~(0xf0);
  78. __raw_writel(val, CIU_REG(0x1c));
  79. return ;
  80. }
  81. static void pm_mpmu_clk_disable(void)
  82. {
  83. /*
  84. * disable clocks in MPMU_CGR_PJ register
  85. * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
  86. */
  87. __raw_writel(0x0000a010, MPMU_CGR_PJ);
  88. }
  89. static void pm_mpmu_clk_enable(void)
  90. {
  91. unsigned int val;
  92. __raw_writel(0xdffefffe, MPMU_CGR_PJ);
  93. val = __raw_readl(MPMU_PLL2_CTRL1);
  94. val |= (1 << 29);
  95. __raw_writel(val, MPMU_PLL2_CTRL1);
  96. return ;
  97. }
  98. void mmp2_pm_enter_lowpower_mode(int state)
  99. {
  100. uint32_t idle_cfg, apcr;
  101. idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG);
  102. apcr = __raw_readl(MPMU_PCR_PJ);
  103. apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD
  104. | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13));
  105. idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE;
  106. switch (state) {
  107. case POWER_MODE_SYS_SLEEP:
  108. apcr |= MPMU_PCR_PJ_SLPEN; /* set the SLPEN bit */
  109. apcr |= MPMU_PCR_PJ_VCTCXOSD; /* set VCTCXOSD */
  110. /* fall through */
  111. case POWER_MODE_CHIP_SLEEP:
  112. apcr |= MPMU_PCR_PJ_SLPEN;
  113. /* fall through */
  114. case POWER_MODE_APPS_SLEEP:
  115. apcr |= MPMU_PCR_PJ_APBSD; /* set APBSD */
  116. /* fall through */
  117. case POWER_MODE_APPS_IDLE:
  118. apcr |= MPMU_PCR_PJ_AXISD; /* set AXISDD bit */
  119. apcr |= MPMU_PCR_PJ_DDRCORSD; /* set DDRCORSD bit */
  120. idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN; /* PJ power down */
  121. apcr |= MPMU_PCR_PJ_SPSD;
  122. /* fall through */
  123. case POWER_MODE_CORE_EXTIDLE:
  124. idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE; /* set the IDLE bit */
  125. idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
  126. idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3)
  127. | APMU_PJ_IDLE_CFG_L2_PWR_SW;
  128. break;
  129. case POWER_MODE_CORE_INTIDLE:
  130. apcr &= ~MPMU_PCR_PJ_SPSD;
  131. break;
  132. }
  133. /* set reserve bits */
  134. apcr |= (1 << 30) | (1 << 25);
  135. /* finally write the registers back */
  136. __raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
  137. __raw_writel(apcr, MPMU_PCR_PJ); /* 0xfe086000 */
  138. }
  139. static int mmp2_pm_enter(suspend_state_t state)
  140. {
  141. int temp;
  142. temp = __raw_readl(MMP2_ICU_INT4_MASK);
  143. if (temp & (1 << 1)) {
  144. printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__);
  145. return -EAGAIN;
  146. }
  147. temp = __raw_readl(APMU_SRAM_PWR_DWN);
  148. temp |= ((1 << 19) | (1 << 18));
  149. __raw_writel(temp, APMU_SRAM_PWR_DWN);
  150. pm_mpmu_clk_disable();
  151. pm_scu_clk_disable();
  152. printk(KERN_INFO "%s: before suspend\n", __func__);
  153. cpu_do_idle();
  154. printk(KERN_INFO "%s: after suspend\n", __func__);
  155. pm_mpmu_clk_enable(); /* enable clocks in MPMU */
  156. pm_scu_clk_enable(); /* enable clocks in SCU */
  157. return 0;
  158. }
  159. /*
  160. * Called after processes are frozen, but before we shut down devices.
  161. */
  162. static int mmp2_pm_prepare(void)
  163. {
  164. mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP);
  165. return 0;
  166. }
  167. /*
  168. * Called after devices are re-setup, but before processes are thawed.
  169. */
  170. static void mmp2_pm_finish(void)
  171. {
  172. mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
  173. }
  174. static int mmp2_pm_valid(suspend_state_t state)
  175. {
  176. return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
  177. }
  178. /*
  179. * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
  180. */
  181. static const struct platform_suspend_ops mmp2_pm_ops = {
  182. .valid = mmp2_pm_valid,
  183. .prepare = mmp2_pm_prepare,
  184. .enter = mmp2_pm_enter,
  185. .finish = mmp2_pm_finish,
  186. };
  187. static int __init mmp2_pm_init(void)
  188. {
  189. uint32_t apcr;
  190. if (!cpu_is_mmp2())
  191. return -EIO;
  192. suspend_set_ops(&mmp2_pm_ops);
  193. /*
  194. * Set bit 0, Slow clock Select 32K clock input instead of VCXO
  195. * VCXO is chosen by default, which would be disabled in suspend
  196. */
  197. __raw_writel(0x5, MPMU_SCCR);
  198. /*
  199. * Clear bit 23 of CIU_CPU_CONF
  200. * direct PJ4 to DDR access through Memory Controller slow queue
  201. * fast queue has issue and cause lcd will flick
  202. */
  203. __raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
  204. /* Clear default low power control bit */
  205. apcr = __raw_readl(MPMU_PCR_PJ);
  206. apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD
  207. | MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13);
  208. __raw_writel(apcr, MPMU_PCR_PJ);
  209. return 0;
  210. }
  211. late_initcall(mmp2_pm_init);