PageRenderTime 31ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/powerpc/platforms/52xx/mpc52xx_pm.c

https://bitbucket.org/abioy/linux
C | 194 lines | 134 code | 36 blank | 24 comment | 5 complexity | 2816b42178168e2a537e437344ee5ad5 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0
  1. #include <linux/init.h>
  2. #include <linux/suspend.h>
  3. #include <linux/io.h>
  4. #include <asm/time.h>
  5. #include <asm/cacheflush.h>
  6. #include <asm/mpc52xx.h>
  7. /* these are defined in mpc52xx_sleep.S, and only used here */
  8. extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs,
  9. struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*);
  10. extern void mpc52xx_ds_sram(void);
  11. extern const long mpc52xx_ds_sram_size;
  12. extern void mpc52xx_ds_cached(void);
  13. extern const long mpc52xx_ds_cached_size;
  14. static void __iomem *mbar;
  15. static void __iomem *sdram;
  16. static struct mpc52xx_cdm __iomem *cdm;
  17. static struct mpc52xx_intr __iomem *intr;
  18. static struct mpc52xx_gpio_wkup __iomem *gpiow;
  19. static void __iomem *sram;
  20. static int sram_size;
  21. struct mpc52xx_suspend mpc52xx_suspend;
  22. static int mpc52xx_pm_valid(suspend_state_t state)
  23. {
  24. switch (state) {
  25. case PM_SUSPEND_STANDBY:
  26. return 1;
  27. default:
  28. return 0;
  29. }
  30. }
  31. int mpc52xx_set_wakeup_gpio(u8 pin, u8 level)
  32. {
  33. u16 tmp;
  34. /* enable gpio */
  35. out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin));
  36. /* set as input */
  37. out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin));
  38. /* enable deep sleep interrupt */
  39. out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin));
  40. /* low/high level creates wakeup interrupt */
  41. tmp = in_be16(&gpiow->wkup_itype);
  42. tmp &= ~(0x3 << (pin * 2));
  43. tmp |= (!level + 1) << (pin * 2);
  44. out_be16(&gpiow->wkup_itype, tmp);
  45. /* master enable */
  46. out_8(&gpiow->wkup_maste, 1);
  47. return 0;
  48. }
  49. int mpc52xx_pm_prepare(void)
  50. {
  51. struct device_node *np;
  52. const struct of_device_id immr_ids[] = {
  53. { .compatible = "fsl,mpc5200-immr", },
  54. { .compatible = "fsl,mpc5200b-immr", },
  55. { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
  56. { .type = "builtin", .compatible = "mpc5200", }, /* efika */
  57. {}
  58. };
  59. /* map the whole register space */
  60. np = of_find_matching_node(NULL, immr_ids);
  61. mbar = of_iomap(np, 0);
  62. of_node_put(np);
  63. if (!mbar) {
  64. pr_err("mpc52xx_pm_prepare(): could not map registers\n");
  65. return -ENOSYS;
  66. }
  67. /* these offsets are from mpc5200 users manual */
  68. sdram = mbar + 0x100;
  69. cdm = mbar + 0x200;
  70. intr = mbar + 0x500;
  71. gpiow = mbar + 0xc00;
  72. sram = mbar + 0x8000; /* Those will be handled by the */
  73. sram_size = 0x4000; /* bestcomm driver soon */
  74. /* call board suspend code, if applicable */
  75. if (mpc52xx_suspend.board_suspend_prepare)
  76. mpc52xx_suspend.board_suspend_prepare(mbar);
  77. else {
  78. printk(KERN_ALERT "%s: %i don't know how to wake up the board\n",
  79. __func__, __LINE__);
  80. goto out_unmap;
  81. }
  82. return 0;
  83. out_unmap:
  84. iounmap(mbar);
  85. return -ENOSYS;
  86. }
  87. char saved_sram[0x4000];
  88. int mpc52xx_pm_enter(suspend_state_t state)
  89. {
  90. u32 clk_enables;
  91. u32 msr, hid0;
  92. u32 intr_main_mask;
  93. void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500;
  94. unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
  95. char saved_0x500[mpc52xx_ds_cached_size];
  96. /* disable all interrupts in PIC */
  97. intr_main_mask = in_be32(&intr->main_mask);
  98. out_be32(&intr->main_mask, intr_main_mask | 0x1ffff);
  99. /* don't let DEC expire any time soon */
  100. mtspr(SPRN_DEC, 0x7fffffff);
  101. /* save SRAM */
  102. memcpy(saved_sram, sram, sram_size);
  103. /* copy low level suspend code to sram */
  104. memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size);
  105. out_8(&cdm->ccs_sleep_enable, 1);
  106. out_8(&cdm->osc_sleep_enable, 1);
  107. out_8(&cdm->ccs_qreq_test, 1);
  108. /* disable all but SDRAM and bestcomm (SRAM) clocks */
  109. clk_enables = in_be32(&cdm->clk_enables);
  110. out_be32(&cdm->clk_enables, clk_enables & 0x00088000);
  111. /* disable power management */
  112. msr = mfmsr();
  113. mtmsr(msr & ~MSR_POW);
  114. /* enable sleep mode, disable others */
  115. hid0 = mfspr(SPRN_HID0);
  116. mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP);
  117. /* save original, copy our irq handler, flush from dcache and invalidate icache */
  118. memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size);
  119. memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size);
  120. flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
  121. /* call low-level sleep code */
  122. mpc52xx_deep_sleep(sram, sdram, cdm, intr);
  123. /* restore original irq handler */
  124. memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size);
  125. flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
  126. /* restore old power mode */
  127. mtmsr(msr & ~MSR_POW);
  128. mtspr(SPRN_HID0, hid0);
  129. mtmsr(msr);
  130. out_be32(&cdm->clk_enables, clk_enables);
  131. out_8(&cdm->ccs_sleep_enable, 0);
  132. out_8(&cdm->osc_sleep_enable, 0);
  133. /* restore SRAM */
  134. memcpy(sram, saved_sram, sram_size);
  135. /* restart jiffies */
  136. wakeup_decrementer();
  137. /* reenable interrupts in PIC */
  138. out_be32(&intr->main_mask, intr_main_mask);
  139. return 0;
  140. }
  141. void mpc52xx_pm_finish(void)
  142. {
  143. /* call board resume code */
  144. if (mpc52xx_suspend.board_resume_finish)
  145. mpc52xx_suspend.board_resume_finish(mbar);
  146. iounmap(mbar);
  147. }
  148. static struct platform_suspend_ops mpc52xx_pm_ops = {
  149. .valid = mpc52xx_pm_valid,
  150. .prepare = mpc52xx_pm_prepare,
  151. .enter = mpc52xx_pm_enter,
  152. .finish = mpc52xx_pm_finish,
  153. };
  154. int __init mpc52xx_pm_init(void)
  155. {
  156. suspend_set_ops(&mpc52xx_pm_ops);
  157. return 0;
  158. }