pm-imx5.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
  3. *
  4. * The code contained herein is licensed under the GNU General Public
  5. * License. You may obtain a copy of the GNU General Public License
  6. * Version 2 or later at the following locations:
  7. *
  8. * http://www.opensource.org/licenses/gpl-license.html
  9. * http://www.gnu.org/copyleft/gpl.html
  10. */
  11. #include <linux/suspend.h>
  12. #include <linux/clk.h>
  13. #include <linux/io.h>
  14. #include <linux/err.h>
  15. #include <linux/export.h>
  16. #include <asm/cacheflush.h>
  17. #include <asm/system_misc.h>
  18. #include <asm/tlbflush.h>
  19. #include "common.h"
  20. #include "cpuidle.h"
  21. #include "hardware.h"
  22. #define MXC_CCM_CLPCR 0x54
  23. #define MXC_CCM_CLPCR_LPM_OFFSET 0
  24. #define MXC_CCM_CLPCR_LPM_MASK 0x3
  25. #define MXC_CCM_CLPCR_STBY_COUNT_OFFSET 9
  26. #define MXC_CCM_CLPCR_VSTBY (0x1 << 8)
  27. #define MXC_CCM_CLPCR_SBYOS (0x1 << 6)
  28. #define MXC_CORTEXA8_PLAT_LPC 0xc
  29. #define MXC_CORTEXA8_PLAT_LPC_DSM (1 << 0)
  30. #define MXC_CORTEXA8_PLAT_LPC_DBG_DSM (1 << 1)
  31. #define MXC_SRPG_NEON_SRPGCR 0x280
  32. #define MXC_SRPG_ARM_SRPGCR 0x2a0
  33. #define MXC_SRPG_EMPGC0_SRPGCR 0x2c0
  34. #define MXC_SRPG_EMPGC1_SRPGCR 0x2d0
  35. #define MXC_SRPGCR_PCR 1
  36. /*
  37. * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
  38. * This is also the lowest power state possible without affecting
  39. * non-cpu parts of the system. For these reasons, imx5 should default
  40. * to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
  41. * uses this state and needs to take no action when registers remain confgiured
  42. * for this state.
  43. */
  44. #define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
  45. struct imx5_pm_data {
  46. phys_addr_t cortex_addr;
  47. phys_addr_t gpc_addr;
  48. };
  49. static const struct imx5_pm_data imx51_pm_data __initconst = {
  50. .cortex_addr = 0x83fa0000,
  51. .gpc_addr = 0x73fd8000,
  52. };
  53. static const struct imx5_pm_data imx53_pm_data __initconst = {
  54. .cortex_addr = 0x63fa0000,
  55. .gpc_addr = 0x53fd8000,
  56. };
  57. static void __iomem *ccm_base;
  58. static void __iomem *cortex_base;
  59. static void __iomem *gpc_base;
  60. void __init imx5_pm_set_ccm_base(void __iomem *base)
  61. {
  62. ccm_base = base;
  63. }
  64. /*
  65. * set cpu low power mode before WFI instruction. This function is called
  66. * mx5 because it can be used for mx51, and mx53.
  67. */
  68. static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
  69. {
  70. u32 plat_lpc, arm_srpgcr, ccm_clpcr;
  71. u32 empgc0, empgc1;
  72. int stop_mode = 0;
  73. /* always allow platform to issue a deep sleep mode request */
  74. plat_lpc = __raw_readl(cortex_base + MXC_CORTEXA8_PLAT_LPC) &
  75. ~(MXC_CORTEXA8_PLAT_LPC_DSM);
  76. ccm_clpcr = __raw_readl(ccm_base + MXC_CCM_CLPCR) &
  77. ~(MXC_CCM_CLPCR_LPM_MASK);
  78. arm_srpgcr = __raw_readl(gpc_base + MXC_SRPG_ARM_SRPGCR) &
  79. ~(MXC_SRPGCR_PCR);
  80. empgc0 = __raw_readl(gpc_base + MXC_SRPG_EMPGC0_SRPGCR) &
  81. ~(MXC_SRPGCR_PCR);
  82. empgc1 = __raw_readl(gpc_base + MXC_SRPG_EMPGC1_SRPGCR) &
  83. ~(MXC_SRPGCR_PCR);
  84. switch (mode) {
  85. case WAIT_CLOCKED:
  86. break;
  87. case WAIT_UNCLOCKED:
  88. ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
  89. break;
  90. case WAIT_UNCLOCKED_POWER_OFF:
  91. case STOP_POWER_OFF:
  92. plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
  93. | MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
  94. if (mode == WAIT_UNCLOCKED_POWER_OFF) {
  95. ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
  96. ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
  97. ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
  98. stop_mode = 0;
  99. } else {
  100. ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
  101. ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
  102. ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
  103. ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
  104. stop_mode = 1;
  105. }
  106. arm_srpgcr |= MXC_SRPGCR_PCR;
  107. break;
  108. case STOP_POWER_ON:
  109. ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
  110. break;
  111. default:
  112. printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
  113. return;
  114. }
  115. __raw_writel(plat_lpc, cortex_base + MXC_CORTEXA8_PLAT_LPC);
  116. __raw_writel(ccm_clpcr, ccm_base + MXC_CCM_CLPCR);
  117. __raw_writel(arm_srpgcr, gpc_base + MXC_SRPG_ARM_SRPGCR);
  118. __raw_writel(arm_srpgcr, gpc_base + MXC_SRPG_NEON_SRPGCR);
  119. if (stop_mode) {
  120. empgc0 |= MXC_SRPGCR_PCR;
  121. empgc1 |= MXC_SRPGCR_PCR;
  122. __raw_writel(empgc0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
  123. __raw_writel(empgc1, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
  124. }
  125. }
  126. static int mx5_suspend_enter(suspend_state_t state)
  127. {
  128. switch (state) {
  129. case PM_SUSPEND_MEM:
  130. mx5_cpu_lp_set(STOP_POWER_OFF);
  131. break;
  132. case PM_SUSPEND_STANDBY:
  133. /* DEFAULT_IDLE_STATE already configured */
  134. break;
  135. default:
  136. return -EINVAL;
  137. }
  138. if (state == PM_SUSPEND_MEM) {
  139. local_flush_tlb_all();
  140. flush_cache_all();
  141. /*clear the EMPGC0/1 bits */
  142. __raw_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
  143. __raw_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
  144. }
  145. cpu_do_idle();
  146. /* return registers to default idle state */
  147. mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
  148. return 0;
  149. }
  150. static int mx5_pm_valid(suspend_state_t state)
  151. {
  152. return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
  153. }
  154. static const struct platform_suspend_ops mx5_suspend_ops = {
  155. .valid = mx5_pm_valid,
  156. .enter = mx5_suspend_enter,
  157. };
  158. static inline int imx5_cpu_do_idle(void)
  159. {
  160. int ret = tzic_enable_wake();
  161. if (likely(!ret))
  162. cpu_do_idle();
  163. return ret;
  164. }
  165. static void imx5_pm_idle(void)
  166. {
  167. imx5_cpu_do_idle();
  168. }
  169. static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
  170. {
  171. int ret;
  172. struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
  173. if (IS_ERR(gpc_dvfs_clk))
  174. return PTR_ERR(gpc_dvfs_clk);
  175. ret = clk_prepare_enable(gpc_dvfs_clk);
  176. if (ret)
  177. return ret;
  178. arm_pm_idle = imx5_pm_idle;
  179. cortex_base = ioremap(data->cortex_addr, SZ_16K);
  180. gpc_base = ioremap(data->gpc_addr, SZ_16K);
  181. WARN_ON(!ccm_base || !cortex_base || !gpc_base);
  182. /* Set the registers to the default cpu idle state. */
  183. mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
  184. ret = imx5_cpuidle_init();
  185. if (ret)
  186. pr_warn("%s: cpuidle init failed %d\n", __func__, ret);
  187. suspend_set_ops(&mx5_suspend_ops);
  188. return 0;
  189. }
  190. void __init imx51_pm_init(void)
  191. {
  192. imx5_pm_common_init(&imx51_pm_data);
  193. }
  194. void __init imx53_pm_init(void)
  195. {
  196. imx5_pm_common_init(&imx53_pm_data);
  197. }