pm.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * linux/arch/arm/mach-omap2/pm.c
  3. *
  4. * OMAP2 Power Management Routines
  5. *
  6. * Copyright (C) 2006 Nokia Corporation
  7. * Tony Lindgren <tony@atomide.com>
  8. *
  9. * Copyright (C) 2005 Texas Instruments, Inc.
  10. * Richard Woodruff <r-woodruff2@ti.com>
  11. *
  12. * Based on pm.c for omap1
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License version 2 as
  16. * published by the Free Software Foundation.
  17. */
  18. #include <linux/pm.h>
  19. #include <linux/sched.h>
  20. #include <linux/proc_fs.h>
  21. #include <linux/pm.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/sysfs.h>
  24. #include <linux/module.h>
  25. #include <linux/delay.h>
  26. #include <asm/io.h>
  27. #include <asm/irq.h>
  28. #include <asm/atomic.h>
  29. #include <asm/mach/time.h>
  30. #include <asm/mach/irq.h>
  31. #include <asm/mach-types.h>
  32. #include <asm/arch/irqs.h>
  33. #include <asm/arch/clock.h>
  34. #include <asm/arch/sram.h>
  35. #include <asm/arch/pm.h>
  36. #include "prcm-regs.h"
  37. static struct clk *vclk;
  38. static void (*omap2_sram_idle)(void);
  39. static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
  40. static void (*saved_idle)(void);
  41. extern void __init pmdomain_init(void);
  42. extern void pmdomain_set_autoidle(void);
  43. static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
  44. void omap2_pm_idle(void)
  45. {
  46. local_irq_disable();
  47. local_fiq_disable();
  48. if (need_resched()) {
  49. local_fiq_enable();
  50. local_irq_enable();
  51. return;
  52. }
  53. /*
  54. * Since an interrupt may set up a timer, we don't want to
  55. * reprogram the hardware timer with interrupts enabled.
  56. * Re-enable interrupts only after returning from idle.
  57. */
  58. timer_dyn_reprogram();
  59. omap2_sram_idle();
  60. local_fiq_enable();
  61. local_irq_enable();
  62. }
  63. static int omap2_pm_prepare(suspend_state_t state)
  64. {
  65. int error = 0;
  66. /* We cannot sleep in idle until we have resumed */
  67. saved_idle = pm_idle;
  68. pm_idle = NULL;
  69. switch (state)
  70. {
  71. case PM_SUSPEND_STANDBY:
  72. case PM_SUSPEND_MEM:
  73. break;
  74. case PM_SUSPEND_DISK:
  75. return -ENOTSUPP;
  76. default:
  77. return -EINVAL;
  78. }
  79. return error;
  80. }
  81. #define INT0_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) | \
  82. OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) | \
  83. OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3))
  84. #define INT1_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4))
  85. #define INT2_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) | \
  86. OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) | \
  87. OMAP_IRQ_BIT(INT_24XX_UART3_IRQ))
  88. #define preg(reg) printk("%s\t(0x%p):\t0x%08x\n", #reg, &reg, reg);
  89. static void omap2_pm_debug(char * desc)
  90. {
  91. printk("%s:\n", desc);
  92. preg(CM_CLKSTCTRL_MPU);
  93. preg(CM_CLKSTCTRL_CORE);
  94. preg(CM_CLKSTCTRL_GFX);
  95. preg(CM_CLKSTCTRL_DSP);
  96. preg(CM_CLKSTCTRL_MDM);
  97. preg(PM_PWSTCTRL_MPU);
  98. preg(PM_PWSTCTRL_CORE);
  99. preg(PM_PWSTCTRL_GFX);
  100. preg(PM_PWSTCTRL_DSP);
  101. preg(PM_PWSTCTRL_MDM);
  102. preg(PM_PWSTST_MPU);
  103. preg(PM_PWSTST_CORE);
  104. preg(PM_PWSTST_GFX);
  105. preg(PM_PWSTST_DSP);
  106. preg(PM_PWSTST_MDM);
  107. preg(CM_AUTOIDLE1_CORE);
  108. preg(CM_AUTOIDLE2_CORE);
  109. preg(CM_AUTOIDLE3_CORE);
  110. preg(CM_AUTOIDLE4_CORE);
  111. preg(CM_AUTOIDLE_WKUP);
  112. preg(CM_AUTOIDLE_PLL);
  113. preg(CM_AUTOIDLE_DSP);
  114. preg(CM_AUTOIDLE_MDM);
  115. preg(CM_ICLKEN1_CORE);
  116. preg(CM_ICLKEN2_CORE);
  117. preg(CM_ICLKEN3_CORE);
  118. preg(CM_ICLKEN4_CORE);
  119. preg(CM_ICLKEN_GFX);
  120. preg(CM_ICLKEN_WKUP);
  121. preg(CM_ICLKEN_DSP);
  122. preg(CM_ICLKEN_MDM);
  123. preg(CM_IDLEST1_CORE);
  124. preg(CM_IDLEST2_CORE);
  125. preg(CM_IDLEST3_CORE);
  126. preg(CM_IDLEST4_CORE);
  127. preg(CM_IDLEST_GFX);
  128. preg(CM_IDLEST_WKUP);
  129. preg(CM_IDLEST_CKGEN);
  130. preg(CM_IDLEST_DSP);
  131. preg(CM_IDLEST_MDM);
  132. preg(RM_RSTST_MPU);
  133. preg(RM_RSTST_GFX);
  134. preg(RM_RSTST_WKUP);
  135. preg(RM_RSTST_DSP);
  136. preg(RM_RSTST_MDM);
  137. preg(PM_WKDEP_MPU);
  138. preg(PM_WKDEP_CORE);
  139. preg(PM_WKDEP_GFX);
  140. preg(PM_WKDEP_DSP);
  141. preg(PM_WKDEP_MDM);
  142. preg(CM_FCLKEN_WKUP);
  143. preg(CM_ICLKEN_WKUP);
  144. preg(CM_IDLEST_WKUP);
  145. preg(CM_AUTOIDLE_WKUP);
  146. preg(CM_CLKSEL_WKUP);
  147. preg(PM_WKEN_WKUP);
  148. preg(PM_WKST_WKUP);
  149. }
  150. static inline void omap2_pm_save_registers(void)
  151. {
  152. /* Save interrupt registers */
  153. OMAP24XX_SAVE(INTC_MIR0);
  154. OMAP24XX_SAVE(INTC_MIR1);
  155. OMAP24XX_SAVE(INTC_MIR2);
  156. /* Save power control registers */
  157. OMAP24XX_SAVE(CM_CLKSTCTRL_MPU);
  158. OMAP24XX_SAVE(CM_CLKSTCTRL_CORE);
  159. OMAP24XX_SAVE(CM_CLKSTCTRL_GFX);
  160. OMAP24XX_SAVE(CM_CLKSTCTRL_DSP);
  161. OMAP24XX_SAVE(CM_CLKSTCTRL_MDM);
  162. /* Save power state registers */
  163. OMAP24XX_SAVE(PM_PWSTCTRL_MPU);
  164. OMAP24XX_SAVE(PM_PWSTCTRL_CORE);
  165. OMAP24XX_SAVE(PM_PWSTCTRL_GFX);
  166. OMAP24XX_SAVE(PM_PWSTCTRL_DSP);
  167. OMAP24XX_SAVE(PM_PWSTCTRL_MDM);
  168. /* Save autoidle registers */
  169. OMAP24XX_SAVE(CM_AUTOIDLE1_CORE);
  170. OMAP24XX_SAVE(CM_AUTOIDLE2_CORE);
  171. OMAP24XX_SAVE(CM_AUTOIDLE3_CORE);
  172. OMAP24XX_SAVE(CM_AUTOIDLE4_CORE);
  173. OMAP24XX_SAVE(CM_AUTOIDLE_WKUP);
  174. OMAP24XX_SAVE(CM_AUTOIDLE_PLL);
  175. OMAP24XX_SAVE(CM_AUTOIDLE_DSP);
  176. OMAP24XX_SAVE(CM_AUTOIDLE_MDM);
  177. /* Save idle state registers */
  178. OMAP24XX_SAVE(CM_IDLEST1_CORE);
  179. OMAP24XX_SAVE(CM_IDLEST2_CORE);
  180. OMAP24XX_SAVE(CM_IDLEST3_CORE);
  181. OMAP24XX_SAVE(CM_IDLEST4_CORE);
  182. OMAP24XX_SAVE(CM_IDLEST_GFX);
  183. OMAP24XX_SAVE(CM_IDLEST_WKUP);
  184. OMAP24XX_SAVE(CM_IDLEST_CKGEN);
  185. OMAP24XX_SAVE(CM_IDLEST_DSP);
  186. OMAP24XX_SAVE(CM_IDLEST_MDM);
  187. /* Save clock registers */
  188. OMAP24XX_SAVE(CM_FCLKEN1_CORE);
  189. OMAP24XX_SAVE(CM_FCLKEN2_CORE);
  190. OMAP24XX_SAVE(CM_ICLKEN1_CORE);
  191. OMAP24XX_SAVE(CM_ICLKEN2_CORE);
  192. OMAP24XX_SAVE(CM_ICLKEN3_CORE);
  193. OMAP24XX_SAVE(CM_ICLKEN4_CORE);
  194. }
  195. static inline void omap2_pm_restore_registers(void)
  196. {
  197. /* Restore clock state registers */
  198. OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU);
  199. OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE);
  200. OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX);
  201. OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP);
  202. OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM);
  203. /* Restore power state registers */
  204. OMAP24XX_RESTORE(PM_PWSTCTRL_MPU);
  205. OMAP24XX_RESTORE(PM_PWSTCTRL_CORE);
  206. OMAP24XX_RESTORE(PM_PWSTCTRL_GFX);
  207. OMAP24XX_RESTORE(PM_PWSTCTRL_DSP);
  208. OMAP24XX_RESTORE(PM_PWSTCTRL_MDM);
  209. /* Restore idle state registers */
  210. OMAP24XX_RESTORE(CM_IDLEST1_CORE);
  211. OMAP24XX_RESTORE(CM_IDLEST2_CORE);
  212. OMAP24XX_RESTORE(CM_IDLEST3_CORE);
  213. OMAP24XX_RESTORE(CM_IDLEST4_CORE);
  214. OMAP24XX_RESTORE(CM_IDLEST_GFX);
  215. OMAP24XX_RESTORE(CM_IDLEST_WKUP);
  216. OMAP24XX_RESTORE(CM_IDLEST_CKGEN);
  217. OMAP24XX_RESTORE(CM_IDLEST_DSP);
  218. OMAP24XX_RESTORE(CM_IDLEST_MDM);
  219. /* Restore autoidle registers */
  220. OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE);
  221. OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE);
  222. OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE);
  223. OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE);
  224. OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP);
  225. OMAP24XX_RESTORE(CM_AUTOIDLE_PLL);
  226. OMAP24XX_RESTORE(CM_AUTOIDLE_DSP);
  227. OMAP24XX_RESTORE(CM_AUTOIDLE_MDM);
  228. /* Restore clock registers */
  229. OMAP24XX_RESTORE(CM_FCLKEN1_CORE);
  230. OMAP24XX_RESTORE(CM_FCLKEN2_CORE);
  231. OMAP24XX_RESTORE(CM_ICLKEN1_CORE);
  232. OMAP24XX_RESTORE(CM_ICLKEN2_CORE);
  233. OMAP24XX_RESTORE(CM_ICLKEN3_CORE);
  234. OMAP24XX_RESTORE(CM_ICLKEN4_CORE);
  235. /* REVISIT: Clear interrupts here */
  236. /* Restore interrupt registers */
  237. OMAP24XX_RESTORE(INTC_MIR0);
  238. OMAP24XX_RESTORE(INTC_MIR1);
  239. OMAP24XX_RESTORE(INTC_MIR2);
  240. }
  241. static int omap2_pm_suspend(void)
  242. {
  243. int processor_type = 0;
  244. /* REVISIT: 0x21 or 0x26? */
  245. if (cpu_is_omap2420())
  246. processor_type = 0x21;
  247. if (!processor_type)
  248. return -ENOTSUPP;
  249. local_irq_disable();
  250. local_fiq_disable();
  251. omap2_pm_save_registers();
  252. /* Disable interrupts except for the wake events */
  253. INTC_MIR_SET0 = 0xffffffff & ~INT0_WAKE_MASK;
  254. INTC_MIR_SET1 = 0xffffffff & ~INT1_WAKE_MASK;
  255. INTC_MIR_SET2 = 0xffffffff & ~INT2_WAKE_MASK;
  256. pmdomain_set_autoidle();
  257. /* Clear old wake-up events */
  258. PM_WKST1_CORE = 0;
  259. PM_WKST2_CORE = 0;
  260. PM_WKST_WKUP = 0;
  261. /* Enable wake-up events */
  262. PM_WKEN1_CORE = (1 << 22) | (1 << 21); /* UART1 & 2 */
  263. PM_WKEN2_CORE = (1 << 2); /* UART3 */
  264. PM_WKEN_WKUP = (1 << 2) | (1 << 0); /* GPIO & GPT1 */
  265. /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled
  266. * in the SRAM suspend code */
  267. CM_FCLKEN1_CORE = 0;
  268. CM_FCLKEN2_CORE = 0;
  269. CM_ICLKEN1_CORE = 0;
  270. CM_ICLKEN3_CORE = 0;
  271. CM_ICLKEN4_CORE = 0;
  272. omap2_pm_debug("Status before suspend");
  273. /* Must wait for serial buffers to clear */
  274. mdelay(200);
  275. /* Jump to SRAM suspend code
  276. * REVISIT: When is this SDRC_DLLB_CTRL?
  277. */
  278. omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type);
  279. /* Back from sleep */
  280. omap2_pm_restore_registers();
  281. local_fiq_enable();
  282. local_irq_enable();
  283. return 0;
  284. }
  285. static int omap2_pm_enter(suspend_state_t state)
  286. {
  287. int ret = 0;
  288. switch (state)
  289. {
  290. case PM_SUSPEND_STANDBY:
  291. case PM_SUSPEND_MEM:
  292. ret = omap2_pm_suspend();
  293. break;
  294. case PM_SUSPEND_DISK:
  295. ret = -ENOTSUPP;
  296. break;
  297. default:
  298. ret = -EINVAL;
  299. }
  300. return ret;
  301. }
  302. static int omap2_pm_finish(suspend_state_t state)
  303. {
  304. pm_idle = saved_idle;
  305. return 0;
  306. }
  307. static struct pm_ops omap_pm_ops = {
  308. .prepare = omap2_pm_prepare,
  309. .enter = omap2_pm_enter,
  310. .finish = omap2_pm_finish,
  311. .valid = pm_valid_only_mem,
  312. };
  313. int __init omap2_pm_init(void)
  314. {
  315. printk("Power Management for TI OMAP.\n");
  316. vclk = clk_get(NULL, "virt_prcm_set");
  317. if (IS_ERR(vclk)) {
  318. printk(KERN_ERR "Could not get PM vclk\n");
  319. return -ENODEV;
  320. }
  321. /*
  322. * We copy the assembler sleep/wakeup routines to SRAM.
  323. * These routines need to be in SRAM as that's the only
  324. * memory the MPU can see when it wakes up.
  325. */
  326. omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
  327. omap24xx_idle_loop_suspend_sz);
  328. omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
  329. omap24xx_cpu_suspend_sz);
  330. pm_set_ops(&omap_pm_ops);
  331. pm_idle = omap2_pm_idle;
  332. pmdomain_init();
  333. return 0;
  334. }
  335. __initcall(omap2_pm_init);