pm.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*
  2. * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
  3. *
  4. * Power management support code for SuperH Mobile
  5. *
  6. * Copyright (C) 2009 Magnus Damm
  7. *
  8. * This file is subject to the terms and conditions of the GNU General Public
  9. * License. See the file "COPYING" in the main directory of this archive
  10. * for more details.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/io.h>
  15. #include <linux/suspend.h>
  16. #include <asm/suspend.h>
  17. #include <asm/uaccess.h>
  18. /*
  19. * Sleep modes available on SuperH Mobile:
  20. *
  21. * Sleep mode is just plain "sleep" instruction
  22. * Sleep Self-Refresh mode is above plus RAM put in Self-Refresh
  23. * Standby Self-Refresh mode is above plus stopped clocks
  24. */
  25. #define SUSP_MODE_SLEEP (SUSP_SH_SLEEP)
  26. #define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF)
  27. #define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF)
  28. /*
  29. * The following modes are not there yet:
  30. *
  31. * R-standby mode is unsupported, but will be added in the future
  32. * U-standby mode is low priority since it needs bootloader hacks
  33. *
  34. * All modes should be tied in with cpuidle. But before that can
  35. * happen we need to keep track of enabled hardware blocks so we
  36. * can avoid entering sleep modes that stop clocks to hardware
  37. * blocks that are in use even though the cpu core is idle.
  38. */
  39. extern const unsigned char sh_mobile_standby[];
  40. extern const unsigned int sh_mobile_standby_size;
  41. static void sh_mobile_call_standby(unsigned long mode)
  42. {
  43. extern void *vbr_base;
  44. void *onchip_mem = (void *)0xe5200000; /* ILRAM */
  45. void (*standby_onchip_mem)(unsigned long) = onchip_mem;
  46. /* Note: Wake up from sleep may generate exceptions!
  47. * Setup VBR to point to on-chip ram if self-refresh is
  48. * going to be used.
  49. */
  50. if (mode & SUSP_SH_SF)
  51. asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
  52. /* Copy the assembly snippet to the otherwise ununsed ILRAM */
  53. memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
  54. wmb();
  55. ctrl_barrier();
  56. /* Let assembly snippet in on-chip memory handle the rest */
  57. standby_onchip_mem(mode);
  58. /* Put VBR back in System RAM again */
  59. if (mode & SUSP_SH_SF)
  60. asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
  61. }
  62. static int sh_pm_enter(suspend_state_t state)
  63. {
  64. local_irq_disable();
  65. set_bl_bit();
  66. sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
  67. local_irq_disable();
  68. clear_bl_bit();
  69. return 0;
  70. }
  71. static struct platform_suspend_ops sh_pm_ops = {
  72. .enter = sh_pm_enter,
  73. .valid = suspend_valid_only_mem,
  74. };
  75. static int __init sh_pm_init(void)
  76. {
  77. suspend_set_ops(&sh_pm_ops);
  78. return 0;
  79. }
  80. late_initcall(sh_pm_init);